Преглед на файлове

MultiSelect: remove ImGuiSelectionRequest/ImGuiMultiSelectIO details from public api to reduce confusion + comments.

ocornut преди 1 година
родител
ревизия
e0282347db
променени са 3 файла, в които са добавени 40 реда и са изтрити 43 реда
  1. 25 31
      imgui.h
  2. 2 1
      imgui_internal.h
  3. 13 11
      imgui_widgets.cpp

+ 25 - 31
imgui.h

@@ -2753,18 +2753,17 @@ enum ImGuiMultiSelectFlags_
 // - 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),  or other structures (store indices
-//   in an interval tree), etc.
+//   external array (store an array in your view data, next to your objects) 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) with no performance penalty, but requires a little more
-//   work on the code.
-//   For small selection set (<100 items), you might want to not bother with using the clipper, as the cost
-//   should be negligible (as least on Dear ImGui side).
+//   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 submitted by your calls to SetNextItemSelectionUserData().
+//   - 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
@@ -2773,8 +2772,7 @@ enum ImGuiMultiSelectFlags_
 //   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 of (e.g. an data) but this may make your lookups and the interpolation between
-//   two values more cumbersome.
+// - You may store another type as long as you can interpolate between two values.
 // - 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.
@@ -2786,8 +2784,8 @@ enum ImGuiMultiSelectFlags_
 //   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.
 // Advanced:
-// - Deletion: If you need to handle items deletion a little more work if needed for post-deletion focus and scrolling to be correct.
-//   refer to 'Demo->Widgets->Selection State' for demos supporting deletion.
+// - 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.
 
 enum ImGuiSelectionRequestType
 {
@@ -2797,33 +2795,29 @@ 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.
 };
 
-// List of requests stored in ImGuiMultiSelectIO
-// - Use 'Demo->Tools->Debug Log->Selection' to see requests as they happen.
-// - Some fields are only necessary 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.
 struct ImGuiSelectionRequest
 {
-    ImGuiSelectionRequestType   Type;           //  ms:w, app:r  /  ms:w, app:r
-    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)
-
-    ImGuiSelectionRequest(ImGuiSelectionRequestType type = ImGuiSelectionRequestType_None) { Type = type; RangeSelected = false; RangeFirstItem = RangeLastItem = (ImGuiSelectionUserData)-1; }
+    //------------------------------------------// 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().
-// Read the large comments block above for details.
-// Lifetime: don't hold on ImGuiMultiSelectIO* pointers over multiple frames or past any subsequent call to BeginMultiSelect() or 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
 {
-    ImVector<ImGuiSelectionRequest> Requests;   //  ms:w, app:r  /  ms:w  app:r  // Requests
-    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).
-
-    ImGuiMultiSelectIO()    { Clear(); }
-    void Clear()            { Requests.resize(0); RangeSrcItem = NavIdItem = (ImGuiSelectionUserData)-1; NavIdSelected = RangeSrcReset = false; }
+    //------------------------------------------// BeginMultiSelect / EndMultiSelect
+    ImVector<ImGuiSelectionRequest> Requests;   //  ms:w, app:r     /  ms:w  app:r   // Requests
+    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).
 };
 
 //-----------------------------------------------------------------------------

+ 2 - 1
imgui_internal.h

@@ -1738,7 +1738,8 @@ struct IMGUI_API ImGuiMultiSelectTempData
     bool                    RangeDstPassedBy;   // Set by the item that matches NavJustMovedToId when IsSetRange is set.
 
     ImGuiMultiSelectTempData()  { Clear(); }
-    void Clear()            { size_t io_sz = sizeof(IO); IO.Clear(); memset((void*)(&IO + 1), 0, sizeof(*this) - io_sz); BoxSelectLastitem = -1; } // Zero-clear except IO
+    void Clear()            { size_t io_sz = sizeof(IO); ClearIO(); memset((void*)(&IO + 1), 0, sizeof(*this) - io_sz); BoxSelectLastitem = -1; } // Zero-clear except IO as we preserve IO.Requests[] buffer allocation.
+    void ClearIO()          { IO.Requests.resize(0); IO.RangeSrcItem = IO.NavIdItem = (ImGuiSelectionUserData)-1; IO.NavIdSelected = IO.RangeSrcReset = false; }
 };
 
 // Persistent storage for multi-select (as long as selection is alive)

+ 13 - 11
imgui_widgets.cpp

@@ -7259,7 +7259,10 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags)
     }
 
     if (request_clear || request_select_all)
