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

MultiSelect: (Breaking) merge ImGuiSelectionRequestType_Clear and ImGuiSelectionRequestType_SelectAll into ImGuiSelectionRequestType_SetAll., rename ImGuiSelectionRequest::RangeSelected to Selected.

The reasoning is that it makes it easier/faster to write an adhoc ImGuiMultiSelectIO handler (e.g. trying to apply multi-select to checkboxes)
ocornut 1 жил өмнө
parent
commit
f36a03c317
3 өөрчлөгдсөн 23 нэмэгдсэн , 31 устгасан
  1. 6 7
      imgui.h
  2. 1 2
      imgui_internal.h
  3. 16 22
      imgui_widgets.cpp

+ 6 - 7
imgui.h

@@ -2744,11 +2744,11 @@ struct ImColor
 // - 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.
+//           - (2) [If using clipper] Honor request list (SetAll/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.
+//           - (6) Honor request list (SetAll/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:
 // - For each item is it submitted by your call to SetNextItemSelectionUserData().
@@ -2771,7 +2771,7 @@ enum ImGuiMultiSelectFlags_
 {
     ImGuiMultiSelectFlags_None                  = 0,
     ImGuiMultiSelectFlags_SingleSelect          = 1 << 0,   // Disable selecting more than one item. This is available to allow single-selection code to share same code/logic if desired. It essentially disables the main purpose of BeginMultiSelect() tho!
-    ImGuiMultiSelectFlags_NoSelectAll           = 1 << 1,   // Disable CTRL+A shortcut sending a SelectAll request.
+    ImGuiMultiSelectFlags_NoSelectAll           = 1 << 1,   // Disable CTRL+A shortcut to select all.
     ImGuiMultiSelectFlags_NoRangeSelect         = 1 << 2,   // Disable Shift+Click/Shift+Keyboard handling (useful for unordered 2D selection).
     ImGuiMultiSelectFlags_BoxSelect             = 1 << 3,   // Enable box-selection (only supporting 1D list when using clipper, not 2D grids). Box-selection works better with little bit of spacing between items hit-box in order to be able to aim at empty space.
     ImGuiMultiSelectFlags_BoxSelect2d           = 1 << 4,   // Enable box-selection with 2D layout/grid support. This alters clipping logic so that e.g. horizontal movements will update selection of normally clipped items.
@@ -2803,9 +2803,8 @@ struct ImGuiMultiSelectIO
 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.
+    ImGuiSelectionRequestType_SetAll,           // Request app to clear selection (if Selected==false) or select all items (if Selected==true)
+    ImGuiSelectionRequestType_SetRange,         // Request app to select/unselect [RangeFirstItem..RangeLastItem] items (inclusive) based on value of Selected. Only EndMultiSelect() request this, app code can read after BeginMultiSelect() and it will always be false.
 };
 
 // Selection request item
@@ -2813,7 +2812,7 @@ 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)
+    bool                        Selected;       //                  /  ms:w, app:r   // Parameter for SetAll/SetRange requests (true = select, false = unselect)
     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)
 };

+ 1 - 2
imgui_internal.h

@@ -1754,8 +1754,7 @@ struct IMGUI_API ImGuiMultiSelectTempData
     ImVec2                  BackupCursorMaxPos;
     ImGuiID                 BoxSelectId;
     ImGuiKeyChord           KeyMods;
-    bool                    LoopRequestClear;
-    bool                    LoopRequestSelectAll;
+    ImS8                    LoopRequestSetAll;  // -1: no operation, 0: clear all, 1: select all.
     bool                    IsEndIO;            // Set when switching IO from BeginMultiSelect() to EndMultiSelect() state.
     bool                    IsFocused;          // Set if currently focusing the selection scope (any item of the selection). May be used if you have custom shortcut associated to selection.
     bool                    IsSetRange;         // Set by BeginMultiSelect() when using Shift+Navigation. Because scrolling may be affected we can't afford a frame of lag with Shift+Navigation.

+ 16 - 22
imgui_widgets.cpp

@@ -7272,9 +7272,8 @@ static void DebugLogMultiSelectRequests(const char* function, const ImGuiMultiSe
     ImGuiContext& g = *GImGui;
     for (const ImGuiSelectionRequest& req : io->Requests)
     {
-        if (req.Type == ImGuiSelectionRequestType_Clear)     IMGUI_DEBUG_LOG_SELECTION("[selection] %s: Request: Clear\n", function);
-        if (req.Type == ImGuiSelectionRequestType_SelectAll) IMGUI_DEBUG_LOG_SELECTION("[selection] %s: Request: SelectAll\n", function);
-        if (req.Type == ImGuiSelectionRequestType_SetRange)  IMGUI_DEBUG_LOG_SELECTION("[selection] %s: Request: SetRange %" IM_PRId64 "..%" IM_PRId64 " (0x%" IM_PRIX64 "..0x%" IM_PRIX64 ") = %d\n", function, req.RangeFirstItem, req.RangeLastItem, req.RangeFirstItem, req.RangeLastItem, req.RangeSelected);
+        if (req.Type == ImGuiSelectionRequestType_SetAll)    IMGUI_DEBUG_LOG_SELECTION("[selection] %s: Request: SetAll %d (= %s)\n", function, req.Selected, req.Selected ? "SelectAll" : "Clear");
+        if (req.Type == ImGuiSelectionRequestType_SetRange)  IMGUI_DEBUG_LOG_SELECTION("[selection] %s: Request: SetRange %" IM_PRId64 "..%" IM_PRId64 " (0x%" IM_PRIX64 "..0x%" IM_PRIX64 ") = %d\n", function, req.RangeFirstItem, req.RangeLastItem, req.RangeFirstItem, req.RangeLastItem, req.Selected);
     }
 }
 
