From 86daa8930e3b8ca9e75fac7307a1181e740c064a Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Nov 2025 13:24:10 +0100 Subject: [PATCH 1/8] Backends, Examples: WebGPU: simplified ifndef (#8381) --- backends/imgui_impl_wgpu.cpp | 4 ++-- backends/imgui_impl_wgpu.h | 4 ++-- examples/example_glfw_wgpu/main.cpp | 4 ++-- examples/example_sdl2_wgpu/main.cpp | 4 ++-- examples/example_sdl3_wgpu/main.cpp | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 86c30cfd4..47c31726b 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -1015,7 +1015,7 @@ void ImGui_ImplWGPU_DebugPrintAdapterInfo(const WGPUAdapter& adapter) wgpuAdapterInfoFreeMembers(info); } -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) && !defined(__EMSCRIPTEN__) +#ifndef __EMSCRIPTEN__ #if defined(__APPLE__) // MacOS specific: is necessary to compile with "-x objective-c++" flags @@ -1079,7 +1079,7 @@ WGPUSurface ImGui_ImplWGPU_CreateWGPUSurfaceHelper(ImGui_ImplWGPU_CreateSurfaceI #endif return surface; } -#endif +#endif // #ifndef __EMSCRIPTEN__ //----------------------------------------------------------------------------- diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index 3d0cf5cc1..f17fe6c25 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -105,7 +105,7 @@ const char* ImGui_ImplWGPU_GetLogLevelName(WGPULogLevel level); #endif // (Optional) Helper to create a surface on macOS/Wayland/X11/Window -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) && !defined(__EMSCRIPTEN__) +#ifndef __EMSCRIPTEN__ struct ImGui_ImplWGPU_CreateSurfaceInfo { WGPUInstance Instance; @@ -116,6 +116,6 @@ struct ImGui_ImplWGPU_CreateSurfaceInfo void* RawInstance; // 0 | 0 | 0 | HINSTANCE }; WGPUSurface ImGui_ImplWGPU_CreateWGPUSurfaceHelper(ImGui_ImplWGPU_CreateSurfaceInfo* info); -#endif +#endif // #ifndef __EMSCRIPTEN__ #endif // #ifndef IMGUI_DISABLE diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp index 2fd746903..ad64ef403 100644 --- a/examples/example_glfw_wgpu/main.cpp +++ b/examples/example_glfw_wgpu/main.cpp @@ -506,7 +506,7 @@ static bool InitWGPU(GLFWwindow* window) // As of today (2025/10) there is no "official" support in GLFW to create a surface for WebGPU backend // This stub uses "low level" GLFW calls to acquire information from a specific Window Manager. // Currently supported platforms: Windows / Linux (X11 and Wayland) / MacOS. Not necessary nor available with EMSCRIPTEN. -#if !defined(__EMSCRIPTEN__) && (defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)) +#ifndef __EMSCRIPTEN__ #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) #define GLFW_HAS_X11_OR_WAYLAND 1 @@ -573,4 +573,4 @@ WGPUSurface CreateWGPUSurface(const WGPUInstance& instance, GLFWwindow* window) #endif return nullptr; } -#endif +#endif // #ifndef __EMSCRIPTEN__ diff --git a/examples/example_sdl2_wgpu/main.cpp b/examples/example_sdl2_wgpu/main.cpp index bddc91b39..d4b9a021b 100644 --- a/examples/example_sdl2_wgpu/main.cpp +++ b/examples/example_sdl2_wgpu/main.cpp @@ -491,7 +491,7 @@ static bool InitWGPU(SDL_Window* window) // As of today (2025/10/31) there is no "official" support in SDL2 to create a surface for WebGPU backend. // This stub uses "low level" SDL2 calls to acquire information from a specific Window Manager. // Currently supported platforms: Windows / Linux (X11 and Wayland) / MacOS. Not necessary nor available with EMSCRIPTEN. -#if !defined(__EMSCRIPTEN__) && (defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)) +#ifndef __EMSCRIPTEN__ #include #undef Status // X11 headers are leaking this and also 'Success', 'Always', 'None', all used in DAWN api. Add #undef if necessary. @@ -538,4 +538,4 @@ WGPUSurface CreateWGPUSurface(const WGPUInstance& instance, SDL_Window* window) #endif return nullptr; } -#endif +#endif // #ifndef __EMSCRIPTEN__ diff --git a/examples/example_sdl3_wgpu/main.cpp b/examples/example_sdl3_wgpu/main.cpp index abfbf6cfa..d56b703c0 100644 --- a/examples/example_sdl3_wgpu/main.cpp +++ b/examples/example_sdl3_wgpu/main.cpp @@ -502,7 +502,7 @@ static bool InitWGPU(SDL_Window* window) // As of today (2025/10) there is no "official" support in SDL3 to create a surface for WebGPU backend // This stub uses "low level" SDL3 calls to acquire information from a specific Window Manager. // Currently supported platforms: Windows / Linux (X11 and Wayland) / MacOS. Not necessary nor available with EMSCRIPTEN. -#if !defined(__EMSCRIPTEN__) && (defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)) +#ifndef __EMSCRIPTEN__ #if defined(SDL_PLATFORM_WIN32) #ifndef WIN32_LEAN_AND_MEAN @@ -550,4 +550,4 @@ static WGPUSurface CreateWGPUSurface(const WGPUInstance& instance, SDL_Window* w #endif return nullptr; } -#endif +#endif // #ifndef __EMSCRIPTEN__ From 7537ba2b4424b6bde2d77e3b423737230c02a4ad Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Nov 2025 19:36:16 +0100 Subject: [PATCH 2/8] Windows: fixed single-axis auto-sizing (via double-clicking a border) to take account of remaining scrollbar on the other axis. (#9060) Potentially now should apply same logic to the other resizing path also described in #9060 --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 21 ++++++++++++--------- imgui.h | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3bab14762..dbc2c51be 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -71,6 +71,8 @@ Other Changes: - Windows: io.ConfigWindowsMoveFromTitleBarOnly is latched during Begin(), effectively allowing to change the value on a per-window basis (although there is a better internal mechanism for it). +- Windows: fixed single-axis auto-sizing (via double-clicking a border) to + take account of remaining scrollbar on the other axis. (#9060) - Disabled: fixed a bug when a previously enabled item that got nav focus and then turns disabled could still be activated using keyboard. (#9036) - InputText: when buffer is not resizable, trying to paste contents that diff --git a/imgui.cpp b/imgui.cpp index b71c539cc..c1415483c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1338,7 +1338,7 @@ static void UpdateFontsEndFrame(); static void UpdateTexturesNewFrame(); static void UpdateTexturesEndFrame(); static void UpdateSettings(); -static int UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_hovered, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); +static int UpdateWindowManualResize(ImGuiWindow* window, int* border_hovered, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); static void RenderWindowOuterBorders(ImGuiWindow* window); static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); @@ -6625,14 +6625,16 @@ static void CalcWindowContentSizes(ImGuiWindow* window, ImVec2* content_size_cur content_size_ideal->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : ImTrunc64(ImMax(window->DC.CursorMaxPos.y, window->DC.IdealMaxPos.y) - window->DC.CursorStartPos.y); } -static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents) +static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents, int axis_mask) { ImGuiContext& g = *GImGui; ImGuiStyle& style = g.Style; const float decoration_w_without_scrollbars = window->DecoOuterSizeX1 + window->DecoOuterSizeX2 - window->ScrollbarSizes.x; const float decoration_h_without_scrollbars = window->DecoOuterSizeY1 + window->DecoOuterSizeY2 - window->ScrollbarSizes.y; ImVec2 size_pad = window->WindowPadding * 2.0f; - ImVec2 size_desired = size_contents + size_pad + ImVec2(decoration_w_without_scrollbars, decoration_h_without_scrollbars); + ImVec2 size_desired; + size_desired[ImGuiAxis_X] = (axis_mask & 1) ? size_contents.x + size_pad.x + decoration_w_without_scrollbars : window->Size.x; + size_desired[ImGuiAxis_Y] = (axis_mask & 2) ? size_contents.y + size_pad.y + decoration_h_without_scrollbars : window->Size.y; // Determine maximum window size // Child windows are layed within their parent (unless they are also popups/menus) and thus have no restriction @@ -6674,7 +6676,7 @@ ImVec2 ImGui::CalcWindowNextAutoFitSize(ImGuiWindow* window) ImVec2 size_contents_current; ImVec2 size_contents_ideal; CalcWindowContentSizes(window, &size_contents_current, &size_contents_ideal); - ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents_ideal); + ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents_ideal, ~0); ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit); return size_final; } @@ -6780,7 +6782,7 @@ ImGuiID ImGui::GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir) // Handle resize for: Resize Grips, Borders, Gamepad // Return true when using auto-fit (double-click on resize grip) -static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_hovered, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect) +static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, int* border_hovered, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect) { ImGuiContext& g = *GImGui; ImGuiWindowFlags flags = window->Flags; @@ -6830,6 +6832,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si if (held && g.IO.MouseDoubleClicked[0]) { // Auto-fit when double-clicking + ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal, ~0); size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit); ret_auto_fit_mask = 0x03; // Both axes ClearActiveID(); @@ -6876,10 +6879,10 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si if (held && g.IO.MouseDoubleClicked[0]) { // Double-clicking bottom or right border auto-fit on this axis - // FIXME: CalcWindowAutoFitSize() doesn't take into account that only one side may be auto-fit when calculating scrollbars. // FIXME: Support top and right borders: rework CalcResizePosSizeFromAnyCorner() to be reusable in both cases. if (border_n == 1 || border_n == 3) // Right and bottom border { + ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal, 1 << axis); size_target[axis] = CalcWindowSizeAfterConstraint(window, size_auto_fit)[axis]; ret_auto_fit_mask |= (1 << axis); hovered = held = false; // So border doesn't show highlighted at new position @@ -7575,7 +7578,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->ScrollbarSizes = ImVec2(0.0f, 0.0f); // Calculate auto-fit size, handle automatic resize - const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal); + const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal, ~0); if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) { // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. @@ -7708,7 +7711,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const float resize_grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); if (handle_borders_and_resize_grips && !window->Collapsed) - if (int auto_fit_mask = UpdateWindowManualResize(window, size_auto_fit, &border_hovered, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) + if (int auto_fit_mask = UpdateWindowManualResize(window, &border_hovered, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) { if (auto_fit_mask & (1 << ImGuiAxis_X)) use_current_size_for_scrollbar_x = true; @@ -7958,7 +7961,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) g.TooltipPreviousWindow = window; // Set default BgClickFlags - // This is set at the end of this function, so UpdateManualResize()/ClampWindowPos() may use last-frame value if overriden by user code. + // This is set at the end of this function, so UpdateWindowManualResize()/ClampWindowPos() may use last-frame value if overriden by user code. // FIXME: The general intent is that we will later expose config options to default to enable scrolling + select scrolling mouse button. window->BgClickFlags = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->BgClickFlags : (g.IO.ConfigWindowsMoveFromTitleBarOnly ? ImGuiWindowBgClickFlags_None : ImGuiWindowBgClickFlags_Move); diff --git a/imgui.h b/imgui.h index 81774857f..9990253de 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.5 WIP" -#define IMGUI_VERSION_NUM 19244 +#define IMGUI_VERSION_NUM 19245 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 From fc262355ca214bc1d03573807aabb9477306aa2f Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Nov 2025 19:40:24 +0100 Subject: [PATCH 3/8] Windows: Fixed an issue where repeated calls to SetNextWindowSize() using 0.0f to auto-size would keep marking ini settings as dirty. + marking dirty on old io.FontAllowUserScaling Ctrl+Wheel --- docs/CHANGELOG.txt | 13 ++++++++----- imgui.cpp | 14 ++++++++------ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index dbc2c51be..7a3ff9019 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -68,11 +68,14 @@ Other Changes: - Tables: Angled headers: fixed an auto-resize feedback loop that could affect tables with empty non-resizing columns using angled headers, making them typically flicker back and forth between +0 and +1 pixels. -- Windows: io.ConfigWindowsMoveFromTitleBarOnly is latched during Begin(), - effectively allowing to change the value on a per-window basis (although - there is a better internal mechanism for it). -- Windows: fixed single-axis auto-sizing (via double-clicking a border) to - take account of remaining scrollbar on the other axis. (#9060) +- Windows: + - Config flag io.ConfigWindowsMoveFromTitleBarOnly is now latched during + Begin(), effectively allowing to change the value on a per-window basis. + (although there is a better internal mechanism for it). + - Fixed single-axis auto-sizing (via double-clicking a border) to + take account of remaining scrollbar on the other axis. (#9060) + - Fixed an issue where repeated calls to SetNextWindowSize() using 0.0f + to auto-size on a given axis would keep marking ini settings as dirty. - Disabled: fixed a bug when a previously enabled item that got nav focus and then turns disabled could still be activated using keyboard. (#9036) - InputText: when buffer is not resizable, trying to paste contents that diff --git a/imgui.cpp b/imgui.cpp index c1415483c..80aa77d10 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6968,8 +6968,8 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, int* border_hove } // Apply back modified position/size to window - const ImVec2 curr_pos = window->Pos; - const ImVec2 curr_size = window->SizeFull; + const ImVec2 old_pos = window->Pos; + const ImVec2 old_size = window->SizeFull; if (size_target.x != FLT_MAX && (window->Size.x != size_target.x || window->SizeFull.x != size_target.x)) window->Size.x = window->SizeFull.x = size_target.x; if (size_target.y != FLT_MAX && (window->Size.y != size_target.y || window->SizeFull.y != size_target.y)) @@ -6978,7 +6978,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, int* border_hove window->Pos.x = ImTrunc(pos_target.x); if (pos_target.y != FLT_MAX && window->Pos.y != ImTrunc(pos_target.y)) window->Pos.y = ImTrunc(pos_target.y); - if (curr_pos.x != window->Pos.x || curr_pos.y != window->Pos.y || curr_size.x != window->SizeFull.x || curr_size.y != window->SizeFull.y) + if (old_pos.x != window->Pos.x || old_pos.y != window->Pos.y || old_size.x != window->SizeFull.x || old_size.y != window->SizeFull.y) MarkIniSettingsDirty(window); // Recalculate next expected border expected coordinates @@ -7579,6 +7579,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Calculate auto-fit size, handle automatic resize const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal, ~0); + const ImVec2 old_size = window->SizeFull; if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) { // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. @@ -7607,9 +7608,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; use_current_size_for_scrollbar_y = true; } - if (!window->Collapsed) - MarkIniSettingsDirty(window); } + if (old_size.x != window->SizeFull.x || old_size.y != window->SizeFull.y) + MarkIniSettingsDirty(window); // Apply minimum/maximum window size constraints and final size window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull); @@ -10220,8 +10221,9 @@ void ImGui::UpdateMouseWheel() { const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; SetWindowPos(window, window->Pos + offset, 0); - window->Size = ImTrunc(window->Size * scale); + window->Size = ImTrunc(window->Size * scale); // FIXME: Legacy-ish code, call SetWindowSize()? window->SizeFull = ImTrunc(window->SizeFull * scale); + MarkIniSettingsDirty(window); } return; } From 52e9d94f93a1f05155a03b0bbeaa221ecbd9e7f1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Nov 2025 20:01:07 +0100 Subject: [PATCH 4/8] Windows: reorganize auto-fitting code blocks in Begin(), aimed to have no side-effect, but.. ..outer ImGuiWindowFlags_AlwaysAutoResize previously took priority for both axis. New logic per-axis. Toward #9060 --- imgui.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 80aa77d10..99e2f496f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7578,32 +7578,32 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->ScrollbarSizes = ImVec2(0.0f, 0.0f); // Calculate auto-fit size, handle automatic resize + // - Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. + // - We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. + // - Auto-fit may only grow window during the first few frames. const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal, ~0); const ImVec2 old_size = window->SizeFull; - if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) + if (!window_size_x_set_by_api) { - // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. - if (!window_size_x_set_by_api) + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) { window->SizeFull.x = size_auto_fit.x; use_current_size_for_scrollbar_x = true; } - if (!window_size_y_set_by_api) - { - window->SizeFull.y = size_auto_fit.y; - use_current_size_for_scrollbar_y = true; - } - } - else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) - { - // Auto-fit may only grow window during the first few frames - // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. - if (!window_size_x_set_by_api && window->AutoFitFramesX > 0) + else if (window->AutoFitFramesX > 0) { window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; use_current_size_for_scrollbar_x = true; } - if (!window_size_y_set_by_api && window->AutoFitFramesY > 0) + } + if (!window_size_y_set_by_api) + { + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) + { + window->SizeFull.y = size_auto_fit.y; + use_current_size_for_scrollbar_y = true; + } + else if (window->AutoFitFramesY > 0) { window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; use_current_size_for_scrollbar_y = true; From b51f6e073c9b31b9672f75d194768247b9344137 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Nov 2025 21:15:43 +0100 Subject: [PATCH 5/8] Windows: reorganize auto-fitting code blocks in Begin(), step 2. Toward #9060 --- imgui.cpp | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 99e2f496f..2c5c73885 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7581,33 +7581,28 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. // - We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. // - Auto-fit may only grow window during the first few frames. + const bool size_auto_fit_x_always = !window_size_x_set_by_api && (flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed; + const bool size_auto_fit_y_always = !window_size_y_set_by_api && (flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed; + const bool size_auto_fit_x_current = !window_size_x_set_by_api && (window->AutoFitFramesX > 0); + const bool size_auto_fit_y_current = !window_size_y_set_by_api && (window->AutoFitFramesY > 0); const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal, ~0); + const ImVec2 old_size = window->SizeFull; - if (!window_size_x_set_by_api) + if (size_auto_fit_x_always || size_auto_fit_x_current) { - if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) - { + if (size_auto_fit_x_always) window->SizeFull.x = size_auto_fit.x; - use_current_size_for_scrollbar_x = true; - } - else if (window->AutoFitFramesX > 0) - { + else window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; - use_current_size_for_scrollbar_x = true; - } + use_current_size_for_scrollbar_x = true; } - if (!window_size_y_set_by_api) + if (size_auto_fit_y_always || size_auto_fit_y_current) { - if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) - { + if (size_auto_fit_y_always) window->SizeFull.y = size_auto_fit.y; - use_current_size_for_scrollbar_y = true; - } - else if (window->AutoFitFramesY > 0) - { + else window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; - use_current_size_for_scrollbar_y = true; - } + use_current_size_for_scrollbar_y = true; } if (old_size.x != window->SizeFull.x || old_size.y != window->SizeFull.y) MarkIniSettingsDirty(window); From a2544f94962ef83c1ea5873cc106d100958715bc Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Nov 2025 21:37:21 +0100 Subject: [PATCH 6/8] Windows: programmatic auto-sizing on a single axis also apply proper logic. (#9060) --- docs/CHANGELOG.txt | 5 +++-- imgui.cpp | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7a3ff9019..e14d32a1a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,8 +72,9 @@ Other Changes: - Config flag io.ConfigWindowsMoveFromTitleBarOnly is now latched during Begin(), effectively allowing to change the value on a per-window basis. (although there is a better internal mechanism for it). - - Fixed single-axis auto-sizing (via double-clicking a border) to - take account of remaining scrollbar on the other axis. (#9060) + - Fixed single-axis auto-sizing (via double-clicking a border or passing + 0.0f on one axis of SetNextWindowSize() call) to take account of remaining + scrollbar on the other axis. (#9060) - Fixed an issue where repeated calls to SetNextWindowSize() using 0.0f to auto-size on a given axis would keep marking ini settings as dirty. - Disabled: fixed a bug when a previously enabled item that got nav focus diff --git a/imgui.cpp b/imgui.cpp index 2c5c73885..949f140ba 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7585,7 +7585,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const bool size_auto_fit_y_always = !window_size_y_set_by_api && (flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed; const bool size_auto_fit_x_current = !window_size_x_set_by_api && (window->AutoFitFramesX > 0); const bool size_auto_fit_y_current = !window_size_y_set_by_api && (window->AutoFitFramesY > 0); - const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal, ~0); + int size_auto_fit_mask = 0; + if (size_auto_fit_x_always || size_auto_fit_x_current) + size_auto_fit_mask |= (1 << ImGuiAxis_X); + if (size_auto_fit_y_always || size_auto_fit_y_current) + size_auto_fit_mask |= (1 << ImGuiAxis_Y); + const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal, size_auto_fit_mask); const ImVec2 old_size = window->SizeFull; if (size_auto_fit_x_always || size_auto_fit_x_current) From 501e0adcdbb6cb0bf0f2ea7a963b8114d3ac408e Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Nov 2025 21:47:15 +0100 Subject: [PATCH 7/8] Windows: CalcWindowAutoFitSize() remove child-specific hack added by 29439bdd27 and made obsolete by 7537ba2b4. (#9060, #1710) --- imgui.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 949f140ba..e195c3bc1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6650,14 +6650,6 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont ImVec2 size_min = CalcWindowMinSize(window); ImVec2 size_auto_fit = ImClamp(size_desired, ImMin(size_min, size_max), size_max); - // FIXME: CalcWindowAutoFitSize() doesn't take into account that only one axis may be auto-fit when calculating scrollbars, - // we may need to compute/store three variants of size_auto_fit, for x/y/xy. - // Here we implement a workaround for child windows only, but a full solution would apply to normal windows as well: - if ((window->ChildFlags & ImGuiChildFlags_ResizeX) && !(window->ChildFlags & (ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeY))) - size_auto_fit.y = window->SizeFull.y; - else if ((window->ChildFlags & ImGuiChildFlags_ResizeY) && !(window->ChildFlags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_AutoResizeX))) - size_auto_fit.x = window->SizeFull.x; - // 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); From de917ebb95830b0a31a0332a95d2babff82b109b Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Nov 2025 21:48:17 +0100 Subject: [PATCH 8/8] Windows: move auto-fit block into braces for clarify. (no-op) --- imgui.cpp | 58 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e195c3bc1..a43dd0097 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7573,36 +7573,38 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. // - We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. // - Auto-fit may only grow window during the first few frames. - const bool size_auto_fit_x_always = !window_size_x_set_by_api && (flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed; - const bool size_auto_fit_y_always = !window_size_y_set_by_api && (flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed; - const bool size_auto_fit_x_current = !window_size_x_set_by_api && (window->AutoFitFramesX > 0); - const bool size_auto_fit_y_current = !window_size_y_set_by_api && (window->AutoFitFramesY > 0); - int size_auto_fit_mask = 0; - if (size_auto_fit_x_always || size_auto_fit_x_current) - size_auto_fit_mask |= (1 << ImGuiAxis_X); - if (size_auto_fit_y_always || size_auto_fit_y_current) - size_auto_fit_mask |= (1 << ImGuiAxis_Y); - const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal, size_auto_fit_mask); + { + const bool size_auto_fit_x_always = !window_size_x_set_by_api && (flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed; + const bool size_auto_fit_y_always = !window_size_y_set_by_api && (flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed; + const bool size_auto_fit_x_current = !window_size_x_set_by_api && (window->AutoFitFramesX > 0); + const bool size_auto_fit_y_current = !window_size_y_set_by_api && (window->AutoFitFramesY > 0); + int size_auto_fit_mask = 0; + if (size_auto_fit_x_always || size_auto_fit_x_current) + size_auto_fit_mask |= (1 << ImGuiAxis_X); + if (size_auto_fit_y_always || size_auto_fit_y_current) + size_auto_fit_mask |= (1 << ImGuiAxis_Y); + const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal, size_auto_fit_mask); - const ImVec2 old_size = window->SizeFull; - if (size_auto_fit_x_always || size_auto_fit_x_current) - { - if (size_auto_fit_x_always) - window->SizeFull.x = size_auto_fit.x; - else - window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; - use_current_size_for_scrollbar_x = true; + const ImVec2 old_size = window->SizeFull; + if (size_auto_fit_x_always || size_auto_fit_x_current) + { + if (size_auto_fit_x_always) + window->SizeFull.x = size_auto_fit.x; + else + window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; + use_current_size_for_scrollbar_x = true; + } + if (size_auto_fit_y_always || size_auto_fit_y_current) + { + if (size_auto_fit_y_always) + window->SizeFull.y = size_auto_fit.y; + else + window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; + use_current_size_for_scrollbar_y = true; + } + if (old_size.x != window->SizeFull.x || old_size.y != window->SizeFull.y) + MarkIniSettingsDirty(window); } - if (size_auto_fit_y_always || size_auto_fit_y_current) - { - if (size_auto_fit_y_always) - window->SizeFull.y = size_auto_fit.y; - else - window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; - use_current_size_for_scrollbar_y = true; - } - if (old_size.x != window->SizeFull.x || old_size.y != window->SizeFull.y) - MarkIniSettingsDirty(window); // Apply minimum/maximum window size constraints and final size window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull);