With tab stop

ImGui’s PushTabStop / PopTabStop pair lets you control which widgets participate in TAB / Shift+TAB focus cycling. The boost layer wraps it as a stateless scope wrapper:

with_tab_stop(false) {
    input_text(TS_FIELD_SKIP, (text = "Skipped by TAB", init = "..."))
}

The wrapper itself emits no telemetry — it only pushes the tab-stop flag on entry and pops it on exit, matching the rest of the with_* family (with_indent, with_disabled, with_button_repeat, with_font, with_clip_rect).

Source: examples/tutorial/with_tab_stop.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_scope_builtin
17require imgui/imgui_visual_aids
18
19// =============================================================================
20// TUTORIAL: with_tab_stop — stateless scope wrapper around PushTabStop /
21//           PopTabStop. While the wrapped block is active, every widget
22//           inside is skipped by TAB / Shift+Tab focus cycling. Useful for
23//           help markers or decorative inputs that shouldn't steal keyboard
24//           focus when navigating an editable form.
25//
26//   with_tab_stop(false) { widgets_to_skip... }
27//
28// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/with_tab_stop.das
29// LIVE:       daslang-live modules/dasImgui/examples/tutorial/with_tab_stop.das
30// =============================================================================
31
32[export]
33def init() {
34    live_create_window("dasImgui with_tab_stop tutorial", 760, 460)
35    live_imgui_init(live_window)
36    let io & = unsafe(GetIO())
37    GetStyle().FontScaleMain = 1.4
38}
39
40[export]
41def update() {
42    if (!live_begin_frame()) return
43    begin_frame()
44
45    ImGui_ImplGlfw_NewFrame()
46    apply_synth_io_override()
47    NewFrame()
48
49    SetNextWindowPos(ImVec2(40.0f, 40.0f), ImGuiCond.Always)
50    SetNextWindowSize(ImVec2(720.0f, 400.0f), ImGuiCond.Always)
51    window(TS_WIN, (text = "with_tab_stop", closable = false,
52                    flags = ImGuiWindowFlags.None)) {
53        text("Press TAB / Shift+TAB to cycle focus.")
54        text("The middle field is wrapped in with_tab_stop(false) - TAB skips it.")
55        separator()
56
57        input_text(TS_FIELD_A, (text = "Field A"))
58        input_text(TS_FIELD_B, (text = "Field B"))
59
60        with_tab_stop(false) {
61            input_text(TS_FIELD_SKIP,
62                (text = "Skipped by TAB", init = "(unreachable via keyboard)"))
63        }
64
65        input_text(TS_FIELD_C, (text = "Field C"))
66        input_text(TS_FIELD_D, (text = "Field D"))
67    }
68
69    end_of_frame()
70    Render()
71    var w, h : int
72    live_get_framebuffer_size(w, h)
73    glViewport(0, 0, w, h)
74    glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
75    glClear(GL_COLOR_BUFFER_BIT)
76    live_imgui_render()
77
78    live_end_frame()
79}
80
81[export]
82def shutdown() {
83    live_imgui_shutdown()
84    live_destroy_window()
85}
86
87[export]
88def main() {
89    init()
90    while (!exit_requested()) {
91        update()
92    }
93    shutdown()
94}

Requires

Same baseline as the other with_* wrappers — already in imgui/imgui_scope_builtin (re-exported by imgui/imgui_boost_v2).

Behaviour

While the wrapped block is active, every focusable widget inside has its ImGui tab-stop flag suppressed:

  • TAB and Shift+TAB cycling skip past those widgets.

  • Mouse click still focuses the widget (tab-stop is keyboard-only).

  • Programmatic focus (SetKeyboardFocusHere) still works.

The flag scope follows the block exactly: as soon as the wrapped block exits, the previous tab-stop policy is restored, so wrapping a help-marker or decorative input inside with_tab_stop(false) doesn’t leak the suppression onto sibling widgets.

When to reach for it

The two recurring shapes:

  • Help markers / tooltips — a (?) glyph that opens an info popup on hover but shouldn’t intercept TAB navigation through the editable form.

  • Decorative inputs — a read-only field that displays computed state next to editable siblings; keyboard navigation should skip past it entirely.

The same pattern is used in examples/imgui_demo/inputs.das — both the Tabbing and Focus-from-code sub-sections wrap their “(tab skip)” field + help marker in with_tab_stop(false) { ... }.

Standalone vs live

Same convention as the other scope-wrapper tutorials. daslang.exe runs the demo headlessly to frame N; daslang-live keeps the window open and reloads on source edits.

See also

Full source: examples/tutorial/with_tab_stop.das

Integration test: tests/integration/test_with_tab_stop.das.

Boost macros — the macro layer.