From d3666940621fcccb500e2725ddd4ec7371eeb8f1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Sep 2021 15:16:58 +0200 Subject: [PATCH] Disabled: Added assert guard for mismatching BeginDisabled()/EndDisabled() blocks. (#211) + Added asserts for missing PopItemFlag() calls. Added both to ErrorCheckEndFrameRecover (#1651) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 17 +++++++++++++++++ imgui.h | 2 +- imgui_internal.h | 10 +++++++--- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index adea71061ccf..09e395dae532 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -49,6 +49,7 @@ Other Changes: an accidental press on NavInput (Triangle button on PS4/PS5) without a wired keyboard. (#2321) - TextUnformatted: Accept null ranges including (NULL,NULL) without asserting, in order to conform to common idioms (e.g. passing .data(), .data() + .size() from a null string). (#3615) +- Disabled: Added assert guard for mismatching BeginDisabled()/EndDisabled() blocks. (#211) - Nav: Fixed toggling menu layer with Alt or exiting menu layer with Esc not moving mouse when the NavEnableSetMousePos config flag is set. - Nav: Fixed a few widgets from not setting reference keyboard/gamepad navigation ID when @@ -66,6 +67,7 @@ Other Changes: - Menus: Fixed crash when navigating left inside a child window inside a sub-menu. (#4510). - Drag and Drop: Fixed using BeginDragDropSource() inside a BeginChild() that returned false. (#4515) - PlotHistogram: Fixed zero-line position when manually specifying min<0 and max>0. (#4349) [@filippocrocchini] +- Misc: Added asserts for missing PopItemFlag() calls. - IO: Added 'io.WantCaptureMouseUnlessPopupClose' alternative to `io.WantCaptureMouse'. (#4480) This allows apps to receive the click on void when that click is used to close popup (by default, clicking on a void when a popup is open will close the popup but not release io.WantCaptureMouse). diff --git a/imgui.cpp b/imgui.cpp index bb051e8b3141..b325697951bc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6661,11 +6661,14 @@ void ImGui::BeginDisabled(bool disabled) if (was_disabled || disabled) g.CurrentItemFlags |= ImGuiItemFlags_Disabled; g.ItemFlagsStack.push_back(g.CurrentItemFlags); + g.DisabledStackSize++; } void ImGui::EndDisabled() { ImGuiContext& g = *GImGui; + IM_ASSERT(g.DisabledStackSize > 0); + g.DisabledStackSize--; bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; //PopItemFlag(); g.ItemFlagsStack.pop_back(); @@ -7340,11 +7343,21 @@ void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, voi if (log_callback) log_callback(user_data, "Recovered from missing PopID() in '%s'", window->Name); PopID(); } + while (g.DisabledStackSize > window->DC.StackSizesOnBegin.SizeOfDisabledStack) + { + if (log_callback) log_callback(user_data, "Recovered from missing EndDisabled() in '%s'", window->Name); + EndDisabled(); + } while (g.ColorStack.Size > window->DC.StackSizesOnBegin.SizeOfColorStack) { if (log_callback) log_callback(user_data, "Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s", window->Name, GetStyleColorName(g.ColorStack.back().Col)); PopStyleColor(); } + while (g.ItemFlagsStack.Size > window->DC.StackSizesOnBegin.SizeOfItemFlagsStack) + { + if (log_callback) log_callback(user_data, "Recovered from missing PopItemFlag() in '%s'", window->Name); + PopItemFlag(); + } while (g.StyleVarStack.Size > window->DC.StackSizesOnBegin.SizeOfStyleVarStack) { if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name); @@ -7385,7 +7398,9 @@ void ImGuiStackSizes::SetToCurrentState() SizeOfFontStack = (short)g.FontStack.Size; SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size; SizeOfGroupStack = (short)g.GroupStack.Size; + SizeOfItemFlagsStack = (short)g.ItemFlagsStack.Size; SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size; + SizeOfDisabledStack = (short)g.DisabledStackSize; } // Compare to detect usage errors @@ -7403,6 +7418,8 @@ void ImGuiStackSizes::CompareWithCurrentState() // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. IM_ASSERT(SizeOfGroupStack == g.GroupStack.Size && "BeginGroup/EndGroup Mismatch!"); IM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size && "BeginPopup/EndPopup or BeginMenu/EndMenu Mismatch!"); + IM_ASSERT(SizeOfDisabledStack == g.DisabledStackSize && "BeginDisabled/EndDisabled Mismatch!"); + IM_ASSERT(SizeOfItemFlagsStack >= g.ItemFlagsStack.Size && "PushItemFlag/PopItemFlag Mismatch!"); IM_ASSERT(SizeOfColorStack >= g.ColorStack.Size && "PushStyleColor/PopStyleColor Mismatch!"); IM_ASSERT(SizeOfStyleVarStack >= g.StyleVarStack.Size && "PushStyleVar/PopStyleVar Mismatch!"); IM_ASSERT(SizeOfFontStack >= g.FontStack.Size && "PushFont/PopFont Mismatch!"); diff --git a/imgui.h b/imgui.h index 6ea22bbb42f4..3f107e4946a0 100644 --- a/imgui.h +++ b/imgui.h @@ -64,7 +64,7 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) #define IMGUI_VERSION "1.85 WIP" -#define IMGUI_VERSION_NUM 18414 +#define IMGUI_VERSION_NUM 18415 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_HAS_TABLE diff --git a/imgui_internal.h b/imgui_internal.h index c5d7d747171e..aec5f4985275 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1381,7 +1381,9 @@ struct IMGUI_API ImGuiStackSizes short SizeOfFontStack; short SizeOfFocusScopeStack; short SizeOfGroupStack; + short SizeOfItemFlagsStack; short SizeOfBeginPopupStack; + short SizeOfDisabledStack; ImGuiStackSizes() { memset(this, 0, sizeof(*this)); } void SetToCurrentState(); @@ -1613,9 +1615,10 @@ struct ImGuiContext bool DragCurrentAccumDirty; float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio - float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled() float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? - int TooltipOverrideCount; + float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled() + short DisabledStackSize; + short TooltipOverrideCount; float TooltipSlowDelay; // Time before slow tooltips appears (FIXME: This is temporary until we merge in tooltip timer+priority work) ImVector ClipboardHandlerData; // If no custom clipboard handler is defined ImVector MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once @@ -1780,6 +1783,7 @@ struct ImGuiContext DragCurrentAccum = 0.0f; DragSpeedDefaultRatio = 1.0f / 100.0f; DisabledAlphaBackup = 0.0f; + DisabledStackSize = 0; ScrollbarClickDeltaToGrabCenter = 0.0f; TooltipOverrideCount = 0; TooltipSlowDelay = 0.50f; @@ -1863,7 +1867,7 @@ struct IMGUI_API ImGuiWindowTempData float TextWrapPos; // Current text wrap pos. ImVector ItemWidthStack; // Store item widths to restore (attention: .back() is not == ItemWidth) ImVector TextWrapPosStack; // Store text wrap pos to restore (attention: .back() is not == TextWrapPos) - ImGuiStackSizes StackSizesOnBegin; // Store size of various stacks for asserting + ImGuiStackSizes StackSizesOnBegin; // Store size of various stacks for asserting // FIXME: Can be moved to ImGuiWindowStackData }; // Storage for one window