From 70aa717a8e1f8cee34ea265b3ecd53d7ad3fb354 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 9 Feb 2024 15:23:43 +0100 Subject: [PATCH] Combo: Fixed not reusing windows optimally when used inside a popup stack. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 6 +++--- imgui_internal.h | 6 +++--- imgui_widgets.cpp | 5 ++++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 80f7807e..7d2b1bea 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -66,6 +66,7 @@ Other changes: the effect would be very disastrous in term of confusion, as reopening would steal focus). - Popups: Slight change to popup closing logic (e.g. after focusing another window) which skipped over popups that are also child windows. +- Combo: Fixed not reusing windows optimally when used inside a popup stack. - Debug Tools: Metrics: Fixed debug break in SetShortcutRouting() not handling ImGuiMod_Shortcut redirect. - Debug Tools: Debug Log: Added "Input Routing" logging. - Debug Tools: Added "nop" to IM_DEBUG_BREAK macro on GCC to work around GDB bug (#7266) [@Peter0x44] diff --git a/imgui.cpp b/imgui.cpp index 70de295d..ab03c38d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6434,7 +6434,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window_stack_data.StackSizesOnBegin.SetToContextState(&g); g.CurrentWindowStack.push_back(window_stack_data); if (flags & ImGuiWindowFlags_ChildMenu) - g.BeginMenuCount++; + g.BeginMenuDepth++; // Update ->RootWindow and others pointers (before any possible call to FocusWindow) if (first_begin_of_the_frame) @@ -7106,7 +7106,7 @@ void ImGui::End() // Pop from window stack g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup; if (window->Flags & ImGuiWindowFlags_ChildMenu) - g.BeginMenuCount--; + g.BeginMenuDepth--; if (window->Flags & ImGuiWindowFlags_Popup) g.BeginPopupStack.pop_back(); g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithContextState(&g); @@ -10926,7 +10926,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags) char name[20]; if (flags & ImGuiWindowFlags_ChildMenu) - ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginMenuCount); // Recycle windows based on depth + ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginMenuDepth); // Recycle windows based on depth else ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame diff --git a/imgui_internal.h b/imgui_internal.h index 2d17b828..d826fbcd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2028,8 +2028,6 @@ struct ImGuiContext ImVector BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) ImVector NavTreeNodeStack; // Stack for TreeNode() when a NavLeft requested is emitted. - int BeginMenuCount; - // Viewports ImVector Viewports; // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData. @@ -2154,6 +2152,8 @@ struct ImGuiContext ImGuiInputTextDeactivatedState InputTextDeactivatedState; ImFont InputTextPasswordFont; ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc. + int BeginMenuDepth; + int BeginComboDepth; ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets ImGuiID ColorEditCurrentID; // Set temporarily while inside of the parent-most ColorEdit4/ColorPicker4 (because they call each others). ImGuiID ColorEditSavedID; // ID we are saving/restoring HS for @@ -2307,7 +2307,6 @@ struct ImGuiContext CurrentFocusScopeId = 0; CurrentItemFlags = ImGuiItemFlags_None; DebugShowGroupRects = false; - BeginMenuCount = 0; NavWindow = NULL; NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0; @@ -2371,6 +2370,7 @@ struct ImGuiContext MouseStationaryTimer = 0.0f; TempInputId = 0; + BeginMenuDepth = BeginComboDepth = 0; ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_; ColorEditCurrentID = ColorEditSavedID = 0; ColorEditSavedHue = ColorEditSavedSat = 0.0f; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2df1c9f3..daf066c0 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1784,7 +1784,7 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags // This is essentially a specialized version of BeginPopupEx() char name[16]; - ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth + ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginComboDepth); // Recycle windows based on depth // Set position given a custom constraint (peak into expected window size so we can position it) // FIXME: This might be easier to express with an hypothetical SetNextWindowPosConstraints() function? @@ -1811,12 +1811,15 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above return false; } + g.BeginComboDepth++; return true; } void ImGui::EndCombo() { + ImGuiContext& g = *GImGui; EndPopup(); + g.BeginComboDepth--; } // Call directly after the BeginCombo/EndCombo block. The preview is designed to only host non-interactive elements