From 9c7183dd048ecd8f4c17f54662ca067c997d3bfb Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 13 Jan 2020 15:05:53 +0100 Subject: [PATCH] MultiSelect: Transition to use FocusScope bits merged in master. Preserve ability to shift+arrow into an item that is part of FocusScope but doesn't carry a selection without breaking selection. --- imgui.cpp | 1 - imgui_internal.h | 15 ++++++++------- imgui_widgets.cpp | 37 +++++++++++++++++++++++-------------- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3cdd6fbde..733a5dfe1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3822,7 +3822,6 @@ void ImGui::Shutdown() g.MenusIdSubmittedThisFrame.clear(); g.InputTextState.ClearFreeMemory(); g.InputTextDeactivatedState.ClearFreeMemory(); - g.MultiSelectScopeWindow = NULL; g.SettingsWindows.clear(); g.SettingsHandlers.clear(); diff --git a/imgui_internal.h b/imgui_internal.h index 41dac9c90..dd5853466 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1210,6 +1210,7 @@ enum ImGuiNextItemDataFlags_ ImGuiNextItemDataFlags_HasOpen = 1 << 1, ImGuiNextItemDataFlags_HasShortcut = 1 << 2, ImGuiNextItemDataFlags_HasRefVal = 1 << 3, + ImGuiNextItemDataFlags_HasSelectionData = 1 << 4, }; struct ImGuiNextItemData @@ -1217,6 +1218,7 @@ struct ImGuiNextItemData ImGuiNextItemDataFlags Flags; ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap. // Non-flags members are NOT cleared by ItemAdd() meaning they are still valid during NavProcessItem() + ImGuiID FocusScopeId; // Set by SetNextItemSelectionUserData() (!= 0 signify value has been set) ImGuiSelectionUserData SelectionUserData; // Set by SetNextItemSelectionUserData() (note that NULL/0 is a valid value, we use -1 == ImGuiSelectionUserData_Invalid to mark invalid values) float Width; // Set by SetNextItemWidth() ImGuiKeyChord Shortcut; // Set by SetNextItemShortcut() @@ -1713,13 +1715,14 @@ struct ImGuiOldColumns struct IMGUI_API ImGuiMultiSelectState { + ImGuiID FocusScopeId; // Same as CurrentWindow->DC.FocusScopeIdCurrent (unless another selection scope was pushed manually) ImGuiMultiSelectData In; // The In requests are set and returned by BeginMultiSelect() ImGuiMultiSelectData Out; // The Out requests are finalized and returned by EndMultiSelect() bool InRangeDstPassedBy; // (Internal) set by the the item that match NavJustMovedToId when InRequestRangeSetNav is set. bool InRequestSetRangeNav; // (Internal) set by BeginMultiSelect() when using Shift+Navigation. Because scrolling may be affected we can't afford a frame of lag with Shift+Navigation. ImGuiMultiSelectState() { Clear(); } - void Clear() { In.Clear(); Out.Clear(); InRangeDstPassedBy = InRequestSetRangeNav = false; } + void Clear() { FocusScopeId = 0; In.Clear(); Out.Clear(); InRangeDstPassedBy = InRequestSetRangeNav = false; } }; #endif // #ifdef IMGUI_HAS_MULTI_SELECT @@ -2117,10 +2120,9 @@ struct ImGuiContext ImVec2 NavWindowingAccumDeltaSize; // Range-Select/Multi-Select - ImGuiID MultiSelectScopeId; - ImGuiWindow* MultiSelectScopeWindow; + bool MultiSelectEnabled; ImGuiMultiSelectFlags MultiSelectFlags; - ImGuiMultiSelectState MultiSelectState; + ImGuiMultiSelectState MultiSelectState; // We currently don't support recursing/stacking multi-select // Render float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list) @@ -2385,9 +2387,8 @@ struct ImGuiContext NavWindowingToggleLayer = false; NavWindowingToggleKey = ImGuiKey_None; - MultiSelectScopeId = 0; - MultiSelectScopeWindow = NULL; - MultiSelectFlags = 0; + MultiSelectEnabled = false; + MultiSelectFlags = ImGuiMultiSelectFlags_None; DimBgRatio = 0.0f; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 62b063d18..4da256960 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6466,7 +6466,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags const bool was_selected = selected; // Multi-selection support (header) - const bool is_multi_select = (g.MultiSelectScopeWindow == window); + const bool is_multi_select = g.MultiSelectEnabled; if (is_multi_select) { flags |= ImGuiTreeNodeFlags_OpenOnArrow; @@ -6814,7 +6814,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; } // Multi-selection support (header) - const bool is_multi_select = (g.MultiSelectScopeWindow == window); + const bool is_multi_select = g.MultiSelectEnabled; const bool was_selected = selected; if (is_multi_select) { @@ -7120,17 +7120,20 @@ void ImGui::DebugNodeTypingSelectState(ImGuiTypingSelectState* data) ImGuiMultiSelectData* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, void* range_ref, bool range_ref_is_selected) { - ImGuiContext& g = *ImGui::GetCurrentContext(); + ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT(g.MultiSelectScopeId == 0); // No recursion allowed yet (we could allow it if we deem it useful) + IM_ASSERT(g.MultiSelectEnabled == false); // No recursion allowed yet (we could allow it if we deem it useful) IM_ASSERT(g.MultiSelectFlags == 0); + IM_ASSERT(g.MultiSelectState.FocusScopeId == 0); + // FIXME: BeginFocusScope() ImGuiMultiSelectState* ms = &g.MultiSelectState; - g.MultiSelectScopeId = window->IDStack.back(); - g.MultiSelectScopeWindow = window; - g.MultiSelectFlags = flags; ms->Clear(); + ms->FocusScopeId = window->IDStack.back(); + PushFocusScope(ms->FocusScopeId); + g.MultiSelectEnabled = true; + g.MultiSelectFlags = flags; if ((flags & ImGuiMultiSelectFlags_NoMultiSelect) == 0) { @@ -7139,7 +7142,7 @@ ImGuiMultiSelectData* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, void* } // Auto clear when using Navigation to move within the selection (we compare SelectScopeId so it possible to use multiple lists inside a same window) - if (g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.MultiSelectScopeId) + if (g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == ms->FocusScopeId && g.NavJustMovedToHasSelectionData) { if (g.IO.KeyShift) ms->InRequestSetRangeNav = true; @@ -7162,14 +7165,16 @@ ImGuiMultiSelectData* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, void* ImGuiMultiSelectData* ImGui::EndMultiSelect() { - ImGuiContext& g = *ImGui::GetCurrentContext(); + ImGuiContext& g = *GImGui; ImGuiMultiSelectState* ms = &g.MultiSelectState; - IM_ASSERT(g.MultiSelectScopeId != 0); + IM_ASSERT(g.MultiSelectState.FocusScopeId == g.CurrentFocusScopeId); + if (g.MultiSelectFlags & ImGuiMultiSelectFlags_NoUnselect) ms->Out.RangeValue = true; - g.MultiSelectScopeId = 0; - g.MultiSelectScopeWindow = NULL; - g.MultiSelectFlags = 0; + g.MultiSelectState.FocusScopeId = 0; + PopFocusScope(); + g.MultiSelectEnabled = false; + g.MultiSelectFlags = ImGuiMultiSelectFlags_None; #ifdef IMGUI_DEBUG_MULTISELECT if (ms->Out.RequestClear) printf("[%05d] EndMultiSelect: RequestClear\n", g.FrameCount); @@ -7185,18 +7190,22 @@ void ImGui::SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_d // Note that flags will be cleared by ItemAdd(), so it's only useful for Navigation code! // This designed so widgets can also cheaply set this before calling ItemAdd(), so we are not tied to MultiSelect api. ImGuiContext& g = *GImGui; - if (g.MultiSelectScopeId != 0) + if (g.MultiSelectState.FocusScopeId != 0) g.NextItemData.ItemFlags |= ImGuiItemFlags_HasSelectionUserData | ImGuiItemFlags_IsMultiSelect; else g.NextItemData.ItemFlags |= ImGuiItemFlags_HasSelectionUserData; g.NextItemData.SelectionUserData = selection_user_data; + g.NextItemData.FocusScopeId = g.CurrentFocusScopeId; } void ImGui::MultiSelectItemHeader(ImGuiID id, bool* p_selected) { ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; ImGuiMultiSelectState* ms = &g.MultiSelectState; + IM_UNUSED(window); + IM_ASSERT(g.NextItemData.FocusScopeId == g.CurrentFocusScopeId && "Forgot to call SetNextItemSelectionUserData() prior to item, required in BeginMultiSelect()/EndMultiSelect() scope"); IM_ASSERT((g.NextItemData.SelectionUserData != ImGuiSelectionUserData_Invalid) && "Forgot to call SetNextItemSelectionUserData() prior to item, required in BeginMultiSelect()/EndMultiSelect() scope"); void* item_data = (void*)g.NextItemData.SelectionUserData;