Skip to content
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

Docking: saving layout #8033

Open
Zaryob opened this issue Oct 1, 2024 · 3 comments
Open

Docking: saving layout #8033

Zaryob opened this issue Oct 1, 2024 · 3 comments
Labels
docking settings .ini persistance

Comments

@Zaryob
Copy link

Zaryob commented Oct 1, 2024

Version/Branch of Dear ImGui:

Branch: docking, Commit: 7937732

Back-ends:

imgui_impl_opengl3.cpp + imgui_impl_XXX.cpp

Compiler, OS:

macOS + Clang 12, GCC, Windows + MSVC

Full config/build information:

No response

Details:

I'm trying to crate a docking area with following code:


    // Get the available space under the buttons
    ImVec2 availableSpaceForDocking = ImGui::GetContentRegionAvail();

    // Create a child region with a dockspace in the remaining space
    ImGui::BeginChild("DockingRegion", availableSpaceForDocking, false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);

    ImGuiID dockspace_id = ImGui::GetID("DockSpace");
    ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), DOCKSPACE_FLAGS);

    if (firstMenuRender) {
        ImGui::DockBuilderRemoveNode(dockspace_id);
        ImGui::DockBuilderAddNode(dockspace_id, DOCKSPACE_FLAGS);
        ImGui::DockBuilderSetNodeSize(dockspace_id, availableSpaceForDocking);

        ImGuiID dockspace_left = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left, 0.2f, nullptr, &dockspace_id);
        ImGui::DockBuilderDockWindow("Waterfall", dockspace_id);
        ImGui::DockBuilderFinish(dockspace_id);

        ImGuiID dockspace_left_down = ImGui::DockBuilderSplitNode(dockspace_left, ImGuiDir_Down, 0.2f, nullptr, &dockspace_left);

        ImGui::DockBuilderDockWindow("Menu", dockspace_left);
        ImGui::DockBuilderDockWindow("Debug", dockspace_left_down);
        ImGui::DockBuilderFinish(dockspace_left);

    }
    ImGui::EndChild();

After that I'm filling "Menu", "Debug" and "Waterfall" windows. But If I want to save this layout to ini file all of my layout corrupts.

Inside of my ini file is that:

[Window][Waterfall]
Pos=308,87
Size=1196,753
Collapsed=0
DockId=0x00000002,0

[Window][Menu]
Pos=8,87
Size=298,600
Collapsed=0
DockId=0x00000003,0

[Window][Debug]
Pos=8,689
Size=298,151
Collapsed=0
DockId=0x00000004,0

[Window][Main]
Pos=0,0
Size=1512,848
Collapsed=0

