8.19.8. Layout primitives
ImGui’s layout cursor advances after every widget — each button,
text, or other rail bumps the cursor to the next line by default.
Four boost rails move the cursor without rendering anything visible:
same_line(IDENT)— keep the next widget on the current row (wrapsImGui::SameLine).spacing(IDENT)— insert one line of vertical gap.new_line(IDENT)— advance one full text-line of vertical space.dummy((size = float2(x, y)))— reserve arbitrary cursor space without rendering.
All four accept the [widget]-style optional IDENT; the tutorial
shows IDENTs on same_line / spacing / new_line (useful when
playwright tests assert their snapshot entries) and the anonymous
dummy form (cursor reservation that no test targets).
All four share EmptyMarkerState — the payload is {}, but the
snapshot still records that the marker fired, so playwright tests can
assert "spacing#3 was rendered between button A and button B".
if (button(BTN_A, (text = "A"))) { /* ... */ }
same_line(SL_AB)
if (button(BTN_B, (text = "B"))) { /* ... */ }
same_line(SL_BC)
if (button(BTN_C, (text = "C"))) { /* ... */ }
spacing(SP_TOP)
new_line(NL_INSERT)
dummy((size = float2(0.0f, 40.0f)))
Source: modules/dasImgui/examples/tutorial/layout_primitives.das.
8.19.8.1. Walkthrough
The markers render nothing, so the recording’s self-check is that each named
marker fired: it narrates the same_line row while asserting the three
buttons and both same_line markers are on screen, then the spacing and
new_line markers in turn (record_check_rendered on each). A marker that
silently dropped out of the layout would abort the recording.
1options gen2
2options _comment_hygiene = true
3options gc
4
5require imgui
6require imgui_app
7require opengl/opengl_boost
8require live/glfw_live
9require live/live_api
10require live/live_commands
11require live/live_vars
12require live_host
13require imgui/imgui_live
14require imgui/imgui_boost_runtime
15require imgui/imgui_boost_v2
16require imgui/imgui_widgets_builtin
17require imgui/imgui_containers_builtin
18require imgui/imgui_visual_aids
19
20// =============================================================================
21// TUTORIAL: layout_primitives — boost v2 cursor-positioning widgets.
22//
23// Layout markers move the imgui cursor without rendering anything. They share
24// EmptyMarkerState — payload is `{}`, but the snapshot still records the
25// widget existed, so playwright can assert "spacing#3 was rendered".
26//
27// Covers: same_line / new_line / spacing / dummy
28//
29// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/layout_primitives.das
30// LIVE: daslang-live modules/dasImgui/examples/tutorial/layout_primitives.das
31// =============================================================================
32
33[export]
34def init() {
35 live_create_window("dasImgui layout primitives", 1000, 640)
36 live_imgui_init(live_window)
37 let io & = unsafe(GetIO())
38 GetStyle().FontScaleMain = 1.4
39}
40
41[export]
42def update() {
43 if (!live_begin_frame()) return
44 begin_frame()
45
46 ImGui_ImplGlfw_NewFrame()
47 apply_synth_io_override()
48 NewFrame()
49
50 SetNextWindowPos(ImVec2(60.0, 60.0), ImGuiCond.Always)
51 SetNextWindowSize(ImVec2(600.0, 360.0), ImGuiCond.Always)
52 window(LAYOUT_WIN, (text = "Layout primitives", closable = false,
53 flags = ImGuiWindowFlags.None)) {
54 text("Three buttons on one row - same_line() keeps them inline.")
55 if (button(BTN_A, (text = "A"))) {
56 print("A\n")
57 }
58 same_line(SL_AB)
59 if (button(BTN_B, (text = "B"))) {
60 print("B\n")
61 }
62 same_line(SL_BC)
63 if (button(BTN_C, (text = "C"))) {
64 print("C\n")
65 }
66
67 spacing(SP_TOP)
68 text("spacing() inserts a small vertical gap (1 line).")
69
70 spacing(SP_MID)
71 spacing(SP_MID2)
72 spacing(SP_MID3)
73 text("Three spacing() calls stack; cheap if you don't want a Dummy.")
74
75 new_line(NL_INSERT)
76 text("new_line() == one full text-line of vertical space.")
77
78 dummy((size = float2(0.0f, 40.0f)))
79 text("dummy(size) reserves arbitrary cursor space.")
80 }
81
82 end_of_frame()
83 Render()
84 var w, h : int
85 live_get_framebuffer_size(w, h)
86 glViewport(0, 0, w, h)
87 glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
88 glClear(GL_COLOR_BUFFER_BIT)
89 live_imgui_render()
90
91 live_end_frame()
92}
93
94[export]
95def shutdown() {
96 live_imgui_shutdown()
97 live_destroy_window()
98}
99
100[export]
101def main() {
102 init()
103 while (!exit_requested()) {
104 update()
105 maybe_collect_gc()
106 }
107 shutdown()
108}
8.19.8.1.1. Requires
Baseline boost layer. All four rails live in
imgui/imgui_widgets_builtin alongside the ordinary widgets — no extra
modules. (imgui/imgui_layout_builtin is a different rail: the
split_h / split_v / dock_left helpers of
Layout.)
8.19.8.1.2. When to reach for each
same_line is the workhorse — every multi-column row, every label-then-input
pattern uses it. Pass an explicit offset_from_start_x if the next widget
needs a column-aligned position; the default (0.0f) packs against the
previous item. A second spacing argument overrides the horizontal gap
(negative = the style’s ItemSpacing.x).
spacing is a minimal 1-line gap — cheaper to read than dummy when
you just want breathing room between sections. Stack three of them if you
want a slightly larger gap without committing to a fixed pixel height.
new_line is conceptually \n at the layout level — one full text
line. Useful when the current row had a tall widget and you want the next
row to start fresh from the left margin without accumulating Y from the
tall content.
dummy(size) reserves an arbitrary rectangle. Pass size = float2(0, 40)
for a 40-pixel-tall invisible spacer. The X component can pre-allocate a
horizontal slot too — useful for grid-like alignment when widgets vary in
width.
8.19.8.1.3. Snapshot shape
Each layout marker registers an entry under its ident, with kind set
to the rail that fired — "same_line", "spacing", "new_line",
"dummy" (EmptyMarkerState is the state struct behind all four,
not the reported kind):
curl -X POST -d '{"name":"imgui_snapshot"}' localhost:9090/command \
| jq '.globals."LAYOUT_WIN/SL_AB"'
Tests that want to verify “this layout was produced” can walk the
snapshot and confirm the markers fired in the expected order — see
modules/dasImgui/tests/test_layout_primitives.das for the assertion shape.
See also
Full source: modules/dasImgui/examples/tutorial/layout_primitives.das
Companion tutorial: Layout — the higher-level layout
helpers (with_indent, with_item_width, with_text_wrap_pos).
Integration test: modules/dasImgui/tests/test_layout_primitives.das.
Boost macros — the macro layer.