17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-04 01:52:05 +01:00

Merge pull request #236 from MaSzyna-EU07/fix/imgui-panels-no-auto-detach

fix(ui): keep panels in the main window when resizing them at the scr…
This commit is contained in:
maj00r
2026-11-04 01:08:30 +01:00
committed by GitHub
3 changed files with 59 additions and 2 deletions

View File

@@ -403,6 +403,8 @@ bool ui_layer::init(GLFWwindow *Window)
{
m_imguiio->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
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()};
imgui_create_window = platformio.Platform_CreateWindow;
platformio.Platform_CreateWindow = create_viewport_window;

View File

@@ -1294,6 +1294,7 @@ static void WindowSelectViewport(ImGuiWindow* window);
static void WindowSyncOwnedViewport(ImGuiWindow* window, ImGuiWindow* parent_window_in_stack);
static bool UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* host_viewport);
static bool UpdateTryMergeWindowIntoHostViewports(ImGuiWindow* window);
static bool WindowStaysInHostViewport(ImGuiWindow* window, ImGuiViewportP* viewport); // MaSzyna addition
static bool GetWindowAlwaysWantOwnViewport(ImGuiWindow* window);
static int FindPlatformMonitorForPos(const ImVec2& pos);
static int FindPlatformMonitorForRect(const ImRect& r);
@@ -1489,6 +1490,7 @@ ImGuiIO::ImGuiIO()
ConfigViewportsNoTaskBarIcon = false;
ConfigViewportsNoDecoration = true;
ConfigViewportsNoDefaultParent = false;
ConfigViewportsNoAutoDetach = false;
// Miscellaneous options
MouseDrawCursor = false;
@@ -6845,6 +6847,11 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
ImVec2 pos_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).
// - 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.
@@ -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 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, resize_limit_rect.Min, resize_limit_rect.Max);
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_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[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
{
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);
}
// 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)
{
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.
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)
//ImGuiViewport* old_viewport = window->Viewport;
@@ -7878,6 +7911,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
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);
// 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;
}
// 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)
{
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
if (window->Viewport == NULL)
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
if (!lock_viewport)

View File

@@ -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 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 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
// (you can visualize and interact with all options in 'Demo->Configuration')