2
0
Эх сурвалжийг харах

MultiSelect: Comments + Assets Browser : Tweak colors.

ocornut 1 жил өмнө
parent
commit
d439f590ab
3 өөрчлөгдсөн 92 нэмэгдсэн , 103 устгасан
  1. 51 71
      imgui.h
  2. 37 30
      imgui_demo.cpp
  3. 4 2
      imgui_widgets.cpp

+ 51 - 71
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,6 +2783,22 @@ enum ImGuiMultiSelectFlags_
     ImGuiMultiSelectFlags_SelectOnClickRelease  = 1 << 10,  // Apply selection on mouse release when clicking an unselected item. Allow dragging an unselected item without altering selection.
 };
 
+// Main IO structure returned by BeginMultiSelect()/EndMultiSelect().
+// 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 (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
+    ImVector<ImGuiSelectionRequest> 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).
+};
+
+// Selection request type
 enum ImGuiSelectionRequestType
 {
     ImGuiSelectionRequestType_None = 0,
@@ -2793,6 +2807,7 @@ enum ImGuiSelectionRequestType
     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
@@ -2802,65 +2817,30 @@ struct ImGuiSelectionRequest
     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.
-// - 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().
-struct ImGuiMultiSelectIO
-{
-    //------------------------------------------// BeginMultiSelect / EndMultiSelect
-    ImVector<ImGuiSelectionRequest> 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).
-};
-
-// Optional helper struct to store multi-selection state + apply multi-selection requests.
+// 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<ImGuiID> replacement.
 // - B) Use your own external storage: e.g. std::set<MyObjectId>, std::vector<MyObjectId>, 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<MyItem> 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<MyItem>*)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<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 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; };
 

+ 37 - 30
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);

+ 4 - 2
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;