8.19.3. Widgets tour

One of every common boost widget on a single panel. The example frames as an audio-settings dialog so each widget reads contextually: a text input for the user name, a slider for volume, a checkbox for mute, a combo for codec quality, a color editor for the accent color, and a button to save.

Source: modules/dasImgui/examples/tutorial/widgets_tour.das.

8.19.3.1. Walkthrough

The recording is voiced and self-verifying: each stage speaks a line while a real gesture fires under it and is asserted — typing into the name field (committed value checked), dragging VOLUME (value must change), clicking MUTED (toggle must register), opening the QUALITY combo and picking High (selection verified), setting TINT from the API (color_edit3’s picker is mouse-only, so the tour drives it via force_set and verifies the swatch took), and clicking Save (click must register). A silently broken stage aborts the recording at teardown instead of shipping.

  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: widgets_tour — one of every common boost widget on a single panel.
 22//
 23// Frame as an audio-settings dialog so each widget reads contextually:
 24//   USER_NAME  : input_text   — who's listening
 25//   VOLUME     : slider_float — master volume
 26//   MUTED      : checkbox     — mute toggle
 27//   QUALITY    : combo        — codec quality preset
 28//   TINT       : color_edit3  — accent color for the UI
 29//   SAVE_BTN   : button       — apply the settings
 30//
 31// Read alongside :ref:`tutorial_boost_basics` for the frame-loop shape; this
 32// tutorial only adds widgets on top of that scaffold.
 33//
 34// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/widgets_tour.das
 35// LIVE:       daslang-live modules/dasImgui/examples/tutorial/widgets_tour.das
 36//
 37// DRIVE (when running live):
 38//   curl -X POST -d '{"name":"imgui_force_set","args":{"target":"AUDIO_WIN/USER_NAME","value":"Boris"}}'        localhost:9090/command
 39//   curl -X POST -d '{"name":"imgui_force_set","args":{"target":"AUDIO_WIN/VOLUME","value":0.75}}'              localhost:9090/command
 40//   curl -X POST -d '{"name":"imgui_force_set","args":{"target":"AUDIO_WIN/MUTED","value":true}}'               localhost:9090/command
 41//   curl -X POST -d '{"name":"imgui_force_set","args":{"target":"AUDIO_WIN/QUALITY","value":2}}'                localhost:9090/command
 42//   curl -X POST -d '{"name":"imgui_force_set","args":{"target":"AUDIO_WIN/TINT","value":{"x":0.2,"y":0.8,"z":0.4}}}' localhost:9090/command
 43//   curl -X POST -d '{"name":"imgui_click","args":{"target":"AUDIO_WIN/SAVE_BTN"}}'                       localhost:9090/command
 44// =============================================================================
 45
 46[export]
 47def init() {
 48    live_create_window("dasImgui widgets tour", 1024, 720)
 49    live_imgui_init(live_window)
 50    let io & = unsafe(GetIO())
 51    GetStyle().FontScaleMain = 1.5
 52}
 53
 54[export]
 55def update() {
 56    if (!live_begin_frame()) return
 57    begin_frame()
 58
 59    ImGui_ImplGlfw_NewFrame()
 60    apply_synth_io_override()
 61    NewFrame()
 62
 63    // Sized for content with breathing room on the right + below for narrate
 64    // post-its to appear without overlapping the panel.
 65    SetNextWindowPos(ImVec2(60.0, 60.0), ImGuiCond.Always)
 66    SetNextWindowSize(ImVec2(720.0, 540.0), ImGuiCond.Always)
 67    window(AUDIO_WIN, (text = "Audio settings", closable = false,
 68                       flags = ImGuiWindowFlags.None)) {
 69        // Text input — buffer + string-mirror managed by the state struct.
 70        input_text(USER_NAME, (text = "Your name"))
 71
 72        spacing(WT_SP_1)
 73
 74        // Slider — float state with [0, 1] bounds set per-frame.
 75        VOLUME.bounds = (0.0f, 1.0f)
 76        slider_float(VOLUME, (text = "Master volume"))
 77
 78        // Checkbox — bool state, toggles on click.
 79        checkbox(MUTED, (text = "Mute"))
 80
 81        spacing(WT_SP_2)
 82
 83        // Combo — int state indexing into the items array.
 84        combo(QUALITY, (text = "Quality",
 85                        items <- ["Low", "Medium", "High", "Ultra"]))
 86
 87        spacing(WT_SP_3)
 88
 89        // Color editor — three-channel RGB, opens a picker on click.
 90        color_edit3(TINT, (text = "Accent color"))
 91
 92        spacing(WT_SP_4)
 93        separator(WT_SEP_1)
 94        spacing(WT_SP_5)
 95
 96        // Button — true on the frame the click registers; click_count accumulates.
 97        if (button(SAVE_BTN, (text = "Save settings"))) {
 98            print("save clicked: name={USER_NAME.value} vol={VOLUME.value} muted={MUTED.value} q={QUALITY.value}\n")
 99        }
100
101        spacing(WT_SP_6)
102        text("saves so far: {SAVE_BTN.click_count}")
103    }
104
105    end_of_frame()
106    Render()
107    var w, h : int
108    live_get_framebuffer_size(w, h)
109    glViewport(0, 0, w, h)
110    glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
111    glClear(GL_COLOR_BUFFER_BIT)
112    live_imgui_render()
113
114    live_end_frame()
115}
116
117[export]
118def shutdown() {
119    live_imgui_shutdown()
120    live_destroy_window()
121}
122
123[export]
124def main() {
125    init()
126    while (!exit_requested()) {
127        update()
128        maybe_collect_gc()
129    }
130    shutdown()
131}

