From 51823d117de96fa9f029d9c176e5b95a584c82e8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 28 May 2024 17:46:00 +0200 Subject: [PATCH 01/16] Misc: made ImGuiDir, ImGuiSortDirection, ImGuiMouseCursor stronger-typed enums + cater for possible warning in backends's switch() Not making ImGuiMouseCursor one because of warnings for non-explicitly handled value (case default: is not enough). --- docs/CHANGELOG.txt | 1 + imgui.h | 32 ++++++++++++++++---------------- imgui_demo.cpp | 2 +- imgui_internal.h | 4 +++- imgui_tables.cpp | 4 ++-- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6e967fb95..e443b8066 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,7 @@ Other changes: responsible for honoring io.ConfigWindowsMoveFromTitleBarOnly. (#7576, #899) - Scrollbar: made scrolling logic more standard: clicking above or below the grab scrolls by one page, holding mouse button repeats scrolling. (#7328, #150) +- Misc: made ImGuiDir and ImGuiSortDirection stronger-typed enums. ----------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 11ccb88ee..1ef13ae94 100644 --- a/imgui.h +++ b/imgui.h @@ -143,6 +143,17 @@ Index of this file: // [SECTION] Forward declarations and basic types //----------------------------------------------------------------------------- +// Scalar data types +typedef unsigned int ImGuiID;// A unique ID used by widgets (typically the result of hashing a stack of string) +typedef signed char ImS8; // 8-bit signed integer +typedef unsigned char ImU8; // 8-bit unsigned integer +typedef signed short ImS16; // 16-bit signed integer +typedef unsigned short ImU16; // 16-bit unsigned integer +typedef signed int ImS32; // 32-bit signed integer == int +typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) +typedef signed long long ImS64; // 64-bit signed integer +typedef unsigned long long ImU64; // 64-bit unsigned integer + // Forward declarations struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit() struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback) @@ -181,15 +192,15 @@ struct ImGuiViewport; // A Platform Window (always only one in 'ma // - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. // - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. // - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments. +enum ImGuiDir : int; // -> enum ImGuiDir // Enum: A cardinal direction (Left, Right, Up, Down) enum ImGuiKey : int; // -> enum ImGuiKey // Enum: A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value) enum ImGuiMouseSource : int; // -> enum ImGuiMouseSource // Enum; A mouse input source identifier (Mouse, TouchScreen, Pen) +enum ImGuiSortDirection : ImU8; // -> enum ImGuiSortDirection // Enum: A sorting direction (ascending or descending) typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type -typedef int ImGuiDir; // -> enum ImGuiDir_ // Enum: A cardinal direction typedef int ImGuiMouseButton; // -> enum ImGuiMouseButton_ // Enum: A mouse button identifier (0=left, 1=right, 2=middle) typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor shape -typedef int ImGuiSortDirection; // -> enum ImGuiSortDirection_ // Enum: A sorting direction (ascending or descending) typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling typedef int ImGuiTableBgTarget; // -> enum ImGuiTableBgTarget_ // Enum: A color target for TableSetBgColor() @@ -239,17 +250,6 @@ typedef void* ImTextureID; // Default: store a pointer or an integer fi typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends) #endif -// Scalar data types -typedef unsigned int ImGuiID;// A unique ID used by widgets (typically the result of hashing a stack of string) -typedef signed char ImS8; // 8-bit signed integer -typedef unsigned char ImU8; // 8-bit unsigned integer -typedef signed short ImS16; // 16-bit signed integer -typedef unsigned short ImU16; // 16-bit unsigned integer -typedef signed int ImS32; // 32-bit signed integer == int -typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) -typedef signed long long ImS64; // 64-bit signed integer -typedef unsigned long long ImU64; // 64-bit unsigned integer - // Character types // (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display) typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings. @@ -1314,7 +1314,7 @@ enum ImGuiDataType_ }; // A cardinal direction -enum ImGuiDir_ +enum ImGuiDir : int { ImGuiDir_None = -1, ImGuiDir_Left = 0, @@ -1325,7 +1325,7 @@ enum ImGuiDir_ }; // A sorting direction -enum ImGuiSortDirection_ +enum ImGuiSortDirection : ImU8 { ImGuiSortDirection_None = 0, ImGuiSortDirection_Ascending = 1, // Ascending = 0->9, A->Z etc. @@ -1924,7 +1924,7 @@ struct ImGuiTableColumnSortSpecs ImGuiID ColumnUserID; // User id of the column (if specified by a TableSetupColumn() call) ImS16 ColumnIndex; // Index of the column ImS16 SortOrder; // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here) - ImGuiSortDirection SortDirection : 8; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending + ImGuiSortDirection SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending ImGuiTableColumnSortSpecs() { memset(this, 0, sizeof(*this)); } }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e497da8e6..337c1fe20 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -6768,7 +6768,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); int window_menu_button_position = style.WindowMenuButtonPosition + 1; if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) - style.WindowMenuButtonPosition = window_menu_button_position - 1; + style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1); ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); diff --git a/imgui_internal.h b/imgui_internal.h index cfe053b7e..c7234dbba 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1582,6 +1582,7 @@ enum ImGuiNavLayer ImGuiNavLayer_COUNT }; +// Storage for navigation query/results struct ImGuiNavItemData { ImGuiWindow* Window; // Init,Move // Best candidate window (result->ItemWindow->RootWindowForNav == request->Window) @@ -1598,6 +1599,7 @@ struct ImGuiNavItemData void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; } }; +// Storage for PushFocusScope() struct ImGuiFocusScopeData { ImGuiID ID; @@ -2516,6 +2518,7 @@ struct IMGUI_API ImGuiWindow int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! ImGuiID MoveId; // == window->GetID("#MOVE") ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) + ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) ImVec2 Scroll; ImVec2 ScrollMax; ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) @@ -2542,7 +2545,6 @@ struct IMGUI_API ImGuiWindow short BeginOrderWithinParent; // Begin() order within immediate parent window, if we are a child window. Otherwise 0. short BeginOrderWithinContext; // Begin() order within entire imgui context. This is mostly used for debugging submission order related issues. short FocusOrder; // Order within WindowsFocusOrder[], altered when windows are focused. - ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) ImS8 AutoFitFramesX, AutoFitFramesY; bool AutoFitOnlyGrows; ImGuiDir AutoPosLastDirection; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index f11b2ff1b..d5848cb50 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -2795,7 +2795,7 @@ ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() static inline ImGuiSortDirection TableGetColumnAvailSortDirection(ImGuiTableColumn* column, int n) { IM_ASSERT(n < column->SortDirectionsAvailCount); - return (column->SortDirectionsAvailList >> (n << 1)) & 0x03; + return (ImGuiSortDirection)((column->SortDirectionsAvailList >> (n << 1)) & 0x03); } // Fix sort direction if currently set on a value which is unavailable (e.g. activating NoSortAscending/NoSortDescending) @@ -2949,7 +2949,7 @@ void ImGui::TableSortSpecsBuild(ImGuiTable* table) sort_spec->ColumnUserID = column->UserID; sort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n; sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder; - sort_spec->SortDirection = column->SortDirection; + sort_spec->SortDirection = (ImGuiSortDirection)column->SortDirection; } table->SortSpecs.Specs = sort_specs; From 109a8632d7617c117d1356265ff31dd658d8f9f1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 28 May 2024 18:18:35 +0200 Subject: [PATCH 02/16] Combo: simplified Combo() API uses a list clipper. Wasn't as trivial before supporting IncludeItemByIndex(). --- docs/CHANGELOG.txt | 2 ++ docs/TODO.txt | 1 - imgui_widgets.cpp | 37 ++++++++++++++++++++----------------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e443b8066..154ae8ff8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,8 @@ Other changes: responsible for honoring io.ConfigWindowsMoveFromTitleBarOnly. (#7576, #899) - Scrollbar: made scrolling logic more standard: clicking above or below the grab scrolls by one page, holding mouse button repeats scrolling. (#7328, #150) +- Combo: simplified Combo() API uses a list clipper (due to its api it wasn't + previously trivial before we added clipper.IncludeItemByIndex() function). - Misc: made ImGuiDir and ImGuiSortDirection stronger-typed enums. diff --git a/docs/TODO.txt b/docs/TODO.txt index 734c4d078..eecce6b42 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -151,7 +151,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - drag float: added leeway on edge (e.g. a few invisible steps past the clamp limits) - combo: a way/helper to customize the combo preview (#1658) -> experimental BeginComboPreview() - - combo: Combo() helper could use clipper. - combo/listbox: keyboard control. need InputText-like non-active focus + key handling. considering keyboard for custom listbox (pr #203) - listbox: multiple selection (WIP range-select branch) - listbox: unselect option (#1208) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f09c3c30c..277588e47 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1952,28 +1952,30 @@ bool ImGui::Combo(const char* label, int* current_item, const char* (*getter)(vo return false; // Display items - // FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed) bool value_changed = false; - for (int i = 0; i < items_count; i++) - { - const char* item_text = getter(user_data, i); - if (item_text == NULL) - item_text = "*Unknown item*"; - - PushID(i); - const bool item_selected = (i == *current_item); - if (Selectable(item_text, item_selected) && *current_item != i) + ImGuiListClipper clipper; + clipper.Begin(items_count); + clipper.IncludeItemByIndex(*current_item); + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - value_changed = true; - *current_item = i; + const char* item_text = getter(user_data, i); + if (item_text == NULL) + item_text = "*Unknown item*"; + + PushID(i); + const bool item_selected = (i == *current_item); + if (Selectable(item_text, item_selected) && *current_item != i) + { + value_changed = true; + *current_item = i; + } + if (item_selected) + SetItemDefaultFocus(); + PopID(); } - if (item_selected) - SetItemDefaultFocus(); - PopID(); - } EndCombo(); - if (value_changed) MarkItemEdited(g.LastItemData.ID); @@ -7011,6 +7013,7 @@ bool ImGui::ListBox(const char* label, int* current_item, const char* (*getter)( bool value_changed = false; ImGuiListClipper clipper; clipper.Begin(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. + clipper.IncludeItemByIndex(*current_item); while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { From 868f4446209b2bb066b007a14c303bde31d5f6db Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 May 2024 16:07:59 +0200 Subject: [PATCH 03/16] Debug: extracted debug log 0xXXXXXXX scanning into a helper function. (#5855) --- docs/README.md | 2 +- imgui.cpp | 42 +++++++++++++++++++++++------------------- imgui.h | 2 +- imgui_internal.h | 1 + 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/docs/README.md b/docs/README.md index f4988cba4..78cf2fea0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -162,7 +162,7 @@ See: [Upcoming Changes](https://github.com/ocornut/imgui/wiki/Upcoming-Changes). See: [Dear ImGui Test Engine + Test Suite](https://github.com/ocornut/imgui_test_engine) for Automation & Testing. -For the purposes of getting search engines to crawl the wiki, here's a link to the [Crawable Wiki](https://github-wiki-see.page/m/ocornut/imgui/wiki) (not for humans, [here's why](https://github-wiki-see.page/)). +For the purposes of getting search engines to crawl the wiki, here's a link to the [Crawlable Wiki](https://github-wiki-see.page/m/ocornut/imgui/wiki) (not for humans, [here's why](https://github-wiki-see.page/)). Getting started? For first-time users having issues compiling/linking/running or issues loading fonts, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions). For ANY other questions, bug reports, requests, feedback, please post on [GitHub Issues](https://github.com/ocornut/imgui/issues). Please read and fill the New Issue template carefully. diff --git a/imgui.cpp b/imgui.cpp index cd40278c6..4f9152d9f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15637,25 +15637,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) clipper.Begin(g.DebugLogIndex.size()); while (clipper.Step()) for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) - { - const char* line_begin = g.DebugLogIndex.get_line_begin(g.DebugLogBuf.c_str(), line_no); - const char* line_end = g.DebugLogIndex.get_line_end(g.DebugLogBuf.c_str(), line_no); - TextUnformatted(line_begin, line_end); // Display line - ImRect text_rect = g.LastItemData.Rect; - if (IsItemHovered()) - for (const char* p = line_begin; p <= line_end - 10; p++) // Search for 0x???????? identifiers - { - ImGuiID id = 0; - if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1) - continue; - ImVec2 p0 = CalcTextSize(line_begin, p); - ImVec2 p1 = CalcTextSize(p, p + 10); - g.LastItemData.Rect = ImRect(text_rect.Min + ImVec2(p0.x, 0.0f), text_rect.Min + ImVec2(p0.x + p1.x, p1.y)); - if (IsMouseHoveringRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, true)) - DebugLocateItemOnHover(id); - p += 10; - } - } + DebugTextUnformattedWithLocateItem(g.DebugLogIndex.get_line_begin(g.DebugLogBuf.c_str(), line_no), g.DebugLogIndex.get_line_end(g.DebugLogBuf.c_str(), line_no)); g.DebugLogFlags = backup_log_flags; if (GetScrollY() >= GetScrollMaxY()) SetScrollHereY(1.0f); @@ -15664,6 +15646,28 @@ void ImGui::ShowDebugLogWindow(bool* p_open) End(); } +// Display line, search for 0xXXXXXXXX identifiers and call DebugLocateItemOnHover() when hovered. +void ImGui::DebugTextUnformattedWithLocateItem(const char* line_begin, const char* line_end) +{ + TextUnformatted(line_begin, line_end); + if (!IsItemHovered()) + return; + ImGuiContext& g = *GImGui; + ImRect text_rect = g.LastItemData.Rect; + for (const char* p = line_begin; p <= line_end - 10; p++) + { + ImGuiID id = 0; + if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1) + continue; + ImVec2 p0 = CalcTextSize(line_begin, p); + ImVec2 p1 = CalcTextSize(p, p + 10); + g.LastItemData.Rect = ImRect(text_rect.Min + ImVec2(p0.x, 0.0f), text_rect.Min + ImVec2(p0.x + p1.x, p1.y)); + if (IsMouseHoveringRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, true)) + DebugLocateItemOnHover(id); + p += 10; + } +} + //----------------------------------------------------------------------------- // [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, ID STACK TOOL) //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 1ef13ae94..aef2bf22c 100644 --- a/imgui.h +++ b/imgui.h @@ -28,7 +28,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.90.8 WIP" -#define IMGUI_VERSION_NUM 19071 +#define IMGUI_VERSION_NUM 19072 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index c7234dbba..2a31473c5 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3495,6 +3495,7 @@ namespace ImGui IMGUI_API void DebugDrawCursorPos(ImU32 col = IM_COL32(255, 0, 0, 255)); IMGUI_API void DebugDrawLineExtents(ImU32 col = IM_COL32(255, 0, 0, 255)); IMGUI_API void DebugDrawItemRect(ImU32 col = IM_COL32(255, 0, 0, 255)); + IMGUI_API void DebugTextUnformattedWithLocateItem(const char* line_begin, const char* line_end); IMGUI_API void DebugLocateItem(ImGuiID target_id); // Call sparingly: only 1 at the same time! IMGUI_API void DebugLocateItemOnHover(ImGuiID target_id); // Only call on reaction to a mouse Hover: because only 1 at the same time! IMGUI_API void DebugLocateItemResolveWithLastItem(); From 661c3885159cb1714ca7e9aebe158cdf4ddebd2a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 May 2024 18:11:07 +0200 Subject: [PATCH 04/16] Debug Log, Test Engine: avoid duplicate carriage return when using ImGuiDebugLogFlags_OutputToTestEngine. (#5855) --- imgui.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 4f9152d9f..4d1c5f051 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15568,8 +15568,11 @@ void ImGui::DebugLogV(const char* fmt, va_list args) if (g.DebugLogFlags & ImGuiDebugLogFlags_OutputToTTY) IMGUI_DEBUG_PRINTF("%s", g.DebugLogBuf.begin() + old_size); #ifdef IMGUI_ENABLE_TEST_ENGINE + // IMGUI_TEST_ENGINE_LOG() adds a trailing \n automatically + const int new_size = g.DebugLogBuf.size(); + const bool trailing_carriage_return = (g.DebugLogBuf[new_size - 1] == '\n'); if (g.DebugLogFlags & ImGuiDebugLogFlags_OutputToTestEngine) - IMGUI_TEST_ENGINE_LOG("%s", g.DebugLogBuf.begin() + old_size); + IMGUI_TEST_ENGINE_LOG("%.*s", new_size - old_size - (trailing_carriage_return ? 1 : 0), g.DebugLogBuf.begin() + old_size); #endif } From 97a1111b94c7bb989e393c9a11b647c7585ac72e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 May 2024 18:27:04 +0200 Subject: [PATCH 05/16] Drag and Drop: tweaked BeginDragDropSource() to remove indent. Added debug log. --- imgui.cpp | 75 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4d1c5f051..a917148e8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13096,6 +13096,8 @@ bool ImGui::IsDragDropActive() void ImGui::ClearDragDrop() { ImGuiContext& g = *GImGui; + if (g.DragDropActive) + IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] ClearDragDrop()\n"); g.DragDropActive = false; g.DragDropPayload.Clear(); g.DragDropAcceptFlags = ImGuiDragDropFlags_None; @@ -13134,7 +13136,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) bool source_drag_active = false; ImGuiID source_id = 0; ImGuiID source_parent_id = 0; - if (!(flags & ImGuiDragDropFlags_SourceExtern)) + if ((flags & ImGuiDragDropFlags_SourceExtern) == 0) { source_id = g.LastItemData.ID; if (source_id != 0) @@ -13196,43 +13198,44 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) } IM_ASSERT(g.DragDropWithinTarget == false); // Can't nest BeginDragDropSource() and BeginDragDropTarget() - if (source_drag_active) + if (!source_drag_active) + return false; + + // Activate drag and drop + if (!g.DragDropActive) { - if (!g.DragDropActive) - { - IM_ASSERT(source_id != 0); - ClearDragDrop(); - ImGuiPayload& payload = g.DragDropPayload; - payload.SourceId = source_id; - payload.SourceParentId = source_parent_id; - g.DragDropActive = true; - g.DragDropSourceFlags = flags; - g.DragDropMouseButton = mouse_button; - if (payload.SourceId == g.ActiveId) - g.ActiveIdNoClearOnFocusLoss = true; - } - g.DragDropSourceFrameCount = g.FrameCount; - g.DragDropWithinSource = true; - - if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) - { - // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) - // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. - bool ret; - if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) - ret = BeginTooltipHidden(); - else - ret = BeginTooltip(); - IM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin("##Hidden", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame(). - IM_UNUSED(ret); - } - - if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) - g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; - - return true; + IM_ASSERT(source_id != 0); + ClearDragDrop(); + IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] BeginDragDropSource() DragDropActive = true, source_id = %08X\n", source_id); + ImGuiPayload& payload = g.DragDropPayload; + payload.SourceId = source_id; + payload.SourceParentId = source_parent_id; + g.DragDropActive = true; + g.DragDropSourceFlags = flags; + g.DragDropMouseButton = mouse_button; + if (payload.SourceId == g.ActiveId) + g.ActiveIdNoClearOnFocusLoss = true; } - return false; + g.DragDropSourceFrameCount = g.FrameCount; + g.DragDropWithinSource = true; + + if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + { + // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) + // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. + bool ret; + if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) + ret = BeginTooltipHidden(); + else + ret = BeginTooltip(); + IM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin("##Hidden", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame(). + IM_UNUSED(ret); + } + + if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) + g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; + + return true; } void ImGui::EndDragDropSource() From e47015aef411f2132fba0ce57a998a5174f87dea Mon Sep 17 00:00:00 2001 From: Rodrigo Rivas Costa Date: Thu, 30 May 2024 19:53:12 +0200 Subject: [PATCH 06/16] Demo: remove incompatible ImGuiInputFlags for Shortcut(). (#7637) --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 337c1fe20..8183ee1ae 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -6295,7 +6295,7 @@ static void ShowDemoWindowInputs() ImGui::RadioButton("ImGuiInputFlags_RouteAlways", &route_type, ImGuiInputFlags_RouteAlways); ImGuiInputFlags flags = route_type | route_options; // Merged flags if (route_type != ImGuiInputFlags_RouteGlobal) - route_options &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused); + flags &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused); ImGui::SeparatorText("Using SetNextItemShortcut()"); ImGui::Text("Ctrl+S"); From f953ebf9ca15bbe1477d4cef499009faa8110814 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 31 May 2024 18:13:25 +0200 Subject: [PATCH 07/16] Disabled: nested tooltips or other non-child window within a BeginDisabled() block disable the disabled state. (#211, #7640) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- imgui.h | 2 +- imgui_internal.h | 3 +++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 154ae8ff8..3b4ff8238 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -49,6 +49,8 @@ Other changes: grab scrolls by one page, holding mouse button repeats scrolling. (#7328, #150) - Combo: simplified Combo() API uses a list clipper (due to its api it wasn't previously trivial before we added clipper.IncludeItemByIndex() function). +- Disabled: nested tooltips or other non-child window within a BeginDisabled() + block disable the disabled state. (#211, #7640) - Misc: made ImGuiDir and ImGuiSortDirection stronger-typed enums. diff --git a/imgui.cpp b/imgui.cpp index a917148e8..cbcf8278a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6648,6 +6648,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // [EXPERIMENTAL] Skip Refresh mode UpdateWindowSkipRefresh(window); + // Nested root windows (typically tooltips) override disabled state + if (window->RootWindow == window) + if ((window->DC.BackupItemDisabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0)) + BeginDisabledOverrideReenable(); + // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() g.CurrentWindow = NULL; @@ -7259,6 +7264,8 @@ void ImGui::End() if (!window->SkipRefresh) PopClipRect(); // Inner window clip rectangle PopFocusScope(); + if (window->RootWindow == window && window->DC.BackupItemDisabled) + EndDisabledOverrideReenable(); if (window->SkipRefresh) { @@ -7523,7 +7530,7 @@ void ImGui::BeginDisabled(bool disabled) } if (was_disabled || disabled) g.CurrentItemFlags |= ImGuiItemFlags_Disabled; - g.ItemFlagsStack.push_back(g.CurrentItemFlags); + g.ItemFlagsStack.push_back(g.CurrentItemFlags); // FIXME-OPT: can we simply skip this and use DisabledStackSize? g.DisabledStackSize++; } @@ -7540,6 +7547,29 @@ void ImGui::EndDisabled() g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar(); } +// Could have been called BeginDisabledDisable() but it didn't want to be award nominated for most awkward function name. +// Ideally we would use a shared e.g. BeginDisabled()->BeginDisabledEx() but earlier needs to be optimal. +// The whole code for this is awkward, will reevaluate if we find a way to implement SetNextItemDisabled(). +void ImGui::BeginDisabledOverrideReenable() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.CurrentItemFlags & ImGuiItemFlags_Disabled); + g.Style.Alpha = g.DisabledAlphaBackup; + g.CurrentItemFlags &= ~ImGuiItemFlags_Disabled; + g.ItemFlagsStack.push_back(g.CurrentItemFlags); + g.DisabledStackSize++; +} + +void ImGui::EndDisabledOverrideReenable() +{ + ImGuiContext& g = *GImGui; + g.DisabledStackSize--; + IM_ASSERT(g.DisabledStackSize > 0); + g.ItemFlagsStack.pop_back(); + g.CurrentItemFlags = g.ItemFlagsStack.back(); + g.Style.Alpha = g.DisabledAlphaBackup * g.Style.DisabledAlpha; +} + void ImGui::PushTabStop(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); @@ -9995,7 +10025,13 @@ void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, vo while (g.DisabledStackSize > stack_sizes->SizeOfDisabledStack) //-V1044 { if (log_callback) log_callback(user_data, "Recovered from missing EndDisabled() in '%s'", window->Name); - EndDisabled(); + if (g.CurrentItemFlags & ImGuiItemFlags_Disabled) + EndDisabled(); + else + { + EndDisabledOverrideReenable(); + window->DC.BackupItemDisabled = false; + } } while (g.ColorStack.Size > stack_sizes->SizeOfColorStack) { diff --git a/imgui.h b/imgui.h index aef2bf22c..689604ba4 100644 --- a/imgui.h +++ b/imgui.h @@ -28,7 +28,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.90.8 WIP" -#define IMGUI_VERSION_NUM 19072 +#define IMGUI_VERSION_NUM 19073 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index 2a31473c5..228a0f7e2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2472,6 +2472,7 @@ struct IMGUI_API ImGuiWindowTempData bool NavWindowHasScrollY; // Set per window when scrolling can be used (== ScrollMax.y > 0.0f) // Miscellaneous + bool BackupItemDisabled; // Non-child window override disabled flag bool MenuBarAppending; // FIXME: Remove this ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items measurement @@ -3127,6 +3128,8 @@ namespace ImGui IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); IMGUI_API void PopItemFlag(); IMGUI_API const ImGuiDataVarInfo* GetStyleVarInfo(ImGuiStyleVar idx); + IMGUI_API void BeginDisabledOverrideReenable(); + IMGUI_API void EndDisabledOverrideReenable(); // Logging/Capture IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. From 538960bf17d1bfb5a6c57d6b735b1457345ac1bc Mon Sep 17 00:00:00 2001 From: Cyao <94928179+cheyao@users.noreply.github.com> Date: Fri, 31 May 2024 18:16:45 +0200 Subject: [PATCH 08/16] Examples: Fixed SDL3 Makefile (#7641) --- examples/example_sdl3_opengl3/Makefile | 6 +++--- examples/example_sdl3_sdlrenderer3/Makefile | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/example_sdl3_opengl3/Makefile b/examples/example_sdl3_opengl3/Makefile index 3a00a31e7..741e97d0c 100644 --- a/examples/example_sdl3_opengl3/Makefile +++ b/examples/example_sdl3_opengl3/Makefile @@ -37,9 +37,9 @@ LIBS = ifeq ($(UNAME_S), Linux) #LINUX ECHO_MESSAGE = "Linux" - LIBS += $(LINUX_GL_LIBS) -ldl `sdl3-config --libs` + LIBS += $(LINUX_GL_LIBS) -ldl `pkg-config sdl3 --libs` - CXXFLAGS += `sdl3-config --cflags` + CXXFLAGS += `pkg-config sdl3 --cflags` CFLAGS = $(CXXFLAGS) endif @@ -48,7 +48,7 @@ ifeq ($(UNAME_S), Darwin) #APPLE LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl3-config --libs` LIBS += -L/usr/local/lib -L/opt/local/lib - CXXFLAGS += `sdl3-config --cflags` + CXXFLAGS += `pkg-config sdl3 --cflags` CXXFLAGS += -I/usr/local/include -I/opt/local/include CFLAGS = $(CXXFLAGS) endif diff --git a/examples/example_sdl3_sdlrenderer3/Makefile b/examples/example_sdl3_sdlrenderer3/Makefile index d0a73bf16..238576c7c 100644 --- a/examples/example_sdl3_sdlrenderer3/Makefile +++ b/examples/example_sdl3_sdlrenderer3/Makefile @@ -26,9 +26,9 @@ LIBS = ifeq ($(UNAME_S), Linux) #LINUX ECHO_MESSAGE = "Linux" - LIBS += -ldl `sdl3-config --libs` + LIBS += -ldl `pkg-config sdl3 --libs` - CXXFLAGS += `sdl3-config --cflags` + CXXFLAGS += `pkg-config sdl3 --cflags` CFLAGS = $(CXXFLAGS) endif @@ -37,7 +37,7 @@ ifeq ($(UNAME_S), Darwin) #APPLE LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl3-config --libs` LIBS += -L/usr/local/lib -L/opt/local/lib - CXXFLAGS += `sdl3-config --cflags` + CXXFLAGS += `pkg-config sdl3 --cflags` CXXFLAGS += -I/usr/local/include -I/opt/local/include CFLAGS = $(CXXFLAGS) endif From 854e21d4b4c8ce3d65cb0e38754458516904743c Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 31 May 2024 18:23:47 +0200 Subject: [PATCH 09/16] Disabled: move field to ImGuiWindowStackData. (#7640) Amend f953ebf --- imgui.cpp | 16 ++++++++-------- imgui_internal.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cbcf8278a..22333b70f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6562,6 +6562,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window_stack_data.Window = window; window_stack_data.ParentLastItemDataBackup = g.LastItemData; window_stack_data.StackSizesOnBegin.SetToContextState(&g); + window_stack_data.DisabledOverrideReenable = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; g.CurrentWindowStack.push_back(window_stack_data); if (flags & ImGuiWindowFlags_ChildMenu) g.BeginMenuDepth++; @@ -6649,9 +6650,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) UpdateWindowSkipRefresh(window); // Nested root windows (typically tooltips) override disabled state - if (window->RootWindow == window) - if ((window->DC.BackupItemDisabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0)) - BeginDisabledOverrideReenable(); + if (window_stack_data.DisabledOverrideReenable && window->RootWindow == window) + BeginDisabledOverrideReenable(); // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() g.CurrentWindow = NULL; @@ -7252,7 +7252,7 @@ void ImGui::End() IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!"); return; } - IM_ASSERT(g.CurrentWindowStack.Size > 0); + ImGuiWindowStackData& window_stack_data = g.CurrentWindowStack.back(); // Error checking: verify that user doesn't directly call End() on a child window. if (window->Flags & ImGuiWindowFlags_ChildWindow) @@ -7264,7 +7264,7 @@ void ImGui::End() if (!window->SkipRefresh) PopClipRect(); // Inner window clip rectangle PopFocusScope(); - if (window->RootWindow == window && window->DC.BackupItemDisabled) + if (window_stack_data.DisabledOverrideReenable && window->RootWindow == window) EndDisabledOverrideReenable(); if (window->SkipRefresh) @@ -7281,12 +7281,12 @@ void ImGui::End() ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); // Pop from window stack - g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup; + g.LastItemData = window_stack_data.ParentLastItemDataBackup; if (window->Flags & ImGuiWindowFlags_ChildMenu) g.BeginMenuDepth--; if (window->Flags & ImGuiWindowFlags_Popup) g.BeginPopupStack.pop_back(); - g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithContextState(&g); + window_stack_data.StackSizesOnBegin.CompareWithContextState(&g); g.CurrentWindowStack.pop_back(); SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window); } @@ -10030,7 +10030,7 @@ void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, vo else { EndDisabledOverrideReenable(); - window->DC.BackupItemDisabled = false; + g.CurrentWindowStack.back().DisabledOverrideReenable = false; } } while (g.ColorStack.Size > stack_sizes->SizeOfColorStack) diff --git a/imgui_internal.h b/imgui_internal.h index 228a0f7e2..fbc3fe41d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1243,7 +1243,8 @@ struct ImGuiWindowStackData { ImGuiWindow* Window; ImGuiLastItemData ParentLastItemDataBackup; - ImGuiStackSizes StackSizesOnBegin; // Store size of various stacks for asserting + ImGuiStackSizes StackSizesOnBegin; // Store size of various stacks for asserting + bool DisabledOverrideReenable; // Non-child window override disabled flag }; struct ImGuiShrinkWidthItem @@ -2472,7 +2473,6 @@ struct IMGUI_API ImGuiWindowTempData bool NavWindowHasScrollY; // Set per window when scrolling can be used (== ScrollMax.y > 0.0f) // Miscellaneous - bool BackupItemDisabled; // Non-child window override disabled flag bool MenuBarAppending; // FIXME: Remove this ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items measurement From 0fce21e8906a8ad9fa09659531afaf2f738a5432 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 31 May 2024 20:57:43 +0200 Subject: [PATCH 10/16] Internals: Disable 0xCC stack fill for ItemAdd()/ItemSize(). --- imgui.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 22333b70f..932abf919 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10120,6 +10120,7 @@ void ImGui::KeepAliveID(ImGuiID id) // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface // declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction. // THIS IS IN THE PERFORMANCE CRITICAL PATH (UNTIL THE CLIPPING TEST AND EARLY-RETURN) +IM_MSVC_RUNTIME_CHECKS_OFF bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemFlags extra_flags) { ImGuiContext& g = *GImGui; @@ -10207,7 +10208,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; return true; } - +IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- // [SECTION] LAYOUT @@ -10244,6 +10245,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu // Register minimum needed size so it can extend the bounding box used for auto-fit calculation. // See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different. // THIS IS IN THE PERFORMANCE CRITICAL PATH. +IM_MSVC_RUNTIME_CHECKS_OFF void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) { ImGuiContext& g = *GImGui; @@ -10279,6 +10281,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) SameLine(); } +IM_MSVC_RUNTIME_CHECKS_RESTORE // Gets back to previous line and continue with horizontal layout // offset_from_start_x == 0 : follow right after previous item From 9aec6d7217cf782b156fdf392f42ed8329ed62d4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 31 May 2024 20:35:22 +0200 Subject: [PATCH 11/16] Internals: Added ItemUnclipByLog for use by ItemAdd(), as we expected to add more. --- imgui.cpp | 13 +++++-------- imgui_internal.h | 8 +++++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 932abf919..a4a578c6f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4237,7 +4237,7 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id) ImGuiWindow* window = g.CurrentWindow; if (!bb.Overlaps(window->ClipRect)) if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId && id != g.NavActivateId)) - if (!g.LogEnabled) + if (!g.ItemUnclipByLog) return true; return false; } @@ -10173,15 +10173,12 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu #endif // Clipping test - // (this is a modified copy of IsClippedEx() so we can reuse the is_rect_visible value) - //const bool is_clipped = IsClippedEx(bb, id); - //if (is_clipped) - // return false; + // (this is an inline copy of IsClippedEx() so we can reuse the is_rect_visible value, otherwise we'd do 'if (IsClippedEx(bb, id)) return false') // g.NavActivateId is not necessarily == g.NavId, in the case of remote activation (e.g. shortcuts) const bool is_rect_visible = bb.Overlaps(window->ClipRect); if (!is_rect_visible) if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId && id != g.NavActivateId)) - if (!g.LogEnabled) + if (!g.ItemUnclipByLog) return false; // [DEBUG] @@ -13585,7 +13582,7 @@ void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) IM_ASSERT(g.LogEnabled == false); IM_ASSERT(g.LogFile == NULL); IM_ASSERT(g.LogBuffer.empty()); - g.LogEnabled = true; + g.LogEnabled = g.ItemUnclipByLog = true; g.LogType = type; g.LogNextPrefix = g.LogNextSuffix = NULL; g.LogDepthRef = window->DC.TreeDepth; @@ -13684,7 +13681,7 @@ void ImGui::LogFinish() break; } - g.LogEnabled = false; + g.LogEnabled = g.ItemUnclipByLog = false; g.LogType = ImGuiLogType_None; g.LogFile = NULL; g.LogBuffer.clear(); diff --git a/imgui_internal.h b/imgui_internal.h index fbc3fe41d..873369833 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1966,10 +1966,11 @@ struct ImGuiContext 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; - bool HoveredIdDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0. float HoveredIdTimer; // Measure contiguous hovering time float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active + bool HoveredIdAllowOverlap; + bool HoveredIdDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0. + bool ItemUnclipByLog; // Disable ItemAdd() clipping, essentially a memory-locality friendly copy of LogEnabled ImGuiID ActiveId; // Active widget ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame) float ActiveIdTimer; @@ -2036,11 +2037,11 @@ struct ImGuiContext ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow' ImGuiID NavId; // Focused item for navigation ImGuiID NavFocusScopeId; // Focused focus scope (e.g. selection code often wants to "clear other items" when landing on an item of the same scope) - ImVector NavFocusRoute; // Reversed copy focus scope stack for NavId (should contains NavFocusScopeId). This essentially follow the window->ParentWindowForFocusRoute chain. ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem() ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0 ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat) ImGuiActivateFlags NavActivateFlags; + ImVector NavFocusRoute; // Reversed copy focus scope stack for NavId (should contains NavFocusScopeId). This essentially follow the window->ParentWindowForFocusRoute chain. ImGuiID NavHighlightActivatedId; float NavHighlightActivatedTimer; ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest). @@ -2277,6 +2278,7 @@ struct ImGuiContext HoveredIdAllowOverlap = false; HoveredIdDisabled = false; HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; + ItemUnclipByLog = false; ActiveId = 0; ActiveIdIsAlive = 0; ActiveIdTimer = 0.0f; From 8ab89657139f48911bafb01e264a454db270a5a7 Mon Sep 17 00:00:00 2001 From: SleekZ <40346672+SleekZ@users.noreply.github.com> Date: Sat, 1 Jun 2024 17:54:20 +1000 Subject: [PATCH 12/16] Improved clarity in comment. (#7642) --- imgui_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index 873369833..0d5cd43a6 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2998,7 +2998,7 @@ namespace ImGui { // Windows // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) - // If this ever crash because g.CurrentWindow is NULL it means that either + // If this ever crashes because g.CurrentWindow is NULL, it means that either: // - ImGui::NewFrame() has never been called, which is illegal. // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } From 6cefd4fd88c47884933c828e3ad725f7675c52f7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Jun 2024 16:41:19 +0200 Subject: [PATCH 13/16] Scrollbar: fixed miscalculation of vertical scrollbar visibility when required solely by the presence of an horizontal scrollbar. (#1574) Initially fixed by 2d9d7a10c, and broken back by a0994d74c2 (v1.71, wow). --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 +- imgui.h | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3b4ff8238..0c5550f99 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,8 @@ Other changes: responsible for honoring io.ConfigWindowsMoveFromTitleBarOnly. (#7576, #899) - Scrollbar: made scrolling logic more standard: clicking above or below the grab scrolls by one page, holding mouse button repeats scrolling. (#7328, #150) +- Scrollbar: fixed miscalculation of vertical scrollbar visibility when required + solely by the presence of an horizontal scrollbar. (#1574) - Combo: simplified Combo() API uses a list clipper (due to its api it wasn't previously trivial before we added clipper.IncludeItemByIndex() function). - Disabled: nested tooltips or other non-child window within a BeginDisabled() diff --git a/imgui.cpp b/imgui.cpp index a4a578c6f..96a0ca118 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6926,7 +6926,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); if (window->ScrollbarX && !window->ScrollbarY) - window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar); window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); // Amend the partially filled window->DecorationXXX values. diff --git a/imgui.h b/imgui.h index 689604ba4..477cf4b5f 100644 --- a/imgui.h +++ b/imgui.h @@ -28,7 +28,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.90.8 WIP" -#define IMGUI_VERSION_NUM 19073 +#define IMGUI_VERSION_NUM 19074 #define IMGUI_HAS_TABLE /* From 68a05e3f0400442e9af743e7555b5ae552e66ed3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Jun 2024 17:16:28 +0200 Subject: [PATCH 14/16] Tables: fixed a bug where after disabling the ScrollY flag for a table, previous scrollbar width would be accounted for. (#5920) Amend 317b33d6 --- docs/CHANGELOG.txt | 2 ++ imgui_tables.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0c5550f99..cd71c6d9f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -49,6 +49,8 @@ Other changes: grab scrolls by one page, holding mouse button repeats scrolling. (#7328, #150) - Scrollbar: fixed miscalculation of vertical scrollbar visibility when required solely by the presence of an horizontal scrollbar. (#1574) +- Tables: fixed a bug where after disabling the ScrollY flag for a table, + previous scrollbar width would be accounted for. (#5920) - Combo: simplified Combo() API uses a list clipper (due to its api it wasn't previously trivial before we added clipper.IncludeItemByIndex() function). - Disabled: nested tooltips or other non-child window within a BeginDisabled() diff --git a/imgui_tables.cpp b/imgui_tables.cpp index d5848cb50..99d09c6df 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -437,6 +437,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG // For non-scrolling tables, WorkRect == OuterRect == InnerRect. // But at this point we do NOT have a correct value for .Max.y (unless a height has been explicitly passed in). It will only be updated in EndTable(). table->WorkRect = table->OuterRect = table->InnerRect = outer_rect; + table->HasScrollbarYPrev = table->HasScrollbarYCurr = false; } // Push a standardized ID for both child-using and not-child-using tables @@ -1490,9 +1491,10 @@ void ImGui::EndTable() } else if (temp_data->UserOuterSize.x <= 0.0f) { + const float inner_content_max_x = table->OuterRect.Min.x + table->ColumnsAutoFitWidth; // Slightly misleading name but used for code symmetry with inner_content_max_y const float decoration_size = table->TempData->AngledHeadersExtraWidth + ((table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f); - outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth + decoration_size - temp_data->UserOuterSize.x); - outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth)); + outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, inner_content_max_x + decoration_size - temp_data->UserOuterSize.x); + outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, inner_content_max_x)); } else { From f8de9fec8c5dc72fca6c35fc6052a8bb9813f5fc Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Jun 2024 18:25:58 +0200 Subject: [PATCH 15/16] Backends: SDL3: Update for SDL_SYSTEM_CURSOR_xxx api renames. (#7653) --- backends/imgui_impl_sdl3.cpp | 18 +++++++++--------- docs/CHANGELOG.txt | 1 + 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 083876611..3da22f9b5 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -413,15 +413,15 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->WantUpdateGamepadsList = true; // Load mouse cursors - bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); - bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); - bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL); - bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); - bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); - bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); - bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); - bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); - bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO); + bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT); + bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_TEXT); + bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE); + bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NS_RESIZE); + bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_EW_RESIZE); + bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NESW_RESIZE); + bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NWSE_RESIZE); + bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER); + bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED); // Set platform dependent data in viewport // Our mouse update function expect PlatformHandle to be filled for the main viewport diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index cd71c6d9f..2f74efc98 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,7 @@ Other changes: - Disabled: nested tooltips or other non-child window within a BeginDisabled() block disable the disabled state. (#211, #7640) - Misc: made ImGuiDir and ImGuiSortDirection stronger-typed enums. +- Backends: SDL3: Update for SDL_SYSTEM_CURSOR_xxx api renames. (#7653) ----------------------------------------------------------------------- From a31aa683ff91077a1a701d40acd55e3181fa2f4d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Jun 2024 19:02:28 +0200 Subject: [PATCH 16/16] Tables: fixed an issue where ideal size reported to parent container wouldn't correctly take account of inner scrollbar. (#7651) --- docs/CHANGELOG.txt | 3 +++ imgui_tables.cpp | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2f74efc98..7f3be8b0d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -49,6 +49,9 @@ Other changes: grab scrolls by one page, holding mouse button repeats scrolling. (#7328, #150) - Scrollbar: fixed miscalculation of vertical scrollbar visibility when required solely by the presence of an horizontal scrollbar. (#1574) +- Tables: fixed an issue where ideal size reported to parent container wouldn't + correctly take account of inner scrollbar, affecting potential auto-resize of + parent container. (#7651) - Tables: fixed a bug where after disabling the ScrollY flag for a table, previous scrollbar width would be accounted for. (#5920) - Combo: simplified Combo() API uses a list clipper (due to its api it wasn't diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 99d09c6df..34ab36e6e 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1491,10 +1491,13 @@ void ImGui::EndTable() } else if (temp_data->UserOuterSize.x <= 0.0f) { + // Some references for this: #7651 + tests "table_reported_size", "table_reported_size_outer" equivalent Y block + // - Checking for ImGuiTableFlags_ScrollX/ScrollY flag makes us a frame ahead when disabling those flags. + // - FIXME-TABLE: Would make sense to pre-compute expected scrollbar visibility/sizes to generally save a frame of feedback. const float inner_content_max_x = table->OuterRect.Min.x + table->ColumnsAutoFitWidth; // Slightly misleading name but used for code symmetry with inner_content_max_y - const float decoration_size = table->TempData->AngledHeadersExtraWidth + ((table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f); + const float decoration_size = table->TempData->AngledHeadersExtraWidth + ((table->Flags & ImGuiTableFlags_ScrollY) ? inner_window->ScrollbarSizes.x : 0.0f); outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, inner_content_max_x + decoration_size - temp_data->UserOuterSize.x); - outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, inner_content_max_x)); + outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, inner_content_max_x + decoration_size)); } else { @@ -1502,9 +1505,9 @@ void ImGui::EndTable() } if (temp_data->UserOuterSize.y <= 0.0f) { - const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollY) ? inner_window->ScrollbarSizes.y : 0.0f; + const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.y : 0.0f; outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, inner_content_max_y + decoration_size - temp_data->UserOuterSize.y); - outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, inner_content_max_y)); + outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, inner_content_max_y + decoration_size)); } else {