Viewports, Docking: Added per-viewport work area system for e.g. menu-bars. Fixed DocksapceOverViewport() and demo code (overlay etc) (#3035, #2889, #2474, #1542, #2109)

Clarified that BeginMenuMainBar() had an incorrect knowledge of its height (which was previously harmless).
Designed to easily allow for status bars although we don't have/use them yet, but custom code could use them.
This commit is contained in:
ocornut 2020-02-26 23:58:45 +01:00
parent f032ad6b1f
commit 75de34e281
5 changed files with 64 additions and 25 deletions

View File

@ -5273,6 +5273,7 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont
if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups) if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups)
size_min = ImMin(size_min, ImVec2(4.0f, 4.0f)); size_min = ImMin(size_min, ImVec2(4.0f, 4.0f));
// FIXME-VIEWPORT-WORKAREA: May want to use GetWorkSize() instead of Size depending on the type of windows?
ImVec2 avail_size = window->Viewport->Size; ImVec2 avail_size = window->Viewport->Size;
if (window->ViewportOwned) if (window->ViewportOwned)
avail_size = ImVec2(FLT_MAX, FLT_MAX); avail_size = ImVec2(FLT_MAX, FLT_MAX);
@ -6002,6 +6003,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
else else
window->WindowPadding = style.WindowPadding; window->WindowPadding = style.WindowPadding;
// Lock menu offset so size calculation can use it as menu-bar windows need a minimum size.
window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
// Collapse window by double-clicking on title bar // Collapse window by double-clicking on title bar
// At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing
if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse) && !window->DockIsActive) if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse) && !window->DockIsActive)
@ -6182,13 +6187,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Clamp position/size so window stays visible within its viewport or monitor // Clamp position/size 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. // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
// FIXME: Similar to code in GetWindowAllowedExtentRect()
ImRect viewport_rect = window->Viewport->GetMainRect(); ImRect viewport_rect = window->Viewport->GetMainRect();
if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
{ {
ImVec2 clamp_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); ImVec2 clamp_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
if (!window->ViewportOwned && viewport_rect.GetWidth() > 0 && viewport_rect.GetHeight() > 0.0f) if (!window->ViewportOwned && viewport_rect.GetWidth() > 0 && viewport_rect.GetHeight() > 0.0f)
{ {
ClampWindowRect(window, viewport_rect, clamp_padding); ClampWindowRect(window, window->Viewport->GetWorkRect(), clamp_padding);
} }
else if (window->ViewportOwned && g.PlatformIO.Monitors.Size > 0) else if (window->ViewportOwned && g.PlatformIO.Monitors.Size > 0)
{ {
@ -6437,8 +6443,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f); window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
window->DC.MenuBarAppending = false; window->DC.MenuBarAppending = false;
window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
window->DC.MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user); window->DC.MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
window->DC.TreeDepth = 0; window->DC.TreeDepth = 0;
window->DC.TreeJumpToParentOnPopMask = 0x00; window->DC.TreeJumpToParentOnPopMask = 0x00;
@ -8514,6 +8518,7 @@ ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& s
return pos; return pos;
} }
// Note that this is used for popups, which can overlap the non work-area of individual viewports.
ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window) ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -8527,6 +8532,7 @@ ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window)
} }
else else
{ {
// Use the full viewport area (not work area) for popups
r_screen.Min = window->Viewport->Pos; r_screen.Min = window->Viewport->Pos;
r_screen.Max = window->Viewport->Pos + window->Viewport->Size; r_screen.Max = window->Viewport->Pos + window->Viewport->Size;
} }
@ -10731,6 +10737,11 @@ static void ImGui::UpdateViewportsNewFrame()
// Update/copy monitor info // Update/copy monitor info
UpdateViewportPlatformMonitor(viewport); UpdateViewportPlatformMonitor(viewport);
// Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again.
viewport->WorkOffsetMin = viewport->CurrWorkOffsetMin;
viewport->WorkOffsetMax = viewport->CurrWorkOffsetMax;
viewport->CurrWorkOffsetMin = viewport->CurrWorkOffsetMax = ImVec2(0.0f, 0.0f);
// Reset alpha every frame. Users of transparency (docking) needs to request a lower alpha back. // Reset alpha every frame. Users of transparency (docking) needs to request a lower alpha back.
viewport->Alpha = 1.0f; viewport->Alpha = 1.0f;
@ -13852,14 +13863,14 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags fla
// Tips: Use with ImGuiDockNodeFlags_PassthruCentralNode! // Tips: Use with ImGuiDockNodeFlags_PassthruCentralNode!
// The limitation with this call is that your window won't have a menu bar. // The limitation with this call is that your window won't have a menu bar.
// Even though we could pass window flags, it would also require the user to be able to call BeginMenuBar() somehow meaning we can't Begin/End in a single function. // Even though we could pass window flags, it would also require the user to be able to call BeginMenuBar() somehow meaning we can't Begin/End in a single function.
// So if you want a menu bar you need to repeat this code manually ourselves. As with advanced other Docking API, we may change this function signature. // But you can also use BeginMainMenuBar(). If you really want a menu bar inside the same window as the one hosting the dockspace, you will need to copy this code somewhere and tweak it.
ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags dockspace_flags, const ImGuiWindowClass* window_class) ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags dockspace_flags, const ImGuiWindowClass* window_class)
{ {
if (viewport == NULL) if (viewport == NULL)
viewport = GetMainViewport(); viewport = GetMainViewport();
SetNextWindowPos(viewport->Pos); SetNextWindowPos(viewport->GetWorkPos());
SetNextWindowSize(viewport->Size); SetNextWindowSize(viewport->GetWorkSize());
SetNextWindowViewport(viewport->ID); SetNextWindowViewport(viewport->ID);
ImGuiWindowFlags host_window_flags = 0; ImGuiWindowFlags host_window_flags = 0;
@ -15230,7 +15241,10 @@ void ImGui::ShowMetricsWindow(bool* p_open)
if (ImGui::TreeNode((void*)(intptr_t)viewport->ID, "Viewport #%d, ID: 0x%08X, Parent: 0x%08X, Window: \"%s\"", viewport->Idx, viewport->ID, viewport->ParentViewportId, viewport->Window ? viewport->Window->Name : "N/A")) if (ImGui::TreeNode((void*)(intptr_t)viewport->ID, "Viewport #%d, ID: 0x%08X, Parent: 0x%08X, Window: \"%s\"", viewport->Idx, viewport->ID, viewport->ParentViewportId, viewport->Window ? viewport->Window->Name : "N/A"))
{ {
ImGuiWindowFlags flags = viewport->Flags; ImGuiWindowFlags flags = viewport->Flags;
ImGui::BulletText("Pos: (%.0f,%.0f), Size: (%.0f,%.0f), Monitor: %d, DpiScale: %.0f%%", viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y, viewport->PlatformMonitor, viewport->DpiScale * 100.0f); ImGui::BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f\nMonitor: %d, DpiScale: %.0f%%",
viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y,
viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y,
viewport->PlatformMonitor, viewport->DpiScale * 100.0f);
if (viewport->Idx > 0) { ImGui::SameLine(); if (ImGui::SmallButton("Reset Pos")) { viewport->Pos = ImVec2(200,200); if (viewport->Window) viewport->Window->Pos = ImVec2(200,200); } } if (viewport->Idx > 0) { ImGui::SameLine(); if (ImGui::SmallButton("Reset Pos")) { viewport->Pos = ImVec2(200,200); if (viewport->Window) viewport->Window->Pos = ImVec2(200,200); } }
ImGui::BulletText("Flags: 0x%04X =%s%s%s%s%s%s%s", viewport->Flags, ImGui::BulletText("Flags: 0x%04X =%s%s%s%s%s%s%s", viewport->Flags,
(flags & ImGuiViewportFlags_CanHostOtherWindows) ? " CanHostOtherWindows" : "", (flags & ImGuiViewportFlags_NoDecoration) ? " NoDecoration" : "", (flags & ImGuiViewportFlags_CanHostOtherWindows) ? " CanHostOtherWindows" : "", (flags & ImGuiViewportFlags_NoDecoration) ? " NoDecoration" : "",

16
imgui.h
View File

@ -2468,14 +2468,18 @@ enum ImGuiViewportFlags_
ImGuiViewportFlags_CanHostOtherWindows = 1 << 9 // Main viewport: can host multiple imgui windows (secondary viewports are associated to a single window). ImGuiViewportFlags_CanHostOtherWindows = 1 << 9 // Main viewport: can host multiple imgui windows (secondary viewports are associated to a single window).
}; };
// The viewports created and managed by imgui. The role of the platform back-end is to create the platform/OS windows corresponding to each viewport. // The viewports created and managed by Dear ImGui. The role of the platform back-end is to create the platform/OS windows corresponding to each viewport.
// - Main Area = entire viewport.
// - Work Area = entire viewport minus sections optionally used by menu bars, status bars. Some positioning code will prefer to use this. Window are also trying to stay within this area.
struct ImGuiViewport struct ImGuiViewport
{ {
ImGuiID ID; // Unique identifier for the viewport ImGuiID ID; // Unique identifier for the viewport
ImGuiViewportFlags Flags; // See ImGuiViewportFlags_ ImGuiViewportFlags Flags; // See ImGuiViewportFlags_
ImVec2 Pos; // Position of viewport both in imgui space and in OS desktop/native space ImVec2 Pos; // Main Area: Position of the viewport (the imgui coordinates are the same as OS desktop/native coordinates)
ImVec2 Size; // Size of viewport in pixel ImVec2 Size; // Main Area: Size of the viewport.
float DpiScale; // 1.0f = 96 DPI = No extra scale ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!)
ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height).
float DpiScale; // 1.0f = 96 DPI = No extra scale.
ImDrawData* DrawData; // The ImDrawData corresponding to this viewport. Valid after Render() and until the next call to NewFrame(). ImDrawData* DrawData; // The ImDrawData corresponding to this viewport. Valid after Render() and until the next call to NewFrame().
ImGuiID ParentViewportId; // (Advanced) 0: no parent. Instruct the platform back-end to setup a parent/child relationship between platform windows. ImGuiID ParentViewportId; // (Advanced) 0: no parent. Instruct the platform back-end to setup a parent/child relationship between platform windows.
@ -2491,6 +2495,10 @@ struct ImGuiViewport
ImGuiViewport() { ID = 0; Flags = 0; DpiScale = 0.0f; DrawData = NULL; ParentViewportId = 0; RendererUserData = PlatformUserData = PlatformHandle = PlatformHandleRaw = NULL; PlatformRequestMove = PlatformRequestResize = PlatformRequestClose = false; } ImGuiViewport() { ID = 0; Flags = 0; DpiScale = 0.0f; DrawData = NULL; ParentViewportId = 0; RendererUserData = PlatformUserData = PlatformHandle = PlatformHandleRaw = NULL; PlatformRequestMove = PlatformRequestResize = PlatformRequestClose = false; }
~ImGuiViewport() { IM_ASSERT(PlatformUserData == NULL && RendererUserData == NULL); } ~ImGuiViewport() { IM_ASSERT(PlatformUserData == NULL && RendererUserData == NULL); }
// Access work-area rectangle
ImVec2 GetWorkPos() { return ImVec2(Pos.x + WorkOffsetMin.x, Pos.y + WorkOffsetMin.y); }
ImVec2 GetWorkSize() { return ImVec2(Size.x - WorkOffsetMin.x + WorkOffsetMax.x, Size.y - WorkOffsetMin.y + WorkOffsetMax.y); } // This not clamped
}; };
#if defined(__clang__) #if defined(__clang__)

View File

@ -222,9 +222,9 @@ void ImGui::ShowDemoWindow(bool* p_open)
IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!"); // Exceptionally add an extra assert here for people confused with initial dear imgui setup IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!"); // Exceptionally add an extra assert here for people confused with initial dear imgui setup
// Examples Apps (accessible from the "Examples" menu) // Examples Apps (accessible from the "Examples" menu)
static bool show_app_main_menu_bar = false;
static bool show_app_dockspace = false; static bool show_app_dockspace = false;
static bool show_app_documents = false; static bool show_app_documents = false;
static bool show_app_main_menu_bar = false;
static bool show_app_console = false; static bool show_app_console = false;
static bool show_app_log = false; static bool show_app_log = false;
static bool show_app_layout = false; static bool show_app_layout = false;
@ -236,9 +236,9 @@ void ImGui::ShowDemoWindow(bool* p_open)
static bool show_app_window_titles = false; static bool show_app_window_titles = false;
static bool show_app_custom_rendering = false; static bool show_app_custom_rendering = false;
if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function)
if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace() if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace()
if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
if (show_app_console) ShowExampleAppConsole(&show_app_console); if (show_app_console) ShowExampleAppConsole(&show_app_console);
if (show_app_log) ShowExampleAppLog(&show_app_log); if (show_app_log) ShowExampleAppLog(&show_app_log);
if (show_app_layout) ShowExampleAppLayout(&show_app_layout); if (show_app_layout) ShowExampleAppLayout(&show_app_layout);
@ -286,8 +286,8 @@ void ImGui::ShowDemoWindow(bool* p_open)
if (no_close) p_open = NULL; // Don't pass our bool* to Begin if (no_close) p_open = NULL; // Don't pass our bool* to Begin
// We specify a default position/size in case there's no data in the .ini file. Typically this isn't required! We only do it to make the Demo applications a little more welcoming. // We specify a default position/size in case there's no data in the .ini file. Typically this isn't required! We only do it to make the Demo applications a little more welcoming.
ImVec2 main_viewport_pos = ImGui::GetMainViewport()->Pos; ImGuiViewport* main_viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(ImVec2(main_viewport_pos.x + 650, main_viewport_pos.y + 20), ImGuiCond_FirstUseEver); ImGui::SetNextWindowPos(ImVec2(main_viewport->GetWorkPos().x + 650, main_viewport->GetWorkPos().y + 20), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
// Main body of the Demo window starts here. // Main body of the Demo window starts here.
@ -4458,7 +4458,9 @@ static void ShowExampleAppSimpleOverlay(bool* p_open)
if (corner != -1) if (corner != -1)
{ {
ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGuiViewport* viewport = ImGui::GetMainViewport();
ImVec2 window_pos = ImVec2((corner & 1) ? (viewport->Pos.x + viewport->Size.x - DISTANCE) : (viewport->Pos.x + DISTANCE), (corner & 2) ? (viewport->Pos.y + viewport->Size.y - DISTANCE) : (viewport->Pos.y + DISTANCE)); ImVec2 work_area_pos = viewport->GetWorkPos(); // Instead of using viewport->Pos we use GetWorkPos() to avoid menu bars, if any!
ImVec2 work_area_size = viewport->GetWorkSize();
ImVec2 window_pos = ImVec2((corner & 1) ? (work_area_pos.x + work_area_size.x - DISTANCE) : (work_area_pos.x + DISTANCE), (corner & 2) ? (work_area_pos.y + work_area_size.y - DISTANCE) : (work_area_pos.y + DISTANCE));
ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f);
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
ImGui::SetNextWindowViewport(viewport->ID); ImGui::SetNextWindowViewport(viewport->ID);
@ -4714,8 +4716,8 @@ void ShowExampleAppDockSpace(bool* p_open)
if (opt_fullscreen) if (opt_fullscreen)
{ {
ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->Pos); ImGui::SetNextWindowPos(viewport->GetWorkPos());
ImGui::SetNextWindowSize(viewport->Size); ImGui::SetNextWindowSize(viewport->GetWorkSize());
ImGui::SetNextWindowViewport(viewport->ID); ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);

View File

@ -934,10 +934,13 @@ struct ImGuiViewportP : public ImGuiViewport
ImVec2 LastPlatformPos; ImVec2 LastPlatformPos;
ImVec2 LastPlatformSize; ImVec2 LastPlatformSize;
ImVec2 LastRendererSize; ImVec2 LastRendererSize;
ImVec2 CurrWorkOffsetMin; // Work area top-left offset being increased during the frame
ImVec2 CurrWorkOffsetMax; // Work area bottom-right offset being decreased during the frame
ImGuiViewportP() { Idx = -1; LastFrameActive = LastFrameDrawLists[0] = LastFrameDrawLists[1] = LastFrontMostStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; PlatformMonitor = -1; PlatformWindowCreated = false; Window = NULL; DrawLists[0] = DrawLists[1] = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); } ImGuiViewportP() { Idx = -1; LastFrameActive = LastFrameDrawLists[0] = LastFrameDrawLists[1] = LastFrontMostStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; PlatformMonitor = -1; PlatformWindowCreated = false; Window = NULL; DrawLists[0] = DrawLists[1] = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); }
~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); } ~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); }
ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
ImRect GetWorkRect() const { return ImRect(Pos.x + WorkOffsetMin.x, Pos.y + WorkOffsetMin.y, Pos.x + Size.x + WorkOffsetMax.x, Pos.y + Size.y + WorkOffsetMax.y); }
void ClearRequestFlags() { PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; } void ClearRequestFlags() { PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; }
}; };
@ -991,7 +994,7 @@ struct ImGuiNextWindowData
ImGuiID ViewportId; ImGuiID ViewportId;
ImGuiID DockId; ImGuiID DockId;
ImGuiWindowClass WindowClass; ImGuiWindowClass WindowClass;
ImVec2 MenuBarOffsetMinVal; // *Always on* This is not exposed publicly, so we don't clear it. ImVec2 MenuBarOffsetMinVal; // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?)
ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); } ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); }
inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; } inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }

