8.19.50. edit_tab_item

Caller-owned visibility bool for a tab. The external-pointer sibling of tab_item (which owns visibility internally). The canonical “shared open state” pattern — a second UI surface (checkbox row, menu toggle, imgui_force_set) drives the same flag the tab’s X-close button writes.

var private g_tab_open : bool = true

edit_tab_item(safe_addr(g_tab_open), (id = "TAB_A",
                                      text = "alpha",
                                      flags = ImGuiTabItemFlags.None)) {
    text("alpha tab body")
}

When *p_open == false the tab is skipped entirely — no header chrome, no body. The X close button on the header writes *p_open = false automatically; you flip it back to true from any other UI surface to re-show the tab.

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

8.19.50.1. Walkthrough

The recording drives the bind end to end with real gestures. First it clicks the external show B checkbox and the beta tab vanishes outright - header and body both gone. Then it closes alpha with the X on its own tab header, and the show A checkbox flips itself off in response: the X and the checkbox write the very same bool. Finally it ticks both boxes back on and every tab returns. Each step is asserted - a checkbox that didn’t flip, a tab that didn’t hide, or an X that didn’t back-propagate would abort the recording.

  1options gen2
  2options _comment_hygiene = true
  3options gc
  4
  5require daslib/safe_addr
  6require imgui
  7require imgui_app
  8require opengl/opengl_boost
  9require live/glfw_live
 10require live/live_api
 11require live/live_commands
 12require live/live_vars
 13require live_host
 14require imgui/imgui_live
 15require imgui/imgui_boost_runtime
 16require imgui/imgui_boost_v2
 17require imgui/imgui_widgets_builtin
 18require imgui/imgui_containers_builtin
 19require imgui/imgui_visual_aids
 20
 21// =============================================================================
 22// TUTORIAL: edit_tab_item — caller-owned visibility bool for a tab.
 23//
 24//   edit_tab_item(safe_addr(open_bool), (id = "..", text = "..",        // bidir
 25//                                         flags = ...)) {                //   bind
 26//       <tab body>
 27//   }
 28//
 29// External-pointer sibling of `tab_item` (which owns visibility on its
 30// TabItemState). When `*p_open == false` the tab is skipped entirely
 31// (no header chrome, no body). The X close button on the header writes
 32// `*p_open = false` — bidir-bound.
 33//
 34// Use this when a SECOND UI surface (a checkbox row, a menu toggle,
 35// imgui_force_set on the external bool) needs to drive the same visibility
 36// flag the X writes. `tab_item`'s internal `state.open` isn't exposed
 37// for write outside the widget, so a shared external bool is the
 38// canonical pattern.
 39//
 40// All edit_* rails require an `id = "<literal>"` argument — that's the
 41// snapshot path. The first positional arg is the bool? pointer (passed
 42// via safe_addr for own globals, unsafe(addr(...)) for array elements
 43// or fields).
 44//
 45// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/edit_tab_item.das
 46// LIVE:       daslang-live modules/dasImgui/examples/tutorial/edit_tab_item.das
 47//
 48// DRIVE (when running live):
 49//   curl -X POST -d '{"name":"imgui_force_set","args":{"target":"ET_WIN/ET_BAR/ET_TAB_A","value":false}}' \
 50//        localhost:9090/command
 51// =============================================================================
 52
 53var private g_tab_a_open : bool = true
 54var private g_tab_b_open : bool = true
 55var private g_tab_c_open : bool = true
 56
 57[export]
 58def init() {
 59    live_create_window("dasImgui edit_tab_item tutorial", 760, 560)
 60    live_imgui_init(live_window)
 61    let io & = unsafe(GetIO())
 62    GetStyle().FontScaleMain = 1.4
 63}
 64
 65[export]
 66def update() {
 67    if (!live_begin_frame()) return
 68    begin_frame()
 69
 70    ImGui_ImplGlfw_NewFrame()
 71    apply_synth_io_override()
 72    NewFrame()
 73
 74    SetNextWindowPos(ImVec2(20.0f, 20.0f), ImGuiCond.Always)
 75    SetNextWindowSize(ImVec2(720.0f, 520.0f), ImGuiCond.Always)
 76    window(ET_WIN, (text = "edit_tab_item tutorial", closable = false,
 77                    flags = ImGuiWindowFlags.None)) {
 78
 79        text("Caller-owned visibility bool - the X button on each tab writes it.")
 80        text(ET_HINT, (text = "Checkboxes below also drive the SAME bools. Bidir-bound on g_tab_*_open."))
 81        separator()
 82
 83        // ---- External controls — second UI surface driving the same bools ----
 84        text("External controls (mirror the X-button state):")
 85        edit_checkbox(safe_addr(g_tab_a_open), (id = "ET_CHECK_A", text = "show A"))
 86        same_line(ET_SL1)
 87        edit_checkbox(safe_addr(g_tab_b_open), (id = "ET_CHECK_B", text = "show B"))
 88        same_line(ET_SL2)
 89        edit_checkbox(safe_addr(g_tab_c_open), (id = "ET_CHECK_C", text = "show C"))
 90        spacing()
 91        separator()
 92
 93        // ---- The tab bar — three edit_tab_item instances ----
 94        tab_bar(ET_BAR, (text = "MyBar",
 95                          flags = ImGuiTabBarFlags.FittingPolicyShrink)) {
 96            edit_tab_item(safe_addr(g_tab_a_open),
 97                          (id = "ET_TAB_A", text = "alpha",
 98                           flags = ImGuiTabItemFlags.None)) {
 99                text(ET_BODY_A, (text = "alpha tab body - close me with the X."))
100            }
101            edit_tab_item(safe_addr(g_tab_b_open),
102                          (id = "ET_TAB_B", text = "beta",
103                           flags = ImGuiTabItemFlags.None)) {
104                text(ET_BODY_B, (text = "beta tab body - close me with the X."))
105            }
106            edit_tab_item(safe_addr(g_tab_c_open),
107                          (id = "ET_TAB_C", text = "gamma",
108                           flags = ImGuiTabItemFlags.None)) {
109                text(ET_BODY_C, (text = "gamma tab body - close me with the X."))
110            }
111        }
112        spacing()
113        text("g_tab_a_open = {g_tab_a_open}, g_tab_b_open = {g_tab_b_open}, g_tab_c_open = {g_tab_c_open}")
114    }
115
116    end_of_frame()
117    Render()
118    var w, h : int
119    live_get_framebuffer_size(w, h)
120    glViewport(0, 0, w, h)
121    glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
122    glClear(GL_COLOR_BUFFER_BIT)
123    live_imgui_render()
124
125    live_end_frame()
126}
127
128[export]
129def shutdown() {
130    live_imgui_shutdown()
131    live_destroy_window()
132}
133
134[export]
135def main() {
136    init()
137    while (!exit_requested()) {
138        update()
139        maybe_collect_gc()
140    }
141    shutdown()
142}

