8.19.4. Display widgets
dasImgui’s read-only display family wraps ImGui’s two main output widgets
into the v2 boost surface. progress_bar wraps ImGui::ProgressBar
with a ProgressBarState payload carrying {fraction, size, overlay};
image wraps ImGui::Image with the full uv0 / uv1 /
tint_col / border_col quartet.
progress_bar(PB_STATIC, (fraction = 0.33f,
size = float2(-1.0f, 0.0f),
overlay = "33%"))
let io & = unsafe(GetIO())
image(IMG_PLAIN, (user_texture_id = io.Fonts.TexRef,
size = float2(96.0f, 96.0f),
uv0 = float2(0.0f, 0.0f),
uv1 = float2(1.0f, 1.0f),
tint_col = float4(1.0f, 1.0f, 1.0f, 1.0f),
border_col = float4(0.0f, 0.0f, 0.0f, 0.0f)))
Display widgets are read-only, so they don’t need a caller-side ident — call
them anonymously and only the parent window(DISPLAY_WIN, ...) registers a
routable entry. This example names each one (PB_STATIC / PB_DRIVEN /
PB_FIXED / IMG_PLAIN / IMG_TINT) so every widget registers its own
snapshot path — which is what lets the recording assert each one’s output (the
static bar on screen, the driven bar’s fraction sweeping, the images present).
Source: modules/dasImgui/examples/tutorial/display_widgets.das.
8.19.4.1. Walkthrough
The recording narrates the three progress bars and two images while the middle
bar’s fraction sweeps under a sine wave. These widgets take no input, so the
self-check is on their output: the static bar and both images are asserted on
screen, and the driven bar’s fraction is asserted to change over time -
so a bar that stopped rendering or a sine that stopped sweeping would abort the
recording.
1options gen2
2options _comment_hygiene = true
3options gc
4
5require math
6require imgui
7require imgui_app
8require opengl/opengl_boost
9require live/glfw_live
10require live/live_api
11require live/live_commands
12require live/live_vars
13require live_host
14require imgui/imgui_live
15require imgui/imgui_boost_runtime
16require imgui/imgui_boost_v2
17require imgui/imgui_widgets_builtin
18require imgui/imgui_containers_builtin
19require imgui/imgui_visual_aids
20
21// =============================================================================
22// TUTORIAL: display_widgets — boost v2 visual-output widgets.
23//
24// progress_bar wraps ImGui::ProgressBar with a ProgressBarState payload
25// carrying {fraction, size, overlay}. image wraps ImGui::Image with full
26// uv0/uv1/tint_col/border_col + a uint64 reinterpret of the texture handle
27// for snapshot readability.
28//
29// The image() example uses the ImGui font atlas texture (always available),
30// so this tutorial runs without any external asset.
31//
32// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/display_widgets.das
33// LIVE: daslang-live modules/dasImgui/examples/tutorial/display_widgets.das
34//
35// DRIVE (when running live):
36// curl -X POST -d '{"name":"imgui_snapshot"}' localhost:9090/command \
37// | jq '.globals."DISPLAY_WIN".payload'
38// =============================================================================
39
40var private g_phase : float = 0.0f
41
42[export]
43def init() {
44 live_create_window("dasImgui display widgets", 940, 680)
45 live_imgui_init(live_window)
46 let io & = unsafe(GetIO())
47 GetStyle().FontScaleMain = 1.4
48}
49
50[export]
51def update() {
52 if (!live_begin_frame()) return
53 begin_frame()
54
55 ImGui_ImplGlfw_NewFrame()
56 apply_synth_io_override()
57 NewFrame()
58
59 g_phase += 0.01f
60 let driven_frac = 0.5f + 0.5f * sin(g_phase)
61
62 SetNextWindowPos(ImVec2(60.0, 60.0), ImGuiCond.Always)
63 SetNextWindowSize(ImVec2(680.0, 420.0), ImGuiCond.Always)
64 window(DISPLAY_WIN, (text = "Display widgets", closable = false,
65 flags = ImGuiWindowFlags.None)) {
66 separator_text("progress_bar")
67
68 // Static bar - 33% with auto-formatted overlay.
69 progress_bar(PB_STATIC, (fraction = 0.33f,
70 size = float2(-1.0f, 0.0f),
71 overlay = "33%"))
72
73 // Driven bar - sine-wave fraction, default overlay.
74 progress_bar(PB_DRIVEN, (fraction = driven_frac,
75 size = float2(-1.0f, 0.0f),
76 overlay = ""))
77
78 // Fixed-width bar with custom overlay text.
79 progress_bar(PB_FIXED, (fraction = 0.75f,
80 size = float2(240.0f, 0.0f),
81 overlay = "loading..."))
82
83 separator_text("image")
84
85 // Use the ImGui font atlas as our texture — always built by frame 1.
86 let io & = unsafe(GetIO())
87 if (io.Fonts.TexData == null) {
88 text("Font atlas not ready - wait for first frame.")
89 } else {
90 text("image() against the font atlas - varying uv + tint per call.")
91 image(IMG_PLAIN, (user_texture_id = io.Fonts.TexRef,
92 size = float2(96.0f, 96.0f),
93 uv0 = float2(0.0f, 0.0f),
94 uv1 = float2(1.0f, 1.0f),
95 tint_col = float4(1.0f, 1.0f, 1.0f, 1.0f),
96 border_col = float4(0.0f, 0.0f, 0.0f, 0.0f)))
97 same_line(SL_IMG)
98 image(IMG_TINT, (user_texture_id = io.Fonts.TexRef,
99 size = float2(96.0f, 96.0f),
100 uv0 = float2(0.0f, 0.0f),
101 uv1 = float2(1.0f, 1.0f),
102 tint_col = float4(0.3f, 0.9f, 0.6f, 1.0f),
103 border_col = float4(1.0f, 1.0f, 1.0f, 0.5f)))
104 }
105 }
106
107 end_of_frame()
108 Render()
109 var w, h : int
110 live_get_framebuffer_size(w, h)
111 glViewport(0, 0, w, h)
112 glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
113 glClear(GL_COLOR_BUFFER_BIT)
114 live_imgui_render()
115
116 live_end_frame()
117}
118
119[export]
120def shutdown() {
121 live_imgui_shutdown()
122 live_destroy_window()
123}
124
125[export]
126def main() {
127 init()
128 while (!exit_requested()) {
129 update()
130 maybe_collect_gc()
131 }
132 shutdown()
133}
8.19.4.1.1. Requires
Baseline boost layer (imgui/imgui_boost_v2 re-exports the rail family
from imgui/imgui_widgets_builtin). No extra modules.
8.19.4.1.2. progress_bar
ProgressBarState mirrors the call-site values verbatim. fraction
holds the raw call-site value (no clamp at the state level); ImGui
clamps to [0, 1] for the rendered bar, but the snapshot payload
reflects whatever the caller passed — so out-of-range inputs surface in
the snapshot for assertion. Pass a negative value for indeterminate
animation. size is the ImGui ImVec2: -1.0f for the X
component fills available width; explicit pixels for fixed width.
overlay is the centered label drawn on top of the bar — leave empty
for the auto-formatted percentage.
8.19.4.1.3. image
user_texture_id is an ImTextureRef (ImGui 1.92’s texture handle)
and is deliberately not echoed into ImageState — the handle is
opaque, so telemetry carries only the actionable per-call args
(size, uv0, uv1, tint_col, border_col). All four
uv0 / uv1 / tint_col / border_col defaults match the C++
ImGui::Image defaults so an unset call is the identity render. The
tutorial uses the ImGui font atlas (GetIO().Fonts.TexRef, guarded on
Fonts.TexData != null for the frames before the backend builds it)
as a guaranteed-available texture; production code passes an
ImTextureRef wrapping its own GPU resource — see
Texture references.
8.19.4.1.4. Snapshot shape
Each named widget registers its own snapshot entry, so a rail’s state is readable directly. Probe with:
curl -X POST -d '{"name":"imgui_snapshot"}' localhost:9090/command \
| jq '.globals."DISPLAY_WIN/PB_DRIVEN".payload'
That returns the driven bar’s {fraction, size, overlay} — useful for
snapshot-driven regression tests when you want to assert PB_DRIVEN’s
fraction matches the sine-driven value (the recording does exactly that, via
record_check_changed). Left anonymous, a widget folds into a line-keyed
entry under the window instead.
See also
Full source: modules/dasImgui/examples/tutorial/display_widgets.das
Integration test: modules/dasImgui/tests/test_display_progress.das and modules/dasImgui/tests/test_display_image.das.
Boost macros — the macro layer.