From d439f590ab54e1a60ea62e0dfb55f5e70ea6f2e5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 21 Dec 2023 15:12:17 +0100 Subject: [PATCH] MultiSelect: Comments + Assets Browser : Tweak colors. --- imgui.h | 132 ++++++++++++++++++++-------------------------- imgui_demo.cpp | 67 ++++++++++++----------- imgui_widgets.cpp | 6 ++- 3 files changed, 97 insertions(+), 108 deletions(-) diff --git a/imgui.h b/imgui.h index c4b8afa69..be79eb665 100644 --- a/imgui.h +++ b/imgui.h @@ -180,6 +180,7 @@ struct ImGuiOnceUponAFrame; // Helper for running a block of code not mo struct ImGuiPayload; // User data payload for drag and drop operations struct ImGuiPlatformImeData; // Platform IME data for io.PlatformSetImeDataFn() function. struct ImGuiSelectionBasicStorage; // Helper struct to store multi-selection state + apply multi-selection requests. +struct ImGuiSelectionRequest; // A selection request (stored in ImGuiMultiSelectIO) struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use) struct ImGuiStorage; // Helper for key->value storage (container sorted by key) struct ImGuiStoragePair; // Helper for key->value storage (pair) @@ -268,7 +269,7 @@ typedef ImWchar16 ImWchar; // Multi-Selection item index or identifier when using BeginMultiSelect() // - Used by SetNextItemSelectionUserData() + and inside ImGuiMultiSelectIO structure. -// - Most users are likely to use this store an item INDEX but this may be used to store a POINTER as well. Read comments near ImGuiMultiSelectIO for details. +// - Most users are likely to use this store an item INDEX but this may be used to store a POINTER/ID as well. Read comments near ImGuiMultiSelectIO for details. typedef ImS64 ImGuiSelectionUserData; // Callback and functions types @@ -2727,48 +2728,45 @@ 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. // Multi-selection system -// - Refer to 'Demo->Widgets->Selection State & Multi-Select' for references using this. +// Also read: https://github.com/ocornut/imgui/wiki/Multi-Select +// - Refer to 'Demo->Widgets->Selection State & Multi-Select' for demos 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 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. +// with support for clipper (skipping non-visible items), box-select and many other details. // - 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 selected items), instructive selection (store a bool inside each object), etc. +// This is designed to allow all kinds of selection storage you may use in your application e.g. set/map/hash. // - 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. +// 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: +// 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.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 are optional and will be handled by each item themselves. It is fine to always honor those steps. // About ImGuiSelectionUserData: -// - This can store an application-defined identifier (e.g. index or pointer). // - For each item is it submitted by your call to SetNextItemSelectionUserData(). +// - This can store an application-defined identifier (e.g. index or pointer). // - 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. -// - However it is perfectly possible to store a POINTER inside this value! The multi-selection system never assume -// that you identify items by indices. It never attempt to iterate/interpolate between 2 ImGuiSelectionUserData values. -// - As most users will want to cast this to integer, for convenience and to reduce confusion we use ImS64 instead -// of void*, being syntactically easier to downcast. But feel free to reinterpret_cast a pointer into this. -// - You may store another type as long as you can interpolate between two values. +// Storing an integer index is the easiest thing to do, as SetRange requests will give you two end-points +// and you will need to iterate/interpolate between them to update your selection. +// - However it is perfectly possible to store a POINTER or another IDENTIFIER inside this value! +// Our system never assume that you identify items by indices, it never attempts to interpolate between two values. +// - As most users will want to store an index, for convenience and to reduce confusion we use ImS64 instead of void*, +// being syntactically easier to downcast. Feel free to reinterpret_cast and store a pointer inside. // - If you need to wrap this API for another language/framework, feel free to expose this as 'int' if simpler. -// 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.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 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 & Multi-Select' for demos supporting deletion. -// Flags for BeginMultiSelect(). +// Flags for BeginMultiSelect() enum ImGuiMultiSelectFlags_ { ImGuiMultiSelectFlags_None = 0, @@ -2785,29 +2783,11 @@ enum ImGuiMultiSelectFlags_ ImGuiMultiSelectFlags_SelectOnClickRelease = 1 << 10, // Apply selection on mouse release when clicking an unselected item. Allow dragging an unselected item without altering selection. }; -enum ImGuiSelectionRequestType -{ - ImGuiSelectionRequestType_None = 0, - ImGuiSelectionRequestType_Clear, // Request app to clear selection. - ImGuiSelectionRequestType_SelectAll, // Request app to select all. - ImGuiSelectionRequestType_SetRange, // Request app to select/unselect [RangeFirstItem..RangeLastItem] items based on 'bool RangeSelected'. Only EndMultiSelect() request this, app code can read after BeginMultiSelect() and it will always be false. -}; - -struct ImGuiSelectionRequest -{ - //------------------------------------------// BeginMultiSelect / EndMultiSelect - ImGuiSelectionRequestType Type; // ms:w, app:r / ms:w, app:r // Request type. You'll most often receive 1 Clear + 1 SetRange with a single-item range. - bool RangeSelected; // / ms:w, app:r // Parameter for SetRange request (true = select range, false = unselect range) - ImGuiSelectionUserData RangeFirstItem; // / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from top to bottom) - ImGuiSelectionUserData RangeLastItem; // / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from bottom to top) -}; - // Main IO structure returned by BeginMultiSelect()/EndMultiSelect(). -// This mainly contains a list of selection requests. Read the large comments block above for details. +// This mainly contains a list of selection requests. // - Use 'Demo->Tools->Debug Log->Selection' to see requests as they happen. -// - Some fields are only useful if your list is dynamic and allows deletion (handling deletion and getting "post-deletion" state right is shown in the demo) -// - Below: who reads/writes each fields? 'r'=read, 'w'=write, 'ms'=multi-select code, 'app'=application/user code, 'BEGIN'=BeginMultiSelect() and after, 'END'=EndMultiSelect() and after. -// - Lifetime: don't hold on ImGuiMultiSelectIO* pointers over multiple frames or past any subsequent call to BeginMultiSelect() or EndMultiSelect(). +// - Some fields are only useful if your list is dynamic and allows deletion (getting post-deletion focus/state right is shown in the demo) +// - Below: who reads/writes each fields? 'r'=read, 'w'=write, 'ms'=multi-select code, 'app'=application/user code. struct ImGuiMultiSelectIO { //------------------------------------------// BeginMultiSelect / EndMultiSelect @@ -2818,49 +2798,49 @@ struct ImGuiMultiSelectIO bool RangeSrcReset; // app:w / ms:r // (If using deletion) Set before EndMultiSelect() to reset ResetSrcItem (e.g. if deleted selection). }; -// Optional helper struct to store multi-selection state + apply multi-selection requests. +// Selection request type +enum ImGuiSelectionRequestType +{ + ImGuiSelectionRequestType_None = 0, + ImGuiSelectionRequestType_Clear, // Request app to clear selection. + ImGuiSelectionRequestType_SelectAll, // Request app to select all. + ImGuiSelectionRequestType_SetRange, // Request app to select/unselect [RangeFirstItem..RangeLastItem] items based on 'bool RangeSelected'. Only EndMultiSelect() request this, app code can read after BeginMultiSelect() and it will always be false. +}; + +// Selection request item +struct ImGuiSelectionRequest +{ + //------------------------------------------// BeginMultiSelect / EndMultiSelect + ImGuiSelectionRequestType Type; // ms:w, app:r / ms:w, app:r // Request type. You'll most often receive 1 Clear + 1 SetRange with a single-item range. + bool RangeSelected; // / ms:w, app:r // Parameter for SetRange request (true = select range, false = unselect range) + ImGuiSelectionUserData RangeFirstItem; // / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from top to bottom) + ImGuiSelectionUserData RangeLastItem; // / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from bottom to top) +}; + +// 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. -// To store a multi-selection, in your real application you could: +// To store a multi-selection, in your 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 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 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) +// - so this helper can be used regardless of your object storage/types, and without using templates or virtual functions. +// - in some cases we read an ID from some custom item data structure (similar to what you would do in your codebase) +// - in some cases we use Index as custom identifier (default implementation returns Index cast as Identifier): only OK for a never changing item list. // 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. -// 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 indirection for clarity. +// See https://github.com/ocornut/imgui/wiki/Multi-Select for minimum pseudo-code example using this helper. +// (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 indirection for clarity.) struct ImGuiSelectionBasicStorage { // 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). + int Size; // Number of selected items (== number of 1 in the Storage), maintained by this helper. 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; }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b84a0ca9f..0df16adb8 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2977,14 +2977,16 @@ struct ExampleDualListBox } }; - +// Multi-selection demos +// Also read: https://github.com/ocornut/imgui/wiki/Multi-Select static void ShowDemoWindowMultiSelect() { IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select"); if (ImGui::TreeNode("Selection State & Multi-Select")) { - HelpMarker("Selections can be built under Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data."); + HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data."); + // Without any fancy API: manage single-selection yourself. IMGUI_DEMO_MARKER("Widgets/Selection State/Single-Select"); if (ImGui::TreeNode("Single-Select")) { @@ -3020,8 +3022,9 @@ static void ShowDemoWindowMultiSelect() ImGui::TreePop(); } - // Demonstrate holding/updating multi-selection data using the BeginMultiSelect/EndMultiSelect API. + // Demonstrate handling proper multi-selection using the BeginMultiSelect/EndMultiSelect API. // SHIFT+Click w/ CTRL and other standard features are supported. + // We use the ImGuiSelectionBasicStorage helper which you may freely reimplement. IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select"); if (ImGui::TreeNode("Multi-Select")) { @@ -3105,8 +3108,7 @@ static void ShowDemoWindowMultiSelect() ImGui::TreePop(); } - // Demonstrate holding/updating multi-selection data and using the BeginMultiSelect/EndMultiSelect API + support dynamic item list and deletion. - // SHIFT+Click w/ CTRL and other standard features are supported. + // Demonstrate dynamic item list + deletion support using the BeginMultiSelect/EndMultiSelect API. // In order to support Deletion without any glitches you need to: // - (1) If items are submitted in their own scrolling area, submit contents size SetNextWindowContentSize() ahead of time to prevent one-frame readjustment of scrolling. // - (2) Items needs to have persistent ID Stack identifier = ID needs to not depends on their index. PushID(index) = KO. PushID(item_id) = OK. This is in order to focus items reliably after a selection. @@ -3263,29 +3265,33 @@ static void ShowDemoWindowMultiSelect() static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect; static WidgetType widget_type = WidgetType_Selectable; - if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; } - ImGui::SameLine(); - if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; } - ImGui::Checkbox("Enable clipper", &use_clipper); - ImGui::Checkbox("Enable deletion", &use_deletion); - ImGui::Checkbox("Enable drag & drop", &use_drag_drop); - ImGui::Checkbox("Show in a table", &show_in_table); - ImGui::Checkbox("Show color button", &show_color_button); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SingleSelect", &flags, ImGuiMultiSelectFlags_SingleSelect); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect", &flags, ImGuiMultiSelectFlags_BoxSelect); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelectNoScroll", &flags, ImGuiMultiSelectFlags_BoxSelectNoScroll); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid); - if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow)) - flags &= ~ImGuiMultiSelectFlags_ScopeRect; - if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect)) - flags &= ~ImGuiMultiSelectFlags_ScopeWindow; - if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClick", &flags, ImGuiMultiSelectFlags_SelectOnClick) && (flags & ImGuiMultiSelectFlags_SelectOnClick)) - flags &= ~ImGuiMultiSelectFlags_SelectOnClickRelease; - if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, ImGuiMultiSelectFlags_SelectOnClickRelease) && (flags & ImGuiMultiSelectFlags_SelectOnClickRelease)) - flags &= ~ImGuiMultiSelectFlags_SelectOnClick; - ImGui::SameLine(); HelpMarker("Allow dragging an unselected item without altering selection."); + if (ImGui::TreeNode("Options")) + { + if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; } + ImGui::SameLine(); + if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; } + ImGui::Checkbox("Enable clipper", &use_clipper); + ImGui::Checkbox("Enable deletion", &use_deletion); + ImGui::Checkbox("Enable drag & drop", &use_drag_drop); + ImGui::Checkbox("Show in a table", &show_in_table); + ImGui::Checkbox("Show color button", &show_color_button); + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SingleSelect", &flags, ImGuiMultiSelectFlags_SingleSelect); + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll); + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect", &flags, ImGuiMultiSelectFlags_BoxSelect); + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelectNoScroll", &flags, ImGuiMultiSelectFlags_BoxSelectNoScroll); + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape); + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid); + if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow)) + flags &= ~ImGuiMultiSelectFlags_ScopeRect; + if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect)) + flags &= ~ImGuiMultiSelectFlags_ScopeWindow; + if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClick", &flags, ImGuiMultiSelectFlags_SelectOnClick) && (flags & ImGuiMultiSelectFlags_SelectOnClick)) + flags &= ~ImGuiMultiSelectFlags_SelectOnClickRelease; + if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, ImGuiMultiSelectFlags_SelectOnClickRelease) && (flags & ImGuiMultiSelectFlags_SelectOnClickRelease)) + flags &= ~ImGuiMultiSelectFlags_SelectOnClick; + ImGui::SameLine(); HelpMarker("Allow dragging an unselected item without altering selection."); + ImGui::TreePop(); + } // Initialize default list with 1000 items. // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection @@ -9797,6 +9803,7 @@ struct ExampleAssetsBrowser // Rendering parameters const ImU32 icon_type_overlay_colors[3] = { 0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255) }; + const ImU32 icon_bg_color = ImGui::GetColorU32(ImGuiCol_MenuBarBg); const ImVec2 icon_type_overlay_size = ImVec2(4.0f, 4.0f); const bool display_label = (LayoutItemSize.x >= ImGui::CalcTextSize("999").x); @@ -9856,7 +9863,7 @@ struct ExampleAssetsBrowser { ImVec2 box_min(pos.x - 1, pos.y - 1); ImVec2 box_max(box_min.x + LayoutItemSize.x + 2, box_min.y + LayoutItemSize.y + 2); // Dubious - draw_list->AddRectFilled(box_min, box_max, IM_COL32(48, 48, 48, 200)); // Background color + draw_list->AddRectFilled(box_min, box_max, icon_bg_color); // Background color if (ShowTypeOverlay && item_data->Type != 0) { ImU32 type_col = icon_type_overlay_colors[item_data->Type % IM_ARRAYSIZE(icon_type_overlay_colors)]; @@ -9864,7 +9871,7 @@ struct ExampleAssetsBrowser } if (display_label) { - ImU32 label_col = item_is_selected ? IM_COL32(255, 255, 255, 255) : ImGui::GetColorU32(ImGuiCol_TextDisabled); + ImU32 label_col = ImGui::GetColorU32(item_is_selected ? ImGuiCol_Text : ImGuiCol_TextDisabled); char label[32]; sprintf(label, "%d", item_data->ID); draw_list->AddText(ImVec2(box_min.x, box_max.y - ImGui::GetFontSize()), label_col, label); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 05ced948e..98569ead2 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7272,7 +7272,8 @@ static void DebugLogMultiSelectRequests(const char* function, const ImGuiMultiSe } } -// Return ImGuiMultiSelectIO structure. Lifetime: valid until corresponding call to EndMultiSelect(). +// Return ImGuiMultiSelectIO structure. +// Lifetime: don't hold on ImGuiMultiSelectIO* pointers over multiple frames or past any subsequent call to BeginMultiSelect() or EndMultiSelect(). ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags) { ImGuiContext& g = *GImGui; @@ -7375,7 +7376,8 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags) return &ms->IO; } -// Return updated ImGuiMultiSelectIO structure. Lifetime: until EndFrame() or next BeginMultiSelect() call. +// Return updated ImGuiMultiSelectIO structure. +// Lifetime: don't hold on ImGuiMultiSelectIO* pointers over multiple frames or past any subsequent call to BeginMultiSelect() or EndMultiSelect(). ImGuiMultiSelectIO* ImGui::EndMultiSelect() { ImGuiContext& g = *GImGui;