MultiSelect: use a single ImGuiMultiSelectIO buffer.

+ using local storage var in EndMultiSelect(), should be no-op.
This commit is contained in:
ocornut 2023-09-22 15:34:25 +02:00
parent 5941edd9f7
commit 33fc61a091
2 changed files with 33 additions and 25 deletions

View File

@ -1720,10 +1720,10 @@ struct IMGUI_API ImGuiMultiSelectTempData
ImGuiID FocusScopeId; // Copied from g.CurrentFocusScopeId (unless another selection scope was pushed manually)
ImGuiMultiSelectFlags Flags;
ImGuiKeyChord KeyMods;
ImGuiMultiSelectIO BeginIO; // Requests are set and returned by BeginMultiSelect(), written to by user during the loop.
ImGuiMultiSelectIO EndIO; // Requests are set during the loop and returned by EndMultiSelect().
ImGuiMultiSelectIO IO; // Requests are set and returned by BeginMultiSelect()/EndMultiSelect() + written to by user during the loop.
bool LoopRequestClear;
bool LoopRequestSelectAll;
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.
bool NavIdPassedBy;
@ -1732,7 +1732,7 @@ struct IMGUI_API ImGuiMultiSelectTempData
//ImRect Rect; // Extent of selection scope between BeginMultiSelect() / EndMultiSelect(), used by ImGuiMultiSelectFlags_ClearOnClickRectVoid.
ImGuiMultiSelectTempData() { Clear(); }
void Clear() { Storage = NULL; FocusScopeId = 0; Flags = 0; KeyMods = 0; BeginIO.Clear(); EndIO.Clear(); LoopRequestClear = LoopRequestSelectAll = IsFocused = IsSetRange = NavIdPassedBy = RangeSrcPassedBy = RangeDstPassedBy = false; }
void Clear() { Storage = NULL; FocusScopeId = 0; Flags = 0; KeyMods = 0; IO.Clear(); IsEndIO = LoopRequestClear = LoopRequestSelectAll = IsFocused = IsSetRange = NavIdPassedBy = RangeSrcPassedBy = RangeDstPassedBy = false; }
};
// Persistent storage for multi-select (as long as selection is alive)

View File

