Narrative widgets
The narrative family is dasImgui’s set of read-only display widgets — text
emission with optional color, emphasis, bullets, or label/value framing.
All share a NarrativeState (or LabelTextState) payload that echoes
the call-site string back into the snapshot, so playwright tests can
assert “the label says what I expect” without any layout state.
Every rail accepts an optional leading ident. Pass one — text(IDENT,
(text = "...")) — and the widget registers at NARRATIVE_WIN/IDENT so a
snapshot can target it by name; omit it — text("...") — and it registers
under an auto-generated source-line key instead. This tutorial passes an
ident on every call so each line is assertable.
The nine rails:
text(IDENT, (text = "..."))— one line of plain text. Implemented viaTextUnformatted(no printf-style format expansion).text_unformatted(IDENT, (text = "..."))— explicit alias fortext; identical implementation. Exists so call sites can signal intent.text_wrapped(IDENT, (text = "..."))— reflows long strings to the window’s content edge.text_colored(IDENT, (color = float4(...), text = ...))— colored variant.text_disabled(IDENT, (text = "..."))— greyed for non-actionable hints.bullet(IDENT)— bullet glyph alone.bullet_text(IDENT, (text = "..."))— bullet glyph + text bundled.label_text(IDENT, (key = ..., value = ...))— two-string display, both echoed into the payload.separator_text(IDENT, (text = "..."))— horizontal rule with a centered label.
Source: examples/tutorial/narrative_widgets.das.
Walkthrough
These widgets take no input, so the recording is a voiced, self-verifying tour: each beat narrates a group while the cursor points at it and asserts the widget rendered and echoed its call-site string into the snapshot — the “the label says what I expect” claim made concrete. A missing or wrong value aborts the recording at teardown instead of shipping.
1options gen2
2
3require imgui
4require imgui_app
5require opengl/opengl_boost
6require live/glfw_live
7require live/live_api
8require live/live_commands
9require live/live_vars
10require live_host
11require imgui/imgui_live
12require imgui/imgui_boost_runtime
13require imgui/imgui_boost_v2
14require imgui/imgui_widgets_builtin
15require imgui/imgui_containers_builtin
16require imgui/imgui_visual_aids
17
18// =============================================================================
19// TUTORIAL: narrative_widgets — boost v2 read-only display widgets.
20//
21// All eight share a NarrativeState (or LabelTextState) payload: the call-site
22// string echoes back into the snapshot so playwright tests can assert "the
23// label says what I expect". No focus, no click, no telemetry beyond `value`.
24//
25// Covers: text / text_unformatted / text_wrapped / text_colored / text_disabled
26// / bullet / bullet_text / label_text / separator_text
27//
28// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/narrative_widgets.das
29// LIVE: daslang-live modules/dasImgui/examples/tutorial/narrative_widgets.das
30//
31// DRIVE (when running live):
32// curl -X POST -d '{"name":"imgui_snapshot"}' localhost:9090/command \
33// | jq '.globals."NARRATIVE_WIN/BULLET_MARK".payload.value'
34// =============================================================================
35
36[export]
37def init() {
38 live_create_window("dasImgui narrative widgets", 760, 600)
39 live_imgui_init(live_window)
40 let io & = unsafe(GetIO())
41 GetStyle().FontScaleMain = 1.4
42}
43
44[export]
45def update() {
46 if (!live_begin_frame()) return
47 begin_frame()
48
49 ImGui_ImplGlfw_NewFrame()
50 apply_synth_io_override()
51 NewFrame()
52
53 SetNextWindowPos(ImVec2(60.0, 60.0), ImGuiCond.Always)
54 SetNextWindowSize(ImVec2(640.0, 480.0), ImGuiCond.Always)
55 window(NARRATIVE_WIN, (text = "Narrative widgets", closable = false,
56 flags = ImGuiWindowFlags.None)) {
57 // Each call passes an explicit ident so the widget registers at
58 // NARRATIVE_WIN/<ident> and a snapshot can assert "the label says what
59 // I expect". NarrativeState.value mirrors the call-site string.
60 text(PLAIN_LINE, (text = "text() - one line, telemetry-visible."))
61
62 // text_wrapped reflows to the window's content edge.
63 text_wrapped(WRAPPED_LINE, (text = "text_wrapped() reflows long strings to the window's right edge. Resize the window and the layout follows; the snapshot still carries the full source string regardless of wrapping."))
64
65 separator_text(SEP_COLOR, (text = "Color and emphasis"))
66
67 // Colored / disabled - visual variants, same payload shape.
68 text_colored(COLORED_LINE, (color = float4(0.7f, 0.9f, 0.4f, 1.0f),
69 text = "text_colored() with an inline float4 color."))
70 text_disabled(DISABLED_LINE, (text = "text_disabled() - greyed for non-actionable hints."))
71
72 separator_text(SEP_BULLET, (text = "Bulleted lines"))
73
74 // bullet() emits the marker glyph; bullet_text() bundles marker + text.
75 bullet(BULLET_MARK)
76 bullet_text(BULLET_FIRST, (text = "First point of interest."))
77 bullet_text(BULLET_SECOND, (text = "Second point - bullet glyph plus text in one call."))
78
79 separator_text(SEP_LABEL, (text = "Label/value pair"))
80
81 // label_text - two-string display, both strings echo into the payload.
82 label_text(VERSION_LABEL, (key = "Version", value = "v2.0-detour"))
83 }
84
85 end_of_frame()
86 Render()
87 var w, h : int
88 live_get_framebuffer_size(w, h)
89 glViewport(0, 0, w, h)
90 glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
91 glClear(GL_COLOR_BUFFER_BIT)
92 live_imgui_render()
93
94 live_end_frame()
95}
96
97[export]
98def shutdown() {
99 live_imgui_shutdown()
100 live_destroy_window()
101}
102
103[export]
104def main() {
105 init()
106 while (!exit_requested()) {
107 update()
108 }
109 shutdown()
110}
Requires
Baseline boost layer (imgui/imgui_boost_v2 re-exports
imgui/imgui_widgets_builtin). No extra modules.
text vs text_unformatted vs text_wrapped
text(s)— emitssthrough ImGui’sTextUnformatted(s). No printf-style format expansion; the string is rendered verbatim.text_unformatted(s)— identical totext(s)(sameTextUnformattedcall). Exists as an explicit-intent alias for call sites whereunformattedreads better, or where you want to underscore the no-printf-expansion contract for readers.text_wrapped(s)— emits throughTextWrapped(s)so the text reflows at the window’s content edge. The wrap position respectswith_text_wrap_posif you’ve pushed one.
The payload shape is identical for all three; the alias-pair
(text / text_unformatted) renders identically, while
text_wrapped is the one that actually changes rendering behavior.
Colored vs disabled
text_colored((color, text)) takes an inline float4 and renders the
text in that color. Useful for status callouts, error indicators, or
section accents. The color is per-call — no scope push needed.
text_disabled(s) renders in ImGui’s StyleColor.TextDisabled — the
greyed tone used for inert menu items and hints. The most common use is
the (?) help marker glyph (see Flat tooltips).
Bullets
bullet(IDENT) emits the marker glyph alone — useful when you want
custom content (a colored swatch, an icon) immediately after the bullet.
bullet_text(IDENT, (text = "...")) is the bundled form — glyph + text
in one call. Use this 95% of the time; reach for bullet(IDENT) +
same_line + custom-glyph only when you genuinely need the manual
layout.
label_text
label_text((key, value)) maps to ImGui’s LabelText(key, value).
ImGui draws the value text on the left and the key as a label to its
right — so (key = "Version", value = "v2.0-detour") renders
v2.0-detour on the left with Version to its right. Both strings
round-trip through the snapshot payload, so snapshot-driven property
tests get both halves for assertion.
separator_text
separator_text("Section name") is a horizontal rule with the label
centered above it. Use it to break a long window into named sections;
much easier to scan than separator() followed by text("Section
name").
Snapshot shape
With an ident, a narrative widget registers at NARRATIVE_WIN/IDENT —
a stable path you can pull a field from. Without one it still surfaces a
path, but keyed by source line (NARRATIVE_WIN/:61:8), which shifts when
you edit the file; pass an ident whenever a test or driver needs to target
the line.
curl -X POST -d '{"name":"imgui_snapshot"}' localhost:9090/command \
| jq '.globals."NARRATIVE_WIN/VERSION_LABEL".payload.value'
See also
Full source: examples/tutorial/narrative_widgets.das
Integration tests: tests/integration/test_narrative_text.das,
tests/integration/test_narrative_bullet.das,
tests/integration/test_narrative_separator.das.
Boost macros — the macro layer.