ocornut / imgui

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

How to constrain the docking of a window #3492

Open GdLinkLock opened 4 years ago

GdLinkLock commented 4 years ago

Version/Branch of Dear ImGui:

Version: 1.78 Branch: master/viewport/docking

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_win32.cpp + imgui_impl_dx9.cpp Compiler:vs2019 Operating System: win10

My Issue/Question: Is there any way to control the docking of a window?

Screenshots/Video docking test

For example,I have there windows,they can dock to each other. What I want to achieve is only window2 and window3 can dock to each other. As far as I know, We can ues ImGuiWindowFlags_NoDocking to disable docking of a window,but is there any way to control the docking of a window?

enum ImGuiWindowFlags_
{
    ImGuiWindowFlags_None                   = 0,
     ......
    ImGuiWindowFlags_NoDocking              = 1 << 21,  // Disable docking of this window

Standalone, minimal, complete and verifiable example:

        ImGui::Begin("window1");
        ImGui::End();

        ImGui::Begin("window2");
        ImGui::End();

        ImGui::Begin("window3");
        ImGui::End();

Thanks in advance.

rokups commented 4 years ago

I think this can be achieved by using SetNextWindowClass() and passing same class to DockSpace*(). I do not have an example for you however, as i have not used this functionality.

ocornut commented 4 years ago

See the ImGuiWindowClass structure and SetNextWindowClass().

GdLinkLock commented 4 years ago

I think this can be achieved by using SetNextWindowClass() and passing same class to DockSpace*(). I do not have an example for you however, as i have not used this functionality.

thank you,I will try.

GdLinkLock commented 4 years ago

See the ImGuiWindowClass structure and SetNextWindowClass().

thank you ocornut,I will try.

GdLinkLock commented 4 years ago

@rokups @ocornut Thanks for the advice,it works for me.
window1 cannot dock Below is the sample code

ImGuiWindowClass window_class1;
window_class1.DockNodeFlagsOverrideSet = ImGuiDockNodeFlags_NoDockingOverMe | 
ImGuiDockNodeFlags_NoDockingOverOther | ImGuiDockNodeFlags_NoDockingSplitOther;
ImGui::SetNextWindowClass(&window_class1);
ImGui::Begin("Window1");
ImGuiID dockSpace1 = ImGui::GetID("dockSpace1");
ImGui::DockSpace(dockSpace1);
ImGui::End();

But I have another question. I add more windows . What I want to achieve is:

I have tried ImGui::SetNextWindowDockID,but it Can't achieve my goal. Could you provide some more suggestions?

Screenshots/Video sub window dock any Standalone, minimal, complete and verifiable example:

{
    ImGuiWindowClass window_class1;
    window_class1.DockNodeFlagsOverrideSet = ImGuiDockNodeFlags_NoDockingOverMe | ImGuiDockNodeFlags_NoDockingOverOther | ImGuiDockNodeFlags_NoDockingSplitOther;
    ImGui::SetNextWindowClass(&window_class1);
    ImGui::Begin("Window1");
    ImGuiID dockSpace1 = ImGui::GetID("dockSpace1");
    ImGui::DockSpace(dockSpace1);
    ImGui::End();

    ImGui::Begin("Window1_A");
    ImGui::End();

    ImGui::Begin("Window1_B");
    ImGui::End();

}

{
    ImGui::Begin("Window2");
    ImGuiID dockSpace2 = ImGui::GetID("dockSpace2");
    ImGui::DockSpace(dockSpace2);
    ImGui::End();

    ImGui::SetNextWindowDockID(dockSpace2, ImGuiCond_FirstUseEver);
    ImGui::Begin("Window2_A");
    ImGui::End();

    ImGui::SetNextWindowDockID(dockSpace2, ImGuiCond_FirstUseEver);
    ImGui::Begin("Window2_B");
    ImGui::End();
}

{
    ImGui::Begin("Window3");
    ImGuiID dockSpace3 = ImGui::GetID("dockSpace3");
    ImGui::DockSpace(dockSpace3);
    ImGui::End();

    ImGui::SetNextWindowDockID(dockSpace3,ImGuiCond_Always);
    ImGui::Begin("Window3_A");
    ImGui::End();

    ImGui::SetNextWindowDockID(dockSpace3, ImGuiCond_Always);
    ImGui::Begin("Window3_B");
    ImGui::End();
}
ocornut commented 4 years ago

Window1_A、 Window1_B can only dock into Window1 Window2_A、 Window2_B can only dock into Window2 Window3_A、 Window3_B can only dock into Window3

You should use the ClassID field of ImGuiWindowClass to do that filtering. Have each of them use an unique ClassID (e.g. GetID("Window1").

GdLinkLock commented 3 years ago

@ocornut Thanks again.

You should use the ClassID field of ImGuiWindowClass to do that filtering. Have each of them use an unique ClassID (e.g. GetID("Window1").

I have tried the ClassID,It can constrain the Window1_A、Window1_B only dock into Window. But is there a way to constrain Window2、 Window3 only dock over each other. More precisely:

Screenshots/Video window2-window3-dock-each-other

Standalone, minimal, complete and verifiable example

{
    ImGuiWindowClass window_class2;
    window_class2.ClassId = ImGui::GetID("XXX");
    window_class2.DockNodeFlagsOverrideSet = ImGuiDockNodeFlags_NoDockingSplitOther | ImGuiDockNodeFlags_NoDockingSplitMe;
    window_class2.DockingAllowUnclassed = false;

    //-----------------Window2------------------------------
    ImGui::SetNextWindowClass(&window_class2);
    ImGui::Begin("Window2");

    ImGuiID dockSpace2 = ImGui::GetID("dockSpace2");
    ImGui::DockSpace(dockSpace2);

    ImGui::End();

    ImGuiWindowClass window_class2_for_subwindow;
    window_class2_for_subwindow.ClassId = ImGui::GetID("Window2");
    window_class2_for_subwindow.DockNodeFlagsOverrideSet = 0;
    window_class2_for_subwindow.DockingAllowUnclassed = true;

    //-----------------Window2_A------------------------------
    ImGui::SetNextWindowClass(&window_class2_for_subwindow);
    ImGui::Begin("Window2_A");
    ImGui::End();

    //-----------------Window2_B------------------------------
    ImGui::SetNextWindowClass(&window_class2_for_subwindow);
    ImGui::Begin("Window2_B");
    ImGui::End();

    //-----------------Window2_C------------------------------
    ImGui::SetNextWindowClass(&window_class2_for_subwindow);
    ImGui::Begin("Window2_C");
    ImGui::End();
}

{
    //-----------------window3------------------------------
    ImGuiWindowClass window_class3;
    window_class3.ClassId = ImGui::GetID("XXX");
    window_class3.DockNodeFlagsOverrideSet = ImGuiDockNodeFlags_NoDockingSplitOther | ImGuiDockNodeFlags_NoDockingSplitMe ;
    window_class3.DockingAllowUnclassed = false;
    ImGui::SetNextWindowClass(&window_class3);
    ImGui::Begin("Window3");

    ImGuiID dockSpace3 = ImGui::GetID("dockSpace3");
    ImGui::DockSpace(dockSpace3);

    ImGui::End();

    ImGuiWindowClass window_class3_for_subwindow;
    window_class3_for_subwindow.ClassId = ImGui::GetID("Window3");
    window_class3_for_subwindow.DockNodeFlagsOverrideSet =  0;
    window_class3_for_subwindow.DockingAllowUnclassed = true;

    //-----------------Window3_A------------------------------
    ImGui::SetNextWindowClass(&window_class3_for_subwindow);
    ImGui::Begin("Window3_A");
    ImGui::End();

    //-----------------Window3_B------------------------------
    ImGui::SetNextWindowClass(&window_class3_for_subwindow);
    ImGui::Begin("Window3_B");
    ImGui::End();
}
markitus18 commented 3 years ago

Hi GgLinkLock,

I believe what you are looking for is ImGui::DockSpace(ImGuiID, const ImVec2&, ImGuiDockNodeFlags, **const ImGuiWindowClass***)

For example: When you are generating a new Dockspace for Window 2 you should include your window_class_2_for_subwindow as a parameter. I think this should work in your current setup.

For more complex setups I suggest you to use a class structure to wrap the content of every window in your program. In my project I am using a WindowFrame class (your Window 2 and Window 3 windows) and a Window class (your subwindow clases). A WindowFrame holds an array of Window objects. This way you can give a specific ImGuiWindowClass to any window type on inizialization.