Skip to content

Commit f55d184

Browse files
committed
Drive demo hub UI via HelloImGui dockable windows
1 parent 447073f commit f55d184

File tree

2 files changed

+41
-47
lines changed

2 files changed

+41
-47
lines changed

python/demo_hub/gui/app.py

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
from datetime import datetime
88
from pathlib import Path
99

10-
from imgui_bundle import imgui, immapp
10+
from imgui_bundle import hello_imgui, imgui, immapp
1111

1212
from demo_hub.core import Recorder, build_default_registry
1313
from demo_hub.gui.primitives import Segment2D
14-
from demo_hub.gui.viewport import draw_topdown
14+
from demo_hub.gui.viewport import draw_topdown_contents
1515

1616
logger = logging.getLogger(__name__)
1717

@@ -69,15 +69,11 @@ def _simulate(state: GuiState) -> None:
6969

7070

7171
def _render(state: GuiState) -> None: # pragma: no cover - manual UI
72-
io = imgui.get_io()
73-
io.config_flags |= imgui.ConfigFlags_.docking_enable
74-
dock_id = _dockspace_fullscreen()
72+
# Legacy entry point; the real UI is composed via hello_imgui dockable windows.
73+
imgui.text("GUI is built via dockable windows.")
7574

76-
_simulate(state)
77-
78-
imgui.set_next_window_dock_id(dock_id, imgui.Cond_.first_use_ever)
79-
imgui.begin("Demo Hub")
8075

76+
def _draw_controls(state: GuiState) -> None:
8177
changed, selected_idx = imgui.combo("Scene", state.selected_idx, state.scene_ids)
8278
if changed:
8379
state.switch_scene(selected_idx)
@@ -118,44 +114,15 @@ def _render(state: GuiState) -> None: # pragma: no cover - manual UI
118114
imgui.text("State")
119115
for key, value in state_payload.items():
120116
imgui.text(f"{key}: {value}")
117+
imgui.separator()
118+
imgui.text(f"frames: {state.step_count}")
121119

122-
imgui.end()
123120

124-
imgui.set_next_window_dock_id(dock_id, imgui.Cond_.first_use_ever)
121+
def _draw_viewport(state: GuiState) -> None:
125122
segments = [
126123
Segment2D(seg[0], seg[1], seg[2]) for seg in state.scene.debug_draw_2d()
127124
]
128-
draw_topdown("Viewport (XZ top-down)", segments)
129-
130-
131-
def _dockspace_fullscreen() -> None:
132-
# Follow Dear ImGui's recommended fullscreen dockspace pattern.
133-
dockspace_flags = imgui.DockNodeFlags_.none
134-
window_flags = (
135-
imgui.WindowFlags_.no_title_bar
136-
| imgui.WindowFlags_.no_collapse
137-
| imgui.WindowFlags_.no_resize
138-
| imgui.WindowFlags_.no_move
139-
| imgui.WindowFlags_.no_bring_to_front_on_focus
140-
| imgui.WindowFlags_.no_nav_focus
141-
| imgui.WindowFlags_.no_docking
142-
)
143-
viewport = imgui.get_main_viewport()
144-
imgui.set_next_window_pos(viewport.pos)
145-
imgui.set_next_window_size(viewport.size)
146-
imgui.set_next_window_viewport(viewport.id_)
147-
imgui.push_style_var(imgui.StyleVar_.window_rounding, 0.0)
148-
imgui.push_style_var(imgui.StyleVar_.window_border_size, 0.0)
149-
imgui.push_style_var(imgui.StyleVar_.window_padding, (0.0, 0.0))
150-
if dockspace_flags & imgui.DockNodeFlags_.passthru_central_node:
151-
window_flags |= imgui.WindowFlags_.no_background
152-
153-
imgui.begin("MainDockSpaceHost", flags=window_flags)
154-
imgui.pop_style_var(3)
155-
dockspace_id = imgui.get_id("MainDockSpace")
156-
imgui.dock_space(dockspace_id, (0.0, 0.0), dockspace_flags)
157-
imgui.end()
158-
return dockspace_id
125+
draw_topdown_contents(segments)
159126

160127

161128
def main(argv: list[str] | None = None) -> None:
@@ -188,9 +155,33 @@ def main(argv: list[str] | None = None) -> None:
188155

189156
params = immapp.RunnerParams()
190157
params.docking_params.main_dock_space_node_flags = imgui.DockNodeFlags_.none
158+
params.docking_params.layout_condition = (
159+
hello_imgui.DockingLayoutCondition.first_use_ever
160+
)
161+
params.docking_params.dockable_windows = [
162+
hello_imgui.DockableWindow(
163+
"Demo Hub",
164+
"MainDockSpace",
165+
lambda: _draw_controls(state),
166+
),
167+
hello_imgui.DockableWindow(
168+
"Viewport (XZ top-down)",
169+
"MainDockSpace",
170+
lambda: _draw_viewport(state),
171+
),
172+
]
173+
174+
def _pre_new_frame() -> None:
175+
io = imgui.get_io()
176+
io.config_flags |= imgui.ConfigFlags_.docking_enable
177+
_simulate(state)
178+
179+
params.callbacks.pre_new_frame = _pre_new_frame
180+
params.imgui_window_params.default_imgui_window_type = (
181+
hello_imgui.DefaultImGuiWindowType.provide_full_screen_dock_space
182+
)
191183
params.app_window_params.window_title = "DART Demo Hub"
192184
params.app_window_params.window_geometry.size = [1280, 720]
193-
params.callbacks.show_gui = lambda: _render(state)
194185
immapp.run(runner_params=params)
195186

196187

python/demo_hub/gui/viewport.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,14 @@
77
from demo_hub.gui.primitives import Segment2D
88

99

10-
def draw_topdown(name: str, segments: Iterable[Segment2D], size=(0, 0)) -> None:
11-
"""Render a simple top-down 2D view using ImGui draw lists."""
12-
imgui.begin(name)
10+
def draw_topdown_contents(segments: Iterable[Segment2D]) -> None:
11+
"""Render top-down view inside an already begun ImGui window."""
1312
canvas_pos = imgui.get_window_pos()
1413
canvas_size = imgui.get_window_size()
1514
width, height = canvas_size.x, canvas_size.y
1615

1716
segs = list(segments)
1817
if not segs:
19-
imgui.end()
2018
return
2119

2220
# Compute bounds
@@ -51,4 +49,9 @@ def project(pt):
5149
p1 = project(seg.end)
5250
draw_list.add_line(p0, p1, col, thickness=2.0)
5351

52+
53+
def draw_topdown(name: str, segments: Iterable[Segment2D], size=(0, 0)) -> None:
54+
"""Render a simple top-down 2D view using ImGui draw lists."""
55+
imgui.begin(name)
56+
draw_topdown_contents(segments)
5457
imgui.end()

0 commit comments

Comments
 (0)