From ac88294b4a28b3b56ed2aaec013acfc5e2a9eda8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 20 Apr 2026 11:07:45 +0200 Subject: [PATCH] MultiSelect: Box-Select +Tables: fix usage of box-selection columns with items straying out of columns. (#7994, #2221) Use 00d3f9295e. + Assets Browser toggle to enable ScrollX. --- docs/CHANGELOG.txt | 2 ++ imgui_demo.cpp | 11 ++++++++--- imgui_widgets.cpp | 11 +++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9a3e84f99..a907de658 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -83,6 +83,8 @@ Other Changes: - Box-Select: fixes for using accross nested child windows. (#8364) - Box-Select + Clipper: fixed an issue selecting items while scrolling while a clipper active. (#7994, #8250, #7821, #7850, #7970) + - Box-Select + Tables: fixed an issue using box-selection in a tables with + items straying out of columns boundaries. (#7994, #2221) - Box-Select + Tables: fixed an issue when calling `BeginMultiSelect()` in a table before layout has been locked (first row or headers row submitted). (#8250) - Style: diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 08924ea9e..bbdfa1c3e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -10726,8 +10726,9 @@ struct ExampleAssetsBrowser bool AllowDragUnselected = false; // Will set ImGuiMultiSelectFlags_SelectOnClickRelease float IconSize = 0; int IconSpacing = 10; - int IconHitSpacing = 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is required to able to amend with Shift+box-select. Value is small in Explorer. + int IconHitSpacing = 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is required to able to amend with Shift+box-select. Value is small in Explorer. bool StretchSpacing = true; + bool UseScrollX = false; // Debug: submit twice the number of items per line (overflow horizontally to exercise ScrollX + box-select) // State ImVector Items; // Our items @@ -10778,12 +10779,15 @@ struct ExampleAssetsBrowser // Layout: calculate number of icon per line and number of lines LayoutItemSize = ImVec2(floorf(IconSize), floorf(IconSize)); LayoutColumnCount = IM_MAX((int)(avail_width / (LayoutItemSize.x + LayoutItemSpacing)), 1); - LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount; // Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may be non-integer. if (StretchSpacing && LayoutColumnCount > 1) LayoutItemSpacing = floorf(avail_width - LayoutItemSize.x * LayoutColumnCount) / LayoutColumnCount; + if (UseScrollX) + LayoutColumnCount *= 2; + LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount; + LayoutItemStep = ImVec2(LayoutItemSize.x + LayoutItemSpacing, LayoutItemSize.y + LayoutItemSpacing); LayoutSelectableSpacing = IM_MAX(floorf(LayoutItemSpacing) - IconHitSpacing, 0.0f); LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f); @@ -10843,6 +10847,7 @@ struct ExampleAssetsBrowser ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32); ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32); ImGui::Checkbox("Stretch Spacing", &StretchSpacing); + ImGui::Checkbox("Use ScrollX", &UseScrollX); ImGui::PopItemWidth(); ImGui::EndMenu(); } @@ -10872,7 +10877,7 @@ struct ExampleAssetsBrowser ImGuiIO& io = ImGui::GetIO(); ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.y + LayoutItemSpacing))); - if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove)) + if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_HorizontalScrollbar)) { ImDrawList* draw_list = ImGui::GetWindowDrawList(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3d9f2bec0..9eb007621 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8358,8 +8358,15 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) if (ms->BoxSelectId != 0) if (ImGuiBoxSelectState* bs = GetBoxSelectState(ms->BoxSelectId)) { - const bool rect_overlap_curr = bs->BoxSelectRectCurr.Overlaps(g.LastItemData.Rect); - const bool rect_overlap_prev = bs->BoxSelectRectPrev.Overlaps(g.LastItemData.Rect); + ImRect item_rect = g.LastItemData.Rect; + if (!window->DC.NavIsScrollPushableX) + { + const ImRect& clip_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasClipRect) ? g.LastItemData.ClipRect : window->ClipRect; + item_rect.Min.x = ImMax(item_rect.Min.x, clip_rect.Min.x); + item_rect.Max.x = ImMin(item_rect.Max.x, clip_rect.Max.x); + } + const bool rect_overlap_curr = bs->BoxSelectRectCurr.Overlaps(item_rect); + const bool rect_overlap_prev = bs->BoxSelectRectPrev.Overlaps(item_rect); if ((rect_overlap_curr && !rect_overlap_prev && !selected) || (rect_overlap_prev && !rect_overlap_curr)) { if (storage->LastSelectionSize <= 0 && bs->IsStartedSetNavIdOnce)