mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-30 04:31: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]; |         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. |         // 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->WorkOffsetMin = viewport->BuildWorkOffsetMin; | ||||||
|         viewport->WorkOffsetMax = viewport->CurrWorkOffsetMax; |         viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax; | ||||||
|         viewport->CurrWorkOffsetMin = viewport->CurrWorkOffsetMax = ImVec2(0.0f, 0.0f); |         viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f); | ||||||
|         viewport->UpdateWorkRect(); |         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              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              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              BuildWorkOffsetMin;     // Work Area: Offset being built during current frame. Generally >= 0.0f. | ||||||
|     ImVec2              CurrWorkOffsetMax;      // Work Area: Offset being built/decreased during current frame |     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()    { 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]); } |     ~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); } |     // 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) | ||||||
|     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)); } |     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 ImGuiWindow*  GetTopMostPopupModal(); | ||||||
|     IMGUI_API ImVec2        FindBestWindowPosForPopup(ImGuiWindow* window); |     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 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 |     // Gamepad/Keyboard Navigation | ||||||
|     IMGUI_API void          NavInitWindow(ImGuiWindow* window, bool force_reinit); |     IMGUI_API void          NavInitWindow(ImGuiWindow* window, bool force_reinit); | ||||||
|   | |||||||
| @@ -6602,46 +6602,63 @@ void ImGui::EndMenuBar() | |||||||
|     window->DC.MenuBarAppending = false; |     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() | bool ImGui::BeginMainMenuBar() | ||||||
| { | { | ||||||
|     ImGuiContext& g = *GImGui; |     ImGuiContext& g = *GImGui; | ||||||
|     ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); |     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. |     // 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)); |     g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); | ||||||
|  |     ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; | ||||||
|     // Get our rectangle at the top of the work area |     float height = GetFrameHeight(); | ||||||
|     if (menu_bar_window == NULL || menu_bar_window->BeginCount == 0) |     bool is_open = BeginViewportSideBar("##MainMenuBar", viewport, ImGuiDir_Up, height, window_flags); | ||||||
|     { |  | ||||||
|         // 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; |  | ||||||
|  |  | ||||||
|     g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); |     g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); | ||||||
|     if (!is_open) |  | ||||||
|     { |     if (is_open) | ||||||
|  |         BeginMenuBar(); | ||||||
|  |     else | ||||||
|         End(); |         End(); | ||||||
|         return false; |     return is_open; | ||||||
|     } |  | ||||||
|     return true; //-V1020 |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void ImGui::EndMainMenuBar() | void ImGui::EndMainMenuBar() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user