From 1870a779e1c1dcbb518c911df87043092a8548fd Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 8 Apr 2026 20:44:54 +0200 Subject: [PATCH] Windows: fixed a single-axis auto-resizing feedback loop issue with nested containers and varying scrollbar visibility. (#9352) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 6 ++++-- imgui_tables.cpp | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5fd47d3d6..0f2e5e4b5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,6 +51,9 @@ Other Changes: - Fixed issues reporting ideal size to parent window/container: (#9352, #7651) - When both scrollbars are visible but only one of ScrollX/ScrollY was explicitly requested. - When vertical scrollbar was not at the top, the computation was often incorrect. +- Windows: + - Fixed a single-axis auto-resizing feedback loop issue with nested containers + and varying scrollbar visibility. (#9352) - Fonts: - imgui_freetype: add FreeType headers & compiled version in 'About Dear ImGui' details. - Clipper: diff --git a/imgui.cpp b/imgui.cpp index 2bd81364b..2df29975e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6768,8 +6768,10 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont // When the window cannot fit all contents (either because of constraints, either because screen is too small), // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit); - bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x < size_contents.x + size_pad.x + decoration_w_without_scrollbars && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); - bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y < size_contents.y + size_pad.y + decoration_h_without_scrollbars && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); + float size_contents_for_scrollbar_x = (axis_mask & 1) ? size_contents.x : window->ContentSize.x; // See #9352. In theory this should use same logic as `window->ScrollbarY = ...` codepath in Begin(). Needs some plumbling. + float size_contents_for_scrollbar_y = (axis_mask & 2) ? size_contents.y : window->ContentSize.y; + bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x < size_contents_for_scrollbar_x + size_pad.x + decoration_w_without_scrollbars && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); + bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y < size_contents_for_scrollbar_y + size_pad.y + decoration_h_without_scrollbars && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); if (will_have_scrollbar_x) size_auto_fit.y += style.ScrollbarSize; if (will_have_scrollbar_y) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 9257b8d43..f8450fbb1 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1566,7 +1566,7 @@ void ImGui::EndTable() else if (temp_data->UserOuterSize.x <= 0.0f) { // Some references for this: #7651 + tests "table_reported_size", "table_reported_size_outer" equivalent Y block, #9352 - // - FIXME-TABLE: Would make sense to pre-compute expected scrollbar visibility/sizes to generally save a frame of feedback? + // - FIXME-TABLE: Would make sense to pre-compute expected scrollbar visibility/sizes to generally save a frame of feedback? See broken test in 'table_reported_size_outer' const float outer_content_max_x = table->OuterRect.Min.x + table->ColumnsAutoFitWidth; const float decoration_size = table->TempData->AngledHeadersExtraWidth + ((inner_window != outer_window) ? inner_window->ScrollbarSizes.x : 0.0f); outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, outer_content_max_x + decoration_size - temp_data->UserOuterSize.x); @@ -1578,6 +1578,7 @@ void ImGui::EndTable() } if (temp_data->UserOuterSize.y <= 0.0f) { + // (same comment as above) const float outer_content_size_y = (inner_window == outer_window) ? (inner_content_max_y - table->InnerRect.Min.y) : (inner_content_max_y - inner_window->DC.CursorStartPos.y); const float outer_content_max_y = table->OuterRect.Min.y + outer_content_size_y; const float decoration_size = (inner_window != outer_window ? inner_window->ScrollbarSizes.y : 0.0f);