Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SVG Row #11

Open
2 tasks
jasonm23 opened this issue Apr 26, 2015 · 46 comments
Open
2 tasks

SVG Row #11

jasonm23 opened this issue Apr 26, 2015 · 46 comments

Comments

@jasonm23
Copy link
Collaborator

  • Modify row to have

:background
:overlay

Both of which are SVG layers.

  • Add documentation to README
@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 1, 2015

screen shot 2015-05-01 at 6 44 23 pm

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 1, 2015

The image above is using a row with background and overlay.

Hi @sabof I've got a few notes / questions / etc. that I'd like you input on...

  • Using <svg> node to contain the row.

  • Not sure how to measure the width of the row.

    (smt/defrow default-left
      :margin 1
      :background `(rect :y 2 :width ,(* 10 (smt/r-width 'default-left)) :height 20 :rx 7 :ry 7 :fill "#000000" :fill-opacity 0.8)
      :overlay `(rect :y 3 :width  ,(* 10 (smt/r-width 'default-left)) :height 20 :rx 7 :ry 7 :fill "#FFFFFF" :fill-opacity 0.1)
      :widgets '(buffer-info buffer-name buffer-dirty)
      :align "left")
    

    it appears that in ,(* 10 (smt/r-width 'default-left)), (smt/r-width) isn't evaluated as I'd expected. When I change buffers to another filename, I'd expect the overall row length to change... see below, the width remains constant.

Any ideas?

screen shot 2015-05-01 at 7 02 53 pm
screen shot 2015-05-01 at 7 02 48 pm
screen shot 2015-05-01 at 7 02 38 pm
screen shot 2015-05-01 at 6 58 43 pm

@sabof
Copy link
Owner

sabof commented May 1, 2015

Yes, because the form is evaluated once, upon definition. You need the fields to accept functions.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 1, 2015

Right

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 1, 2015

screen shot 2015-05-01 at 11 23 39 pm

Works pretty well. I'll need to get the (* 5.5 derived from the actual style font size, but looks quite good so far.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 1, 2015

Note the orange boxes on the right are placeholders for the "right" align rows.

I'll look at that in the morning, obviously they are drawing in the wrong direction.

screen shot 2015-05-01 at 11 27 23 pm

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 1, 2015

I guess I can use (smt/r-align (row)) in the background / overlay functions, to determine drawing direction.

  • additional helper functions for geometry / origin / width (in pixels) would be useful.
    • (smt/r-x-origin (row)) get the x pixel origin
    • (smt/r-width-pixels (row)) get the row width in pixels
  • :text-padding - apply a simple left pixel padding to the text node in row.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 1, 2015

Any ideas on determining pixel width of a row @sabof?

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 1, 2015

I guess that each widget would have to provide a pixel width, which we fold.

@sabof
Copy link
Owner

sabof commented May 1, 2015

You can multiply it by (frame-char-width). I guess I wouldn't mind if width were to mean "pixel width".

@sabof
Copy link
Owner

sabof commented May 1, 2015

Or at least all internal calculations where to be done in pixels.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 1, 2015

Is frame char width how it derives the row width?

I assumed that different font sizes of widget text might affect this measurement.

Ps. where were.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 2, 2015

Geometry calculated when using (frame-char-width)

screen shot 2015-05-02 at 8 14 43 am

@sabof
Copy link
Owner

sabof commented May 2, 2015

The width is used when calculating whether widgets overlap. The system doesn't know about font sizes.

What is the code?

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 2, 2015

What is needed is for a widget to return its width in pixels, ie. smt/w-pixel-width

Then it's a case of foldl / reduce on the row's widgets to get the correct pixel width.

If we assume 72 or 96 ppi we can do the approximate math. Unfortunately though we will have an issue thanks to proportional fonts, before we get a true value.

Let's just put a pin in this for now.

We may be able to do some off screen rendering and image measurement, but I think it's going to be trouble.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 2, 2015

The code just changes the above s/5.5/(frame-char-width)/

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 2, 2015

Oh,

I see I didn't post the original.

In a nutshell: a svg rect inside a lambda (row)

:width ,(* (frame-char-width) (smt/r-width row)) ...

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 2, 2015

the original factor was 5.5 instead of frame-char-width ...

It does show that some level of approximation is useful here though.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 2, 2015

It's worth noting that with more accurate measures we won't be hiding rows that would actually fit.

@sabof
Copy link
Owner

sabof commented May 2, 2015

Never mind, I've assumed the error messages where significant.

Might it be possible to wrap the row container within SVG?

@sabof
Copy link
Owner

sabof commented May 2, 2015

It might even be possible for it manage hiding, by putting a large line-height somewhere.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 2, 2015

I've done this with my scratch of smt/r-export-default

SVG container, positioned by align. (background and overlay support.)

The only things left are

  • nice/accurate width measurement
  • left / right pixel padding support. (ie. interior margins before positioning/sizing the text block.)
  • tidy up the code and pull request
(defun smt/r-export-default (row theme)
  `(svg :x ,(if (equal (smt/r-align row) "left")
                (* (smt/r-margin row)
                   (frame-char-width))
              (- (smt/window-pixel-width)
                 (* (smt/r-margin row)
                    (frame-char-width))
                 (* (smt/r-width row)
                    (frame-char-size))))
        :y 0

        :width ,(* (smt/r-width row)
                   (frame-char-size))

        ,(smt/r-background row)
        (text
         :x ,(if (equal (smt/r-align row) "left")
                 0
                 (* (smt/r-width row)
                    (frame-char-size)))
         :y ,(smt/r-baseline row)
         :text-anchor
         ,(if (equal (smt/r-align row) "left")
              "start"
            "end")
         ,@(mapcar (lambda (widget-or-name)
                     (smt/w-export
                      (smt/t-normalize-widget
                       theme widget-or-name)
                      row theme))
                   (smt/r-widgets row))
         )
        ,(smt/r-overlay row)))

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 2, 2015

As you can see here, the width measurement is not very useful when using (frame-char-width)

Note the green container boxes on the right aligned rows.

screen shot 2015-05-02 at 9 42 42 am

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 2, 2015

Tidied up

(defun smt/r-export-default (row theme)
  `(svg :x ,(if (equal (smt/r-align row) "left")
                (* (smt/r-margin row) (frame-char-width))
              (- (smt/window-pixel-width)
                 (* (smt/r-margin row) (frame-char-width))
                 (* (smt/r-width row) (frame-char-width))))
        :y 0
        :width ,(* (smt/r-width row) (frame-char-width))
        ,(smt/r-background row)
        (text :x ,(if (equal (smt/r-align row) "left")
                      0
                    (* (smt/r-width row) (frame-char-width)))
              :y ,(smt/r-baseline row)
              :text-anchor ,(if (equal (smt/r-align row) "left") "start" "end")
              ,@(mapcar (lambda (widget-or-name)
                          (smt/w-export
                           (smt/t-normalize-widget
                            theme widget-or-name)
                           row theme))
                        (smt/r-widgets row)))
        ,(smt/r-overlay row)))

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 2, 2015

Just noticed I typo'ed frame-char-size instead of frame-char-width

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 2, 2015

The results are a bit better...

screen shot 2015-05-02 at 9 48 41 am

screen shot 2015-05-02 at 9 49 57 am

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 3, 2015

Added basic left / right padding support (only applied to leading margin, ie. left/right depending on alignment.)

(defun smt/r-export-default (row theme)
  `(svg :x ,(if (equal (smt/r-align row) "left")
                (* (smt/r-margin row) (frame-char-width))
              (- (smt/window-pixel-width)
                 (* (smt/r-margin row) (frame-char-width))
                 (* (smt/r-width row) (frame-char-width))))
        :y 0
        :width ,(* (smt/r-width row) (frame-char-width))
        ,(smt/r-background row)
        (text :x ,(if (equal (smt/r-align row) "left")
                      (smt/r-padding-left row)
                    (- (* (smt/r-width row) (frame-char-width)) (smt/r-padding-right row)))
              :y ,(smt/r-baseline row)
              :text-anchor ,(if (equal (smt/r-align row) "left") "start" "end")
              ,@(mapcar (lambda (widget-or-name)
                          (smt/w-export
                           (smt/t-normalize-widget
                            theme widget-or-name)
                           row theme))
                        (smt/r-widgets row)))
        ,(smt/r-overlay row)))

@sabof
Copy link
Owner

sabof commented May 3, 2015

Isn't "svg" supposed to be the top-level element, similar to "html"?

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 3, 2015

You may nest them to create a relative Cartesian coordinate space.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 3, 2015

Re char widths I see some options as

  • find char widths / string width code in Emacs (likely font parsing is not done in EmacsLisp, so that's unlikely a solution, I'll have to check though.)
  • build a widget tspan into a text, create an svg image and measure it, all in Emacs... Seems silly, and likely slow.
  • build font tables in cache for each style. List widths, and calculate strings. Memoize results. (Recalc if string changes.) - font tables would need to be generated on init. Could be cached to temporary file. Build font table from an external tool. (Most languages have some sort of font parsing libs.)

... ? Other options.

@sabof
Copy link
Owner

sabof commented May 3, 2015

I guess one could run a background process with a more full SVG API. I'm not sure if means justify the ends in this case. Perhaps an approximation + margin would work almost as well.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 3, 2015

It won't work well at all. However a full SVG API is not necessary.

Just font / string width measurement is needed.

The payoff is the ability to accurately layout the svg modeline. AFAIK that's the holy grail of this project, if it's going to be seriously useful.

The font table to cache method is adequate, we might also be able to utilize something like Cairo, ImageMagick etc. obviously cross platform is something to keep an eye on.

Sadly all the Emacs string font width (for proportional) functions require the string to be rendered in the window / current buffer. Which is obviously a no no.

It will be quite "fun" having to deal with OsX dfont.


We can make a stipulation whereby a non-text widget must be to declare its static width or provide a function to make its dynamic width available.

I don't think it's much to ask a theme / widget developer.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 3, 2015

it won't work at all well.

Approximation that is.

@sabof
Copy link
Owner

sabof commented May 3, 2015

I was thinking that if an additional dependency is to be brought, might as well get a full API.

@sabof
Copy link
Owner

sabof commented May 3, 2015

Admittedly, I'm not very fond of the idea. If similar effects can be achieved with SVG alone, I'd rather not do it.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 4, 2015

We can't make containers fit to the text they're displaying, with SVG alone... or can we?

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 4, 2015

I think Emacs-Mac-Port's method of rendering SVG (using WebKit) allows it to use JS / script blocks.
But to remain portable we can't really go in that direction.

I was thinking that if an additional dependency is to be brought, might as well get a full API.

An external headless webkit? :) (I'm only sort of joking.)

@sabof
Copy link
Owner

sabof commented May 4, 2015

If you can add a background to the text element, that should be enough -- one image for left, one for center, and one for right.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 4, 2015

Can you add a background to the text element? I don't think that's possible in SVG.

@sabof
Copy link
Owner

sabof commented May 4, 2015

Maybe indeed you can't. This seems to work:

convert -font Arial -pointsize 72 label:Thomas gif:- | identify gif:- | awk '{ print $3 }'

It has the downside of requiring bash, but admittedly I doubt I'm going to implement something more complicated.

It could be wrapped in something like smt/w-width-text-pixels, along with a fall-back.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 4, 2015

Bash isn't required, ImageMagick is, on Linux.

Unfortunately that won't cut it on OSX or Win. ImageMagick will install of course, but it won't support fonts (out the box.)

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 4, 2015

BTW @sabof, I'm not expecting you to implement this, I'm spitballing possible solutions.

I'm planning on implementing the solution.

@sabof
Copy link
Owner

sabof commented May 4, 2015

Indeed the additional overhead of reading/writing to a temporary file is probably trivial.

Why, what's special about win/osx fonts?

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 4, 2015

I can't check windows, but OSX / ImageMagick don't play together (font wise) because OS X keeps its fonts in a non compatible bundling format.

(It keeps them in .dfont bundles.)

Windows might be ok. I will figure that out for sure.

@jasonm23
Copy link
Collaborator Author

jasonm23 commented May 4, 2015

There is a way to get the fonts out of dfont packages (that's required for IM) but that's a lot of finagling and friction.

@jasonm23
Copy link
Collaborator Author

Next attempt: Node canvas, or maybe just straight to Cairo.
Note on font locations - http://stackoverflow.com/a/3955069/311660

A combination of freetype and cairo is definitely going to work out, I may just make a x-platform string/font measuring utility with these two. I'll do some experiments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants