@ -2753,51 +2753,47 @@ static const char* ExampleNames[] =
" Cauliflower " , " Celery " , " Celery Root " , " Celcuce " , " Chayote " , " Chinese Broccoli " , " Corn " , " Cucumber "
" Cauliflower " , " Celery " , " Celery Root " , " Celcuce " , " Chayote " , " Chinese Broccoli " , " Corn " , " Cucumber "
} ;
} ;
// 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 from some custom item data structure.
// 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 THIS UNNECESSARY 'ExampleSelectionAdapter' INDIRECTION LOGIC.
// In theory, for maximum abstraction, this class could contains IndexToUserData() and UserDataToIndex() functions,
// but because we always use indices in SetNextItemSelectionUserData() in the demo, we omit that for clarify.
struct ExampleSelectionAdapter
{
void * Data = NULL ;
ImGuiID ( * IndexToStorage ) ( ExampleSelectionAdapter * self , int idx ) ; // Function to convert item index to data stored in persistent selection
ExampleSelectionAdapter ( ) { SetupForDirectIndexes ( ) ; }
// Example for the simplest case: Index==SelectionStorage (this adapter doesn't even need to use the item data field)
void SetupForDirectIndexes ( ) { IndexToStorage = [ ] ( ExampleSelectionAdapter * , int idx ) { return ( ImGuiID ) idx ; } ; }
} ;
// [Advanced] Helper class to store multi-selection state, used by the BeginMultiSelect() demos.
// [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.
// Provide an abstraction layer for the purpose of the demo showcasing different forms of underlying selection data.
// To store a single-selection:
// To store a single-selection:
// - You only need a single variable and don't need any of this!
// - You only need a single variable and don't need any of this!
// To store a multi-selection, in your real application you could:
// To store a multi-selection, in your real application you could:
// - A) Use external storage: e.g. std::set<index>, std::set< MyObjectId>, std::vector<MyObjectId>, interval trees, etc.
// - 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...
// 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.
// 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).
// - B) Or use intrusively stored selection (e.g. 'bool IsSelected' inside your object).
// - It is simple, but it means you cannot have multiple simultaneous views over your objects.
// - 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:
// - Some of our features requires you to provide the selection _size_, which with this specific strategy require additional work.
// either you maintain it (which requires storage outside of objects) either you recompute (which may be costly for large sets).
// - So we suggest using intrusive selection for multi-select is not really adequate.
// - 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.
struct ExampleSelection
struct ExampleSelection
{
{
// Data
// Data
ImGuiStorage Storage ; // Selection set
ImGuiStorage Storage ; // Selection set (think of this as similar to e.g. std::set<ImGuiID>)
int Size ; // Number of selected items (== number of 1 in the Storage, maintained by this class).
int Size ; // Number of selected items (== number of 1 in the Storage, maintained by this class).
bool QueueDeletion ; // Request deleting selected items
bool QueueDeletion ; // Request deleting selected items
// Adapter to convert item index to item identifier
// e.g.
// selection.AdapterData = (void*)my_items;
// selection.AdapterIndexToStorageId = [](ExampleSelection* s, int idx) { return ((MyItems**)s->AdapterData)[idx]->ID; };
void * AdapterData ;
ImGuiID ( * AdapterIndexToStorageId ) ( ExampleSelection * self , int idx ) ;
// Functions
// Functions
ExampleSelection ( ) { Clear ( ) ; }
ExampleSelection ( ) { Clear ( ) ; AdapterData = NULL ; AdapterIndexToStorageId = [ ] ( ExampleSelection * , int idx ) { return ( ImGuiID ) idx ; } ; }
void Clear ( ) { Storage . Data . resize ( 0 ) ; Size = 0 ; QueueDeletion = false ; }
void Clear ( ) { Storage . Data . resize ( 0 ) ; Size = 0 ; QueueDeletion = false ; }
void Swap ( ExampleSelection & rhs ) { Storage . Data . swap ( rhs . Storage . Data ) ; }
void Swap ( ExampleSelection & rhs ) { Storage . Data . swap ( rhs . Storage . Data ) ; }
bool Contains ( ImGuiID key ) const { return Storage . GetInt ( key , 0 ) ! = 0 ; }
bool Contains ( ImGuiID key ) const { return Storage . GetInt ( key , 0 ) ! = 0 ; }
@ -2808,8 +2804,8 @@ struct ExampleSelection
void DebugTooltip ( ) { if ( ImGui : : BeginTooltip ( ) ) { for ( auto & pair : Storage . Data ) if ( pair . val_i ) ImGui : : Text ( " 0x%03X (%d) " , pair . key , pair . key ) ; ImGui : : EndTooltip ( ) ; } }
void DebugTooltip ( ) { if ( ImGui : : BeginTooltip ( ) ) { for ( auto & pair : Storage . Data ) if ( pair . val_i ) ImGui : : Text ( " 0x%03X (%d) " , pair . key , pair . key ) ; ImGui : : EndTooltip ( ) ; } }
// Apply requests coming from BeginMultiSelect() and EndMultiSelect().
// Apply requests coming from BeginMultiSelect() and EndMultiSelect().
// - Must be done in this order! Clear->SelectAll->SetRange. Enable 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.
// - Enable 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.
// - Honoring Request SetRange requires that you can iterate/interpolate between RangeFirstItem and RangeLastItem.
// - 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.
// - 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
// - 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 lookup in order to have some way to iterate/interpolate between two items.
@ -2824,34 +2820,34 @@ struct ExampleSelection
// if (req.Type == ImGuiSelectionRequestType_SelectAll) { Clear(); for (int n = 0; n < items_count; n++) { AddItem(n); } }
// 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); } }
// if (req.Type == ImGuiSelectionRequestType_SetRange) { for (int n = (int)ms_io->RangeFirstItem; n <= (int)ms_io->RangeLastItem; n++) { UpdateItem(n, ms_io->RangeSelected); } }
// }
// }
void ApplyRequests ( ImGuiMultiSelectIO * ms_io , ExampleSelectionAdapter * adapter , int items_count )
void ApplyRequests ( ImGuiMultiSelectIO * ms_io , int items_count )
{
{
IM_ASSERT ( adapter - > IndexToStorage ! = NULL ) ;
IM_ASSERT ( AdapterIndexToStorageId ! = NULL ) ;
for ( ImGuiSelectionRequest & req : ms_io - > Requests )
for ( ImGuiSelectionRequest & req : ms_io - > Requests )
{
{
if ( req . Type = = ImGuiSelectionRequestType_Clear | | req . Type = = ImGuiSelectionRequestType_SelectAll )
if ( req . Type = = ImGuiSelectionRequestType_Clear )
Clear ( ) ;
Clear ( ) ;
if ( req . Type = = ImGuiSelectionRequestType_SelectAll )
if ( req . Type = = ImGuiSelectionRequestType_SelectAll )
{
{
Storage . Data . resize ( 0 ) ;
Storage . Data . reserve ( items_count ) ;
Storage . Data . reserve ( items_count ) ;
for ( int idx = 0 ; idx < items_count ; idx + + )
for ( int idx = 0 ; idx < items_count ; idx + + )
AddItem ( adapter - > IndexToStorage ( adapter , idx ) ) ;
AddItem ( AdapterIndexToStorageId ( this , idx ) ) ;
}
}
if ( req . Type = = ImGuiSelectionRequestType_SetRange )
if ( req . Type = = ImGuiSelectionRequestType_SetRange )
for ( int idx = ( int ) req . RangeFirstItem ; idx < = ( int ) req . RangeLastItem ; idx + + )
for ( int idx = ( int ) req . RangeFirstItem ; idx < = ( int ) req . RangeLastItem ; idx + + )
UpdateItem ( adapter - > IndexToStorage ( adapter , idx ) , req . RangeSelected ) ;
UpdateItem ( AdapterIndexToStorageId ( this , idx ) , req . RangeSelected ) ;
}
}
}
}
// Find which item should be Focused after deletion.
// Find which item should be Focused after deletion.
// We output an index in the before-deletion-items list, that user will call SetKeyboardFocusHere() on .
// Call _before_ item submission. Retunr an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it .
// The subsequent ApplyDeletionPostLoop() code will use it to apply Selection.
// The subsequent ApplyDeletionPostLoop() code will use it to apply Selection.
// - We cannot provide this logic in core Dear ImGui because we don't have access to selection data.
// - We cannot provide this logic in core Dear ImGui because we don't have access to selection data.
// - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for consistency and flexibility.
// - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for consistency and flexibility.
// - Important: Deletion only works if the underlying ImGuiID for your items are stable: aka not depend on their index, but on e.g. item id/ptr.
// - Important: Deletion only works if the underlying ImGuiID for your items are stable: aka not depend on their index, but on e.g. item id/ptr.
// FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or offset.
// FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or offset.
template < typename ITEM_TYPE >
int ApplyDeletionPreLoop ( ImGuiMultiSelectIO * ms_io , int items_count )
int ApplyDeletionPreLoop ( ImGuiMultiSelectIO * ms_io , ExampleSelectionAdapter * adapter , ImVector < ITEM_TYPE > & items )
{
{
QueueDeletion = false ;
QueueDeletion = false ;
@ -2864,13 +2860,13 @@ struct ExampleSelection
}
}
// If focused item is selected: land on first unselected item after focused item.
// If focused item is selected: land on first unselected item after focused item.
for ( int idx = focused_idx + 1 ; idx < items . Size ; idx + + )
for ( int idx = focused_idx + 1 ; idx < items_count ; idx + + )
if ( ! Contains ( adapter - > IndexToStorage ( adapter , idx ) ) )
if ( ! Contains ( AdapterIndexToStorageId ( this , idx ) ) )
return idx ;
return idx ;
// If focused item is selected: otherwise return last unselected item before focused item.
// If focused item is selected: otherwise return last unselected item before focused item.
for ( int idx = IM_MIN ( focused_idx , items . Size ) - 1 ; idx > = 0 ; idx - - )
for ( int idx = IM_MIN ( focused_idx , items_count ) - 1 ; idx > = 0 ; idx - - )
if ( ! Contains ( adapter - > IndexToStorage ( adapter , idx ) ) )
if ( ! Contains ( AdapterIndexToStorageId ( this , idx ) ) )
return idx ;
return idx ;
return - 1 ;
return - 1 ;
@ -2880,7 +2876,7 @@ struct ExampleSelection
// - Call after EndMultiSelect()
// - Call after EndMultiSelect()
// - We cannot provide this logic in core Dear ImGui because we don't have access to your items, nor to selection data.
// - We cannot provide this logic in core Dear ImGui because we don't have access to your items, nor to selection data.
template < typename ITEM_TYPE >
template < typename ITEM_TYPE >
void ApplyDeletionPostLoop ( ImGuiMultiSelectIO * ms_io , ExampleSelectionAdapter * adapter , ImVector < ITEM_TYPE > & items , int item_curr_idx_to_select )
void ApplyDeletionPostLoop ( ImGuiMultiSelectIO * ms_io , ImVector < ITEM_TYPE > & items , int item_curr_idx_to_select )
{
{
// Rewrite item list (delete items) + convert old selection index (before deletion) to new selection index (after selection).
// Rewrite item list (delete items) + convert old selection index (before deletion) to new selection index (after selection).
// If NavId was not part of selection, we will stay on same item.
// If NavId was not part of selection, we will stay on same item.
@ -2889,7 +2885,7 @@ struct ExampleSelection
int item_next_idx_to_select = - 1 ;
int item_next_idx_to_select = - 1 ;
for ( int idx = 0 ; idx < items . Size ; idx + + )
for ( int idx = 0 ; idx < items . Size ; idx + + )
{
{
if ( ! Contains ( adapter - > IndexToStorage ( adapter , idx ) ) )
if ( ! Contains ( AdapterIndexToStorageId ( this , idx ) ) )
new_items . push_back ( items [ idx ] ) ;
new_items . push_back ( items [ idx ] ) ;
if ( item_curr_idx_to_select = = idx )
if ( item_curr_idx_to_select = = idx )
item_next_idx_to_select = new_items . Size - 1 ;
item_next_idx_to_select = new_items . Size - 1 ;
@ -2899,7 +2895,7 @@ struct ExampleSelection
// Update selection
// Update selection
Clear ( ) ;
Clear ( ) ;
if ( item_next_idx_to_select ! = - 1 & & ms_io - > NavIdSelected )
if ( item_next_idx_to_select ! = - 1 & & ms_io - > NavIdSelected )
AddItem ( adapter - > IndexToStorage ( adapter , item_next_idx_to_select ) ) ;
AddItem ( AdapterIndexToStorageId ( this , item_next_idx_to_select ) ) ;
}
}
} ;
} ;
@ -2939,10 +2935,9 @@ struct ExampleDualListBox
void ApplySelectionRequests ( ImGuiMultiSelectIO * ms_io , int side )
void ApplySelectionRequests ( ImGuiMultiSelectIO * ms_io , int side )
{
{
// In this example we store item id in selection (instead of item index)
// In this example we store item id in selection (instead of item index)
ExampleSelectionAdapter adapter ;
Selections [ side ] . AdapterData = Items [ side ] . Data ;
adapter . Data = Items [ side ] . Data ;
Selections [ side ] . AdapterIndexToStorageId = [ ] ( ExampleSelection * self , int idx ) { ImGuiID * items = ( ImGuiID * ) self - > AdapterData ; return items [ idx ] ; } ;
adapter . IndexToStorage = [ ] ( ExampleSelectionAdapter * self , int idx ) { return ( ImGuiID ) ( ( ImGuiID * ) self - > Data ) [ idx ] ; } ;
Selections [ side ] . ApplyRequests ( ms_io , Items [ side ] . Size ) ;
Selections [ side ] . ApplyRequests ( ms_io , & adapter , Items [ side ] . Size ) ;
}
}
static int IMGUI_CDECL CompareItemsByValue ( const void * lhs , const void * rhs )
static int IMGUI_CDECL CompareItemsByValue ( const void * lhs , const void * rhs )
{
{
@ -3091,8 +3086,8 @@ static void ShowDemoWindowMultiSelect()
IMGUI_DEMO_MARKER ( " Widgets/Selection State/Multi-Select " ) ;
IMGUI_DEMO_MARKER ( " Widgets/Selection State/Multi-Select " ) ;
if ( ImGui : : TreeNode ( " Multi-Select " ) )
if ( ImGui : : TreeNode ( " Multi-Select " ) )
{
{
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
static ExampleSelection selection ;
static ExampleSelection selection ;
ExampleSelectionAdapter selection_adapter ; // Use default: Pass index to SetNextItemSelectionUserData(), store index in Selection
ImGui : : Text ( " Tips: Use 'Debug Log->Selection' to see selection requests as they happen. " ) ;
ImGui : : Text ( " Tips: Use 'Debug Log->Selection' to see selection requests as they happen. " ) ;
@ -3109,7 +3104,7 @@ static void ShowDemoWindowMultiSelect()
{
{
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape ;
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape ;
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( flags ) ;
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( flags ) ;
selection . ApplyRequests ( ms_io , & selection_adapter , ITEMS_COUNT ) ;
selection . ApplyRequests ( ms_io , ITEMS_COUNT ) ;
for ( int n = 0 ; n < ITEMS_COUNT ; n + + )
for ( int n = 0 ; n < ITEMS_COUNT ; n + + )
{
{
@ -3121,7 +3116,7 @@ static void ShowDemoWindowMultiSelect()
}
}
ms_io = ImGui : : EndMultiSelect ( ) ;
ms_io = ImGui : : EndMultiSelect ( ) ;
selection . ApplyRequests ( ms_io , & selection_adapter , ITEMS_COUNT ) ;
selection . ApplyRequests ( ms_io , ITEMS_COUNT ) ;
ImGui : : EndListBox ( ) ;
ImGui : : EndListBox ( ) ;
}
}
@ -3132,8 +3127,8 @@ static void ShowDemoWindowMultiSelect()
IMGUI_DEMO_MARKER ( " Widgets/Selection State/Multi-Select (with clipper) " ) ;
IMGUI_DEMO_MARKER ( " Widgets/Selection State/Multi-Select (with clipper) " ) ;
if ( ImGui : : TreeNode ( " Multi-Select (with clipper) " ) )
if ( ImGui : : TreeNode ( " Multi-Select (with clipper) " ) )
{
{
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
static ExampleSelection selection ;
static ExampleSelection selection ;
ExampleSelectionAdapter selection_adapter ; // Use default: Pass index to SetNextItemSelectionUserData(), store index in Selection
ImGui : : Text ( " Added features: " ) ;
ImGui : : Text ( " Added features: " ) ;
ImGui : : BulletText ( " Using ImGuiListClipper. " ) ;
ImGui : : BulletText ( " Using ImGuiListClipper. " ) ;
@ -3144,7 +3139,7 @@ static void ShowDemoWindowMultiSelect()
{
{
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape ;
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape ;
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( flags ) ;
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( flags ) ;
selection . ApplyRequests ( ms_io , & selection_adapter , ITEMS_COUNT ) ;
selection . ApplyRequests ( ms_io , ITEMS_COUNT ) ;
ImGuiListClipper clipper ;
ImGuiListClipper clipper ;
clipper . Begin ( ITEMS_COUNT ) ;
clipper . Begin ( ITEMS_COUNT ) ;
@ -3163,7 +3158,7 @@ static void ShowDemoWindowMultiSelect()
}
}
ms_io = ImGui : : EndMultiSelect ( ) ;
ms_io = ImGui : : EndMultiSelect ( ) ;
selection . ApplyRequests ( ms_io , & selection_adapter , ITEMS_COUNT ) ;
selection . ApplyRequests ( ms_io , ITEMS_COUNT ) ;
ImGui : : EndListBox ( ) ;
ImGui : : EndListBox ( ) ;
}
}
@ -3183,9 +3178,9 @@ static void ShowDemoWindowMultiSelect()
{
{
// Intentionally separating items data from selection data!
// Intentionally separating items data from selection data!
// But you may decide to store selection data inside your item (aka intrusive storage).
// But you may decide to store selection data inside your item (aka intrusive storage).
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
static ImVector < int > items ;
static ImVector < int > items ;
static ExampleSelection selection ;
static ExampleSelection selection ;
ExampleSelectionAdapter selection_adapter ; // Use default: Pass index to SetNextItemSelectionUserData(), store index in Selection
ImGui : : Text ( " Adding features: " ) ;
ImGui : : Text ( " Adding features: " ) ;
ImGui : : BulletText ( " Dynamic list with Delete key support. " ) ;
ImGui : : BulletText ( " Dynamic list with Delete key support. " ) ;
@ -3210,7 +3205,7 @@ static void ShowDemoWindowMultiSelect()
{
{
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape ;
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape ;
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( flags ) ;
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( flags ) ;
selection . ApplyRequests ( ms_io , & selection_adapter , items . Size ) ;
selection . ApplyRequests ( ms_io , items . Size ) ;
// FIXME-MULTISELECT: Shortcut(). Hard to demo this? May be helpful to send a helper/optional "delete" signal.
// FIXME-MULTISELECT: Shortcut(). Hard to demo this? May be helpful to send a helper/optional "delete" signal.
// FIXME-MULTISELECT: may turn into 'ms_io->RequestDelete' -> need HasSelection passed.
// FIXME-MULTISELECT: may turn into 'ms_io->RequestDelete' -> need HasSelection passed.
@ -3218,7 +3213,7 @@ static void ShowDemoWindowMultiSelect()
const bool want_delete = selection . QueueDeletion | | ( ( selection . GetSize ( ) > 0 ) & & ImGui : : IsWindowFocused ( ) & & ImGui : : IsKeyPressed ( ImGuiKey_Delete ) ) ;
const bool want_delete = selection . QueueDeletion | | ( ( selection . GetSize ( ) > 0 ) & & ImGui : : IsWindowFocused ( ) & & ImGui : : IsKeyPressed ( ImGuiKey_Delete ) ) ;
int item_curr_idx_to_focus = - 1 ;
int item_curr_idx_to_focus = - 1 ;
if ( want_delete )
if ( want_delete )
item_curr_idx_to_focus = selection . ApplyDeletionPreLoop ( ms_io , & selection_adapter , items ) ;
item_curr_idx_to_focus = selection . ApplyDeletionPreLoop ( ms_io , items . Size ) ;
for ( int n = 0 ; n < items . Size ; n + + )
for ( int n = 0 ; n < items . Size ; n + + )
{
{
@ -3235,9 +3230,9 @@ static void ShowDemoWindowMultiSelect()
// Apply multi-select requests
// Apply multi-select requests
ms_io = ImGui : : EndMultiSelect ( ) ;
ms_io = ImGui : : EndMultiSelect ( ) ;
selection . ApplyRequests ( ms_io , & selection_adapter , items . Size ) ;
selection . ApplyRequests ( ms_io , items . Size ) ;
if ( want_delete )
if ( want_delete )
selection . ApplyDeletionPostLoop ( ms_io , & selection_adapter , items , item_curr_idx_to_focus ) ;
selection . ApplyDeletionPostLoop ( ms_io , items , item_curr_idx_to_focus ) ;
ImGui : : EndListBox ( ) ;
ImGui : : EndListBox ( ) ;
}
}
@ -3264,10 +3259,10 @@ static void ShowDemoWindowMultiSelect()
IMGUI_DEMO_MARKER ( " Widgets/Selection State/Multi-Select (multiple scopes) " ) ;
IMGUI_DEMO_MARKER ( " Widgets/Selection State/Multi-Select (multiple scopes) " ) ;
if ( ImGui : : TreeNode ( " Multi-Select (multiple scopes) " ) )
if ( ImGui : : TreeNode ( " Multi-Select (multiple scopes) " ) )
{
{
// Use default select: Pass index to SetNextItemSelectionUserData(), store index in Selection
const int SCOPES_COUNT = 3 ;
const int SCOPES_COUNT = 3 ;
const int ITEMS_COUNT = 8 ; // Per scope
const int ITEMS_COUNT = 8 ; // Per scope
static ExampleSelection selections_data [ SCOPES_COUNT ] ;
static ExampleSelection selections_data [ SCOPES_COUNT ] ;
ExampleSelectionAdapter selection_adapter ; // Use default: Pass index to SetNextItemSelectionUserData(), store index in Selection
// Use ImGuiMultiSelectFlags_ScopeRect to not affect other selections in same window.
// Use ImGuiMultiSelectFlags_ScopeRect to not affect other selections in same window.
static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ScopeRect | ImGuiMultiSelectFlags_ClearOnEscape ; // | ImGuiMultiSelectFlags_ClearOnClickVoid;
static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ScopeRect | ImGuiMultiSelectFlags_ClearOnEscape ; // | ImGuiMultiSelectFlags_ClearOnClickVoid;
@ -3282,7 +3277,7 @@ static void ShowDemoWindowMultiSelect()
ImGui : : PushID ( selection_scope_n ) ;
ImGui : : PushID ( selection_scope_n ) ;
ExampleSelection * selection = & selections_data [ selection_scope_n ] ;
ExampleSelection * selection = & selections_data [ selection_scope_n ] ;
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( flags ) ;
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( flags ) ;
selection - > ApplyRequests ( ms_io , & selection_adapter , ITEMS_COUNT ) ;
selection - > ApplyRequests ( ms_io , ITEMS_COUNT ) ;
ImGui : : SeparatorText ( " Selection scope " ) ;
ImGui : : SeparatorText ( " Selection scope " ) ;
ImGui : : Text ( " Selection size: %d/%d " , selection - > GetSize ( ) , ITEMS_COUNT ) ;
ImGui : : Text ( " Selection size: %d/%d " , selection - > GetSize ( ) , ITEMS_COUNT ) ;
@ -3298,7 +3293,7 @@ static void ShowDemoWindowMultiSelect()
// Apply multi-select requests
// Apply multi-select requests
ms_io = ImGui : : EndMultiSelect ( ) ;
ms_io = ImGui : : EndMultiSelect ( ) ;
selection - > ApplyRequests ( ms_io , & selection_adapter , ITEMS_COUNT ) ;
selection - > ApplyRequests ( ms_io , ITEMS_COUNT ) ;
ImGui : : PopID ( ) ;
ImGui : : PopID ( ) ;
}
}
ImGui : : TreePop ( ) ;
ImGui : : TreePop ( ) ;
@ -3356,11 +3351,11 @@ static void ShowDemoWindowMultiSelect()
ImGui : : SameLine ( ) ; HelpMarker ( " Allow dragging an unselected item without altering selection. " ) ;
ImGui : : SameLine ( ) ; HelpMarker ( " Allow dragging an unselected item without altering selection. " ) ;
// Initialize default list with 1000 items.
// Initialize default list with 1000 items.
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
static ImVector < int > items ;
static ImVector < int > items ;
static int items_next_id = 0 ;
static int items_next_id = 0 ;
if ( items_next_id = = 0 ) { for ( int n = 0 ; n < 1000 ; n + + ) { items . push_back ( items_next_id + + ) ; } }
if ( items_next_id = = 0 ) { for ( int n = 0 ; n < 1000 ; n + + ) { items . push_back ( items_next_id + + ) ; } }
static ExampleSelection selection ;
static ExampleSelection selection ;
ExampleSelectionAdapter selection_adapter ; // Use default: Pass index to SetNextItemSelectionUserData(), store index in Selection
ImGui : : Text ( " Selection size: %d/%d " , selection . GetSize ( ) , items . Size ) ;
ImGui : : Text ( " Selection size: %d/%d " , selection . GetSize ( ) , items . Size ) ;
@ -3373,14 +3368,14 @@ static void ShowDemoWindowMultiSelect()
ImGui : : PushStyleVar ( ImGuiStyleVar_ItemSpacing , ImVec2 ( ImGui : : GetStyle ( ) . ItemSpacing . x , 0.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_ItemSpacing , ImVec2 ( ImGui : : GetStyle ( ) . ItemSpacing . x , 0.0f ) ) ;
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( flags ) ;
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( flags ) ;
selection . ApplyRequests ( ms_io , & selection_adapter , items . Size ) ;
selection . ApplyRequests ( ms_io , items . Size ) ;
// FIXME-MULTISELECT: Shortcut(). Hard to demo this? May be helpful to send a helper/optional "delete" signal.
// FIXME-MULTISELECT: Shortcut(). Hard to demo this? May be helpful to send a helper/optional "delete" signal.
// FIXME-MULTISELECT: may turn into 'ms_io->RequestDelete' -> need HasSelection passed.
// FIXME-MULTISELECT: may turn into 'ms_io->RequestDelete' -> need HasSelection passed.
const bool want_delete = selection . QueueDeletion | | ( ( selection . GetSize ( ) > 0 ) & & ImGui : : IsWindowFocused ( ) & & ImGui : : IsKeyPressed ( ImGuiKey_Delete ) ) ;
const bool want_delete = selection . QueueDeletion | | ( ( selection . GetSize ( ) > 0 ) & & ImGui : : IsWindowFocused ( ) & & ImGui : : IsKeyPressed ( ImGuiKey_Delete ) ) ;
int item_curr_idx_to_focus = - 1 ;
int item_curr_idx_to_focus = - 1 ;
if ( want_delete )
if ( want_delete )
item_curr_idx_to_focus = selection . ApplyDeletionPreLoop ( ms_io , & selection_adapter , items ) ;
item_curr_idx_to_focus = selection . ApplyDeletionPreLoop ( ms_io , items . Size ) ;
if ( show_in_table )
if ( show_in_table )
{
{
@ -3519,9 +3514,9 @@ static void ShowDemoWindowMultiSelect()
// Apply multi-select requests
// Apply multi-select requests
ms_io = ImGui : : EndMultiSelect ( ) ;
ms_io = ImGui : : EndMultiSelect ( ) ;
selection . ApplyRequests ( ms_io , & selection_adapter , items . Size ) ;
selection . ApplyRequests ( ms_io , items . Size ) ;
if ( want_delete )
if ( want_delete )
selection . ApplyDeletionPostLoop ( ms_io , & selection_adapter , items , item_curr_idx_to_focus ) ;
selection . ApplyDeletionPostLoop ( ms_io , items , item_curr_idx_to_focus ) ;
if ( widget_type = = WidgetType_TreeNode )
if ( widget_type = = WidgetType_TreeNode )
ImGui : : PopStyleVar ( ) ;
ImGui : : PopStyleVar ( ) ;
@ -9521,10 +9516,10 @@ void ShowExampleAppDocuments(bool* p_open)
struct ExampleAsset
struct ExampleAsset
{
{
int ID ;
ImGuiID ID ;
int Type ;
int Type ;
ExampleAsset ( int id , int type ) { ID = id ; Type = type ; }
ExampleAsset ( ImGuiID id , int type ) { ID = id ; Type = type ; }
static const ImGuiTableSortSpecs * s_current_sort_specs ;
static const ImGuiTableSortSpecs * s_current_sort_specs ;
@ -9546,7 +9541,7 @@ struct ExampleAsset
const ImGuiTableColumnSortSpecs * sort_spec = & s_current_sort_specs - > Specs [ n ] ;
const ImGuiTableColumnSortSpecs * sort_spec = & s_current_sort_specs - > Specs [ n ] ;
int delta = 0 ;
int delta = 0 ;
if ( sort_spec - > ColumnIndex = = 0 )
if ( sort_spec - > ColumnIndex = = 0 )
delta = ( a - > ID - b - > ID ) ;
delta = ( ( int ) a - > ID - ( int ) b - > ID ) ;
else if ( sort_spec - > ColumnIndex = = 1 )
else if ( sort_spec - > ColumnIndex = = 1 )
delta = ( a - > Type - b - > Type ) ;
delta = ( a - > Type - b - > Type ) ;
if ( delta > 0 )
if ( delta > 0 )
@ -9554,7 +9549,7 @@ struct ExampleAsset
if ( delta < 0 )
if ( delta < 0 )
return ( sort_spec - > SortDirection = = ImGuiSortDirection_Ascending ) ? - 1 : + 1 ;
return ( sort_spec - > SortDirection = = ImGuiSortDirection_Ascending ) ? - 1 : + 1 ;
}
}
return ( a - > ID - b - > ID ) ;
return ( ( int ) a - > ID - ( int ) b - > ID ) ;
}
}
} ;
} ;
const ImGuiTableSortSpecs * ExampleAsset : : s_current_sort_specs = NULL ;
const ImGuiTableSortSpecs * ExampleAsset : : s_current_sort_specs = NULL ;
@ -9572,7 +9567,7 @@ struct ExampleAssetsBrowser
// State
// State
ImVector < ExampleAsset > Items ;
ImVector < ExampleAsset > Items ;
ExampleSelection Selection ;
ExampleSelection Selection ;
int NextItemId = 0 ;
ImGuiID NextItemId = 0 ;
bool SortDirty = false ;
bool SortDirty = false ;
float ZoomWheelAccum = 0.0f ;
float ZoomWheelAccum = 0.0f ;
@ -9701,12 +9696,12 @@ struct ExampleAssetsBrowser
ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid ;
ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid ;
if ( AllowDragUnselected )
if ( AllowDragUnselected )
ms_flags | = ImGuiMultiSelectFlags_SelectOnClickRelease ; // To allow dragging an unselected item without altering selection.
ms_flags | = ImGuiMultiSelectFlags_SelectOnClickRelease ; // To allow dragging an unselected item without altering selection.
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( ms_flags ) ;
ImGuiMultiSelectIO * ms_io = ImGui : : BeginMultiSelect ( ms_flags ) ;
ExampleSelectionAdapter selection_adapter ;
selection_adapter . Data = this ;
// Use custom selection adapter: store ID in selection (recommended)
selection_adapter . IndexToStorage = [ ] ( ExampleSelectionAdapter * self_ , int idx ) { ExampleAssetsBrowser * self = ( ExampleAssetsBrowser * ) self_ - > Data ; return ( ImGuiID ) self - > Items [ idx ] . ID ; } ;
Selection . AdapterData = this ;
Selection . ApplyRequests ( ms_io , & selection_adapter , Items . Size ) ;
Selection . AdapterIndexToStorageId = [ ] ( ExampleSelection * self_ , int idx ) { ExampleAssetsBrowser * self = ( ExampleAssetsBrowser * ) self_ - > AdapterData ; return self - > Items [ idx ] . ID ; } ;
Selection . ApplyRequests ( ms_io , Items . Size ) ;
// Altering ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()...
// Altering ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()...
// But it is necessary for two reasons:
// But it is necessary for two reasons:
@ -9735,7 +9730,7 @@ struct ExampleAssetsBrowser
for ( int item_idx = item_min_idx_for_current_line ; item_idx < item_max_idx_for_current_line ; + + item_idx )
for ( int item_idx = item_min_idx_for_current_line ; item_idx < item_max_idx_for_current_line ; + + item_idx )
{
{
ExampleAsset * item_data = & Items [ item_idx ] ;
ExampleAsset * item_data = & Items [ item_idx ] ;
ImGui : : PushID ( item_data - > ID ) ;
ImGui : : PushID ( ( int ) item_data - > ID ) ;
// Position item
// Position item
ImVec2 pos = ImVec2 ( start_pos . x + ( item_idx % column_count ) * ( item_size . x + item_spacing ) , start_pos . y + ( line_idx * line_height ) ) ;
ImVec2 pos = ImVec2 ( start_pos . x + ( item_idx % column_count ) * ( item_size . x + item_spacing ) , start_pos . y + ( line_idx * line_height ) ) ;
@ -9800,7 +9795,7 @@ struct ExampleAssetsBrowser
ImGui : : PopStyleVar ( ) ; // ImGuiStyleVar_ItemSpacing
ImGui : : PopStyleVar ( ) ; // ImGuiStyleVar_ItemSpacing
ms_io = ImGui : : EndMultiSelect ( ) ;
ms_io = ImGui : : EndMultiSelect ( ) ;
Selection . ApplyRequests ( ms_io , & selection_adapter , Items . Size ) ;
Selection . ApplyRequests ( ms_io , Items . Size ) ;
// FIXME-MULTISELECT: Find a way to expose this in public API. This currently requires "imgui_internal.h"
// FIXME-MULTISELECT: Find a way to expose this in public API. This currently requires "imgui_internal.h"
//ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);
//ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);