diff --git a/imgui.h b/imgui.h index 1361e902b..0e7a63ce6 100644 --- a/imgui.h +++ b/imgui.h @@ -673,7 +673,7 @@ namespace ImGui // Multi-selection system for Selectable() and TreeNode() functions. // - This enables standard multi-selection/range-selection idioms (CTRL+Mouse/Keyboard, SHIFT+Mouse/Keyboard, etc.) in a way that also allow a clipper to be used. // - ImGuiSelectionUserData is often used to store your item index. - // - Read comments near ImGuiMultiSelectIO for instructions/details and see 'Demo->Widgets->Selection State' for demo. + // - Read comments near ImGuiMultiSelectIO for instructions/details and see 'Demo->Widgets->Selection State & Multi-Select' for demo. IMGUI_API ImGuiMultiSelectIO* BeginMultiSelect(ImGuiMultiSelectFlags flags); IMGUI_API ImGuiMultiSelectIO* EndMultiSelect(); IMGUI_API void SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data); @@ -2726,46 +2726,24 @@ struct ImColor #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. -// Flags for BeginMultiSelect(). -// (we provide 'ImGuiMultiSelectFlags_SingleSelect' for consistency and flexiblity to allow a single-selection to use same code/logic, but it essentially disable the biggest purpose of BeginMultiSelect(). -// If you use 'ImGuiMultiSelectFlags_SingleSelect' you can handle single-selection in a simpler way by just calling Selectable()/TreeNode() and reacting on clicks). -enum ImGuiMultiSelectFlags_ -{ - ImGuiMultiSelectFlags_None = 0, - ImGuiMultiSelectFlags_SingleSelect = 1 << 0, // Disable selecting more than one item. This is available to allow single-selection code to use same code/logic is desired, but may not be very useful. - ImGuiMultiSelectFlags_NoSelectAll = 1 << 1, // Disable CTRL+A shortcut to set RequestSelectAll - ImGuiMultiSelectFlags_BoxSelect = 1 << 2, // Enable box-selection. Box-selection works better with little bit of spacing between items hit-box in order to be able to aim at empty space. - ImGuiMultiSelectFlags_NoBoxSelectScroll = 1 << 3, // Disable scrolling when box-selecting near edges of scope. - ImGuiMultiSelectFlags_ClearOnEscape = 1 << 4, // Clear selection when pressing Escape while scope is focused. - ImGuiMultiSelectFlags_ClearOnClickVoid = 1 << 5, // Clear selection when clicking on empty location within scope. - ImGuiMultiSelectFlags_ScopeWindow = 1 << 6, // Scope for _ClearOnClickVoid and _BoxSelect is whole window (Default). Use if (use if BeginMultiSelect() covers a whole window. - ImGuiMultiSelectFlags_ScopeRect = 1 << 7, // Scope for _ClearOnClickVoid and _BoxSelect is rectangle covering submitted items. Use if multiple BeginMultiSelect() are used in the same host window. - ImGuiMultiSelectFlags_SelectOnClick = 1 << 8, // Apply selection on mouse down when clicking on unselected item. (Default) - ImGuiMultiSelectFlags_SelectOnClickRelease = 1 << 9, // Apply selection on mouse release when clicking an unselected item. Allow dragging an unselected item without altering selection. -}; - // Multi-selection system -// - Refer to 'Demo->Widgets->Selection State' for references using this. +// - Refer to 'Demo->Widgets->Selection State & Multi-Select' for references using this. // - This system implements standard multi-selection idioms (CTRL+Mouse/Keyboard, SHIFT+Mouse/Keyboard, etc) -// and supports a clipper being used. Handling this manually and correctly i tricky, this is why we provide +// and supports a clipper being used. Handling this manually and correctly is tricky, this is why we provide // the functionality. If you don't need SHIFT+Mouse/Keyboard range-select + clipping, you can implement a // simple form of multi-selection yourself, by reacting to click/presses on Selectable() items. // - TreeNode() and Selectable() are supported but custom widgets may use it as well. // - In the spirit of Dear ImGui design, your code owns actual selection data. // This is designed to allow all kinds of selection storage you may use in your application: -// e.g. set/map/hash (store only selected items), instructive selection (store a bool inside each object), -// external array (store an array in your view data, next to your objects) etc. +// e.g. set/map/hash (store selected items), instructive selection (store a bool inside each object), etc. // - The work involved to deal with multi-selection differs whether you want to only submit visible items and // clip others, or submit all items regardless of their visibility. Clipping items is more efficient and will // allow you to deal with large lists (1k~100k items). See "Usage flow" section below for details. // If you are not sure, always start without clipping! You can work your way to the optimized version afterwards. -// About ImGuiSelectionBasicStorage: -// - This is an optional helper to store a selection state and apply selection requests. -// - It is used by our demos and provided as a convenience if you want to quickly implement multi-selection. // About ImGuiSelectionUserData: -// - This is your application-defined identifier in a selection set: -// - For each item is it submitted by your call to SetNextItemSelectionUserData(). -// - In return we store them into RangeSrcItem/RangeFirstItem/RangeLastItem and other fields in ImGuiMultiSelectIO. +// - This can store an application-defined identifier (e.g. index or pointer). +// - For each item is it submitted by your call to SetNextItemSelectionUserData(). +// - In return we store them into RangeSrcItem/RangeFirstItem/RangeLastItem and other fields in ImGuiMultiSelectIO. // - Most applications will store an object INDEX, hence the chosen name and type. // Storing an integer index is the easiest thing to do, as RequestSetRange requests will give you two end-points // and you will need to iterate/interpolate between them to honor range selection. @@ -2778,15 +2756,33 @@ enum ImGuiMultiSelectFlags_ // Usage flow: // BEGIN - (1) Call BeginMultiSelect() and retrieve the ImGuiMultiSelectIO* result. // - (2) [If using clipper] Honor request list (Clear/SelectAll/SetRange requests) by updating your selection data. Same code as Step 6. -// - (3) [If using clipper] You need to make sure RangeSrcItem is always submitted. Calculate its index and pass to clipper.IncludeIndex(). If already using indices in ImGuiSelectionUserData, it is as simple as clipper.IncludeIndex((int)ms_io->RangeSrcItem); +// - (3) [If using clipper] You need to make sure RangeSrcItem is always submitted. Calculate its index and pass to clipper.IncludeItemByIndex(). If storing indices in ImGuiSelectionUserData, a simple clipper.IncludeItemByIndex(ms_io->RangeSrcItem) call will work. // LOOP - (4) Submit your items with SetNextItemSelectionUserData() + Selectable()/TreeNode() calls. // END - (5) Call EndMultiSelect() and retrieve the ImGuiMultiSelectIO* result. // - (6) Honor request list (Clear/SelectAll/SetRange requests) by updating your selection data. Same code as Step 2. -// If you submit all items (no clipper), Step 2 and 3 and will be handled by Selectable()/TreeNode on a per-item basis. -// However it is perfectly fine to honor all steps even if you don't use a clipper. +// If you submit all items (no clipper), Step 2 and 3 are optional and will be handled by each item themselves. It is perfectly fine if you honor those steps without a clipper. +// About ImGuiSelectionBasicStorage: +// - This is an optional helper to store a selection state and apply selection requests. +// - It is used by our demos and provided as a convenience if you want to quickly implement multi-selection. // Advanced: // - Deletion: If you need to handle items deletion: more work if needed for post-deletion focus and scrolling to be correct. -// Refer to 'Demo->Widgets->Selection State' for demos supporting deletion. +// Refer to 'Demo->Widgets->Selection State & Multi-Select' for demos supporting deletion. + +// Flags for BeginMultiSelect(). +enum ImGuiMultiSelectFlags_ +{ + ImGuiMultiSelectFlags_None = 0, + ImGuiMultiSelectFlags_SingleSelect = 1 << 0, // Disable selecting more than one item. This is available to allow single-selection code to share same code/logic if desired. It essentially disables the main purpose of BeginMultiSelect() tho! + ImGuiMultiSelectFlags_NoSelectAll = 1 << 1, // Disable CTRL+A shortcut sending a SelectAll request. + ImGuiMultiSelectFlags_BoxSelect = 1 << 2, // Enable box-selection. Box-selection works better with little bit of spacing between items hit-box in order to be able to aim at empty space. + ImGuiMultiSelectFlags_NoBoxSelectScroll = 1 << 3, // Disable scrolling when box-selecting near edges of scope. + ImGuiMultiSelectFlags_ClearOnEscape = 1 << 4, // Clear selection when pressing Escape while scope is focused. + ImGuiMultiSelectFlags_ClearOnClickVoid = 1 << 5, // Clear selection when clicking on empty location within scope. + ImGuiMultiSelectFlags_ScopeWindow = 1 << 6, // Scope for _ClearOnClickVoid and _BoxSelect is whole window (Default). Use if BeginMultiSelect() covers a whole window. + ImGuiMultiSelectFlags_ScopeRect = 1 << 7, // Scope for _ClearOnClickVoid and _BoxSelect is rectangle covering submitted items. Use if multiple BeginMultiSelect() are used in the same host window. + ImGuiMultiSelectFlags_SelectOnClick = 1 << 8, // Apply selection on mouse down when clicking on unselected item. (Default) + ImGuiMultiSelectFlags_SelectOnClickRelease = 1 << 9, // Apply selection on mouse release when clicking an unselected item. Allow dragging an unselected item without altering selection. +}; enum ImGuiSelectionRequestType { @@ -2814,58 +2810,70 @@ struct ImGuiSelectionRequest struct ImGuiMultiSelectIO { //------------------------------------------// BeginMultiSelect / EndMultiSelect - ImVector Requests; // ms:w, app:r / ms:w app:r // Requests + ImVector Requests; // ms:w, app:r / ms:w app:r // Requests to apply to your selection data. ImGuiSelectionUserData RangeSrcItem; // ms:w app:r / // (If using clipper) Begin: Source item (generally the first selected item when multi-selecting, which is used as a reference point) must never be clipped! ImGuiSelectionUserData NavIdItem; // ms:w, app:r / // (If using deletion) Last known SetNextItemSelectionUserData() value for NavId (if part of submitted items). bool NavIdSelected; // ms:w, app:r / app:r // (If using deletion) Last known selection state for NavId (if part of submitted items). bool RangeSrcReset; // 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! +// Optional helper struct 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. // 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, std::set, 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. +// - 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(*) / 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. +// - how you want to identify items in multi-selection API? Indices(*) or Custom Ids or Pointers -> Indices is 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 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) +// - 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 casted 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 WILL PROBABLY PREFER TO GET RID OF THE UNNECESSARY 'AdapterIndexToStorageId()' INDIRECTION LOGIC. +// When your application settles on a choice, you may want to get rid of this indirection layer and do your own thing. +// Minimum pseudo-code example using this helper: +// { +// 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.ApplyRequests(ms_io, items.Size); +// 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, items.Size); +// } // 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. +// but because we always use indices in SetNextItemSelectionUserData() in the demo, we omit that indirection for clarity. struct ImGuiSelectionBasicStorage { - ImGuiStorage Storage; // [Internal] Selection set. Think of this as similar to e.g. std::set - int Size; // 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; + // Members + ImGuiStorage Storage; // [Internal] Selection set. Think of this as similar to e.g. std::set + int Size; // Number of selected items (== number of 1 in the Storage, maintained by this class). + void* AdapterData; // Adapter to convert item index to item identifier // e.g. selection.AdapterData = (void*)my_items; ImGuiID (*AdapterIndexToStorageId)(ImGuiSelectionBasicStorage* self, int idx); // e.g. selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return ((MyItems**)self->AdapterData)[idx]->ID; }; - // Selection storage - ImGuiSelectionBasicStorage() { Clear(); AdapterData = NULL; AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage*, int idx) { return (ImGuiID)idx; }; } - void Clear() { Storage.Data.resize(0); Size = 0; } - void Swap(ImGuiSelectionBasicStorage& r){ Storage.Data.swap(r.Storage.Data); } - bool Contains(ImGuiID key) const { return Storage.GetInt(key, 0) != 0; } - void AddItem(ImGuiID key) { int* p_int = Storage.GetIntRef(key, 0); if (*p_int != 0) return; *p_int = 1; Size++; } - void RemoveItem(ImGuiID key) { int* p_int = Storage.GetIntRef(key, 0); if (*p_int == 0) return; *p_int = 0; Size--; } - void UpdateItem(ImGuiID key, bool v) { if (v) { AddItem(key); } else { RemoveItem(key); } } - int GetSize() const { return Size; } + // Methods: selection storage + ImGuiSelectionBasicStorage() { Clear(); AdapterData = NULL; AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage*, int idx) { return (ImGuiID)idx; }; } + void Clear() { Storage.Data.resize(0); Size = 0; } + void Swap(ImGuiSelectionBasicStorage& r) { Storage.Data.swap(r.Storage.Data); } + bool Contains(ImGuiID key) const { return Storage.GetInt(key, 0) != 0; } + void AddItem(ImGuiID key) { int* p_int = Storage.GetIntRef(key, 0); if (*p_int != 0) return; *p_int = 1; Size++; } + void RemoveItem(ImGuiID key) { int* p_int = Storage.GetIntRef(key, 0); if (*p_int == 0) return; *p_int = 0; Size--; } + void UpdateItem(ImGuiID key, bool v) { if (v) { AddItem(key); } else { RemoveItem(key); } } + int GetSize() const { return Size; } - // Request handling (apply requests coming from BeginMultiSelect() and EndMultiSelect() functions) + // Methods: apply selection requests (that are coming from BeginMultiSelect() and EndMultiSelect() functions) IMGUI_API void ApplyRequests(ImGuiMultiSelectIO* ms_io, int items_count); }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 291d50e8c..58cc4ee57 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2783,7 +2783,7 @@ struct ExampleSelectionStorageWithDeletion : ImGuiSelectionBasicStorage // - 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. // - 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 scroll offset. int ApplyDeletionPreLoop(ImGuiMultiSelectIO* ms_io, int items_count) { QueueDeletion = false; @@ -2890,7 +2890,7 @@ struct ExampleDualListBox } void Show() { - ImGui::Checkbox("Sorted", &OptKeepSorted); + //ImGui::Checkbox("Sorted", &OptKeepSorted); if (ImGui::BeginTable("split", 3, ImGuiTableFlags_None)) { ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Left side @@ -2964,13 +2964,15 @@ struct ExampleDualListBox if (request_move_selected != -1) MoveSelected(request_move_selected, request_move_selected ^ 1); - // FIXME-MULTISELECT: action from outside + // FIXME-MULTISELECT: Support action from outside + /* if (OptKeepSorted == false) { ImGui::NewLine(); if (ImGui::ArrowButton("MoveUp", ImGuiDir_Up)) {} if (ImGui::ArrowButton("MoveDown", ImGuiDir_Down)) {} } + */ ImGui::EndTable(); } @@ -3025,20 +3027,19 @@ static void ShowDemoWindowMultiSelect() IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select"); if (ImGui::TreeNode("Multi-Select")) { - // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection - static ImGuiSelectionBasicStorage selection; - - ImGui::Text("Tips: Use 'Debug Log->Selection' to see selection requests as they happen."); - ImGui::Text("Supported features:"); ImGui::BulletText("Keyboard navigation (arrows, page up/down, home/end, space)."); ImGui::BulletText("Ctrl modifier to preserve and toggle selection."); ImGui::BulletText("Shift modifier for range selection."); ImGui::BulletText("CTRL+A to select all."); + ImGui::Text("Tip: Use 'Debug Log->Selection' to see selection requests as they happen."); + + // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection + const int ITEMS_COUNT = 50; + static ImGuiSelectionBasicStorage selection; + ImGui::Text("Selection: %d/%d", selection.GetSize(), ITEMS_COUNT); // The BeginListBox() has no actual purpose for selection logic (other that offering a scrolling region). - const int ITEMS_COUNT = 50; - ImGui::Text("Selection: %d/%d", selection.GetSize(), ITEMS_COUNT); if (ImGui::BeginListBox("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20))) { ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape; @@ -3124,8 +3125,6 @@ static void ShowDemoWindowMultiSelect() ImGui::Text("Adding features:"); ImGui::BulletText("Dynamic list with Delete key support."); ImGui::Text("Selection size: %d/%d", selection.GetSize(), items.Size); - //if (ImGui::IsItemHovered() && selection.GetSize() > 0) - // selection.DebugTooltip(); // Initialize default list with 50 items + button to add/remove items. static int items_next_id = 0; @@ -3146,10 +3145,9 @@ static void ShowDemoWindowMultiSelect() ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags); 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: may turn into 'ms_io->RequestDelete' -> need HasSelection passed. + // FIXME-MULTISELECT: Shortcut(). Hard to demo this? May be helpful to turn into 'ms_io->RequestDelete' signal -> need HasSelection passed. // FIXME-MULTISELECT: If pressing Delete + another key we have ambiguous behavior. - const bool want_delete = selection.QueueDeletion || ((selection.GetSize() > 0) && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_Delete)); + const bool want_delete = selection.QueueDeletion || ((selection.Size > 0) && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_Delete)); int item_curr_idx_to_focus = -1; if (want_delete) item_curr_idx_to_focus = selection.ApplyDeletionPreLoop(ms_io, items.Size); @@ -3309,9 +3307,8 @@ static void ShowDemoWindowMultiSelect() ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags); 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: may turn into 'ms_io->RequestDelete' -> need HasSelection passed. - const bool want_delete = selection.QueueDeletion || ((selection.GetSize() > 0) && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_Delete)); + // FIXME-MULTISELECT: Shortcut(). Hard to demo this? May be helpful to turn into 'ms_io->RequestDelete' signal -> need HasSelection passed. + const bool want_delete = selection.QueueDeletion || ((selection.Size > 0) && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_Delete)); int item_curr_idx_to_focus = -1; if (want_delete) item_curr_idx_to_focus = selection.ApplyDeletionPreLoop(ms_io, items.Size); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 11ae828c9..e0b32ac86 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6858,7 +6858,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // Render if (hovered || selected) { - // FIXME-MULTISELECT, FIXME-STYLE: Color for 'selected' elements? ImGuiCol_HeaderSelected + // FIXME-MULTISELECT: Styling: Color for 'selected' elements? ImGuiCol_HeaderSelected ImU32 col; if (selected && !hovered) col = GetColorU32(ImLerp(GetStyleColorVec4(ImGuiCol_Header), GetStyleColorVec4(ImGuiCol_HeaderHovered), 0.5f)); @@ -7558,7 +7558,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) if (is_shift && !is_singleselect) { // Shift+Arrow always select - // Ctrl+Shift+Arrow copy source selection state (alrady stored by BeginMultiSelect() in RangeSelected) + // Ctrl+Shift+Arrow copy source selection state (already stored by BeginMultiSelect() in storage->RangeSelected) //IM_ASSERT(storage->HasRangeSrc && storage->HasRangeValue); if (storage->RangeSrcItem == ImGuiSelectionUserData_Invalid) storage->RangeSrcItem = item_data;