From cd15f7e6f9f4368a049a175d64c8591bfff301a4 Mon Sep 17 00:00:00 2001 From: Mihaly Sisak Date: Sat, 25 Jan 2025 15:38:50 +0100 Subject: [PATCH] add ImGuiWindowFlags_UserDrawnOverlappingDecorators --- imgui.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++---- imgui.h | 3 +++ imgui_internal.h | 36 ++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 63c6748f4..dd644e5e7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7153,8 +7153,15 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar // FIXME-DOCK: Ideally we'd use ImGuiCol_TitleBgActive/ImGuiCol_TitleBg here, but neither is guaranteed to be visible enough at this sort of size.. ImU32 col = GetColorU32(((held && hovered) || (node->IsFocused && !hovered)) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); - window->DrawList->AddTriangleFilled(p, p + ImVec2(unhide_sz_draw, 0.0f), p + ImVec2(0.0f, unhide_sz_draw), col); + ImVec2 p2 = p + ImVec2(unhide_sz_draw, 0.0f); + ImVec2 p3 = p + ImVec2(0.0f, unhide_sz_draw); + if (flags & ImGuiWindowFlags_UserDrawnOverlappingDecorators) + window->Decorator.DockingTabBar.Fill(p, p2, p3, col); + else + window->DrawList->AddTriangleFilled(p, p2, p3, col); } + else if (flags & ImGuiWindowFlags_UserDrawnOverlappingDecorators) + window->Decorator.DockingTabBar.Reset(); // Scrollbars if (window->ScrollbarX) @@ -7173,12 +7180,31 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); const float border_inner = IM_ROUND(window_border_size * 0.5f); - window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(border_inner, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, border_inner))); - window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, border_inner) : ImVec2(border_inner, resize_grip_draw_size))); - window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + border_inner), corner.y + grip.InnerDir.y * (window_rounding + border_inner)), window_rounding, grip.AngleMin12, grip.AngleMax12); - window->DrawList->PathFillConvex(col); + ImVec2 p1 = corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(border_inner, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, border_inner)); + ImVec2 p2 = corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, border_inner) : ImVec2(border_inner, resize_grip_draw_size)); + ImVec2 pc = ImVec2(corner.x + grip.InnerDir.x * (window_rounding + border_inner), corner.y + grip.InnerDir.y * (window_rounding + border_inner)); + float r = window_rounding; + int a1 = grip.AngleMin12; + int a2 = grip.AngleMax12; + if (flags & ImGuiWindowFlags_UserDrawnOverlappingDecorators) + { + window->Decorator.ResizeGrip[resize_grip_n].Fill(p1, p2, pc, r, a1, a2, col); + } + else + { + window->DrawList->PathLineTo(p1); + window->DrawList->PathLineTo(p2); + window->DrawList->PathArcToFast(pc, r, a1, a2); + window->DrawList->PathFillConvex(col); + } } + if (flags & ImGuiWindowFlags_UserDrawnOverlappingDecorators) + for (int resize_grip_n = resize_grip_count; resize_grip_n < 4; resize_grip_n++) + window->Decorator.ResizeGrip[resize_grip_n].Reset(); } + else if (flags & ImGuiWindowFlags_UserDrawnOverlappingDecorators) + for (int resize_grip_n = 0; resize_grip_n < 4; resize_grip_n++) + window->Decorator.ResizeGrip[resize_grip_n].Reset(); // Borders (for dock node host they will be rendered over after the tab bar) if (handle_borders_and_resize_grips && !window->DockNodeAsHost) @@ -8277,6 +8303,36 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) return !window->SkipItems; } +// In case of ImGuiWindowFlags_UserDrawnOverlappingDecorators +// the Begin() call does not draw the docking unhide tab bar (small triangle in the corner) and resize grips +// but saves them to the window->Decorator structure +void ImGui::DrawOverlappingDecorators() +{ + ImGuiWindow* window = GetCurrentWindow(); + + IM_ASSERT_USER_ERROR(window != NULL, "Call this function beween Begin() and End()"); + + int flags = window->Flags; + + IM_ASSERT_USER_ERROR(flags & ImGuiWindowFlags_UserDrawnOverlappingDecorators, "Only call this function for windows with ImGuiWindowFlags_UserDrawnOverlappingDecorators set"); + + if (window->Decorator.DockingTabBar.IsDrawing) + { + ImGuiDecoratorDockingTabBar& dt = window->Decorator.DockingTabBar; + window->DrawList->AddTriangleFilled(dt.P1, dt.P2, dt.P3, dt.Col); + } + + for (int resize_grip_n = 0; resize_grip_n < 4; resize_grip_n++) + if (window->Decorator.ResizeGrip[resize_grip_n].IsDrawing) + { + ImGuiDecoratorResizeGrip& rg = window->Decorator.ResizeGrip[resize_grip_n]; + window->DrawList->PathLineTo(rg.P1); + window->DrawList->PathLineTo(rg.P2); + window->DrawList->PathArcToFast(rg.Pc, rg.R, rg.A1, rg.A2); + window->DrawList->PathFillConvex(rg.Col); + } +} + static void ImGui::SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect) { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index ccbebdcc1..568eb49da 100644 --- a/imgui.h +++ b/imgui.h @@ -374,7 +374,9 @@ namespace ImGui // such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding // BeginXXX function returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] // - Note that the bottom of window stack always contains a window called "Debug". + // - DrawOverlappingDecorators() is only needed if the window was created with the ImGuiWindowFlags_UserDrawnOverlappingDecorators flag IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); + IMGUI_API void DrawOverlappingDecorators(); IMGUI_API void End(); // Child Windows @@ -1127,6 +1129,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoNavFocus = 1 << 17, // No focusing toward this window with keyboard/gamepad navigation (e.g. skipped by CTRL+TAB) ImGuiWindowFlags_UnsavedDocument = 1 << 18, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. ImGuiWindowFlags_NoDocking = 1 << 19, // Disable docking of this window + ImGuiWindowFlags_UserDrawnOverlappingDecorators=1<<20, // Draw docking unhide tab bar (small triangle in the corner) and resize grips when user calls DrawOverlappingDecorators() ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, diff --git a/imgui_internal.h b/imgui_internal.h index 916ae04c0..204351f05 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2677,6 +2677,41 @@ struct IMGUI_API ImGuiWindowTempData ImVector TextWrapPosStack; // Store text wrap pos to restore (attention: .back() is not == TextWrapPos) }; +// Overlapping decorators for ImGuiWindowFlags_UserDrawnOverlappingDecorators, docking unhide tab bar (small triangle in the corner) +struct IMGUI_API ImGuiDecoratorDockingTabBar +{ + bool IsDrawing; // Is this gui element being drawn in this frame + ImVec2 P1; // window->DrawList->AddTriangleFilled p1 + ImVec2 P2; // window->DrawList->AddTriangleFilled p2 + ImVec2 P3; // window->DrawList->AddTriangleFilled p3 + ImU32 Col; // window->DrawList->AddTriangleFilled col + + void Fill(ImVec2 p1, ImVec2 p2, ImVec2 p3, ImU32 col) { IsDrawing = true; P1 = p1; P2 = p2; P3 = p3; Col = col; } + void Reset() { IsDrawing = false; } +}; + +// Overlapping decorators for ImGuiWindowFlags_UserDrawnOverlappingDecorators, resize grips +struct IMGUI_API ImGuiDecoratorResizeGrip +{ + bool IsDrawing; // Is this gui element being drawn in this frame + ImVec2 P1; // window->DrawList->PathLineTo 1st call pos + ImVec2 P2; // window->DrawList->PathLineTo 2nd call pos + ImVec2 Pc; // window->DrawList->PathArcToFast center + float R; // window->DrawList->PathArcToFast radius + int A1; // window->DrawList->PathArcToFast a_min_of_12 + int A2; // window->DrawList->PathArcToFast a_max_of_12 + ImU32 Col; // window->DrawList->PathFillConvex col + + void Fill(ImVec2 p1, ImVec2 p2, ImVec2 pc, float r, int a1, int a2, ImU32 col) { IsDrawing = true; P1 = p1; P2 = p2; Pc = pc; R = r; A1 = a1; A2 = a2; Col = col; } + void Reset() { IsDrawing = false; } +}; + +struct IMGUI_API ImGuiDecorator +{ + ImGuiDecoratorDockingTabBar DockingTabBar; + ImGuiDecoratorResizeGrip ResizeGrip[4]; +}; + // Storage for one window struct IMGUI_API ImGuiWindow { @@ -2751,6 +2786,7 @@ struct IMGUI_API ImGuiWindow ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack. (In theory this should be in the TempData structure) ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. + ImGuiDecorator Decorator; // Temporary overlapping decorator data for ImGuiWindowFlags_UserDrawnOverlappingDecorators // The best way to understand what those rectangles are is to use the 'Metrics->Tools->Show Windows Rectangles' viewer. // The main 'OuterRect', omitted as a field, is window->Rect().