Skip to content

Instantly share code, notes, and snippets.

@AidanSun05
Created February 5, 2022 00:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save AidanSun05/953f1048ffe5699800d2c92b88c36d9f to your computer and use it in GitHub Desktop.
Save AidanSun05/953f1048ffe5699800d2c92b88c36d9f to your computer and use it in GitHub Desktop.
A commented example for Dear ImGui's DockBuilder API.
// The DockBuilder API is still marked as experimental, include Dear ImGui's internal header to pull the functions in:
#include "imgui_internal.h"
// [...]
// Beginning of main loop
// 1. DockBuilder functions only need to run once to take effect.
// This state variable will let us check for the first frame of the app.
static bool firstLoop = true;
// Only run DockBuilder functions on the first frame of the app:
if (firstLoop) {
// 2. We want our whole dock node to be positioned in the center of the window, so we'll need to calculate that first.
// The "work area" is the space inside the platform window created by GLFW, SDL, etc. minus the main menu bar if present.
ImVec2 workPos = ImGui::GetMainViewport()->GetWorkPos(); // The coordinates of the top-left corner of the work area
ImVec2 workSize = ImGui::GetMainViewport()->GetWorkSize(); // The dimensions (size) of the work area
// We'll need to halve the size, then add those resultant values to the top-left corner to get to the middle point on both X and Y.
ImVec2 workCenter{ workPos.x + workSize.x * 0.5f, workPos.y + workSize.y * 0.5f };
// For completeness, this can be simplified in modern versions of Dear ImGui.
// v1.81 (found by git blame) adds a new function GetWorkCenter() which does these same calculations, so for any code using a newer version:
//
// if (firstLoop) {
// ImVec2 workCenter = ImGui::GetMainViewport()->GetWorkCenter();
// 3. Now we'll need to create our dock node:
ImGuiID id = ImGui::GetID("MainWindowGroup"); // The string chosen here is arbitrary (it just gives us something to work with)
ImGui::DockBuilderRemoveNode(id); // Clear any preexisting layouts associated with the ID we just chose
ImGui::DockBuilderAddNode(id); // Create a new dock node to use
// 4. Set the dock node's size and position:
ImVec2 size{ 600, 300 }; // A decently large dock node size (600x300px) so everything displays clearly
// Calculate the position of the dock node
//
// `DockBuilderSetNodePos()` will position the top-left corner of the node to the coordinate given.
// This means that the node itself won't actually be in the center of the window; its top-left corner will.
//
// To fix this, we'll need to subtract half the node size from both the X and Y dimensions to move it left and up.
// This new coordinate will be the position of the node's top-left corner that will center the node in the window.
ImVec2 nodePos{ workCenter.x - size.x * 0.5f, workCenter.y - size.y * 0.5f };
// Set the size and position:
ImGui::DockBuilderSetNodeSize(id, size);
ImGui::DockBuilderSetNodePos(id, nodePos);
// 5. Split the dock node to create spaces to put our windows in:
// Split the dock node in the left direction to create our first docking space. This will be on the left side of the node.
// (The 0.5f means that the new space will take up 50% of its parent - the dock node.)
ImGuiID dock1 = ImGui::DockBuilderSplitNode(id, ImGuiDir_Left, 0.5f, nullptr, &id);
// +-----------+
// | |
// | 1 |
// | |
// +-----------+
// Split the same dock node in the right direction to create our second docking space.
// At this point, the dock node has two spaces, one on the left and one on the right.
ImGuiID dock2 = ImGui::DockBuilderSplitNode(id, ImGuiDir_Right, 0.5f, nullptr, &id);
// +-----+-----+
// | | |
// | 1 | 2 |
// | | |
// +-----+-----+
// split ->
// For our last docking space, we want it to be under the second one but not under the first.
// Split the second space in the down direction so that we now have an additional space under it.
//
// Notice how "dock2" is now passed rather than "id".
// The new space takes up 50% of the second space rather than 50% of the original dock node.
ImGuiID dock3 = ImGui::DockBuilderSplitNode(dock2, ImGuiDir_Down, 0.5f, nullptr, &dock2);
// +-----+-----+
// | | 2 | split
// | 1 +-----+ |
// | | 3 | V
// +-----+-----+
// 6. Add windows to each docking space:
ImGui::DockBuilderDockWindow("One", dock1);
ImGui::DockBuilderDockWindow("Two", dock2);
ImGui::DockBuilderDockWindow("Three", dock3);
// 7. We're done setting up our docking configuration:
ImGui::DockBuilderFinish(id);
}
// 8. Create some windows to put in the dock node:
// (The titles of these windows must match the strings given in DockBuilderDockWindow().)
ImGui::Begin("One");
ImGui::End();
ImGui::Begin("Two");
ImGui::End();
ImGui::Begin("Three");
ImGui::End();
// 9. At this point, we're at the end of the loop iteration.
// If this is our first one, set the state variable to false so the DockBuilder functions don't run again:
if (firstLoop) firstLoop = false;
// End of main loop
@broken-bytes
Copy link

image
I am getting above error when running your sample.

@broken-bytes
Copy link

image
This line of code creates the crash

@AidanSun05
Copy link
Author

Did you run this example by itself, or did you incorporate it into your own code?

If the latter, there may be something else interfering; the crash may not be caused by this sample itself. Try running it as a standalone program (the easiest way to do this is to copy this sample code into a Dear ImGui example file). This will determine if the error is really caused from this sample.

If this standalone program still doesn't work, please provide your Dear ImGui version and a call stack from where it crashed.

@broken-bytes
Copy link

It was your code without any additional stuff.
The issue is that there is no Window yet. GetID() uses the first window it finds in order to get an ID. Since in this snippet there is no window beforehand, if crashes

@AidanSun05
Copy link
Author

AidanSun05 commented Mar 21, 2022

I put a breakpoint on the offending ImGui::GetID() line, then stepped into it in the debugger. I saw that the current window was the invisible "Debug##Default" window.

image

I commented out the lines that create that window in imgui.cpp and I got basically the same crash you did.

image

image

This means that there's probably something going on with your setup and main loop (ex. Did you call ImGui::NewFrame() at the top of your main loop? That's the function that creates the Debug##Default window.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment