unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#71039: :box :line-width and :underline :position should accept fractional sizes
@ 2024-05-18 14:52 JD Smith
  2024-05-18 16:06 ` Eli Zaretskii
  0 siblings, 1 reply; 5+ messages in thread
From: JD Smith @ 2024-05-18 14:52 UTC (permalink / raw)
  To: 71039

[-- Attachment #1: Type: text/plain, Size: 1130 bytes --]


For modes which layout mostly on fixed character-width grids, it is convenient to preserve that layout even as the text-scale changes.  Most of the size related attributes associated with display and face properties accommodate this style well, since they accept floating point values which adapt to the underlying char size.  These include face height, display height and raise, specified space dimensions, etc.   

There are, however, two face size attributes which are hard-coded in pixels: :box :linewidth and :underline :position.  It would be very convenient if these also accepted fractional floating point values.  E.g. a face attribute of:

:box (:line-width (0.5 . -0.25)) 

would indicate a box with half a char width outside padding left & right, and one-quarter char height padding above and below.

In addition, :box would be even more powerful, and obviate the use of SVG styling in many situations, if :box :line-width optionally accepted a list of four parameters for box dimensions, one for each side:

:line-width (left right top bottom)

naturally as either pixel or floating point fractions.


[-- Attachment #2: Type: text/html, Size: 1699 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* bug#71039: :box :line-width and :underline :position should accept fractional sizes
  2024-05-18 14:52 bug#71039: :box :line-width and :underline :position should accept fractional sizes JD Smith
@ 2024-05-18 16:06 ` Eli Zaretskii
  2024-05-19  1:32   ` JD Smith
  0 siblings, 1 reply; 5+ messages in thread
From: Eli Zaretskii @ 2024-05-18 16:06 UTC (permalink / raw)
  To: JD Smith; +Cc: 71039

> From: JD Smith <jdtsmith@gmail.com>
> Date: Sat, 18 May 2024 10:52:03 -0400
> 
> There are, however, two face size attributes which are hard-coded in pixels: :box :linewidth and :underline :
> position.  It would be very convenient if these also accepted fractional floating point values.  E.g. a face
> attribute of:
> 
>  :box (:line-width (0.5 . -0.25)) 
> 
> would indicate a box with half a char width outside padding left & right, and one-quarter char height padding
> above and below.

Are you sure this is a good idea?  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)?  We currently force the
thickness and position of the underline to be identical for all the
characters of a stretch of underlined text, even if they are displayed
using different fonts, and we take those values from the first part of
the underlined text's stretch.  This is because having the underline
break or show differently in the middle of an underlined text has ugly
appearance.

OTOH, calculating the thickness and position in pixels from the face
font's dimensions is easy enough if your code needs that.

Given these two facts, I'm not sure supporting float values here will
be worth the effort.

> In addition, :box would be even more powerful, and obviate the use of SVG styling in many situations, if :box :
> line-width optionally accepted a list of four parameters for box dimensions, one for each side:
> 
>  :line-width (left right top bottom)
> 
> naturally as either pixel or floating point fractions.

How is this different from specifying the thickness and the position,
as we have today?





^ permalink raw reply	[flat|nested] 5+ messages in thread

* bug#71039: :box :line-width and :underline :position should accept fractional sizes
  2024-05-18 16:06 ` Eli Zaretskii
@ 2024-05-19  1:32   ` JD Smith
  2024-05-19  6:37     ` Eli Zaretskii
  0 siblings, 1 reply; 5+ messages in thread
From: JD Smith @ 2024-05-19  1:32 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71039



> On May 18, 2024, at 12:06 PM, Eli Zaretskii <eliz@gnu.org> wrote:
> 
>> From: JD Smith <jdtsmith@gmail.com>
>> Date: Sat, 18 May 2024 10:52:03 -0400
>> 
>> There are, however, two face size attributes which are hard-coded in pixels: :box :linewidth and :underline :
>> position.  It would be very convenient if these also accepted fractional floating point values.  E.g. a face
>> attribute of:
>> 
>> :box (:line-width (0.5 . -0.25)) 
>> 
>> would indicate a box with half a char width outside padding left & right, and one-quarter char height padding
>> above and below.
> 
> 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.

