mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-11-03 22:51:06 +01:00 
			
		
		
		
	Internals: extracted a more reusable BeginViewportSideBar() out of BeginMainMenuBar(). (#3966, #3518)
Complement ca34c81c in docking branch which removed assumption that we can't tell size ahead of Begin().
			
			
This commit is contained in:
		@@ -10566,9 +10566,9 @@ static void ImGui::UpdateViewportsNewFrame()
 | 
			
		||||
        ImGuiViewportP* viewport = g.Viewports[n];
 | 
			
		||||
 | 
			
		||||
        // 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);
 | 
			
		||||
        viewport->WorkOffsetMin = viewport->BuildWorkOffsetMin;
 | 
			
		||||
        viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax;
 | 
			
		||||
        viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f);
 | 
			
		||||
        viewport->UpdateWorkRect();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1180,14 +1180,21 @@ struct ImGuiViewportP : public ImGuiViewport
 | 
			
		||||
 | 
			
		||||
    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).
 | 
			
		||||
    ImVec2              CurrWorkOffsetMin;      // Work Area: Offset being built/increased during current frame
 | 
			
		||||
    ImVec2              CurrWorkOffsetMax;      // Work Area: Offset being built/decreased during current frame
 | 
			
		||||
    ImVec2              BuildWorkOffsetMin;     // Work Area: Offset being built during current frame. Generally >= 0.0f.
 | 
			
		||||
    ImVec2              BuildWorkOffsetMax;     // Work Area: Offset being built during current frame. Generally <= 0.0f.
 | 
			
		||||
 | 
			
		||||
    ImGuiViewportP()                { DrawListsLastFrame[0] = DrawListsLastFrame[1] = -1; DrawLists[0] = DrawLists[1] = NULL; }
 | 
			
		||||
    ~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  GetWorkRect() const     { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); }
 | 
			
		||||
    void    UpdateWorkRect()        { WorkPos = ImVec2(Pos.x + WorkOffsetMin.x, Pos.y + WorkOffsetMin.y); WorkSize = ImVec2(ImMax(0.0f, Size.x - WorkOffsetMin.x + WorkOffsetMax.x), ImMax(0.0f, Size.y - WorkOffsetMin.y + WorkOffsetMax.y)); }
 | 
			
		||||
    ImGuiViewportP()    { DrawListsLastFrame[0] = DrawListsLastFrame[1] = -1; DrawLists[0] = DrawLists[1] = NULL; }
 | 
			
		||||
    ~ImGuiViewportP()   { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); }
 | 
			
		||||
 | 
			
		||||
    // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect)
 | 
			
		||||
    ImVec2  CalcWorkRectPos(const ImVec2& off_min) const                            { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); }
 | 
			
		||||
    ImVec2  CalcWorkRectSize(const ImVec2& off_min, const ImVec2& off_max) const    { return ImVec2(ImMax(0.0f, Size.x - off_min.x + off_max.x), ImMax(0.0f, Size.y - off_min.y + off_max.y)); }
 | 
			
		||||
    void    UpdateWorkRect()            { WorkPos = CalcWorkRectPos(WorkOffsetMin); WorkSize = CalcWorkRectSize(WorkOffsetMin, WorkOffsetMax); } // Update public fields
 | 
			
		||||
 | 
			
		||||
    // Helpers to retrieve ImRect (we don't need to store BuildWorkRect as every access tend to change it, hence the code asymmetry)
 | 
			
		||||
    ImRect  GetMainRect() const         { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
 | 
			
		||||
    ImRect  GetWorkRect() const         { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); }
 | 
			
		||||
    ImRect  GetBuildWorkRect() const    { ImVec2 pos = CalcWorkRectPos(BuildWorkOffsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkOffsetMin, BuildWorkOffsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
@@ -2309,6 +2316,7 @@ namespace ImGui
 | 
			
		||||
    IMGUI_API ImGuiWindow*  GetTopMostPopupModal();
 | 
			
		||||
    IMGUI_API ImVec2        FindBestWindowPosForPopup(ImGuiWindow* window);
 | 
			
		||||
    IMGUI_API ImVec2        FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy);
 | 
			
		||||
    IMGUI_API bool          BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags);
 | 
			
		||||
 | 
			
		||||
    // Gamepad/Keyboard Navigation
 | 
			
		||||
    IMGUI_API void          NavInitWindow(ImGuiWindow* window, bool force_reinit);
 | 
			
		||||
 
 | 
			
		||||
@@ -6602,46 +6602,63 @@ void ImGui::EndMenuBar()
 | 
			
		||||
    window->DC.MenuBarAppending = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Important: calling order matters!
 | 
			
		||||