8.19.50.1.1. Requires

  • daslib/safe_addrsafe_addr(global) for the pointer arg.

  • imgui/imgui_containers_builtinedit_tab_item + tab_bar.

  • imgui/imgui_widgets_builtinedit_checkbox (for the external controls), text.

8.19.50.1.2. Why edit_tab_item over tab_item

tab_item (container) owns its open state internally on TabItemState.open. That field is read-only from outside the widget — there’s no public channel to flip it. So if you need a SECOND UI surface to drive the same visibility, you have to choose:

  • Use tab_item and accept that only the X-close button can hide the tab.

  • Use edit_tab_item with a shared external bool — both the X button AND your other UI write the same value.

The recording shows the second case: a row of checkboxes mirrors the state of three tabs. Clicking a checkbox hides the tab; clicking the tab’s X writes the bool, which back-propagates to the checkbox the next frame.

8.19.50.1.3. The id arg

All edit_* rails require an id = "<literal>" argument — that’s the snapshot path segment. Unlike the IDENT of state-owned widgets (which the [widget] macro promotes from a bare identifier to a string), the id here is a regular string literal you pass inline. Snapshot probes use it the same way:

curl -X POST -d '{"name":"imgui_snapshot"}' localhost:9090/command \
    | jq '.globals."ET_WIN/ET_BAR/ET_TAB_A"'

8.19.50.1.4. The pointer arg

The first positional arg is var p_open : bool? — a daslang pointer to a bool. How you get the pointer depends on where the bool lives:

  • Module-scope globalsafe_addr(g_open). Safest; verified at compile time.

  • Array elementunsafe(addr(arr[i])). Required because safe_addr only works on locally-scoped expressions, not computed addresses.

  • Struct fieldunsafe(addr(my_struct.field)). Same reason.

The recording uses safe_addr on three module globals (g_tab_a_open / b / c).

8.19.50.1.5. Driving from outside

imgui_force_set writes the external bool through edit_checkbox’s channel (which shares the bool with the tab):

# Hide alpha tab:
curl -X POST -d '{"name":"imgui_force_set","args":{"target":"ET_WIN/ET_CHECK_A","value":false}}' \
     localhost:9090/command

The X-button click on the tab header writes the same bool — symmetric.

See also

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

Internal-state sibling: Tab bar (covers tab_item + tab_item_button).

External-binding tour: External-pointer editing rail — every edit_* rail in one window.

Boost macros — the macro layer.