From 3ac367ff41b33eb7e7e6013f0132441b5cbfed35 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 26 Jun 2024 17:00:52 +0200 Subject: [PATCH] MultiSelect: ImGuiSelectionBasicStorage: (breaking) rework GetNextSelectedItem() api to avoid ambiguity/failure when user uses a zero id. --- imgui.h | 6 +++--- imgui_demo.cpp | 8 +++++--- imgui_widgets.cpp | 5 +++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/imgui.h b/imgui.h index 6e86b85c0..a66e8d84c 100644 --- a/imgui.h +++ b/imgui.h @@ -2817,7 +2817,7 @@ struct ImGuiSelectionRequest // Optional helper to store multi-selection state + apply multi-selection requests. // - Used by our demos and provided as a convenience to easily implement basic multi-selection. -// - Iterate selection with 'void* it = NULL; while (ImGuiId id = selection.GetNextSelectedItem(&it)) { ... }' +// - Iterate selection with 'void* it = NULL; ImGuiID id; while (selection.GetNextSelectedItem(&it, &id)) { ... }' // Or you can check 'if (Contains(id)) { ... }' for each possible object if their number is not too high to iterate. // - USING THIS IS NOT MANDATORY. This is only a helper and not a required API. // To store a multi-selection, in your application you could: @@ -2834,10 +2834,10 @@ struct ImGuiSelectionRequest struct ImGuiSelectionBasicStorage { // Members - ImGuiStorage _Storage; // [Internal] Selection set. Think of this as similar to e.g. std::set. Prefer not accessing directly: iterate with GetNextSelectedItem(). int Size; // Number of selected items (== number of 1 in the Storage), maintained by this helper. void* UserData; // User data for use by adapter function // e.g. selection.UserData = (void*)my_items; ImGuiID (*AdapterIndexToStorageId)(ImGuiSelectionBasicStorage* self, int idx); // e.g. selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return ((MyItems**)self->UserData)[idx]->ID; }; + ImGuiStorage _Storage; // [Internal] Selection set. Think of this as similar to e.g. std::set. Prefer not accessing directly: iterate with GetNextSelectedItem(). // Methods ImGuiSelectionBasicStorage(); @@ -2846,7 +2846,7 @@ struct ImGuiSelectionBasicStorage IMGUI_API void Clear(); // Clear selection IMGUI_API void Swap(ImGuiSelectionBasicStorage& r); // Swap two selections IMGUI_API void SetItemSelected(ImGuiID id, bool selected); // Add/remove an item from selection (generally done by ApplyRequests() function) - IMGUI_API ImGuiID GetNextSelectedItem(void** opaque_it); // Iterate selection with 'void* it = NULL; while (ImGuiId id = selection.GetNextSelectedItem(&it)) { ... }' + IMGUI_API bool GetNextSelectedItem(void** opaque_it, ImGuiID* out_id); // Iterate selection with 'void* it = NULL; ImGuiId id; while (selection.GetNextSelectedItem(&it, &id)) { ... }' inline ImGuiID GetStorageIdFromIndex(int idx) { return AdapterIndexToStorageId(this, idx); } // Convert index to item id based on provided adapter. }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ec5037297..690c79fda 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3447,11 +3447,12 @@ static void ShowDemoWindowMultiSelect() { ImVector payload_items; void* it = NULL; + ImGuiID id = 0; if (!item_is_selected) payload_items.push_back(item_id); else - while (int id = (int)selection.GetNextSelectedItem(&it)) - payload_items.push_back(id); + while (selection.GetNextSelectedItem(&it, &id)) + payload_items.push_back((int)id); ImGui::SetDragDropPayload("MULTISELECT_DEMO_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes()); } @@ -9907,10 +9908,11 @@ struct ExampleAssetsBrowser { ImVector payload_items; void* it = NULL; + ImGuiID id = 0; if (!item_is_selected) payload_items.push_back(item_data->ID); else - while (ImGuiID id = Selection.GetNextSelectedItem(&it)) + while (Selection.GetNextSelectedItem(&it, &id)) payload_items.push_back(id); ImGui::SetDragDropPayload("ASSETS_BROWSER_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes()); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 54b1b1f68..fccc15d14 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7847,7 +7847,7 @@ bool ImGuiSelectionBasicStorage::Contains(ImGuiID id) const // GetNextSelectedItem() is an abstraction allowing us to change our underlying actual storage system without impacting user. // (e.g. store unselected vs compact down, compact down on demand, use raw ImVector instead of ImGuiStorage...) -ImGuiID ImGuiSelectionBasicStorage::GetNextSelectedItem(void** opaque_it) +bool ImGuiSelectionBasicStorage::GetNextSelectedItem(void** opaque_it, ImGuiID* out_id) { ImGuiStoragePair* it = (ImGuiStoragePair*)*opaque_it; ImGuiStoragePair* it_end = _Storage.Data.Data + _Storage.Data.Size; @@ -7859,7 +7859,8 @@ ImGuiID ImGuiSelectionBasicStorage::GetNextSelectedItem(void** opaque_it) it++; const bool has_more = (it != it_end); *opaque_it = has_more ? (void**)(it + 1) : (void**)(it); - return has_more ? it->key : 0; + *out_id = has_more ? it->key : 0; + return has_more; } void ImGuiSelectionBasicStorage::SetItemSelected(ImGuiID id, bool selected)