mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-04 06:44:01 +01:00
fix(ui): keep panels in the main window when resizing them at the screen edge
Pulling a panel's grip into the corner of the screen pushed it a couple of pixels past the main window, and ImGui gave it an OS window of its own. Now a panel only comes out when dragged with the cursor outside the main window. A panel that stays in the main window needs its grips in reach, so a resize stops at the edge, and a panel left past the edge or too big for the window is moved back and shrunk to fit. This is a new io.ConfigViewportsNoAutoDetach option in our copy of ImGui, so it has to be carried over when ImGui gets updated. ImGui itself has no option for this, as of 1.93.1.
This commit is contained in:
@@ -403,6 +403,8 @@ bool ui_layer::init(GLFWwindow *Window)
|
|||||||
{
|
{
|
||||||
m_imguiio->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
m_imguiio->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||||
m_imguiio->ConfigViewportsNoTaskBarIcon = true;
|
m_imguiio->ConfigViewportsNoTaskBarIcon = true;
|
||||||
|
// only dragging a panel with the cursor past the main window takes it out, not resizing it or placing it at the edge
|
||||||
|
m_imguiio->ConfigViewportsNoAutoDetach = true;
|
||||||
auto &platformio{ImGui::GetPlatformIO()};
|
auto &platformio{ImGui::GetPlatformIO()};
|
||||||
imgui_create_window = platformio.Platform_CreateWindow;
|
imgui_create_window = platformio.Platform_CreateWindow;
|
||||||
platformio.Platform_CreateWindow = create_viewport_window;
|
platformio.Platform_CreateWindow = create_viewport_window;
|
||||||
|
|||||||
@@ -1294,6 +1294,7 @@ static void WindowSelectViewport(ImGuiWindow* window);
|
|||||||
static void WindowSyncOwnedViewport(ImGuiWindow* window, ImGuiWindow* parent_window_in_stack);
|
static void WindowSyncOwnedViewport(ImGuiWindow* window, ImGuiWindow* parent_window_in_stack);
|
||||||
static bool UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* host_viewport);
|
static bool UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* host_viewport);
|
||||||
static bool UpdateTryMergeWindowIntoHostViewports(ImGuiWindow* window);
|
static bool UpdateTryMergeWindowIntoHostViewports(ImGuiWindow* window);
|
||||||
|
static bool WindowStaysInHostViewport(ImGuiWindow* window, ImGuiViewportP* viewport); // MaSzyna addition
|
||||||
static bool GetWindowAlwaysWantOwnViewport(ImGuiWindow* window);
|
static bool GetWindowAlwaysWantOwnViewport(ImGuiWindow* window);
|
||||||
static int FindPlatformMonitorForPos(const ImVec2& pos);
|
static int FindPlatformMonitorForPos(const ImVec2& pos);
|
||||||
static int FindPlatformMonitorForRect(const ImRect& r);
|
static int FindPlatformMonitorForRect(const ImRect& r);
|
||||||
@@ -1489,6 +1490,7 @@ ImGuiIO::ImGuiIO()
|
|||||||
ConfigViewportsNoTaskBarIcon = false;
|
ConfigViewportsNoTaskBarIcon = false;
|
||||||
ConfigViewportsNoDecoration = true;
|
ConfigViewportsNoDecoration = true;
|
||||||
ConfigViewportsNoDefaultParent = false;
|
ConfigViewportsNoDefaultParent = false;
|
||||||
|
ConfigViewportsNoAutoDetach = false;
|
||||||
|
|
||||||
// Miscellaneous options
|
// Miscellaneous options
|
||||||
MouseDrawCursor = false;
|
MouseDrawCursor = false;
|
||||||
@@ -6845,6 +6847,11 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
|
|||||||
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);
|
||||||
|
|
||||||
|
// MaSzyna addition: a resize stops at the edge of the host viewport, so the grips and borders can still be reached
|
||||||
|
ImRect resize_limit_rect(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX);
|
||||||
|
if (!window->ViewportOwned && WindowStaysInHostViewport(window, window->Viewport))
|
||||||
|
resize_limit_rect = window->Viewport->GetWorkRect();
|
||||||
|
|
||||||
// Clip mouse interaction rectangles within the viewport rectangle (in practice the narrowing is going to happen most of the time).
|
// Clip mouse interaction rectangles within the viewport rectangle (in practice the narrowing is going to happen most of the time).
|
||||||
// - Not narrowing would mostly benefit the situation where OS windows _without_ decoration have a threshold for hovering when outside their limits.
|
// - Not narrowing would mostly benefit the situation where OS windows _without_ decoration have a threshold for hovering when outside their limits.
|
||||||
// This is however not the case with current backends under Win32, but a custom borderless window implementation would benefit from it.
|
// This is however not the case with current backends under Win32, but a custom borderless window implementation would benefit from it.
|
||||||
@@ -6892,6 +6899,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
|
|||||||
ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? clamp_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? clamp_rect.Max.y : +FLT_MAX);
|
ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? clamp_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? clamp_rect.Max.y : +FLT_MAX);
|
||||||
ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip
|
ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip
|
||||||
corner_target = ImClamp(corner_target, clamp_min, clamp_max);
|
corner_target = ImClamp(corner_target, clamp_min, clamp_max);
|
||||||
|
corner_target = ImClamp(corner_target, resize_limit_rect.Min, resize_limit_rect.Max);
|
||||||
CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target);
|
CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6971,6 +6979,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
|
|||||||
ImVec2 clamp_min(border_n == ImGuiDir_Right ? clamp_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down || (border_n == ImGuiDir_Up && window_move_from_title_bar) ? clamp_rect.Min.y : -FLT_MAX);
|
ImVec2 clamp_min(border_n == ImGuiDir_Right ? clamp_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down || (border_n == ImGuiDir_Up && window_move_from_title_bar) ? clamp_rect.Min.y : -FLT_MAX);
|
||||||
ImVec2 clamp_max(border_n == ImGuiDir_Left ? clamp_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? clamp_rect.Max.y : +FLT_MAX);
|
ImVec2 clamp_max(border_n == ImGuiDir_Left ? clamp_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? clamp_rect.Max.y : +FLT_MAX);
|
||||||
border_target = ImClamp(border_target, clamp_min, clamp_max);
|
border_target = ImClamp(border_target, clamp_min, clamp_max);
|
||||||
|
border_target[axis] = ImClamp(border_target[axis], resize_limit_rect.Min[axis], resize_limit_rect.Max[axis]);
|
||||||
if (flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent
|
if (flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent
|
||||||
{
|
{
|
||||||
ImGuiWindow* parent_window = window->ParentWindow;
|
ImGuiWindow* parent_window = window->ParentWindow;
|
||||||
@@ -7056,6 +7065,30 @@ static inline void ClampWindowPos(ImGuiWindow* window, const ImRect& visibility_
|
|||||||
window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);
|
window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MaSzyna addition: see io.ConfigViewportsNoAutoDetach
|
||||||
|
static inline bool IsWindowBeingMoved(ImGuiWindow* window)
|
||||||
|
{
|
||||||
|
ImGuiContext& g = *GImGui;
|
||||||
|
return g.MovingWindow != NULL && g.MovingWindow->RootWindowDockTree == window->RootWindowDockTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaSzyna addition: a window left past the edge of its host viewport would have its grips and borders out of reach
|
||||||
|
static inline void KeepWindowInsideRect(ImGuiWindow* window, const ImRect& rect)
|
||||||
|
{
|
||||||
|
if (rect.GetWidth() <= 0.0f || rect.GetHeight() <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(window->Flags & (ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)))
|
||||||
|
{
|
||||||
|
const ImVec2 size_full = ImMin(window->SizeFull, rect.GetSize());
|
||||||
|
if (size_full.x != window->SizeFull.x || size_full.y != window->SizeFull.y)
|
||||||
|
ImGui::MarkIniSettingsDirty(window);
|
||||||
|
window->SizeFull = size_full;
|
||||||
|
window->Size = ImMin(window->Size, rect.GetSize());
|
||||||
|
}
|
||||||
|
window->Pos = ImMax(ImMin(window->Pos, rect.Max - window->Size), rect.Min);
|
||||||
|
}
|
||||||
|
|
||||||
static void RenderWindowOuterSingleBorder(ImGuiWindow* window, int border_n, ImU32 border_col, float border_size)
|
static void RenderWindowOuterSingleBorder(ImGuiWindow* window, int border_n, ImU32 border_col, float border_size)
|
||||||
{
|
{
|
||||||
const ImGuiResizeBorderDef& def = resize_border_def[border_n];
|
const ImGuiResizeBorderDef& def = resize_border_def[border_n];
|
||||||
@@ -7828,7 +7861,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||||||
|
|
||||||
// Late create viewport if we don't fit within our current host viewport.
|
// Late create viewport if we don't fit within our current host viewport.
|
||||||
if (window->ViewportAllowPlatformMonitorExtend >= 0 && !window->ViewportOwned && !(window->Viewport->Flags & ImGuiViewportFlags_IsMinimized))
|
if (window->ViewportAllowPlatformMonitorExtend >= 0 && !window->ViewportOwned && !(window->Viewport->Flags & ImGuiViewportFlags_IsMinimized))
|
||||||
if (!window->Viewport->GetMainRect().Contains(window->Rect()))
|
if (!window->Viewport->GetMainRect().Contains(window->Rect()) && !WindowStaysInHostViewport(window, window->Viewport))
|
||||||
{
|
{
|
||||||
// This is based on the assumption that the DPI will be known ahead (same as the DPI of the selection done in UpdateSelectWindowViewport)
|
// This is based on the assumption that the DPI will be known ahead (same as the DPI of the selection done in UpdateSelectWindowViewport)
|
||||||
//ImGuiViewport* old_viewport = window->Viewport;
|
//ImGuiViewport* old_viewport = window->Viewport;
|
||||||
@@ -7878,6 +7911,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||||||
ClampWindowPos(window, visibility_rect);
|
ClampWindowPos(window, visibility_rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MaSzyna addition: the host window of a floating dock node has its position set through the api, it's free to move all the same
|
||||||
|
if (!window->ViewportOwned && !IsWindowBeingMoved(window) && (!window_pos_set_by_api || (flags & ImGuiWindowFlags_DockNodeHost)) && WindowStaysInHostViewport(window, window->Viewport))
|
||||||
|
KeepWindowInsideRect(window, viewport_work_rect);
|
||||||
|
|
||||||
window->Pos = ImTrunc(window->Pos);
|
window->Pos = ImTrunc(window->Pos);
|
||||||
|
|
||||||
// Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
|
// Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
|
||||||
@@ -15780,6 +15818,22 @@ static bool ImGui::GetWindowAlwaysWantOwnViewport(ImGuiWindow* window)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MaSzyna addition: see io.ConfigViewportsNoAutoDetach
|
||||||
|
static bool ImGui::WindowStaysInHostViewport(ImGuiWindow* window, ImGuiViewportP* viewport)
|
||||||
|
{
|
||||||
|
ImGuiContext& g = *GImGui;
|
||||||
|
if (!g.IO.ConfigViewportsNoAutoDetach)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const ImGuiWindowFlags not_affected_flags = ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip;
|
||||||
|
if (window->Flags & not_affected_flags)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!IsWindowBeingMoved(window) || !IsMousePosValid())
|
||||||
|
return true;
|
||||||
|
return viewport->GetMainRect().Contains(g.IO.MousePos);
|
||||||
|
}
|
||||||
|
|
||||||
static bool ImGui::UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* viewport)
|
static bool ImGui::UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* viewport)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
@@ -16323,7 +16377,7 @@ static void ImGui::WindowSelectViewport(ImGuiWindow* window)
|
|||||||
// Fallback: merge in default viewport if z-order matches, otherwise create a new viewport
|
// Fallback: merge in default viewport if z-order matches, otherwise create a new viewport
|
||||||
if (window->Viewport == NULL)
|
if (window->Viewport == NULL)
|
||||||
if (!UpdateTryMergeWindowIntoHostViewport(window, main_viewport))
|
if (!UpdateTryMergeWindowIntoHostViewport(window, main_viewport))
|
||||||
window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_None);
|
window->Viewport = WindowStaysInHostViewport(window, main_viewport) ? main_viewport : AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_None);
|
||||||
|
|
||||||
// Mark window as allowed to protrude outside of its viewport and into the current monitor
|
// Mark window as allowed to protrude outside of its viewport and into the current monitor
|
||||||
if (!lock_viewport)
|
if (!lock_viewport)
|
||||||
|
|||||||
@@ -2360,6 +2360,7 @@ struct ImGuiIO
|
|||||||
bool ConfigViewportsNoTaskBarIcon; // = false // Disable default OS task bar icon flag for secondary viewports. When a viewport doesn't want a task bar icon, ImGuiViewportFlags_NoTaskBarIcon will be set on it.
|
bool ConfigViewportsNoTaskBarIcon; // = false // Disable default OS task bar icon flag for secondary viewports. When a viewport doesn't want a task bar icon, ImGuiViewportFlags_NoTaskBarIcon will be set on it.
|
||||||
bool ConfigViewportsNoDecoration; // = true // Disable default OS window decoration flag for secondary viewports. When a viewport doesn't want window decorations, ImGuiViewportFlags_NoDecoration will be set on it. Enabling decoration can create subsequent issues at OS levels (e.g. minimum window size).
|
bool ConfigViewportsNoDecoration; // = true // Disable default OS window decoration flag for secondary viewports. When a viewport doesn't want window decorations, ImGuiViewportFlags_NoDecoration will be set on it. Enabling decoration can create subsequent issues at OS levels (e.g. minimum window size).
|
||||||
bool ConfigViewportsNoDefaultParent; // = false // Disable default OS parenting to main viewport for secondary viewports. By default, viewports are marked with ParentViewportId = <main_viewport>, expecting the platform backend to setup a parent/child relationship between the OS windows (some backend may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows.
|
bool ConfigViewportsNoDefaultParent; // = false // Disable default OS parenting to main viewport for secondary viewports. By default, viewports are marked with ParentViewportId = <main_viewport>, expecting the platform backend to setup a parent/child relationship between the OS windows (some backend may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows.
|
||||||
|
bool ConfigViewportsNoAutoDetach; // = false // MaSzyna addition: a floating window stays inside its host viewport: a resize stops at its edge, and a window left past it, or too big for it, is moved and shrunk to fit. It gets a viewport of its own only when dragged with the mouse cursor past the host viewport. Popups and tooltips are not affected.
|
||||||
|
|
||||||
// Miscellaneous options
|
// Miscellaneous options
|
||||||
// (you can visualize and interact with all options in 'Demo->Configuration')
|
// (you can visualize and interact with all options in 'Demo->Configuration')
|
||||||
|
|||||||
Reference in New Issue
Block a user