[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0

[Window][Credits]
Pos=450,305
Size=612,238
Collapsed=0

[Docking][Data]
DockSpace     ID=0x1E887784 Window=0xE8252DDA Pos=8,87 Size=1496,753 Split=X
  DockNode    ID=0x00000001 Parent=0x1E887784 SizeRef=298,753 Split=Y
    DockNode  ID=0x00000003 Parent=0x00000001 SizeRef=298,600 Selected=0xA57AB2C6
    DockNode  ID=0x00000004 Parent=0x00000001 SizeRef=298,151 Selected=0x392A5ADD
  DockNode    ID=0x00000002 Parent=0x1E887784 SizeRef=1196,753 Selected=0xDF29319E

Original layout:
Screenshot 2024-10-01 at 20 56 40

After ini file loaded:
Screenshot 2024-10-01 at 20 58 22

It seems all windows goes 0,0 point.

How does it possible? Is there any solution?

Edit:

When I save this layout it seems configuration on ini file is corrupted:

[Window][Waterfall]
Pos=8,87
Size=1360,687
Collapsed=0

[Window][Menu]
Pos=8,87
Size=300,547
Collapsed=0

[Window][Debug]
Pos=0,0
Size=213,268
Collapsed=0

[Window][Main]
Pos=0,0
Size=1512,782
Collapsed=0

[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0

[Window][Credits]
Pos=450,305
Size=612,238
Collapsed=0

[Docking][Data]
DockSpace ID=0x1E887784 Window=0xE8252DDA Pos=8,87 Size=1496,687 CentralNode=1

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

No response

@Zaryob Zaryob changed the title Docking Saving layout [Docking] Saving layout Oct 1, 2024
@ocornut ocornut added docking settings .ini persistance labels Oct 2, 2024
@Zaryob
Copy link
Author

Zaryob commented Oct 2, 2024

In addition to loading from ini file I also tried to build with this code:

#define IMGUI_HAS_DOCK

#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include <imgui_internal.h>
#include <GLFW/glfw3.h> // Include glfw3.h after our OpenGL definitions
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <sstream>

// Helper function to split string by a delimiter
std::vector<std::string> split(const std::string& s, char delimiter) {
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream(s);
    while (std::getline(tokenStream, token, delimiter)) {
        tokens.push_back(token);
    }
    return tokens;
}

bool firstTime=true;

// Function to setup docking from a given INI style string
void setupDockingFromINI(const std::string& iniStyleConfig) {
    // Example of iniStyleConfig:
    // "[Docking][Data]\nDockNode ID=0x1E887784 Pos=0,0 Size=1264,651 Split=X\nDockNode ID=0x00000001 Parent=0x1E887784 SizeRef=252,651 Split=Y\n..."

    // Parsing the configuration
    std::istringstream configStream(iniStyleConfig);
    std::string line;
    std::map<ImGuiID, ImGuiID> dockParents;
    std::vector<std::string> dockSettings;

    while (std::getline(configStream, line)) {
        if (line.find("DockNode") != std::string::npos) {
            dockSettings.push_back(line);
        }
    }

    // Clear any previous dockspace
    //ImGuiID dockspaceId = ImGui::GetID("Dockspace");
    //ImGui::DockBuilderRemoveNode(dockspaceId); // Clear out existing layout
    //ImGui::DockBuilderAddNode(dockspaceId, ImGuiDockNodeFlags_DockSpace); // Add back the node
    //ImGui::DockBuilderSetNodeSize(dockspaceId, ImGui::GetMainViewport()->Size);

    // Process each DockNode setting
    ImGui::BeginChild("DockingRegion");

    bool processed=false;

    ImGuiID processed_id;
    if(firstTime){
    for (const auto& setting : dockSettings) {
        auto tokens = split(setting, ' ');
        ImGuiID id = 0, parent = 0;
        bool splitSet = false;
        ImGuiDir splitDir = ImGuiDir_None;

        for (const auto& token : tokens) {
            auto keyVal = split(token, '=');
            if (keyVal.size() < 2) continue;
            auto& key = keyVal[0];
            auto& value = keyVal[1];

            if (key == "ID") {
                id = std::stoul(value, nullptr, 16);
                dockParents[id] = 0;
            } else if (key == "Parent") {
                parent = std::stoul(value, nullptr, 16);
                dockParents[id] = parent;
            } else if (key == "Split") {
                splitSet = true;
                if (value == "X") splitDir = ImGuiDir_Left;
                else if (value == "Y") splitDir = ImGuiDir_Up;
            }
        }

        if (splitSet) {
            // Assume we split with some standard ratio for simplicity
            float splitRatio = 0.5f;

            if(!processed){
                processed=true;
                ImGui::DockSpace(processed_id, ImVec2(100.0f, 100.0f), ImGuiDockNodeFlags_PassthruCentralNode);
                ImGui::DockBuilderRemoveNode(id);

            }
            ImGui::DockBuilderAddNode(id, ImGuiDockNodeFlags_DockSpace); // Add back the node

            ImGuiID newId = ImGui::DockBuilderSplitNode(id, splitDir, splitRatio, nullptr, &id);
            dockParents[id] = newId;
        }
    }
    // Finish by docking some windows
    //ImGui::DockBuilderDockWindow("Window1", 0x00000001);
    ImGui::DockBuilderDockWindow("Window2", 0x00000003);
    ImGui::DockBuilderDockWindow("Window3", 0x00000004);
    ImGui::DockBuilderFinish(0x00000001);
    }
    if(!firstTime){
        ImGui::DockSpace(processed_id, ImVec2(100.0f, 100.0f), ImGuiDockNodeFlags_PassthruCentralNode);
        firstTime=false;
    }
    else{
        firstTime=false;

        size_t ini_data_size = 0;
        const char* ini_data = ImGui::SaveIniSettingsToMemory(&ini_data_size);
        std::cout<<std::endl<<"STD"<<std::endl<<ini_data<<std::endl;
    }
    ImGui::EndChild();

}

// Example use case within your ImGui main loop
void render() {
    ImGui::NewFrame();

    // Define the INI-style config string
    std::string iniConfig = R"(
        [Docking][Data]
        DockNode ID=0x1E887784 Pos=0,0 Size=1264,651 Split=X
        DockNode ID=0x00000001 Parent=0x1E887784 SizeRef=252,651 Split=Y
        DockNode ID=0x00000003 Parent=0x00000001 SizeRef=252,519
        DockNode ID=0x00000004 Parent=0x00000001 SizeRef=252,130
    )";

    // Setup docking as specified in the iniConfig
    setupDockingFromINI(iniConfig);

    // Rendering and other ImGui windows here
    ImGui::Begin("Window1");
    ImGui::Text("Content of Window 1");
    ImGui::End();

    ImGui::Begin("Window2");
    ImGui::Text("Content of Window 2");
    ImGui::End();

    ImGui::Begin("Window3");
    ImGui::Text("Content of Window 3");
    ImGui::End();

    ImGui::Render();
}
static void glfw_error_callback(int error, const char* description)
{
    std::cerr << "Glfw Error " << error << ": " << description << std::endl;
}

int main(int, char**)
{
    // Setup window
    glfwSetErrorCallback(glfw_error_callback);
    if (!glfwInit())
        return 1;

    // GL 3.0 + GLSL 130
    const char* glsl_version = "#version 130";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);

    // Create window with graphics context
    GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui - Docking Example", NULL, NULL);
    if (window == NULL)
        return 1;
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1); // Enable vsync

    // Initialize OpenGL loader
    if (glfwInit() != GLFW_TRUE)
    {
        std::cerr << "Failed to initialize OpenGL loader!" << std::endl;
        return 1;
    }

    // Setup Dear ImGui context
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO();
    io.IniFilename = NULL;
    io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking

    // Setup Dear ImGui style
    ImGui::StyleColorsDark();

    // Setup Platform/Renderer backends
    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init(glsl_version);

    // Main loop
    while (!glfwWindowShouldClose(window))
    {
        // Poll and handle events (inputs, window resize, etc.)
        glfwPollEvents();

        // Start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();

        render();

        int display_w, display_h;
        glfwGetFramebufferSize(window, &display_w, &display_h);
        glViewport(0, 0, display_w, display_h);
        glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        glfwSwapBuffers(window);
    }

    // Cleanup
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();

    glfwDestroyWindow(window);
    glfwTerminate();

    return 0;
}

