#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.
@ -2757,6 +2758,54 @@ struct ImGuiMultiSelectIO
boolRangeSrcReset;// app:w / ms:r // (If using deletion) Set before EndMultiSelect() to reset ResetSrcItem (e.g. if deleted selection).
};
// Helper struct to store multi-selection state + apply multi-selection requests.
// - Used by our demos and provided as a convenience if you want to quickly implement multi-selection.
// - Provide an abstraction layer for the purpose of the demo showcasing different forms of underlying selection data.
// - USING THIS IS NOT MANDATORY. This is only a helper and is not part of the main API. Advanced users are likely to implement their own.
// To store a single-selection, you only need a single variable and don't need any of this!
// 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<ImGuiID> replacement.
// - B) Use your own external storage: e.g. std::set<MyObjectId>, std::vector<MyObjectId>, std::set<index>, interval trees, etc.
// are generally appropriate. Even a large array of bool might work for you...
// - C) Use intrusively stored selection (e.g. 'bool IsSelected' inside your object). Not recommended because:
// - it means you cannot have multiple simultaneous views over your objects.
// - some of our features requires you to provide the selection _size_, which with this specific strategy require additional work.
// Our BeginMultiSelect() api/system doesn't make assumption about:
// - how you want to identify items in multi-selection API? Indices(*) / Custom Identifiers / Pointers ?
// - how you want to store persistent selection data? Indices / Custom Identifiers(*) / Pointers ?
// (*) This is the suggested solution: pass indices to API (because easy to iterate/interpolate) + persist your custom identifiers inside selection data.
// In ImGuiSelectionBasicStorage we:
// - always use indices in the multi-selection API (passed to SetNextItemSelectionUserData(), retrieved in ImGuiMultiSelectIO)
// - use a little extra indirection layer in order to abstract how persistent selection data is derived from an index.
// - in some cases we use Index as custom identifier (default, not ideal)
// - 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 WILL PROBABLY PREFER TO GET RID OF THE UNNECESSARY 'AdapterIndexToStorageId()' INDIRECTION LOGIC.
// In theory, for maximum abstraction, this class could contains AdapterIndexToUserData() and AdapterUserDataToIndex() functions as well,
// but because we always use indices in SetNextItemSelectionUserData() in the demo, we omit that for clarify.
structImGuiSelectionBasicStorage
{
ImGuiStorageStorage;// [Internal] Selection set. Think of this as similar to e.g. std::set<ImGuiID>
intSize;// Number of selected items (== number of 1 in the Storage, maintained by this class).
// Adapter to convert item index to item identifier
void*AdapterData;// e.g. selection.AdapterData = (void*)my_items;
ImGuiID(*AdapterIndexToStorageId)(ImGuiSelectionBasicStorage*self,intidx);// e.g. selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return ((MyItems**)self->AdapterData)[idx]->ID; };
// [Advanced] Helper class to store multi-selection state, used by the BeginMultiSelect() demos.
// Provide an abstraction layer for the purpose of the demo showcasing different forms of underlying selection data.
// To store a single-selection:
// - You only need a single variable and don't need any of this!
// To store a multi-selection, in your real application you could:
// - A) Use external storage: e.g. std::set<MyObjectId>, std::vector<MyObjectId>, std::set<index>, interval trees, etc.
// are generally appropriate. Even a large array of bool might work for you...
// This code here use ImGuiStorage (a simple key->value storage) as a std::set replacement to avoid external dependencies.
// - B) Or use intrusively stored selection (e.g. 'bool IsSelected' inside your object).
// - That means you cannot have multiple simultaneous views over your objects.
// - Some of our features requires you to provide the selection _size_, which with this specific strategy require additional work.
// - So we suggest using intrusive selection for multi-select is not really adequate.
// Our multi-selection system doesn't make assumption about:
// - how you want to identify items in multi-selection API? Indices(*) / Custom Identifiers / Pointers ?
// - how you want to store persistent selection data? Indices / Custom Identifiers(*) / Pointers ?
// (*) This is the suggested solution: pass indices to API (because easy to iterate/interpolate) + persist your custom identifiers inside selection data.
// In this demo we:
// - always use indices in the multi-selection API (passed to SetNextItemSelectionUserData(), retrieved in ImGuiMultiSelectIO)
// - use a little extra indirection layer in order to abstract how persistent selection data is derived from an index.
// - in some cases we use Index as custom identifier
// - in some cases we read an ID from some custom item data structure (this is 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 WILL PROBABLY PREFER TO GET RID OF THE UNNECESSARY 'AdapterIndexToStorageId()' INDIRECTION LOGIC.
// In theory, for maximum abstraction, this class could contains AdapterIndexToUserData() and AdapterUserDataToIndex() functions as well,
// but because we always use indices in SetNextItemSelectionUserData() in the demo, we omit that for clarify.
// Apply requests coming from BeginMultiSelect() and EndMultiSelect().
// - Enable 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.
// - Honoring SetRange requests requires that you can iterate/interpolate between RangeFirstItem and RangeLastItem.
// - In this demo we often submit indices to SetNextItemSelectionUserData() + store the same indices in persistent selection.
// - Your code may do differently. If you store pointers or objects ID in ImGuiSelectionUserData you may need to perform
// a lookup in order to have some way to iterate/interpolate between two items.
// - A full-featured application is likely to allow search/filtering which is likely to lead to using indices
// and constructing a view index <> object id/ptr data structure anyway.
// WHEN YOUR APPLICATION SETTLES ON A CHOICE, YOU WILL PROBABLY PREFER TO GET RID OF THIS UNNECESSARY 'ExampleSelectionAdapter' INDIRECTION LOGIC.
// Notice that with the simplest adapter (using indices everywhere), all functions return their parameters.
// The most simple implementation (using indices everywhere) would look like:
// for (ImGuiSelectionRequest& req : ms_io->Requests)
// {
// if (req.Type == ImGuiSelectionRequestType_Clear) { Clear(); }
// if (req.Type == ImGuiSelectionRequestType_SelectAll) { Clear(); for (int n = 0; n < items_count; n++) { AddItem(n); } }
// if (req.Type == ImGuiSelectionRequestType_SetRange) { for (int n = (int)ms_io->RangeFirstItem; n <= (int)ms_io->RangeLastItem; n++) { UpdateItem(n, ms_io->RangeSelected); } }
// Apply requests coming from BeginMultiSelect() and EndMultiSelect().
// - Enable 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.
// - Honoring SetRange requests requires that you can iterate/interpolate between RangeFirstItem and RangeLastItem.
// - In this demo we often submit indices to SetNextItemSelectionUserData() + store the same indices in persistent selection.
// - Your code may do differently. If you store pointers or objects ID in ImGuiSelectionUserData you may need to perform
// a lookup in order to have some way to iterate/interpolate between two items.
// - A full-featured application is likely to allow search/filtering which is likely to lead to using indices
// and constructing a view index <> object id/ptr data structure anyway.
// WHEN YOUR APPLICATION SETTLES ON A CHOICE, YOU WILL PROBABLY PREFER TO GET RID OF THIS UNNECESSARY 'ImGuiSelectionBasicStorage' INDIRECTION LOGIC.
// Notice that with the simplest adapter (using indices everywhere), all functions return their parameters.
// The most simple implementation (using indices everywhere) would look like:
// for (ImGuiSelectionRequest& req : ms_io->Requests)
// {
// if (req.Type == ImGuiSelectionRequestType_Clear) { Clear(); }
// if (req.Type == ImGuiSelectionRequestType_SelectAll) { Clear(); for (int n = 0; n < items_count; n++) { AddItem(n); } }
// if (req.Type == ImGuiSelectionRequestType_SetRange) { for (int n = (int)ms_io->RangeFirstItem; n <= (int)ms_io->RangeLastItem; n++) { UpdateItem(n, ms_io->RangeSelected); } }