@@ -7372,11 +7371,10 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags)
 
     if (request_clear || request_select_all)
     {
-        ImGuiSelectionRequest req = { request_select_all ? ImGuiSelectionRequestType_SelectAll : ImGuiSelectionRequestType_Clear, false, (ImGuiSelectionUserData)-1, (ImGuiSelectionUserData)-1 };
+        ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, request_select_all, (ImGuiSelectionUserData)-1, (ImGuiSelectionUserData)-1 };
         ms->IO.Requests.push_back(req);
     }
-    ms->LoopRequestClear = request_clear;
-    ms->LoopRequestSelectAll = request_select_all;
+    ms->LoopRequestSetAll = request_select_all ? 1 : request_clear ? 0 : -1;
 
     if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection)
         DebugLogMultiSelectRequests("BeginMultiSelect", &ms->IO);
@@ -7441,7 +7439,7 @@ 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 };
+                ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, false, (ImGuiSelectionUserData)-1, (ImGuiSelectionUserData)-1 };
                 ms->IO.Requests.resize(0);
                 ms->IO.Requests.push_back(req);
             }
@@ -7494,13 +7492,11 @@ void ImGui::MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags
         ImGuiSelectionUserData item_data = g.NextItemData.SelectionUserData;
         IM_ASSERT(g.NextItemData.FocusScopeId == g.CurrentFocusScopeId && "Forgot to call SetNextItemSelectionUserData() prior to item, required in BeginMultiSelect()/EndMultiSelect() scope");
 
-        // Apply Clear/SelectAll requests requested by BeginMultiSelect().
+        // Apply SetAll (Clear/SelectAll )requests requested by BeginMultiSelect().
         // This is only useful if the user hasn't processed them already, and this only works if the user isn't using the clipper.
-        // If you are using a clipper (aka not submitting every element of the list) you need to process the Clear/SelectAll request after calling BeginMultiSelect()
-        if (ms->LoopRequestClear)
-            selected = false;
-        else if (ms->LoopRequestSelectAll)
-            selected = true;
+        // If you are using a clipper you need to process the SetAll request after calling BeginMultiSelect()
+        if (ms->LoopRequestSetAll != -1)
+            selected = (ms->LoopRequestSetAll == 1);
 
         // When using SHIFT+Nav: because it can incur scrolling we cannot afford a frame of lag with the selection highlight (otherwise scrolling would happen before selection)
         // For this to work, we need someone to set 'RangeSrcPassedBy = true' at some point (either clipper either SetNextItemSelectionUserData() function)
@@ -7595,7 +7591,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
             selected = !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)
+            if (prev_req && prev_req->Type == ImGuiSelectionRequestType_SetRange && prev_req->RangeLastItem == ms->BoxSelectLastitem && prev_req->Selected == selected)
                 prev_req->RangeLastItem = item_data; // Merge span into same request
             else
                 ms->IO.Requests.push_back(req);
@@ -7657,7 +7653,7 @@ 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 };
+            ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, false, (ImGuiSelectionUserData)-1, (ImGuiSelectionUserData)-1 };
             ms->IO.Requests.resize(0);
             ms->IO.Requests.push_back(req);
         }
@@ -7734,27 +7730,25 @@ void ImGui::DebugNodeMultiSelectState(ImGuiMultiSelectState* storage)
 // The most simple implementation (using indices everywhere) would look like:
 //   for (ImGuiSelectionRequest& req : ms_io->Requests)
 //   {
-//      if (req.Type == ImGuiSelectionRequestType_Clear)     { Clear(); }
-//      if (req.Type == ImGuiSelectionRequestType_SelectAll) { Clear(); for (int n = 0; n < items_count; n++) { AddItem(n); } }
-//      if (req.Type == ImGuiSelectionRequestType_SetRange)  { for (int n = (int)ms_io->RangeFirstItem; n <= (int)ms_io->RangeLastItem; n++) { UpdateItem(n, ms_io->RangeSelected); } }
+//      if (req.Type == ImGuiSelectionRequestType_SetAll)    { Clear(); if (req.Selected) { for (int n = 0; n < items_count; n++) { AddItem(n); } }
+//      if (req.Type == ImGuiSelectionRequestType_SetRange)  { for (int n = (int)ms_io->RangeFirstItem; n <= (int)ms_io->RangeLastItem; n++) { UpdateItem(n, ms_io->Selected); } }
 //   }
 void ImGuiSelectionBasicStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io, int items_count)
 {
     IM_ASSERT(AdapterIndexToStorageId != NULL);
     for (ImGuiSelectionRequest& req : ms_io->Requests)
     {
-        if (req.Type == ImGuiSelectionRequestType_Clear)
+        if (req.Type == ImGuiSelectionRequestType_SetAll)
             Clear();
-        if (req.Type == ImGuiSelectionRequestType_SelectAll)
+        if (req.Type == ImGuiSelectionRequestType_SetAll && req.Selected)
         {
-            Clear();
             Storage.Data.reserve(items_count);
             for (int idx = 0; idx < items_count; idx++)
                 AddItem(AdapterIndexToStorageId(this, idx));
         }
         if (req.Type == ImGuiSelectionRequestType_SetRange)
             for (int idx = (int)req.RangeFirstItem; idx <= (int)req.RangeLastItem; idx++)
-                UpdateItem(AdapterIndexToStorageId(this, idx), req.RangeSelected);
+                UpdateItem(AdapterIndexToStorageId(this, idx), req.Selected);
     }
 }