Main menu bar
Two related v2 additions live together in this tutorial. The first is
main_menu_bar(IDENT) { ... } — the screen-top bar (BeginMainMenuBar
/ EndMainMenuBar), distinct from menu_bar(IDENT) { ... } which
attaches to the current window (BeginMenuBar, requires
ImGuiWindowFlags.MenuBar). The second is the
menu_item / menu_label split for the leaves under a menu:
menu_item(IDENT, (text=, shortcut=, enabled=))— toggleable.ToggleState.valueflips on click.menu_label(IDENT, (text=, shortcut=, selected=, enabled=))— static.ClickState.click_countaccumulates;selectedis a fixed check-mark (not driven by the click).
menu_label is the right rail for section headers
(selected=false, enabled=false), permanent-check labels
(selected=true), and any “do something, don’t toggle” menu entry.
main_menu_bar(MAIN_BAR) {
menu(FILE_MENU, (text = "File", enabled = true)) {
menu_item(MI_DARKMODE, (text = "Dark mode", shortcut = "Ctrl+D"))
menu_item(MI_AUTOSAVE, (text = "Auto-save", shortcut = ""))
separator(FILE_SEP)
menu_label(FILE_HEADER, (text = "(recent files)",
shortcut = "", selected = false,
enabled = false))
menu_label(FILE_RECENT1, (text = "demo.das"))
menu_label(FILE_STAR, (text = "Star this project",
shortcut = "", selected = true))
}
}
Source: examples/tutorial/main_menu_bar.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_visual_aids
17
18// =============================================================================
19// TUTORIAL: main_menu_bar — top-level menu bar + menu_item vs menu_label split.
20//
21// Two related v2 additions live in this tutorial:
22//
23// 1. `main_menu_bar(IDENT) { ... }` is the screen-top bar (`BeginMainMenuBar`)
24// — distinct from `menu_bar(IDENT) { ... }` which attaches to the current
25// window (`BeginMenuBar`, requires `ImGuiWindowFlags.MenuBar`).
26//
27// 2. `menu_item` vs `menu_label`:
28// - menu_item(IDENT, (text=, shortcut=, enabled=)) → toggleable.
29// ToggleState.value mutates on click.
30// - menu_label(IDENT, (text=, shortcut=, selected=, enabled=)) → static.
31// ClickState.click_count accumulates; `selected` is a fixed check-mark.
32//
33// Use menu_label for section headers (`selected=false, enabled=false`),
34// permanent-check labels (`selected=true`), and any "do something, don't
35// toggle" menu entry.
36//
37// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/main_menu_bar.das
38// LIVE: daslang-live modules/dasImgui/examples/tutorial/main_menu_bar.das
39//
40// DRIVE (when running live):
41// curl -X POST -d '{"name":"imgui_click","args":{"target":"MAIN_BAR/FILE_MENU/MI_DARKMODE"}}' \
42// localhost:9090/command
43// =============================================================================
44
45[export]
46def init() {
47 live_create_window("dasImgui main_menu_bar tutorial", 800, 480)
48 live_imgui_init(live_window)
49 let io & = unsafe(GetIO())
50 GetStyle().FontScaleMain = 1.4
51}
52
53[export]
54def update() {
55 if (!live_begin_frame()) return
56 begin_frame()
57
58 ImGui_ImplGlfw_NewFrame()
59 apply_synth_io_override()
60 NewFrame()
61
62 // The bar sits at screen top, NOT inside any window().
63 main_menu_bar(MAIN_BAR) {
64 menu(FILE_MENU, (text = "File", enabled = true)) {
65 // Toggleable — clicking flips MI_DARKMODE.value.
66 menu_item(MI_DARKMODE, (text = "Dark mode", shortcut = "Ctrl+D"))
67 menu_item(MI_AUTOSAVE, (text = "Auto-save", shortcut = ""))
68 separator(FILE_SEP)
69 // Section header — static, disabled, no check.
70 menu_label(FILE_HEADER, (text = "(recent files)",
71 shortcut = "", selected = false,
72 enabled = false))
73 menu_label(FILE_RECENT1, (text = "demo.das"))
74 menu_label(FILE_RECENT2, (text = "tour.das"))
75 separator(FILE_SEP2)
76 // Permanent check — selected=true makes it always-checked.
77 menu_label(FILE_STAR, (text = "Star this project",
78 shortcut = "", selected = true))
79 menu_item(MI_QUIT, (text = "Quit", shortcut = "Ctrl+Q"))
80 }
81 menu(EDIT_MENU, (text = "Edit", enabled = true)) {
82 // menu_label for an action — emits click_count, no toggle.
83 menu_label(EDIT_UNDO, (text = "Undo", shortcut = "Ctrl+Z"))
84 menu_label(EDIT_REDO, (text = "Redo", shortcut = "Ctrl+Y",
85 selected = false, enabled = false))
86 }
87 }
88
89 SetNextWindowPos(ImVec2(60.0, 80.0), ImGuiCond.Always)
90 SetNextWindowSize(ImVec2(680.0, 320.0), ImGuiCond.Always)
91 window(BODY, (text = "State readout", closable = false,
92 flags = ImGuiWindowFlags.None)) {
93 text("Click items in the bar above; the snapshot updates below.")
94 separator(BODY_SEP)
95 text("MI_DARKMODE.value = {MI_DARKMODE.value}")
96 text("MI_AUTOSAVE.value = {MI_AUTOSAVE.value}")
97 text("EDIT_UNDO.click_count = {EDIT_UNDO.click_count}")
98 text("MI_QUIT.value = {MI_QUIT.value}")
99 }
100
101 end_of_frame()
102 Render()
103 var w, h : int
104 live_get_framebuffer_size(w, h)
105 glViewport(0, 0, w, h)
106 glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
107 glClear(GL_COLOR_BUFFER_BIT)
108 live_imgui_render()
109
110 live_end_frame()
111}
112
113[export]
114def shutdown() {
115 live_imgui_shutdown()
116 live_destroy_window()
117}
118
119[export]
120def main() {
121 init()
122 while (!exit_requested()) {
123 update()
124 }
125 shutdown()
126}
Requires
Baseline boost layer (imgui/imgui_boost_v2 re-exports
imgui/imgui_containers_builtin). No extra modules.
main_menu_bar vs menu_bar
The two bar variants pick opposite anchor strategies:
main_menu_bar(IDENT) { ... }attaches to the viewport — sits at the top of the screen, persists across windows, ImGui draws the chrome. Use it when there’s exactly one bar in the app.menu_bar(IDENT) { ... }attaches to the current window — appears inside that window’s titlebar area. The host window must haveImGuiWindowFlags.MenuBarset, or the menu_bar render is a no-op. Use it for per-document menus inside a tabbed editor, the imgui_demo’s own menu bar, or any window-local command surface.
Both expose the same menu() / menu_item / menu_label children;
only the anchor differs.
menu_item vs menu_label
menu_item and menu_label look identical visually (text + optional
shortcut + optional check-mark) but back different state structs:
menu_itemcarriesToggleState— thevaluebool flips on every click. Use it for boolean app-state toggles (“Dark mode”, “Auto-save”, “Show hidden files”).menu_labelcarriesClickState— theclick_countint accumulates without touchingselected. Use it for actions (“Undo”, “Quit”, “About”) and for static labels with a fixed check (selected=true) or no check at all.
Combine selected= and enabled= on menu_label to get section
headers (selected=false, enabled=false greys the entry and shows no
check) or permanent-check items (selected=true, enabled=true shows
the check and stays clickable).
Driving from outside
The full menu hierarchy is routable once a menu is open:
curl -X POST -d '{"name":"imgui_click","args":{"target":"MAIN_BAR/FILE_MENU/MI_DARKMODE"}}' \
localhost:9090/command
The bar’s own header (MAIN_BAR) has a degenerate bbox (the chrome has
no clickable “header”). The first-level menu() children
(MAIN_BAR/FILE_MENU, MAIN_BAR/EDIT_MENU) DO register routable
headers. Submenu items only register a bbox while their parent menu is
open, so external drivers wanting to click a menu_item have to open the
parent first (synth click on the header, wait one frame, then click the
child). The walkthrough above does exactly this with real clicks, dropping
straight DOWN the open menu’s column onto each item: a diagonal travel to an
item that sits off-axis from its header would clip a sibling header, and
ImGui hover-switches the open menu mid-travel (the click then lands in the
wrong menu). Menu items span the full menu width, so a vertical drop at the
header’s center-x always lands on the item.
Snapshot shape
MI_DARKMODE.value is the live toggle bool; EDIT_UNDO.click_count
is the accumulating action counter. Both surface in the snapshot under
their qualified path:
curl -X POST -d '{"name":"imgui_snapshot"}' localhost:9090/command \
| jq '.globals."MAIN_BAR/FILE_MENU/MI_DARKMODE".payload'
The tutorial’s body window prints both per-frame so the state changes are visible alongside the menu interactions.
See also
Full source: examples/tutorial/main_menu_bar.das
Integration tests: tests/integration/test_menu_main.das and tests/integration/test_menu_label_static.das.
Boost macros — the macro layer.