ocornut / imgui

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

BeginViewportSideBar() and moving windows with ConfigWindowsMoveFromTitleBarOnly #7118

Open KennyProgrammer opened 11 months ago

KennyProgrammer commented 11 months ago

Version/Branch of Dear ImGui:

Version: 1.88 Branch: docking

Back-end/Renderer/Compiler/OS

Back-ends imgui_impl_win32.cpp + imgui_impl_opengl3.cpp/ imgui_impl_dx11.cpp Compiler: MSVC Operating System: Windows 10

My Issue/Question: When I try to move a window through the sidebar (aka ImGui::BeginViewportSideBar() ), just as I move a window to any area of the main window, the position of the window being moved to the border of the sidebar. This happens only when I create it with UP direction, when I create a sidebar, for example, for a status bar with the DOWN direction, there is nothing like that, everything works fine.

Also when popups, tooltips or any window are opened on sidebar, it shifts its position to dockspace window (e.g. below all sibebars).

Standalone, minimal, complete and verifiable example:

Here example how i create tool bar using sidebar:

ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)ImGui::GetMainViewport();
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus;

// Toolbar Window (Panel) uses as BeginViewportSideBar.
ImGui::BeginViewportSideBar("##ToolBar", viewport, ImGuiDir_Up, 28.0f, windowFlags | ImGuiWindowFlags_NoNavInputs);

// ... render some content here...

ImGui::End();

Screenshots/Video

Here a few videos how what problem looks like:

In first video firstly i show how it should be and then when i move window into main window the window doesnt move above sidebar.

https://github.com/ocornut/imgui/assets/56895345/263d4cf1-4718-4e3a-aecb-653a31f43b0e

And the same with another windows (tooltips, popups, etc)

https://github.com/ocornut/imgui/assets/56895345/cefe1bb6-a276-489f-a933-10ee6075df34

PS: I know that ImGui::BeginViewportSideBar() API is beta and not public, so its actually bug of this function or problem because it called BeginViewportand work with viewports not with windows? So if it is, the are exist alternative ways to create toolbars?

PSS: This is not critical but really annoying that you can move windows through sidebars.

ocornut commented 11 months ago

Do you have io.ConfigWindowsMoveFromTitleBarOnly set to true?

If you can only move a window by its title bar we make it so that title bar can never be over a side bar (e.g. main menu bar). Otherwise we would need to guarantee that your window can never be covered by the side bar.

Perhaps we can have a system where if you specify ImGuiWindowFlags_NoBringToFrontOnFocus for the side bar then its geometry is declared differently in viewport->WorkRect.

If you don't call BeginViewportSideBar() more than once, you can backup and restore viewport->BuildWorkOffsetMin and viewport->BuildWorkOffsetMax in order to not alter the viewport WorkRect. Or you may do this directly:

ImGui::SetNextWindowPos(viewport->Pos);
ImGui::SetNextWindowSize(viewport->Size);
ImGui::Begin(....);
KennyProgrammer commented 11 months ago

Do you have io.ConfigWindowsMoveFromTitleBarOnly set to true?

Yes, I have this flag set, I put it a long time ago, it seems to have solved one of my problems earlier. I'll try to remove it and see if something else breaks.

After test: This actually fix problem on 50%, now another issue happens that when this window intersects with platform non-client area that i defined for my main window, i cannot move that window, because it acts as non-client and move main window instead. Perhaps this can be resolved in the same way as I blocked non-client area interaction for any widget inside the title bar that is located in the non-client area. (e.g. by returning client area instead in windows code when ImGui::IsAnyItemActive())

If you can only move a window by its title bar we make it so that title bar can never be over a side bar (e.g. main menu bar). Otherwise we would need to guarantee that your window can never be covered by the side bar.

I did not understand the last sentence a little, why not just let the window move freely (at least at the moment when it is inside the main window (because it does not use the platform window interface))

Perhaps we can have a system where if you specify ImGuiWindowFlags_NoBringToFrontOnFocus for the side bar then its geometry is declared differently in viewport->WorkRect.

I noticed that I don't have this flag on the sidebar, I'll try to set it and maybe it will be a solution.

