mirror of
https://github.com/ocornut/imgui.git
synced 2024-12-03 21:59:15 +08:00
Viewport: Clamp windows within monitors + fallback rescue window when it is out of sight (e.g. removed monitor, changed resolution) + Win32: declare primary monitor at the beginning of the list. (#1542)
This commit is contained in:
parent
010757266e
commit
376f2aec54
1
TODO.txt
1
TODO.txt
@ -259,7 +259,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
|
||||
- focus: unable to use SetKeyboardFocusHere() on clipped widgets. (#787)
|
||||
|
||||
- viewport: popup/tooltip glitches when appearing near the monitor limits (e.g. opening a menu).
|
||||
- viewport: clamp windows position within monitors (especially important on monitor configuration change) -> clamp to closest rectangle.
|
||||
- viewport: platform: introduce getfocus/setfocus api, so e.g. focus flags can be honored, imgui-side ctrl-tab can focus os window, OS alt-tab can focus imgui window etc.
|
||||
- viewport: store per-viewport/monitor DPI in .ini file so an application reload or main window changing DPI on reload can be properly patched for.
|
||||
- viewport: IME positioning are wrong.
|
||||
|
@ -578,7 +578,11 @@ static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, H
|
||||
imgui_monitor.WorkMin = ImVec2((float)info.rcWork.left, (float)info.rcWork.top);
|
||||
imgui_monitor.WorkMax = ImVec2((float)info.rcWork.right, (float)info.rcWork.bottom);
|
||||
imgui_monitor.DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
|
||||
ImGui::GetPlatformIO().Monitors.push_back(imgui_monitor);
|
||||
ImGuiPlatformIO& io = ImGui::GetPlatformIO();
|
||||
if (info.dwFlags & MONITORINFOF_PRIMARY)
|
||||
io.Monitors.push_front(imgui_monitor);
|
||||
else
|
||||
io.Monitors.push_back(imgui_monitor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
64
imgui.cpp
64
imgui.cpp
@ -832,7 +832,7 @@ ImGuiStyle::ImGuiStyle()
|
||||
GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar
|
||||
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
|
||||
ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
|
||||
DisplayWindowPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
|
||||
DisplayWindowPadding = ImVec2(20,20); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
|
||||
DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
|
||||
MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
|
||||
AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
|
||||
@ -3817,6 +3817,8 @@ void ImGui::NewFrame()
|
||||
// Disable feature, our back-ends do not support it
|
||||
g.IO.ConfigFlags &= ~ImGuiConfigFlags_ViewportsEnable;
|
||||
}
|
||||
|
||||
// Perform simple checks on platform monitor data + compute a total bounding box for quick early outs
|
||||
for (int monitor_n = 0; monitor_n < g.PlatformIO.Monitors.Size; monitor_n++)
|
||||
{
|
||||
ImGuiPlatformMonitor& mon = g.PlatformIO.Monitors[monitor_n];
|
||||
@ -6122,13 +6124,37 @@ static int FindPlatformMonitorForPos(ImVec2 platform_pos)
|
||||
ImGuiContext& g = *GImGui;
|
||||
for (int monitor_n = 0; monitor_n < g.PlatformIO.Monitors.Size; monitor_n++)
|
||||
{
|
||||
const ImGuiPlatformMonitor* monitor = &g.PlatformIO.Monitors[monitor_n];
|
||||
if (ImRect(monitor->FullMin, monitor->FullMax).Contains(platform_pos))
|
||||
const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[monitor_n];
|
||||
if (ImRect(monitor.FullMin, monitor.FullMax).Contains(platform_pos))
|
||||
return monitor_n;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Search for the monitor with the largest intersection area with the given rectangle
|
||||
// We generally try to avoid searching loops but the monitor count should be very small here
|
||||
static int FindPlatformMonitorForRect(const ImRect& rect)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
float surface_threshold = rect.GetWidth() * rect.GetHeight() * 0.5f;
|
||||
int best_monitor_n = -1;
|
||||
float best_monitor_surface = 0.001f;
|
||||
for (int monitor_n = 0; monitor_n < g.PlatformIO.Monitors.Size && best_monitor_surface < surface_threshold; monitor_n++)
|
||||
{
|
||||
const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[monitor_n];
|
||||
if (ImRect(monitor.FullMin, monitor.FullMax).Contains(rect))
|
||||
return monitor_n;
|
||||
ImRect overlapping_rect = rect;
|
||||
overlapping_rect.ClipWithFull(ImRect(monitor.FullMin, monitor.FullMax));
|
||||
float overlapping_surface = overlapping_rect.GetWidth() * overlapping_rect.GetHeight();
|
||||
if (overlapping_surface < best_monitor_surface)
|
||||
continue;
|
||||
best_monitor_surface = overlapping_surface;
|
||||
best_monitor_n = monitor_n;
|
||||
}
|
||||
return best_monitor_n;
|
||||
}
|
||||
|
||||
// FIXME-VIEWPORT: This is all super messy and ought to be clarified or rewritten.
|
||||
static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
|
||||
{
|
||||
@ -6367,6 +6393,11 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
|
||||
window->Size = window->SizeFull;
|
||||
}
|
||||
|
||||
static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, const ImVec2& padding)
|
||||
{
|
||||
window->PosFloat = ImMin(rect.Max - padding, ImMax(window->PosFloat + window->Size, rect.Min + padding) - window->Size);
|
||||
}
|
||||
|
||||
// Push a new ImGui window to add widgets to.
|
||||
// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.
|
||||
// - Begin/End can be called multiple times during the frame with the same window name to append content.
|
||||
@ -6680,17 +6711,29 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
window->Viewport->Flags |= ImGuiViewportFlags_NoRendererClear;
|
||||
}
|
||||
|
||||
// Clamp position so window stays visible within its viewport
|
||||
// Clamp position so window stays visible within its viewport or monitor
|
||||
// Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
|
||||
ImRect viewport_rect = window->Viewport->GetRect();
|
||||
if (!window->ViewportOwned && !window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
|
||||
if (viewport_rect.GetWidth() > 0 && viewport_rect.GetHeight() > 0.0f)
|
||||
if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
|
||||
{
|
||||
ImVec2 clamp_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
|
||||
if (!window->ViewportOwned && viewport_rect.GetWidth() > 0 && viewport_rect.GetHeight() > 0.0f)
|
||||
ClampWindowRect(window, viewport_rect, clamp_padding);
|
||||
else if (window->ViewportOwned && g.PlatformIO.Monitors.Size > 0)
|
||||
{
|
||||
ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
|
||||
window->PosFloat = ImMax(window->PosFloat + window->Size, viewport_rect.Min + padding) - window->Size;
|
||||
window->PosFloat = ImMin(window->PosFloat, viewport_rect.Max - padding);
|
||||
int monitor_n = FindPlatformMonitorForRect(viewport_rect);
|
||||
if (monitor_n == -1)
|
||||
{
|
||||
// Fallback for "lost" window (e.g. a monitor disconnected): we move the window back over the main viewport
|
||||
window->PosFloat = g.Viewports[0]->Pos + style.DisplayWindowPadding;
|
||||
window->ViewportTryMerge = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClampWindowRect(window, ImRect(g.PlatformIO.Monitors[monitor_n].WorkMin, g.PlatformIO.Monitors[monitor_n].WorkMax), clamp_padding);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
window->Pos = ImFloor(window->PosFloat);
|
||||
|
||||
// Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
|
||||
@ -14208,6 +14251,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
else
|
||||
ImGui::BulletText("NavRectRel[0]: <None>");
|
||||
ImGui::BulletText("Viewport: %d, ViewportId: 0x%08X, ViewportPlatformPos: (%.1f,%.1f)", window->Viewport ? window->Viewport->Idx : -1, window->ViewportId, window->ViewportPos.x, window->ViewportPos.y);
|
||||
ImGui::BulletText("Monitor: %d", FindPlatformMonitorForRect(window->Rect()));
|
||||
if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
|
||||
if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
|
||||
if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
|
||||
|
2
imgui.h
2
imgui.h
@ -1004,7 +1004,7 @@ struct ImGuiStyle
|
||||
float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar.
|
||||
float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
|
||||
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered.
|
||||
ImVec2 DisplayWindowPadding; // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
|
||||
ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
|
||||
ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly!
|
||||
float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
|
||||
bool AntiAliasedLines; // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU.
|
||||
|
Loading…
Reference in New Issue
Block a user