diff --git a/imgui.cpp b/imgui.cpp index 4633754e5..1e02c839e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -56,6 +56,7 @@ CODE - Main Code (most of the code! lots of stuff, needs tidying up) - Tooltips - Popups +- Viewports, Platform Windows - Navigation - Columns - Drag and Drop @@ -911,7 +912,6 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, // Platform Dependents default implementation for IO functions static const char* GetClipboardTextFn_DefaultImpl(void* user_data); static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); -static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); namespace ImGui { @@ -3582,53 +3582,6 @@ void ImGui::Render() #endif } -ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImVec2& pos, const ImVec2& size, ImGuiViewportFlags flags) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(id != 0); - - ImGuiViewportP* viewport = (ImGuiViewportP*)FindViewportByID(id); - if (viewport) - { - viewport->Pos = pos; - viewport->Size = size; - } - else - { - // New viewport - viewport = IM_NEW(ImGuiViewportP)(); - viewport->ID = id; - viewport->Idx = g.Viewports.Size; - viewport->Pos = viewport->LastPos = pos; - viewport->Size = size; - viewport->PlatformMonitor = FindPlatformMonitorForRect(viewport->GetRect()); - g.Viewports.push_back(viewport); - - if (window && (window->Flags & ImGuiWindowFlags_NoFocusOnAppearing)) - flags |= ImGuiViewportFlags_NoFocusOnAppearing; - - // We normally setup for all viewports in NewFrame() but here need to handle the mid-frame creation of a new viewport. - // We need to extend the fullscreen clip rect so the OverlayDrawList clip is correct for that the first frame - g.DrawListSharedData.ClipRectFullscreen.z = ImMax(g.DrawListSharedData.ClipRectFullscreen.z, viewport->Pos.x + viewport->Size.x); - g.DrawListSharedData.ClipRectFullscreen.w = ImMax(g.DrawListSharedData.ClipRectFullscreen.w, viewport->Pos.y + viewport->Size.y); - - // Request an initial DpiScale before the OS platform window creation - // This is so we can select an appropriate font size on the first frame of our window lifetime - if (g.PlatformIO.Platform_GetWindowDpiScale) - viewport->DpiScale = g.PlatformIO.Platform_GetWindowDpiScale(viewport); - } - - viewport->Window = window; - viewport->Flags = flags; - viewport->LastFrameActive = g.FrameCount; - IM_ASSERT(window == NULL || viewport->ID == window->ID); - - if (window != NULL) - window->ViewportOwned = true; - - return viewport; -} - const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) { const char* text_display_end = text; @@ -4636,118 +4589,6 @@ static int ImGui::FindPlatformMonitorForRect(const ImRect& rect) return best_monitor_n; } -// FIXME-VIEWPORT: This is all super messy and ought to be clarified or rewritten. -static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - ImGuiWindowFlags flags = window->Flags; - window->ViewportAllowPlatformMonitorExtend = -1; - - // Restore main viewport if multi-viewport is not supported by the back-end - ImGuiViewportP* main_viewport = g.Viewports[0]; - if (!(g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) - { - window->Viewport = main_viewport; - window->ViewportId = main_viewport->ID; - window->ViewportOwned = false; - return; - } - - // Merge into host viewports (after moving, resizing) - if (window->ViewportOwned && window->ViewportTryMerge && g.ActiveId == 0) - { - UpdateTryMergeWindowIntoHostViewport(window, g.Viewports[0]); - window->ViewportTryMerge = false; - } - window->ViewportOwned = false; - - // Appearing popups reset their viewport so they can inherit again - if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && window->Appearing) - { - window->Viewport = NULL; - window->ViewportId = 0; - } - - if (!g.NextWindowData.ViewportCond) - { - // By default inherit from parent window - if (window->Viewport == NULL && window->ParentWindow) - window->Viewport = window->ParentWindow->Viewport; - - // Attempt to restore saved viewport id (= window that hasn't been activated yet), try to restore the viewport based on saved 'window->ViewportPos' restored from .ini file - if (window->Viewport == NULL && window->ViewportId != 0) - { - window->Viewport = FindViewportByID(window->ViewportId); - if (window->Viewport == NULL && window->ViewportPos.x != FLT_MAX && window->ViewportPos.y != FLT_MAX) - window->Viewport = AddUpdateViewport(window, window->ID, window->ViewportPos, window->Size, ImGuiViewportFlags_NoDecoration); - } - } - - if (g.NextWindowData.ViewportCond) - { - // Code explicitly request a viewport - window->Viewport = FindViewportByID(g.NextWindowData.ViewportId); - window->ViewportId = g.NextWindowData.ViewportId; // Store ID even if Viewport isn't resolved yet. - } - else if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ChildMenu)) - { - // Always inherit viewport from parent window - window->Viewport = window->ParentWindow->Viewport; - } - else if (flags & ImGuiWindowFlags_Tooltip) - { - window->Viewport = g.MouseViewport; - } - else if (g.MovingWindow && g.MovingWindow->RootWindow == window && IsMousePosValid()) - { - // Transition to our own viewport when leaving our host boundaries + set the NoInputs flag (which will be cleared in UpdateMovingWindow when releasing the mouse) - // If we are already in our own viewport, if need to set the NoInputs flag. - // If we have no viewport (which happens when detaching a docked node) immediately create one. - // We test for 'window->Viewport->Window == window' instead of 'window->ViewportOwned' because ViewportOwned is not valid during this function. - bool has_viewport = (window->Viewport != NULL); - bool own_viewport = has_viewport && (window->Viewport->Window == window); - bool leave_host_viewport = has_viewport && !own_viewport && !window->Viewport->GetRect().Contains(window->Rect()); - bool move_from_own_viewport = has_viewport && own_viewport && !(window->Viewport->Flags & ImGuiViewportFlags_NoInputs); - if (!has_viewport || leave_host_viewport || move_from_own_viewport) - window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_NoDecoration | ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoInputs); - } - else if (GetWindowAlwaysWantOwnViewport(window)) - { - window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_NoDecoration); - } - - // Mark window as allowed to protrude outside of its viewport and into the current monitor - // We need to take account of the possibility that mouse may become invalid. - const bool use_mouse_ref = (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow); - if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) - { - ImVec2 mouse_ref = (flags & ImGuiWindowFlags_Tooltip) ? g.IO.MousePos : g.CurrentPopupStack.back().OpenMousePos; - bool mouse_valid = IsMousePosValid(&mouse_ref); - if ((window->Appearing || (flags & ImGuiWindowFlags_Tooltip)) && (!use_mouse_ref || mouse_valid)) - window->ViewportAllowPlatformMonitorExtend = FindPlatformMonitorForPos((use_mouse_ref && mouse_valid) ? mouse_ref : NavCalcPreferredRefPos()); - else - window->ViewportAllowPlatformMonitorExtend = window->Viewport->PlatformMonitor; - } - if (window->ViewportTrySplit && window->ViewportAllowPlatformMonitorExtend < 0) - window->ViewportAllowPlatformMonitorExtend = window->Viewport->PlatformMonitor; - window->ViewportTrySplit = false; - - // Fallback to default viewport - if (window->Viewport == NULL) - window->Viewport = main_viewport; - - // Update flags - window->ViewportOwned = (window == window->Viewport->Window); - if (window->ViewportOwned) - window->Viewport->Flags |= ImGuiViewportFlags_NoDecoration; - - // If the OS window has a title bar, hide our imgui title bar - if (window->ViewportOwned && !(window->Viewport->Flags & ImGuiViewportFlags_NoDecoration)) - window->Flags |= ImGuiWindowFlags_NoTitleBar; - - window->ViewportId = window->Viewport->ID; -} - struct ImGuiResizeGripDef { ImVec2 CornerPos; @@ -7619,6 +7460,165 @@ static void ImGui::UpdateViewports() IM_ASSERT(g.MouseViewport != NULL); } +ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImVec2& pos, const ImVec2& size, ImGuiViewportFlags flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(id != 0); + + ImGuiViewportP* viewport = (ImGuiViewportP*)FindViewportByID(id); + if (viewport) + { + viewport->Pos = pos; + viewport->Size = size; + } + else + { + // New viewport + viewport = IM_NEW(ImGuiViewportP)(); + viewport->ID = id; + viewport->Idx = g.Viewports.Size; + viewport->Pos = viewport->LastPos = pos; + viewport->Size = size; + viewport->PlatformMonitor = FindPlatformMonitorForRect(viewport->GetRect()); + g.Viewports.push_back(viewport); + + if (window && (window->Flags & ImGuiWindowFlags_NoFocusOnAppearing)) + flags |= ImGuiViewportFlags_NoFocusOnAppearing; + + // We normally setup for all viewports in NewFrame() but here need to handle the mid-frame creation of a new viewport. + // We need to extend the fullscreen clip rect so the OverlayDrawList clip is correct for that the first frame + g.DrawListSharedData.ClipRectFullscreen.z = ImMax(g.DrawListSharedData.ClipRectFullscreen.z, viewport->Pos.x + viewport->Size.x); + g.DrawListSharedData.ClipRectFullscreen.w = ImMax(g.DrawListSharedData.ClipRectFullscreen.w, viewport->Pos.y + viewport->Size.y); + + // Request an initial DpiScale before the OS platform window creation + // This is so we can select an appropriate font size on the first frame of our window lifetime + if (g.PlatformIO.Platform_GetWindowDpiScale) + viewport->DpiScale = g.PlatformIO.Platform_GetWindowDpiScale(viewport); + } + + viewport->Window = window; + viewport->Flags = flags; + viewport->LastFrameActive = g.FrameCount; + IM_ASSERT(window == NULL || viewport->ID == window->ID); + + if (window != NULL) + window->ViewportOwned = true; + + return viewport; +} + +// FIXME-VIEWPORT: This is all super messy and ought to be clarified or rewritten. +static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + ImGuiWindowFlags flags = window->Flags; + window->ViewportAllowPlatformMonitorExtend = -1; + + // Restore main viewport if multi-viewport is not supported by the back-end + ImGuiViewportP* main_viewport = g.Viewports[0]; + if (!(g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) + { + window->Viewport = main_viewport; + window->ViewportId = main_viewport->ID; + window->ViewportOwned = false; + return; + } + + // Merge into host viewports (after moving, resizing) + if (window->ViewportOwned && window->ViewportTryMerge && g.ActiveId == 0) + { + UpdateTryMergeWindowIntoHostViewport(window, g.Viewports[0]); + window->ViewportTryMerge = false; + } + window->ViewportOwned = false; + + // Appearing popups reset their viewport so they can inherit again + if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && window->Appearing) + { + window->Viewport = NULL; + window->ViewportId = 0; + } + + if (!g.NextWindowData.ViewportCond) + { + // By default inherit from parent window + if (window->Viewport == NULL && window->ParentWindow) + window->Viewport = window->ParentWindow->Viewport; + + // Attempt to restore saved viewport id (= window that hasn't been activated yet), try to restore the viewport based on saved 'window->ViewportPos' restored from .ini file + if (window->Viewport == NULL && window->ViewportId != 0) + { + window->Viewport = FindViewportByID(window->ViewportId); + if (window->Viewport == NULL && window->ViewportPos.x != FLT_MAX && window->ViewportPos.y != FLT_MAX) + window->Viewport = AddUpdateViewport(window, window->ID, window->ViewportPos, window->Size, ImGuiViewportFlags_NoDecoration); + } + } + + if (g.NextWindowData.ViewportCond) + { + // Code explicitly request a viewport + window->Viewport = FindViewportByID(g.NextWindowData.ViewportId); + window->ViewportId = g.NextWindowData.ViewportId; // Store ID even if Viewport isn't resolved yet. + } + else if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ChildMenu)) + { + // Always inherit viewport from parent window + window->Viewport = window->ParentWindow->Viewport; + } + else if (flags & ImGuiWindowFlags_Tooltip) + { + window->Viewport = g.MouseViewport; + } + else if (g.MovingWindow && g.MovingWindow->RootWindow == window && IsMousePosValid()) + { + // Transition to our own viewport when leaving our host boundaries + set the NoInputs flag (which will be cleared in UpdateMovingWindow when releasing the mouse) + // If we are already in our own viewport, if need to set the NoInputs flag. + // If we have no viewport (which happens when detaching a docked node) immediately create one. + // We test for 'window->Viewport->Window == window' instead of 'window->ViewportOwned' because ViewportOwned is not valid during this function. + bool has_viewport = (window->Viewport != NULL); + bool own_viewport = has_viewport && (window->Viewport->Window == window); + bool leave_host_viewport = has_viewport && !own_viewport && !window->Viewport->GetRect().Contains(window->Rect()); + bool move_from_own_viewport = has_viewport && own_viewport && !(window->Viewport->Flags & ImGuiViewportFlags_NoInputs); + if (!has_viewport || leave_host_viewport || move_from_own_viewport) + window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_NoDecoration | ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoInputs); + } + else if (GetWindowAlwaysWantOwnViewport(window)) + { + window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_NoDecoration); + } + + // Mark window as allowed to protrude outside of its viewport and into the current monitor + // We need to take account of the possibility that mouse may become invalid. + const bool use_mouse_ref = (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow); + if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) + { + ImVec2 mouse_ref = (flags & ImGuiWindowFlags_Tooltip) ? g.IO.MousePos : g.CurrentPopupStack.back().OpenMousePos; + bool mouse_valid = IsMousePosValid(&mouse_ref); + if ((window->Appearing || (flags & ImGuiWindowFlags_Tooltip)) && (!use_mouse_ref || mouse_valid)) + window->ViewportAllowPlatformMonitorExtend = FindPlatformMonitorForPos((use_mouse_ref && mouse_valid) ? mouse_ref : NavCalcPreferredRefPos()); + else + window->ViewportAllowPlatformMonitorExtend = window->Viewport->PlatformMonitor; + } + if (window->ViewportTrySplit && window->ViewportAllowPlatformMonitorExtend < 0) + window->ViewportAllowPlatformMonitorExtend = window->Viewport->PlatformMonitor; + window->ViewportTrySplit = false; + + // Fallback to default viewport + if (window->Viewport == NULL) + window->Viewport = main_viewport; + + // Update flags + window->ViewportOwned = (window == window->Viewport->Window); + if (window->ViewportOwned) + window->Viewport->Flags |= ImGuiViewportFlags_NoDecoration; + + // If the OS window has a title bar, hide our imgui title bar + if (window->ViewportOwned && !(window->Viewport->Flags & ImGuiViewportFlags_NoDecoration)) + window->Flags |= ImGuiWindowFlags_NoTitleBar; + + window->ViewportId = window->Viewport->ID; +} + void ImGui::UpdatePlatformWindows() { ImGuiContext& g = *GImGui;