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_addr—safe_addr(global)for the pointer arg.imgui/imgui_containers_builtin—edit_tab_item+tab_bar.imgui/imgui_widgets_builtin—edit_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_itemand accept that only the X-close button can hide the tab.Use
edit_tab_itemwith 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 global —
safe_addr(g_open). Safest; verified at compile time.Array element —
unsafe(addr(arr[i])). Required becausesafe_addronly works on locally-scoped expressions, not computed addresses.Struct field —
unsafe(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.