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.
This commit is contained in:
ocornut
2026-04-09 22:15:32 +02:00
parent b444694b3d
commit f08b33fd0c
3 changed files with 9 additions and 5 deletions

View File

@@ -60,8 +60,10 @@ Other Changes:
default ItemWidth. (#9355) default ItemWidth. (#9355)
- Multi-Select: - Multi-Select:
- Box-Select: fixed an issue using ImGuiMultiSelectFlags_BoxSelect2d mode, where - 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) 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: - Fonts:
- imgui_freetype: add FreeType headers & compiled version in 'About Dear ImGui' details. - imgui_freetype: add FreeType headers & compiled version in 'About Dear ImGui' details.
- Clipper: - Clipper:

View File

@@ -1915,7 +1915,8 @@ struct IMGUI_API ImGuiMultiSelectTempData
ImGuiMultiSelectFlags Flags; ImGuiMultiSelectFlags Flags;
ImVec2 ScopeRectMin; ImVec2 ScopeRectMin;
ImVec2 BackupCursorMaxPos; 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; ImGuiID BoxSelectId;
ImGuiKeyChord KeyMods; ImGuiKeyChord KeyMods;
ImS8 LoopRequestSetAll; // -1: no operation, 0: clear all, 1: select all. ImS8 LoopRequestSetAll; // -1: no operation, 0: clear all, 1: select all.

View File

@@ -8050,7 +8050,7 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel
storage->LastSelectionSize = 0; storage->LastSelectionSize = 0;
} }
ms->LoopRequestSetAll = request_select_all ? 1 : request_clear ? 0 : -1; ms->LoopRequestSetAll = request_select_all ? 1 : request_clear ? 0 : -1;
ms->LastSubmittedItem = ImGuiSelectionUserData_Invalid; ms->PrevSubmittedItem = ImGuiSelectionUserData_Invalid;
if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection) if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection)
DebugLogMultiSelectRequests("BeginMultiSelect", &ms->IO); DebugLogMultiSelectRequests("BeginMultiSelect", &ms->IO);
@@ -8153,6 +8153,8 @@ void ImGui::SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_d
g.NextItemData.ItemFlags |= ImGuiItemFlags_HasSelectionUserData | ImGuiItemFlags_IsMultiSelect; g.NextItemData.ItemFlags |= ImGuiItemFlags_HasSelectionUserData | ImGuiItemFlags_IsMultiSelect;
if (ms->IO.RangeSrcItem == selection_user_data) if (ms->IO.RangeSrcItem == selection_user_data)
ms->RangeSrcPassedBy = true; 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 else
{ {
@@ -8430,7 +8432,6 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
} }
if (storage->NavIdItem == item_data) if (storage->NavIdItem == item_data)
ms->NavIdPassedBy = true; ms->NavIdPassedBy = true;
ms->LastSubmittedItem = item_data;
*p_selected = selected; *p_selected = selected;
*p_pressed = pressed; *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) 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]; 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; prev->RangeLastItem = last_item;
return; return;