View File

@ -6182,20 +6182,32 @@ void ImGui::EndMenuBar()
window->DC.MenuBarAppending = false; window->DC.MenuBarAppending = false;
} }
// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.
bool ImGui::BeginMainMenuBar() bool ImGui::BeginMainMenuBar()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiViewport* viewport = g.Viewports[0]; ImGuiViewportP* viewport = g.Viewports[0];
// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.
g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f));
SetNextWindowPos(viewport->Pos);
SetNextWindowSize(ImVec2(viewport->Size.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y)); // Get our rectangle in the work area, and report the size we need for next frame.
SetNextWindowViewport(viewport->ID); // Enforce viewport so we don't create our onw viewport when ImGuiConfigFlags_ViewportsNoMerge is set. // We don't attempt to calculate our height ahead, as it depends on the per-viewport font size. However menu-bar will affect the minimum window size so we'll get the right height.
ImVec2 menu_bar_pos = viewport->Pos + viewport->CurrWorkOffsetMin;
ImVec2 menu_bar_size = ImVec2(viewport->Size.x - viewport->CurrWorkOffsetMin.x + viewport->CurrWorkOffsetMax.x, 1.0f);
// Create window
SetNextWindowPos(menu_bar_pos);
SetNextWindowSize(menu_bar_size);
SetNextWindowViewport(viewport->ID); // Enforce viewport so we don't create our own viewport when ImGuiConfigFlags_ViewportsNoMerge is set.
PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint, however the presence of a menu-bar will give us the minimum height we want.
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar(); bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar();
PopStyleVar(2); PopStyleVar(2);
// Feed back into work area using actual window size
viewport->CurrWorkOffsetMin.y += GetCurrentWindow()->Size.y;
g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
if (!is_open) if (!is_open)
{ {