New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to achieve a multiline menu bar or a second menu bar under the main one? #3518
Comments
I think you just want to use Begin() and set the position and size to fit the boundaries of the buttons or menu items you places on that window. you can using ImGui::SetNextWindowPos() and ImGui::SetNextWindowSize() to make custom menu bar like seen in Visual Studio. |
I was able to achieve this effect by duplicating The pixel gap is caused by the fact that i changed the border color to match that of the background. |
@alexandru-cazacu Could you please post your complete code ? For some reason the second menu bar always continues in the first row for me. |
@Nightmare82 Sure here it is. I just duplicated It might not be the optimal solution, but it gets the job done. bool HY_ImGui_BeginMainStatusBar()
{
ImGuiContext& g = *GImGui;
ImGuiViewportP* viewport = g.Viewports[0];
ImGuiWindow* menu_bar_window = ImGui::FindWindowByName("##MainStatusBar");
// 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));
// Get our rectangle at the top of the work area
//__debugbreak();
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);
ImGui::SetNextWindowPos(menu_bar_pos);
ImGui::SetNextWindowSize(menu_bar_size);
}
// Create window
ImGui::SetNextWindowViewport(viewport->ID); // Enforce viewport so we don't create our own viewport when ImGuiConfigFlags_ViewportsNoMerge is set.
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::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;
bool is_open = ImGui::Begin("##MainStatusBar", NULL, window_flags) && ImGui::BeginMenuBar();
ImGui::PopStyleVar(2);
// Report our size into work area (for next frame) using actual window size
menu_bar_window = ImGui::GetCurrentWindow();
if (menu_bar_window->BeginCount == 1)
viewport->CurrWorkOffsetMin.y += menu_bar_window->Size.y;
g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
if (!is_open)
{
ImGui::End();
return false;
}
return true; //-V1020
}
void HY_ImGui_EndMainStatusBar()
{
ImGui::EndMenuBar();
// When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window
// FIXME: With this strategy we won't be able to restore a NULL focus.
ImGuiContext& g = *GImGui;
if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest)
ImGui::FocusTopMostWindowUnderOne(g.NavWindow, NULL);
ImGui::End();
} Then to use it: if (HY_ImGui_BeginMainStatusBar()) {
ImGui::Text("Happy status bar");
HY_ImGui_EndMainStatusBar();
} Watch out for the window name, in my case it's |
I have refactored some code in a58271c to make this easier, you can now use |
Thanks a lot @alexandru-cazacu ! @ocornut sounds great, thanks! |
I tried a58271c and it worked perfecly: Here is the snippet i used: ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)ImGui::GetMainViewport();
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
float height = ImGui::GetFrameHeight();
if (ImGui::BeginViewportSideBar("##SecondaryMenuBar", viewport, ImGuiDir_Up, height, window_flags)) {
if (ImGui::BeginMenuBar()) {
ImGui::Text("Happy secondary menu bar");
ImGui::EndMenuBar();
}
ImGui::End();
}
if (ImGui::BeginViewportSideBar("##MainStatusBar", viewport, ImGuiDir_Down, height, window_flags)) {
if (ImGui::BeginMenuBar()) {
ImGui::Text("Happy status bar");
ImGui::EndMenuBar();
}
ImGui::End();
} And here is a screenshot (using |
Hi Friends, |
@mnesarco It'll need more feedback until we can promote I'll also be reworking API to claim space in the "menu layer" of individual window, so the |
@ocornut Thank you, I will love to see the new API. Thank you for all your hard work. The more I use ImGui the more I love it. |
Thank you for the example. Some notes: // [1] BeginViewportSideBar signature receives ImGuiViewport* viewport
//
// You can change this:
// ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)ImGui::GetMainViewport();
// To this:
// ImGuiViewport* viewport = ImGui::GetMainViewport();
//
// But you can pass just NULL because main viewport is the default.
//
// [2] ImGui::BeginViewportSideBar uses ImGui::Begin so the call to ImGui::End should be out of the {if scope}
//
// Updated version:
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
float height = ImGui::GetFrameHeight();
if (ImGui::BeginViewportSideBar("##SecondaryMenuBar", NULL, ImGuiDir_Up, height, window_flags)) {
if (ImGui::BeginMenuBar()) {
ImGui::Text("Happy secondary menu bar");
ImGui::EndMenuBar();
}
}
ImGui::End();
if (ImGui::BeginViewportSideBar("##MainStatusBar", NULL, ImGuiDir_Down, height, window_flags)) {
if (ImGui::BeginMenuBar()) {
ImGui::Text("Happy status bar");
ImGui::EndMenuBar();
}
}
ImGui::End();
Cheers. |
I am currently in the stable branch and doing this: const ImGuiViewport *viewport = ImGui::GetMainViewport();
// Set position to the bottom of the viewport
ImGui::SetNextWindowPos(
ImVec2(viewport->Pos.x,
viewport->Pos.y + viewport->Size.y - ImGui::GetFrameHeight()));
// Extend width to viewport width
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, ImGui::GetFrameHeight()));
// Add menu bar flag and disable everything else
ImGuiWindowFlags flags =
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollWithMouse |
ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoBackground |
ImGuiWindowFlags_MenuBar;
if (ImGui::Begin("StatusBar", nullptr, flags)) {
if (ImGui::BeginMenuBar()) {
ImGui::Text("%s", state.c_str());
ImGui::EndMenuBar();
}
ImGui::End();
} May I ask what problem does |
Thanks for this, had been struggling with trying to implement this myself the past few days. |
…. (toward #5143, #4868, #3692, #3518) This is not strictly required presently, but will be consistent with adding inner decoration sizes in next commit, as well as generally being sane. Locking TitleBarHeight() / MenuBarHeight() values per-window probably have side-effects in ill-defined situation related to changing font size per window.
…. (toward ocornut#5143, ocornut#4868, ocornut#3692, ocornut#3518) This is not strictly required presently, but will be consistent with adding inner decoration sizes in next commit, as well as generally being sane. Locking TitleBarHeight() / MenuBarHeight() values per-window probably have side-effects in ill-defined situation related to changing font size per window.
Nechroposting a bit because I received a notification from user @rlrq97 asking how to implement the floating toolbar in this screenshot (I can't find the original comment anymore, maybe it was deleted). Maybe it's a bit off topic, but I don't know where to post this, and someone might find it useful. This is the final result using an embedded icon font. //
// Viewport panel
//
ImGuiWindowFlags viewportWindowFlags = ImGuiWindowFlags_MenuBar;
ImVec4 windowBg = style.Colors[ImGuiCol_WindowBg];
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0);
ImGui::PushStyleColor(ImGuiCol_WindowBg, {0, 0, 0, 0});
if (ImGui::Begin("Viewport", nullptr, viewportWindowFlags)) {
// Menu bar
if (ImGui::BeginMenuBar()) {
// ...
ImGui::EndMenuBar();
}
// Toolbar
float textHeight = ImGui::CalcTextSize("A").y;
int toolbarItems = 10;
// style.FramePadding can also be used here
ImVec2 toolbarItemSize = ImVec2{textHeight, textHeight} * 2.0f;
ImVec2 toolbarPos = ImGui::GetWindowPos() + ImGui::GetCursorPos();
ImVec2 toolbarSize = {toolbarItemSize.x + style.WindowPadding.x * 2.0f, //
toolbarItemSize.y * toolbarItems + style.WindowPadding.y * 2.0f};
ImGui::SetNextWindowPos(toolbarPos);
ImGui::SetNextWindowSize(toolbarSize);
ImGuiWindowFlags toolbarFlags = ImGuiWindowFlags_NoDecoration | //
ImGuiWindowFlags_NoMove | //
ImGuiWindowFlags_NoScrollWithMouse | //
ImGuiWindowFlags_NoSavedSettings | //
ImGuiWindowFlags_NoBringToFrontOnFocus;
ImGuiSelectableFlags selectableFlags = ImGuiSelectableFlags_NoPadWithHalfSpacing;
// You shouldn't need this. My parent window has a transparent bg so I set the original window bg color here.
ImGui::PushStyleColor(ImGuiCol_WindowBg, windowBg);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {0.0f, 0.0f});
if (ImGui::Begin("##ViewportToolbar", nullptr, toolbarFlags)) {
// Bring the toolbar window always on top.
ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow());
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f, 0.5f));
if (ImGui::Selectable(ICON_FA_MOUSE_POINTER, gCurrentBrush == Brush::Select, selectableFlags, toolbarItemSize)) {
gCurrentBrush = Brush::Select;
}
if (ImGui::Selectable(ICON_FA_PLUS, gCurrentBrush == Brush::Add, selectableFlags, toolbarItemSize)) {
gCurrentBrush = Brush::Add;
}
// More buttons ...
ImGui::Separator();
if (ImGui::Selectable(ICON_FA_PLUS_SQUARE, gCurrentBrush == Brush::AddChunk, selectableFlags, toolbarItemSize)) {
gCurrentBrush = Brush::AddChunk;
}
if (ImGui::Selectable(ICON_FA_MINUS_SQUARE, gCurrentBrush == Brush::RemoveChunk, selectableFlags, toolbarItemSize)) {
gCurrentBrush = Brush::RemoveChunk;
}
ImGui::PopStyleVar(); // ImGuiStyleVar_SelectableTextAlign
}
ImGui::End();
ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
ImGui::PopStyleColor(); // ImGuiCol_WindowBg
}
ImGui::End();
ImGui::PopStyleColor(); // ImGuiCol_WindowBg
ImGui::PopStyleVar(); // ImGuiStyleVar_FrameRounding One last thing, I think this issue can be closed. The original request, having the possibility to have a secondary menu bar under the main one, can be achieved with |
Version/Branch of Dear ImGui:
Version: 1.79
Branch: docking
Back-end/Renderer/Compiler/OS
Back-ends: imgui_impl_opengl3.cpp + imgui_impl_sdl.cpp
Compiler: msvc
Operating System: Windows 10
My Issue/Question:
How to create a multiline menu bar or many menu bars?
I'd like to achieve something like this:
or like this:
where the first menu bar has
file
etc.and the second menu bar right under it (or the same menu bar, but with widgets next lined) with options like unity or visual studio has (unity: hand button, rotation button, play scene, pause scene, etc.)
I also want to have full docking and viewport functionality.
I tried to use
ImGui::NextLine()
, it does not work, andbut it does not work as a regular widget I guess so a new menu bar hasn't been created under the main one.
The text was updated successfully, but these errors were encountered: