Buttons

Six shapes of click trigger. All six use ClickState; state.clicked is the per-frame bool, state.click_count accumulates across frames.

button(IDENT, (text = ".."))                       // the workhorse
small_button(IDENT, (text = ".."))                 // no frame padding
arrow_button(IDENT, (text = "..", dir = ...))      // triangle glyph
invisible_button(IDENT, (text = "..", size = ...)) // hit area, no render
image_button(IDENT, (text = "..",                  // textured button
                     user_texture_id = tex_id,
                     size = ...))
tab_item_button(IDENT, (text = "..",               // button styled as tab,
                        flags = ...))              //   inside a tab_bar

Source: examples/tutorial/buttons.das.

Walkthrough

  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: buttons — six shapes of click trigger.
 20//
 21//   button(IDENT, (text = ".."))                       — the workhorse.
 22//   small_button(IDENT, (text = ".."))                 — no frame padding,
 23//                                                        for inline tools.
 24//   arrow_button(IDENT, (text = "..", dir = ...))      — triangular glyph,
 25//                                                        ImGuiDir.{Up,Down,
 26//                                                        Left,Right}.
 27//   invisible_button(IDENT, (text = "..", size = ...)) — hit area without
 28//                                                        rendering — overlay
 29//                                                        a clickable region
 30//                                                        on a drawlist scene.
 31//   image_button(IDENT, (text = "..",                  — textured button. The
 32//                        user_texture_id = tex_id,        font atlas works as
 33//                        size = ...))                     a no-setup texture.
 34//   tab_item_button(IDENT, (text = "..",               — button styled as a
 35//                           flags = ...))                 tab — MUST be called
 36//                                                        INSIDE a tab_bar.
 37//
 38// All six use `ClickState`: `state.clicked` is the per-frame click bool,
 39// `state.click_count` accumulates total clicks.
 40//
 41// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/buttons.das
 42// LIVE:       daslang-live modules/dasImgui/examples/tutorial/buttons.das
 43//
 44// DRIVE (when running live):
 45//   curl -X POST -d '{"name":"imgui_click","args":{"target":"BT_WIN/BT_GO"}}' \
 46//        localhost:9090/command
 47//   curl -X POST -d '{"name":"imgui_click","args":{"target":"BT_WIN/BAR/BT_ADD"}}' \
 48//        localhost:9090/command
 49// =============================================================================
 50
 51[export]
 52def init() {
 53    live_create_window("dasImgui buttons tutorial", 800, 720)
 54    live_imgui_init(live_window)
 55    let io & = unsafe(GetIO())
 56    GetStyle().FontScaleMain = 1.4
 57}
 58
 59[export]
 60def update() {
 61    if (!live_begin_frame()) return
 62    begin_frame()
 63
 64    ImGui_ImplGlfw_NewFrame()
 65    apply_synth_io_override()
 66    NewFrame()
 67
 68    SetNextWindowPos(ImVec2(20.0f, 20.0f), ImGuiCond.Always)
 69    SetNextWindowSize(ImVec2(760.0f, 680.0f), ImGuiCond.Always)
 70    window(BT_WIN, (text = "buttons tutorial", closable = false,
 71                    flags = ImGuiWindowFlags.None)) {
 72
 73        text("Six shapes — ClickState everywhere; state.click_count accumulates.")
 74        text(BT_HINT, (text = "Plain / small / arrow / invisible / image / tab_item — pick by visual fit."))
 75        separator()
 76
 77        // ---- Stage 1: button — the workhorse ----
 78        if (button(BT_GO, (text = "Go"))) {
 79            // Hook your click handler here.
 80        }
 81        text("BT_GO clicks = {BT_GO.click_count}")
 82        spacing()
 83
 84        // ---- Stage 2: small_button — no padding, inline tool ----
 85        small_button(BT_SMALL, (text = "quit"))
 86        text("BT_SMALL clicks = {BT_SMALL.click_count}  // SmallButton has zero frame padding")
 87        spacing()
 88
 89        // ---- Stage 3: arrow_button — directional pair ----
 90        arrow_button(BT_BACK, (text = "##back", dir = ImGuiDir.Left)); same_line(BT_SL1)
 91        arrow_button(BT_FWD,  (text = "##fwd",  dir = ImGuiDir.Right))
 92        text("nav clicks: back={BT_BACK.click_count}, fwd={BT_FWD.click_count}")
 93        spacing()
 94
 95        // ---- Stage 4: invisible_button — hit area without a glyph ----
 96        text("Invisible hotspot below (120×24, no glyph):")
 97        invisible_button(BT_HOT, (text = "##hotspot", size = float2(120.0f, 24.0f)))
 98        text("BT_HOT clicks = {BT_HOT.click_count}  // overlay on a drawlist / image / etc.")
 99        spacing()
100
101        // ---- Stage 5: image_button — textured button (font atlas) ----
102        let io & = unsafe(GetIO())
103        if (io.Fonts.TexData != null) {
104            image_button(BT_IMG, (text = "##font",
105                                  user_texture_id = io.Fonts.TexRef,
106                                  size = float2(48.0f, 48.0f)))
107            text("BT_IMG clicks = {BT_IMG.click_count}  // textured 48×48 of the font atlas")
108        }
109        spacing()
110
111        // ---- Stage 6: tab_item_button — must live inside a tab_bar ----
112        text("tab_item_button — leading '?' tallies, trailing '+' grows the bar:")
113        tab_bar(BT_BAR, (text = "MyBar",
114                          flags = ImGuiTabBarFlags.FittingPolicyShrink)) {
115            tab_item_button(BT_HELP, (text = "?",
116                                       flags = ImGuiTabItemFlags.Leading |
117                                               ImGuiTabItemFlags.NoTooltip))
118            tab_item_button(BT_ADD, (text = "+",
119                                      flags = ImGuiTabItemFlags.Trailing |
120                                              ImGuiTabItemFlags.NoTooltip))
121            tab_item(BT_TAB_A, (text = "alpha", closable = false,
122                                 flags = ImGuiTabItemFlags.None)) {
123                text(BT_BODY_A, (text = "tab alpha body"))
124            }
125            tab_item(BT_TAB_B, (text = "beta", closable = false,
126                                 flags = ImGuiTabItemFlags.None)) {
127                text(BT_BODY_B, (text = "tab beta body"))
128            }
129        }
130        text("BT_HELP clicks = {BT_HELP.click_count}, BT_ADD clicks = {BT_ADD.click_count}")
131    }
132
133    end_of_frame()
134    Render()
135    var w, h : int
136    live_get_framebuffer_size(w, h)
137    glViewport(0, 0, w, h)
138    glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
139    glClear(GL_COLOR_BUFFER_BIT)
140    live_imgui_render()
141
142    live_end_frame()
143}
144
145[export]
146def shutdown() {
147    live_imgui_shutdown()
148    live_destroy_window()
149}
150
151[export]
152def main() {
153    init()
154    while (!exit_requested()) {
155        update()
156    }
157    shutdown()
158}

