From 07ff47bf1b7fb3dced2dc91ca39efedaff34e337 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 23 Jan 2019 19:54:36 +0100 Subject: [PATCH] Docking: Fixed various border / padding related inconsistency with dock node vs floating windows. (#2109) --- docs/TODO.txt | 5 ++--- imgui.cpp | 31 ++++++++++++++++++++----------- imgui_internal.h | 1 + imgui_widgets.cpp | 6 +++--- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index acc334a95..b32a5a0d0 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -135,8 +135,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - dock: B~ SetNextWindowDock() calls (with conditional) -> defer everything to DockContextUpdate (repro: Documents->[X]Windows->Dock 1 elsewhere->Click Redock All - dock: B~ tidy up tab list popup buttons features (available with manual tab-bar, see ImGuiTabBarFlags_NoTabListPopupButton code, not used by docking nodes) - dock: B- SetNextWindowDockId(0) with a second Begin() in the frame will asserts - - dock: B- inconsistent clipping/border 1-pixel issue (#2) - - dock: B- fix/disable auto-resize grip on split host nodes (~#2) + - dock: B: resize grip drawn in host window typically appears under scrollbar. - dock: B- SetNextWindowFocus() doesn't seem to apply if the window is hidden this frame, need repro (#4) - dock: B- resizing a dock tree small currently has glitches (overlapping collapse and close button, etc.) - dock: B- dpi: look at interaction with the hi-dpi and multi-dpi stuff. @@ -323,7 +322,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - 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: implicit/fallback Debug window can hog a zombie viewport (harmless, noisy?) > could at least clear out the reference on a per session basis? - viewport: need to clarify how to use GetMousePos() from a user point of view. - - platform: glfw: no support for ImGuiBackendFlags_HasMouseHoveredViewport. + - platform: glfw: no support for ImGuiBackendFlags_HasMouseHoveredViewport. - platform: sdl: no support for ImGuiBackendFlags_HasMouseHoveredViewport. maybe we could use SDL_GetMouseFocus() / SDL_WINDOW_MOUSE_FOCUS if imgui could fallback on its heuristic when NoInputs is set - platform: sdl: no refresh of monitor/display (SDL doesn't seem to have an event for it). - platform: sdl: multi-viewport + minimized window seems to break mouse wheel events (at least under Win32). diff --git a/imgui.cpp b/imgui.cpp index fd670da69..7d93d53da 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1046,7 +1046,7 @@ static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); static void UpdateMouseInputs(); static void UpdateMouseWheel(); static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); -static void RenderOuterBorders(ImGuiWindow* window, int border_held); +static void RenderOuterBorders(ImGuiWindow* window); static void EndFrameDrawDimmedBackgrounds(); // Viewports @@ -2567,6 +2567,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) Appearing = false; Hidden = false; HasCloseButton = false; + ResizeBorderHeld = -1; BeginCount = 0; BeginOrderWithinParent = -1; BeginOrderWithinContext = -1; @@ -5115,13 +5116,15 @@ static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, cons window->Pos = ImMin(rect.Max - padding, ImMax(window->Pos + size_for_clamping, rect.Min + padding) - size_for_clamping); } -static void ImGui::RenderOuterBorders(ImGuiWindow* window, int border_held) +static void ImGui::RenderOuterBorders(ImGuiWindow* window) { ImGuiContext& g = *GImGui; float rounding = window->WindowRounding; float border_size = window->WindowBorderSize; if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + + int border_held = window->ResizeBorderHeld; if (border_held != -1) { struct ImGuiResizeBorderDef @@ -5373,9 +5376,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) flags = window->Flags; // Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies) - if (window->DockIsActive) - window->WindowBorderSize = 0.0f; - else if (flags & ImGuiWindowFlags_ChildWindow) + if (flags & ImGuiWindowFlags_ChildWindow) window->WindowBorderSize = style.ChildBorderSize; else window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize; @@ -5579,13 +5580,17 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) want_focus = true; } + // Decide if we are going to handle borders and resize grips + const bool handle_borders_and_resize_grips = (window->DockNodeAsHost || !window->DockIsActive); + // Handle manual resize: Resize Grips, Borders, Gamepad int border_held = -1; ImU32 resize_grip_col[4] = { 0 }; const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // 4 const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); - if (!window->Collapsed) + if (handle_borders_and_resize_grips && !window->Collapsed) UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]); + window->ResizeBorderHeld = (signed char)border_held; // Synchronize window --> viewport if (window->ViewportOwned) @@ -5698,7 +5703,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { ImRect menu_bar_rect = window->MenuBarRect(); menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. - window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); + window->DrawList->AddRectFilled(menu_bar_rect.Min+ImVec2(window_border_size,0), menu_bar_rect.Max-ImVec2(window_border_size,0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); } @@ -5725,7 +5730,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) Scrollbar(ImGuiLayoutType_Vertical); // Render resize grips (after their input handling so we don't have a frame of latency) - if (!(flags & ImGuiWindowFlags_NoResize)) + if (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize)) { for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) { @@ -5738,8 +5743,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } } - // Borders - RenderOuterBorders(window, border_held); + // Borders (for dock node host they will be rendered over after the tab bar) + if (handle_borders_and_resize_grips && !window->DockNodeAsHost) + RenderOuterBorders(window); } // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars. @@ -11300,6 +11306,10 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) if (beginned_into_host_window) End(); } + + // Render outer borders last (after the tab bar) + if (node->IsRootNode() && host_window) + RenderOuterBorders(host_window); } // Compare TabItem nodes given the last known DockOrder (will persist in .ini file as hint), used to sort tabs when multiple tabs are added on the same frame. @@ -11403,7 +11413,6 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w ImRect title_bar_rect = ImRect(node->Pos, node->Pos + ImVec2(node->Size.x, g.FontSize + style.FramePadding.y * 2.0f)); ImU32 title_bar_col = GetColorU32(host_window->Collapsed ? ImGuiCol_TitleBgCollapsed : is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); host_window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, host_window->WindowRounding, ImDrawCornerFlags_Top); - host_window->DrawList->AddLine(title_bar_rect.GetBL(), title_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.WindowBorderSize); // Collapse button if (CollapseButton(host_window->GetID("#COLLAPSE"), title_bar_rect.Min, node)) diff --git a/imgui_internal.h b/imgui_internal.h index de762b520..a90ff53fc 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1285,6 +1285,7 @@ struct IMGUI_API ImGuiWindow bool Appearing; // Set during the frame where the window is appearing (or re-appearing) bool Hidden; // Do not display (== (HiddenFramesForResize > 0) || bool HasCloseButton; // Set when the window has a close button (p_open != NULL) + signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3) short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 17d87f48f..b547f82f4 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5551,7 +5551,7 @@ bool ImGui::BeginMenuBar() // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. ImRect bar_rect = window->MenuBarRect(); - ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f)); + ImRect clip_rect(ImFloor(bar_rect.Min.x + window->WindowBorderSize + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize)) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f)); clip_rect.ClipWith(window->OuterRectClipped); PushClipRect(clip_rect.Min, clip_rect.Max, false); @@ -5931,8 +5931,8 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG const float y = tab_bar->BarRect.Max.y - 1.0f; if (dock_node != NULL) { - const float separator_min_x = dock_node->Pos.x; - const float separator_max_x = dock_node->Pos.x + dock_node->Size.x; + const float separator_min_x = dock_node->Pos.x + window->WindowBorderSize; + const float separator_max_x = dock_node->Pos.x + dock_node->Size.x - window->WindowBorderSize; window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); } else