If you don't call BeginViewportSideBar()more than once, you can backup and restore viewport->BuildWorkOffsetMin and viewport->BuildWorkOffsetMax in order to not alter the viewport WorkRect.

I call this more that once, for TitleBar, MenuBar, Toolbar and StatusBar.

KennyProgrammer commented 11 months ago

So i finally resolve problem. For most cases and users that use ImGui setting io.ConfigWindowsMoveFromTitleBarOnly to false will be enough witch is by default.

But for my game engine case not. So i read code and found where ConfigWindowsMoveFromTitleBarOnly actually used.

I don't like to modify the source code of any library, but I had to. At least until there is an alternative solution. So I created a new ConfigWindowsMoveFromTitleBarOnlyEx flag in imgui.h which I wrapped in the FE_IMGUI_C0005 macro (yes, I have already modified ImGui 4 times, not significant changes, but significant for my engine) so that it could be turned off and it was easier for me to switch to the new version. And implemented only for the first case, ignoring the second. And set this flag to true insted original ConfigWindowsMoveFromTitleBarOnly, and it worked.

https://github.com/ocornut/imgui/assets/56895345/9aec7b4c-7fdd-4866-9d1a-d22b942c7401

ocornut commented 11 months ago

Second it used in ClampWindowRect unfortunately, I do not fully understand why (it may solve some other problem). But this was actual problem in my case.

Because otherwise your window can get stuck behind another window and you can never move it again is the only moving pointi s the title bar.

KennyProgrammer commented 11 months ago

Because otherwise your window can get stuck behind another window and you can never move it again is the only moving pointi s the title bar.

Well, for this, as I understand it, there is already a check here so technically we shouldn't be in this situation.

UpdateMouseMovingWindowEndFrame

or rather, in these lines:

 if (g.IO.ConfigWindowsMoveFromTitleBarOnly)
     if (!(root_window->Flags & ImGuiWindowFlags_NoTitleBar) || root_window->DockIsActive)
         if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
             g.MovingWindow = NULL;

By the second case, I meant this function:

static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& visibility_rect)
{
    ImGuiContext& g = *GImGui;
    ImVec2 size_for_clamping = window->Size;
    if (g.IO.ConfigWindowsMoveFromTitleBarOnly && (!(window->Flags & ImGuiWindowFlags_NoTitleBar) || window->DockNodeAsHost))
        size_for_clamping.y = ImGui::GetFrameHeight(); // Not using window->TitleBarHeight() as DockNodeAsHost will report 0.0f here.
    window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);
}

Here when used g.IO.ConfigWindowsMoveFromTitleBarOnly, it set size_for_clamping.y as ImGui::GetFrameHeight() of the window i guess.

Exactly when I originally had ConfigWindowsMoveFromTitleBarOnly to true it calls this: size_for_clamping.y = ImGui::GetFrameHeight();

and then i cannot move window througth sidebar.

ocornut commented 11 months ago

You misunderstood my message, read it again. Without this position clamping code (the second part) it would become possible to "lose" a window behind a sidebar and never be able to move it again.

The only valid case where it would be acceptable to alter the clamping logic is if we can guarantee that the sidebar will never be brought to front on focus.

KennyProgrammer commented 11 months ago

Now I got it. It's just that I've been testing it and I've never had a case where the sidebar came to the fore. And then I saw that I already had the ImGuiWindowFlags_NoBringToFrontOnFocus flag set on the sidebar which guarantee that the sidebar will never be brought to front on focus.

Sorry, for misunderstanding.

KennyProgrammer commented 11 months ago

Like this: image And i guess if i make status bar even bigger and without ImGuiWindowFlags_NoBringToFrontOnFocus that will be what you talking about.

ocornut commented 11 months ago

But I think we can improve the situation if ImGuiWindowFlags_NoBringToFrontOnFocus is set.

KennyProgrammer commented 11 months ago

Exactly, and especially when ConfigWindowsMoveFromTitleBarOnly is set to true + ImGuiWindowFlags_NoBringToFrontOnFocus on sidebar, so as not to create such minor problems.

Anyways, thank you :)