Search code examples
c++imgui

How do I make a dockable window fill up the remaining dockspace programatically?


I have a simple application with 2 dockable windows in a dockspace. One is sidebar and the other is the content.

I am using the docking branch of imgui

How do I make the content window fill up the remaining dockspace programmatically? Kind of like Visual Studio Code

Currently, there is some weird space between the sidebar and the content window

Current Output Expected Output, I got this by manually dragging the window and docking it

I do it like this

static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode;
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking;

ImGuiViewport* viewport = ImGui::GetMainViewport();

ImGui::SetNextWindowPos(viewport->Pos);
ImGui::SetNextWindowSize(viewport->Size);
ImGui::SetNextWindowViewport(viewport->ID);

ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
window_flags |= ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;

if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
    window_flags |= ImGuiWindowFlags_NoBackground;

ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(1.0f, 0.0f));
ImGui::Begin("Root", nullptr, window_flags);
ImGui::PopStyleVar();
ImGui::PopStyleVar(2);

// Dockspace
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
{
    ImGuiID dockspace_id = ImGui::GetID("Root");
    ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
    
    static auto first_time = true;
    if (first_time)
    {
        first_time = false;
        
        ImGui::DockBuilderRemoveNode(dockspace_id);
        ImGui::DockBuilderAddNode(dockspace_id, dockspace_flags | ImGuiDockNodeFlags_DockSpace);
        ImGui::DockBuilderSetNodeSize(dockspace_id, viewport->Size);
        
        auto dock_id_left = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left, 0.2f, nullptr, &dockspace_id);
        auto dock_id_right = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right, 1.0f, nullptr, &dockspace_id);
        
        ImGui::DockBuilderDockWindow("Sidebar", dock_id_left);
        ImGui::DockBuilderDockWindow("Content", dock_id_right);
        ImGui::DockBuilderFinish(dockspace_id);
    }
}


ImGui::Begin("Sidebar");
ImGui::Text("Text 1");
ImGui::Text("Text 2");
ImGui::Text("Text 3");
ImGui::End();

ImGui::Begin("Content");
ImGui::Button("Button 1");
ImGui::Button("Button 2");
ImGui::Button("Button 3");
ImGui::End();

Solution

  • I eventually figured this same issue out thanks to this comment on the docking thread. Intuitively you want to create a "dock node" for each space, but in ImGui terms we're really docking one window to the side and docking the other window to the central dock space which will make it take up the remaining space.

    Therefore your code should look like this to get one docked side bar and one (or more) window(s) in the remaining space:

    ImGuiIO& io = ImGui::GetIO();
    if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) {
        ImGuiID dockspace_id = ImGui::GetID("MyDockspace");
        ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
    
        static auto first_time = true;
        if (first_time)
        {
            first_time = false;
            // Clear out existing layout
            ImGui::DockBuilderRemoveNode(dockspace_id);
            // Add empty node
            ImGui::DockBuilderAddNode(dockspace_id, dockspace_flags | ImGuiDockNodeFlags_DockSpace);
            // Main node should cover entire window
            ImGui::DockBuilderSetNodeSize(dockspace_id, ImGui::GetWindowSize());
            // get id of main dock space area
            ImGuiID dockspace_main_id = dockspace_id;
            // Create a dock node for the right docked window
            ImGuiID right = ImGui::DockBuilderSplitNode(dockspace_main_id, ImGuiDir_Right, 0.25f, nullptr, &dockspace_main_id);
    
            ImGui::DockBuilderDockWindow("Content One", dockspace_main_id);
            ImGui::DockBuilderDockWindow("Content Two", dockspace_main_id);
            ImGui::DockBuilderDockWindow("Side Bar", right);
            ImGui::DockBuilderFinish(dockspace_id);
        }
    }
    

    When using two windows like this, they show up as tabbed window in the main space.