Skip to content

Commit ae7f833

Browse files
committed
Window: Resizing from edges (with io.ConfigResizeWindowsFromEdges Beta flag) extends the hit region of root floating windows outside the window, making it easier to resize windows. Resize grips are also extended accordingly so there are no discontinuity when hovering between borders and corners. (ocornut#1495, ocornut#822, ocornut#2110)
1 parent 76e31bd commit ae7f833

File tree

2 files changed

+42
-25
lines changed

2 files changed

+42
-25
lines changed

docs/CHANGELOG.txt

+3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ Other Changes:
4949
erroneously wrapped the value to one of the min/max edge. (#2024, #708, #320, #2075).
5050
- DragFloat: Disabled using power curve when one edge is FLT_MAX (broken in 1.61). (#2024)
5151
- DragFloat: Disabled setting a default drag speed when one edge is FLT_MAX. (#2024)
52+
- Window: Resizing from edges (with io.ConfigResizeWindowsFromEdges Beta flag) extends the hit region
53+
of root floating windows outside the window, making it easier to resize windows. Resize grips are also
54+
extended accordingly so there are no discontinuity when hovering between borders and corners. (#1495, #822)
5255
- BeginChild(): Fixed BeginChild(const char*, ...) variation erroneously not applying the ID stack
5356
to the provided string to uniquely identify the child window. This was undoing an intentional change
5457
introduced in 1.50 and broken in 1.60. (#1698, #894, #713).

imgui.cpp

+39-25
Original file line numberDiff line numberDiff line change
@@ -889,8 +889,12 @@ CODE
889889
#endif
890890

891891
// When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch.
892-
static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in
893-
static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear
892+
static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in
893+
static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear
894+
895+
// Window resizing from edges (when io.ConfigResizeWindowsFromEdges = true)
896+
static const float RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow().
897+
static const float RESIZE_WINDOWS_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
894898

895899
//-------------------------------------------------------------------------
896900
// [SECTION] FORWARD DECLARATIONS
@@ -3698,6 +3702,8 @@ static void FindHoveredWindow()
36983702
if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoInputs))
36993703
hovered_window = g.MovingWindow;
37003704

3705+
ImVec2 padding_regular = g.Style.TouchExtraPadding;
3706+
ImVec2 padding_for_resize_from_edges = g.IO.ConfigResizeWindowsFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS, RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS)) : padding_regular;
37013707
for (int i = g.Windows.Size - 1; i >= 0 && hovered_window == NULL; i--)
37023708
{
37033709
ImGuiWindow* window = g.Windows[i];
@@ -3707,14 +3713,19 @@ static void FindHoveredWindow()
37073713
continue;
37083714

37093715
// Using the clipped AABB, a child window will typically be clipped by its parent (not always)
3710-
ImRect bb(window->OuterRectClipped.Min - g.Style.TouchExtraPadding, window->OuterRectClipped.Max + g.Style.TouchExtraPadding);
3711-
if (bb.Contains(g.IO.MousePos))
3712-
{
3713-
if (hovered_window == NULL)
3714-
hovered_window = window;
3715-
if (hovered_window)
3716-
break;
3717-
}
3716+
ImRect bb(window->OuterRectClipped);
3717+
if ((window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_NoResize))
3718+
bb.Expand(padding_regular);
3719+
else
3720+
bb.Expand(padding_for_resize_from_edges);
3721+
if (!bb.Contains(g.IO.MousePos))
3722+
continue;
3723+
3724+
// Those seemingly unnecessary extra tests are because the code here is a little different in viewport/docking branches.
3725+
if (hovered_window == NULL)
3726+
hovered_window = window;
3727+
if (hovered_window)
3728+
break;
37183729
}
37193730

37203731
g.HoveredWindow = hovered_window;
@@ -4367,10 +4378,10 @@ static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_
43674378
{
43684379
ImRect rect = window->Rect();
43694380
if (thickness == 0.0f) rect.Max -= ImVec2(1,1);
4370-
if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y, rect.Max.x - perp_padding, rect.Min.y + thickness);
4371-
if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x, rect.Max.y - perp_padding);
4372-
if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y);
4373-
if (border_n == 3) return ImRect(rect.Min.x, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding);
4381+
if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness);
4382+
if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding);
4383+
if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness);
4384+
if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding);
43744385
IM_ASSERT(0);
43754386
return ImRect();
43764387
}
@@ -4382,10 +4393,13 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
43824393
ImGuiWindowFlags flags = window->Flags;
43834394
if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
43844395
return;
4396+
if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit Debug window.
4397+
return;
43854398

43864399
const int resize_border_count = g.IO.ConfigResizeWindowsFromEdges ? 4 : 0;
43874400
const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
4388-
const float grip_hover_size = (float)(int)(grip_draw_size * 0.75f);
4401+
const float grip_hover_inner_size = (float)(int)(grip_draw_size * 0.75f);
4402+
const float grip_hover_outer_size = g.IO.ConfigResizeWindowsFromEdges ? RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS : 0.0f;
43894403

43904404
ImVec2 pos_target(FLT_MAX, FLT_MAX);
43914405
ImVec2 size_target(FLT_MAX, FLT_MAX);
@@ -4398,11 +4412,12 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
43984412
const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos);
43994413

44004414
// Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
4401-
ImRect resize_rect(corner, corner + grip.InnerDir * grip_hover_size);
4415+
ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size);
44024416
if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
44034417
if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
44044418
bool hovered, held;
44054419
ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
4420+
//GetOverlayDrawList()->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
44064421
if (hovered || held)
44074422
g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
44084423

@@ -4416,20 +4431,19 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
44164431
{
44174432
// Resize from any of the four corners
44184433
// We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
4419-
ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize() * grip.CornerPos; // Corner of the window corresponding to our corner grip
4434+
ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPos); // Corner of the window corresponding to our corner grip
44204435
CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPos, &pos_target, &size_target);
44214436
}
44224437
if (resize_grip_n == 0 || held || hovered)
44234438
resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
44244439
}
44254440
for (int border_n = 0; border_n < resize_border_count; border_n++)
44264441
{
4427-
const float BORDER_SIZE = 5.0f; // FIXME: Only works _inside_ window because of HoveredWindow check.
4428-
const float BORDER_APPEAR_TIMER = 0.05f; // Reduce visual noise
44294442
bool hovered, held;
4430-
ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_size, BORDER_SIZE);
4443+
ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS);
44314444
ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
4432-
if ((hovered && g.HoveredIdTimer > BORDER_APPEAR_TIMER) || held)
4445+
//GetOverlayDrawList()->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
4446+
if ((hovered && g.HoveredIdTimer > RESIZE_WINDOWS_FROM_EDGES_FEEDBACK_TIMER) || held)
44334447
{
44344448
g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
44354449
if (held) *border_held = border_n;
@@ -4438,10 +4452,10 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
44384452
{
44394453
ImVec2 border_target = window->Pos;
44404454
ImVec2 border_posn;
4441-
if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y); }
4442-
if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + BORDER_SIZE); }
4443-
if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + BORDER_SIZE); }
4444-
if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x); }
4455+
if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); }
4456+
if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); }
4457+
if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); }
4458+
if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); }
44454459
CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
44464460
}
44474461
}

0 commit comments

Comments
 (0)