// e.g. instructive selection (store a bool inside each object), external array (store an array aside from your objects),
// e.g. instructive selection (store a bool inside each object), external array (store an array aside from your objects),
// hash/map/set (store only selected items in a hash/map/set), or other structures (store indices in an interval tree), etc.
// hash/map/set (store only selected items in a hash/map/set), or other structures (store indices in an interval tree), etc.
// Usage flow:
// Usage flow:
// 1) Call BeginMultiSelect() with the last saved value of ->RangeSrc and its selection state.
// Begin
// It is because you need to pass its selection state (and you own selection) that we don't store this value in Dear ImGui.
// 1) Call BeginMultiSelect() with the last saved value of ->RangeSrc and its selection state.
// (For the initial frame or when resetting your selection state: you may use the value for your first item or a "null" value that matches the type stored in your void*).
// It is because you need to pass its selection state (and you own selection) that we don't store this value in Dear ImGui.
// 2) Honor Clear/SelectAll requests by updating your selection data. [Only required if you are using a clipper in step 4]
// (For the initial frame or when resetting your selection state: you may use the value for your first item or a "null" value that matches the type stored in your void*).
// 3) Set RangeSrcPassedBy=true if the RangeSrc item is part of the items clipped before the first submitted/visible item. [Only required if you are using a clipper in step 4]
// 2) Honor Clear/SelectAll requests by updating your selection data. Only required if you are using a clipper in step 4: but you can use same code as step 6 anyway.
// This is because for range-selection we need to know if we are currently "inside" or "outside" the range.
// Loop
// If you are using integer indices everywhere, this is easy to compute: if (clipper.DisplayStart > (int)data->RangeSrc) { data->RangeSrcPassedBy = true; }
// 3) Set RangeSrcPassedBy=true if the RangeSrc item is part of the items clipped before the first submitted/visible item. [Only required if you are using a clipper in step 4]
// 4) Submit your items with SetNextItemSelectionUserData() + Selectable()/TreeNode() calls.
// This is because for range-selection we need to know if we are currently "inside" or "outside" the range.
// Call IsItemToggledSelection() to query if the selection state has been toggled, if you need the info immediately for your display (before EndMultiSelect()).
// If you are using integer indices everywhere, this is easy to compute: if (clipper.DisplayStart > (int)data->RangeSrc) { data->RangeSrcPassedBy = true; }
// When cannot return a "IsItemSelected()" value because we need to consider clipped/unprocessed items, this is why we return a "Toggle" event instead.
// 4) Submit your items with SetNextItemSelectionUserData() + Selectable()/TreeNode() calls.
// 5) Call EndMultiSelect(). Save the value of ->RangeSrc for the next frame (you may convert the value in a format that is safe for persistance)
// Call IsItemToggledSelection() to query if the selection state has been toggled, if you need the info immediately for your display (before EndMultiSelect()).
// 6) Honor Clear/SelectAll/SetRange requests by updating your selection data. Always process them in this order (as you will receive Clear+SetRange request simultaneously)
// When cannot return a "IsItemSelected()" value because we need to consider clipped/unprocessed items, this is why we return a "Toggle" event instead.
// End
// 5) Call EndMultiSelect(). Save the value of ->RangeSrc for the next frame (you may convert the value in a format that is safe for persistance)
// 6) Honor Clear/SelectAll/SetRange requests by updating your selection data. Always process them in this order (as you will receive Clear+SetRange request simultaneously)
// If you submit all items (no clipper), Step 2 and 3 and will be handled by Selectable() on a per-item basis.
// If you submit all items (no clipper), Step 2 and 3 and will be handled by Selectable() on a per-item basis.
structImGuiMultiSelectData
structImGuiMultiSelectData
{
{
boolIsFocused;// Begin // Set if currently focusing the selection scope (any item of the selection). May be used if you have custom shortcut associated to selection.
boolRequestClear;// Begin, End // 1. Request user to clear selection
boolRequestClear;// Begin, End // Request user to clear selection
boolRequestSelectAll;// Begin, End // 2. Request user to select all
boolRequestSelectAll;// Begin, End // Request user to select all
boolRequestSetRange;// End // 3. Request user to set or clear selection in the [RangeSrc..RangeDst] range
boolRequestSetRange;// End // Request user to set or clear selection in the [RangeSrc..RangeDst] range
boolRangeSrcPassedBy;// Loop // (If clipping) Need to be set by user if RangeSrc was part of the clipped set before submitting the visible items. Ignore if not clipping.
boolRangeSrcPassedBy;// In loop // (If clipping) Need to be set by user if RangeSrc was part of the clipped set before submitting the visible items. Ignore if not clipping.
boolRangeValue;// End // End: parameter from RequestSetRange request. true = Select Range, false = Unselect Range.
boolRangeValue;// End // End: parameter from RequestSetRange request. True = Select Range, False = Unselect range.
void*RangeSrc;// Begin, End // End: parameter from RequestSetRange request + you need to save this value so you can pass it again next frame. / Begin: this is the value you passed to BeginMultiSelect()
void*RangeSrc;// Begin, End // End: parameter from RequestSetRange request + you need to save this value so you can pass it again next frame. / Begin: this is the value you passed to BeginMultiSelect()
void*RangeDst;// End // End: parameter from RequestSetRange request.
void*RangeDst;// End // End: parameter from RequestSetRange request.
intRangeDirection;// End // End: parameter from RequestSetRange request. +1 if RangeSrc came before RangeDst, -1 otherwise. Available as an indicator in case you cannot infer order from the void* values.
intRangeDirection;// End // End: parameter from RequestSetRange request. +1 if RangeSrc came before RangeDst, -1 otherwise. Available as an indicator in case you cannot infer order from the void* values.
// you will need a way to iterate from one object to another given the ID you use.
// 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'.
// 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: Would be worth providing a demo of doing this.
// FIXME-MULTISELECT: SetRange() is currently very inefficient since it doesn't take advantage of the fact that ImGuiStorage stores sorted key.
// FIXME-MULTISELECT: This implementation of SetRange() is inefficient because it doesn't take advantage of the fact that ImGuiStorage stores sorted key.
voidSelectAll(intcount){Storage.Data.resize(count);for(intidx=0;idx<count;idx++)Storage.Data[idx]=ImGuiStoragePair((ImGuiID)idx,1);SelectionSize=count;}// This could be using SetRange(), but it this way is faster.
voidSelectAll(intcount){Storage.Data.resize(count);for(intidx=0;idx<count;idx++)Storage.Data[idx]=ImGuiStoragePair((ImGuiID)idx,1);SelectionSize=count;}// This could be using SetRange(), but it this way is faster.
// Apply requests coming from BeginMultiSelect() and EndMultiSelect(). Must be done in this order! Order->SelectAll->SetRange.
ImGuiIDFocusScopeId;// Same as g.CurrentFocusScopeId (unless another selection scope was pushed manually)
ImGuiIDFocusScopeId;// Copied from g.CurrentFocusScopeId (unless another selection scope was pushed manually)
ImGuiMultiSelectFlagsFlags;
ImGuiKeyChordKeyMods;
ImGuiWindow*Window;
ImGuiMultiSelectDataIn;// The In requests are set and returned by BeginMultiSelect()
ImGuiMultiSelectDataIn;// The In requests are set and returned by BeginMultiSelect()
ImGuiMultiSelectDataOut;// The Out requests are finalized and returned by EndMultiSelect()
ImGuiMultiSelectDataOut;// The Out requests are finalized and returned by EndMultiSelect()
boolIsFocused;// Set if currently focusing the selection scope (any item of the selection). May be used if you have custom shortcut associated to selection.
boolInRangeDstPassedBy;// (Internal) set by the the item that match NavJustMovedToId when InRequestRangeSetNav is set.
boolInRangeDstPassedBy;// (Internal) set by the the item that match NavJustMovedToId when InRequestRangeSetNav is set.
boolInRequestSetRangeNav;// (Internal) set by BeginMultiSelect() when using Shift+Navigation. Because scrolling may be affected we can't afford a frame of lag with Shift+Navigation.
boolInRequestSetRangeNav;// (Internal) set by BeginMultiSelect() when using Shift+Navigation. Because scrolling may be affected we can't afford a frame of lag with Shift+Navigation.
//ImRect Rect; // Extent of selection scope between BeginMultiSelect() / EndMultiSelect(), used by ImGuiMultiSelectFlags_ClearOnClickRectVoid.
//ImRect Rect; // Extent of selection scope between BeginMultiSelect() / EndMultiSelect(), used by ImGuiMultiSelectFlags_ClearOnClickRectVoid.
// FIXME: Polling key mods after the fact (frame following the move request) is incorrect, but latching it would requires non-trivial change in MultiSelectItemFooter()
// FIXME: Polling key mods after the fact (frame following the move request) is incorrect, but latching it would requires non-trivial change in MultiSelectItemFooter()