From 0a53b45858fbb20f10c141794f2f107bd6b68e26 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 Jun 2023 11:14:51 +0200 Subject: [PATCH 01/15] CollapsingHeader/TreeNode: Fixed text padding when using _Framed+_Leaf flags. (#6549) --- docs/CHANGELOG.txt | 4 +++- imgui_widgets.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 076b3e838..77ac2a911 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -67,7 +67,9 @@ Other changes: - IsWindowHovered, IsItemHovered: Assert when passed any unsupported flags. - Tables: Fixed a regression in 1.89.6 leading to the first column of tables with either ScrollX or ScrollY flags from being impossible to resize. (#6503) -- InputText: Fixed not returning true when buffer is cleared by ImGuiInputTextFlags_EscapeClearsAll. (#5688, #2620) +- CollapsingHeader/TreeNode: Fixed text padding when using _Framed+_Leaf flags. (#6549) [@BobbyAnguelov] +- InputText: Fixed not returning true when buffer is cleared while using the + ImGuiInputTextFlags_EscapeClearsAll flag. (#5688, #2620) - Clipper: Rework inner logic to allow functioning with a zero-clear constructor. This is order to facilitate usage for language bindings (e.g cimgui or dear_binding) where user may not be callinga constructor manually. (#5856) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index a69917939..87daaae71 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6262,7 +6262,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l else if (!is_leaf) RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f); else // Leaf without bullet, left-adjusted text - text_pos.x -= text_offset_x; + text_pos.x -= text_offset_x -padding.x; if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) frame_bb.Max.x -= g.FontSize + style.FramePadding.x; From cada78917cd02c0a69e81e99638e1460a1eab0fa Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 Jun 2023 18:12:37 +0200 Subject: [PATCH 02/15] Tables: removed misleading, seemingy useless use of ImGuiButtonFlags_AllowtemOverlap in TableUpdateBorders(). (#6512, #3909) This was copied from SplitterBehavior(). The only hypothetical value in SplitterBehavior() would be ability to manually call SetItemAllowOverlap() after the call. Btw generally AllowOverlap is undesirable for columns as e.g. a spanning selectable would cover entire width and prevent columns from being used. # Conflicts: # imgui_tables.cpp --- imgui_tables.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index c5534a513..7f6e45a5b 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1208,7 +1208,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table) //GetForegroundDrawList()->AddRect(hit_rect.Min, hit_rect.Max, IM_COL32(255, 0, 0, 100)); bool hovered = false, held = false; - bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_NoNavFocus); + bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_NoNavFocus); if (pressed && IsMouseDoubleClicked(0)) { TableSetColumnWidthAutoSingle(table, column_n); From 3ec128c5fd0f6a87a36abeb0525a5c126f6598fe Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 Jun 2023 14:47:05 +0200 Subject: [PATCH 03/15] Selectable, TreeNode: When using ImGuiSelectableFlags_AllowOverlap/ImGuiTreeNodeFlags_AllowOverlap and holding item held, overlapping widgets won't appear as hovered. (#6512, #3909) Essentially we are going to remove calls to SetItemAllowOverlap() and standardize the fact that only 'HoveredId == id' test from it is performed. # Conflicts: # imgui_widgets.cpp --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 77ac2a911..c20cfe941 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -65,6 +65,8 @@ Other changes: Tweaked default value of style.HoverDelayShort from 0.10 to 0.15. (#1485) - IsWindowHovered: Added support for ImGuiHoveredFlags_Stationary. - IsWindowHovered, IsItemHovered: Assert when passed any unsupported flags. +- Selectable, TreeNode: When using ImGuiSelectableFlags_AllowOverlap/ImGuiTreeNodeFlags_AllowOverlap + and holding item held, overlapping widgets won't appear as hovered. (#6512, #3909) - Tables: Fixed a regression in 1.89.6 leading to the first column of tables with either ScrollX or ScrollY flags from being impossible to resize. (#6503) - CollapsingHeader/TreeNode: Fixed text padding when using _Framed+_Leaf flags. (#6549) [@BobbyAnguelov] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 87daaae71..c97f5e3e3 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1559,7 +1559,7 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap); if (hovered) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb - if (g.ActiveId != id) + if (g.ActiveId != id) // Because: we don't want to hover other while Active SetItemAllowOverlap(); if (held || (hovered && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay)) @@ -6241,7 +6241,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen; } } - if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) + if ((flags & ImGuiTreeNodeFlags_AllowItemOverlap) && g.ActiveId != id) // Because: we don't want to hover other while Active SetItemAllowOverlap(); // In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger. @@ -6528,7 +6528,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (pressed) MarkItemEdited(id); - if (flags & ImGuiSelectableFlags_AllowItemOverlap) + if ((flags & ImGuiTreeNodeFlags_AllowItemOverlap) && g.ActiveId != id) // Because: we don't want to hover other while Active SetItemAllowOverlap(); // In this branch, Selectable() cannot toggle the selection so this will never trigger. @@ -8407,8 +8407,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, if (pressed && !is_tab_button) TabBarQueueFocus(tab_bar, tab); - // Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs to be hovered) - if (g.ActiveId != id) + // Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs or collapse/close button to be hovered) + if (g.ActiveId != id) // Because: we don't want to hover other items while dragging active) SetItemAllowOverlap(); // Drag and drop: re-order tabs From a2f65811717cfea701f8dd91c88ead53a45db08d Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 27 Jun 2023 10:57:08 +0200 Subject: [PATCH 04/15] Selectable: Fixed bad manual cherry-pick/merge (fixes 3ec128c) --- imgui_widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c97f5e3e3..fdcd21240 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6528,7 +6528,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (pressed) MarkItemEdited(id); - if ((flags & ImGuiTreeNodeFlags_AllowItemOverlap) && g.ActiveId != id) // Because: we don't want to hover other while Active + if ((flags & ImGuiSelectableFlags_AllowItemOverlap) && g.ActiveId != id) // Because: we don't want to hover other while Active SetItemAllowOverlap(); // In this branch, Selectable() cannot toggle the selection so this will never trigger. From d5d4d709c7f03527d334ff0ffd65d0a090c64102 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 27 Jun 2023 14:41:51 +0200 Subject: [PATCH 05/15] Drag and Drop: moved "drag souce doesn't report as hovered" from ButtonBehavior() to ItemHoverable(). Ensure DragXXX, SliderXXXX, InputText, PlotXXX follow same logic. Amend 251f178a6, a33f0d1f7 --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 4 ++++ imgui_widgets.cpp | 4 ---- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c20cfe941..86b9de707 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -75,6 +75,9 @@ Other changes: - Clipper: Rework inner logic to allow functioning with a zero-clear constructor. This is order to facilitate usage for language bindings (e.g cimgui or dear_binding) where user may not be callinga constructor manually. (#5856) +- Drag and Drop: Apply default behavior of drag source not reporting itself as hovered + at lower-level, so DragXXX, SliderXXX, InputXXX, Plot widgets are fullfilling it. + (Behavior doesn't apply when ImGuiDragDropFlags_SourceNoDisableHover is set). - Modals: In the case of nested modal, made sure that focused or appearing windows are moved below the lowest blocking modal (rather than the highest one). (#4317) - GetKeyName(): Fixed assert with ImGuiMod_XXX values when IMGUI_DISABLE_OBSOLETE_KEYIO is set. diff --git a/imgui.cpp b/imgui.cpp index 2349389ba..a60c2f179 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4050,6 +4050,10 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) return false; } + // Drag source doesn't report as hovered + if (g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover)) + return false; + // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level // hover test in widgets code. We could also decide to split this function is two. if (id != 0) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index fdcd21240..2dc948680 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -506,10 +506,6 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool bool pressed = false; bool hovered = ItemHoverable(bb, id); - // Drag source doesn't report as hovered - if (hovered && g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover)) - hovered = false; - // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) From 836aff346700ee7e21ee4ba78568392faf285fd8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 27 Jun 2023 15:23:19 +0200 Subject: [PATCH 06/15] Drag and Drop: Amend ItemHoverable() logic for item with no identifier. Amend d5d4d70 --- imgui.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a60c2f179..5c43cbd38 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4050,20 +4050,22 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) return false; } - // Drag source doesn't report as hovered - if (g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover)) - return false; - // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level // hover test in widgets code. We could also decide to split this function is two. if (id != 0) + { + // Drag source doesn't report as hovered + if (g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover)) + return false; + SetHoveredID(id); + } // When disabled we'll return false but still set HoveredId if (item_flags & ImGuiItemFlags_Disabled) { // Release active id if turning disabled - if (g.ActiveId == id) + if (g.ActiveId == id && id != 0) ClearActiveID(); g.HoveredIdDisabled = true; return false; From b03a4993b337a12b0e16091723d0e91bc65b85bb Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 27 Jun 2023 15:43:33 +0200 Subject: [PATCH 07/15] Internals: reorder tests in ItemHoverable() so most likely early out are taken first. --- imgui.cpp | 10 +++++----- imgui_tables.cpp | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5c43cbd38..6cf7bcd1c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4031,17 +4031,17 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) { ImGuiContext& g = *GImGui; - if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) - return false; - ImGuiWindow* window = g.CurrentWindow; if (g.HoveredWindow != window) return false; - if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) - return false; if (!IsMouseHoveringRect(bb.Min, bb.Max)) return false; + if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) + return false; + if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) + return false; + // Done with rectangle culling so we can perform heavier checks now. ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 7f6e45a5b..1f480be2b 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1167,8 +1167,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Process hit-testing on resizing borders. Actual size change will be applied in EndTable() // - Set table->HoveredColumnBorder with a short delay/timer to reduce visual feedback noise. -// - Submit ahead of table contents and header, use ImGuiButtonFlags_AllowItemOverlap to prioritize -// widgets overlapping the same area. void ImGui::TableUpdateBorders(ImGuiTable* table) { ImGuiContext& g = *GImGui; From 06f5b46133785d35636b612f0a5c0fbf72c28142 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 27 Jun 2023 11:19:37 +0200 Subject: [PATCH 08/15] Overlap: Fixed first frame of an overlap highlighting underlying item if previous frame didn't hover anything. (#6512, #3909, #517) --- docs/CHANGELOG.txt | 6 ++++-- imgui.h | 2 +- imgui_widgets.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 86b9de707..f258e0dd3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -63,10 +63,12 @@ Other changes: isn't covered as much. (Match offset for drag and drop tooltips) - IsItemHovered: Tweaked default value of style.HoverDelayNormal from 0.30 to 0.40, Tweaked default value of style.HoverDelayShort from 0.10 to 0.15. (#1485) +- Overlapping items: (#6512, #3909, #517) + - Selectable, TreeNode: When using ImGuiSelectableFlags_AllowOverlap/ImGuiTreeNodeFlags_AllowOverlap + and holding item held, overlapping widgets won't appear as hovered. (#6512, #3909) + - Fixed first frame of an overlap highlighting underlying item if previous frame didn't hover anything. - IsWindowHovered: Added support for ImGuiHoveredFlags_Stationary. - IsWindowHovered, IsItemHovered: Assert when passed any unsupported flags. -- Selectable, TreeNode: When using ImGuiSelectableFlags_AllowOverlap/ImGuiTreeNodeFlags_AllowOverlap - and holding item held, overlapping widgets won't appear as hovered. (#6512, #3909) - Tables: Fixed a regression in 1.89.6 leading to the first column of tables with either ScrollX or ScrollY flags from being impossible to resize. (#6503) - CollapsingHeader/TreeNode: Fixed text padding when using _Framed+_Leaf flags. (#6549) [@BobbyAnguelov] diff --git a/imgui.h b/imgui.h index 96d0a3015..723114e0a 100644 --- a/imgui.h +++ b/imgui.h @@ -23,7 +23,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.89.7 WIP" -#define IMGUI_VERSION_NUM 18965 +#define IMGUI_VERSION_NUM 18966 #define IMGUI_HAS_TABLE /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2dc948680..3bbb9b30a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -524,7 +524,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool g.HoveredWindow = backup_hovered_window; // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. - if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0)) + if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && g.HoveredIdPreviousFrame != id) hovered = false; // Mouse handling From 51f564eea6333bae9242f40c983a3e29d119a9c2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 Jun 2023 14:00:00 +0200 Subject: [PATCH 09/15] (Breaking) Overlap: Renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete). (#6512, #3909, #517) + Internals: Renamed 'ImGuiButtonFlags_AllowItemOverlap' to 'ImGuiButtonFlags_AllowOverlap' without redirection. --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 3 ++- imgui.h | 12 ++++++++++-- imgui_demo.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 4 ++-- imgui_widgets.cpp | 20 ++++++++++---------- 7 files changed, 30 insertions(+), 17 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f258e0dd3..46474277a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -40,6 +40,10 @@ Breaking changes: As the fields were added in 1.89 and expected to be left unchanged by most users, or only tweaked once during app initialisation, we are exceptionally accepting the breakage. Majority of users should not even notice. +- Overlapping items: (#6512, #3909) + - Renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap'. + - Renamed 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap' + - Kept redirecting enums (will obsolete). Other changes: diff --git a/imgui.cpp b/imgui.cpp index 6cf7bcd1c..5ffb3f49e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -397,6 +397,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/06/28 (1.89.7) - overlapping items: renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete). - 2023/06/20 (1.89.7) - moved io.HoverDelayShort/io.HoverDelayNormal to style.HoverDelayShort/style.HoverDelayNormal. As the fields were added in 1.89 and expected to be left unchanged by most users, or only tweaked once during app initialization, we are exceptionally accepting the breakage. - 2023/05/30 (1.89.6) - backends: renamed "imgui_impl_sdlrenderer.cpp" to "imgui_impl_sdlrenderer2.cpp" and "imgui_impl_sdlrenderer.h" to "imgui_impl_sdlrenderer2.h". This is in prevision for the future release of SDL3. - 2023/05/22 (1.89.6) - listbox: commented out obsolete/redirecting functions that were marked obsolete more than two years ago: @@ -5284,7 +5285,7 @@ bool ImGui::IsItemEdited() } // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. -// FIXME: Although this is exposed, its interaction and ideal idiom with using ImGuiButtonFlags_AllowItemOverlap flag are extremely confusing, need rework. +// FIXME: Although this is exposed, its interaction and ideal idiom with using ImGuiButtonFlags_AllowOverlap flag are extremely confusing, need rework. void ImGui::SetItemAllowOverlap() { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index 723114e0a..a3a5b2a33 100644 --- a/imgui.h +++ b/imgui.h @@ -1033,7 +1033,7 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_None = 0, ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected ImGuiTreeNodeFlags_Framed = 1 << 1, // Draw frame with background (e.g. for CollapsingHeader) - ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one + ImGuiTreeNodeFlags_AllowOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open @@ -1047,6 +1047,10 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 14, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog, + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 +#endif }; // Flags for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() functions. @@ -1080,7 +1084,11 @@ enum ImGuiSelectableFlags_ ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text - ImGuiSelectableFlags_AllowItemOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one + ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiSelectableFlags_AllowItemOverlap = ImGuiSelectableFlags_AllowOverlap, // Renamed in 1.89.7 +#endif }; // Flags for ImGui::BeginCombo() diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 591482f50..944c1b7bd 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -5482,7 +5482,7 @@ static void ShowDemoWindowTables() ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow) { - ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap : ImGuiSelectableFlags_None; + ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None; if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height))) { if (ImGui::GetIO().KeyCtrl) diff --git a/imgui_internal.h b/imgui_internal.h index e91830c32..062623641 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -861,7 +861,7 @@ enum ImGuiButtonFlagsPrivate_ ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping - ImGuiButtonFlags_AllowItemOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() + ImGuiButtonFlags_AllowOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press // [UNUSED] //ImGuiButtonFlags_Disabled = 1 << 14, // disable interactions -> use BeginDisabled() or ImGuiItemFlags_Disabled ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 1f480be2b..ec149b3ad 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -2959,9 +2959,9 @@ void ImGui::TableHeader(const char* label) //GetForegroundDrawList()->AddRect(cell_r.Min, cell_r.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] //GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] - // Using AllowItemOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items. + // Using AllowOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items. bool hovered, held; - bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowItemOverlap); + bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowOverlap); if (g.ActiveId != id) SetItemAllowOverlap(); if (held || hovered || selected) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3bbb9b30a..591046a52 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -524,7 +524,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool g.HoveredWindow = backup_hovered_window; // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. - if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && g.HoveredIdPreviousFrame != id) + if (hovered && (flags & ImGuiButtonFlags_AllowOverlap) && g.HoveredIdPreviousFrame != id) hovered = false; // Mouse handling @@ -1552,7 +1552,7 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float bool hovered, held; ImRect bb_interact = bb; bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); - ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap); + ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowOverlap); if (hovered) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb if (g.ActiveId != id) // Because: we don't want to hover other while Active @@ -6163,8 +6163,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l } ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None; - if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) - button_flags |= ImGuiButtonFlags_AllowItemOverlap; + if (flags & ImGuiTreeNodeFlags_AllowOverlap) + button_flags |= ImGuiButtonFlags_AllowOverlap; if (!is_leaf) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; @@ -6237,7 +6237,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen; } } - if ((flags & ImGuiTreeNodeFlags_AllowItemOverlap) && g.ActiveId != id) // Because: we don't want to hover other while Active + if ((flags & ImGuiTreeNodeFlags_AllowOverlap) && g.ActiveId != id) // Because: we don't want to hover other while Active SetItemAllowOverlap(); // In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger. @@ -6382,7 +6382,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl ImGuiID id = window->GetID(label); flags |= ImGuiTreeNodeFlags_CollapsingHeader; if (p_visible) - flags |= ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; + flags |= ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; bool is_open = TreeNodeBehavior(id, flags, label); if (p_visible != NULL) { @@ -6411,7 +6411,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl // Tip: pass a non-visible label (e.g. "##hello") then you can use the space to draw other text or image. // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id. -// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowItemOverlap are also frequently used flags. +// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowOverlap are also frequently used flags. // FIXME: Selectable() with (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported. bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) { @@ -6495,7 +6495,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } - if (flags & ImGuiSelectableFlags_AllowItemOverlap) { button_flags |= ImGuiButtonFlags_AllowItemOverlap; } + if (flags & ImGuiSelectableFlags_AllowOverlap) { button_flags |= ImGuiButtonFlags_AllowOverlap; } const bool was_selected = selected; bool hovered, held; @@ -6524,7 +6524,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (pressed) MarkItemEdited(id); - if ((flags & ImGuiSelectableFlags_AllowItemOverlap) && g.ActiveId != id) // Because: we don't want to hover other while Active + if ((flags & ImGuiSelectableFlags_AllowOverlap) && g.ActiveId != id) // Because: we don't want to hover other while Active SetItemAllowOverlap(); // In this branch, Selectable() cannot toggle the selection so this will never trigger. @@ -8395,7 +8395,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } // Click to Select a tab - ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowItemOverlap); + ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap); if (g.DragDropActive) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; bool hovered, held; From 07e24b405886e93434512c636d40daca7f10f888 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 Jun 2023 17:09:46 +0200 Subject: [PATCH 10/15] ButtonBehavior: pull ImGuiButtonFlags_Repeat from ImGuiItemFlags_ButtonRepeat, matching ItemHoverable() logic. So more widgets can take advantage of Repeat logic. --- imgui_widgets.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 591046a52..299581f4f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -492,6 +492,11 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0) flags |= ImGuiButtonFlags_PressedOnDefault_; + // Default behavior inherited from item flags + const ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); + if (item_flags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + ImGuiWindow* backup_hovered_window = g.HoveredWindow; const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window; if (flatten_hovered_children) @@ -698,9 +703,6 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags if (!ItemAdd(bb, id)) return false; - if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) - flags |= ImGuiButtonFlags_Repeat; - bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); @@ -777,9 +779,6 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu if (!ItemAdd(bb, id)) return false; - if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) - flags |= ImGuiButtonFlags_Repeat; - bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); From a9a5cbf431c47e5a9dfa67840ef53f794d2f59f8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 Jun 2023 13:46:40 +0200 Subject: [PATCH 11/15] Overlap: Internals: add NextItemData.ItemFlags to facilitate implementation of SetNextItemAllowOverlap() + potentially remove extra_flags from ItemAdd(). (#6512, #3909) --- imgui.cpp | 3 ++- imgui.h | 2 +- imgui_internal.h | 3 ++- imgui_widgets.cpp | 8 ++------ 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5ffb3f49e..66fd7e807 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9438,7 +9438,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu g.LastItemData.ID = id; g.LastItemData.Rect = bb; g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb; - g.LastItemData.InFlags = g.CurrentItemFlags | extra_flags; + g.LastItemData.InFlags = g.CurrentItemFlags | g.NextItemData.ItemFlags | extra_flags; g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None; // Directional navigation processing @@ -9470,6 +9470,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!"); } g.NextItemData.Flags = ImGuiNextItemDataFlags_None; + g.NextItemData.ItemFlags = ImGuiItemFlags_None; #ifdef IMGUI_ENABLE_TEST_ENGINE if (id != 0) diff --git a/imgui.h b/imgui.h index a3a5b2a33..8b3117547 100644 --- a/imgui.h +++ b/imgui.h @@ -1294,7 +1294,7 @@ enum ImGuiHoveredFlags_ ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 5, // Return true even if a popup window is normally blocking access to this item/window //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 6, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. - ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 8, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window + ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 8, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another WINDOW. ImGuiHoveredFlags_AllowWhenDisabled = 1 << 9, // IsItemHovered() only: Return true even if the item is disabled ImGuiHoveredFlags_NoNavOverride = 1 << 10, // IsItemHovered() only: Disable using gamepad/keyboard navigation state when active, always query mouse ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, diff --git a/imgui_internal.h b/imgui_internal.h index 062623641..b895d983f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1179,13 +1179,14 @@ enum ImGuiNextItemDataFlags_ struct ImGuiNextItemData { ImGuiNextItemDataFlags Flags; + ImGuiItemFlags ItemFlags; float Width; // Set by SetNextItemWidth() ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging) ImGuiCond OpenCond; bool OpenVal; // Set by SetNextItemOpen() ImGuiNextItemData() { memset(this, 0, sizeof(*this)); } - inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } // Also cleared manually by ItemAdd()! + inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()! }; // Status storage for the last submitted item diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 299581f4f..0eca30153 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1163,10 +1163,8 @@ bool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value) if (!all_on && any_on) { ImGuiContext& g = *GImGui; - ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; - g.CurrentItemFlags |= ImGuiItemFlags_MixedValue; + g.NextItemData.ItemFlags |= ImGuiItemFlags_MixedValue; pressed = Checkbox(label, &all_on); - g.CurrentItemFlags = backup_item_flags; } else { @@ -4959,11 +4957,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)... Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); - ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; - g.CurrentItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; + g.NextItemData.ItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; EndChild(); item_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow); - g.CurrentItemFlags = backup_item_flags; // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active... // FIXME: This quite messy/tricky, should attempt to get rid of the child window. From 8439a73645d10cd270236273812f026f7fcf96da Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 Jun 2023 15:00:51 +0200 Subject: [PATCH 12/15] Overlap: Added 'SetNextItemAllowOverlap()' as a replacement for 'SetItemAllowOverlap()'. (#6512, #3909, #517) # Conflicts: # imgui.cpp # imgui_widgets.cpp --- docs/CHANGELOG.txt | 7 ++++++- imgui.cpp | 16 ++++++++++++++-- imgui.h | 8 ++++++-- imgui_internal.h | 5 +++-- imgui_tables.cpp | 2 -- imgui_widgets.cpp | 37 +++++++++++++++++++++---------------- 6 files changed, 50 insertions(+), 25 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 46474277a..a3176ed50 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -40,7 +40,12 @@ Breaking changes: As the fields were added in 1.89 and expected to be left unchanged by most users, or only tweaked once during app initialisation, we are exceptionally accepting the breakage. Majority of users should not even notice. -- Overlapping items: (#6512, #3909) +- Overlapping items: (#6512, #3909, #517) + - Added 'SetNextItemAllowOverlap()' (called before an item) as a replacement for using + 'SetItemAllowOverlap()' (called after an item). This is roughly equivalent to using the + legacy 'SetItemAllowOverlap()' call (public API) + ImGuiButtonFlags_AllowOverlap (internal). + - Obsoleted 'SetItemAllowOverlap()': it didn't and couldn't work reliably since 1.89 (2022-11-15), + and relied on ambiguously defined design. Use 'SetNextItemAllowOverlap()' before item instead. - Renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap'. - Renamed 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap' - Kept redirecting enums (will obsolete). diff --git a/imgui.cpp b/imgui.cpp index 66fd7e807..f18ddbe7c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -397,6 +397,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/06/28 (1.89.7) - overlapping items: obsoleted 'SetItemAllowOverlap()' (called after item) in favor of calling 'SetNextItemAllowOverlap()' (called before item). 'SetItemAllowOverlap()' didn't and couldn't work reliably since 1.89 (2022-11-15). - 2023/06/28 (1.89.7) - overlapping items: renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete). - 2023/06/20 (1.89.7) - moved io.HoverDelayShort/io.HoverDelayNormal to style.HoverDelayShort/style.HoverDelayNormal. As the fields were added in 1.89 and expected to be left unchanged by most users, or only tweaked once during app initialization, we are exceptionally accepting the breakage. - 2023/05/30 (1.89.6) - backends: renamed "imgui_impl_sdlrenderer.cpp" to "imgui_impl_sdlrenderer2.cpp" and "imgui_impl_sdlrenderer.h" to "imgui_impl_sdlrenderer2.h". This is in prevision for the future release of SDL3. @@ -5284,17 +5285,28 @@ bool ImGui::IsItemEdited() return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Edited) != 0; } +// Allow next item to be overlapped by subsequent items. +// This works by requiring HoveredId to match for two subsequent frames, +// so if a following items overwrite it our interactions will naturally be disabled. +void ImGui::SetNextItemAllowOverlap() +{ + ImGuiContext& g = *GImGui; + g.NextItemData.ItemFlags |= ImGuiItemflags_AllowOverlap; +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. -// FIXME: Although this is exposed, its interaction and ideal idiom with using ImGuiButtonFlags_AllowOverlap flag are extremely confusing, need rework. +// FIXME-LEGACY: Use SetNextItemAllowOverlap() *before* your item instead. void ImGui::SetItemAllowOverlap() { ImGuiContext& g = *GImGui; ImGuiID id = g.LastItemData.ID; if (g.HoveredId == id) g.HoveredIdAllowOverlap = true; - if (g.ActiveId == id) + if (g.ActiveId == id) // Before we made this obsolete, most calls to SetItemAllowOverlap() used to avoid this path by testing g.ActiveId != id. g.ActiveIdAllowOverlap = true; } +#endif // FIXME: It might be undesirable that this will likely disable KeyOwner-aware shortcuts systems. Consider a more fine-tuned version for the two users of this function. void ImGui::SetActiveIdUsingAllKeyboardKeys() diff --git a/imgui.h b/imgui.h index 8b3117547..2af5a2a94 100644 --- a/imgui.h +++ b/imgui.h @@ -23,7 +23,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.89.7 WIP" -#define IMGUI_VERSION_NUM 18966 +#define IMGUI_VERSION_NUM 18967 #define IMGUI_HAS_TABLE /* @@ -839,6 +839,9 @@ namespace ImGui IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. + // Overlapping mode + IMGUI_API void SetNextItemAllowOverlap(); // allow next item to be overlapped by a subsequent item. Useful with invisible buttons, selectable, treenode covering an area where subsequent items may need to be added. Note that both Selectable() and TreeNode() have dedicated flags doing this. + // Item/Widgets Utilities and Query Functions // - Most of the functions are referring to the previous Item that has been submitted. // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. @@ -859,7 +862,6 @@ namespace ImGui IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space) IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space) IMGUI_API ImVec2 GetItemRectSize(); // get size of last item - IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area. // Viewports // - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. @@ -3072,6 +3074,8 @@ namespace ImGui #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS namespace ImGui { + // OBSOLETED in 1.89.7 (from June 2023) + IMGUI_API void SetItemAllowOverlap(); // Use SetNextItemAllowOverlap() before item. // OBSOLETED in 1.89.4 (from March 2023) static inline void PushAllowKeyboardFocus(bool tab_stop) { PushTabStop(tab_stop); } static inline void PopAllowKeyboardFocus() { PopTabStop(); } diff --git a/imgui_internal.h b/imgui_internal.h index b895d983f..79aeff1cd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -802,6 +802,7 @@ enum ImGuiItemFlags_ ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. ImGuiItemFlags_NoWindowHoverableCheck = 1 << 8, // false // Disable hoverable check in ItemHoverable() + ImGuiItemflags_AllowOverlap = 1 << 9, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame. // Controlled by widget code ImGuiItemFlags_Inputable = 1 << 10, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. @@ -861,7 +862,7 @@ enum ImGuiButtonFlagsPrivate_ ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping - ImGuiButtonFlags_AllowOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() + ImGuiButtonFlags_AllowOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable. ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press // [UNUSED] //ImGuiButtonFlags_Disabled = 1 << 14, // disable interactions -> use BeginDisabled() or ImGuiItemFlags_Disabled ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine @@ -1179,7 +1180,7 @@ enum ImGuiNextItemDataFlags_ struct ImGuiNextItemData { ImGuiNextItemDataFlags Flags; - ImGuiItemFlags ItemFlags; + ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemflags_AllowOverlap. float Width; // Set by SetNextItemWidth() ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging) ImGuiCond OpenCond; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index ec149b3ad..e4c5269c6 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -2962,8 +2962,6 @@ void ImGui::TableHeader(const char* label) // Using AllowOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items. bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowOverlap); - if (g.ActiveId != id) - SetItemAllowOverlap(); if (held || hovered || selected) { const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0eca30153..ba5d89830 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -496,6 +496,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool const ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); if (item_flags & ImGuiItemFlags_ButtonRepeat) flags |= ImGuiButtonFlags_Repeat; + if (item_flags & ImGuiItemflags_AllowOverlap) + flags |= ImGuiButtonFlags_AllowOverlap; ImGuiWindow* backup_hovered_window = g.HoveredWindow; const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window; @@ -529,8 +531,13 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool g.HoveredWindow = backup_hovered_window; // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. - if (hovered && (flags & ImGuiButtonFlags_AllowOverlap) && g.HoveredIdPreviousFrame != id) - hovered = false; + if (flags & ImGuiButtonFlags_AllowOverlap) + { + if (hovered && g.HoveredIdPreviousFrame != id) + hovered = false; + if (g.HoveredId == id) // FIXME: Added this to match legacy SetItemAllowOverlap(). Investigate precise side-effects of using (hovered==true) instead? + g.HoveredIdAllowOverlap = true; + } // Mouse handling const ImGuiID test_owner_id = (flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any : id; @@ -1546,14 +1553,20 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float if (!ItemAdd(bb, id, NULL, ImGuiItemFlags_NoNav)) return false; + // FIXME: AFAIK the only leftover reason for passing ImGuiButtonFlags_AllowOverlap here is + // to allow caller of SplitterBehavior() to call SetItemAllowOverlap() after the item. + // Nowadays we would instead want to use SetNextItemAllowOverlap() before the item. + ImGuiButtonFlags button_flags = ImGuiButtonFlags_FlattenChildren; +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + button_flags |= ImGuiButtonFlags_AllowOverlap; +#endif + bool hovered, held; ImRect bb_interact = bb; bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); - ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowOverlap); + ButtonBehavior(bb_interact, id, &hovered, &held, button_flags); if (hovered) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb - if (g.ActiveId != id) // Because: we don't want to hover other while Active - SetItemAllowOverlap(); if (held || (hovered && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay)) SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW); @@ -6158,7 +6171,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l } ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None; - if (flags & ImGuiTreeNodeFlags_AllowOverlap) + if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap)) button_flags |= ImGuiButtonFlags_AllowOverlap; if (!is_leaf) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; @@ -6232,8 +6245,6 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen; } } - if ((flags & ImGuiTreeNodeFlags_AllowOverlap) && g.ActiveId != id) // Because: we don't want to hover other while Active - SetItemAllowOverlap(); // In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger. if (selected != was_selected) //-V547 @@ -6490,7 +6501,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } - if (flags & ImGuiSelectableFlags_AllowOverlap) { button_flags |= ImGuiButtonFlags_AllowOverlap; } + if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; } const bool was_selected = selected; bool hovered, held; @@ -6519,9 +6530,6 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (pressed) MarkItemEdited(id); - if ((flags & ImGuiSelectableFlags_AllowOverlap) && g.ActiveId != id) // Because: we don't want to hover other while Active - SetItemAllowOverlap(); - // In this branch, Selectable() cannot toggle the selection so this will never trigger. if (selected != was_selected) //-V547 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection; @@ -8390,6 +8398,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } // Click to Select a tab + // Allow the close button to overlap ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap); if (g.DragDropActive) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; @@ -8398,10 +8407,6 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, if (pressed && !is_tab_button) TabBarQueueFocus(tab_bar, tab); - // Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs or collapse/close button to be hovered) - if (g.ActiveId != id) // Because: we don't want to hover other items while dragging active) - SetItemAllowOverlap(); - // Drag and drop: re-order tabs if (held && !tab_appearing && IsMouseDragging(0)) { From 10c7709f303831552d4da4366352b6d2ff9b40fb Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 27 Jun 2023 14:58:40 +0200 Subject: [PATCH 13/15] Overlap: IsItemHovered: Changed behavior to return false when querying an item using AllowOverlap mode. Added ImGuiHoveredFlags_AllowWhenOverlappedByItem, ImGuiHoveredFlags_AllowWhenOverlappedByWindow., (#6512, #3909, #517) --- docs/CHANGELOG.txt | 5 +++++ imgui.cpp | 14 +++++++++++--- imgui.h | 8 +++++--- imgui_demo.cpp | 6 ++++-- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a3176ed50..863f36a69 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,8 @@ Breaking changes: and relied on ambiguously defined design. Use 'SetNextItemAllowOverlap()' before item instead. - Renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap'. - Renamed 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap' + - IsItemHovered: Changed behavior to return false when querying an item using AllowOverlap mode + which is being overlapped. Added ImGuiHoveredFlags_AllowWhenOverlappedByItem. (#6512, #3909, #517) - Kept redirecting enums (will obsolete). Other changes: @@ -72,6 +74,9 @@ Other changes: isn't covered as much. (Match offset for drag and drop tooltips) - IsItemHovered: Tweaked default value of style.HoverDelayNormal from 0.30 to 0.40, Tweaked default value of style.HoverDelayShort from 0.10 to 0.15. (#1485) + - IsItemHovered: Added _AllowWhenOverlappedByWindow to ignore window-overlap only. + Option ImGuiHoveredFlags_AllowWhenOverlapped now expand into a combination of both + _AllowWhenOverlappedByWindow + _AllowWhenOverlappedByItem, matching old behavior. - Overlapping items: (#6512, #3909, #517) - Selectable, TreeNode: When using ImGuiSelectableFlags_AllowOverlap/ImGuiTreeNodeFlags_AllowOverlap and holding item held, overlapping widgets won't appear as hovered. (#6512, #3909) diff --git a/imgui.cpp b/imgui.cpp index f18ddbe7c..87d8911a5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -399,6 +399,7 @@ CODE - 2023/06/28 (1.89.7) - overlapping items: obsoleted 'SetItemAllowOverlap()' (called after item) in favor of calling 'SetNextItemAllowOverlap()' (called before item). 'SetItemAllowOverlap()' didn't and couldn't work reliably since 1.89 (2022-11-15). - 2023/06/28 (1.89.7) - overlapping items: renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete). + - 2023/06/28 (1.89.7) - overlapping items: IsItemHovered() now by default return false when querying an item using AllowOverlap mode which is being overlapped. Use ImGuiHoveredFlags_AllowWhenOverlappedByItem to revert to old behavior. - 2023/06/20 (1.89.7) - moved io.HoverDelayShort/io.HoverDelayNormal to style.HoverDelayShort/style.HoverDelayNormal. As the fields were added in 1.89 and expected to be left unchanged by most users, or only tweaked once during app initialization, we are exceptionally accepting the breakage. - 2023/05/30 (1.89.6) - backends: renamed "imgui_impl_sdlrenderer.cpp" to "imgui_impl_sdlrenderer2.cpp" and "imgui_impl_sdlrenderer.h" to "imgui_impl_sdlrenderer2.h". This is in prevision for the future release of SDL3. - 2023/05/22 (1.89.6) - listbox: commented out obsolete/redirecting functions that were marked obsolete more than two years ago: @@ -3983,12 +3984,13 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was // the test that has been running for a long while. if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0) - if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0) + if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByWindow) == 0) return false; // Test if another item is active (e.g. being dragged) + const ImGuiID id = g.LastItemData.ID; if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0) - if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) + if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) return false; // Test if interactions on this window are blocked by an active popup or modal. @@ -4002,8 +4004,14 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) // Special handling for calling after Begin() which represent the title bar or tab. // When the window is skipped/collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. - if (g.LastItemData.ID == window->MoveId && window->WriteAccessed) + if (id == window->MoveId && window->WriteAccessed) return false; + + // Test if using AllowOverlap and overlapped + if ((g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap) && id != 0) + if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByItem) == 0) + if (g.HoveredIdPreviousFrame != g.LastItemData.ID) + return false; } // Handle hover delay diff --git a/imgui.h b/imgui.h index 2af5a2a94..f07e7c2fc 100644 --- a/imgui.h +++ b/imgui.h @@ -1296,9 +1296,11 @@ enum ImGuiHoveredFlags_ ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 5, // Return true even if a popup window is normally blocking access to this item/window //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 6, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. - ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 8, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another WINDOW. - ImGuiHoveredFlags_AllowWhenDisabled = 1 << 9, // IsItemHovered() only: Return true even if the item is disabled - ImGuiHoveredFlags_NoNavOverride = 1 << 10, // IsItemHovered() only: Disable using gamepad/keyboard navigation state when active, always query mouse + ImGuiHoveredFlags_AllowWhenOverlappedByItem = 1 << 8, // IsItemHovered() only: Return true even if the item uses AllowOverlap mode and is overlapped by another hoverable item. + ImGuiHoveredFlags_AllowWhenOverlappedByWindow = 1 << 9, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window. + ImGuiHoveredFlags_AllowWhenDisabled = 1 << 10, // IsItemHovered() only: Return true even if the item is disabled + ImGuiHoveredFlags_NoNavOverride = 1 << 11, // IsItemHovered() only: Disable using gamepad/keyboard navigation state when active, always query mouse + ImGuiHoveredFlags_AllowWhenOverlapped = ImGuiHoveredFlags_AllowWhenOverlappedByItem | ImGuiHoveredFlags_AllowWhenOverlappedByWindow, ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows, diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 944c1b7bd..775f2e174 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2430,7 +2430,8 @@ static void ShowDemoWindowWidgets() "IsItemHovered() = %d\n" "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" - "IsItemHovered(_AllowWhenOverlapped) = %d\n" + "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n" + "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n" "IsItemHovered(_AllowWhenDisabled) = %d\n" "IsItemHovered(_RectOnly) = %d\n" "IsItemActive() = %d\n" @@ -2449,7 +2450,8 @@ static void ShowDemoWindowWidgets() ImGui::IsItemHovered(), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled), ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), ImGui::IsItemActive(), From 4dee919bc0decdfc1f4f2c46ac0225ff276c8d18 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 28 Jun 2023 13:47:57 +0200 Subject: [PATCH 14/15] (Breaking) Internals: added ImGuiItemFlags param to ItemHoverable(), so it can be called from ButtonBehavior() not following an ItemAdd(). This also allow moving AllowOverlap logic from ButtonBehavior() to ItemHoverable(), allowing other widgets to honor it. (#6512, #3909, #517) --- imgui.cpp | 6 +++--- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 33 +++++++++++++++++---------------- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 87d8911a5..cb61b31e7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4038,7 +4038,8 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) } // Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). -bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) +// (this does not rely on LastItemData it can be called from a ButtonBehavior() call not following an ItemAdd() call) +bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -4053,7 +4054,6 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) return false; // Done with rectangle culling so we can perform heavier checks now. - ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) { g.HoveredIdDisabled = true; @@ -12360,7 +12360,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) // Rely on keeping other window->LastItemXXX fields intact. source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect); KeepAliveID(source_id); - bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id); + bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id, g.LastItemData.InFlags); if (is_hovered && g.IO.MouseClicked[mouse_button]) { SetActiveID(source_id, window); diff --git a/imgui_internal.h b/imgui_internal.h index 79aeff1cd..cb1d1b12f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2876,7 +2876,7 @@ namespace ImGui IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); inline void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f) { ItemSize(bb.GetSize(), text_baseline_y); } // FIXME: This is a misleading API since we expect CursorPos to be bb.Min. IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemFlags extra_flags = 0); - IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); + IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags); IMGUI_API bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags = 0); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id); IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index e4c5269c6..c8059ec33 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -976,7 +976,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) const ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table_instance->LastOuterHeight)); const ImGuiID backup_active_id = g.ActiveId; g.ActiveId = 0; - const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0); + const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0, ImGuiItemFlags_None); g.ActiveId = backup_active_id; // [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ba5d89830..2476a160f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -493,11 +493,12 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool flags |= ImGuiButtonFlags_PressedOnDefault_; // Default behavior inherited from item flags - const ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); - if (item_flags & ImGuiItemFlags_ButtonRepeat) - flags |= ImGuiButtonFlags_Repeat; - if (item_flags & ImGuiItemflags_AllowOverlap) - flags |= ImGuiButtonFlags_AllowOverlap; + // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that. + ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); + if (flags & ImGuiButtonFlags_AllowOverlap) + item_flags |= ImGuiItemflags_AllowOverlap; + if (flags & ImGuiButtonFlags_Repeat) + item_flags |= ImGuiItemFlags_ButtonRepeat; ImGuiWindow* backup_hovered_window = g.HoveredWindow; const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window; @@ -511,7 +512,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool #endif bool pressed = false; - bool hovered = ItemHoverable(bb, id); + bool hovered = ItemHoverable(bb, id, item_flags); // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) @@ -531,7 +532,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool g.HoveredWindow = backup_hovered_window; // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. - if (flags & ImGuiButtonFlags_AllowOverlap) + if (item_flags & ImGuiItemflags_AllowOverlap) { if (hovered && g.HoveredIdPreviousFrame != id) hovered = false; @@ -587,7 +588,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { if (mouse_button_released != -1) { - const bool has_repeated_at_least_once = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior + const bool has_repeated_at_least_once = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior if (!has_repeated_at_least_once) pressed = true; if (!(flags & ImGuiButtonFlags_NoNavFocus)) @@ -598,7 +599,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. - if (g.ActiveId == id && (flags & ImGuiButtonFlags_Repeat)) + if (g.ActiveId == id && (item_flags & ImGuiItemFlags_ButtonRepeat)) if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, test_owner_id, ImGuiInputFlags_Repeat)) pressed = true; } @@ -616,7 +617,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { bool nav_activated_by_code = (g.NavActivateId == id); bool nav_activated_by_inputs = (g.NavActivatePressedId == id); - if (!nav_activated_by_inputs && (flags & ImGuiButtonFlags_Repeat)) + if (!nav_activated_by_inputs && (item_flags & ImGuiItemFlags_ButtonRepeat)) { // Avoid pressing multiple keys from triggering excessive amount of repeat events const ImGuiKeyData* key1 = GetKeyData(ImGuiKey_Space); @@ -663,7 +664,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { // Report as pressed when releasing the mouse (this is the most common path) bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseReleased[mouse_button] && g.IO.MouseClickedLastCount[mouse_button] == 2; - bool is_repeating_already = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps + bool is_repeating_already = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps bool is_button_avail_or_owned = TestKeyOwner(MouseButtonToKey(mouse_button), test_owner_id); if (!is_double_click_release && !is_repeating_already && is_button_avail_or_owned) pressed = true; @@ -2421,7 +2422,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { @@ -3014,7 +3015,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { @@ -3181,7 +3182,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); const bool clicked = hovered && IsMouseClicked(0, id); if (clicked || g.NavActivateId == id) { @@ -4147,7 +4148,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ return false; item_status_flags = g.LastItemData.StatusFlags; } - const bool hovered = ItemHoverable(frame_bb, id); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); if (hovered) g.MouseCursor = ImGuiMouseCursor_TextInput; @@ -6714,7 +6715,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, 0, &frame_bb)) return -1; - const bool hovered = ItemHoverable(frame_bb, id); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); // Determine scale from values if not specified if (scale_min == FLT_MAX || scale_max == FLT_MAX) From 6137443d24948a1d3bde507835435d8ef4814ed9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 28 Jun 2023 13:51:50 +0200 Subject: [PATCH 15/15] Overlap: moved ImGuiItemflags_AllowOverlap handling from ButtoBehavior() to ItemHoverable() now that it is possible. (#6512, #3909, #517) This allows DragXXX, SliderXXX, PlotXXX etc to honor SetNextItemAllowOverlap(). --- docs/CHANGELOG.txt | 8 ++++---- imgui.cpp | 9 +++++++++ imgui_widgets.cpp | 9 --------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 863f36a69..1545cf8d8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,10 @@ Breaking changes: - Renamed 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap' - IsItemHovered: Changed behavior to return false when querying an item using AllowOverlap mode which is being overlapped. Added ImGuiHoveredFlags_AllowWhenOverlappedByItem. (#6512, #3909, #517) + - Selectable, TreeNode: When using ImGuiSelectableFlags_AllowOverlap/ImGuiTreeNodeFlags_AllowOverlap + and holding item held, overlapping widgets won't appear as hovered. (#6512, #3909) + - Most item types should now work with SetNextItemAllowOverlap(). (#6512, #3909, #517) + - Fixed first frame of an overlap highlighting underlying item if previous frame didn't hover anything. - Kept redirecting enums (will obsolete). Other changes: @@ -77,10 +81,6 @@ Other changes: - IsItemHovered: Added _AllowWhenOverlappedByWindow to ignore window-overlap only. Option ImGuiHoveredFlags_AllowWhenOverlapped now expand into a combination of both _AllowWhenOverlappedByWindow + _AllowWhenOverlappedByItem, matching old behavior. -- Overlapping items: (#6512, #3909, #517) - - Selectable, TreeNode: When using ImGuiSelectableFlags_AllowOverlap/ImGuiTreeNodeFlags_AllowOverlap - and holding item held, overlapping widgets won't appear as hovered. (#6512, #3909) - - Fixed first frame of an overlap highlighting underlying item if previous frame didn't hover anything. - IsWindowHovered: Added support for ImGuiHoveredFlags_Stationary. - IsWindowHovered, IsItemHovered: Assert when passed any unsupported flags. - Tables: Fixed a regression in 1.89.6 leading to the first column of tables with either diff --git a/imgui.cpp b/imgui.cpp index cb61b31e7..63e4f7dd7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4069,6 +4069,15 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag return false; SetHoveredID(id); + + // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. + // This allows using patterns where a later submitted widget overlaps a previous one. Generally perceived as a front-to-back hit-test. + if (item_flags & ImGuiItemflags_AllowOverlap) + { + g.HoveredIdAllowOverlap = true; + if (g.HoveredIdPreviousFrame != id) + return false; + } } // When disabled we'll return false but still set HoveredId diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2476a160f..ecdb2d613 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -531,15 +531,6 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (flatten_hovered_children) g.HoveredWindow = backup_hovered_window; - // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. - if (item_flags & ImGuiItemflags_AllowOverlap) - { - if (hovered && g.HoveredIdPreviousFrame != id) - hovered = false; - if (g.HoveredId == id) // FIXME: Added this to match legacy SetItemAllowOverlap(). Investigate precise side-effects of using (hovered==true) instead? - g.HoveredIdAllowOverlap = true; - } - // Mouse handling const ImGuiID test_owner_id = (flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any : id; if (hovered)