From dc0a1682e3b5d74c685a31649ece5d2dabedbd37 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 May 2024 15:01:52 +0200 Subject: [PATCH] MultiSelect: Box-Select: when dragging from void, first hit item sets NavId by simulating a press, so navigation can resume from that spot. --- imgui_internal.h | 1 + imgui_widgets.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index 5fb2d568d..53b0c85c4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1758,6 +1758,7 @@ struct IMGUI_API ImGuiMultiSelectTempData bool IsEndIO; // Set when switching IO from BeginMultiSelect() to EndMultiSelect() state. bool IsFocused; // Set if currently focusing the selection scope (any item of the selection). May be used if you have custom shortcut associated to selection. bool IsKeyboardSetRange; // Set by BeginMultiSelect() when using Shift+Navigation. Because scrolling may be affected we can't afford a frame of lag with Shift+Navigation. + bool IsSelectionEmpty; // Set by BeginMultiSelect() based on optional info provided by user. May be false positive, never false negative. bool NavIdPassedBy; bool RangeSrcPassedBy; // Set by the item that matches RangeSrcItem. bool RangeDstPassedBy; // Set by the item that matches NavJustMovedToId when IsSetRange is set. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f83fda9e2..9eaadc2a8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7330,6 +7330,7 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int cur ms->FocusScopeId = id; ms->Flags = flags; ms->IsFocused = (ms->FocusScopeId == g.NavFocusScopeId); + ms->IsSelectionEmpty = (current_selection_size == 0); ms->BackupCursorMaxPos = window->DC.CursorMaxPos; ms->ScopeRectMin = window->DC.CursorMaxPos = window->DC.CursorPos; PushFocusScope(ms->FocusScopeId); @@ -7398,6 +7399,8 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int cur if (request_clear || request_select_all) { ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, request_select_all, ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid }; + if (!request_select_all) + ms->IsSelectionEmpty = true; ms->IO.Requests.push_back(req); } ms->LoopRequestSetAll = request_select_all ? 1 : request_clear ? 0 : -1; @@ -7655,10 +7658,13 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) selected = !selected; ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, selected, item_data, item_data }; ImGuiSelectionRequest* prev_req = (ms->IO.Requests.Size > 0) ? &ms->IO.Requests.Data[ms->IO.Requests.Size - 1] : NULL; - if (prev_req && prev_req->Type == ImGuiSelectionRequestType_SetRange && prev_req->RangeLastItem == ms->BoxSelectLastitem && prev_req->Selected == selected) + if (ms->IsSelectionEmpty && bs->IsStartedFromVoid) + pressed = true; // First item act as a pressed: code below will emit selection request and set NavId (whatever we emit here will be overriden anyway) + else if (prev_req && prev_req->Type == ImGuiSelectionRequestType_SetRange && prev_req->RangeLastItem == ms->BoxSelectLastitem && prev_req->Selected == selected) prev_req->RangeLastItem = item_data; // Merge span into same request else ms->IO.Requests.push_back(req); + ms->IsSelectionEmpty = false; } ms->BoxSelectLastitem = item_data; }