ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
57.74k stars 9.9k forks source link

Adapting custom title bar widgets to the docking branch #5115

Open simongeilfus opened 2 years ago

simongeilfus commented 2 years ago

Version/Branch of Dear ImGui:

Version: 1.88 WIP / 18709 Branch: docking

Back-end/Renderer/Compiler/OS

Back-ends: currently imgui_impl_glfw but issue not back-end related Compiler: issue not building/platform related Operating System: issue not building/platform related

My Issue/Question/Context:

I've been depending for a while on a couple of custom widgets that use the available space in the window's title bar. Mostly a TitleBarIcon and a Begin/EndTitleBarMenu that push small buttons left and right of the title bar title. Nothing especially hacky apart from a PushClipRect to get access to the window's TitleBarRect and a SetCursorPos for laying out the buttons.

image

As discussed in other threads, despite the advantages of using that empty space it does open all sort of conflicts in a context where all windows are dockable. Per-window "title bar widgets" don't have an obvious place to move to when those title bars are turned into tabs.

That said I can totally live with the limitation of those widgets being limited to "non-dockable-into" windows (or windows that won't actually use their dockspace's tab bar). I'm currently enforcing that with ImGuiWindowClass / ImGuiDockNodeFlags_NoDockingOverMe on that kind of windows and I'm absolutely happy with the fact that those windows can't turn into tabs.

image

Now for the actual issue;

Widgets within a window TitleBarRect are hoverable and clickable until their host window become docked.

I understand that DockNodeUpdateTabBar requires a ButtonBehavior to be able to drag that node from the tab bar. And this seems to be the primary widget overlapping with my buttons. (no cursor in the following screenshot but the mouse is clicking inside the red area). image

But even after commenting the block surrounding that ButtonBehavior I can't seem to figure out who else is stealing mouse events. There is an active ID when clicking in the tab bar but it's a bit hard to tell to whom it belongs to (again, no cursor in the following screenshot but the mouse is clicking inside the red area). image

And the questions;

Is there any workaround to get back mouse events inside the dock node's tab bar? Or alternatively/ideally is there any plan to support windows that can dock without a tab bar (using their title bar instead)?

I know ImGuiDockNodeFlags_HiddenTabBar is not too far off my second question but unfortunately it's missing the "please render the original title bar instead". As I understand it ImGuiDockNodeFlags_NoDockingOverMe prevents the window's tab bar to ever be used, so would it work, at least conceptually to have those windows keep their regular title bar when this flag is set?

Standalone, minimal, complete and verifiable example:

ImGuiIO &io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
ImGui::Begin( "Title" );
const ImGuiWindow* window = ImGui::GetCurrentWindow();
const ImRect titleBarRect = window->TitleBarRect();
ImGui::PushClipRect( titleBarRect.Min, titleBarRect.Max, false );
ImGui::SetCursorPos( ImVec2( 80.0f, 0.0f ) );
// button works fine until the window is docked
ImGui::Button( "Overlapping Button" );
ImGui::PopClipRect();
ImGui::End();

Sorry for the long read - and this lovely "can-of-worm-friendly" edge case. Any suggestion would be very much appreciated.

Thanks!

Edit: I realized it's not entirely obvious because of the lack of collapse/dock buttons but all the screenshots above apart from the first one are from docked windows.

AlexvZyl commented 2 years ago

I have a similar issue which might need the same solution as this one - I built an event layer on top of imgui (I have multiple engines running at the same time, so it was necessary to do this to properly dispatch events in an elegant way, but is not important) and I use ImGui::IsWindowHovered() to detect which of my windows are hovered (#4992). I use a modified version of that function, so I refrained from opening an issue. My problem is that when the mouse hovers the tab of a docked window, that function does not register the window as hovered, preventing me from properly changing focus and some other things regarding the renderer.

https://github.com/ocornut/imgui/blob/2c03aac6d30720d8f717dcd9cbb8b9a6799396b8/imgui.h#L345

My hacked function for reference:

https://github.com/Alex-vZyl/imgui/blob/21307a2884c885c290f079cfd50a72fcec7dc2b7/imgui.cpp#L7570-L7607

P.S. I really like what you did with the buttons in the tab bar!

luis605 commented 2 months ago

Hi, is it possible to make the button clickable?

ImGui::Begin( "Title" );
const ImGuiWindow* window = ImGui::GetCurrentWindow();
const ImRect titleBarRect = window->TitleBarRect();
ImGui::PushClipRect( titleBarRect.Min, titleBarRect.Max, false );
ImGui::SetCursorPos( ImVec2( 80.0f, 0.0f ) );
// button works fine until the window is docked
ImGui::Button( "Overlapping Button" );
ImGui::PopClipRect();
ImGui::End();
ocornut commented 2 months ago

I am going to work on a proper solution for this for 1.91.

It's going to be quite a large task to do right, and it also interfere with the intent of "fixing" the Begin() API: if we switch to mandatory check of Begin() return value, it means we don't enter into a collapsed window or non-selected tabs, YET title bar contents still needs to be submitted.