@ -7149,10 +7149,10 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags)
storage->Window = window;
ms->Storage = storage;
// We want EndIO's NavIdItem/NavIdSelected to match BeginIO's one, so the value never changes after EndMultiSelect()
ms->BeginIO.RangeSrcItem = ms->EndIO.RangeSrcItem = storage->RangeSrcItem;
ms->BeginIO.NavIdItem = ms->EndIO.NavIdItem = storage->NavIdItem;
ms->BeginIO.NavIdSelected = ms->EndIO.NavIdSelected = (storage->NavIdSelected == 1) ? true : false;
ms->IO.RangeSrcItem = storage->RangeSrcItem;
ms->IO.NavIdItem = storage->NavIdItem;
ms->IO.NavIdSelected = (storage->NavIdSelected == 1) ? true : false;
ms->IO.Requests.resize(0);
bool request_clear = false;
bool request_select_all = false;
@ -7191,14 +7191,14 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags)
}
if (request_clear || request_select_all)
ms->BeginIO.Requests.push_back(ImGuiSelectionRequest(request_select_all ? ImGuiSelectionRequestType_SelectAll : ImGuiSelectionRequestType_Clear));
ms->IO.Requests.push_back(ImGuiSelectionRequest(request_select_all ? ImGuiSelectionRequestType_SelectAll : ImGuiSelectionRequestType_Clear));
ms->LoopRequestClear = request_clear;
ms->LoopRequestSelectAll = request_select_all;
if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection)
DebugLogMultiSelectRequests("BeginMultiSelect", &ms->BeginIO);
DebugLogMultiSelectRequests("BeginMultiSelect", &ms->IO);
return &ms->BeginIO;
return &ms->IO;
}
// Return updated ImGuiMultiSelectIO structure. Lifetime: until EndFrame() or next BeginMultiSelect() call.
@ -7206,46 +7206,49 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect()
{
ImGuiContext& g = *GImGui;
ImGuiMultiSelectTempData* ms = g.CurrentMultiSelect;
ImGuiMultiSelectState* storage = ms->Storage;
IM_ASSERT(ms->FocusScopeId == g.CurrentFocusScopeId);
IM_ASSERT(g.CurrentMultiSelect != NULL && ms->Storage->Window == g.CurrentWindow);
IM_ASSERT(g.CurrentMultiSelect != NULL && storage->Window == g.CurrentWindow);
if (ms->IsFocused)
{
// We currently don't allow user code to modify RangeSrcItem by writing to BeginIO's version, but that would be an easy change here.
if (ms->BeginIO.RangeSrcReset || (ms->RangeSrcPassedBy == false && ms->BeginIO.RangeSrcItem != ImGuiSelectionUserData_Invalid)) // Can't read storage->RangeSrcItem here -> we want the state at begining of the scope (see tests for easy failure)
if (ms->IO.RangeSrcReset || (ms->RangeSrcPassedBy == false && ms->IO.RangeSrcItem != ImGuiSelectionUserData_Invalid)) // Can't read storage->RangeSrcItem here -> we want the state at begining of the scope (see tests for easy failure)
{
IMGUI_DEBUG_LOG_SELECTION("[selection] EndMultiSelect: Reset RangeSrcItem.\n"); // Will set be to NavId.
ms->Storage->RangeSrcItem = ImGuiSelectionUserData_Invalid;
storage->RangeSrcItem = ImGuiSelectionUserData_Invalid;
}
if (ms->NavIdPassedBy == false && ms->Storage->NavIdItem != ImGuiSelectionUserData_Invalid)
if (ms->NavIdPassedBy == false && storage->NavIdItem != ImGuiSelectionUserData_Invalid)
{
IMGUI_DEBUG_LOG_SELECTION("[selection] EndMultiSelect: Reset NavIdItem.\n");
ms->Storage->NavIdItem = ImGuiSelectionUserData_Invalid;
ms->Storage->NavIdSelected = -1;
storage->NavIdItem = ImGuiSelectionUserData_Invalid;
storage->NavIdSelected = -1;
}
}
if (ms->IsEndIO == false)
ms->IO.Requests.resize(0);
// Clear selection when clicking void?
// We specifically test for IsMouseDragPastThreshold(0) == false to allow box-selection!
if (ms->Flags & ImGuiMultiSelectFlags_ClearOnClickWindowVoid)
if (IsWindowHovered() && g.HoveredId == 0)
if (IsMouseReleased(0) && IsMouseDragPastThreshold(0) == false && g.IO.KeyMods == ImGuiMod_None)
{
ms->EndIO.Requests.resize(0);
ms->EndIO.Requests.push_back(ImGuiSelectionRequest(ImGuiSelectionRequestType_Clear));
ms->IO.Requests.resize(0);
ms->IO.Requests.push_back(ImGuiSelectionRequest(ImGuiSelectionRequestType_Clear));
}
// Unwind
ms->FocusScopeId = 0;
ms->Flags = ImGuiMultiSelectFlags_None;
ms->BeginIO.Clear(); // Invalidate contents of BeginMultiSelect() to enforce scope.
PopFocusScope();
g.CurrentMultiSelect = NULL;
if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection)
DebugLogMultiSelectRequests("EndMultiSelect", &ms->EndIO);
DebugLogMultiSelectRequests("EndMultiSelect", &ms->IO);
return &ms->EndIO;
return &ms->IO;
}
void ImGui::SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data)
@ -7260,7 +7263,7 @@ void ImGui::SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_d
{
// Auto updating RangeSrcPassedBy for cases were clipper is not used (done before ItemAdd() clipping)
g.NextItemData.ItemFlags |= ImGuiItemFlags_HasSelectionUserData | ImGuiItemFlags_IsMultiSelect;
if (ms->BeginIO.RangeSrcItem == selection_user_data)
if (ms->IO.RangeSrcItem == selection_user_data)
ms->RangeSrcPassedBy = true;
}
else
@ -7357,6 +7360,11 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
storage->RangeSrcItem = item_data;
storage->RangeSelected = selected; // Will be updated at the end of this function anyway.
}
if (ms->IsEndIO == false)
{
ms->IO.Requests.resize(0);
ms->IsEndIO = true;
}
// Auto-select as you navigate a list
if (g.NavJustMovedToId == id)
@ -7416,8 +7424,8 @@ 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)
{
ms->EndIO.Requests.resize(0);
ms->EndIO.Requests.push_back(ImGuiSelectionRequest(ImGuiSelectionRequestType_Clear));
ms->IO.Requests.resize(0);
ms->IO.Requests.push_back(ImGuiSelectionRequest(ImGuiSelectionRequestType_Clear));
}
int range_direction;
@ -7443,7 +7451,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
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;
ms->EndIO.Requests.push_back(req);
ms->IO.Requests.push_back(req);
}
// Update/store the selection state of the Source item (used by CTRL+SHIFT, when Source is unselected we perform a range unselect)