Skip to content

Commit

Permalink
RangeSelect/MultiSelect: box-select: added scroll support.
Browse files Browse the repository at this point in the history
  • Loading branch information
ocornut committed Sep 26, 2023
1 parent d92fe92 commit c8e2f5a
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
1 change: 1 addition & 0 deletions imgui_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ static inline int ImModPositive(int a, int b)
static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; }
static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
static inline float ImLinearRemapClamp(float s0, float s1, float d0, float d1, float x) { return ImSaturate((x - s0) / (s1 - s0)) * (d1 - d0) + d0; }
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
static inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; }
static inline float ImExponentialMovingAverage(float avg, float sample, int n) { avg -= avg / n; avg += sample / n; return avg; }
Expand Down
43 changes: 35 additions & 8 deletions imgui_widgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6871,6 +6871,8 @@ void ImGui::DebugNodeTypingSelectState(ImGuiTypingSelectState* data)
//-------------------------------------------------------------------------
// [SECTION] Widgets: Multi-Select support
//-------------------------------------------------------------------------
// - DebugLogMultiSelectRequests() [Internal]
// - MultiSelectStartBoxSelect() [Internal]
// - BeginMultiSelect()
// - EndMultiSelect()
// - SetNextItemSelectionUserData()
Expand Down Expand Up @@ -6907,6 +6909,8 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags)
ImGuiMultiSelectTempData* ms = &g.MultiSelectTempData[0];
IM_ASSERT(g.CurrentMultiSelect == NULL); // No recursion allowed yet (we could allow it if we deem it useful)
g.CurrentMultiSelect = ms;
if ((flags & (ImGuiMultiSelectFlags_ScopeWindow | ImGuiMultiSelectFlags_ScopeRect)) == 0)
flags |= ImGuiMultiSelectFlags_ScopeWindow;

// FIXME: BeginFocusScope()
const ImGuiID id = window->IDStack.back();
Expand Down Expand Up @@ -7012,6 +7016,23 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags)
return &ms->IO;
}

static void ScrollWithMouseDrag(ImGuiWindow* window, const ImRect& r)
{
ImGuiContext& g = *GImGui;
for (int n = 0; n < 2; n++)
{
float dist = (g.IO.MousePos[n] > r.Max[n]) ? g.IO.MousePos[n] - r.Max[n] : (g.IO.MousePos[n] < r.Min[n]) ? g.IO.MousePos[n] - r.Min[n] : 0.0f;
if (dist == 0.0f || (dist < 0.0f && window->Scroll[n] < 0.0f) || (dist > 0.0f && window->Scroll[n] >= window->ScrollMax[n]))
continue;
float speed_multiplier = ImLinearRemapClamp(g.FontSize, g.FontSize * 5.0f, 1.0f, 4.0f, ImAbs(dist)); // x1 to x4 depending on distance
float scroll_step = IM_ROUND(g.FontSize * 35.0f * speed_multiplier * ImSign(dist) * g.IO.DeltaTime);
if (n == 0)
ImGui::SetScrollX(window, window->Scroll[n] + scroll_step);
else
ImGui::SetScrollY(window, window->Scroll[n] + scroll_step);
}
}

// Return updated ImGuiMultiSelectIO structure. Lifetime: until EndFrame() or next BeginMultiSelect() call.
ImGuiMultiSelectIO* ImGui::EndMultiSelect()
{
Expand All @@ -7022,6 +7043,7 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect()
IM_ASSERT(ms->FocusScopeId == g.CurrentFocusScopeId);
IM_ASSERT(g.CurrentMultiSelect != NULL && storage->Window == g.CurrentWindow);

const ImRect scope_rect = (ms->Flags & ImGuiMultiSelectFlags_ScopeRect) ? ImRect(ms->ScopeRectMin, ImMax(window->DC.CursorMaxPos, ms->ScopeRectMin)) : window->InnerClipRect;
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.
Expand All @@ -7037,25 +7059,30 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect()
storage->NavIdSelected = -1;
}

// Box-select: render selection rectangle
// FIXME-MULTISELECT: Scroll on box-select
if ((ms->Flags & ImGuiMultiSelectFlags_BoxSelect) && storage->BoxSelectActive)
{
// Box-select: render selection rectangle
ms->Storage->BoxSelectEndPosRel = WindowPosAbsToRel(window, g.IO.MousePos);
window->DrawList->AddRectFilled(ms->BoxSelectRectCurr.Min, ms->BoxSelectRectCurr.Max, GetColorU32(ImGuiCol_SeparatorHovered, 0.30f)); // FIXME-MULTISELECT: Styling
window->DrawList->AddRect(ms->BoxSelectRectCurr.Min, ms->BoxSelectRectCurr.Max, GetColorU32(ImGuiCol_NavHighlight)); // FIXME-MULTISELECT: Styling
ImRect box_select_r = ms->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
window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavHighlight)); // FIXME-MULTISELECT: Styling

// Box-select: scroll
ImRect scroll_r = scope_rect;
scroll_r.Expand(g.Style.FramePadding);
if ((ms->Flags & ImGuiMultiSelectFlags_ScopeWindow) && !scroll_r.Contains(g.IO.MousePos))
ScrollWithMouseDrag(window, scroll_r);
}
}

if (ms->IsEndIO == false)
ms->IO.Requests.resize(0);

const ImRect scope_rect(ms->ScopeRectMin, ImMax(window->DC.CursorMaxPos, ms->ScopeRectMin));
const bool scope_hovered = (ms->Flags & ImGuiMultiSelectFlags_ScopeRect) ? IsMouseHoveringRect(scope_rect.Min, scope_rect.Max) : IsWindowHovered();

// Clear selection when clicking void?
// We specifically test for IsMouseDragPastThreshold(0) == false to allow box-selection!
if (scope_hovered && g.HoveredId == 0)
const bool scope_hovered = (ms->Flags & ImGuiMultiSelectFlags_ScopeRect) ? scope_rect.Contains(g.IO.MousePos) : IsWindowHovered();
if (scope_hovered && g.HoveredId == 0 && g.ActiveId == 0)
{
if (ms->Flags & ImGuiMultiSelectFlags_BoxSelect)
if (!storage->BoxSelectActive && !storage->BoxSelectStarting && g.IO.MouseClickedCount[0] == 1)
Expand Down

0 comments on commit c8e2f5a

Please sign in to comment.