Subject: bug#71039: :box :line-width and :underline :position should accept fractional sizes

From: Eli Zaretskii <[email-masked]>
Date: Sun, 19 May 2024 09:37:19 +0300

> From: JD Smith <[email-masked]>
> Date: Sat, 18 May 2024 21:32:23 -0400
> Cc: [email-masked]
> 
> > Are you sure this is a good idea?  
> 
> Definitely!  I've spent a good bit of time working around the absence of this feature (and, while I found solutions, they were too convoluted to be practical).
> 
> > What would you like this to do when
> > two adjacent runs of text are shown using different-size fonts (which
> > AFAIU is the main use case for this feature)?  
> 
> They'd have different height boxes, and that would be the desired effect.  Sort of the same idea as something like:
> 
> (insert "\n"
>         (propertize " Short " 'face '(:box (:line-width (0 . -4)) :inverse-video t))
>         (propertize " BOX " 'face '(:box (:line-width (0 . -2)) :inverse-video t))
>         (propertize " tall box " 'face '(:box (:line-width (1 . 1))))
>         "\n")
> 
> except also adaptive to the text height.  Normally of course you would not do this for random text.  Instead you'd apply targeted floating :box widths to short stretches of text, like labels.

I think it will look ugly, but I guess to each their own.

Anyway, the line width is stored in the face structure when the face
is realized, and kept there for when the box face needs to be drawn.
If the values are relative, the drawing back-end will need to compute
the corresponding absolute width values by accessing the font metrics
(or is it the height of the screen line?) at draw time.  And we will
need to do that for all the back-ends we have.  Patches welcome.

> I'm confident they'd be used quite a lot.  Do you have a sense of how difficult these improvements would be?  Since you can already now apply fractional specified space like (space :width (0.25 . width)), I was hopeful the calculations would be close at hand.

The space width is calculated in the back-end-independent part of the
display code (xdisp.c), because it yields a stretch glyph of a certain
width (which is later drawn on screen as a stretch of background
color).  By contrast, the box face is implemented in back-end code
(*term.c), since it needs to draw lines using the display-specific
APIs.  So we cannot use the same code in these two cases.

> What the above proposal would do is allow you to specify the box width separately on all 4 sides of the affected text: left, right, top, and bottom.  So for example:
> 
> 	:line-width (4 0 -0.25 -0.1)
> 
> would push the box 4 pixel to the left, and pull the box down from the top more than up from the bottom. As a related idea, following your suggestion, you could keep :line-width as-is and add a :box :position attribute that shifts the box vertically (which would be the same except symmetric left/right).  
> 
> The floating point width is probably more important, but this would enable some useful effects like simple text-based progress bars, etc. 

This will need to extend the face structure to store 4 line thickness
values, not 2 as we do today.