MultiSelect: added ImGuiSelectionExternalStorage helper. Simplify bool demo.
diff --git a/imgui.h b/imgui.h
index c0c2d0b..050c8bb 100644
--- a/imgui.h
+++ b/imgui.h
@@ -44,7 +44,7 @@
 // [SECTION] ImGuiIO
 // [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload)
 // [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor)
-// [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, ImGuiSelectionBasicStorage)
+// [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage)
 // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData)
 // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont)
 // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport)
@@ -180,6 +180,7 @@
 struct ImGuiPayload;                // User data payload for drag and drop operations
 struct ImGuiPlatformImeData;        // Platform IME data for io.PlatformSetImeDataFn() function.
 struct ImGuiSelectionBasicStorage;  // Optional helper to store multi-selection state + apply multi-selection requests.
+struct ImGuiSelectionExternalStorage;//Optional helper to apply multi-selection requests to existing randomly accessible storage.
 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)
@@ -2860,6 +2861,19 @@
     ImGuiID         GetStorageIdFromIndex(int idx)      { return AdapterIndexToStorageId(this, idx); }
 };
 
+// Optional helper to apply multi-selection requests to existing randomly accessible storage.
+// Convenient if you want to quickly wire multi-select API on e.g. an array of bool or items storing their own selection state.
+struct ImGuiSelectionExternalStorage
+{
+    // Members
+    void            (*AdapterSetItemSelected)(ImGuiSelectionExternalStorage* self, int idx, bool selected); // e.g. AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int idx, bool selected) { ((MyItems**)self->UserData)[idx]->Selected = selected; }
+    void*           UserData;       // User data for use by adapter function                                // e.g. selection.UserData = (void*)my_items;
+
+    // Methods
+    ImGuiSelectionExternalStorage()             { memset(this, 0, sizeof(*this)); }
+    IMGUI_API void  ApplyRequests(ImGuiMultiSelectIO* ms_io);                           // Generic function, using AdapterSetItemSelected()
+};
+
 //-----------------------------------------------------------------------------
 // [SECTION] Drawing API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData)
 // Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList.
diff --git a/imgui_demo.cpp b/imgui_demo.cpp
index b3dc5ef..3cd2046 100644
--- a/imgui_demo.cpp
+++ b/imgui_demo.cpp
@@ -3212,41 +3212,28 @@
             ImGui::BulletText("Shift+Keyboard to copy current value to other boxes.");
 
             // If you have an array of checkboxes, you may want to use NoAutoSelect + NoAutoClear and the ImGuiSelectionExternalStorage helper.
-            static bool values[20] = {};
+            static bool items[20] = {};
             static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_NoAutoSelect | ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_ClearOnEscape;
             ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
             ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
             ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect", &flags, ImGuiMultiSelectFlags_BoxSelect); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as checkboxes are varying width.
 
-            struct Funcs
-            {
-                static void ApplyMultiSelectRequestsToBoolArray(ImGuiMultiSelectIO* ms_io, bool items[], int items_count)
-                {
-                    for (ImGuiSelectionRequest& req : ms_io->Requests)
-                    {
-                        if (req.Type == ImGuiSelectionRequestType_SetAll)
-                            for (int n = 0; n < items_count; n++)
-                                items[n] = req.Selected;
-                        else if (req.Type == ImGuiSelectionRequestType_SetRange)
-                            for (int n = (int)req.RangeFirstItem; n <= (int)req.RangeLastItem; n++)
-                                items[n] = req.Selected;
-                    }
-                }
-            };
-
             if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY))
             {
-                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags);
-                Funcs::ApplyMultiSelectRequestsToBoolArray(ms_io, values, IM_ARRAYSIZE(values)); //// By specs, it could be optional to apply requests from BeginMultiSelect() if not using a clipper.
+                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, -1, IM_ARRAYSIZE(items));
+                ImGuiSelectionExternalStorage storage_wrapper;
+                storage_wrapper.UserData = (void*)items;
+                storage_wrapper.AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int n, bool selected) { bool* array = (bool*)self->UserData; array[n] = selected; };
+                storage_wrapper.ApplyRequests(ms_io);
                 for (int n = 0; n < 20; n++)
                 {
                     char label[32];
                     sprintf(label, "Item %d", n);
                     ImGui::SetNextItemSelectionUserData(n);
-                    ImGui::Checkbox(label, &values[n]);
+                    ImGui::Checkbox(label, &items[n]);
                 }
                 ms_io = ImGui::EndMultiSelect();
-                Funcs::ApplyMultiSelectRequestsToBoolArray(ms_io, values, IM_ARRAYSIZE(values));
+                storage_wrapper.ApplyRequests(ms_io);
             }
             ImGui::EndChild();
 
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 1ebabe4..c85b6ff 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -7854,6 +7854,22 @@
     }
 }
 
+// Apply requests coming from BeginMultiSelect() and EndMultiSelect().
+// We also pull 'ms_io->ItemsCount' as passed for BeginMultiSelect() for consistency with ImGuiSelectionBasicStorage
+// This makes no assumption about underlying storage.
+void ImGuiSelectionExternalStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io)
+{
+    IM_ASSERT(AdapterSetItemSelected);
+    for (ImGuiSelectionRequest& req : ms_io->Requests)
+    {
+        if (req.Type == ImGuiSelectionRequestType_SetAll)
+            for (int idx = 0; idx < ms_io->ItemsCount; idx++)
+                AdapterSetItemSelected(this, idx, req.Selected);
+        if (req.Type == ImGuiSelectionRequestType_SetRange)
+            for (int idx = (int)req.RangeFirstItem; idx <= (int)req.RangeLastItem; idx++)
+                AdapterSetItemSelected(this, idx, req.Selected);
+    }
+}
 
 //-------------------------------------------------------------------------
 // [SECTION] Widgets: ListBox