I’m waiting to get:


[Docking][Data]
        DockNode ID=0x1E887784 Pos=0,0 Size=1264,651 Split=X
        DockNode ID=0x00000001 Parent=0x1E887784 SizeRef=252,651 Split=Y
        DockNode ID=0x00000003 Parent=0x00000001 SizeRef=252,519
        DockNode ID=0x00000004 Parent=0x00000001 SizeRef=252,130

as written in used ini string but getting:


[Docking][Data]
DockSpace   ID=0x00000001 Pos=0,0 Size=0,0 Split=Y
  DockNode  ID=0x00000002 Parent=0x00000001 SizeRef=0,32
  DockNode  ID=0x00000003 Parent=0x00000001 SizeRef=0,32 CentralNode=1
DockSpace   ID=0x1E887784 Pos=0,0 Size=0,0 CentralNode=1
DockSpace   ID=0xF7367248 Window=0x0AA2306B Pos=68,87 Size=100,100 CentralNode=1

@Zaryob
Copy link
Author

Zaryob commented Oct 2, 2024

I have get some approach:

#include <json.hpp>
#include <imgui/imgui.h>
#include <imgui/imgui_internal.h>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>

using json = nlohmann::json;

struct DockNodeInfo {
    ImGuiID nodeID;
    int splitAxis;
    ImVec2 size;
    ImGuiDockNodeFlags sharedFlags;
    ImGuiDockNodeFlags localFlags;
    ImGuiDockNodeFlags mergedFlags;
    int state;
    std::vector<std::string> windows;
    DockNodeInfo* child[2] = { nullptr, nullptr }; // To hold child nodes
};

