Browse Source

MultiSelect: ImGuiSelectionBasicStorage: simplify by removing compacting code (compacting may be opt-in?).

GetNextSelectedItem() wrapper gives us more flexibility to work on this kind of stuff now.
ocornut 1 year ago
parent
commit
2af3b2ac81
2 changed files with 11 additions and 40 deletions
  1. 2 2
      imgui.h
  2. 9 38
      imgui_widgets.cpp

+ 2 - 2
imgui.h

@@ -2835,7 +2835,7 @@ struct ImGuiSelectionBasicStorage
 {
     // Members
     ImGuiStorage    _Storage;       // [Internal] Selection set. Think of this as similar to e.g. std::set<ImGuiID>. Prefer not accessing directly: iterate with GetNextSelectedItem().
-    int             Size;           // Number of selected items, maintained by this helper.
+    int             Size;           // Number of selected items (== number of 1 in the Storage), maintained by this helper.
     void*           UserData;       // User data for use by adapter function                // e.g. selection.UserData = (void*)my_items;
     ImGuiID         (*AdapterIndexToStorageId)(ImGuiSelectionBasicStorage* self, int idx);  // e.g. selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return ((MyItems**)self->UserData)[idx]->ID; };
 
@@ -2849,7 +2849,7 @@ struct ImGuiSelectionBasicStorage
     ImGuiSelectionBasicStorage()                                { Size = 0; UserData = 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); int lhs_size = Size; Size = r.Size; r.Size = lhs_size; }
-    IMGUI_API void      SetItemSelected(ImGuiID id, bool selected);
+    void                SetItemSelected(ImGuiID id, bool v)     { int* p_int = _Storage.GetIntRef(id, 0); if (v && *p_int == 0) { *p_int = 1; Size++; } else if (!v && *p_int != 0) { *p_int = 0; Size--; } }
 };
 
 // Optional helper to apply multi-selection requests to existing randomly accessible storage.

+ 9 - 38
imgui_widgets.cpp

@@ -7830,63 +7830,34 @@ ImGuiID ImGuiSelectionBasicStorage::GetNextSelectedItem(void** opaque_it)
     if (it == NULL)
         it = _Storage.Data.Data;
     IM_ASSERT(it >= _Storage.Data.Data && it <= it_end);
+    if (it != it_end)
+        while (it->val_i == 0 && it < it_end)
+            it++;
     const bool has_more = (it != it_end);
     *opaque_it = has_more ? (void**)(it + 1) : (void**)(it);
     return has_more ? it->key : 0;
 }
 
-// Basic function to update selection (for very large amounts of changes, see what ApplyRequests is doing)
-void ImGuiSelectionBasicStorage::SetItemSelected(ImGuiID id, bool selected)
-{
-    ImGuiStoragePair* it = ImLowerBound(_Storage.Data.Data, _Storage.Data.Data + _Storage.Data.Size, id);
-    if (selected == (it != _Storage.Data.Data + _Storage.Data.Size) && (it->key == id))
-        return;
-    if (selected)
-        _Storage.Data.insert(it, ImGuiStoragePair(id, 1));
-    else
-        _Storage.Data.erase(it);
-    Size = _Storage.Data.Size;
-}
-
 // Optimized for batch edits (with same value of 'selected')
 static void ImGuiSelectionBasicStorage_BatchSetItemSelected(ImGuiSelectionBasicStorage* selection, ImGuiID id, bool selected, int size_before_amends)
 {
     ImGuiStorage* storage = &selection->_Storage;
     ImGuiStoragePair* it = ImLowerBound(storage->Data.Data, storage->Data.Data + size_before_amends, id);
-    if (selected == (it != storage->Data.Data + size_before_amends) && (it->key == id))
+    const bool is_contained = (it != storage->Data.Data + size_before_amends) && (it->key == id);
+    if (selected == is_contained && it->val_i == 1)
         return;
-    if (selected)
+    if (selected && !is_contained)
         storage->Data.push_back(ImGuiStoragePair(id, 1)); // Push unsorted at end of vector, will be sorted in SelectionMultiAmendsFinish()
-    else
-        it->val_i = 0; // Clear in-place, will be removed in SelectionMultiAmendsFinish()
+    else if (is_contained)
+        it->val_i = selected ? 1 : 0; // Modify in-place.
     selection->Size += selected ? +1 : -1;
 }
 
-static void ImGuiSelectionBasicStorage_Compact(ImGuiSelectionBasicStorage* selection)
-{
-    ImGuiStorage* storage = &selection->_Storage;
-    ImGuiStoragePair* p_out = storage->Data.Data;
-    ImGuiStoragePair* p_end = storage->Data.Data + storage->Data.Size;
-    for (ImGuiStoragePair* p_in = p_out; p_in < p_end; p_in++)
-        if (p_in->val_i != 0)
-        {
-            if (p_out != p_in)
-                *p_out = *p_in;
-            p_out++;
-        }
-    storage->Data.Size = (int)(p_out - storage->Data.Data);
-}
-
 static void ImGuiSelectionBasicStorage_BatchFinish(ImGuiSelectionBasicStorage* selection, bool selected, int size_before_amends)
 {
     ImGuiStorage* storage = &selection->_Storage;
-    if (selection->Size == size_before_amends)
-        return;
-    if (selected)
+    if (selected && selection->Size != size_before_amends)
         storage->BuildSortByKey(); // When done selecting: sort everything
-    else
-        ImGuiSelectionBasicStorage_Compact(selection); // When done unselecting: compact by removing all zero values (might be done lazily when iterating selection?)
-    IM_ASSERT(selection->Size == storage->Data.Size);
 }
 
 // Apply requests coming from BeginMultiSelect() and EndMultiSelect().