Requires

Already in the baseline boost layer:

  • imgui/imgui_widgets_builtin — every *_button rail.

  • imgui/imgui_containers_builtintab_bar / tab_item for the tab_item_button host.

  • imgui/imgui_boost_runtimeClickState (shared across all six widgets).

button — the workhorse

The default click trigger. Returns true on the frame the user clicked; state.click_count tallies across frames:

if (button(SAVE, (text = "Save"))) {
    // one-shot handler — runs once per click
}
// OR drive on accumulated count:
text("saves: {SAVE.click_count}")

size = (0, 0) lets ImGui auto-size to the label. Pass an explicit size for fixed-width toolbar rows.

small_button — zero padding

Same widget shape; SmallButton() drops the frame padding. Use for inline tool strips that need to feel like part of the surrounding text:

text("Status: ")
same_line()
small_button(REFRESH, (text = "refresh"))

No size arg — small_button always auto-sizes.

arrow_button — directional glyph

A triangle pointing in one of four directions. dir : ImGuiDir picks the direction:

arrow_button(BACK, (text = "##back", dir = ImGuiDir.Left)); same_line()
arrow_button(FWD,  (text = "##fwd",  dir = ImGuiDir.Right))

The text is the ImGui label (mostly "##name" to suppress visible text — the glyph carries the meaning). Each call needs its own IDENT (separate ClickState).

