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. (#1495, #822, #2110)

This commit is contained in:
omar 2018-10-02 18:43:10 +02:00
parent 76e31bd51a
commit ae7f833c69
2 changed files with 42 additions and 25 deletions

View File

@ -49,6 +49,9 @@ Other Changes:
erroneously wrapped the value to one of the min/max edge. (#2024, #708, #320, #2075). erroneously wrapped the value to one of the min/max edge. (#2024, #708, #320, #2075).
- DragFloat: Disabled using power curve when one edge is FLT_MAX (broken in 1.61). (#2024) - DragFloat: Disabled using power curve when one edge is FLT_MAX (broken in 1.61). (#2024)
- DragFloat: Disabled setting a default drag speed when one edge is FLT_MAX. (#2024) - DragFloat: Disabled setting a default drag speed when one edge is FLT_MAX. (#2024)
- 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. (#1495, #822)
- BeginChild(): Fixed BeginChild(const char*, ...) variation erroneously not applying the ID stack - BeginChild(): Fixed BeginChild(const char*, ...) variation erroneously not applying the ID stack
to the provided string to uniquely identify the child window. This was undoing an intentional change to the provided string to uniquely identify the child window. This was undoing an intentional change
introduced in 1.50 and broken in 1.60. (#1698, #894, #713). introduced in 1.50 and broken in 1.60. (#1698, #894, #713).

View File

@ -892,6 +892,10 @@ CODE
static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in
static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear
// Window resizing from edges (when io.ConfigResizeWindowsFromEdges = true)
static const float RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow().
static const float RESIZE_WINDOWS_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// [SECTION] FORWARD DECLARATIONS // [SECTION] FORWARD DECLARATIONS
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -3698,6 +3702,8 @@ static void FindHoveredWindow()
if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoInputs)) if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoInputs))
hovered_window = g.MovingWindow; hovered_window = g.MovingWindow;
ImVec2 padding_regular = g.Style.TouchExtraPadding;
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;
for (int i = g.Windows.Size - 1; i >= 0 && hovered_window == NULL; i--) for (int i = g.Windows.Size - 1; i >= 0 && hovered_window == NULL; i--)
{ {
ImGuiWindow* window = g.Windows[i]; ImGuiWindow* window = g.Windows[i];
@ -3707,15 +3713,20 @@ static void FindHoveredWindow()
continue; continue;
// Using the clipped AABB, a child window will typically be clipped by its parent (not always) // Using the clipped AABB, a child window will typically be clipped by its parent (not always)
ImRect bb(window->OuterRectClipped.Min - g.Style.TouchExtraPadding, window->OuterRectClipped.Max + g.Style.TouchExtraPadding); ImRect bb(window->OuterRectClipped);
if (bb.Contains(g.IO.MousePos)) if ((window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_NoResize))
{ bb.Expand(padding_regular);
else
bb.Expand(padding_for_resize_from_edges);
if (!bb.Contains(g.IO.MousePos))
continue;
// Those seemingly unnecessary extra tests are because the code here is a little different in viewport/docking branches.
if (hovered_window == NULL) if (hovered_window == NULL)
hovered_window = window; hovered_window = window;
if (hovered_window) if (hovered_window)
break; break;
} }
}
g.HoveredWindow = hovered_window; g.HoveredWindow = hovered_window;
g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
@ -4367,10 +4378,10 @@ static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_
{ {
ImRect rect = window->Rect(); ImRect rect = window->Rect();
if (thickness == 0.0f) rect.Max -= ImVec2(1,1); if (thickness == 0.0f) rect.Max -= ImVec2(1,1);
if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y, rect.Max.x - perp_padding, rect.Min.y + thickness); if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness);
if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x, rect.Max.y - perp_padding); if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding);
if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y); if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness);
if (border_n == 3) return ImRect(rect.Min.x, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding);
IM_ASSERT(0); IM_ASSERT(0);
return ImRect(); return ImRect();
} }
@ -4382,10 +4393,13 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
ImGuiWindowFlags flags = window->Flags; ImGuiWindowFlags flags = window->Flags;
if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
return; return;
if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit Debug window.
return;
const int resize_border_count = g.IO.ConfigResizeWindowsFromEdges ? 4 : 0; const int resize_border_count = g.IO.ConfigResizeWindowsFromEdges ? 4 : 0;
const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
const float grip_hover_size = (float)(int)(grip_draw_size * 0.75f); const float grip_hover_inner_size = (float)(int)(grip_draw_size * 0.75f);
const float grip_hover_outer_size = g.IO.ConfigResizeWindowsFromEdges ? RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS : 0.0f;
ImVec2 pos_target(FLT_MAX, FLT_MAX); ImVec2 pos_target(FLT_MAX, FLT_MAX);
ImVec2 size_target(FLT_MAX, FLT_MAX); ImVec2 size_target(FLT_MAX, FLT_MAX);
@ -4398,11 +4412,12 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos); const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos);
// Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
ImRect resize_rect(corner, corner + grip.InnerDir * grip_hover_size); ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size);
if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x); if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y); if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
bool hovered, held; bool hovered, held;
ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
//GetOverlayDrawList()->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
if (hovered || held) if (hovered || held)
g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
@ -4416,7 +4431,7 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
{ {
// Resize from any of the four corners // Resize from any of the four corners
// We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize() * grip.CornerPos; // Corner of the window corresponding to our corner grip 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
CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPos, &pos_target, &size_target); CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPos, &pos_target, &size_target);
} }
if (resize_grip_n == 0 || held || hovered) if (resize_grip_n == 0 || held || hovered)
@ -4424,12 +4439,11 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
} }
for (int border_n = 0; border_n < resize_border_count; border_n++) for (int border_n = 0; border_n < resize_border_count; border_n++)
{ {
const float BORDER_SIZE = 5.0f; // FIXME: Only works _inside_ window because of HoveredWindow check.
const float BORDER_APPEAR_TIMER = 0.05f; // Reduce visual noise
bool hovered, held; bool hovered, held;
ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_size, BORDER_SIZE); ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS);
ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren); ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
if ((hovered && g.HoveredIdTimer > BORDER_APPEAR_TIMER) || held) //GetOverlayDrawList()->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
if ((hovered && g.HoveredIdTimer > RESIZE_WINDOWS_FROM_EDGES_FEEDBACK_TIMER) || held)
{ {
g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
if (held) *border_held = border_n; if (held) *border_held = border_n;
@ -4438,10 +4452,10 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
{ {
ImVec2 border_target = window->Pos; ImVec2 border_target = window->Pos;
ImVec2 border_posn; ImVec2 border_posn;
if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y); } 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); }
if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + BORDER_SIZE); } 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); }
if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + BORDER_SIZE); } 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); }
if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x); } 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); }
CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
} }
} }