From 387fc138945dae9a9d78af27b1110d1597bc4b7e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 7 Jun 2023 16:25:19 +0200 Subject: [PATCH] MultiSelect: Clarify and better enforce lifetime of BeginMultiSelect() value. --- imgui_demo.cpp | 11 +++++------ imgui_widgets.cpp | 3 +++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c66a9e434..09ac14057 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2780,7 +2780,7 @@ struct ExampleSelection { // Data ImGuiStorage Storage; // Selection set - int SelectionSize; // Number of selected items (== number of 1 in the Storage, maintained by this class) // FIXME-RANGESELECT: Imply more difficult to track with intrusive selection schemes? + int SelectionSize; // Number of selected items (== number of 1 in the Storage, maintained by this class). // FIXME-MULTISELECT: Imply more difficult to track with intrusive selection schemes? int RangeRef; // Reference/pivot item (generally last clicked item) // Functions @@ -2790,13 +2790,12 @@ struct ExampleSelection void SetSelected(int n, bool v) { int* p_int = Storage.GetIntRef((ImGuiID)n, 0); if (*p_int == (int)v) return; if (v) SelectionSize++; else SelectionSize--; *p_int = (bool)v; } int GetSize() const { return SelectionSize; } - // When using SelectAll() / SetRange() we assume that our objects ID are indices. + // When using SetRange() / SelectAll() we assume that our objects ID are indices. // In this demo we always store selection using indices and never in another manner (e.g. object ID or pointers). // If your selection system is storing selection using object ID and you want to support Shift+Click range-selection, - // you will need a way to iterate from one object to another given the ID you use. - // You are likely to need some kind of data structure to convert 'view index' <> 'object ID'. - // FIXME-MULTISELECT: Would be worth providing a demo of doing this. - // FIXME-MULTISELECT: This implementation of SetRange() is inefficient because it doesn't take advantage of the fact that ImGuiStorage stores sorted key. + // you will need a way to iterate from one item to the other item given the ID you use. + // You are likely to need some kind of data structure to convert 'view index' <> 'object ID' (FIXME-MULTISELECT: Would be worth providing a demo of doing this). + // Note: This implementation of SetRange() is inefficient because it doesn't take advantage of the fact that ImGuiStorage stores sorted key. void SetRange(int a, int b, bool v) { if (b < a) { int tmp = b; b = a; a = tmp; } for (int n = a; n <= b; n++) SetSelected(n, v); } void SelectAll(int count) { Storage.Data.resize(count); for (int idx = 0; idx < count; idx++) Storage.Data[idx] = ImGuiStoragePair((ImGuiID)idx, 1); SelectionSize = count; } // This could be using SetRange(), but it this way is faster. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 911aa8b1d..350a9e86c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7131,6 +7131,7 @@ static void DebugLogMultiSelectRequests(const char* function, const ImGuiMultiSe if (data->RequestSetRange) IMGUI_DEBUG_LOG_SELECTION("[selection] %s: RequestSetRange %p..%p = %d (dir %+d)\n", function, data->RangeSrcItem, data->RangeDstItem, data->RangeSelected, data->RangeDirection); } +// Return ImGuiMultiSelectIO structure. Lifetime: valid until corresponding call to EndMultiSelect(). ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, void* range_ref, bool range_ref_is_selected) { ImGuiContext& g = *GImGui; @@ -7184,6 +7185,7 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, void* r return &ms->BeginIO; } +// Return updated ImGuiMultiSelectIO structure. Lifetime: until EndFrame() or next BeginMultiSelect() call. ImGuiMultiSelectIO* ImGui::EndMultiSelect() { ImGuiContext& g = *GImGui; @@ -7205,6 +7207,7 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() ms->FocusScopeId = 0; ms->Window = NULL; ms->Flags = ImGuiMultiSelectFlags_None; + ms->BeginIO.Clear(); // Invalidate contents of BeginMultiSelect() to enforce scope. PopFocusScope(); g.CurrentMultiSelect = NULL;