invisible_button — hit area only

Renders nothing, but captures clicks inside its bbox. The canonical use: overlay a hit area on top of a drawlist scene, image, or custom glyph:

invisible_button(HOTSPOT, (text = "##hotspot",
                           size = float2(120.0f, 24.0f)))
if (HOTSPOT.clicked) {
    // capture click on the scene below
}

Requires an explicit size — there’s no glyph to derive bounds from. ImGui still tracks hover and click via IsItemHovered() / IsItemClicked(), so it composes with the rest of the imgui interaction stack.

image_button — textured trigger

Renders a texture as the button face. user_texture_id : void? is ImGui’s opaque texture handle — on GL it’s the GL texture id cast to void?. The font atlas (io.Fonts.TexID) is always available and makes for a no-setup demo target:

let io & = unsafe(GetIO())
let font_tex = io.Fonts.TexID
if (font_tex != null) {
    image_button(BTN, (text = "##font",
                       user_texture_id = font_tex,
                       size = float2(48.0f, 48.0f)))
}

Real apps load their own textures via stbi or LoadTextureFromFile helpers (see examples/imgui_demo/widgets.das for the 8-button image-grid pattern). uv0 / uv1 slice into the texture; bg_col / tint_col modulate the rendered face.

tab_item_button — button styled as a tab

A click trigger that visually matches sibling tab_item headers. Must live inside a tab_bar body. Flag with Leading to anchor to the start of the bar, Trailing to the end — the canonical ? / + row:

tab_bar(BAR, (text = "MyTabBar",
               flags = ImGuiTabBarFlags.FittingPolicyResizeDown)) {
    if (tab_item_button(HELP, (text = "?",
                                flags = ImGuiTabItemFlags.Leading |
                                        ImGuiTabItemFlags.NoTooltip))) {
        // open help popup
    }
    if (tab_item_button(ADD, (text = "+",
                               flags = ImGuiTabItemFlags.Trailing |
                                       ImGuiTabItemFlags.NoTooltip))) {
        // push a new entry
    }
    tab_item(TAB_A, (text = "alpha", closable = false,
                     flags = ImGuiTabItemFlags.None)) {
        text(BODY_A, (text = "tab body"))
    }
}

Unlike tab_item it has no content pane (no block body) — it’s a trigger only. See Tab bar for the regular tab pattern.

Driving from outside

Every *_button accepts imgui_click and snapshot probes:

# Plain button
curl -X POST -d '{"name":"imgui_click","args":{"target":"BT_WIN/BT_GO"}}' \
     localhost:9090/command
# Tab-bar-nested button — path includes the bar segment
curl -X POST -d '{"name":"imgui_click","args":{"target":"BT_WIN/BT_BAR/BT_HELP"}}' \
     localhost:9090/command

Caller-owned variant

For sites where the click target lives on an external bool, use edit_button from imgui_boost_runtime (see External-pointer editing rail).

See also

Full source: examples/tutorial/buttons.das

Features-side demo: examples/features/triggers.das — every ClickState widget in one window, useful for imgui_click smoke testing.

Sibling tutorials: Color (color_button is a special button variant), Tab bar (where tab_item_button lives).

Boost macros — the macro layer.