From 204ae8a407acf98ba4ba47932aaa632a0ae52b83 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 Sep 2023 14:16:41 +0200 Subject: [PATCH 1/6] Internals: added ImRect::ContainsWithPad() --- imgui.cpp | 13 ++++--------- imgui_internal.h | 1 + 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c30a1a13..034d4016 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5212,12 +5212,8 @@ static void FindHoveredWindow() continue; // Using the clipped AABB, a child window will typically be clipped by its parent (not always) - ImRect bb(window->OuterRectClipped); - if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) - bb.Expand(padding_regular); - else - bb.Expand(padding_for_resize); - if (!bb.Contains(g.IO.MousePos)) + ImVec2 hit_padding = (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) ? padding_regular : padding_for_resize; + if (!window->OuterRectClipped.ContainsWithPad(g.IO.MousePos, hit_padding)) continue; // Support for one rectangular hole in any given window @@ -8387,9 +8383,8 @@ bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool c if (clip) rect_clipped.ClipWith(g.CurrentWindow->ClipRect); - // Expand for touch input - const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); - if (!rect_for_touch.Contains(g.IO.MousePos)) + // Hit testing, expanded for touch input + if (!rect_clipped.ContainsWithPad(g.IO.MousePos, g.Style.TouchExtraPadding)) return false; return true; } diff --git a/imgui_internal.h b/imgui_internal.h index 58459adb..bd21fc69 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -544,6 +544,7 @@ struct IMGUI_API ImRect ImVec2 GetBR() const { return Max; } // Bottom-right bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } + bool ContainsWithPad(const ImVec2& p, const ImVec2& pad) const { return p.x >= Min.x - pad.x && p.y >= Min.y - pad.y && p.x < Max.x + pad.x && p.y < Max.y + pad.y; } bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; } void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; } From 8175a478813ca7f4e35906dd65ca232183ac3406 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 Sep 2023 15:21:55 +0200 Subject: [PATCH 2/6] Debug Tools: Renamed ShowStackToolWindow() ("Stack Tool") to ShowIdStackToolWindow() ("ID Stack Tool"). (#4631) --- docs/CHANGELOG.txt | 2 ++ docs/FAQ.md | 2 +- imconfig.h | 2 +- imgui.cpp | 39 +++++++++++++++++++-------------------- imgui.h | 3 ++- imgui_demo.cpp | 8 ++++---- imgui_internal.h | 12 ++++++------ 7 files changed, 35 insertions(+), 33 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 95e7009b..86d9ffdd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -42,6 +42,8 @@ HOW TO UPDATE? Breaking changes: + - Debug Tools: Renamed ShowStackToolWindow() ("Stack Tool") to ShowIdStackToolWindow() ("ID Stack Tool"), + as earlier name was misleading. Kept inline redirection function. (#4631) - ListBox, Combo: Changed signature of "name getter" callback in old one-liner ListBox()/Combo() apis. Before: getter type: bool (*getter)(void* user_data, int idx, const char** out_text) diff --git a/docs/FAQ.md b/docs/FAQ.md index dcf144a3..04078db2 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -217,7 +217,7 @@ Interactive widgets (such as calls to Button buttons) need a unique ID. **Unique IDs are used internally to track active widgets and occasionally associate state to widgets.
Unique IDs are implicitly built from the hash of multiple elements that identify the "path" to the UI element.** -Since Dear ImGui 1.85, you can use `Demo>Tools>Stack Tool` or call `ImGui::ShowStackToolWindow()`. The tool display intermediate values leading to the creation of a unique ID, making things easier to debug and understand. +Since Dear ImGui 1.85, you can use `Demo>Tools>Stack Tool` or call `ImGui::ShowIdStackToolWindow()`. The tool display intermediate values leading to the creation of a unique ID, making things easier to debug and understand. ![Stack tool](https://user-images.githubusercontent.com/8225057/136235657-a0ea5665-dcd1-423f-9be6-dc3f8ced8f12.png) diff --git a/imconfig.h b/imconfig.h index b56ba494..3c6e198a 100644 --- a/imconfig.h +++ b/imconfig.h @@ -34,7 +34,7 @@ // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. -//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88). +//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIdStackToolWindow() will be empty. //---- Don't implement some functions to reduce linkage requirements. //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) diff --git a/imgui.cpp b/imgui.cpp index 034d4016..835918b4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -88,7 +88,7 @@ CODE // [SECTION] PLATFORM DEPENDENT HELPERS // [SECTION] METRICS/DEBUGGER WINDOW // [SECTION] DEBUG LOG WINDOW -// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL) +// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, ID STACK TOOL) */ @@ -424,6 +424,7 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2023/09/26 (1.90.0) - debug tools: Renamed ShowStackToolWindow() ("Stack Tool") to ShowIdStackToolWindow() ("ID Stack Tool"), as earlier name was misleading. Kept inline redirection function. (#4631) - 2023/09/15 (1.90.0) - ListBox, Combo: changed signature of "name getter" callback in old one-liner ListBox()/Combo() apis. kept inline redirection function (will obsolete). - old: bool Combo(const char* label, int* current_item, bool (*getter)(void* user_data, int idx, const char** out_text), ...) - new: bool Combo(const char* label, int* current_item, const char* (*getter)(void* user_data, int idx), ...); @@ -7798,7 +7799,7 @@ void ImGui::PushOverrideID(ImGuiID id) } // Helper to avoid a common series of PushOverrideID -> GetID() -> PopID() call -// (note that when using this pattern, TestEngine's "Stack Tool" will tend to not display the intermediate stack level. +// (note that when using this pattern, ID Stack Tool will tend to not display the intermediate stack level. // for that to work we would need to do PushOverrideID() -> ItemAdd() -> PopID() which would alter widget code a little more) ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed) { @@ -13702,8 +13703,8 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; if (cfg->ShowDebugLog) ShowDebugLogWindow(&cfg->ShowDebugLog); - if (cfg->ShowStackTool) - ShowStackToolWindow(&cfg->ShowStackTool); + if (cfg->ShowIdStackTool) + ShowIdStackToolWindow(&cfg->ShowIdStackTool); if (!Begin("Dear ImGui Metrics/Debugger", p_open) || GetCurrentWindow()->BeginCount > 1) { @@ -13789,15 +13790,13 @@ void ImGui::ShowMetricsWindow(bool* p_open) SameLine(); MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); - // Stack Tool is your best friend! Checkbox("Show Debug Log", &cfg->ShowDebugLog); SameLine(); MetricsHelpMarker("You can also call ImGui::ShowDebugLogWindow() from your code."); - // Stack Tool is your best friend! - Checkbox("Show Stack Tool", &cfg->ShowStackTool); + Checkbox("Show ID Stack Tool", &cfg->ShowIdStackTool); SameLine(); - MetricsHelpMarker("You can also call ImGui::ShowStackToolWindow() from your code."); + MetricsHelpMarker("You can also call ImGui::ShowIdStackToolWindow() from your code."); Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder); Checkbox("Show windows rectangles", &cfg->ShowWindowsRects); @@ -14720,7 +14719,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) } //----------------------------------------------------------------------------- -// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL) +// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, ID STACK TOOL) //----------------------------------------------------------------------------- // Draw a small cross at current CursorPos in current window's DrawList @@ -14821,13 +14820,13 @@ void ImGui::UpdateDebugToolItemPicker() EndTooltip(); } -// [DEBUG] Stack Tool: update queries. Called by NewFrame() +// [DEBUG] ID Stack Tool: update queries. Called by NewFrame() void ImGui::UpdateDebugToolStackQueries() { ImGuiContext& g = *GImGui; - ImGuiStackTool* tool = &g.DebugStackTool; + ImGuiIdStackTool* tool = &g.DebugIdStackTool; - // Clear hook when stack tool is not visible + // Clear hook when id stack tool is not visible g.DebugHookIdInfo = 0; if (g.FrameCount != tool->LastActiveFrame + 1) return; @@ -14861,12 +14860,12 @@ void ImGui::UpdateDebugToolStackQueries() } } -// [DEBUG] Stack tool: hooks called by GetID() family functions +// [DEBUG] ID Stack tool: hooks called by GetID() family functions void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - ImGuiStackTool* tool = &g.DebugStackTool; + ImGuiIdStackTool* tool = &g.DebugIdStackTool; // Step 0: stack query // This assumes that the ID was computed with the current ID stack, which tends to be the case for our widget. @@ -14909,7 +14908,7 @@ void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* dat info->DataType = data_type; } -static int StackToolFormatLevelInfo(ImGuiStackTool* tool, int n, bool format_for_ui, char* buf, size_t buf_size) +static int StackToolFormatLevelInfo(ImGuiIdStackTool* tool, int n, bool format_for_ui, char* buf, size_t buf_size) { ImGuiStackLevelInfo* info = &tool->Results[n]; ImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? ImGui::FindWindowByID(info->ID) : NULL; @@ -14926,20 +14925,20 @@ static int StackToolFormatLevelInfo(ImGuiStackTool* tool, int n, bool format_for return ImFormatString(buf, buf_size, "???"); } -// Stack Tool: Display UI -void ImGui::ShowStackToolWindow(bool* p_open) +// ID Stack Tool: Display UI +void ImGui::ShowIdStackToolWindow(bool* p_open) { ImGuiContext& g = *GImGui; if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)) SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 8.0f), ImGuiCond_FirstUseEver); - if (!Begin("Dear ImGui Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1) + if (!Begin("Dear ImGui ID Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1) { End(); return; } // Display hovered/active status - ImGuiStackTool* tool = &g.DebugStackTool; + ImGuiIdStackTool* tool = &g.DebugIdStackTool; const ImGuiID hovered_id = g.HoveredIdPreviousFrame; const ImGuiID active_id = g.ActiveId; #ifdef IMGUI_ENABLE_TEST_ENGINE @@ -15021,7 +15020,7 @@ void ImGui::DebugNodeViewport(ImGuiViewportP*) {} void ImGui::DebugLog(const char*, ...) {} void ImGui::DebugLogV(const char*, va_list) {} void ImGui::ShowDebugLogWindow(bool*) {} -void ImGui::ShowStackToolWindow(bool*) {} +void ImGui::ShowIdStackToolWindow(bool*) {} void ImGui::DebugHookIdInfo(ImGuiID, ImGuiDataType, const void*, const void*) {} void ImGui::UpdateDebugToolItemPicker() {} void ImGui::UpdateDebugToolStackQueries() {} diff --git a/imgui.h b/imgui.h index 76c5065d..952d8397 100644 --- a/imgui.h +++ b/imgui.h @@ -307,7 +307,7 @@ namespace ImGui IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window. demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Metrics/Debugger window. display Dear ImGui internals: windows, draw commands, various internal state, etc. IMGUI_API void ShowDebugLogWindow(bool* p_open = NULL); // create Debug Log window. display a simplified log of important dear imgui events. - IMGUI_API void ShowStackToolWindow(bool* p_open = NULL); // create Stack Tool window. hover items with mouse to query information about the source of their unique ID. + IMGUI_API void ShowIdStackToolWindow(bool* p_open = NULL); // create Stack Tool window. hover items with mouse to query information about the source of their unique ID. IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information. IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles. @@ -3100,6 +3100,7 @@ namespace ImGui namespace ImGui { // OBSOLETED in 1.90.0 (from September 2023) + static inline void ShowStackToolWindow(bool* p_open = NULL) { ShowIdStackToolWindow(p_open); } IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1); IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1); // OBSOLETED in 1.89.7 (from June 2023) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 476ae1d1..bf020110 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -290,7 +290,7 @@ void ImGui::ShowDemoWindow(bool* p_open) // Dear ImGui Tools (accessible from the "Tools" menu) static bool show_tool_metrics = false; static bool show_tool_debug_log = false; - static bool show_tool_stack_tool = false; + static bool show_tool_id_stack_tool = false; static bool show_tool_style_editor = false; static bool show_tool_about = false; @@ -298,8 +298,8 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::ShowMetricsWindow(&show_tool_metrics); if (show_tool_debug_log) ImGui::ShowDebugLogWindow(&show_tool_debug_log); - if (show_tool_stack_tool) - ImGui::ShowStackToolWindow(&show_tool_stack_tool); + if (show_tool_id_stack_tool) + ImGui::ShowIdStackToolWindow(&show_tool_id_stack_tool); if (show_tool_style_editor) { ImGui::Begin("Dear ImGui Style Editor", &show_tool_style_editor); @@ -398,7 +398,7 @@ void ImGui::ShowDemoWindow(bool* p_open) #endif ImGui::MenuItem("Metrics/Debugger", NULL, &show_tool_metrics, has_debug_tools); ImGui::MenuItem("Debug Log", NULL, &show_tool_debug_log, has_debug_tools); - ImGui::MenuItem("Stack Tool", NULL, &show_tool_stack_tool, has_debug_tools); + ImGui::MenuItem("ID Stack Tool", NULL, &show_tool_id_stack_tool, has_debug_tools); ImGui::MenuItem("Style Editor", NULL, &show_tool_style_editor); ImGui::MenuItem("About Dear ImGui", NULL, &show_tool_about); ImGui::EndMenu(); diff --git a/imgui_internal.h b/imgui_internal.h index bd21fc69..04c667bb 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1784,7 +1784,7 @@ enum ImGuiDebugLogFlags_ struct ImGuiMetricsConfig { bool ShowDebugLog = false; - bool ShowStackTool = false; + bool ShowIdStackTool = false; bool ShowWindowsRects = false; bool ShowWindowsBeginOrder = false; bool ShowTablesRects = false; @@ -1806,8 +1806,8 @@ struct ImGuiStackLevelInfo ImGuiStackLevelInfo() { memset(this, 0, sizeof(*this)); } }; -// State for Stack tool queries -struct ImGuiStackTool +// State for ID Stack tool queries +struct ImGuiIdStackTool { int LastActiveFrame; int StackLevel; // -1: query stack and resize Results, >= 0: individual stack level @@ -1816,7 +1816,7 @@ struct ImGuiStackTool bool CopyToClipboardOnCtrlC; float CopyToClipboardLastTime; - ImGuiStackTool() { memset(this, 0, sizeof(*this)); CopyToClipboardLastTime = -FLT_MAX; } + ImGuiIdStackTool() { memset(this, 0, sizeof(*this)); CopyToClipboardLastTime = -FLT_MAX; } }; //----------------------------------------------------------------------------- @@ -1888,7 +1888,7 @@ struct ImGuiContext ImVec2 WheelingAxisAvg; // Item/widgets state and tracking information - ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] + ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] ImGuiID HoveredId; // Hovered widget, filled during the frame ImGuiID HoveredIdPreviousFrame; bool HoveredIdAllowOverlap; @@ -2130,7 +2130,7 @@ struct ImGuiContext ImU8 DebugItemPickerMouseButton; ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this ID ImGuiMetricsConfig DebugMetricsConfig; - ImGuiStackTool DebugStackTool; + ImGuiIdStackTool DebugIdStackTool; // Misc float FramerateSecPerFrame[60]; // Calculate estimate of framerate for user over the last 60 frames.. From 9ece0bdc023846dd5dd02b69c49a871626320d4c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 Sep 2023 21:07:25 +0200 Subject: [PATCH 3/6] BeginGroup(): Fixed a bug pushing line lower extent too far down when called after a call to SameLine() followed by manual cursor manipulation. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 ++ imgui_internal.h | 1 + 3 files changed, 5 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 86d9ffdd..f13ee1cd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -93,6 +93,8 @@ Other changes: (regression from 1.89.2, only happened in some states). (#6783, #6000) - InputTextMultiline: Fixed Tabbing cycle leading to a situation where Enter key wouldn't be accepted by the widget when navigation highlight is visible. (#6802, #3092, #5759, #787) +- BeginGroup(): Fixed a bug pushing line lower extent too far down when called after a call + to SameLine() followed by manual cursor manipulation. - BeginListBox(): Fixed not consuming SetNextWindowXXX data when returning false. - MenuBar: Fixed an issue where layouting an item in the menu-bar would erroneously register contents size in a way that would affect the scrolling layer. diff --git a/imgui.cpp b/imgui.cpp index 835918b4..5dba9bb4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9854,6 +9854,7 @@ void ImGui::BeginGroup() group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset; group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; group_data.BackupHoveredIdIsAlive = g.HoveredId != 0; + group_data.BackupIsSameLine = window->DC.IsSameLine; group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; group_data.EmitItem = true; @@ -9885,6 +9886,7 @@ void ImGui::EndGroup() window->DC.GroupOffset = group_data.BackupGroupOffset; window->DC.CurrLineSize = group_data.BackupCurrLineSize; window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset; + window->DC.IsSameLine = group_data.BackupIsSameLine; if (g.LogEnabled) g.LogLinePosY = -FLT_MAX; // To enforce a carriage return diff --git a/imgui_internal.h b/imgui_internal.h index 04c667bb..99c41a0a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1071,6 +1071,7 @@ struct IMGUI_API ImGuiGroupData ImGuiID BackupActiveIdIsAlive; bool BackupActiveIdPreviousFrameIsAlive; bool BackupHoveredIdIsAlive; + bool BackupIsSameLine; bool EmitItem; }; From 456aa3bc0add9b809be6d1f736cfe611350e02b8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Sep 2023 16:34:31 +0200 Subject: [PATCH 4/6] Menus: Fixed a bug where activating an item in a child-menu and dragging mouse over the parent-menu would erroneously close the child-menu. (#6869) Regression from 0dec430 --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f13ee1cd..387c9a22 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -96,6 +96,8 @@ Other changes: - BeginGroup(): Fixed a bug pushing line lower extent too far down when called after a call to SameLine() followed by manual cursor manipulation. - BeginListBox(): Fixed not consuming SetNextWindowXXX data when returning false. +- Menus: Fixed a bug where activating an item in a child-menu and dragging mouse over the + parent-menu would erroneously close the child-menu. (Regression from 1.88). (#6869) - MenuBar: Fixed an issue where layouting an item in the menu-bar would erroneously register contents size in a way that would affect the scrolling layer. Was most often noticable when using an horizontal scrollbar. (#6789) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 41adcae1..86961d64 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7497,7 +7497,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) // The 'HovereWindow == window' check creates an inconsistency (e.g. moving away from menu slowly tends to hit same window, whereas moving away fast does not) // But we also need to not close the top-menu menu when moving over void. Perhaps we should extend the triangle check to a larger polygon. // (Remember to test this on BeginPopup("A")->BeginMenu("B") sequence which behaves slightly differently as B isn't a Child of A and hovering isn't shared.) - if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavDisableMouseHover) + if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavDisableMouseHover && g.ActiveId == 0) want_close = true; // Open From f1519efb166562b48ab2c6e15c7978ebd616974c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Sep 2023 17:25:55 +0200 Subject: [PATCH 5/6] BeginGroup(): fix/amend 9ece0bd. --- imgui.cpp | 2 ++ imgui_internal.h | 1 + 2 files changed, 3 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 5dba9bb4..052f5e55 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9847,6 +9847,7 @@ void ImGui::BeginGroup() ImGuiGroupData& group_data = g.GroupStack.back(); group_data.WindowID = window->ID; group_data.BackupCursorPos = window->DC.CursorPos; + group_data.BackupCursorPosPrevLine = window->DC.CursorPosPrevLine; group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; group_data.BackupIndent = window->DC.Indent; group_data.BackupGroupOffset = window->DC.GroupOffset; @@ -9881,6 +9882,7 @@ void ImGui::EndGroup() ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos)); window->DC.CursorPos = group_data.BackupCursorPos; + window->DC.CursorPosPrevLine = group_data.BackupCursorPosPrevLine; window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); window->DC.Indent = group_data.BackupIndent; window->DC.GroupOffset = group_data.BackupGroupOffset; diff --git a/imgui_internal.h b/imgui_internal.h index 99c41a0a..6206642c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1064,6 +1064,7 @@ struct IMGUI_API ImGuiGroupData ImGuiID WindowID; ImVec2 BackupCursorPos; ImVec2 BackupCursorMaxPos; + ImVec2 BackupCursorPosPrevLine; ImVec1 BackupIndent; ImVec1 BackupGroupOffset; ImVec2 BackupCurrLineSize; From 2f431a948c3171300c15fb3f35b5ac1055fe1c22 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Sep 2023 17:34:23 +0200 Subject: [PATCH 6/6] IO: removed io.MetricsActiveAllocations introduced in 1.63. Same as 'g.DebugMemAllocCount - g.DebugMemFreeCount' (still displayed in Metrics. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 57 ++++++++++++++++++++++++++++++++++++++-------- imgui.h | 11 ++++----- imgui_internal.h | 19 ++++++++++++++++ 4 files changed, 75 insertions(+), 15 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 387c9a22..64a7003f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,6 +44,8 @@ Breaking changes: - Debug Tools: Renamed ShowStackToolWindow() ("Stack Tool") to ShowIdStackToolWindow() ("ID Stack Tool"), as earlier name was misleading. Kept inline redirection function. (#4631) + - IO: Removed io.MetricsActiveAllocations introduced in 1.63, was displayed in Metrics and unlikely to + be accessed by end-user. Value still visible in the UI and easily to recompute from a delta. - ListBox, Combo: Changed signature of "name getter" callback in old one-liner ListBox()/Combo() apis. Before: getter type: bool (*getter)(void* user_data, int idx, const char** out_text) @@ -103,6 +105,7 @@ Other changes: Was most often noticable when using an horizontal scrollbar. (#6789) - Misc: Most text functions also treat "%.*s" (along with "%s") specially to avoid formatting. (#3466, #6846) - IO: Setting io.WantSetMousePos ignores incoming MousePos events. (#6837, #228) [@bertaye] +- Debug Tools: Metrics: Added log recent alloc/free calls. - ImDrawList: Added AddEllipse(), AddEllipseFilled(), PathEllipticalArcTo(). (#2743) [@Doohl] - ImVector: Added find_index() helper. - Backends: GLFW: Clear emscripten's MouseWheel callback before shutdown. (#6790, #6096, #4019) [@halx99] diff --git a/imgui.cpp b/imgui.cpp index 052f5e55..7e13fef9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -424,6 +424,7 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2023/09/27 (1.90.0) - io: removed io.MetricsActiveAllocations introduced in 1.63. Same as 'g.DebugMemAllocCount - g.DebugMemFreeCount' (still displayed in Metrics, unlikely to be accessed by end-user). - 2023/09/26 (1.90.0) - debug tools: Renamed ShowStackToolWindow() ("Stack Tool") to ShowIdStackToolWindow() ("ID Stack Tool"), as earlier name was misleading. Kept inline redirection function. (#4631) - 2023/09/15 (1.90.0) - ListBox, Combo: changed signature of "name getter" callback in old one-liner ListBox()/Combo() apis. kept inline redirection function (will obsolete). - old: bool Combo(const char* label, int* current_item, bool (*getter)(void* user_data, int idx, const char** out_text), ...) @@ -4223,26 +4224,50 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) void* ImGui::MemAlloc(size_t size) { void* ptr = (*GImAllocatorAllocFunc)(size, GImAllocatorUserData); +#ifndef IMGUI_DISABLE_DEBUG_TOOLS if (ImGuiContext* ctx = GImGui) - { - ctx->IO.MetricsActiveAllocations++; - //printf("[%05d] MemAlloc(%d) -> 0x%p\n", ctx->FrameCount, size, ptr); - } + DebugAllocHook(&ctx->DebugAllocInfo, ctx->FrameCount, ptr, size); +#endif return ptr; } // IM_FREE() == ImGui::MemFree() void ImGui::MemFree(void* ptr) { +#ifndef IMGUI_DISABLE_DEBUG_TOOLS if (ptr != NULL) if (ImGuiContext* ctx = GImGui) - { - ctx->IO.MetricsActiveAllocations--; - //printf("[%05d] MemFree(0x%p)\n", ctx->FrameCount, ptr); - } + DebugAllocHook(&ctx->DebugAllocInfo, ctx->FrameCount, ptr, (size_t)-1); +#endif return (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData); } +// We record the number of allocation in recent frames, as a way to audit/sanitize our guiding principles of "no allocations on idle/repeating frames" +void ImGui::DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size) +{ + ImGuiDebugAllocEntry* entry = &info->LastEntriesBuf[info->LastEntriesIdx]; + IM_UNUSED(ptr); + if (entry->FrameCount != frame_count) + { + info->LastEntriesIdx = (info->LastEntriesIdx + 1) % IM_ARRAYSIZE(info->LastEntriesBuf); + entry = &info->LastEntriesBuf[info->LastEntriesIdx]; + entry->FrameCount = frame_count; + entry->AllocCount = entry->FreeCount = 0; + } + if (size != (size_t)-1) + { + entry->AllocCount++; + info->TotalAllocCount++; + //printf("[%05d] MemAlloc(%d) -> 0x%p\n", frame_count, size, ptr); + } + else + { + entry->FreeCount++; + info->TotalFreeCount++; + //printf("[%05d] MemFree(0x%p)\n", frame_count, ptr); + } +} + const char* ImGui::GetClipboardText() { ImGuiContext& g = *GImGui; @@ -13720,7 +13745,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) Text("Dear ImGui %s", GetVersion()); Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); - Text("%d visible windows, %d active allocations", io.MetricsRenderWindows, io.MetricsActiveAllocations); + Text("%d visible windows, %d current allocations", io.MetricsRenderWindows, g.DebugAllocInfo.TotalAllocCount - g.DebugAllocInfo.TotalFreeCount); //SameLine(); if (SmallButton("GC")) { g.GcCompactAll = true; } Separator(); @@ -14034,6 +14059,20 @@ void ImGui::ShowMetricsWindow(bool* p_open) TreePop(); } + // Settings + if (TreeNode("Memory allocations")) + { + ImGuiDebugAllocInfo* info = &g.DebugAllocInfo; + Text("%d current allocations", info->TotalAllocCount - info->TotalFreeCount); + int buf_size = IM_ARRAYSIZE(info->LastEntriesBuf); + for (int n = buf_size - 1; n >= 0; n--) + { + ImGuiDebugAllocEntry* entry = &info->LastEntriesBuf[(info->LastEntriesIdx - n + buf_size) % buf_size]; + BulletText("Frame %06d: %+3d ( %2d malloc, %2d free )", entry->FrameCount, entry->AllocCount - entry->FreeCount, entry->AllocCount, entry->FreeCount); + } + TreePop(); + } + if (TreeNode("Inputs")) { Text("KEYBOARD/GAMEPAD/MOUSE KEYS"); diff --git a/imgui.h b/imgui.h index 952d8397..788231ff 100644 --- a/imgui.h +++ b/imgui.h @@ -2039,11 +2039,6 @@ struct ImGuiIO // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) // (default to use native imm32 api on Windows) void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - void* ImeWindowHandle; // = NULL // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning. -#else - void* _UnusedPadding; // Unused field to keep data structure the same size. -#endif // Optional: Platform locale ImWchar PlatformLocaleDecimalPoint; // '.' // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point @@ -2090,7 +2085,6 @@ struct ImGuiIO int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 int MetricsRenderWindows; // Number of visible windows int MetricsActiveWindows; // Number of active windows - int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. // Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and io.KeysDown[] (native indices) every frame. @@ -2101,6 +2095,11 @@ struct ImGuiIO bool KeysDown[ImGuiKey_COUNT]; // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow. float NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. #endif +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + void* ImeWindowHandle; // = NULL // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning. +#else + void* _UnusedPadding; +#endif //------------------------------------------------------------------ // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! diff --git a/imgui_internal.h b/imgui_internal.h index 6206642c..148093f0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1783,6 +1783,23 @@ enum ImGuiDebugLogFlags_ ImGuiDebugLogFlags_OutputToTestEngine = 1 << 11, // Also send output to Test Engine }; +struct ImGuiDebugAllocEntry +{ + int FrameCount; + ImS16 AllocCount; + ImS16 FreeCount; +}; + +struct ImGuiDebugAllocInfo +{ + int TotalAllocCount; // Number of call to MemAlloc(). + int TotalFreeCount; + ImS16 LastEntriesIdx; // Current index in buffer + ImGuiDebugAllocEntry LastEntriesBuf[6]; // Track last 6 frames that had allocations + + ImGuiDebugAllocInfo() { memset(this, 0, sizeof(*this)); } +}; + struct ImGuiMetricsConfig { bool ShowDebugLog = false; @@ -2133,6 +2150,7 @@ struct ImGuiContext ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this ID ImGuiMetricsConfig DebugMetricsConfig; ImGuiIdStackTool DebugIdStackTool; + ImGuiDebugAllocInfo DebugAllocInfo; // Misc float FramerateSecPerFrame[60]; // Calculate estimate of framerate for user over the last 60 frames.. @@ -3326,6 +3344,7 @@ namespace ImGui // Debug Log IMGUI_API void DebugLog(const char* fmt, ...) IM_FMTARGS(1); IMGUI_API void DebugLogV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size); // size >= 0 : alloc, size = -1 : free // Debug Tools IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL);