imgui
imgui copied to clipboard
Implement run-time extra line spacing / line gap
This PR address #4578, #2945 feature requests.
Summary
I made a pass over ImGui and prepared necessary patch to support extra spacing in text.
I introduced two new parameters in ImFont:
ExtraLineHeight- by how many pixels line height should be increased, extra space will be equally distributed between top and bottom of the fontExtraLineAdvance- by how many pixels spacing should be increased between consecutive lines of multiline texts, does not affect line height, just move cursor more
Tasks
- [x] Implement
ExtraLineHeight - [x] ~~Implement
ExtraLineAdvance~~ Removed in favor ofExtraLineHeight - [x] Implement
BaselineOffset - [x] Use
FontLineHeightfor vertical axis instead ofFontSize - [ ] Collect feedbak
- [x] Rename
_FontSizeback toFontSize - [ ] Version bump / cleanup
- [ ] Determine course of action with
GetFontXXXfunctions
Preview
ExtraLineHeight=0 ExtraLineAdvance=0 |
![]() |
|---|---|
ExtraLineHeight=8 ExtraLineAdvance=0 |
![]() |
ExtraLineHeight=0 ExtraLineAdvance=8 |
![]() |
ExtraLineHeight=8 ExtraLineAdvance=8 |
![]() |
How atlas generation changed?
Atlas itself isn't affected. Change is entirely run-time only. Also Font scale, window scale and global scale still works as expected.
![]() |
|---|
How does it behave in action?
| https://user-images.githubusercontent.com/1197433/142724958-04c92c42-87ee-4473-b234-6b5322fd368d.mp4 |
|---|
In my use case I would want to use negative values. It may not be advisable to limit the sliders present in the "Hello world!" window to be >= 0.
In my use case I would want to use negative values. It may not be advisable to limit the sliders present in the "Hello world!" window to be >= 0.
Negative values does work, these parameters are not limited to positive values.
Yes, I didn't saw anything in the code which would limit them. This is more about the immediate availability through the UI. It may be of use to some people, considering that most fonts now produce an ugly margin. I don't understand this, as typesetting is hard (let's go shopping) and manually fixing this through these parameters may be the easy way to go.
For example, this is Noto Sans:

And this is Droid Sans of the same size:

If a random comment on reddit is to be believed, these fonts should be rendered without any differences.
If a random comment on reddit is to be believed, these fonts should be rendered without any differences.
They may share outlines, but overall metrics may be changed to better fit purpose they were created for. EM scaling appears to be different between them. That's my theory without looking at font files.
I would definitely appreciate this.
Adding the extra equally on top and bottom would be problematic for me. I'm already using cursor position to fix typography in my Dear ImGui apps, and extra-equally wouldn't fix the issues for me.
Could you split the extra line height into two please? In typography it's common to need line spacing at the bottom only, and ocassionally at the top. If a font has a very low x height for example, it may be desirable to only add space at the bottom because the top of the font may already be very empty.
Another use case is attempting to align a text label with a particular graphic element. Adding spacing at top or bottom would be the most precise way to do that, if it's equal, I'd have to also adjust cursor position any way to compensate.
I think your proposal, with the split, would make my life much easier, as I think it would be less cumbersome that over-riding Dear ImGui's layout.
I think I would add baseline offset rather than two separate spacings. It will allow to achieve the same effect while being more intuitive, I think.
@meshula There is a baseline offset available now

From conversation outside of github.
What value to do see separating LineHeight and LineAdvance?
LineAdvance is used in multiline context allowing to control how much new lines will advance. Can be safetly merged with LineHeight.
Shouldn't some of those values eventually become Style values, but then how we can be shared across multiple font?
Usually user want to tweak single font instance. Moving ExtraLineHeight and BaselineOffset to style would mean user will have to keep these values along with ImFont and remember to change style together with font. This appears to be less user friendly interface, so I put them in ImFont directly.
We already have a GetTextLineHeight() and GetTextLineHeightWithSpacing() btw need to clarify how they differs/overlap with new funcitons
GetFontSize() is used to calculate item width exclusively across ImGui.
GetFontLineHeight() was added for sake of completness. As it turns out GetTextLineHeight() does exactly same thing. GetFontLineHeight() can be safetly removed. GetFontSize() comment could point that is should not be used as font line height and GetTextLineHeight() should be used instead.
GetFontLineAdvance() may be removed if we decide to merge it with line height.
GetFontBaselineOffset() was added for completness, may be safetly removed.
Changes:
- I squashed tiny fixups together
- Pushed a commit that removes ExtraLineAdvance in favor ExtraLineHeight
There is some interaction with how clipper works with these changes.
Setting ExtraLineHeight to a negative value and drawing clipped text lines, like such:
ImGuiListClipper clipper;
clipper.Begin( (int)lines.size() );
while( clipper.Step() )
{
for( auto i=clipper.DisplayStart; i<clipper.DisplayEnd; i++ )
{
ImGui::Text( "text" );
}
}
Produces blank space at the bottom of the visible clipped area.

I cannot reproduce the issue. I tried also putting list in child window.
Is your copy of ImGui older than 1.86 WIP (18510)? Clipper had some bug fixed, if you did cherry-picked this feature to older version of ImGui you still may them.

Is your copy of ImGui older than 1.86 WIP (18510)?
1.86 + docking + this change. This requires resolving conflicts, maybe I did something wrong there?
I cannot reproduce the issue.
This is the font setup I do:
scale = 1.5f;
fixedWidth = io.Fonts->AddFontFromMemoryCompressedTTF( tracy::FiraCodeRetina_compressed_data, tracy::FiraCodeRetina_compressed_size, round( 15.0f * scale ), &configBasic );
fixedWidth->ExtraLineHeight = -5.0f * scale;
With FiraCode 5.2 (https://github.com/tonsky/FiraCode/releases/tag/5.2).
The number of lines has to be significant (2500 in my case).
Ok, i will try to reproduce with that.
In the mean time, you might be interested with a few commits from feature/hidpi-support. Mainly:
- aa4e8efabfeb195c9f7281aa02426df963731b11 - Adds
float ImFontConfig::Density, you get more detailed atlas texture without breaking metrics (this add this and support in embedded stb_truetype) - 44e829f8b1dc562f22476709ad99a707c04ba8d0 - Adds support
float ImFontConfig::Densityin imgui_freetype - 1819260e2549a628e5ed0ff24647a4be194bf6de - Use io.DisplayFramebufferScale to correctly scale AA fringe
There is FiraCode v6.2 available, is there any particular reason to stick to v5.2?
In the mean time, you might be interested with a few commits from feature/hidpi-support. Mainly:
I have hi-dpi support on Windows and Linux by changing font size. What is this feature branch improving here?
There is FiraCode v6.2 available, is there any particular reason to stick to v5.2?
6.0 was not monospace with Freetype, don't know how 6.x works in that regard. I guess 6.2 fixes this?
I have hi-dpi support on Windows and Linux by changing font size. What is this feature branch improving here?
Main perk is you can keep font size constant. UI designed with 1.0f will scale to DPI while staying sharp and mostly where it suppose to be. Photoshop did good job scaling image up, widget borders and primitive fringes are blurry on scaled image.
| 1.0 | 1.0 resized to 1.5 vs. native 1.5 |
|---|---|
![]() |
![]() |
6.0 was not monospace with Freetype, don't know how 6.x works in that regard. I guess 6.2 fixes this?
Release 6.2 appears to fix exactly that: https://github.com/tonsky/FiraCode/releases/tag/6.2 :
- Fixed monospaced property #1325
I reproduced bug, I'm working on a fix.
UI designed with 1.0f will scale to DPI while staying sharp and mostly where it suppose to be.
That's how it currently works. The only platform where it's broken is MacOS (because ImGui behaves differently there).
The image below is a composite of two similar views with different font sizes (50% and 200%). The font size can be dynamically adjusted in run time.

That's how it currently works. The only platform where it's broken is MacOS (because ImGui behaves differently there).
On my branch I made osx example work. Granted this was done with io.DisplayFramebufferScale and ImFontConfig::Density, which my go to solution for DPI problem regardless of platform.
The image below is a composite of two similar views with different font sizes (50% and 200%). The font size can be dynamically adjusted in run time.
Looks like everything in your app is scalable. Cool, this works too.
~~Problem is present on current master branch too. I think I will hunt it there first and then introduce line spacing into the mix.~~
That was totally my derp. It is fixed now.
ImGui isn't happy when font size / line height has fractional part, so scaled metrics are rounded.
Problem is present on current master branch too. I think I will hunt it there first and then introduce line spacing into the mix.
Now that you have said this, I think I had this exact problem on master some time ago. I resorted to just rounding the font size to an integer value.
Anyways, the solution works. I am just rounding the value passed to ExtraLineHeight, so I haven't tested the actual fix.
I have realized that for my use case I need just to set ItemSpacing to 0, e.g.:
ImGui::PushStyleVar( ImGuiStyleVar_ItemSpacing, ImVec2( 0, 0 ) );
Rebased on v1.89 WIP (18808)






