8.18.1.5. 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: modules/dasImgui/examples/tutorial/narrative_widgets.das.
8.18.1.5.1. 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
2options _comment_hygiene = true
3
4require imgui
5require imgui_app
6require opengl/opengl_boost
7require live/glfw_live
8require live/live_api
9require live/live_commands
10require live/live_vars
11require live_host
12require imgui/imgui_live
13require imgui/imgui_boost_runtime
14require imgui/imgui_boost_v2
15require imgui/imgui_widgets_builtin
16require imgui/imgui_containers_builtin
17require imgui/imgui_visual_aids
18
19// =============================================================================
20// TUTORIAL: narrative_widgets — boost v2 read-only display widgets.
21//
22// All eight share a NarrativeState (or LabelTextState) payload: the call-site
23// string echoes back into the snapshot so playwright tests can assert "the
24// label says what I expect". No focus, no click, no telemetry beyond `value`.
25//
26// Covers: text / text_unformatted / text_wrapped / text_colored / text_disabled
27// / bullet / bullet_text / label_text / separator_text
28//
29// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/narrative_widgets.das
30// LIVE: daslang-live modules/dasImgui/examples/tutorial/narrative_widgets.das
31//
32// DRIVE (when running live):
33// curl -X POST -d '{"name":"imgui_snapshot"}' localhost:9090/command \
34// | jq '.globals."NARRATIVE_WIN/BULLET_MARK".payload.value'
35// =============================================================================
36
37[export]
38def init() {
39 live_create_window("dasImgui narrative widgets", 760, 600)
40 live_imgui_init(live_window)
41 let io & = unsafe(GetIO())
42 GetStyle().FontScaleMain = 1.4
43}
44
45[export]
46def update() {
47 if (!live_begin_frame()) return
48 begin_frame()
49
50 ImGui_ImplGlfw_NewFrame()
51 apply_synth_io_override()
52 NewFrame()
53
54 SetNextWindowPos(ImVec2(60.0, 60.0), ImGuiCond.Always)
55 SetNextWindowSize(ImVec2(640.0, 480.0), ImGuiCond.Always)
56 window(NARRATIVE_WIN, (text = "Narrative widgets", closable = false,
57 flags = ImGuiWindowFlags.None)) {
58 // Each call passes an explicit ident so the widget registers at
59 // NARRATIVE_WIN/<ident> and a snapshot can assert "the label says what
60 // I expect". NarrativeState.value mirrors the call-site string.
61 text(PLAIN_LINE, (text = "text() - one line, telemetry-visible."))
62
63 // text_wrapped reflows to the window's content edge.
64 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."))
65
66 separator_text(SEP_COLOR, (text = "Color and emphasis"))
67
68 // Colored / disabled - visual variants, same payload shape.
69 text_colored(COLORED_LINE, (color = float4(0.7f, 0.9f, 0.4f, 1.0f),
70 text = "text_colored() with an inline float4 color."))
71 text_disabled(DISABLED_LINE, (text = "text_disabled() - greyed for non-actionable hints."))
72
73 separator_text(SEP_BULLET, (text = "Bulleted lines"))
74
75 // bullet() emits the marker glyph; bullet_text() bundles marker + text.
76 bullet(BULLET_MARK)
77 bullet_text(BULLET_FIRST, (text = "First point of interest."))
78 bullet_text(BULLET_SECOND, (text = "Second point - bullet glyph plus text in one call."))
79
80 separator_text(SEP_LABEL, (text = "Label/value pair"))
81
82 // label_text - two-string display, both strings echo into the payload.
83 label_text(VERSION_LABEL, (key = "Version", value = "v2.0-detour"))
84 }
85
86 end_of_frame()
87 Render()
88 var w, h : int
89 live_get_framebuffer_size(w, h)
90 glViewport(0, 0, w, h)
91 glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
92 glClear(GL_COLOR_BUFFER_BIT)
93 live_imgui_render()
94
95 live_end_frame()
96}
97
98[export]
99def shutdown() {
100 live_imgui_shutdown()
101 live_destroy_window()
102}
103
104[export]
105def main() {
106 init()
107 while (!exit_requested()) {
108 update()
109 }
110 shutdown()
111}
8.18.1.5.1.1. Requires
Baseline boost layer (imgui/imgui_boost_v2 re-exports
imgui/imgui_widgets_builtin). No extra modules.
8.18.1.5.1.2. 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.
8.18.1.5.1.3. 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).
8.18.1.5.1.4. 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.
8.18.1.5.1.5. 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.
8.18.1.5.1.6. 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").
8.18.1.5.1.7. 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: modules/dasImgui/examples/tutorial/narrative_widgets.das
Integration tests: modules/dasImgui/tests/test_narrative_text.das,
modules/dasImgui/tests/test_narrative_bullet.das,
modules/dasImgui/tests/test_narrative_separator.das.
Boost macros — the macro layer.