From cc2177de15d98c2b1f23ebc9de779639fad09030 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 14 Mar 2023 15:24:16 +0100 Subject: [PATCH] Debug Tools: Added io.ConfigDebugBeginReturnValueOnce / io.ConfigDebugBeginReturnValueLoop options. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 24 ++++++++++++++++++++++++ imgui.h | 8 ++++++++ imgui_demo.cpp | 9 +++++++++ imgui_internal.h | 2 ++ 5 files changed, 45 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7b5aeff41..a974e47e2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -81,6 +81,8 @@ Other changes: before and can accept the same data type. (#6183). - Drag and Drop: Clear drag and drop state as soon as delivery is accepted in order to avoid inteferences. (#5817, #6183) [@DimaKoltun] +- Debug Tools: Added io.ConfigDebugBeginReturnValueOnce / io.ConfigDebugBeginReturnValueLoop + options to simulate Begin/BeginChild returning false to facilitate debugging user behavior. - Backends: OpenGL3: Fixed restoration of a potentially deleted OpenGL program. If an active program was pending deletion, attempting to restore it would error. (#6220, #6224) [@Cyphall] - Backends: Win32: Use WM_NCMOUSEMOVE / WM_NCMOUSELEAVE to track mouse positions over diff --git a/imgui.cpp b/imgui.cpp index 823ad2fb9..08106b90e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1230,6 +1230,8 @@ ImGuiIO::ImGuiIO() ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; ConfigMemoryCompactTimer = 60.0f; + ConfigDebugBeginReturnValueOnce = false; + ConfigDebugBeginReturnValueLoop = false; // Platform Functions // Note: Initialize() will setup default clipboard/ime handlers. @@ -4601,6 +4603,13 @@ void ImGui::NewFrame() Begin("Debug##Default"); IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true); + // [DEBUG] When io.ConfigDebugBeginReturnValue is set, we make Begin()/BeginChild() return false at different level of the window-stack, + // allowing to validate correct Begin/End behavior in user code. + if (g.IO.ConfigDebugBeginReturnValueLoop) + g.DebugBeginReturnValueCullDepth = (g.DebugBeginReturnValueCullDepth == -1) ? 0 : ((g.DebugBeginReturnValueCullDepth + ((g.FrameCount % 4) == 0 ? 1 : 0)) % 10); + else + g.DebugBeginReturnValueCullDepth = -1; + CallContextHooks(&g, ImGuiContextHookType_NewFramePost); } @@ -6735,6 +6744,15 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->SkipItems = skip_items; } + // [DEBUG] io.ConfigDebugBeginReturnValue override return value to test Begin/End and BeginChild/EndChild behaviors. + // (The implicit fallback window is NOT automatically ended allowing it to always be able to receive commands without crashing) + if (!window->IsFallbackWindow && ((g.IO.ConfigDebugBeginReturnValueOnce && window_just_created) || (g.IO.ConfigDebugBeginReturnValueLoop && g.DebugBeginReturnValueCullDepth == g.CurrentWindowStack.Size))) + { + if (window->AutoFitFramesX > 0) { window->AutoFitFramesX++; } + if (window->AutoFitFramesY > 0) { window->AutoFitFramesY++; } + return false; + } + return !window->SkipItems; } @@ -8994,7 +9012,9 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() { if (g.CurrentWindowStack.Size > 1) { + ImGuiWindow* window = g.CurrentWindowStack.back().Window; // <-- This window was not Ended! IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + IM_UNUSED(window); while (g.CurrentWindowStack.Size > 1) End(); } @@ -13460,6 +13480,10 @@ void ImGui::ShowMetricsWindow(bool* p_open) } } + Checkbox("Debug Begin/BeginChild return value", &io.ConfigDebugBeginReturnValueLoop); + SameLine(); + MetricsHelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running."); + TreePop(); } diff --git a/imgui.h b/imgui.h index 0fd3ce284..3dd3936dd 100644 --- a/imgui.h +++ b/imgui.h @@ -1941,6 +1941,14 @@ struct ImGuiIO bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. float ConfigMemoryCompactTimer; // = 60.0f // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable. + // Debug options + // - tools to test correct Begin/End and BeginChild/EndChild behaviors. + // - presently Begn()/End() and BeginChild()EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX() + // this is inconsistent with other BeginXXX functions and create confusion for many users. + // - we expect to update the API eventually. In the meanwhile we provided tools to facilitate checking user-code behavior. + bool ConfigDebugBeginReturnValueOnce; // = false // First-time calls to Begin()/BeginChild() will return false. NEEDS TO BE SET AT APPLICATION BOOT TIME if you don't want to miss windows. + bool ConfigDebugBeginReturnValueLoop; // = false // Some calls to Begin()/BeginChild() will return false. Will cycle through window depths then repeat. Suggested use: add "io.ConfigDebugBeginReturnValue = io.KeyShift" in your main loop then occasionally press SHIFT. Windows should be flickering while running. + //------------------------------------------------------------------ // Platform Functions // (the imgui_impl_xxxx backend files are setting those up for you) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 50082d743..cf3f59dc4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -463,6 +463,15 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors); ImGui::Text("Also see Style->Rendering for rendering options."); + + ImGui::SeparatorText("Debug"); + ImGui::BeginDisabled(); + ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); // . + ImGui::EndDisabled(); + ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover"); + ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop); + ImGui::SameLine(); HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running."); + ImGui::TreePop(); ImGui::Spacing(); } diff --git a/imgui_internal.h b/imgui_internal.h index dd152192a..c11286dde 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1996,6 +1996,7 @@ struct ImGuiContext ImGuiTextIndex DebugLogIndex; ImU8 DebugLogClipperAutoDisableFrames; ImU8 DebugLocateFrames; // For DebugLocateItemOnHover(). This is used together with DebugLocateId which is in a hot/cached spot above. + ImS8 DebugBeginReturnValueCullDepth; // Cycle between 0..9 then wrap around. bool DebugItemPickerActive; // Item picker is active (started with DebugStartItemPicker()) ImU8 DebugItemPickerMouseButton; ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this ID @@ -2169,6 +2170,7 @@ struct ImGuiContext DebugLocateId = 0; DebugLogClipperAutoDisableFrames = 0; DebugLocateFrames = 0; + DebugBeginReturnValueCullDepth = -1; DebugItemPickerActive = false; DebugItemPickerMouseButton = ImGuiMouseButton_Left; DebugItemPickerBreakId = 0;