From f08b33fd0c9ef438ef2a1d87447a700f01aa7168 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 9 Apr 2026 22:15:32 +0200 Subject: [PATCH] Multi-Select: Box-Select: fixed an issue where items out of horizontal view would sometimes lead to incorrect merging of sequential selection requests. (#7994, #1861, #6518) SetNextItemSelectionUserData() could use g.NextItemData.SelectionUserData if we could guarantee if would be valid when nesting multi-select blocks. But it doesn't make much of a difference as whole ImGuiMultiSelectTempData fits in 2 cache lines. --- docs/CHANGELOG.txt | 4 +++- imgui_internal.h | 3 ++- imgui_widgets.cpp | 7 ++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 148728e7b..cf57f093b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -60,8 +60,10 @@ Other Changes: default ItemWidth. (#9355) - Multi-Select: - Box-Select: fixed an issue using ImGuiMultiSelectFlags_BoxSelect2d mode, where - items out of view wouldn't be properly selected when scrolling while mouse cursor + items out of view wouldn't be properly selected while scrolling while mouse cursor is hovering outside of selection scope. (#7994, #1861, #6518) + - Box-Select: fixed an issue where items out of horizontal view would sometimes lead + to incorrect merging of sequential selection requests. (#7994, #1861, #6518) - Fonts: - imgui_freetype: add FreeType headers & compiled version in 'About Dear ImGui' details. - Clipper: diff --git a/imgui_internal.h b/imgui_internal.h index 2a51931ef..5281c012e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1915,7 +1915,8 @@ struct IMGUI_API ImGuiMultiSelectTempData ImGuiMultiSelectFlags Flags; ImVec2 ScopeRectMin; ImVec2 BackupCursorMaxPos; - ImGuiSelectionUserData LastSubmittedItem; // Copy of last submitted item data, used to merge output ranges. + ImGuiSelectionUserData CurrSubmittedItem; // Copy of last submitted item data, used to merge output ranges. + ImGuiSelectionUserData PrevSubmittedItem; // Copy of previous submitted item data, used to merge output ranges. ImGuiID BoxSelectId; ImGuiKeyChord KeyMods; ImS8 LoopRequestSetAll; // -1: no operation, 0: clear all, 1: select all. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index bee85438f..b929589aa 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8050,7 +8050,7 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel storage->LastSelectionSize = 0; } ms->LoopRequestSetAll = request_select_all ? 1 : request_clear ? 0 : -1; - ms->LastSubmittedItem = ImGuiSelectionUserData_Invalid; + ms->PrevSubmittedItem = ImGuiSelectionUserData_Invalid; if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection) DebugLogMultiSelectRequests("BeginMultiSelect", &ms->IO); @@ -8153,6 +8153,8 @@ void ImGui::SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_d g.NextItemData.ItemFlags |= ImGuiItemFlags_HasSelectionUserData | ImGuiItemFlags_IsMultiSelect; if (ms->IO.RangeSrcItem == selection_user_data) ms->RangeSrcPassedBy = true; + ms->PrevSubmittedItem = ms->CurrSubmittedItem; // Can't rely on previous g.NextItemData.SelectionUserData because NextItemData is not restored on nested multi-select. + ms->CurrSubmittedItem = selection_user_data; } else { @@ -8430,7 +8432,6 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) } if (storage->NavIdItem == item_data) ms->NavIdPassedBy = true; - ms->LastSubmittedItem = item_data; *p_selected = selected; *p_pressed = pressed; @@ -8449,7 +8450,7 @@ void ImGui::MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, if (ms->IO.Requests.Size > 0 && first_item == last_item && (ms->Flags & ImGuiMultiSelectFlags_NoRangeSelect) == 0) { ImGuiSelectionRequest* prev = &ms->IO.Requests.Data[ms->IO.Requests.Size - 1]; - if (prev->Type == ImGuiSelectionRequestType_SetRange && prev->RangeLastItem == ms->LastSubmittedItem && prev->Selected == selected) + if (prev->Type == ImGuiSelectionRequestType_SetRange && prev->RangeLastItem == ms->PrevSubmittedItem && prev->Selected == selected) { prev->RangeLastItem = last_item; return;