json serializeDockNode(ImGuiDockNode* node)
{
    if (!node) return nullptr;

    json j;
    j["NodeID"] = node->ID;
    j["SplitAxis"] = node->SplitAxis;
    j["Size"] = { node->Size.x, node->Size.y };
    j["SharedFlags"] = node->SharedFlags;
    j["LocalFlags"] = node->LocalFlags;
    j["LocalFlagsInWindows"] = node->LocalFlagsInWindows;
    j["MergedFlags"] = node->MergedFlags;
    j["State"] = node->State;

    // Serialize docked windows
    if (!node->Windows.empty()) {
        j["Windows"] = json::array();
        for (ImGuiWindow* window : node->Windows) {
            json window_info;
            window_info["WindowID"] = window->ID;
            window_info["WindowName"] = window->Name;
            j["Windows"].push_back(window_info);
        }
    }

    // Serialize child nodes (if any)
    if (node->ChildNodes[0]) {
        j["ChildNode1"] = serializeDockNode(node->ChildNodes[0]);
    }
    if (node->ChildNodes[1]) {
        j["ChildNode2"] = serializeDockNode(node->ChildNodes[1]);
    }

    return j;
}

DockNodeInfo deserializeDockNode(const json& j)
{
    DockNodeInfo nodeInfo;
    nodeInfo.nodeID = j["NodeID"].get<ImGuiID>();
    nodeInfo.splitAxis = j["SplitAxis"].get<int>();
    nodeInfo.size = ImVec2(j["Size"][0].get<float>(), j["Size"][1].get<float>());
    nodeInfo.sharedFlags = j["SharedFlags"].get<ImGuiDockNodeFlags>();
    nodeInfo.localFlags = j["LocalFlags"].get<ImGuiDockNodeFlags>();
    nodeInfo.mergedFlags = j["MergedFlags"].get<ImGuiDockNodeFlags>();
    nodeInfo.state = j["State"].get<int>();

    // Deserialize the windows associated with the node
    if (j.contains("Windows")) {
        for (const auto& window : j["Windows"]) {
            nodeInfo.windows.push_back(window["WindowName"].get<std::string>());
        }
    }

    // Deserialize child nodes recursively
    if (j.contains("ChildNode1")) {
        nodeInfo.child[0] = new DockNodeInfo(deserializeDockNode(j["ChildNode1"]));
    }
    if (j.contains("ChildNode2")) {
        nodeInfo.child[1] = new DockNodeInfo(deserializeDockNode(j["ChildNode2"]));
    }

    return nodeInfo;
}

void createDockFromInfo(ImGuiID dockspaceID, const DockNodeInfo& info, int child_num)
{
    // Set up the dock node (starting with the dockspace root node)
    if (info.child[0] != nullptr || info.child[1] != nullptr) {
        // Split the dock node if it has children
        ImGuiID nodeID = info.child[0] ? info.child[0]->nodeID : 0;
        ImGuiID parentID =info.nodeID;
        ImGuiDir splitDir;
        float splitRatio = 0.5f;

        if(info.splitAxis == -1) {
            splitDir = ImGuiDir_None;
        }
        else if(child_num == 0){
            splitDir = (ImGuiDir)(child_num + 2 * info.splitAxis);

        }
        else{
            splitDir = (ImGuiDir)(child_num + 2 * info.splitAxis);

        }
        if(info.splitAxis==0) {
            splitRatio = info.child[0]->size.x / (info.child[0]->size.x + info.child[1]->size.x);
        }
        else
        {
            splitRatio = info.child[0]->size.y / (info.child[0]->size.y + info.child[1]->size.y);
        }
        ImGui::DockBuilderSplitNode(info.nodeID, splitDir, splitRatio,
                                    &nodeID, &parentID);

        // Recursively handle child nodes
        if (info.child[0]) {
            createDockFromInfo(dockspaceID, *info.child[0], 0);
        }
        if (info.child[1]) {
            createDockFromInfo(dockspaceID, *info.child[1], 1);
        }
    } else {
        // If the node has no children, dock the windows
        for (const auto& window_name : info.windows) {
            ImGui::DockBuilderDockWindow(window_name.c_str(), info.nodeID);
        }
    }
}

