Browse Source

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().
pull/3951/head
ocornut 4 years ago
parent
commit
a58271c079
  1. 6
      imgui.cpp
  2. 14
      imgui_internal.h
  3. 79
      imgui_widgets.cpp

6
imgui.cpp

@ -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();
} }
} }

14
imgui_internal.h

@ -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]); }
// 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 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 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)); } 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);

79
imgui_widgets.cpp

@ -6602,46 +6602,63 @@ void ImGui::EndMenuBar()
window->DC.MenuBarAppending = false; window->DC.MenuBarAppending = false;
} }
bool ImGui::BeginMainMenuBar() // Important: calling order matters!
{ // FIXME: Somehow overlapping with docking tech.
ImGuiContext& g = *GImGui; // FIXME: The "rect-cut" aspect of this could be formalized into a lower-level helper (rect-cut: https://halt.software/dead-simple-layouts)
ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, ImGuiDir dir, float axis_size, ImGuiWindowFlags window_flags)
ImGuiWindow* menu_bar_window = FindWindowByName("##MainMenuBar"); {
IM_ASSERT(dir != ImGuiDir_None);
// 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)); 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);
// Get our rectangle at the top of the work area // Report our size into work area (for next frame) using actual window size
if (menu_bar_window == NULL || menu_bar_window->BeginCount == 0) if (dir == ImGuiDir_Up || dir == ImGuiDir_Left)
{ viewport->BuildWorkOffsetMin[axis] += axis_size;
// Set window position else if (dir == ImGuiDir_Down || dir == ImGuiDir_Right)
// We don't attempt to calculate our height ahead, as it depends on the per-viewport font size. viewport->BuildWorkOffsetMax[axis] -= axis_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 window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); 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. PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; bool is_open = Begin(name, NULL, window_flags);
bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar();
PopStyleVar(2); PopStyleVar(2);
// Report our size into work area (for next frame) using actual window size return is_open;
menu_bar_window = GetCurrentWindow(); }
if (menu_bar_window->BeginCount == 1)
viewport->CurrWorkOffsetMin.y += menu_bar_window->Size.y;
bool ImGui::BeginMainMenuBar()
{
ImGuiContext& g = *GImGui;
ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport();
// 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));
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); 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()

Loading…
Cancel
Save