> We currently force the
> thickness and position of the underline to be identical for all the
> characters of a stretch of underlined text, even if they are displayed
> using different fonts, and we take those values from the first part of
> the underlined text's stretch.  This is because having the underline
> break or show differently in the middle of an underlined text has ugly
> appearance.

I wan't aware of this behavior, but I do see the value in that special rule for underlines.  It's possible that pixel position indeed makes the most sense for underline, given the face-merging behavior you describe.  I included it mostly for completeness.

More important is :box.  For various effects which cover short stretches of text like label boxes, etc., the ability to have the box thickness scale with char size would be very useful.  Often these use inverse-video, so that the "box" is in the background color.  Many packages reach for SVG images in this context, but with a little help, many of those uses could be avoided.

> OTOH, calculating the thickness and position in pixels from the face
> font's dimensions is easy enough if your code needs that.

Sure, but upon text-scaling, this calculation needs to be performed again (probably in a temporary buffer, and across many faces).  Then, per-buffer face remaps must be applied and managed, etc.   I've done that, but it's a lot to juggle for a simple box.

> Given these two facts, I'm not sure supporting float values here will
> be worth the effort.

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.

>> In addition, :box would be even more powerful, and obviate the use of SVG styling in many situations, if :box :
>> line-width optionally accepted a list of four parameters for box dimensions, one for each side:
>> 
>> :line-width (left right top bottom)
>> 
>> naturally as either pixel or floating point fractions.
> 
> How is this different from specifying the thickness and the position,
> as we have today?

AFAIU there is no :position offset for :box?  Right now, :box can specify thickness as a fixed number of pixels outside (or inside, if negative) the character(s), and in recent versions these widths can differ vertically and horizontally.  But boxes are always centered horizontally on the boxed text and vertically on the line (including any line-spacing).

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. 




^ permalink raw reply	[flat|nested] 5+ messages in thread

* bug#71039: :box :line-width and :underline :position should accept fractional sizes
  2024-05-19  1:32   ` JD Smith
@ 2024-05-19  6:37     ` Eli Zaretskii
  2024-05-19 13:45       ` JD Smith
  0 siblings, 1 reply; 5+ messages in thread
From: Eli Zaretskii @ 2024-05-19  6:37 UTC (permalink / raw)
  To: JD Smith; +Cc: 71039

> From: JD Smith <jdtsmith@gmail.com>
> Date: Sat, 18 May 2024 21:32:23 -0400
> Cc: 71039@debbugs.gnu.org
> 
> > 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.





^ permalink raw reply	[flat|nested] 5+ messages in thread

* bug#71039: :box :line-width and :underline :position should accept fractional sizes
  2024-05-19  6:37     ` Eli Zaretskii
@ 2024-05-19 13:45       ` JD Smith
  0 siblings, 0 replies; 5+ messages in thread
From: JD Smith @ 2024-05-19 13:45 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 71039



> On May 19, 2024, at 2:37 AM, Eli Zaretskii <eliz@gnu.org> wrote:
> 
>>  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.

That's just a random example, not meant for appearance evaluation ;).  It's already the idea used for popular packages like org-modern (with some difficulty resulting from the limitations of :box).  The basic idea is to give more flexibility for box placement, which will open up many uses.

> 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

I guess this is how face must already handle :height, selecting a font based on that (after inheritance, and multiplying all the :height's together).  Perhaps turning fractional box size into pixel values could make use of that work?  Surely that is not back-end dependent.

> (or is it the height of the screen line?) at draw time.  

Ideally the fractional box widths would be relative to the font size itself, but I think line height would also be fine, if that were simpler and more performant.

>> 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.

I see, thanks.  Given that, it would probably be worthwhile to get broader input on what types of back-end dependent screen drawing improvements would be valuable for faces.

>> 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.

Or 3, if the :position flavor were deemed superior.  

Thanks for the information.






^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-05-19 13:45 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-18 14:52 bug#71039: :box :line-width and :underline :position should accept fractional sizes JD Smith
2024-05-18 16:06 ` Eli Zaretskii
2024-05-19  1:32   ` JD Smith
2024-05-19  6:37     ` Eli Zaretskii
2024-05-19 13:45       ` JD Smith

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).