8.18.1.42. Input text widgets
The input_text family is text editing — single-line, multiline,
grow-on-overflow, callback-driven, and the inline filter editor. Six
widgets, one InputTextState (text_filter uses its own
TextFilterState).
input_text(IDENT, (text = "..", flags = ImGuiInputTextFlags....))
input_text_with_hint(IDENT, (text, hint, flags))
input_text_multiline(IDENT, (text, size = float2(w, h), flags))
input_text_growable(IDENT, (text, flags)) // CallbackResize plumbed
input_text_callback(IDENT, text, flags, cb) // user lambda on flagged events
text_filter(IDENT, (text, width)) + passes_filter(IDENT, line)
Buffer-as-pointer path: state owns array<uint8> buffer + a string
mirror. input_text_growable plumbs ImGui’s CallbackResize through
a daslang lambda + stack thunk so the buffer expands past
state.capacity automatically.
Source: modules/dasImgui/examples/tutorial/input_text.das.
8.18.1.42.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
18require strings
19
20// =============================================================================
21// TUTORIAL: input_text family — text editing widgets.
22//
23// input_text(IDENT, (text = "..", flags = ImGuiInputTextFlags....))
24// input_text_with_hint(IDENT, (text, hint, flags))
25// input_text_multiline(IDENT, (text, size = float2(w, h), flags))
26// input_text_growable(IDENT, (text, flags)) — auto-grows buffer
27// input_text_callback(IDENT, text, flags, cb) — user callback
28// text_filter(IDENT, (text, width)) + passes_filter(IDENT, line)
29//
30// Six widgets, six modalities sharing one InputTextState struct (text_filter
31// uses TextFilterState — different shape, integrates with the family).
32//
33// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/input_text.das
34// LIVE: daslang-live modules/dasImgui/examples/tutorial/input_text.das
35//
36// DRIVE (when running live):
37// curl -X POST -d '{"name":"imgui_force_set","args":{"target":"IT_WIN/IT_NAME","value":"hello"}}' \
38// localhost:9090/command
39// curl -X POST -d '{"name":"imgui_force_set","args":{"target":"IT_WIN/IT_BIO","value":"line1\nline2"}}' \
40// localhost:9090/command
41// =============================================================================
42
43let private COMMANDS <- ["help", "history", "clear", "classify", "echo", "exit"]
44
45let private LOG_LINES <- [
46 "[info] startup complete",
47 "[warn] cache miss for key=42",
48 "[info] connected to api.example.com",
49 "[error] failed to write tmp/foo: disk full",
50 "[info] saved settings",
51 "[debug] frame budget = 16.6ms"
52]
53
54//! Indexed-form text widget requires explicit table declaration at module scope.
55var private IT_LINE : table<int; NarrativeState>
56
57
58def private completion_cb(var data : ImGuiInputTextCallbackData) : int {
59 if (data.EventFlag == ImGuiInputTextFlags.CallbackCompletion) {
60 let prefix = clone_string(data.Buf)
61 var matches <- [for (c in COMMANDS); c; where c |> starts_with(prefix)]
62 if (length(matches) == 1) {
63 data |> DeleteChars(0, data.BufTextLen)
64 data |> InsertChars(0, matches[0])
65 }
66 delete matches
67 }
68 return 0
69}
70
71[export]
72def init() {
73 live_create_window("dasImgui input_text tutorial", 760, 760)
74 live_imgui_init(live_window)
75 let io & = unsafe(GetIO())
76 GetStyle().FontScaleMain = 1.4
77}
78
79[export]
80def update() {
81 if (!live_begin_frame()) return
82 begin_frame()
83
84 ImGui_ImplGlfw_NewFrame()
85 apply_synth_io_override()
86 NewFrame()
87
88 SetNextWindowPos(ImVec2(20.0f, 20.0f), ImGuiCond.Always)
89 SetNextWindowSize(ImVec2(720.0f, 720.0f), ImGuiCond.Always)
90 window(IT_WIN, (text = "input_text tutorial", closable = false,
91 flags = ImGuiWindowFlags.None)) {
92
93 // ---- Stage 1: basic input_text ----
94 input_text(IT_NAME, (text = "name"))
95 text("IT_NAME.value = '{IT_NAME.value}' (capacity={IT_NAME.capacity})")
96 spacing()
97
98 // ---- Stage 2: with_hint — placeholder when empty ----
99 input_text_with_hint(IT_EMAIL, (text = "email",
100 hint = "you@example.com"))
101 text("IT_EMAIL.value = '{IT_EMAIL.value}'")
102 spacing()
103
104 // ---- Stage 3: multiline — CR/LF tolerant, sized box ----
105 input_text_multiline(IT_BIO, (text = "bio",
106 size = float2(0.0f, 90.0f)))
107 text("IT_BIO length = {length(IT_BIO.value)} bytes")
108 spacing()
109
110 // ---- Stage 4: growable — buffer expands past `capacity` automatically ----
111 input_text_growable(IT_FREE, (text = "free-form"))
112 text("IT_FREE capacity = {IT_FREE.capacity}, length = {length(IT_FREE.value)}")
113 spacing()
114
115 // ---- Stage 5: callback — TAB completes against COMMANDS dictionary ----
116 text("Type a prefix (h/cla/ex) and press TAB:")
117 if (input_text_callback(IT_CMD, "command",
118 ImGuiInputTextFlags.CallbackCompletion,
119 @(var data : ImGuiInputTextCallbackData) =>
120 completion_cb(data))) {}
121 spacing()
122 separator()
123
124 // ---- Stage 6: text_filter — incl,-excl token filter ----
125 text("text_filter - type 'info' or '-debug' to filter the log:")
126 text_filter(IT_FILTER)
127 for (i in range(length(LOG_LINES))) {
128 if (passes_filter(IT_FILTER, LOG_LINES[i])) {
129 text(IT_LINE[i], (text = LOG_LINES[i]))
130 }
131 }
132 }
133
134 end_of_frame()
135 Render()
136 var w, h : int
137 live_get_framebuffer_size(w, h)
138 glViewport(0, 0, w, h)
139 glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
140 glClear(GL_COLOR_BUFFER_BIT)
141 live_imgui_render()
142
143 live_end_frame()
144}
145
146[export]
147def shutdown() {
148 live_imgui_shutdown()
149 live_destroy_window()
150}
151
152[export]
153def main() {
154 init()
155 while (!exit_requested()) {
156 update()
157 }
158 shutdown()
159}
8.18.1.42.1.1. Requires
Already in the baseline boost layer:
imgui/imgui_widgets_builtin— everyinput_text*rail +text_filter+passes_filter.imgui/imgui_boost_runtime—InputTextState(buffer + mirror) andTextFilterState(boundImGuiTextFilterinline).strings— forstarts_withused in the callback completion stage.
8.18.1.42.1.2. Basic and with_hint
input_text is the single-line editor backed by a fixed-size buffer
(state.capacity, default 256 bytes). input_text_with_hint adds a
placeholder rendered when the buffer is empty:
input_text(NAME, (text = "name"))
input_text_with_hint(EMAIL, (text = "email",
hint = "you@example.com"))
Both share InputTextState. state.value is a clone of the buffer
content updated each frame.
8.18.1.42.1.3. Multiline
input_text_multiline accepts CR / LF and exposes a sized text box.
size = float2(0, 0) lets ImGui pick a default rect — wide and short.
Pass an explicit (w, h) for editor-style panels:
input_text_multiline(BIO, (text = "bio",
size = float2(0.0f, 90.0f))) // 90px tall
8.18.1.42.1.4. Growable
input_text_growable is the same as input_text but the buffer
resizes itself when the user types past state.capacity. ImGui’s
CallbackResize event is plumbed through a daslang lambda; the thunk
holding (Context*, LineInfo*, lambda) lives on the C call stack for
the duration of the ImGui::InputText call:
input_text_growable(FREE, (text = "free-form"))
// state.capacity grows as needed; state.buffer follows
Use this when the input is genuinely free-form (notes, code, long URLs); use the fixed-size form when 256 bytes is enough (names, emails, identifiers).
8.18.1.42.1.5. Callback
input_text_callback takes an extra cb arg — a lambda fired by
ImGui on flagged events. Wire the events you want via flags:
CallbackCompletion— TAB pressedCallbackHistory— Up/Down arrowsCallbackAlways— every frame the field is activeCallbackCharFilter— per-character; return non-zero to rejectCallbackEdit— buffer modifiedCallbackResize— buffer overflow (useinput_text_growablefor the standard impl)
input_text_callback(CMD, "command",
ImGuiInputTextFlags.CallbackCompletion,
@(var data : ImGuiInputTextCallbackData) =>
completion_cb(data))
The data : ImGuiInputTextCallbackData pointer is valid only inside
the call. data.Buf is the current buffer; DeleteChars /
InsertChars are the in-place edit helpers. Cloning data.Buf to a
daslang string + doing the matching in pure das is the common pattern.
8.18.1.42.1.6. text_filter
text_filter renders an inline InputText editor whose buffer is
parsed as comma-separated tokens:
foo,bar— pass lines containingfooORbar-debug— exclude lines containingdebuginfo,-debug— combine
Pair with passes_filter(STATE, line) : bool to gate output:
text_filter(FILTER)
for (i in range(length(LOG_LINES))) {
if (passes_filter(FILTER, LOG_LINES[i])) {
text(LOG_LINE[i], (text = LOG_LINES[i]))
}
}
While the filter expression is empty, passes_filter returns true
for every line — the filter is silently disabled until the user types.
Use is_active(STATE) to branch on filter-empty vs filter-non-empty
when you want a different code path (e.g. clipper-cull vs sequential
scan).
8.18.1.42.1.7. Indexed-form note
The text(IDENT[i], (text = ...)) form requires you to declare the
table at module scope:
var private LOG_LINE : table<int; NarrativeState>
The single-state form (text(IDENT, (text = ...))) auto-emits the
state global from the macro. Indexed form does not — the table key type
needs the user’s hand.
8.18.1.42.1.8. Driving from outside
The walkthrough above types into every field with real synthetic key
events (a real click to focus, then imgui_key_type), so it exercises
exactly what a user would: the completion callback fires on Tab, the filter
narrows the log as you type, and one \n in the multiline buffer inserts
exactly one line break. For scripted setup that skips the keystrokes,
imgui_force_set writes state.pending_value and the next frame
overwrites the buffer:
curl -X POST -d '{"name":"imgui_force_set","args":{"target":"IT_WIN/IT_NAME","value":"hello"}}' \
localhost:9090/command
# Multiline content — embed \n in the JSON string:
curl -X POST -d '{"name":"imgui_force_set","args":{"target":"IT_WIN/IT_BIO","value":"line 1\nline 2"}}' \
localhost:9090/command
For input_text_growable, sending a payload longer than current
state.capacity triggers CallbackResize on the same frame the
buffer is consumed.
text_filter is currently read-only via telemetry — there’s no
imgui_force_set path that writes the filter expression. Click the filter
field and type directly to change it.
See also
Full source: modules/dasImgui/examples/tutorial/input_text.das
Features-side demos: modules/dasImgui/examples/features/inputs_text.das (all five
non-filter forms) and modules/dasImgui/examples/features/input_text_callback.das
(canonical TAB-completion).
Sibling tutorial: Input numeric widgets.
Boost macros — the macro layer.