// FIXME: Somehow overlapping with docking tech.
 | 
			
		||||
// FIXME: The "rect-cut" aspect of this could be formalized into a lower-level helper (rect-cut: https://halt.software/dead-simple-layouts)
 | 
			
		||||
bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, ImGuiDir dir, float axis_size, ImGuiWindowFlags window_flags)
 | 
			
		||||
{
 | 
			
		||||
    IM_ASSERT(dir != ImGuiDir_None);
 | 
			
		||||
 | 
			
		||||
    ImGuiWindow* bar_window = FindWindowByName(name);
 | 
			
		||||
    if (bar_window == NULL || bar_window->BeginCount == 0)
 | 
			
		||||
    {
 | 
			
		||||
        // Calculate and set window size/position
 | 
			
		||||
        ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport());
 | 
			
		||||
        ImRect avail_rect = viewport->GetBuildWorkRect();
 | 
			
		||||
        ImGuiAxis axis = (dir == ImGuiDir_Up || dir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X;
 | 
			
		||||
        ImVec2 pos = avail_rect.Min;
 | 
			
		||||
        if (dir == ImGuiDir_Right || dir == ImGuiDir_Down)
 | 
			
		||||
            pos[axis] = avail_rect.Max[axis] - axis_size;
 | 
			
		||||
        ImVec2 size = avail_rect.GetSize();
 | 
			
		||||
        size[axis] = axis_size;
 | 
			
		||||
        SetNextWindowPos(pos);
 | 
			
		||||
        SetNextWindowSize(size);
 | 
			
		||||
 | 
			
		||||
        // Report our size into work area (for next frame) using actual window size
 | 
			
		||||
        if (dir == ImGuiDir_Up || dir == ImGuiDir_Left)
 | 
			
		||||
            viewport->BuildWorkOffsetMin[axis] += axis_size;
 | 
			
		||||
        else if (dir == ImGuiDir_Down || dir == ImGuiDir_Right)
 | 
			
		||||
            viewport->BuildWorkOffsetMax[axis] -= axis_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
 | 
			
		||||
    PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
 | 
			
		||||
    PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint
 | 
			
		||||
    bool is_open = Begin(name, NULL, window_flags);
 | 
			
		||||
    PopStyleVar(2);
 | 
			
		||||
 | 
			
		||||
    return is_open;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ImGui::BeginMainMenuBar()
 | 
			
		||||
{
 | 
			
		||||
    ImGuiContext& g = *GImGui;
 | 
			
		||||
    ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport();
 | 
			
		||||
    ImGuiWindow* menu_bar_window = FindWindowByName("##MainMenuBar");
 | 
			
		||||
 | 
			
		||||
    // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.
 | 
			
		||||
    // FIXME: This could be generalized as an opt-in way to clamp window->DC.CursorStartPos to avoid SafeArea?
 | 
			
		||||
    // FIXME: Consider removing support for safe area down the line... it's messy. Nowadays consoles have support for TV calibration in OS settings.
 | 
			
		||||
    g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f));
 | 
			
		||||
 | 
			
		||||
    // Get our rectangle at the top of the work area
 | 
			
		||||
    if (menu_bar_window == NULL || menu_bar_window->BeginCount == 0)
 | 
			
		||||
    {
 | 
			
		||||
        // Set window position
 | 
			
		||||
        // 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);
 | 
			
		||||
        SetNextWindowPos(menu_bar_pos);
 | 
			
		||||
        SetNextWindowSize(menu_bar_size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Create window
 | 
			
		||||
    PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
 | 
			
		||||
    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_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
 | 
			
		||||
    bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar();
 | 
			
		||||
    PopStyleVar(2);
 | 
			
		||||
 | 
			
		||||
    // Report our size into work area (for next frame) using actual window size
 | 
			
		||||
    menu_bar_window = GetCurrentWindow();
 | 
			
		||||
    if (menu_bar_window->BeginCount == 1)
 | 
			
		||||
        viewport->CurrWorkOffsetMin.y += menu_bar_window->Size.y;
 | 
			
		||||
 | 
			
		||||
    ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
 | 
			
		||||
    float height = GetFrameHeight();
 | 
			
		||||
    bool is_open = BeginViewportSideBar("##MainMenuBar", viewport, ImGuiDir_Up, height, window_flags);
 | 
			
		||||
    g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
 | 
			
		||||
    if (!is_open)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    if (is_open)
 | 
			
		||||
        BeginMenuBar();
 | 
			
		||||
    else
 | 
			
		||||
        End();
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true; //-V1020
 | 
			
		||||
    return is_open;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ImGui::EndMainMenuBar()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user