8.19.3.1.1. Requires

The require block matches Boost basics exactly — backend (imgui_app / glfw / opengl), live host (live/*), and the v2 boost layer (imgui_live, imgui_boost_runtime, imgui_boost_v2, imgui_widgets_builtin, imgui_containers_builtin for the window(...) block container). One extra line pulls in imgui/imgui_visual_aids so the post-it narrate overlay the driver script paints into the recording is available at render time.

8.19.3.1.2. Init and shutdown

init() opens a 1024x720 GLFW window via live_create_window and hands the handle to live_imgui_init. It also bumps GetStyle().FontScaleMain to 1.5 so the recorded APNG reads at typical Sphinx HTML widths without zooming (ImGui 1.92 moved io.FontGlobalScale onto the style as FontScaleMain). shutdown() mirrors the pair in reverse order.

8.19.3.1.3. The frame loop

update() follows the standard dasImgui v2 shape — see Boost basics for the line-by-line breakdown. The only addition is a single call to apply_synth_io_override() between ImGui_ImplGlfw_NewFrame and NewFrame. The GLFW backend polls real OS mouse data every focused frame and would otherwise win the IO race against any synthesized event the driver script posted just before. The override re-asserts the synth IO so live-driven clicks land at the right widget.

8.19.3.1.4. Widgets

All six widgets live inside a single window(AUDIO_WIN, ...) boost container — same pattern Boost basics introduced, so leaves register at AUDIO_WIN/<ident>:

window(AUDIO_WIN, (text = "Audio settings", closable = false,
                   flags = ImGuiWindowFlags.None)) {
    input_text(USER_NAME, (text = "Your name"))
    VOLUME.bounds = (0.0f, 1.0f)
    slider_float(VOLUME, (text = "Master volume"))
    checkbox(MUTED, (text = "Mute"))
    combo(QUALITY, (text = "Quality", items <- ["Low", "Medium", "High", "Ultra"]))
    color_edit3(TINT, (text = "Accent color"))
    if (button(SAVE_BTN, (text = "Save settings"))) {
        print("save clicked: vol={VOLUME.value} muted={MUTED.value}\n")
    }
}

Each boost macro declares the named global the first time it expands and registers it under the path-prefixed name. The slider’s range comes from a plain field assignment one line above the macro call: VOLUME.bounds = (0.0f, 1.0f). The combo’s item list moves into the named argument with items <- because string arrays are non-copyable. SAVE_BTN.click_count accumulates across frames — handy for assertions in a test harness.

8.19.3.1.5. Standalone vs live

main() runs the loop directly when invoked as daslang.exe widgets_tour.das. Under daslang-live the host calls init / update / shutdown itself; main is ignored. Every state struct (USER_NAME, VOLUME, MUTED, QUALITY, TINT, SAVE_BTN) carries @live by default, so live-reloading the source preserves the widget contents.

8.19.3.1.6. Driving from outside

Under daslang-live the boost layer exposes imgui_force_set and imgui_click over localhost:9090. The top of the source file lists one curl invocation per widget. Each target is path-qualified:

curl -X POST -d '{"name":"imgui_force_set","args":{"target":"AUDIO_WIN/USER_NAME","value":"Boris"}}' \
     localhost:9090/command

For color_edit3, value is a JSON object with x / y / z fields — from_JV reads float3 from object form, not array form. For combo, value is the zero-based index into the items array.

8.19.3.1.7. Next steps

Layout helpers — splitters, columns, child windows — are next on top of the same widget set. To write your own widget kind on the same rails — a rotary knob, an XY-pad, a meter — see Custom widgets.

See also

Full source: modules/dasImgui/examples/tutorial/widgets_tour.das

Richer reference: modules/dasImgui/examples/features/inputs_*.das — every widget with every option exercised, against the same boost layer.

Previous tutorial: Boost basics

Next tutorial: Custom widgets

Boost macros — the macro layer.

Builtin widgets — widget reference.