diff --git a/Multi-Select.md b/Multi-Select.md index 5450186..d7baf62 100644 --- a/Multi-Select.md +++ b/Multi-Select.md @@ -8,10 +8,9 @@ - [Overview](#Overview) - [Features](#Features) - [Demo Code](#demo-code) -- [Principal APIs](#principal-apis) -- [Typical usage flow](#typical-usage-flow) -- [About ImGuiSelectionUserData](#about-imguiselectionuserdata) - [Using ImGuiSelectionBasicStorage helper](#using-ImGuiSelectionBasicStorage-helper) +- [Main API](#main-api) +- [About ImGuiSelectionUserData](#about-imguiselectionuserdata) - [Using ImGuiSelectionExternalStorage helper](#using-ImGuiSelectionExternalStorage-helper) ---- @@ -40,7 +39,56 @@ Always refer to demo code for usage. Demos are in `Demo->Widgets->Selection State & Multi-Select` and `Demo->Examples->Assets Browser`. -### Principal APIs +---- + +### Using ImGuiSelectionBasicStorage helper + +:bulb: `ImGuiSelectionBasicStorage` is an 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. +- USING THIS IS NOT MANDATORY. This is only a helper and not a required API. + +Minimum pseudo-code example using this helper: +```cpp +static vector items; // Your items +static ImGuiSelectionBasicStorage selection; // Your selection +selection.AdapterData = (void*)&items; // Setup adapter so selection.ApplyRequests() function can convert indexes to identifiers. +selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return ((vector*)self->AdapterData))[idx].ID; }; + +ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ImGuiMultiSelectFlags_None, selection.Size, items.Size); +selection.ApplyRequests(ms_io); +for (int idx = 0; idx < items.Size; idx++) +{ + bool item_is_selected = selection.Contains(items[idx].ID); + ImGui::SetNextItemSelectionUserData(idx); + ImGui::Selectable(label, item_is_selected); +} +ms_io = ImGui::EndMultiSelect(); +selection.ApplyRequests(ms_io); +``` + +To store a multi-selection, in your real application you could: +- A) Use this helper as a convenience. We use our simple key->value ImGuiStorage as a std::set replacement. +- B) Use your own external storage: e.g. std::set, std::vector, interval trees, etc. +- C) Use intrusively stored selection (e.g. 'bool IsSelected' inside objects). Not recommended because you can't have multiple views over same objects. Also some features requires to provide selection _size_, which with this strategy requires additional work. + +Our BeginMultiSelect() api/system doesn't make assumption about: +- how you want to identify items in multi-selection API? (Indices or Custom Ids or Pointers? Indices are better: easy to iterate/interpolate) +- how you want to store persistent selection data? (Indices or Custom Ids or Pointers? Custom Ids is better: as selection can persist) + +In ImGuiSelectionBasicStorage we: +- always use indices in the multi-selection API (passed to SetNextItemSelectionUserData(), retrieved in ImGuiMultiSelectIO) +- use the AdapterIndexToStorageId() indirection layer to abstract how persistent selection data is derived from an index. +- in some cases we use Index as custom identifier (default implementation returns Index cast as Identifier): only valid for a never changing item list. +- in some cases we read an ID from some custom item data structure (better, and closer to what you would do in your codebase) + +Many combinations are possible depending on how you prefer to store your items and how you prefer to store your selection. +When your application settles on a choice, you may want to get rid of this indirection layer and do your own thing. + +---- + +### Main API + +:bulb: This is the low-level API. When using the `ImGuiSelectionBasicStorage` you may not need to care about details of `ImGuiMultiSelectIO` and `ImGuiSelectionRequest`. ```cpp // Main API @@ -84,8 +132,7 @@ enum ImGuiSelectionRequestType }; ``` -### Typical usage flow - +TL;DR; - Identify submitted items with `SetNextItemSelectionUserData()`, most likely using an index into your current data-set. - Store and maintain actual selection data using persistent object identifiers. - Usage Flow: @@ -117,51 +164,6 @@ enum ImGuiSelectionRequestType ---- -### Using ImGuiSelectionBasicStorage helper - -`ImGuiSelectionBasicStorage` is an 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. -- USING THIS IS NOT MANDATORY. This is only a helper and not a required API. Advanced users are likely to implement their own. - -Minimum pseudo-code example using this helper: -```cpp -static vector items; // Your items -static ImGuiSelectionBasicStorage selection; // Your selection -selection.AdapterData = (void*)&items; // Setup adapter so selection.ApplyRequests() function can convert indexes to identifiers. -selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return ((vector*)self->AdapterData))[idx].ID; }; - -ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ImGuiMultiSelectFlags_None, selection.Size, items.Size); -selection.ApplyRequests(ms_io); -for (int idx = 0; idx < items.Size; idx++) -{ - bool item_is_selected = selection.Contains(items[idx].ID); - ImGui::SetNextItemSelectionUserData(idx); - ImGui::Selectable(label, item_is_selected); -} -ms_io = ImGui::EndMultiSelect(); -selection.ApplyRequests(ms_io); -``` - -To store a multi-selection, in your real application you could: -- A) Use this helper as a convenience. We use our simple key->value ImGuiStorage as a std::set replacement. -- B) Use your own external storage: e.g. std::set, std::vector, interval trees, etc. -- C) Use intrusively stored selection (e.g. 'bool IsSelected' inside objects). Not recommended because you can't have multiple views over same objects. Also some features requires to provide selection _size_, which with this strategy requires additional work. - -Our BeginMultiSelect() api/system doesn't make assumption about: -- how you want to identify items in multi-selection API? (Indices or Custom Ids or Pointers? Indices are better: easy to iterate/interpolate) -- how you want to store persistent selection data? (Indices or Custom Ids or Pointers? Custom Ids is better: as selection can persist) - -In ImGuiSelectionBasicStorage we: -- always use indices in the multi-selection API (passed to SetNextItemSelectionUserData(), retrieved in ImGuiMultiSelectIO) -- use the AdapterIndexToStorageId() indirection layer to abstract how persistent selection data is derived from an index. -- in some cases we use Index as custom identifier (default implementation returns Index cast as Identifier): only valid for a never changing item list. -- in some cases we read an ID from some custom item data structure (better, and closer to what you would do in your codebase) - -Many combinations are possible depending on how you prefer to store your items and how you prefer to store your selection. -When your application settles on a choice, you may want to get rid of this indirection layer and do your own thing. - ----- - ### Using ImGuiSelectionExernalStorage helper Optional helper to apply multi-selection requests to existing randomly accessible storage.