8.18.1.39. Drag widgets
The drag family is click-and-scrub numeric editing: press inside the
widget, drag horizontally, release. The value tracks pixel movement
scaled by speed. Same call shape spans scalar / vector / range and
float / int — one mental model, ten widgets.
drag_float(IDENT, (text = "..", speed = 0.01f, format = "%.3f",
flags = ImGuiSliderFlags....))
drag_int(IDENT, (text = "..", speed = 1.0f, format = "%d"))
drag_float2 / drag_float3 / drag_float4 // vector forms
drag_int2 / drag_int3 / drag_int4
drag_float_range2(IDENT, (text, speed, format)) // paired lo / hi handles
drag_int_range2(IDENT, (text, speed, format))
Bounds live on the state struct (IDENT.bounds = (lo, hi)), set once
per frame from app code. Zero-init = unclamped — scrub goes anywhere.
Source: modules/dasImgui/examples/tutorial/drag.das.
8.18.1.39.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_visual_aids
18
19// =============================================================================
20// TUTORIAL: drag widgets — click-and-scrub numeric editing.
21//
22// drag_float(IDENT, (text = "..", speed = 0.01f, format = "%.3f",
23// flags = ImGuiSliderFlags....))
24// drag_int / drag_float2/3/4 / drag_int2/3/4 / drag_float_range2 /
25// drag_int_range2 — same shape; scalar / vector / range variants.
26//
27// Bounds live on the state struct (`IDENT.bounds = (lo, hi)`), set once per
28// frame from app code. Zero-init = unclamped (drag scrubs to any value).
29// `speed` is units-per-pixel of horizontal drag; `format` is the printf-style
30// label format.
31//
32// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/drag.das
33// LIVE: daslang-live modules/dasImgui/examples/tutorial/drag.das
34//
35// DRIVE (when running live):
36// # Set scalar value directly:
37// curl -X POST -d '{"name":"imgui_force_set","args":{"target":"DRAG_WIN/D_FLOAT","value":0.75}}' \
38// localhost:9090/command
39// # Set vector value (one number per component):
40// curl -X POST -d '{"name":"imgui_force_set","args":{"target":"DRAG_WIN/D_VEC3","value":[1.0,2.0,3.0]}}' \
41// localhost:9090/command
42// # Set range (lo, hi):
43// curl -X POST -d '{"name":"imgui_force_set","args":{"target":"DRAG_WIN/D_RANGE","value":[10.0,40.0]}}' \
44// localhost:9090/command
45// =============================================================================
46
47[export]
48def init() {
49 live_create_window("dasImgui drag tutorial", 760, 520)
50 live_imgui_init(live_window)
51 let io & = unsafe(GetIO())
52 GetStyle().FontScaleMain = 1.4
53}
54
55[export]
56def update() {
57 if (!live_begin_frame()) return
58 begin_frame()
59
60 ImGui_ImplGlfw_NewFrame()
61 apply_synth_io_override()
62 NewFrame()
63
64 SetNextWindowPos(ImVec2(20.0f, 20.0f), ImGuiCond.Always)
65 SetNextWindowSize(ImVec2(720.0f, 480.0f), ImGuiCond.Always)
66 window(DRAG_WIN, (text = "drag tutorial", closable = false,
67 flags = ImGuiWindowFlags.None)) {
68
69 text("Click and drag horizontally to scrub the value.")
70 text(D_HINT, (text = "Bounds set via IDENT.bounds = (lo, hi). Zero-init = unclamped."))
71 separator()
72
73 // ---- Stage 1: scalar float, clamped 0..1 ----
74 D_FLOAT.bounds = (0.0f, 1.0f)
75 drag_float(D_FLOAT, (text = "opacity", speed = 0.005f, format = "%.3f"))
76 text("D_FLOAT.value = {D_FLOAT.value}")
77 spacing()
78
79 // ---- Stage 2: scalar int ----
80 D_INT.bounds = (0, 100)
81 drag_int(D_INT, (text = "score", speed = 1.0f, format = "%d"))
82 text("D_INT.value = {D_INT.value}")
83 spacing()
84
85 // ---- Stage 3: vector — three components on one row ----
86 D_VEC3.bounds = (-10.0f, 10.0f)
87 drag_float3(D_VEC3, (text = "position", speed = 0.05f, format = "%.2f"))
88 text("D_VEC3.value = ({D_VEC3.value.x}, {D_VEC3.value.y}, {D_VEC3.value.z})")
89 spacing()
90
91 // ---- Stage 4: range — paired min/max scrubbing, lo <= hi enforced ----
92 D_RANGE.bounds = (0.0f, 100.0f)
93 drag_float_range2(D_RANGE, (text = "band", speed = 0.5f, format = "%.1f"))
94 text("D_RANGE.value = [{D_RANGE.value.x}, {D_RANGE.value.y}]")
95 }
96
97 end_of_frame()
98 Render()
99 var w, h : int
100 live_get_framebuffer_size(w, h)
101 glViewport(0, 0, w, h)
102 glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
103 glClear(GL_COLOR_BUFFER_BIT)
104 live_imgui_render()
105
106 live_end_frame()
107}
108
109[export]
110def shutdown() {
111 live_imgui_shutdown()
112 live_destroy_window()
113}
114
115[export]
116def main() {
117 init()
118 while (!exit_requested()) {
119 update()
120 }
121 shutdown()
122}
8.18.1.39.1.1. Requires
Already in the baseline boost layer:
imgui/imgui_widgets_builtin— everydrag_*rail.imgui/imgui_boost_runtime—DragStateFloat/DragStateInt/DragStateFloat3/DragStateRangeFloatstate structs.
8.18.1.39.1.2. Speed and format
speed is units-per-pixel of horizontal cursor movement:
drag_float(OPACITY, (text = "opacity", speed = 0.005f)) // 0.005 / px → 200 px = 1.0
drag_int(SCORE, (text = "score", speed = 1.0f)) // 1 / px → ImGui clamps to int
format is the printf-style label format. The default "%.3f" /
"%d" covers most cases; bump to "%.6f" for fine-grained float
values or "%+04d" for signed-padded ints.
8.18.1.39.1.3. Bounds
Bounds are a property of the state, not the call:
D_FLOAT.bounds = (0.0f, 1.0f)
drag_float(D_FLOAT, (text = "opacity", speed = 0.005f))
Set them every frame (idempotent assignment, no branching needed). The
wrapper passes (min, max) to ImGui’s DragFloat which clamps the
scrub. Zero-initialized bounds = (0, 0) = special-cased to mean
unclamped.
8.18.1.39.1.4. Vector forms
The 2 / 3 / 4 suffix puts that many components on one row,
each its own drag handle. state.value becomes float2 / float3
/ float4 (or int2 / int3 / int4):
D_VEC3.bounds = (-10.0f, 10.0f) // applies to every component
drag_float3(D_VEC3, (text = "position", speed = 0.05f))
// D_VEC3.value.x, D_VEC3.value.y, D_VEC3.value.z
8.18.1.39.1.5. Range forms
drag_float_range2 / drag_int_range2 render two handles sharing
one bar — useful for “filter between lo and hi” widgets:
D_RANGE.bounds = (0.0f, 100.0f)
drag_float_range2(D_RANGE, (text = "band", speed = 0.5f))
// D_RANGE.value.x = lo, D_RANGE.value.y = hi (ImGui enforces lo <= hi)
8.18.1.39.1.6. Driving from outside
Every drag widget exposes the same telemetry channel — imgui_force_set
writes state.pending_value which the next frame consumes:
# Scalar:
curl -X POST -d '{"name":"imgui_force_set","args":{"target":"DRAG_WIN/D_FLOAT","value":0.75}}' \
localhost:9090/command
# Vector — one number per component:
curl -X POST -d '{"name":"imgui_force_set","args":{"target":"DRAG_WIN/D_VEC3","value":[1.0,2.0,3.0]}}' \
localhost:9090/command
# Range — (lo, hi) tuple:
curl -X POST -d '{"name":"imgui_force_set","args":{"target":"DRAG_WIN/D_RANGE","value":[10.0,40.0]}}' \
localhost:9090/command
The dispatcher ([widget_dispatch] on the state struct) accepts the
right JSON shape per state type — scalar number, array of numbers, or
two-element array for ranges.
8.18.1.39.1.7. Drag vs slider vs input
The three numeric-edit families differ in interaction shape:
drag — click and scrub, no fixed track. Best for “tweak this value” where the absolute range is large or open-ended.
slider — click and drag along a fixed-width track between
v_min/v_max. Best for bounded percentages, settings sliders.input — type the number, optionally with
+/-step buttons. Best for precise values where the user knows the number.
All three families share the same vector / scalar / format conventions. See Slider widgets.
8.18.1.39.1.8. Caller-owned variant
For sites where the value lives on an external scalar (not a widget
state struct), use the edit_drag_* rail instead — it takes a
T? pointer via safe_addr and skips the state-struct allocation:
var g_opacity : float = 0.5f
edit_drag_float(safe_addr(g_opacity), (id = "OPACITY",
text = "opacity", speed = 0.005f))
See External-pointer editing rail.
See also
Full source: modules/dasImgui/examples/tutorial/drag.das
Features-side demo: modules/dasImgui/examples/features/inputs_drag.das — every drag
widget in one window, useful for imgui_force_set smoke testing.
Sibling tutorial: Slider widgets.
Boost macros — the macro layer.