void createDockLayoutFromJson(ImGuiID dockspaceID, std::string filename) {
    // Parse the JSON
    // Open the JSON file
    std::ifstream input_file(filename);
    if (!input_file.is_open()) {
        std::cert <<"Could not open file: "<< filename << std::end;
        return;
    }

    // Parse the JSON
    json layout_json;
    input_file >> layout_json;

    // Deserialize root node
    DockNodeInfo root_node_info = deserializeDockNode(layout_json);

    if(root_node_info.nodeID != dockspaceID) {
        // Remove any existing dockspace and prepare for a new layout
        ImGuiID dockspace_id = root_node_info.nodeID ;
        ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_None);

        ImGui::DockBuilderRemoveNode(dockspace_id); // Clear out existing dockspace
        ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_None); // Add the main dockspace
        dockspaceID = dockspace_id;

    }
    // Rebuild the layout from the deserialized tree
    createDockFromInfo(dockspaceID, root_node_info, 0);

}

void printAllDockNodesAsJson(ImGuiDockNode* node, std::string filename) {
    if (node) {
        // Serialize the dock node tree into JSON
        json root_node_json = serializeDockNode(node);

        // Output JSON to console or file
        std::string json_output = root_node_json.dump(4); // 4 is the indentation level
        // Write the JSON string to a file
        std::cout << json_output<<std::endl;
        std::ofstream file(filename, std::ios::out);
        if (file.is_open()) {
            file << json_output;
            file.close();
            std::cout << "JSON saved to file: "<< filename << std::end;
        } else {
            std::cerr <<"Could not open file for writing: "<< filename<< std::end;
        }
    } else {
         std::cerr <<"DockSpace node not found."<< std::end;
    }
}

At this time if I get different dockspace it will get error:

Assertion failed: (node != __null), function DockBuilderSplitNode, file imgui.cpp, line 19684.

I will get more steps... :)

@ocornut ocornut changed the title [Docking] Saving layout Docking: saving layout Oct 3, 2024
@Zaryob
Copy link
Author

Zaryob commented Oct 5, 2024

I get this approach worked. :)

I will put it for anyone need different approaches

#include <gui/layout.h>
#include <json.hpp>
#include <fstream>
#include <iostream>
#include <map>

using json = nlohmann::json;

std::map<ImGuiID, ImGuiID> dictionary;

json serializeDockNode(ImGuiDockNode* node)
{
    if (!node) return nullptr;

    json j;
    j["NodeID"] = node->ID;
    j["SplitAxis"] = node->SplitAxis;
    j["Size"] = { node->Size.x, node->Size.y };
    j["SharedFlags"] = node->SharedFlags;
    j["LocalFlags"] = node->LocalFlags;
    j["LocalFlagsInWindows"] = node->LocalFlagsInWindows;
    j["MergedFlags"] = node->MergedFlags;
    j["State"] = node->State;

    // Serialize docked windows
    if (!node->Windows.empty()) {
        j["Windows"] = json::array();
        for (ImGuiWindow* window : node->Windows) {
            json window_info;
            window_info["WindowID"] = window->ID;
            window_info["WindowName"] = window->Name;
            j["Windows"].push_back(window_info);
        }
    }

    // Serialize child nodes (if any)
    if (node->ChildNodes[0]) {
        j["ChildNode1"] = serializeDockNode(node->ChildNodes[0]);
    }
    if (node->ChildNodes[1]) {
        j["ChildNode2"] = serializeDockNode(node->ChildNodes[1]);
    }

    return j;
}

DockNodeInfo deserializeDockNode(const json& j)
{
    DockNodeInfo nodeInfo;
    nodeInfo.nodeID = j["NodeID"].get<ImGuiID>();
    nodeInfo.splitAxis = j["SplitAxis"].get<int>();
    nodeInfo.size = ImVec2(j["Size"][0].get<float>(), j["Size"][1].get<float>());
    nodeInfo.sharedFlags = j["SharedFlags"].get<ImGuiDockNodeFlags>();
    nodeInfo.localFlags = j["LocalFlags"].get<ImGuiDockNodeFlags>();
    nodeInfo.mergedFlags = j["MergedFlags"].get<ImGuiDockNodeFlags>();
    nodeInfo.state = j["State"].get<int>();

    // Deserialize the windows associated with the node
    if (j.contains("Windows")) {
        for (const auto& window : j["Windows"]) {
            nodeInfo.windows.push_back(window["WindowName"].get<std::string>());
        }
    }

    // Deserialize child nodes recursively
    if (j.contains("ChildNode1")) {
        nodeInfo.child[0] = new DockNodeInfo(deserializeDockNode(j["ChildNode1"]));
    }
    if (j.contains("ChildNode2")) {
        nodeInfo.child[1] = new DockNodeInfo(deserializeDockNode(j["ChildNode2"]));
    }

    return nodeInfo;
}

