dear_imgui_rs/widget/
input.rs

1//! Text and scalar inputs
2//!
3//! Single-line and multi-line text inputs backed by `String` or `ImString`
4//! (zero-copy), plus number input helpers. Builders provide flags and
5//! callback hooks for validation and behavior tweaks.
6//!
7//! Quick examples:
8//! ```no_run
9//! # use dear_imgui_rs::*;
10//! # let mut ctx = Context::create();
11//! # let ui = ctx.frame();
12//! // Text (String)
13//! let mut s = String::from("hello");
14//! ui.input_text("Name", &mut s).build();
15//!
16//! // Text (ImString, zero-copy)
17//! let mut im = ImString::with_capacity(64);
18//! ui.input_text_imstr("ImStr", &mut im).build();
19//!
20//! // Numbers
21//! let mut i = 0i32;
22//! let mut f = 1.0f32;
23//! ui.input_int("Count", &mut i);
24//! ui.input_float("Scale", &mut f);
25//! ```
26//!
27#![allow(
28    clippy::cast_possible_truncation,
29    clippy::cast_sign_loss,
30    clippy::as_conversions
31)]
32use crate::InputTextFlags;
33use crate::internal::DataTypeKind;
34use crate::string::ImString;
35use crate::sys;
36use crate::ui::Ui;
37use std::ffi::{c_int, c_void};
38use std::marker::PhantomData;
39use std::ptr;
40
41/// # Input Widgets
42impl Ui {
43    /// Creates a single-line text input widget builder.
44    ///
45    /// # Examples
46    ///
47    /// ```no_run
48    /// # use dear_imgui_rs::*;
49    /// # let mut ctx = Context::create();
50    /// # let ui = ctx.frame();
51    /// let mut text = String::new();
52    /// if ui.input_text("Label", &mut text).build() {
53    ///     println!("Text changed: {}", text);
54    /// }
55    /// ```
56    #[doc(alias = "InputText", alias = "InputTextWithHint")]
57    pub fn input_text<'p>(
58        &self,
59        label: impl AsRef<str>,
60        buf: &'p mut String,
61    ) -> InputText<'_, 'p, String, String, PassthroughCallback> {
62        InputText::new(self, label, buf)
63    }
64
65    /// Creates a single-line text input backed by ImString (zero-copy)
66    pub fn input_text_imstr<'p>(
67        &self,
68        label: impl AsRef<str>,
69        buf: &'p mut ImString,
70    ) -> InputTextImStr<'_, 'p, String, String, PassthroughCallback> {
71        InputTextImStr::new(self, label, buf)
72    }
73
74    /// Creates a multi-line text input widget builder.
75    ///
76    /// # Examples
77    ///
78    /// ```no_run
79    /// # use dear_imgui_rs::*;
80    /// # let mut ctx = Context::create();
81    /// # let ui = ctx.frame();
82    /// let mut text = String::new();
83    /// if ui.input_text_multiline("Label", &mut text, [200.0, 100.0]).build() {
84    ///     println!("Text changed: {}", text);
85    /// }
86    /// ```
87    #[doc(alias = "InputTextMultiline")]
88    pub fn input_text_multiline<'p>(
89        &self,
90        label: impl AsRef<str>,
91        buf: &'p mut String,
92        size: impl Into<[f32; 2]>,
93    ) -> InputTextMultiline<'_, 'p> {
94        InputTextMultiline::new(self, label, buf, size)
95    }
96
97    /// Creates a multi-line text input backed by ImString (zero-copy)
98    pub fn input_text_multiline_imstr<'p>(
99        &self,
100        label: impl AsRef<str>,
101        buf: &'p mut ImString,
102        size: impl Into<[f32; 2]>,
103    ) -> InputTextMultilineImStr<'_, 'p> {
104        InputTextMultilineImStr::new(self, label, buf, size)
105    }
106
107    /// Creates an integer input widget.
108    ///
109    /// Returns true if the value was edited.
110    #[doc(alias = "InputInt")]
111    pub fn input_int(&self, label: impl AsRef<str>, value: &mut i32) -> bool {
112        self.input_int_config(label).build(value)
113    }
114
115    /// Creates a float input widget.
116    ///
117    /// Returns true if the value was edited.
118    #[doc(alias = "InputFloat")]
119    pub fn input_float(&self, label: impl AsRef<str>, value: &mut f32) -> bool {
120        self.input_float_config(label).build(value)
121    }
122
123    /// Creates a double input widget.
124    ///
125    /// Returns true if the value was edited.
126    #[doc(alias = "InputDouble")]
127    pub fn input_double(&self, label: impl AsRef<str>, value: &mut f64) -> bool {
128        self.input_double_config(label).build(value)
129    }
130
131    /// Creates an integer input builder
132    pub fn input_int_config(&self, label: impl AsRef<str>) -> InputInt<'_> {
133        InputInt::new(self, label)
134    }
135
136    /// Creates a float input builder
137    pub fn input_float_config(&self, label: impl AsRef<str>) -> InputFloat<'_> {
138        InputFloat::new(self, label)
139    }
140
141    /// Creates a double input builder
142    pub fn input_double_config(&self, label: impl AsRef<str>) -> InputDouble<'_> {
143        InputDouble::new(self, label)
144    }
145
146    /// Shows an input field for a scalar value. This is not limited to `f32` and `i32` and can be used with
147    /// any primitive scalar type e.g. `u8` and `f64`.
148    #[doc(alias = "InputScalar")]
149    pub fn input_scalar<'p, L, T>(&self, label: L, value: &'p mut T) -> InputScalar<'_, 'p, T, L>
150    where
151        L: AsRef<str>,
152        T: DataTypeKind,
153    {
154        InputScalar::new(self, label, value)
155    }
156
157    /// Shows a horizontal array of scalar value input fields. See [`input_scalar`].
158    ///
159    /// [`input_scalar`]: Self::input_scalar
160    #[doc(alias = "InputScalarN")]
161    pub fn input_scalar_n<'p, L, T>(
162        &self,
163        label: L,
164        values: &'p mut [T],
165    ) -> InputScalarN<'_, 'p, T, L>
166    where
167        L: AsRef<str>,
168        T: DataTypeKind,
169    {
170        InputScalarN::new(self, label, values)
171    }
172
173    /// Widget to edit two floats
174    #[doc(alias = "InputFloat2")]
175    pub fn input_float2<'p, L>(&self, label: L, value: &'p mut [f32; 2]) -> InputFloat2<'_, 'p, L>
176    where
177        L: AsRef<str>,
178    {
179        InputFloat2::new(self, label, value)
180    }
181
182    /// Widget to edit three floats
183    #[doc(alias = "InputFloat3")]
184    pub fn input_float3<'p, L>(&self, label: L, value: &'p mut [f32; 3]) -> InputFloat3<'_, 'p, L>
185    where
186        L: AsRef<str>,
187    {
188        InputFloat3::new(self, label, value)
189    }
190
191    /// Widget to edit four floats
192    #[doc(alias = "InputFloat4")]
193    pub fn input_float4<'p, L>(&self, label: L, value: &'p mut [f32; 4]) -> InputFloat4<'_, 'p, L>
194    where
195        L: AsRef<str>,
196    {
197        InputFloat4::new(self, label, value)
198    }
199
200    /// Widget to edit two integers
201    #[doc(alias = "InputInt2")]
202    pub fn input_int2<'p, L>(&self, label: L, value: &'p mut [i32; 2]) -> InputInt2<'_, 'p, L>
203    where
204        L: AsRef<str>,
205    {
206        InputInt2::new(self, label, value)
207    }
208
209    /// Widget to edit three integers
210    #[doc(alias = "InputInt3")]
211    pub fn input_int3<'p, L>(&self, label: L, value: &'p mut [i32; 3]) -> InputInt3<'_, 'p, L>
212    where
213        L: AsRef<str>,
214    {
215        InputInt3::new(self, label, value)
216    }
217
218    /// Widget to edit four integers
219    #[doc(alias = "InputInt4")]
220    pub fn input_int4<'p, L>(&self, label: L, value: &'p mut [i32; 4]) -> InputInt4<'_, 'p, L>
221    where
222        L: AsRef<str>,
223    {
224        InputInt4::new(self, label, value)
225    }
226}
227
228/// Builder for a text input widget
229#[must_use]
230pub struct InputText<'ui, 'p, L = String, H = String, T = PassthroughCallback> {
231    ui: &'ui Ui,
232    label: L,
233    buf: &'p mut String,
234    flags: InputTextFlags,
235    capacity_hint: Option<usize>,
236    hint: Option<H>,
237    callback_handler: T,
238    _phantom: PhantomData<&'ui ()>,
239}
240
241/// Builder for a text input backed by ImString (zero-copy)
242#[must_use]
243pub struct InputTextImStr<'ui, 'p, L = String, H = String, T = PassthroughCallback> {
244    ui: &'ui Ui,
245    label: L,
246    buf: &'p mut ImString,
247    flags: InputTextFlags,
248    hint: Option<H>,
249    callback_handler: T,
250    _phantom: PhantomData<&'ui ()>,
251}
252
253impl<'ui, 'p> InputTextImStr<'ui, 'p, String, String, PassthroughCallback> {
254    pub fn new(ui: &'ui Ui, label: impl AsRef<str>, buf: &'p mut ImString) -> Self {
255        Self {
256            ui,
257            label: label.as_ref().to_string(),
258            buf,
259            flags: InputTextFlags::empty(),
260            hint: None,
261            callback_handler: PassthroughCallback,
262            _phantom: PhantomData,
263        }
264    }
265}
266
267impl<'ui, 'p, L: AsRef<str>, H: AsRef<str>, T> InputTextImStr<'ui, 'p, L, H, T> {
268    pub fn flags(mut self, flags: InputTextFlags) -> Self {
269        self.flags = flags;
270        self
271    }
272    pub fn hint<H2: AsRef<str>>(self, hint: H2) -> InputTextImStr<'ui, 'p, L, H2, T> {
273        InputTextImStr {
274            ui: self.ui,
275            label: self.label,
276            buf: self.buf,
277            flags: self.flags,
278            hint: Some(hint),
279            callback_handler: self.callback_handler,
280            _phantom: PhantomData,
281        }
282    }
283    pub fn read_only(mut self, ro: bool) -> Self {
284        self.flags.set(InputTextFlags::READ_ONLY, ro);
285        self
286    }
287    pub fn password(mut self, pw: bool) -> Self {
288        self.flags.set(InputTextFlags::PASSWORD, pw);
289        self
290    }
291    pub fn auto_select_all(mut self, v: bool) -> Self {
292        self.flags.set(InputTextFlags::AUTO_SELECT_ALL, v);
293        self
294    }
295    pub fn enter_returns_true(mut self, v: bool) -> Self {
296        self.flags.set(InputTextFlags::ENTER_RETURNS_TRUE, v);
297        self
298    }
299
300    pub fn build(self) -> bool {
301        let label_ptr = self.ui.scratch_txt(self.label.as_ref());
302        let hint_ptr = if let Some(ref hint) = self.hint {
303            self.ui.scratch_txt(hint.as_ref())
304        } else {
305            std::ptr::null()
306        };
307        let buf_ptr = self.buf.as_mut_ptr();
308        let buf_size = self.buf.capacity_with_nul();
309        let user_ptr = self.buf as *mut ImString as *mut c_void;
310
311        extern "C" fn resize_cb_imstr(data: *mut sys::ImGuiInputTextCallbackData) -> c_int {
312            unsafe {
313                if (*data).EventFlag == (sys::ImGuiInputTextFlags_CallbackResize as i32) {
314                    let im = &mut *((*data).UserData as *mut ImString);
315                    let requested = (*data).BufSize as usize;
316                    if im.0.len() < requested {
317                        im.0.resize(requested, 0);
318                    }
319                    (*data).Buf = im.as_mut_ptr();
320                    (*data).BufDirty = true;
321                }
322            }
323            0
324        }
325
326        let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
327        let result = unsafe {
328            if hint_ptr.is_null() {
329                sys::igInputText(
330                    label_ptr,
331                    buf_ptr,
332                    buf_size,
333                    flags.bits(),
334                    Some(resize_cb_imstr),
335                    user_ptr,
336                )
337            } else {
338                sys::igInputTextWithHint(
339                    label_ptr,
340                    hint_ptr,
341                    buf_ptr,
342                    buf_size,
343                    flags.bits(),
344                    Some(resize_cb_imstr),
345                    user_ptr,
346                )
347            }
348        };
349        // Ensure ImString logical length reflects actual text (scan to NUL)
350        unsafe { self.buf.refresh_len() };
351        result
352    }
353}
354impl<'ui, 'p> InputText<'ui, 'p, String, String, PassthroughCallback> {
355    /// Creates a new text input builder
356    pub fn new(ui: &'ui Ui, label: impl AsRef<str>, buf: &'p mut String) -> Self {
357        Self {
358            ui,
359            label: label.as_ref().to_string(),
360            buf,
361            flags: InputTextFlags::NONE,
362            capacity_hint: None,
363            hint: None,
364            callback_handler: PassthroughCallback,
365            _phantom: PhantomData,
366        }
367    }
368}
369
370impl<'ui, 'p, L, H, T> InputText<'ui, 'p, L, H, T> {
371    /// Sets the flags for the input
372    pub fn flags(mut self, flags: InputTextFlags) -> Self {
373        self.flags = flags;
374        self
375    }
376
377    /// Hint a minimum buffer capacity to reduce reallocations for large fields
378    pub fn capacity_hint(mut self, cap: usize) -> Self {
379        self.capacity_hint = Some(cap);
380        self
381    }
382
383    /// Sets a hint text
384    pub fn hint<H2: AsRef<str>>(self, hint: H2) -> InputText<'ui, 'p, L, H2, T> {
385        InputText {
386            ui: self.ui,
387            label: self.label,
388            buf: self.buf,
389            flags: self.flags,
390            capacity_hint: self.capacity_hint,
391            hint: Some(hint),
392            callback_handler: self.callback_handler,
393            _phantom: PhantomData,
394        }
395    }
396
397    /// Sets a callback handler for the input text
398    pub fn callback<T2: InputTextCallbackHandler>(
399        self,
400        callback_handler: T2,
401    ) -> InputText<'ui, 'p, L, H, T2> {
402        InputText {
403            ui: self.ui,
404            label: self.label,
405            buf: self.buf,
406            flags: self.flags,
407            capacity_hint: self.capacity_hint,
408            hint: self.hint,
409            callback_handler,
410            _phantom: PhantomData,
411        }
412    }
413
414    /// Sets callback flags for the input text
415    pub fn callback_flags(mut self, callback_flags: InputTextCallback) -> Self {
416        self.flags |= InputTextFlags::from_bits_truncate(callback_flags.bits() as i32);
417        self
418    }
419
420    /// Makes the input read-only
421    pub fn read_only(mut self, read_only: bool) -> Self {
422        self.flags.set(InputTextFlags::READ_ONLY, read_only);
423        self
424    }
425
426    /// Enables password mode
427    pub fn password(mut self, password: bool) -> Self {
428        self.flags.set(InputTextFlags::PASSWORD, password);
429        self
430    }
431
432    /// Enables auto-select all when first taking focus
433    pub fn auto_select_all(mut self, auto_select: bool) -> Self {
434        self.flags.set(InputTextFlags::AUTO_SELECT_ALL, auto_select);
435        self
436    }
437
438    /// Makes Enter key return true instead of adding new line
439    pub fn enter_returns_true(mut self, enter_returns: bool) -> Self {
440        self.flags
441            .set(InputTextFlags::ENTER_RETURNS_TRUE, enter_returns);
442        self
443    }
444
445    /// Allows only decimal characters (0123456789.+-*/)
446    pub fn chars_decimal(mut self, decimal: bool) -> Self {
447        self.flags.set(InputTextFlags::CHARS_DECIMAL, decimal);
448        self
449    }
450
451    /// Allows only hexadecimal characters (0123456789ABCDEFabcdef)
452    pub fn chars_hexadecimal(mut self, hex: bool) -> Self {
453        self.flags.set(InputTextFlags::CHARS_HEXADECIMAL, hex);
454        self
455    }
456
457    /// Turns a..z into A..Z
458    pub fn chars_uppercase(mut self, uppercase: bool) -> Self {
459        self.flags.set(InputTextFlags::CHARS_UPPERCASE, uppercase);
460        self
461    }
462
463    /// Filters out spaces and tabs
464    pub fn chars_no_blank(mut self, no_blank: bool) -> Self {
465        self.flags.set(InputTextFlags::CHARS_NO_BLANK, no_blank);
466        self
467    }
468}
469
470// Implementation for all InputText types
471impl<'ui, 'p, L, H, T> InputText<'ui, 'p, L, H, T>
472where
473    L: AsRef<str>,
474    H: AsRef<str>,
475    T: InputTextCallbackHandler,
476{
477    /// Builds the text input widget
478    pub fn build(self) -> bool {
479        let label_ptr = self.ui.scratch_txt(self.label.as_ref());
480        let hint_ptr = if let Some(ref hint) = self.hint {
481            self.ui.scratch_txt(hint.as_ref())
482        } else {
483            std::ptr::null()
484        };
485
486        if let Some(extra) = self.capacity_hint {
487            let needed = extra.saturating_sub(self.buf.capacity().saturating_sub(self.buf.len()));
488            if needed > 0 {
489                self.buf.reserve(needed);
490            }
491        }
492
493        // Ensure temporary NUL terminator
494        self.buf.push('\0');
495        let capacity = self.buf.capacity();
496        let buf_ptr = self.buf.as_mut_ptr() as *mut std::os::raw::c_char;
497
498        #[repr(C)]
499        struct UserData<T> {
500            container: *mut String,
501            handler: T,
502        }
503
504        extern "C" fn callback_router<T: InputTextCallbackHandler>(
505            data: *mut sys::ImGuiInputTextCallbackData,
506        ) -> c_int {
507            let event_flag = unsafe { InputTextFlags::from_bits_truncate((*data).EventFlag) };
508            let user = unsafe { &mut *((*data).UserData as *mut UserData<T>) };
509            match event_flag {
510                InputTextFlags::CALLBACK_RESIZE => unsafe {
511                    let requested = (*data).BufSize as usize;
512                    let s = &mut *user.container;
513                    debug_assert_eq!(s.as_ptr() as *const _, (*data).Buf);
514                    if requested > s.capacity() {
515                        let additional = requested.saturating_sub(s.len());
516                        s.reserve(additional);
517                        (*data).Buf = s.as_mut_ptr() as *mut _;
518                        (*data).BufDirty = true;
519                    }
520                    0
521                },
522                InputTextFlags::CALLBACK_COMPLETION => {
523                    let info = unsafe { TextCallbackData::new(data) };
524                    user.handler.on_completion(info);
525                    0
526                }
527                InputTextFlags::CALLBACK_HISTORY => {
528                    let key = unsafe { (*data).EventKey };
529                    let dir = if key == sys::ImGuiKey_UpArrow {
530                        HistoryDirection::Up
531                    } else {
532                        HistoryDirection::Down
533                    };
534                    let info = unsafe { TextCallbackData::new(data) };
535                    user.handler.on_history(dir, info);
536                    0
537                }
538                InputTextFlags::CALLBACK_ALWAYS => {
539                    let info = unsafe { TextCallbackData::new(data) };
540                    user.handler.on_always(info);
541                    0
542                }
543                InputTextFlags::CALLBACK_EDIT => {
544                    let info = unsafe { TextCallbackData::new(data) };
545                    user.handler.on_edit(info);
546                    0
547                }
548                InputTextFlags::CALLBACK_CHAR_FILTER => {
549                    let ch =
550                        unsafe { std::char::from_u32((*data).EventChar as u32).unwrap_or('\0') };
551                    let new_ch = user.handler.char_filter(ch).map(|c| c as u32).unwrap_or(0);
552                    unsafe {
553                        (*data).EventChar = new_ch as u16;
554                    }
555                    0
556                }
557                _ => 0,
558            }
559        }
560
561        let mut user_data = UserData {
562            container: self.buf as *mut String,
563            handler: self.callback_handler,
564        };
565        let user_ptr = &mut user_data as *mut _ as *mut c_void;
566
567        let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
568        let result = unsafe {
569            if hint_ptr.is_null() {
570                sys::igInputText(
571                    label_ptr,
572                    buf_ptr,
573                    capacity,
574                    flags.bits(),
575                    Some(callback_router::<T>),
576                    user_ptr,
577                )
578            } else {
579                sys::igInputTextWithHint(
580                    label_ptr,
581                    hint_ptr,
582                    buf_ptr,
583                    capacity,
584                    flags.bits(),
585                    Some(callback_router::<T>),
586                    user_ptr,
587                )
588            }
589        };
590
591        // Trim to first NUL (remove pushed terminator)
592        let cap = unsafe { (&*user_data.container).capacity() };
593        let slice = unsafe { std::slice::from_raw_parts((&*user_data.container).as_ptr(), cap) };
594        if let Some(len) = slice.iter().position(|&b| b == 0) {
595            unsafe { (&mut *user_data.container).as_mut_vec().set_len(len) };
596        }
597        result
598    }
599}
600
601/// Builder for multiline text input widget
602#[derive(Debug)]
603#[must_use]
604pub struct InputTextMultiline<'ui, 'p> {
605    ui: &'ui Ui,
606    label: String,
607    buf: &'p mut String,
608    size: [f32; 2],
609    flags: InputTextFlags,
610    capacity_hint: Option<usize>,
611}
612
613/// Builder for multiline text input backed by ImString (zero-copy)
614#[derive(Debug)]
615#[must_use]
616pub struct InputTextMultilineImStr<'ui, 'p> {
617    ui: &'ui Ui,
618    label: String,
619    buf: &'p mut ImString,
620    size: [f32; 2],
621    flags: InputTextFlags,
622}
623
624impl<'ui, 'p> InputTextMultilineImStr<'ui, 'p> {
625    pub fn new(
626        ui: &'ui Ui,
627        label: impl AsRef<str>,
628        buf: &'p mut ImString,
629        size: impl Into<[f32; 2]>,
630    ) -> Self {
631        Self {
632            ui,
633            label: label.as_ref().to_string(),
634            buf,
635            size: size.into(),
636            flags: InputTextFlags::NONE,
637        }
638    }
639    pub fn flags(mut self, flags: InputTextFlags) -> Self {
640        self.flags = flags;
641        self
642    }
643    pub fn read_only(mut self, v: bool) -> Self {
644        self.flags.set(InputTextFlags::READ_ONLY, v);
645        self
646    }
647    pub fn build(self) -> bool {
648        let label_ptr = self.ui.scratch_txt(&self.label);
649        let buf_ptr = self.buf.as_mut_ptr();
650        let buf_size = self.buf.capacity_with_nul();
651        let user_ptr = self.buf as *mut ImString as *mut c_void;
652        let size_vec: sys::ImVec2 = self.size.into();
653
654        extern "C" fn resize_cb_imstr(data: *mut sys::ImGuiInputTextCallbackData) -> c_int {
655            unsafe {
656                if (*data).EventFlag == (sys::ImGuiInputTextFlags_CallbackResize as i32) {
657                    let im = &mut *((*data).UserData as *mut ImString);
658                    let requested = (*data).BufSize as usize;
659                    if im.0.len() < requested {
660                        im.0.resize(requested, 0);
661                    }
662                    (*data).Buf = im.as_mut_ptr();
663                    (*data).BufDirty = true;
664                }
665            }
666            0
667        }
668
669        let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
670        let result = unsafe {
671            sys::igInputTextMultiline(
672                label_ptr,
673                buf_ptr,
674                buf_size,
675                size_vec,
676                flags.bits(),
677                Some(resize_cb_imstr),
678                user_ptr,
679            )
680        };
681        // Ensure ImString logical length reflects actual text (scan to NUL)
682        unsafe { self.buf.refresh_len() };
683        result
684    }
685}
686impl<'ui, 'p> InputTextMultiline<'ui, 'p> {
687    /// Creates a new multiline text input builder
688    pub fn new(
689        ui: &'ui Ui,
690        label: impl AsRef<str>,
691        buf: &'p mut String,
692        size: impl Into<[f32; 2]>,
693    ) -> Self {
694        Self {
695            ui,
696            label: label.as_ref().to_string(),
697            buf,
698            size: size.into(),
699            flags: InputTextFlags::NONE,
700            capacity_hint: None,
701        }
702    }
703
704    /// Sets the flags for the input
705    pub fn flags(mut self, flags: InputTextFlags) -> Self {
706        self.flags = flags;
707        self
708    }
709
710    /// Hint a minimum buffer capacity to reduce reallocations for large fields
711    pub fn capacity_hint(mut self, cap: usize) -> Self {
712        self.capacity_hint = Some(cap);
713        self
714    }
715
716    /// Makes the input read-only
717    pub fn read_only(mut self, read_only: bool) -> Self {
718        self.flags.set(InputTextFlags::READ_ONLY, read_only);
719        self
720    }
721
722    /// Builds the multiline text input widget
723    pub fn build(self) -> bool {
724        let label_ptr = self.ui.scratch_txt(&self.label);
725
726        // Optional pre-reserve
727        if let Some(extra) = self.capacity_hint {
728            let needed = extra.saturating_sub(self.buf.capacity().saturating_sub(self.buf.len()));
729            if needed > 0 {
730                self.buf.reserve(needed);
731            }
732        }
733
734        // Ensure a NUL terminator and use String's capacity directly
735        self.buf.push('\0');
736        let capacity = self.buf.capacity();
737        let buf_ptr = self.buf.as_mut_ptr() as *mut std::os::raw::c_char;
738
739        #[repr(C)]
740        struct UserData {
741            container: *mut String,
742        }
743
744        extern "C" fn callback_router(data: *mut sys::ImGuiInputTextCallbackData) -> c_int {
745            let event_flag = unsafe { InputTextFlags::from_bits_truncate((*data).EventFlag) };
746            match event_flag {
747                InputTextFlags::CALLBACK_RESIZE => unsafe {
748                    let requested = (*data).BufSize as usize;
749                    let s = &mut *(&mut *((*data).UserData as *mut UserData)).container;
750                    debug_assert_eq!(s.as_ptr() as *const _, (*data).Buf);
751                    if requested > s.capacity() {
752                        let additional = requested.saturating_sub(s.len());
753                        s.reserve(additional);
754                        (*data).Buf = s.as_mut_ptr() as *mut _;
755                        (*data).BufDirty = true;
756                    }
757                    0
758                },
759                _ => 0,
760            }
761        }
762
763        let mut user_data = UserData {
764            container: self.buf as *mut String,
765        };
766        let user_ptr = &mut user_data as *mut _ as *mut c_void;
767
768        let size_vec: sys::ImVec2 = self.size.into();
769        let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
770        let result = unsafe {
771            sys::igInputTextMultiline(
772                label_ptr,
773                buf_ptr,
774                capacity,
775                size_vec,
776                flags.bits(),
777                Some(callback_router),
778                user_ptr,
779            )
780        };
781
782        // Trim at NUL to restore real length
783        let cap = unsafe { (&*user_data.container).capacity() };
784        let slice = unsafe { std::slice::from_raw_parts((&*user_data.container).as_ptr(), cap) };
785        if let Some(len) = slice.iter().position(|&b| b == 0) {
786            unsafe { (&mut *user_data.container).as_mut_vec().set_len(len) };
787        }
788        result
789    }
790
791    /// Enable ImGui callbacks for this multiline input and attach a handler.
792    pub fn callback<T2: InputTextCallbackHandler>(
793        mut self,
794        callbacks: InputTextCallback,
795        handler: T2,
796    ) -> InputTextMultilineWithCb<'ui, 'p, T2> {
797        // Note: ImGui forbids CallbackHistory/Completion with Multiline.
798        // We intentionally do NOT enable them here to avoid assertions.
799        if callbacks.contains(InputTextCallback::ALWAYS) {
800            self.flags.insert(InputTextFlags::CALLBACK_ALWAYS);
801        }
802        if callbacks.contains(InputTextCallback::CHAR_FILTER) {
803            self.flags.insert(InputTextFlags::CALLBACK_CHAR_FILTER);
804        }
805        if callbacks.contains(InputTextCallback::EDIT) {
806            self.flags.insert(InputTextFlags::CALLBACK_EDIT);
807        }
808
809        InputTextMultilineWithCb {
810            ui: self.ui,
811            label: self.label,
812            buf: self.buf,
813            size: self.size,
814            flags: self.flags,
815            capacity_hint: self.capacity_hint,
816            handler,
817        }
818    }
819}
820
821/// Multiline InputText with attached callback handler
822pub struct InputTextMultilineWithCb<'ui, 'p, T> {
823    ui: &'ui Ui,
824    label: String,
825    buf: &'p mut String,
826    size: [f32; 2],
827    flags: InputTextFlags,
828    capacity_hint: Option<usize>,
829    handler: T,
830}
831
832impl<'ui, 'p, T: InputTextCallbackHandler> InputTextMultilineWithCb<'ui, 'p, T> {
833    pub fn build(self) -> bool {
834        let label_ptr = self.ui.scratch_txt(&self.label);
835
836        if let Some(extra) = self.capacity_hint {
837            let needed = extra.saturating_sub(self.buf.capacity().saturating_sub(self.buf.len()));
838            if needed > 0 {
839                self.buf.reserve(needed);
840            }
841        }
842
843        // Ensure NUL terminator
844        self.buf.push('\0');
845        let capacity = self.buf.capacity();
846        let buf_ptr = self.buf.as_mut_ptr() as *mut std::os::raw::c_char;
847
848        #[repr(C)]
849        struct UserData<T> {
850            container: *mut String,
851            handler: T,
852        }
853
854        extern "C" fn callback_router<T: InputTextCallbackHandler>(
855            data: *mut sys::ImGuiInputTextCallbackData,
856        ) -> c_int {
857            let event_flag = unsafe { InputTextFlags::from_bits_truncate((*data).EventFlag) };
858            let user = unsafe { &mut *((*data).UserData as *mut UserData<T>) };
859            match event_flag {
860                InputTextFlags::CALLBACK_RESIZE => unsafe {
861                    let requested = (*data).BufSize as usize;
862                    let s = &mut *user.container;
863                    debug_assert_eq!(s.as_ptr() as *const _, (*data).Buf);
864                    if requested > s.capacity() {
865                        let additional = requested.saturating_sub(s.len());
866                        s.reserve(additional);
867                        (*data).Buf = s.as_mut_ptr() as *mut _;
868                        (*data).BufDirty = true;
869                    }
870                    0
871                },
872                InputTextFlags::CALLBACK_COMPLETION => {
873                    let info = unsafe { TextCallbackData::new(data) };
874                    user.handler.on_completion(info);
875                    0
876                }
877                InputTextFlags::CALLBACK_HISTORY => {
878                    let key = unsafe { (*data).EventKey };
879                    let dir = if key == sys::ImGuiKey_UpArrow {
880                        HistoryDirection::Up
881                    } else {
882                        HistoryDirection::Down
883                    };
884                    let info = unsafe { TextCallbackData::new(data) };
885                    user.handler.on_history(dir, info);
886                    0
887                }
888                InputTextFlags::CALLBACK_ALWAYS => {
889                    let info = unsafe { TextCallbackData::new(data) };
890                    user.handler.on_always(info);
891                    0
892                }
893                InputTextFlags::CALLBACK_EDIT => {
894                    let info = unsafe { TextCallbackData::new(data) };
895                    user.handler.on_edit(info);
896                    0
897                }
898                InputTextFlags::CALLBACK_CHAR_FILTER => {
899                    let ch =
900                        unsafe { std::char::from_u32((*data).EventChar as u32).unwrap_or('\0') };
901                    let new_ch = user.handler.char_filter(ch).map(|c| c as u32).unwrap_or(0);
902                    unsafe {
903                        (*data).EventChar = new_ch as u16;
904                    }
905                    0
906                }
907                _ => 0,
908            }
909        }
910
911        let mut user_data = UserData {
912            container: self.buf as *mut String,
913            handler: self.handler,
914        };
915        let user_ptr = &mut user_data as *mut _ as *mut c_void;
916
917        let size_vec: sys::ImVec2 = self.size.into();
918        let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
919        let result = unsafe {
920            sys::igInputTextMultiline(
921                label_ptr,
922                buf_ptr,
923                capacity,
924                size_vec,
925                flags.bits(),
926                Some(callback_router::<T>),
927                user_ptr,
928            )
929        };
930
931        // Trim at NUL
932        let cap = unsafe { (&*user_data.container).capacity() };
933        let slice = unsafe { std::slice::from_raw_parts((&*user_data.container).as_ptr(), cap) };
934        if let Some(len) = slice.iter().position(|&b| b == 0) {
935            unsafe { (&mut *user_data.container).as_mut_vec().set_len(len) };
936        }
937        result
938    }
939}
940
941/// Builder for integer input widget
942#[derive(Debug)]
943#[must_use]
944pub struct InputInt<'ui> {
945    ui: &'ui Ui,
946    label: String,
947    step: i32,
948    step_fast: i32,
949    flags: InputTextFlags,
950}
951
952impl<'ui> InputInt<'ui> {
953    /// Creates a new integer input builder
954    pub fn new(ui: &'ui Ui, label: impl AsRef<str>) -> Self {
955        Self {
956            ui,
957            label: label.as_ref().to_string(),
958            step: 1,
959            step_fast: 100,
960            flags: InputTextFlags::NONE,
961        }
962    }
963
964    /// Sets the step value
965    pub fn step(mut self, step: i32) -> Self {
966        self.step = step;
967        self
968    }
969
970    /// Sets the fast step value
971    pub fn step_fast(mut self, step_fast: i32) -> Self {
972        self.step_fast = step_fast;
973        self
974    }
975
976    /// Sets the flags for the input
977    pub fn flags(mut self, flags: InputTextFlags) -> Self {
978        self.flags = flags;
979        self
980    }
981
982    /// Builds the integer input widget
983    pub fn build(self, value: &mut i32) -> bool {
984        let label_ptr = self.ui.scratch_txt(&self.label);
985        unsafe {
986            sys::igInputInt(
987                label_ptr,
988                value as *mut i32,
989                self.step,
990                self.step_fast,
991                self.flags.bits(),
992            )
993        }
994    }
995}
996
997/// Builder for float input widget
998#[derive(Debug)]
999#[must_use]
1000pub struct InputFloat<'ui> {
1001    ui: &'ui Ui,
1002    label: String,
1003    step: f32,
1004    step_fast: f32,
1005    format: Option<String>,
1006    flags: InputTextFlags,
1007}
1008
1009impl<'ui> InputFloat<'ui> {
1010    /// Creates a new float input builder
1011    pub fn new(ui: &'ui Ui, label: impl AsRef<str>) -> Self {
1012        Self {
1013            ui,
1014            label: label.as_ref().to_string(),
1015            step: 0.0,
1016            step_fast: 0.0,
1017            format: None,
1018            flags: InputTextFlags::NONE,
1019        }
1020    }
1021
1022    /// Sets the step value
1023    pub fn step(mut self, step: f32) -> Self {
1024        self.step = step;
1025        self
1026    }
1027
1028    /// Sets the fast step value
1029    pub fn step_fast(mut self, step_fast: f32) -> Self {
1030        self.step_fast = step_fast;
1031        self
1032    }
1033
1034    /// Sets the display format
1035    pub fn format(mut self, format: impl AsRef<str>) -> Self {
1036        self.format = Some(format.as_ref().to_string());
1037        self
1038    }
1039
1040    /// Sets the flags for the input
1041    pub fn flags(mut self, flags: InputTextFlags) -> Self {
1042        self.flags = flags;
1043        self
1044    }
1045
1046    /// Builds the float input widget
1047    pub fn build(self, value: &mut f32) -> bool {
1048        let label_ptr = self.ui.scratch_txt(&self.label);
1049        let format_ptr = self.ui.scratch_txt_opt(self.format.as_ref());
1050        let format_ptr = if format_ptr.is_null() {
1051            self.ui.scratch_txt("%.3f")
1052        } else {
1053            format_ptr
1054        };
1055
1056        unsafe {
1057            sys::igInputFloat(
1058                label_ptr,
1059                value as *mut f32,
1060                self.step,
1061                self.step_fast,
1062                format_ptr,
1063                self.flags.bits(),
1064            )
1065        }
1066    }
1067}
1068
1069/// Builder for double input widget
1070#[derive(Debug)]
1071#[must_use]
1072pub struct InputDouble<'ui> {
1073    ui: &'ui Ui,
1074    label: String,
1075    step: f64,
1076    step_fast: f64,
1077    format: Option<String>,
1078    flags: InputTextFlags,
1079}
1080
1081impl<'ui> InputDouble<'ui> {
1082    /// Creates a new double input builder
1083    pub fn new(ui: &'ui Ui, label: impl AsRef<str>) -> Self {
1084        Self {
1085            ui,
1086            label: label.as_ref().to_string(),
1087            step: 0.0,
1088            step_fast: 0.0,
1089            format: None,
1090            flags: InputTextFlags::NONE,
1091        }
1092    }
1093
1094    /// Sets the step value
1095    pub fn step(mut self, step: f64) -> Self {
1096        self.step = step;
1097        self
1098    }
1099
1100    /// Sets the fast step value
1101    pub fn step_fast(mut self, step_fast: f64) -> Self {
1102        self.step_fast = step_fast;
1103        self
1104    }
1105
1106    /// Sets the display format
1107    pub fn format(mut self, format: impl AsRef<str>) -> Self {
1108        self.format = Some(format.as_ref().to_string());
1109        self
1110    }
1111
1112    /// Sets the flags for the input
1113    pub fn flags(mut self, flags: InputTextFlags) -> Self {
1114        self.flags = flags;
1115        self
1116    }
1117
1118    /// Builds the double input widget
1119    pub fn build(self, value: &mut f64) -> bool {
1120        let label_ptr = self.ui.scratch_txt(&self.label);
1121        let format_ptr = self.ui.scratch_txt_opt(self.format.as_ref());
1122        let format_ptr = if format_ptr.is_null() {
1123            self.ui.scratch_txt("%.6f")
1124        } else {
1125            format_ptr
1126        };
1127
1128        unsafe {
1129            sys::igInputDouble(
1130                label_ptr,
1131                value as *mut f64,
1132                self.step,
1133                self.step_fast,
1134                format_ptr,
1135                self.flags.bits(),
1136            )
1137        }
1138    }
1139}
1140
1141// InputText Callback System
1142// =========================
1143
1144bitflags::bitflags! {
1145    /// Callback flags for InputText widgets
1146    #[repr(transparent)]
1147    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1148    pub struct InputTextCallback: u32 {
1149        /// Call user function on pressing TAB (for completion handling)
1150        const COMPLETION = sys::ImGuiInputTextFlags_CallbackCompletion as u32;
1151        /// Call user function on pressing Up/Down arrows (for history handling)
1152        const HISTORY = sys::ImGuiInputTextFlags_CallbackHistory as u32;
1153        /// Call user function every time. User code may query cursor position, modify text buffer.
1154        const ALWAYS = sys::ImGuiInputTextFlags_CallbackAlways as u32;
1155        /// Call user function to filter character.
1156        const CHAR_FILTER = sys::ImGuiInputTextFlags_CallbackCharFilter as u32;
1157        /// Callback on buffer edit (note that InputText already returns true on edit, the
1158        /// callback is useful mainly to manipulate the underlying buffer while focus is active)
1159        const EDIT = sys::ImGuiInputTextFlags_CallbackEdit as u32;
1160    }
1161}
1162
1163/// Direction for history navigation
1164#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1165pub enum HistoryDirection {
1166    /// Up arrow key pressed
1167    Up,
1168    /// Down arrow key pressed
1169    Down,
1170}
1171
1172/// This trait provides an interface which ImGui will call on InputText callbacks.
1173///
1174/// Each method is called *if and only if* the corresponding flag for each
1175/// method is passed to ImGui in the `callback` builder.
1176pub trait InputTextCallbackHandler {
1177    /// Filters a char -- returning a `None` means that the char is removed,
1178    /// and returning another char substitutes it out.
1179    ///
1180    /// To make ImGui run this callback, use [InputTextCallback::CHAR_FILTER].
1181    fn char_filter(&mut self, _c: char) -> Option<char> {
1182        None
1183    }
1184
1185    /// Called when the user presses the completion key (TAB by default).
1186    ///
1187    /// To make ImGui run this callback, use [InputTextCallback::COMPLETION].
1188    fn on_completion(&mut self, _data: TextCallbackData) {}
1189
1190    /// Called when the user presses Up/Down arrow keys for history navigation.
1191    ///
1192    /// To make ImGui run this callback, use [InputTextCallback::HISTORY].
1193    fn on_history(&mut self, _direction: HistoryDirection, _data: TextCallbackData) {}
1194
1195    /// Called every frame when the input text is active.
1196    ///
1197    /// To make ImGui run this callback, use [InputTextCallback::ALWAYS].
1198    fn on_always(&mut self, _data: TextCallbackData) {}
1199
1200    /// Called when the text buffer is edited.
1201    ///
1202    /// To make ImGui run this callback, use [InputTextCallback::EDIT].
1203    fn on_edit(&mut self, _data: TextCallbackData) {}
1204}
1205
1206/// This struct provides methods to edit the underlying text buffer that
1207/// Dear ImGui manipulates. Primarily, it gives [remove_chars](Self::remove_chars),
1208/// [insert_chars](Self::insert_chars), and mutable access to what text is selected.
1209pub struct TextCallbackData(*mut sys::ImGuiInputTextCallbackData);
1210
1211impl TextCallbackData {
1212    /// Creates the buffer.
1213    unsafe fn new(data: *mut sys::ImGuiInputTextCallbackData) -> Self {
1214        Self(data)
1215    }
1216
1217    /// Get a reference to the text callback buffer's str.
1218    pub fn str(&self) -> &str {
1219        unsafe {
1220            std::str::from_utf8(std::slice::from_raw_parts(
1221                (*(self.0)).Buf as *const _,
1222                (*(self.0)).BufTextLen as usize,
1223            ))
1224            .expect("internal imgui error -- it boofed a utf8")
1225        }
1226    }
1227
1228    /// Get the current cursor position
1229    pub fn cursor_pos(&self) -> usize {
1230        unsafe { (*(self.0)).CursorPos as usize }
1231    }
1232
1233    /// Set the cursor position
1234    pub fn set_cursor_pos(&mut self, pos: usize) {
1235        unsafe {
1236            (*(self.0)).CursorPos = pos as i32;
1237        }
1238    }
1239
1240    /// Get the selection start position
1241    pub fn selection_start(&self) -> usize {
1242        unsafe { (*(self.0)).SelectionStart as usize }
1243    }
1244
1245    /// Set the selection start position
1246    pub fn set_selection_start(&mut self, pos: usize) {
1247        unsafe {
1248            (*(self.0)).SelectionStart = pos as i32;
1249        }
1250    }
1251
1252    /// Get the selection end position
1253    pub fn selection_end(&self) -> usize {
1254        unsafe { (*(self.0)).SelectionEnd as usize }
1255    }
1256
1257    /// Set the selection end position
1258    pub fn set_selection_end(&mut self, pos: usize) {
1259        unsafe {
1260            (*(self.0)).SelectionEnd = pos as i32;
1261        }
1262    }
1263
1264    /// Select all text
1265    pub fn select_all(&mut self) {
1266        unsafe {
1267            (*(self.0)).SelectionStart = 0;
1268            (*(self.0)).SelectionEnd = (*(self.0)).BufTextLen;
1269        }
1270    }
1271
1272    /// Clear selection
1273    pub fn clear_selection(&mut self) {
1274        unsafe {
1275            (*(self.0)).SelectionStart = (*(self.0)).CursorPos;
1276            (*(self.0)).SelectionEnd = (*(self.0)).CursorPos;
1277        }
1278    }
1279
1280    /// Returns true if there is a selection
1281    pub fn has_selection(&self) -> bool {
1282        unsafe { (*(self.0)).SelectionStart != (*(self.0)).SelectionEnd }
1283    }
1284
1285    /// Delete characters in the range [pos, pos+bytes_count)
1286    pub fn remove_chars(&mut self, pos: usize, bytes_count: usize) {
1287        unsafe {
1288            sys::ImGuiInputTextCallbackData_DeleteChars(self.0, pos as i32, bytes_count as i32);
1289        }
1290    }
1291
1292    /// Insert text at the given position
1293    pub fn insert_chars(&mut self, pos: usize, text: &str) {
1294        let text_cstr = format!("{}\0", text);
1295        unsafe {
1296            sys::ImGuiInputTextCallbackData_InsertChars(
1297                self.0,
1298                pos as i32,
1299                text_cstr.as_ptr() as *const std::os::raw::c_char,
1300                text_cstr.as_ptr().add(text.len()) as *const std::os::raw::c_char,
1301            );
1302        }
1303    }
1304
1305    /// Gives access to the underlying byte array MUTABLY.
1306    ///
1307    /// ## Safety
1308    ///
1309    /// This is very unsafe, and the following invariants must be
1310    /// upheld:
1311    /// 1. Keep the data utf8 valid.
1312    /// 2. After editing the string, call [set_dirty].
1313    ///
1314    /// To truncate the string, please use [remove_chars]. To extend
1315    /// the string, please use [insert_chars] and [push_str].
1316    ///
1317    /// This function should have highly limited usage, but could be for
1318    /// editing certain characters in the buffer based on some external condition.
1319    ///
1320    /// [remove_chars]: Self::remove_chars
1321    /// [set_dirty]: Self::set_dirty
1322    /// [insert_chars]: Self::insert_chars
1323    /// [push_str]: Self::push_str
1324    pub unsafe fn str_as_bytes_mut(&mut self) -> &mut [u8] {
1325        unsafe {
1326            let str = std::str::from_utf8_mut(std::slice::from_raw_parts_mut(
1327                (*(self.0)).Buf as *const _ as *mut _,
1328                (*(self.0)).BufTextLen as usize,
1329            ))
1330            .expect("internal imgui error -- it boofed a utf8");
1331
1332            str.as_bytes_mut()
1333        }
1334    }
1335
1336    /// Sets the dirty flag on the text to imgui, indicating that
1337    /// it should reapply this string to its internal state.
1338    ///
1339    /// **NB:** You only need to use this method if you're using `[str_as_bytes_mut]`.
1340    /// If you use the helper methods [remove_chars] and [insert_chars],
1341    /// this will be set for you. However, this is no downside to setting
1342    /// the dirty flag spuriously except the minor CPU time imgui will spend.
1343    ///
1344    /// [str_as_bytes_mut]: Self::str_as_bytes_mut
1345    /// [remove_chars]: Self::remove_chars
1346    /// [insert_chars]: Self::insert_chars
1347    pub fn set_dirty(&mut self) {
1348        unsafe {
1349            (*(self.0)).BufDirty = true;
1350        }
1351    }
1352
1353    /// Returns the selected text directly. Note that if no text is selected,
1354    /// an empty str slice will be returned.
1355    pub fn selected(&self) -> &str {
1356        let start = self.selection_start().min(self.selection_end());
1357        let end = self.selection_start().max(self.selection_end());
1358        &self.str()[start..end]
1359    }
1360
1361    /// Pushes the given str to the end of this buffer. If this
1362    /// would require the String to resize, it will be resized.
1363    /// This is automatically handled.
1364    pub fn push_str(&mut self, text: &str) {
1365        let current_len = unsafe { (*(self.0)).BufTextLen as usize };
1366        self.insert_chars(current_len, text);
1367    }
1368}
1369
1370/// This is a ZST which implements InputTextCallbackHandler as a passthrough.
1371///
1372/// If you do not set a callback handler, this will be used (but will never
1373/// actually run, since you will not have passed imgui any flags).
1374pub struct PassthroughCallback;
1375impl InputTextCallbackHandler for PassthroughCallback {}
1376
1377/// This is our default callback function that routes ImGui callbacks to our trait methods.
1378extern "C" fn callback(data: *mut sys::ImGuiInputTextCallbackData) -> c_int {
1379    let event_flag = unsafe { InputTextFlags::from_bits_truncate((*data).EventFlag) };
1380    let buffer_ptr = unsafe { (*data).UserData as *mut String };
1381
1382    // Handle different callback types
1383    match event_flag {
1384        InputTextFlags::CALLBACK_RESIZE => {
1385            unsafe {
1386                let requested_size = (*data).BufSize as usize;
1387                let buffer = &mut *buffer_ptr;
1388
1389                // Confirm that we ARE working with our string
1390                debug_assert_eq!(buffer.as_ptr() as *const _, (*data).Buf);
1391
1392                if requested_size > buffer.capacity() {
1393                    let additional_bytes = requested_size - buffer.len();
1394
1395                    // Reserve more data
1396                    buffer.reserve(additional_bytes);
1397
1398                    (*data).Buf = buffer.as_mut_ptr() as *mut _;
1399                    (*data).BufDirty = true;
1400                }
1401            }
1402        }
1403        _ => {
1404            // For other callbacks, we need the actual callback handler
1405            // This will only work for non-PassthroughCallback types
1406            // PassthroughCallback should never trigger these callbacks
1407        }
1408    }
1409
1410    0
1411}
1412
1413/// Builder for an input scalar widget.
1414#[must_use]
1415pub struct InputScalar<'ui, 'p, T, L, F = &'static str> {
1416    value: &'p mut T,
1417    label: L,
1418    step: Option<T>,
1419    step_fast: Option<T>,
1420    display_format: Option<F>,
1421    flags: InputTextFlags,
1422    ui: &'ui Ui,
1423}
1424
1425impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind> InputScalar<'ui, 'p, T, L> {
1426    /// Constructs a new input scalar builder.
1427    #[doc(alias = "InputScalar")]
1428    pub fn new(ui: &'ui Ui, label: L, value: &'p mut T) -> Self {
1429        InputScalar {
1430            value,
1431            label,
1432            step: None,
1433            step_fast: None,
1434            display_format: None,
1435            flags: InputTextFlags::empty(),
1436            ui,
1437        }
1438    }
1439}
1440
1441impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind, F: AsRef<str>> InputScalar<'ui, 'p, T, L, F> {
1442    /// Sets the display format using *a C-style printf string*
1443    pub fn display_format<F2: AsRef<str>>(
1444        self,
1445        display_format: F2,
1446    ) -> InputScalar<'ui, 'p, T, L, F2> {
1447        InputScalar {
1448            value: self.value,
1449            label: self.label,
1450            step: self.step,
1451            step_fast: self.step_fast,
1452            display_format: Some(display_format),
1453            flags: self.flags,
1454            ui: self.ui,
1455        }
1456    }
1457
1458    /// Sets the step value for the input
1459    #[inline]
1460    pub fn step(mut self, value: T) -> Self {
1461        self.step = Some(value);
1462        self
1463    }
1464
1465    /// Sets the fast step value for the input
1466    #[inline]
1467    pub fn step_fast(mut self, value: T) -> Self {
1468        self.step_fast = Some(value);
1469        self
1470    }
1471
1472    /// Sets the input text flags
1473    #[inline]
1474    pub fn flags(mut self, flags: InputTextFlags) -> Self {
1475        self.flags = flags;
1476        self
1477    }
1478
1479    /// Builds an input scalar that is bound to the given value.
1480    ///
1481    /// Returns true if the value was changed.
1482    pub fn build(self) -> bool {
1483        unsafe {
1484            let (one, two) = self
1485                .ui
1486                .scratch_txt_with_opt(self.label, self.display_format);
1487
1488            sys::igInputScalar(
1489                one,
1490                T::KIND as i32,
1491                self.value as *mut T as *mut c_void,
1492                self.step
1493                    .as_ref()
1494                    .map(|step| step as *const T)
1495                    .unwrap_or(ptr::null()) as *const c_void,
1496                self.step_fast
1497                    .as_ref()
1498                    .map(|step| step as *const T)
1499                    .unwrap_or(ptr::null()) as *const c_void,
1500                two,
1501                self.flags.bits() as i32,
1502            )
1503        }
1504    }
1505}
1506
1507/// Builder for an input scalar array widget.
1508#[must_use]
1509pub struct InputScalarN<'ui, 'p, T, L, F = &'static str> {
1510    values: &'p mut [T],
1511    label: L,
1512    step: Option<T>,
1513    step_fast: Option<T>,
1514    display_format: Option<F>,
1515    flags: InputTextFlags,
1516    ui: &'ui Ui,
1517}
1518
1519impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind> InputScalarN<'ui, 'p, T, L> {
1520    /// Constructs a new input scalar array builder.
1521    #[doc(alias = "InputScalarN")]
1522    pub fn new(ui: &'ui Ui, label: L, values: &'p mut [T]) -> Self {
1523        InputScalarN {
1524            values,
1525            label,
1526            step: None,
1527            step_fast: None,
1528            display_format: None,
1529            flags: InputTextFlags::empty(),
1530            ui,
1531        }
1532    }
1533}
1534
1535impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind, F: AsRef<str>> InputScalarN<'ui, 'p, T, L, F> {
1536    /// Sets the display format using *a C-style printf string*
1537    pub fn display_format<F2: AsRef<str>>(
1538        self,
1539        display_format: F2,
1540    ) -> InputScalarN<'ui, 'p, T, L, F2> {
1541        InputScalarN {
1542            values: self.values,
1543            label: self.label,
1544            step: self.step,
1545            step_fast: self.step_fast,
1546            display_format: Some(display_format),
1547            flags: self.flags,
1548            ui: self.ui,
1549        }
1550    }
1551
1552    /// Sets the step value for the input
1553    #[inline]
1554    pub fn step(mut self, value: T) -> Self {
1555        self.step = Some(value);
1556        self
1557    }
1558
1559    /// Sets the fast step value for the input
1560    #[inline]
1561    pub fn step_fast(mut self, value: T) -> Self {
1562        self.step_fast = Some(value);
1563        self
1564    }
1565
1566    /// Sets the input text flags
1567    #[inline]
1568    pub fn flags(mut self, flags: InputTextFlags) -> Self {
1569        self.flags = flags;
1570        self
1571    }
1572
1573    /// Builds a horizontal array of multiple input scalars attached to the given slice.
1574    ///
1575    /// Returns true if any value was changed.
1576    pub fn build(self) -> bool {
1577        unsafe {
1578            let (one, two) = self
1579                .ui
1580                .scratch_txt_with_opt(self.label, self.display_format);
1581
1582            sys::igInputScalarN(
1583                one,
1584                T::KIND as i32,
1585                self.values.as_mut_ptr() as *mut c_void,
1586                self.values.len() as i32,
1587                self.step
1588                    .as_ref()
1589                    .map(|step| step as *const T)
1590                    .unwrap_or(ptr::null()) as *const c_void,
1591                self.step_fast
1592                    .as_ref()
1593                    .map(|step| step as *const T)
1594                    .unwrap_or(ptr::null()) as *const c_void,
1595                two,
1596                self.flags.bits() as i32,
1597            )
1598        }
1599    }
1600}
1601
1602/// Builder for a 2-component float input widget.
1603#[must_use]
1604pub struct InputFloat2<'ui, 'p, L, F = &'static str> {
1605    label: L,
1606    value: &'p mut [f32; 2],
1607    display_format: Option<F>,
1608    flags: InputTextFlags,
1609    ui: &'ui Ui,
1610}
1611
1612impl<'ui, 'p, L: AsRef<str>> InputFloat2<'ui, 'p, L> {
1613    /// Constructs a new input float2 builder.
1614    #[doc(alias = "InputFloat2")]
1615    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 2]) -> Self {
1616        InputFloat2 {
1617            label,
1618            value,
1619            display_format: None,
1620            flags: InputTextFlags::empty(),
1621            ui,
1622        }
1623    }
1624}
1625
1626impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat2<'ui, 'p, L, F> {
1627    /// Sets the display format using *a C-style printf string*
1628    pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat2<'ui, 'p, L, F2> {
1629        InputFloat2 {
1630            label: self.label,
1631            value: self.value,
1632            display_format: Some(display_format),
1633            flags: self.flags,
1634            ui: self.ui,
1635        }
1636    }
1637
1638    /// Sets the input text flags
1639    #[inline]
1640    pub fn flags(mut self, flags: InputTextFlags) -> Self {
1641        self.flags = flags;
1642        self
1643    }
1644
1645    /// Builds the input float2 widget.
1646    ///
1647    /// Returns true if any value was changed.
1648    pub fn build(self) -> bool {
1649        unsafe {
1650            let (one, two) = self
1651                .ui
1652                .scratch_txt_with_opt(self.label, self.display_format);
1653
1654            sys::igInputFloat2(one, self.value.as_mut_ptr(), two, self.flags.bits() as i32)
1655        }
1656    }
1657}
1658
1659/// Builder for a 3-component float input widget.
1660#[must_use]
1661pub struct InputFloat3<'ui, 'p, L, F = &'static str> {
1662    label: L,
1663    value: &'p mut [f32; 3],
1664    display_format: Option<F>,
1665    flags: InputTextFlags,
1666    ui: &'ui Ui,
1667}
1668
1669impl<'ui, 'p, L: AsRef<str>> InputFloat3<'ui, 'p, L> {
1670    /// Constructs a new input float3 builder.
1671    #[doc(alias = "InputFloat3")]
1672    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 3]) -> Self {
1673        InputFloat3 {
1674            label,
1675            value,
1676            display_format: None,
1677            flags: InputTextFlags::empty(),
1678            ui,
1679        }
1680    }
1681}
1682
1683impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat3<'ui, 'p, L, F> {
1684    /// Sets the display format using *a C-style printf string*
1685    pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat3<'ui, 'p, L, F2> {
1686        InputFloat3 {
1687            label: self.label,
1688            value: self.value,
1689            display_format: Some(display_format),
1690            flags: self.flags,
1691            ui: self.ui,
1692        }
1693    }
1694
1695    /// Sets the input text flags
1696    #[inline]
1697    pub fn flags(mut self, flags: InputTextFlags) -> Self {
1698        self.flags = flags;
1699        self
1700    }
1701
1702    /// Builds the input float3 widget.
1703    ///
1704    /// Returns true if any value was changed.
1705    pub fn build(self) -> bool {
1706        unsafe {
1707            let (one, two) = self
1708                .ui
1709                .scratch_txt_with_opt(self.label, self.display_format);
1710
1711            sys::igInputFloat3(one, self.value.as_mut_ptr(), two, self.flags.bits() as i32)
1712        }
1713    }
1714}
1715
1716/// Builder for a 4-component float input widget.
1717#[must_use]
1718pub struct InputFloat4<'ui, 'p, L, F = &'static str> {
1719    label: L,
1720    value: &'p mut [f32; 4],
1721    display_format: Option<F>,
1722    flags: InputTextFlags,
1723    ui: &'ui Ui,
1724}
1725
1726impl<'ui, 'p, L: AsRef<str>> InputFloat4<'ui, 'p, L> {
1727    /// Constructs a new input float4 builder.
1728    #[doc(alias = "InputFloat4")]
1729    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 4]) -> Self {
1730        InputFloat4 {
1731            label,
1732            value,
1733            display_format: None,
1734            flags: InputTextFlags::empty(),
1735            ui,
1736        }
1737    }
1738}
1739
1740impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat4<'ui, 'p, L, F> {
1741    /// Sets the display format using *a C-style printf string*
1742    pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat4<'ui, 'p, L, F2> {
1743        InputFloat4 {
1744            label: self.label,
1745            value: self.value,
1746            display_format: Some(display_format),
1747            flags: self.flags,
1748            ui: self.ui,
1749        }
1750    }
1751
1752    /// Sets the input text flags
1753    #[inline]
1754    pub fn flags(mut self, flags: InputTextFlags) -> Self {
1755        self.flags = flags;
1756        self
1757    }
1758
1759    /// Builds the input float4 widget.
1760    ///
1761    /// Returns true if any value was changed.
1762    pub fn build(self) -> bool {
1763        unsafe {
1764            let (one, two) = self
1765                .ui
1766                .scratch_txt_with_opt(self.label, self.display_format);
1767
1768            sys::igInputFloat4(one, self.value.as_mut_ptr(), two, self.flags.bits() as i32)
1769        }
1770    }
1771}
1772
1773/// Builder for a 2-component int input widget.
1774#[must_use]
1775pub struct InputInt2<'ui, 'p, L> {
1776    label: L,
1777    value: &'p mut [i32; 2],
1778    flags: InputTextFlags,
1779    ui: &'ui Ui,
1780}
1781
1782impl<'ui, 'p, L: AsRef<str>> InputInt2<'ui, 'p, L> {
1783    /// Constructs a new input int2 builder.
1784    #[doc(alias = "InputInt2")]
1785    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 2]) -> Self {
1786        InputInt2 {
1787            label,
1788            value,
1789            flags: InputTextFlags::empty(),
1790            ui,
1791        }
1792    }
1793
1794    /// Sets the input text flags
1795    #[inline]
1796    pub fn flags(mut self, flags: InputTextFlags) -> Self {
1797        self.flags = flags;
1798        self
1799    }
1800
1801    /// Builds the input int2 widget.
1802    ///
1803    /// Returns true if any value was changed.
1804    pub fn build(self) -> bool {
1805        unsafe {
1806            let label_cstr = self.ui.scratch_txt(self.label);
1807
1808            sys::igInputInt2(
1809                label_cstr,
1810                self.value.as_mut_ptr(),
1811                self.flags.bits() as i32,
1812            )
1813        }
1814    }
1815}
1816
1817/// Builder for a 3-component int input widget.
1818#[must_use]
1819pub struct InputInt3<'ui, 'p, L> {
1820    label: L,
1821    value: &'p mut [i32; 3],
1822    flags: InputTextFlags,
1823    ui: &'ui Ui,
1824}
1825
1826impl<'ui, 'p, L: AsRef<str>> InputInt3<'ui, 'p, L> {
1827    /// Constructs a new input int3 builder.
1828    #[doc(alias = "InputInt3")]
1829    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 3]) -> Self {
1830        InputInt3 {
1831            label,
1832            value,
1833            flags: InputTextFlags::empty(),
1834            ui,
1835        }
1836    }
1837
1838    /// Sets the input text flags
1839    #[inline]
1840    pub fn flags(mut self, flags: InputTextFlags) -> Self {
1841        self.flags = flags;
1842        self
1843    }
1844
1845    /// Builds the input int3 widget.
1846    ///
1847    /// Returns true if any value was changed.
1848    pub fn build(self) -> bool {
1849        unsafe {
1850            let label_cstr = self.ui.scratch_txt(self.label);
1851
1852            sys::igInputInt3(
1853                label_cstr,
1854                self.value.as_mut_ptr(),
1855                self.flags.bits() as i32,
1856            )
1857        }
1858    }
1859}
1860
1861/// Builder for a 4-component int input widget.
1862#[must_use]
1863pub struct InputInt4<'ui, 'p, L> {
1864    label: L,
1865    value: &'p mut [i32; 4],
1866    flags: InputTextFlags,
1867    ui: &'ui Ui,
1868}
1869
1870impl<'ui, 'p, L: AsRef<str>> InputInt4<'ui, 'p, L> {
1871    /// Constructs a new input int4 builder.
1872    #[doc(alias = "InputInt4")]
1873    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 4]) -> Self {
1874        InputInt4 {
1875            label,
1876            value,
1877            flags: InputTextFlags::empty(),
1878            ui,
1879        }
1880    }
1881
1882    /// Sets the input text flags
1883    #[inline]
1884    pub fn flags(mut self, flags: InputTextFlags) -> Self {
1885        self.flags = flags;
1886        self
1887    }
1888
1889    /// Builds the input int4 widget.
1890    ///
1891    /// Returns true if any value was changed.
1892    pub fn build(self) -> bool {
1893        unsafe {
1894            let label_cstr = self.ui.scratch_txt(self.label);
1895
1896            sys::igInputInt4(
1897                label_cstr,
1898                self.value.as_mut_ptr(),
1899                self.flags.bits() as i32,
1900            )
1901        }
1902    }
1903}