TextBaseOffset increases PrevLineSize beyond the height of buttons even though size is fixed
Version/Branch of Dear ImGui:
Version 1.90.1 : Docking branch
Back-ends:
imgui_impl_glfw.cpp + imgui_impl_openGL.cpp
Compiler, OS:
Window 11 + MSVC 201703
Full config/build information:
Dear ImGui 1.90.1 (19010)
--------------------------------
sizeof(size_t): 8, sizeof(ImDrawIdx): 4, sizeof(ImDrawVert): 20
define: __cplusplus=199711
define: IMGUI_DISABLE_OBSOLETE_KEYIO
define: _WIN32
define: _WIN64
define: _MSC_VER=1944
define: _MSVC_LANG=201703
define: IMGUI_HAS_VIEWPORT
define: IMGUI_HAS_DOCK
--------------------------------
io.BackendPlatformName: imgui_impl_glfw
io.BackendRendererName: imgui_impl_opengl3
io.ConfigFlags: 0x00000068
NavNoCaptureKeyboard
NoMouseCursorChange
DockingEnable
io.ConfigViewportsNoDecoration
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x00001C0E
HasMouseCursors
HasSetMousePos
PlatformHasViewports
HasMouseHoveredViewport
RendererHasVtxOffset
RendererHasViewports
--------------------------------
io.Fonts: 12 fonts, Flags: 0x00000000, TexSize: 1024,2048
io.DisplaySize: 2880.00,1620.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------
style.WindowPadding: 6.00,6.00
style.WindowBorderSize: 0.00
style.FramePadding: 15.00,13.00
style.FrameRounding: 6.00
style.FrameBorderSize: 0.00
style.ItemSpacing: 18.00,4.00
style.ItemInnerSpacing: 15.00,6.00
Details:
Hi, I'm seeing an issue with buttons on the same line where each button increases the line size by a value equivalent to the previous button's framepadding (which determines the textBaseOffset) even though a custom size has been defined for the button. This causes the button to take up more height on the line than what is actually drawn.
This becomes an issue when drawing the buttons inside a child that has the flags AlwaysAutoResize|AutoResizeY or when it's inside a group. As the button creates an invisible gap below it, the child does not resize to visually fit to the height of the button.
It seems that the LineTextBaseOffset logic in ImGui::ItemSize works as intended when the size of the button is calculated from the frame padding, but I can't see why it should extend the "lineSize" beyond the button size when it's been set by a user.
Is there any way I can work around this without having to set the padding to 0 before I draw a widget that will have a sameline after?
Many thanks. Martin
Screenshots/Video:
Here I draw buttons on a line with a defined size of {50,50}. Where every other button has a larger framepadding in the Y axis.
I wrap the buttons in groups to highlight the gap created
The child window with auto resize does not resize to end where the buttons visually end.
Here are some screenshots I put together when trying to find out why some buttons were adding a gap below. It might be helpful
It's not limited to buttons either, Input boxes do the same, but in this case it does not matter as much as the second input does not extend past the current maximum line size.
Here's a real issue I'm dealing with: I use ChildRegions in order to center things vertically, in this case it's the text and the separator. But due to the child not resizing to the visual height of the buttons, the centering doesn't work properly.
My workaround is to define the height of the child to match the buttons visually and add " ImGuiWindowFlags_NoScrollWithMouse| ImGuiWindowFlags_NoScrollbar"
Minimal, Complete and Verifiable Example code:
ImGui::SetNextWindowSize({ 1200,200 }, ImGuiCond_Appearing);
if (ImGui::Begin("ButtonTest", NULL)) {
if (ImGui::BeginChild("Child", {0,0},ImGuiChildFlags_AlwaysAutoResize| ImGuiChildFlags_AutoResizeY)) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, 10 });
ImGui::InputText("##temp", &std::string(""));
ImGui::PopStyleVar();
ImGui::SameLine();
ImVec2 btnSize = { 50,50 };
const int numButtons = 10;
for (size_t i = 0; i < numButtons; i++){
ImGui::BeginGroup();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, 30.f *(i%2)});
ImGui::Button("ABC", btnSize);
ImGui::PopStyleVar();
ImGui::EndGroup();
if (i != numButtons-1) {
ImGui::SameLine();
}
}
}
ImGui::EndChild();
}
ImGui::End();
Thanks for your report. Simplified repro:
if (ImGui::Begin("ButtonTest #8732"))
{
for (int i = 0; i < 3; i++)
{
ImGui::PushID(i);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, 30.f * (i % 2) });
ImGui::Button("ABC", { 50.0f, 50.0f });
ImGui::SameLine();
if (ImGui::IsItemHovered())
ImGui::DebugDrawLineExtents(); // imgui_internal.h
ImGui::PopStyleVar();
ImGui::PopID();
}
ImGui::NewLine();
ImGui::Text("Hello");
}
ImGui::End();
or
if (ImGui::Begin("ButtonTest #8732"))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, 0 });
ImGui::Button("ABC0", { 50.0f, 50.0f });
if (ImGui::IsItemHovered())
ImGui::DebugDrawLineExtents(); // imgui_internal.h
ImGui::PopStyleVar();
ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, 30 });
ImGui::Button("ABC1", { 50.0f, 50.0f });
if (ImGui::IsItemHovered())
ImGui::DebugDrawLineExtents(); // imgui_internal.h
ImGui::PopStyleVar();
ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, 0 });
ImGui::Button("ABC2", { 50.0f, 50.0f });
if (ImGui::IsItemHovered())
ImGui::DebugDrawLineExtents(); // imgui_internal.h
ImGui::PopStyleVar();
}
ImGui::End();
For reference this is caused by ec0e953c for #2833, but the correct change is not yet obvious to me.
Setting offset_to_match_baseline_y = 0.0f fixes the case here but break e.g. the "layout_baseline_and_cursormax" test which is the one visible in #2833.
I pretty much have the fix for this but I don't have a good path for integrating it short-term.
(1) The simple path would involve making ItemSize(ImRect& r) the primary ItemSize function, and have widgets using it instead of ItemSize(ImVec2& ) and more correctly honoring cases where r.Min != window->DC.CursorPos.
This is what's done in this simplified patch:
imgui-36eec16-item size fix for 8732.patch imgui-efa5c88-tests code.patch
(2) This causes a unfortunate problem, where inferring size from r.Max - r.Min exacerbate some floating point precision issues (which normally are mitigated in various places). As a result, e.g. the "misc_clipper_floating_point_precision" regression test in imgui_test_suite fails.
(3) In theory I could today make it new signature e.g ItemLayout(pos, size) and this would solve this immediately, but a new signature/design for the ItemSize/ItemAdd combo is part of a much bigger long-awaited refactor and I don't think it is great idea to change it twice, as calls to the new signature would be visible in all widgets and would easily spread, even if internal.
I believe the best I can do right now if I try to move forward with that planned refactor.