void createDockFromInfo(ImGuiID dockspaceID, const DockNodeInfo& info)
{
    // Set up the dock node (starting with the dockspace root node)
    if (info.child[0] != nullptr || info.child[1] != nullptr) {
        // Split the dock node if it has children
        ImGuiID nodeID = info.nodeID;
        ImGuiID leftID = info.child[0]->nodeID;
        ImGuiID rightID = info.child[1]->nodeID;
        if(dictionary.size() != 0){
            nodeID=dictionary[nodeID];
        }

        ImGuiDir splitDir;
        float splitRatio = 0.5f;

        if(info.splitAxis == -1) {
            splitDir = ImGuiDir_None;
        }
        else if(info.splitAxis == 0){
            splitDir = (ImGuiDir)(info.splitAxis);

        }
        else{
            splitDir = (ImGuiDir)(2 * info.splitAxis);

        }
        if(info.splitAxis==0) {
            splitRatio = info.child[0]->size.x / (info.child[0]->size.x + info.child[1]->size.x);
        }
        else
        {
            splitRatio = info.child[0]->size.y / (info.child[0]->size.y + info.child[1]->size.y);
        }
        // Split the main dockspace node into left and right nodes

        ImGui::DockBuilderSplitNode(nodeID, splitDir, splitRatio, &leftID, &rightID);

        dictionary[info.child[0]->nodeID] = leftID;
        dictionary[info.child[1]->nodeID] = rightID;

        // Recursively handle child nodes
        if (info.child[0]) {
            createDockFromInfo(dockspaceID, *info.child[0]);
        }
        if (info.child[1]) {
            createDockFromInfo(dockspaceID, *info.child[1]);
        }
       } else {
        // If the node has no children, dock the windows
        for (const auto& window_name : info.windows) {
            ImGui::DockBuilderDockWindow(window_name.c_str(), dictionary[info.nodeID]);
        }
    }
}

void layout::createDockLayoutFromJson(ImGuiID& dockspaceID, ImVec2 availableSpaceForDocking, std::string filename) {
    // Parse the JSON
    // Open the JSON file
    dictionary.clear();
    std::ifstream input_file(filename);
    if (!input_file.is_open()) {
        std::cerr<<"Could not open file: "<<filename<<std::endl;
        return;
    }

    // Parse the JSON
    json layout_json;
    input_file >> layout_json;

    // Deserialize root node
    DockNodeInfo root_node_info = deserializeDockNode(layout_json);
    // Remove any existing dockspace and prepare for a new layout
    ImGui::DockBuilderRemoveNode(dockspaceID); // Clear out existing dockspace

    // Remove any existing dockspace and prepare for a new layout
    ImGuiID dockspace_id = root_node_info.nodeID ;
    ImGui::DockSpace(dockspace_id, availableSpaceForDocking, ImGuiDockNodeFlags_None);

    ImGui::DockBuilderRemoveNode(dockspace_id); // Clear out existing dockspace
    ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_None); // Add the main dockspace
    dockspaceID = dockspace_id;


    // Rebuild the layout from the deserialized tree
    createDockFromInfo(dockspace_id, root_node_info);
    ImGui::DockBuilderFinish(dockspace_id);

}

void layout::printAllDockNodesAsJson(ImGuiDockNode* node, std::string filename) {
    if (node) {
        // Serialize the dock node tree into JSON
        json root_node_json = serializeDockNode(node);

        // Output JSON to console or file
        std::string json_output = root_node_json.dump(4); // 4 is the indentation level
        // Write the JSON string to a file
        std::cout << json_output<<std::endl;
        std::ofstream file(filename, std::ios::out);
        if (file.is_open()) {
            file << json_output;
            file.close();
            std::cout<<"JSON saved to file: "<<filename<<std::endl;
        } else {
            std::cerr<<"Could not open file for writing: "<< filename<<std::endl;
        }
    } else {
        std::cerr<<"DockSpace node not found."<<std::endl;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docking settings .ini persistance
Projects
None yet
Development

No branches or pull requests

2 participants