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.