From b08f438669ba7ec69d5fa3ef3c868bad4fbbb75e Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Apr 2023 17:59:06 +0200 Subject: [PATCH] RangeSelect/MultiSelect: Added ImGuiMultiSelectFlags_ClearOnEscape (unsure of best design), expose IsFocused for custom shortcuts. --- imgui.h | 5 ++++- imgui_demo.cpp | 5 +++-- imgui_widgets.cpp | 30 ++++++++++++++++++++---------- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/imgui.h b/imgui.h index 408e3128..3939b30b 100644 --- a/imgui.h +++ b/imgui.h @@ -2662,7 +2662,7 @@ struct ImColor #define IMGUI_HAS_MULTI_SELECT // Multi-Select/Range-Select WIP branch // <-- This is currently _not_ in the top of imgui.h to prevent merge conflicts. // Flags for BeginMultiSelect(). -// This system is designed to allow mouse/keyboard multi-selection, including support for range-selection (SHIFT + click), +// This system is designed to allow mouse/keyboard multi-selection, including support for range-selection (SHIFT+click and SHIFT+keyboard), // which is difficult to re-implement manually. If you disable multi-selection with ImGuiMultiSelectFlags_NoMultiSelect // (which is provided for consistency and flexibility), the whole BeginMultiSelect() system becomes largely overkill as // you can handle single-selection in a simpler manner by just calling Selectable() and reacting on clicks yourself. @@ -2672,6 +2672,7 @@ enum ImGuiMultiSelectFlags_ ImGuiMultiSelectFlags_NoMultiSelect = 1 << 0, ImGuiMultiSelectFlags_NoUnselect = 1 << 1, // Disable unselecting items with CTRL+Click, CTRL+Space etc. ImGuiMultiSelectFlags_NoSelectAll = 1 << 2, // Disable CTRL+A shortcut to set RequestSelectAll + ImGuiMultiSelectFlags_ClearOnEscape = 1 << 3, // Enable ESC shortcut to clear selection }; // Abstract: @@ -2710,6 +2711,7 @@ enum ImGuiMultiSelectFlags_ // If you submit all items (no clipper), Step 2 and 3 and will be handled by Selectable() on a per-item basis. struct ImGuiMultiSelectData { + bool IsFocused; // Begin // Set if currently focusing the selection scope (any item of the selection). May be used if you have custom shortcut associated to selection. bool RequestClear; // Begin, End // Request user to clear selection bool RequestSelectAll; // Begin, End // Request user to select all bool RequestSetRange; // End // Request user to set or clear selection in the [RangeSrc..RangeDst] range @@ -2722,6 +2724,7 @@ struct ImGuiMultiSelectData ImGuiMultiSelectData() { Clear(); } void Clear() { + IsFocused = false; RequestClear = RequestSelectAll = RequestSetRange = RangeSrcPassedBy = RangeValue = false; RangeSrc = RangeDst = NULL; RangeDirection = 0; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 2f158074..3bb12597 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2842,7 +2842,8 @@ static void ShowDemoWindowMultiSelect() ImGui::Text("Selection size: %d", selection.GetSelectionSize()); if (ImGui::BeginListBox("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20))) { - ImGuiMultiSelectData* multi_select_data = ImGui::BeginMultiSelect(ImGuiMultiSelectFlags_None, (void*)(intptr_t)selection.RangeRef, selection.GetSelected(selection.RangeRef)); + ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape; + ImGuiMultiSelectData* multi_select_data = ImGui::BeginMultiSelect(flags, (void*)(intptr_t)selection.RangeRef, selection.GetSelected(selection.RangeRef)); if (multi_select_data->RequestClear) { selection.Clear(); } if (multi_select_data->RequestSelectAll) { selection.SelectAll(ITEMS_COUNT); } @@ -2856,7 +2857,7 @@ static void ShowDemoWindowMultiSelect() sprintf(label, "Object %05d: %s", n, random_names[n % IM_ARRAYSIZE(random_names)]); bool item_is_selected = selection.GetSelected(n); - ImGui::SetNextItemSelectionData((void*)(intptr_t)n); + ImGui::SetNextItemSelectionUserData(n); ImGui::Selectable(label, item_is_selected); if (ImGui::IsItemToggledSelection()) selection.SetSelected(n, !item_is_selected); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 722857af..e8caf4e7 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7021,6 +7021,9 @@ ImGuiMultiSelectData* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, void* g.MultiSelectEnabledWindow = window; g.MultiSelectFlags = flags; + // Report focus + ms->In.IsFocused = ms->Out.IsFocused = (ms->FocusScopeId == g.NavFocusScopeId); + // Use copy of keyboard mods at the time of the request, otherwise we would requires mods to be held for an extra frame. g.MultiSelectKeyMods = g.NavJustMovedToId ? g.NavJustMovedToKeyMods : g.IO.KeyMods; @@ -7040,16 +7043,23 @@ ImGuiMultiSelectData* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, void* ms->In.RequestClear = true; } - // Select All helper shortcut - // Note: we are comparing FocusScope so we don't need to be testing for IsWindowFocused() - if (!(flags & ImGuiMultiSelectFlags_NoMultiSelect) && !(flags & ImGuiMultiSelectFlags_NoSelectAll)) - if (ms->FocusScopeId == g.NavFocusScopeId && g.ActiveId == 0) - if (g.IO.KeyCtrl && IsKeyPressed(GetKeyIndex(ImGuiKey_A))) + // Shortcuts + if (ms->In.IsFocused) + { + // Select All helper shortcut (CTRL+A) + // Note: we are comparing FocusScope so we don't need to be testing for IsWindowFocused() + if (!(flags & ImGuiMultiSelectFlags_NoMultiSelect) && !(flags & ImGuiMultiSelectFlags_NoSelectAll)) + if (Shortcut(ImGuiMod_Ctrl | ImGuiKey_A)) ms->In.RequestSelectAll = true; + if (flags & ImGuiMultiSelectFlags_ClearOnEscape) + if (Shortcut(ImGuiKey_Escape)) + ms->In.RequestClear = true; + } + #ifdef IMGUI_DEBUG_MULTISELECT - if (ms->In.RequestClear) printf("[%05d] BeginMultiSelect: RequestClear\n", g.FrameCount); - if (ms->In.RequestSelectAll) printf("[%05d] BeginMultiSelect: RequestSelectAll\n", g.FrameCount); + if (ms->In.RequestClear) IMGUI_DEBUG_LOG("BeginMultiSelect: RequestClear\n"); + if (ms->In.RequestSelectAll) IMGUI_DEBUG_LOG("BeginMultiSelect: RequestSelectAll\n"); #endif return &ms->In; @@ -7069,9 +7079,9 @@ ImGuiMultiSelectData* ImGui::EndMultiSelect() g.MultiSelectFlags = ImGuiMultiSelectFlags_None; #ifdef IMGUI_DEBUG_MULTISELECT - if (ms->Out.RequestClear) printf("[%05d] EndMultiSelect: RequestClear\n", g.FrameCount); - if (ms->Out.RequestSelectAll) printf("[%05d] EndMultiSelect: RequestSelectAll\n", g.FrameCount); - if (ms->Out.RequestSetRange) printf("[%05d] EndMultiSelect: RequestSetRange %p..%p = %d\n", g.FrameCount, ms->Out.RangeSrc, ms->Out.RangeDst, ms->Out.RangeValue); + if (ms->Out.RequestClear) IMGUI_DEBUG_LOG("EndMultiSelect: RequestClear\n"); + if (ms->Out.RequestSelectAll) IMGUI_DEBUG_LOG("EndMultiSelect: RequestSelectAll\n"); + if (ms->Out.RequestSetRange) IMGUI_DEBUG_LOG("EndMultiSelect: RequestSetRange %p..%p = %d\n", ms->Out.RangeSrc, ms->Out.RangeDst, ms->Out.RangeValue); #endif return &ms->Out;