From eed95027956805f83caddc0fd82dd05cdb2ee082 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Dec 2024 14:28:04 +0100 Subject: [PATCH] Error Handling: Fixed bugs recovering from within a table that created a child window, and from nested child windows. (#1651) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 29 +++++++++++++++++++---------- imgui_internal.h | 2 +- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index afd6c57c1..f91342903 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,8 @@ Breaking changes: Other changes: +- Error Handling: Fixed bugs recovering from within a table that created + a child window, and from nested child windows. (#1651) - InputText: Fixed a bug where character replacements performed from a callback were not applied when pasting from clipbard. (#8229) - InputText: Fixed issue when activating a ReadOnly field when the underlying diff --git a/imgui.cpp b/imgui.cpp index cf59a5a53..c5ede70a3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3884,7 +3884,8 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) Time = 0.0f; FrameCount = 0; FrameCountEnded = FrameCountRendered = -1; - WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; + WithinEndChildID = 0; + WithinFrameScope = WithinFrameScopeWithImplicitWindow = false; GcCompactAll = false; TestEngineHookItems = false; TestEngine = NULL; @@ -6106,10 +6107,10 @@ void ImGui::EndChild() ImGuiContext& g = *GImGui; ImGuiWindow* child_window = g.CurrentWindow; - IM_ASSERT(g.WithinEndChild == false); + const ImGuiID backup_within_end_child_id = g.WithinEndChildID; IM_ASSERT(child_window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() calls - g.WithinEndChild = true; + g.WithinEndChildID = child_window->ID; ImVec2 child_size = child_window->Size; End(); if (child_window->BeginCount == 1) @@ -6141,7 +6142,7 @@ void ImGui::EndChild() if (g.HoveredWindow == child_window) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; } - g.WithinEndChild = false; + g.WithinEndChildID = backup_within_end_child_id; g.LogLinePosY = -FLT_MAX; // To enforce a carriage return } @@ -7773,7 +7774,7 @@ void ImGui::End() // Error checking: verify that user doesn't directly call End() on a child window. if (window->Flags & ImGuiWindowFlags_ChildWindow) - IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!"); + IM_ASSERT_USER_ERROR(g.WithinEndChildID == window->ID, "Must call EndChild() and not End()!"); // Close anything that is open if (window->DC.CurrentColumns) @@ -10485,8 +10486,16 @@ void ImGui::ErrorRecoveryTryToRecoverState(const ImGuiErrorRecoveryState* state_ ImGuiWindow* window = g.CurrentWindow; if (window->Flags & ImGuiWindowFlags_ChildWindow) { - IM_ASSERT_USER_ERROR(0, "Missing EndChild()"); - EndChild(); + if (g.CurrentTable != NULL && g.CurrentTable->InnerWindow == g.CurrentWindow) + { + IM_ASSERT_USER_ERROR(0, "Missing EndTable()"); + EndTable(); + } + else + { + IM_ASSERT_USER_ERROR(0, "Missing EndChild()"); + EndChild(); + } } else { @@ -11921,11 +11930,11 @@ void ImGui::EndPopup() NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); // Child-popups don't need to be laid out - IM_ASSERT(g.WithinEndChild == false); + const ImGuiID backup_within_end_child_id = g.WithinEndChildID; if (window->Flags & ImGuiWindowFlags_ChildWindow) - g.WithinEndChild = true; + g.WithinEndChildID = window->ID; End(); - g.WithinEndChild = false; + g.WithinEndChildID = backup_within_end_child_id; } // Helper to open a popup if mouse button is released over the item diff --git a/imgui_internal.h b/imgui_internal.h index 947277489..316ac1844 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2045,9 +2045,9 @@ struct ImGuiContext int FrameCount; int FrameCountEnded; int FrameCountRendered; + ImGuiID WithinEndChildID; // Set within EndChild() bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame() bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed - bool WithinEndChild; // Set within EndChild() bool GcCompactAll; // Request full GC bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() void* TestEngine; // Test engine user data