8.19.37. Selectable hover

selectable is a toggleable row — its ToggleState flips between selected and unselected on click. Some call sites want the row geometry only, with the selected flag pinned to false; the hover variant covers that:

var private SH_ROW : table<int; EmptyMarkerState>

for (i in range(length(ROWS))) {
    let hovered = selectable_hover(SH_ROW[i], (text = "Row {i}: {ROWS[i]}"))
    if (hovered) {
        // per-frame side-effect, e.g. SetMouseCursor(...)
    }
}

EmptyMarkerState backs the widget; the return value is the per-frame hover bool. The selected flag is fixed at false — clicks render a brief selection highlight but the row never persists as selected.

One widget per loop iteration means an indexed state table, and the [widget] macro does not auto-emit those — declare SH_ROW : table<int; EmptyMarkerState> at module scope yourself (string keys work too: table<string; EmptyMarkerState>).

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

8.19.37.1. Walkthrough

  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: selectable_hover — hover-target variant of selectable.
 22//
 23//   selectable(IDENT, (text = "Row"))        — toggleable (ToggleState).
 24//   selectable_hover(IDENT, (text = "Row"))  — hover only (EmptyMarkerState);
 25//                                               selected pinned to false;
 26//                                               returns true while hovered.
 27//
 28// Use the hover variant when the selectable row is the surface for a
 29// per-frame hover side-effect (e.g. "while hovering this cursor sample,
 30// set ImGui's mouse cursor to that style") and the toggle semantics of
 31// regular selectable would be incorrect.
 32//
 33// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/selectable_hover.das
 34// LIVE:       daslang-live modules/dasImgui/examples/tutorial/selectable_hover.das
 35// =============================================================================
 36
 37var private STATE_MESSAGE = "Hover any row."
 38var private SH_ROW : table<int; EmptyMarkerState>
 39
 40let private ROWS = fixed_array("Arrow", "TextInput", "ResizeAll", "Hand", "NotAllowed")
 41
 42[export]
 43def init() {
 44    live_create_window("dasImgui selectable_hover tutorial", 600, 380)
 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    SetNextWindowPos(ImVec2(40.0f, 40.0f), ImGuiCond.Always)
 60    SetNextWindowSize(ImVec2(520.0f, 300.0f), ImGuiCond.Always)
 61    window(SH_WIN, (text = "selectable_hover", closable = false,
 62                    flags = ImGuiWindowFlags.None)) {
 63        text("Hover a row - STATE_MESSAGE follows the highlighted item.")
 64        separator()
 65
 66        for (i in range(length(ROWS))) {
 67            let hovered = selectable_hover(SH_ROW[i], (text = "Row {i}: {ROWS[i]}"))
 68            if (hovered) {
 69                STATE_MESSAGE = "Hovering: {ROWS[i]}"
 70            }
 71        }
 72
 73        separator()
 74        text(SH_STATUS, (text = STATE_MESSAGE))
 75    }
 76
 77    end_of_frame()
 78    Render()
 79    var w, h : int
 80    live_get_framebuffer_size(w, h)
 81    glViewport(0, 0, w, h)
 82    glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
 83    glClear(GL_COLOR_BUFFER_BIT)
 84    live_imgui_render()
 85
 86    live_end_frame()
 87}
 88
 89[export]
 90def shutdown() {
 91    live_imgui_shutdown()
 92    live_destroy_window()
 93}
 94
 95[export]
 96def main() {
 97    init()
 98    while (!exit_requested()) {
 99        update()
100        maybe_collect_gc()
101    }
102    shutdown()
103}

8.19.37.1.1. Requires

Same baseline as selectableimgui/imgui_widgets_builtin, which every widget tutorial already requires.

8.19.37.1.2. When to reach for it

When the selectable row is a hover surface, not a toggle:

  • examples/imgui_demo/inputs.das — the Mouse Cursors list renders one selectable_hover row per ImGuiMouseCursor value and sets ImGui’s cursor while a row is hovered. Toggle semantics would be wrong (no persistent selection; the cursor follows hover frame-to-frame).

  • Per-row preview rails where hovering shows a tooltip / status pane and the click semantics don’t matter.

8.19.37.1.3. Toggle vs hover

  • selectable(IDENT, (text)) — returns bool changed, persists state.value (selected/unselected) across frames.

  • selectable_hover(IDENT, (text)) — returns bool hovered, no persistent selection state.

A site that needs both (click toggles, hover previews) should use the regular selectable and read IsItemHovered() after the call.

8.19.37.1.4. Standalone vs live

Same convention as the other widget tutorials.

See also

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

Integration test: modules/dasImgui/tests/test_selectable_hover.das.

Boost macros — the macro layer.