-        ms->IO.Requests.push_back(ImGuiSelectionRequest(request_select_all ? ImGuiSelectionRequestType_SelectAll : ImGuiSelectionRequestType_Clear));
+    {
+        ImGuiSelectionRequest req = { request_select_all ? ImGuiSelectionRequestType_SelectAll : ImGuiSelectionRequestType_Clear, false, (ImGuiSelectionUserData)-1, (ImGuiSelectionUserData)-1 };
+        ms->IO.Requests.push_back(req);
+    }
     ms->LoopRequestClear = request_clear;
     ms->LoopRequestSelectAll = request_select_all;
 
@@ -7328,8 +7331,9 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect()
         if (ms->Flags & ImGuiMultiSelectFlags_ClearOnClickVoid)
             if (IsMouseReleased(0) && IsMouseDragPastThreshold(0) == false && g.IO.KeyMods == ImGuiMod_None)
             {
+                ImGuiSelectionRequest req = { ImGuiSelectionRequestType_Clear, false, (ImGuiSelectionUserData)-1, (ImGuiSelectionUserData)-1 };
                 ms->IO.Requests.resize(0);
-                ms->IO.Requests.push_back(ImGuiSelectionRequest(ImGuiSelectionRequestType_Clear));
+                ms->IO.Requests.push_back(req);
             }
     }
 
@@ -7479,9 +7483,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
         if ((rect_overlap_curr && !rect_overlap_prev && !selected) || (rect_overlap_prev && !rect_overlap_curr))
         {
             selected = !selected;
-            ImGuiSelectionRequest req(ImGuiSelectionRequestType_SetRange);
-            req.RangeFirstItem = req.RangeLastItem = item_data;
-            req.RangeSelected = selected;
+            ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, selected, item_data, item_data };
             ImGuiSelectionRequest* prev_req = (ms->IO.Requests.Size > 0) ? &ms->IO.Requests.Data[ms->IO.Requests.Size - 1] : NULL;
             if (prev_req && prev_req->Type == ImGuiSelectionRequestType_SetRange && prev_req->RangeLastItem == ms->BoxSelectLastitem && prev_req->RangeSelected == selected)
                 prev_req->RangeLastItem = item_data; // Merge span into same request
@@ -7545,12 +7547,13 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
             request_clear = true; // With is_shift==false the RequestClear was done in BeginIO, not necessary to do again.
         if (request_clear)
         {
+            ImGuiSelectionRequest req = { ImGuiSelectionRequestType_Clear, false, (ImGuiSelectionUserData)-1, (ImGuiSelectionUserData)-1 };
             ms->IO.Requests.resize(0);
-            ms->IO.Requests.push_back(ImGuiSelectionRequest(ImGuiSelectionRequestType_Clear));
+            ms->IO.Requests.push_back(req);
         }
 
         int range_direction;
-        ImGuiSelectionRequest req(ImGuiSelectionRequestType_SetRange);
+        bool range_selected;
         if (is_shift && !is_singleselect)
         {
             // Shift+Arrow always select
@@ -7558,7 +7561,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
             //IM_ASSERT(storage->HasRangeSrc && storage->HasRangeValue);
             if (storage->RangeSrcItem == ImGuiSelectionUserData_Invalid)
                 storage->RangeSrcItem = item_data;
-            req.RangeSelected = (is_ctrl && storage->RangeSelected != -1) ? (storage->RangeSelected != 0) : true;
+            range_selected = (is_ctrl && storage->RangeSelected != -1) ? (storage->RangeSelected != 0) : true;
             range_direction = ms->RangeSrcPassedBy ? +1 : -1;
         }
         else
@@ -7566,12 +7569,11 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
             // Ctrl inverts selection, otherwise always select
             selected = is_ctrl ? !selected : true;
             storage->RangeSrcItem = item_data;
-            req.RangeSelected = selected;
+            range_selected = selected;
             range_direction = +1;
         }
         ImGuiSelectionUserData range_dst_item = item_data;
-        req.RangeFirstItem = (range_direction > 0) ? storage->RangeSrcItem : range_dst_item;
-        req.RangeLastItem = (range_direction > 0) ? range_dst_item : storage->RangeSrcItem;
+        ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, range_selected, (range_direction > 0) ? storage->RangeSrcItem : range_dst_item, (range_direction > 0) ? range_dst_item : storage->RangeSrcItem };
         ms->IO.Requests.push_back(req);
     }