Group
group brackets BeginGroup/EndGroup — a pure layout container
with no chrome, no flags, and no observable state. What it does is
combine its children into a single layout unit so that:
same_line after the closing brace continues from the group’s right edge, not the last widget’s. Two stacked column blocks share a row by sandwiching
same_line()between two groups.IsItemHovered /
IsItemActive/GetItemRect*after the group report against the combined bbox of every widget inside. Lets a tooltip attach to “anywhere in the icon-plus-label cluster” with no manual rectangle math.
GroupState is empty. The path push still happens, so widgets inside
group(LEFT_GRP) register under <window>/LEFT_GRP/<leaf>.
Source: examples/tutorial/group.das.
Walkthrough
The recording walks the three patterns. First it toggles a checkbox in each of
the two side-by-side blocks — both stay live while same_line keeps them on
one row. Then it hovers the middle of the [i] Info cluster, not the button,
and the tooltip still fires — proof that IsItemHovered after EndGroup
reads against the whole group’s bounding box. Finally it drags the row’s slider
and the value updates on the line below. Every step is a real synth gesture the
recording asserts landed.
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: group — BeginGroup/EndGroup pure layout grouping.
20//
21// group(IDENT) { body }
22//
23// Treats several widgets as a single layout unit. Two effects:
24//
25// 1. Same-line stacking — same_line() after the group's closing brace
26// continues from the group's right edge, not the last widget's. Useful
27// for laying out (label-block | value-block | edit-block) rows.
28//
29// 2. Hit-test the whole group — IsItemHovered() / IsItemActive() called
30// after EndGroup() report against the group's combined bbox. Lets a
31// tooltip attach to "anywhere inside the icon-plus-label cluster".
32//
33// GroupState is empty — no flags, no observables. Pure structural marker.
34// The path push still happens, so a checkbox inside group(LEFT_GRP) is
35// reachable at GRP_WIN/LEFT_GRP/L_WIRE.
36//
37// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/group.das
38// LIVE: daslang-live modules/dasImgui/examples/tutorial/group.das
39// =============================================================================
40
41[export]
42def init() {
43 live_create_window("dasImgui group tutorial", 720, 480)
44 live_imgui_init(live_window)
45 let io & = unsafe(GetIO())
46 GetStyle().FontScaleMain = 1.4
47}
48
49[export]
50def update() {
51 if (!live_begin_frame()) return
52 begin_frame()
53
54 ImGui_ImplGlfw_NewFrame()
55 apply_synth_io_override()
56 NewFrame()
57
58 SetNextWindowPos(ImVec2(20.0f, 20.0f), ImGuiCond.Always)
59 SetNextWindowSize(ImVec2(680.0f, 440.0f), ImGuiCond.Always)
60 window(GRP_WIN, (text = "group tutorial", closable = false,
61 flags = ImGuiWindowFlags.None)) {
62
63 text("group(IDENT) takes a block and treats its widgets as one layout unit.")
64 separator()
65
66 // ---- A: two side-by-side groups via same_line ----
67 text("A) Two groups + same_line: each block stacks vertically; same_line")
68 text(" between them keeps the right block's top aligned with the left.")
69 group(LEFT_GRP) {
70 text("Left block")
71 checkbox(L_WIRE, (text = "Wireframe"))
72 checkbox(L_GRID, (text = "Show grid"))
73 // Narrow the slider so LEFT_GRP leaves enough room for RIGHT_GRP
74 // on the same row at FontGlobalScale 1.4 + 680 px content width.
75 SetNextItemWidth(160.0f)
76 slider_int(L_FRAMES, (text = "frame limit"))
77 }
78 same_line((spacing = 24.0f))
79 group(RIGHT_GRP) {
80 text("Right block")
81 checkbox(R_VSYNC, (text = "VSync"))
82 checkbox(R_FULL, (text = "Fullscreen"))
83 small_button(R_APPLY, (text = "Apply"))
84 }
85 separator()
86
87 // ---- B: group as a tooltip hit-test surface ----
88 text("B) Hit-test a whole cluster - hover anywhere in the row below.")
89 group(HOVER_GRP) {
90 text("[i] Info")
91 same_line()
92 text("hover me anywhere in this row")
93 same_line()
94 small_button(HOVER_BTN, (text = "Action"))
95 }
96 if (IsItemHovered(ImGuiHoveredFlags.None)) {
97 tooltip(GRP_TIP) {
98 text("BeginTooltip while the whole group is hovered.")
99 text("IsItemHovered() after EndGroup() reports against the combined bbox.")
100 }
101 }
102 separator()
103
104 // ---- C: group used as a "row" with right-aligned status ----
105 text("C) The (label | value | button) row pattern.")
106 group(ROW_GRP) {
107 text("Speed:")
108 same_line()
109 slider_float(ROW_SPEED, (text = "##speed"))
110 same_line()
111 small_button(ROW_RESET, (text = "Reset"))
112 }
113 text("ROW_SPEED.value = {ROW_SPEED.value}")
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 }
140 shutdown()
141}
Requires
Already in the baseline boost layer:
imgui/imgui_containers_builtin—groupplustooltip,same_line,separator.imgui/imgui_widgets_builtin— leaves used inside the group.
Two columns via same_line
The classic use: stack two column blocks side by side without manually computing column widths.
group(LEFT_GRP) {
text("Left block")
checkbox(L_WIRE, (text = "Wireframe"))
// Narrow the slider so the left group leaves room for the
// right group on the same row.
SetNextItemWidth(160.0f)
slider_int(L_FRAMES, (text = "frame limit"))
}
same_line((spacing = 24.0f))
group(RIGHT_GRP) {
text("Right block")
checkbox(R_VSYNC, (text = "VSync"))
small_button(R_APPLY, (text = "Apply"))
}
Without the groups, same_line would only join the previous widget
(the slider) to the next, leaving the rest of the right block to
overlap. The group treats four widgets as one item for same_line’s
“continue from the right edge” semantics.
Hit-testing a cluster
IsItemHovered after EndGroup applies to the whole group’s bbox.
The tutorial uses it to gate a manual tooltip:
group(HOVER_GRP) {
text("[i] Info")
same_line()
text("hover me anywhere in this row")
same_line()
small_button(HOVER_BTN, (text = "Action"))
}
if (IsItemHovered(ImGuiHoveredFlags.None)) {
tooltip(GRP_TIP) {
text("BeginTooltip while the whole group is hovered.")
}
}
Hovering the icon, the label, the button — any of them — fires the
tooltip. No need for IsItemHovered on each child or for Set...
rectangle hacks. The group’s bbox subsumes everything.
Note that HOVER_BTN is still independently clickable. Group hit-test
reads over the cluster but does NOT block child events.
Why no flags?
ImGui’s BeginGroup/EndGroup take no parameters. The wrapper’s
only argument is the IDENT. GroupState carries an
@optional _placeholder field so the [container] auto-emitter
has something to serialize — the field is unused and the JV payload
is {}.
Standalone vs live
Same convention as the other tutorials.
Driving from outside
The group itself isn’t open/close-driveable (nothing to open). Its children are reachable at the composed path:
curl -X POST -d '{"name":"imgui_force_set","args":{"target":"GRP_WIN/ROW_GRP/ROW_SPEED","value":0.75}}' \
localhost:9090/command
curl -X POST -d '{"name":"imgui_click","args":{"target":"GRP_WIN/ROW_GRP/ROW_RESET"}}' \
localhost:9090/command
See also
Full source: examples/tutorial/group.das
Features-side demo: examples/features/containers_window.das — uses
group alongside child to lay out a window’s right pane.
Sibling: Containers — umbrella container tour.
Boost macros — the macro layer.