From 5d9de14493c39ec1ca00eed1be4b1e02761857e4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 20 Dec 2023 22:19:55 +0100 Subject: [PATCH] MultiSelect: Box-Select: Refactor: Renames. Split into two commits to facilite looking into previous one if needed. --- imgui.cpp | 26 ++++++++++----------- imgui_internal.h | 26 ++++++++++----------- imgui_widgets.cpp | 58 +++++++++++++++++++++++------------------------ 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d82d48c51..ffbebea7c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3083,19 +3083,19 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) float max_y = window->ClipRect.Max.y; // Add box selection range - if (ImGuiBoxSelectState* bs = &g.BoxSelectState) - if (bs->BoxSelectActive && bs->BoxSelectWindow == window) - { - // FIXME: Selectable() use of half-ItemSpacing isn't consistent in matter of layout, as ItemAdd(bb) stray above ItemSize()'s CursorPos. - // RangeSelect's BoxSelect relies on comparing overlap of previous and current rectangle and is sensitive to that. - // As a workaround we currently half ItemSpacing worth on each side. - min_y -= g.Style.ItemSpacing.y; - max_y += g.Style.ItemSpacing.y; + ImGuiBoxSelectState* bs = &g.BoxSelectState; + if (bs->IsActive && bs->Window == window) + { + // FIXME: Selectable() use of half-ItemSpacing isn't consistent in matter of layout, as ItemAdd(bb) stray above ItemSize()'s CursorPos. + // RangeSelect's BoxSelect relies on comparing overlap of previous and current rectangle and is sensitive to that. + // As a workaround we currently half ItemSpacing worth on each side. + min_y -= g.Style.ItemSpacing.y; + max_y += g.Style.ItemSpacing.y; - // Box-select on 2D area requires different clipping. - if (bs->BoxSelectUnclipMode) - data->Ranges.push_back(ImGuiListClipperRange::FromPositions(bs->BoxSelectUnclipRect.Min.y, bs->BoxSelectUnclipRect.Max.y, 0, 0)); - } + // Box-select on 2D area requires different clipping. + if (bs->UnclipMode) + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(bs->UnclipRect.Min.y, bs->UnclipRect.Max.y, 0, 0)); + } const int off_min = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) ? -1 : 0; const int off_max = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) ? 1 : 0; @@ -14998,7 +14998,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) if (TreeNode("MultiSelect", "MultiSelect (%d)", g.MultiSelectStorage.GetAliveCount())) { ImGuiBoxSelectState* ms = &g.BoxSelectState; - Text("BoxSelect ID=0x%08X, Starting = %d, Active %d", ms->BoxSelectId, ms->BoxSelectStarting, ms->BoxSelectActive); + Text("BoxSelect ID=0x%08X, Starting = %d, Active %d", ms->ID, ms->IsStarting, ms->IsActive); for (int n = 0; n < g.MultiSelectStorage.GetMapSize(); n++) if (ImGuiMultiSelectState* state = g.MultiSelectStorage.TryGetMapData(n)) DebugNodeMultiSelectState(state); diff --git a/imgui_internal.h b/imgui_internal.h index 165e3c058..8e71683f4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1714,21 +1714,21 @@ struct ImGuiOldColumns struct ImGuiBoxSelectState { // Active box-selection data (persistent, 1 active at a time) - ImGuiID BoxSelectId; - bool BoxSelectActive; - bool BoxSelectStarting; - bool BoxSelectFromVoid; - ImGuiKeyChord BoxSelectKeyMods : 16; // Latched key-mods for box-select logic. - ImVec2 BoxSelectStartPosRel; // Start position in window-relative space (to support scrolling) - ImVec2 BoxSelectEndPosRel; // End position in window-relative space - ImGuiWindow* BoxSelectWindow; + ImGuiID ID; + bool IsActive; + bool IsStarting; + bool IsStartedFromVoid; // Starting click was not from an item. + ImGuiKeyChord KeyMods : 16; // Latched key-mods for box-select logic. + ImVec2 StartPosRel; // Start position in window-contents relative space (to support scrolling) + ImVec2 EndPosRel; // End position in window-contents relative space + ImGuiWindow* Window; // Temporary/Transient data - bool BoxSelectUnclipMode; // Set/cleared by the BeginMultiSelect()/EndMultiSelect() owning active box-select. - ImRect BoxSelectRectPrev; // Selection rectangle in absolute coordinates (derived every frame from BoxSelectStartPosRel and MousePos) + bool UnclipMode; // (Temp/Transient, here in hot area). Set/cleared by the BeginMultiSelect()/EndMultiSelect() owning active box-select. + ImRect UnclipRect; // Rectangle where ItemAdd() clipping may be temporarily disabled. Need support by multi-select supporting widgets. + ImRect BoxSelectRectPrev; // Selection rectangle in absolute coordinates (derived every frame from BoxSelectStartPosRel and MousePos) ImRect BoxSelectRectCurr; - ImRect BoxSelectUnclipRect; // Rectangle where ItemAdd() clipping may be temporarily disabled. Need support by multi-select supporting widgets. - ImGuiSelectionUserData BoxSelectLastitem; + ImGuiSelectionUserData LastSubmittedItem; // Copy of last submitted item data, used to merge output ranges. ImGuiBoxSelectState() { memset(this, 0, sizeof(*this)); } }; @@ -3405,7 +3405,7 @@ namespace ImGui // Multi-Select API IMGUI_API void MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags* p_button_flags); IMGUI_API void MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed); - inline ImGuiBoxSelectState* GetBoxSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.BoxSelectState.BoxSelectId == id && g.BoxSelectState.BoxSelectActive) ? &g.BoxSelectState : NULL; } + inline ImGuiBoxSelectState* GetBoxSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.BoxSelectState.ID == id && g.BoxSelectState.IsActive) ? &g.BoxSelectState : NULL; } // Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API) IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 7470b607e..7f3e529ca 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6789,7 +6789,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (!is_multi_select) return false; // Extra layer of "no logic clip" for box-select support - if (!g.BoxSelectState.BoxSelectUnclipMode || !g.BoxSelectState.BoxSelectUnclipRect.Overlaps(bb)) + if (!g.BoxSelectState.UnclipMode || !g.BoxSelectState.UnclipRect.Overlaps(bb)) return false; } @@ -7122,11 +7122,11 @@ static void BoxSelectStart(ImGuiID id, ImGuiSelectionUserData clicked_item) { ImGuiContext& g = *GImGui; ImGuiBoxSelectState* bs = &g.BoxSelectState; - bs->BoxSelectId = id; - bs->BoxSelectStarting = true; // Consider starting box-select. - bs->BoxSelectFromVoid = (clicked_item == ImGuiSelectionUserData_Invalid); - bs->BoxSelectKeyMods = g.IO.KeyMods; - bs->BoxSelectStartPosRel = bs->BoxSelectEndPosRel = ImGui::WindowPosAbsToRel(g.CurrentWindow, g.IO.MousePos); + bs->ID = id; + bs->IsStarting = true; // Consider starting box-select. + bs->IsStartedFromVoid = (clicked_item == ImGuiSelectionUserData_Invalid); + bs->KeyMods = g.IO.KeyMods; + bs->StartPosRel = bs->EndPosRel = ImGui::WindowPosAbsToRel(g.CurrentWindow, g.IO.MousePos); } static void BoxSelectScrollWithMouseDrag(ImGuiWindow* window, const ImRect& inner_r) @@ -7259,38 +7259,38 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags) ms->BoxSelectId = GetID("##BoxSelect"); KeepAliveID(ms->BoxSelectId); } - if ((flags & ImGuiMultiSelectFlags_BoxSelect) && ms->BoxSelectId == bs->BoxSelectId) + if ((flags & ImGuiMultiSelectFlags_BoxSelect) && ms->BoxSelectId == bs->ID) { - bs->BoxSelectUnclipMode = false; + bs->UnclipMode = false; // BoxSelectStarting is set by MultiSelectItemFooter() when considering a possible box-select. We validate it here and lock geometry. - if (bs->BoxSelectStarting && IsMouseDragPastThreshold(0)) + if (bs->IsStarting && IsMouseDragPastThreshold(0)) { - bs->BoxSelectActive = true; - bs->BoxSelectWindow = ms->Storage->Window; - bs->BoxSelectStarting = false; + bs->IsActive = true; + bs->Window = ms->Storage->Window; + bs->IsStarting = false; SetActiveID(ms->BoxSelectId, window); - if (bs->BoxSelectFromVoid && (bs->BoxSelectKeyMods & ImGuiMod_Shift) == 0) + if (bs->IsStartedFromVoid && (bs->KeyMods & ImGuiMod_Shift) == 0) request_clear = true; } - else if ((bs->BoxSelectStarting || bs->BoxSelectActive) && g.IO.MouseDown[0] == false) + else if ((bs->IsStarting || bs->IsActive) && g.IO.MouseDown[0] == false) { - bs->BoxSelectId = 0; - bs->BoxSelectActive = bs->BoxSelectStarting = false; + bs->ID = 0; + bs->IsActive = bs->IsStarting = false; if (g.ActiveId == ms->BoxSelectId) ClearActiveID(); } - if (bs->BoxSelectActive) + if (bs->IsActive) { // Current frame absolute prev/current rectangles are used to toggle selection. // They are derived from positions relative to scrolling space. const ImRect scope_rect = window->InnerClipRect; - ImVec2 start_pos_abs = WindowPosRelToAbs(window, bs->BoxSelectStartPosRel); - ImVec2 prev_end_pos_abs = WindowPosRelToAbs(window, bs->BoxSelectEndPosRel); // Clamped already + ImVec2 start_pos_abs = WindowPosRelToAbs(window, bs->StartPosRel); + ImVec2 prev_end_pos_abs = WindowPosRelToAbs(window, bs->EndPosRel); // Clamped already ImVec2 curr_end_pos_abs = g.IO.MousePos; if (ms->Flags & ImGuiMultiSelectFlags_ScopeWindow) // Box-select scrolling only happens with ScopeWindow curr_end_pos_abs = ImClamp(curr_end_pos_abs, scope_rect.Min, scope_rect.Max); - bs->BoxSelectLastitem = -1; + bs->LastSubmittedItem = ImGuiSelectionUserData_Invalid; bs->BoxSelectRectPrev.Min = ImMin(start_pos_abs, prev_end_pos_abs); bs->BoxSelectRectPrev.Max = ImMax(start_pos_abs, prev_end_pos_abs); bs->BoxSelectRectCurr.Min = ImMin(start_pos_abs, curr_end_pos_abs); @@ -7301,9 +7301,9 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags) if (flags & ImGuiMultiSelectFlags_BoxSelect2d) if (bs->BoxSelectRectPrev.Min.x != bs->BoxSelectRectCurr.Min.x || bs->BoxSelectRectPrev.Max.x != bs->BoxSelectRectCurr.Max.x) { - bs->BoxSelectUnclipRect = bs->BoxSelectRectPrev; - bs->BoxSelectUnclipRect.Add(bs->BoxSelectRectCurr); - bs->BoxSelectUnclipMode = true; + bs->UnclipRect = bs->BoxSelectRectPrev; + bs->UnclipRect.Add(bs->BoxSelectRectCurr); + bs->UnclipMode = true; } //GetForegroundDrawList()->AddRect(ms->BoxSelectNoClipRect.Min, ms->BoxSelectNoClipRect.Max, IM_COL32(255,0,0,200), 0.0f, 0, 3.0f); @@ -7357,7 +7357,7 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() if ((ms->Flags & ImGuiMultiSelectFlags_BoxSelect) && bs != NULL) { // Box-select: render selection rectangle - bs->BoxSelectEndPosRel = WindowPosAbsToRel(window, ImClamp(g.IO.MousePos, scope_rect.Min, scope_rect.Max)); // Clamp stored position according to current scrolling view + bs->EndPosRel = WindowPosAbsToRel(window, ImClamp(g.IO.MousePos, scope_rect.Min, scope_rect.Max)); // Clamp stored position according to current scrolling view ImRect box_select_r = bs->BoxSelectRectCurr; box_select_r.ClipWith(scope_rect); window->DrawList->AddRectFilled(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_SeparatorHovered, 0.30f)); // FIXME-MULTISELECT: Styling @@ -7370,7 +7370,7 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() if ((ms->Flags & ImGuiMultiSelectFlags_ScopeWindow) && (ms->Flags & ImGuiMultiSelectFlags_BoxSelectNoScroll) == 0 && !scroll_r.Contains(g.IO.MousePos)) BoxSelectScrollWithMouseDrag(window, scroll_r); - bs->BoxSelectUnclipMode = false; + bs->UnclipMode = false; } } @@ -7383,7 +7383,7 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() if (scope_hovered && g.HoveredId == 0 && g.ActiveId == 0) { if (ms->Flags & ImGuiMultiSelectFlags_BoxSelect) - if (!g.BoxSelectState.BoxSelectActive && !g.BoxSelectState.BoxSelectStarting && g.IO.MouseClickedCount[0] == 1) + if (!g.BoxSelectState.IsActive && !g.BoxSelectState.IsStarting && g.IO.MouseClickedCount[0] == 1) BoxSelectStart(ms->BoxSelectId, ImGuiSelectionUserData_Invalid); if (ms->Flags & ImGuiMultiSelectFlags_ClearOnClickVoid) @@ -7543,12 +7543,12 @@ 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 == bs->BoxSelectLastitem && prev_req->RangeSelected == selected) + if (prev_req && prev_req->Type == ImGuiSelectionRequestType_SetRange && prev_req->RangeLastItem == bs->LastSubmittedItem && prev_req->RangeSelected == selected) prev_req->RangeLastItem = item_data; // Merge span into same request else ms->IO.Requests.push_back(req); } - bs->BoxSelectLastitem = item_data; + bs->LastSubmittedItem = item_data; } // Right-click handling: this could be moved at the Selectable() level. @@ -7576,7 +7576,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) // Box-select ImGuiInputSource input_source = (g.NavJustMovedToId == id || g.NavActivateId == id) ? g.NavInputSource : ImGuiInputSource_Mouse; if (ms->Flags & ImGuiMultiSelectFlags_BoxSelect) - if (selected == false && !g.BoxSelectState.BoxSelectActive && !g.BoxSelectState.BoxSelectStarting && input_source == ImGuiInputSource_Mouse && g.IO.MouseClickedCount[0] == 1) + if (selected == false && !g.BoxSelectState.IsActive && !g.BoxSelectState.IsStarting && input_source == ImGuiInputSource_Mouse && g.IO.MouseClickedCount[0] == 1) BoxSelectStart(ms->BoxSelectId, item_data); //----------------------------------------------------------------------------------------