Skip to content

Commit 4ffa1e1

Browse files
docking: DockBuilder surface + real split-layout demo (#7)
* feat(docking): DockBuilder surface + real split-layout demo The previous demo pre-docked both panels into one tab group — visually just a tab bar, no visible docking. Export the minimal DockBuilder surface (DockBuilderSplitNode/DockWindow/Finish + ImGuiDir-typed Dir_* constants, gated by the docking feature; imgui_internal.h enters the GMF only when the feature is on) and rebuild the example as an IDE-style first-frame layout: Scene | Viewport | Inspector with Console split below — four real dock nodes, drag any tab to re-split/stack/float. Default (feature-off) build/tests unchanged. * feat: viewports feature — panels detach into real OS windows New independent `viewports` feature (usually combined with docking): - core exports GetMainViewport/UpdatePlatformWindows/ RenderPlatformWindowsDefault/SetNextWindowPos + ConfigFlags_ViewportsEnable (gated by MCPP_FEATURE_VIEWPORTS). - imgui.app facade enables ViewportsEnable and renders platform windows each frame (with GL context backup/restore); GlfwOpenGL3 gains GetCurrentContext. - docking example requests ["docking", "viewports"] and spawns a 'Detached' panel outside the main window — verified: a separate OS window appears in the X window tree and renders (drag back inside to re-dock). Default (feature-off) build/tests unchanged. --------- Co-authored-by: sunrisepeak <x.d2learn.org@gmail.com>
1 parent 0f75121 commit 4ffa1e1

7 files changed

Lines changed: 108 additions & 15 deletions

File tree

examples/docking/mcpp.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ description = "Dockable-windows demo using the imgui `docking` feature"
55
license = "MIT"
66

77
[dependencies]
8-
imgui = { path = "../..", features = ["docking"] }
8+
imgui = { path = "../..", features = ["docking", "viewports"] }

examples/docking/src/main.cpp

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,62 @@
1-
// Docking demo — `imgui = { ..., features = ["docking"] }`.
2-
// The imgui.app facade auto-enables ImGuiConfigFlags_DockingEnable when the
3-
// feature is active; DockSpaceOverViewport turns the whole window into a
4-
// dock host, so the two panels below can be dragged into / split around it.
1+
// Docking + multi-viewport demo —
2+
// imgui = { ..., features = ["docking", "viewports"] }
3+
//
4+
// On the first frame, DockBuilder splits the dockspace into an IDE-style
5+
// layout (Scene | Viewport | Inspector, Console at the bottom). Every pane is
6+
// a real dock node: drag any tab to re-split, stack, or float it.
7+
// With `viewports`, drag a tab OUTSIDE the main window and it detaches into
8+
// its own OS window; the "Detached" panel below starts outside on purpose.
59
import imgui.core;
610
import imgui.app;
711

812
int main() {
913
return ImGui::App::run({.title = "mcpp imgui docking demo"}, [] {
10-
const auto dockspace = ImGui::DockSpaceOverViewport();
14+
auto dockspace = ImGui::DockSpaceOverViewport();
1115

12-
// Pre-dock both panels into the dockspace on first run; they remain
13-
// freely draggable/splittable afterwards.
14-
ImGui::SetNextWindowDockID(dockspace, ImGui::Cond_FirstUseEver);
15-
ImGui::Begin("Toolbox");
16-
ImGui::TextUnformatted("Drag this panel onto the dockspace.");
17-
ImGui::TextUnformatted("Docked: ");
18-
ImGui::TextUnformatted(ImGui::IsWindowDocked() ? "yes" : "no");
16+
static bool layout_built = false;
17+
if (!layout_built) {
18+
layout_built = true;
19+
const auto root = dockspace;
20+
auto left = ImGui::DockBuilderSplitNode(
21+
dockspace, ImGui::Dir_Left, 0.22f, nullptr, &dockspace);
22+
auto down = ImGui::DockBuilderSplitNode(
23+
dockspace, ImGui::Dir_Down, 0.28f, nullptr, &dockspace);
24+
auto right = ImGui::DockBuilderSplitNode(
25+
dockspace, ImGui::Dir_Right, 0.30f, nullptr, &dockspace);
26+
ImGui::DockBuilderDockWindow("Scene", left);
27+
ImGui::DockBuilderDockWindow("Console", down);
28+
ImGui::DockBuilderDockWindow("Inspector", right);
29+
ImGui::DockBuilderDockWindow("Viewport", dockspace);
30+
ImGui::DockBuilderFinish(root);
31+
}
32+
33+
ImGui::Begin("Scene");
34+
ImGui::TextUnformatted("Scene tree pane (left split).");
35+
ImGui::TextUnformatted(ImGui::IsWindowDocked() ? "docked: yes" : "docked: no");
36+
ImGui::End();
37+
38+
ImGui::Begin("Viewport");
39+
ImGui::TextUnformatted("Central pane. Drag any tab to");
40+
ImGui::TextUnformatted("re-split / stack / float it.");
1941
ImGui::End();
2042

21-
ImGui::SetNextWindowDockID(dockspace, ImGui::Cond_FirstUseEver);
2243
ImGui::Begin("Inspector");
23-
ImGui::TextUnformatted("Split me against the Toolbox.");
44+
ImGui::TextUnformatted("Properties pane (right split).");
45+
ImGui::End();
46+
47+
ImGui::Begin("Console");
48+
ImGui::TextUnformatted("Log pane (bottom split).");
49+
ImGui::End();
50+
51+
// Starts OUTSIDE the main window: with `viewports` this is a real,
52+
// separate OS window from the very first frame.
53+
const auto* main_vp = ImGui::GetMainViewport();
54+
ImGui::SetNextWindowPos(
55+
ImVec2{main_vp->Pos.x + main_vp->Size.x + 60.0f, main_vp->Pos.y + 80.0f},
56+
ImGui::Cond_FirstUseEver);
57+
ImGui::Begin("Detached");
58+
ImGui::TextUnformatted("I live in my own OS window.");
59+
ImGui::TextUnformatted("Drag me back inside to re-dock.");
2460
ImGui::End();
2561
});
2662
}

mcpp.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ default = []
2727
# docking: export the Dock* API surface and auto-enable
2828
# ImGuiConfigFlags_DockingEnable in the imgui.app facade.
2929
docking = []
30+
# viewports: ImGui windows dragged outside the main window detach into real
31+
# OS windows (multi-viewport). Usually combined with docking.
32+
viewports = []
3033

3134
[dependencies]
3235
compat.imgui = "1.92.8-docking"

src/app.cppm

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ export namespace ImGui::App {
5757
// `docking` feature: enable dockable windows out of the box.
5858
ImGui::GetIO().ConfigFlags |= ImGui::ConfigFlags_DockingEnable;
5959
#endif
60+
#ifdef MCPP_FEATURE_VIEWPORTS
61+
// `viewports` feature: windows dragged outside the main window
62+
// detach into real OS windows.
63+
ImGui::GetIO().ConfigFlags |= ImGui::ConfigFlags_ViewportsEnable;
64+
#endif
6065

6166
if (!Backend::Init(window)) {
6267
const auto error = Backend::LastError();
@@ -84,6 +89,15 @@ export namespace ImGui::App {
8489
Backend::ClearColor(0.10f, 0.10f, 0.12f, 1.0f);
8590
Backend::ClearColorBuffer();
8691
Backend::RenderDrawData(ImGui::GetDrawData());
92+
#ifdef MCPP_FEATURE_VIEWPORTS
93+
// Render the detached OS windows, then restore the main context.
94+
{
95+
auto* backup = Backend::GetCurrentContext();
96+
ImGui::UpdatePlatformWindows();
97+
ImGui::RenderPlatformWindowsDefault();
98+
Backend::MakeContextCurrent(backup);
99+
}
100+
#endif
87101
Backend::SwapBuffers(window);
88102
}
89103

src/backends/glfw_opengl3.cppm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ export namespace ImGui::Backend {
6262
GlfwPlatform::MakeContextCurrent(window);
6363
}
6464

65+
static Window* GetCurrentContext() {
66+
return GlfwPlatform::GetCurrentContext();
67+
}
68+
6569
static void SwapInterval(int interval) {
6670
GlfwPlatform::SwapInterval(interval);
6771
}

src/backends/platform_glfw.cppm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export namespace ImGui::Backend {
7171
glfwMakeContextCurrent(window);
7272
}
7373

74+
static Window* GetCurrentContext() {
75+
return glfwGetCurrentContext();
76+
}
77+
7478
static FbSize FramebufferSize(Window* window) {
7579
int width = 0;
7680
int height = 0;

src/core.cppm

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
module;
22

33
#include <imgui.h>
4+
#ifdef MCPP_FEATURE_DOCKING
5+
// DockBuilder (programmatic dock layouts) lives in the internal header.
6+
#include <imgui_internal.h>
7+
#endif
48

59
export module imgui.core;
610

@@ -42,9 +46,37 @@ export namespace ImGui {
4246
using ::ImGui::GetWindowDockID;
4347
using ::ImGui::IsWindowDocked;
4448

49+
// DockBuilder — programmatic dock layouts (e.g. an IDE-style default
50+
// split). Upstream ships it in imgui_internal.h; the docking feature
51+
// exports the minimal stable surface needed to build layouts.
52+
using ::ImGui::DockBuilderSplitNode;
53+
using ::ImGui::DockBuilderDockWindow;
54+
using ::ImGui::DockBuilderFinish;
55+
4556
// Unscoped global enumerators, re-exported as namespaced constants for
4657
// module consumers.
4758
inline constexpr int ConfigFlags_DockingEnable = ::ImGuiConfigFlags_DockingEnable;
4859
inline constexpr int Cond_FirstUseEver = ::ImGuiCond_FirstUseEver;
60+
// Typed as the underlying enum so they pass straight into
61+
// DockBuilderSplitNode without the consumer naming ImGuiDir.
62+
inline constexpr ::ImGuiDir Dir_Left = ::ImGuiDir_Left;
63+
inline constexpr ::ImGuiDir Dir_Right = ::ImGuiDir_Right;
64+
inline constexpr ::ImGuiDir Dir_Up = ::ImGuiDir_Up;
65+
inline constexpr ::ImGuiDir Dir_Down = ::ImGuiDir_Down;
66+
}
67+
#endif
68+
69+
// Multi-viewport surface — gated by the `viewports` feature: ImGui windows
70+
// dragged (or positioned) outside the main window become real OS windows.
71+
#ifdef MCPP_FEATURE_VIEWPORTS
72+
export using ImGuiViewport = ::ImGuiViewport;
73+
74+
export namespace ImGui {
75+
using ::ImGui::GetMainViewport;
76+
using ::ImGui::UpdatePlatformWindows;
77+
using ::ImGui::RenderPlatformWindowsDefault;
78+
using ::ImGui::SetNextWindowPos;
79+
80+
inline constexpr int ConfigFlags_ViewportsEnable = ::ImGuiConfigFlags_ViewportsEnable;
4981
}
5082
#endif

0 commit comments

Comments
 (0)