diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6aa294071..a28d9cc90 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -66,6 +66,8 @@ Other Changes: - ColorPicker: Fixed SV triangle gradient to block (broken in 1.73). (#2864, #2711). [@lewa-j] - TreeNode: Fixed combination of ImGuiTreeNodeFlags_SpanFullWidth and ImGuiTreeNodeFlags_OpenOnArrow incorrectly locating the arrow hit position to the left of the frame. (#2451, #2438, #1897) +- TreeNode: The collapsing arrow accepts click even if modifier keys are being held, facilitating + interactions with multi-select patterns. (#2886, #1896, #1861) - DragScalar, SliderScalar, InputScalar: Added p_ prefix to parameter that are pointers to the data to clarify how they are used, and more comments redirecting to the demo code. (#2844) - Misc: Optimized storage of window settings data (reducing allocation count). diff --git a/imgui_internal.h b/imgui_internal.h index 37d460207..63357cea2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -365,7 +365,7 @@ enum ImGuiButtonFlags_ ImGuiButtonFlags_DontClosePopups = 1 << 7, // disable automatically closing parent popup on press // [UNUSED] ImGuiButtonFlags_Disabled = 1 << 8, // disable interactions ImGuiButtonFlags_AlignTextBaseLine = 1 << 9, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine - ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable interaction if a key modifier is held + ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable mouse interaction if a key modifier is held ImGuiButtonFlags_NoHoldingActiveID = 1 << 11, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12, // press when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) ImGuiButtonFlags_NoNavFocus = 1 << 13, // don't override navigation focus when activated diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 41f96c84e..d59683153 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5269,7 +5269,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // - OpenOnDoubleClick .............. double-click anywhere to open // - OpenOnArrow .................... single-click on arrow to open // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open - ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers; + ImGuiButtonFlags button_flags = 0; if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) button_flags |= ImGuiButtonFlags_AllowItemOverlap; if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) @@ -5277,6 +5277,15 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (!is_leaf) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + // We allow clicking on the arrow section with keyboard modifiers held, in order to easily + // allow browsing a tree while preserving selection with code implementing multi-selection patterns. + // When clicking on the rest of the tree node we always disallow keyboard modifiers. + const float hit_padding_x = style.TouchExtraPadding.x; + const float arrow_hit_x1 = (text_pos.x - text_offset_x) - hit_padding_x; + const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + hit_padding_x; + if (window != g.HoveredWindow || !(g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2)) + button_flags |= ImGuiButtonFlags_NoKeyModifiers; + bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0; const bool was_selected = selected; @@ -5287,13 +5296,10 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { if (pressed) { - const float hit_padding_x = style.TouchExtraPadding.x; - const float arrow_hit_x1 = (text_pos.x - text_offset_x) - hit_padding_x; - const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + hit_padding_x; - if (flags & ImGuiTreeNodeFlags_OpenOnArrow) - toggled |= (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2) && (!g.NavDisableMouseHover); // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id)) toggled = true; + if (flags & ImGuiTreeNodeFlags_OpenOnArrow) + toggled |= (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2) && (!g.NavDisableMouseHover); // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseDoubleClicked[0]) toggled = true; if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again.