8.18.1.35. 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: modules/dasImgui/examples/tutorial/with_tab_stop.das.

8.18.1.35.1. Walkthrough

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

8.18.1.35.1.1. Requires

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

8.18.1.35.1.2. 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.

8.18.1.35.1.3. 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) { ... }.

8.18.1.35.1.4. 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: modules/dasImgui/examples/tutorial/with_tab_stop.das

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

Boost macros — the macro layer.