Skip to main content

dear_imgui_rs/widget/input/
numeric.rs

1use crate::InputTextFlags;
2use crate::internal::DataTypeKind;
3use crate::sys;
4use crate::ui::Ui;
5use std::borrow::Cow;
6use std::ffi::c_void;
7use std::ptr;
8
9/// Builder for integer input widget
10#[derive(Debug)]
11#[must_use]
12pub struct InputInt<'ui> {
13    ui: &'ui Ui,
14    label: Cow<'ui, str>,
15    step: i32,
16    step_fast: i32,
17    flags: InputTextFlags,
18}
19
20impl<'ui> InputInt<'ui> {
21    /// Creates a new integer input builder
22    pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>) -> Self {
23        Self {
24            ui,
25            label: label.into(),
26            step: 1,
27            step_fast: 100,
28            flags: InputTextFlags::NONE,
29        }
30    }
31
32    /// Sets the step value
33    pub fn step(mut self, step: i32) -> Self {
34        self.step = step;
35        self
36    }
37
38    /// Sets the fast step value
39    pub fn step_fast(mut self, step_fast: i32) -> Self {
40        self.step_fast = step_fast;
41        self
42    }
43
44    /// Sets the flags for the input
45    pub fn flags(mut self, flags: InputTextFlags) -> Self {
46        self.flags = flags;
47        self
48    }
49
50    /// Builds the integer input widget
51    pub fn build(self, value: &mut i32) -> bool {
52        let label_ptr = self.ui.scratch_txt(self.label.as_ref());
53        unsafe {
54            sys::igInputInt(
55                label_ptr,
56                value as *mut i32,
57                self.step,
58                self.step_fast,
59                self.flags.raw(),
60            )
61        }
62    }
63}
64
65/// Builder for float input widget
66#[derive(Debug)]
67#[must_use]
68pub struct InputFloat<'ui> {
69    ui: &'ui Ui,
70    label: Cow<'ui, str>,
71    step: f32,
72    step_fast: f32,
73    format: Option<Cow<'ui, str>>,
74    flags: InputTextFlags,
75}
76
77impl<'ui> InputFloat<'ui> {
78    /// Creates a new float input builder
79    pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>) -> Self {
80        Self {
81            ui,
82            label: label.into(),
83            step: 0.0,
84            step_fast: 0.0,
85            format: None,
86            flags: InputTextFlags::NONE,
87        }
88    }
89
90    /// Sets the step value
91    pub fn step(mut self, step: f32) -> Self {
92        self.step = step;
93        self
94    }
95
96    /// Sets the fast step value
97    pub fn step_fast(mut self, step_fast: f32) -> Self {
98        self.step_fast = step_fast;
99        self
100    }
101
102    /// Sets the display format
103    pub fn format(mut self, format: impl Into<Cow<'ui, str>>) -> Self {
104        self.format = Some(format.into());
105        self
106    }
107
108    /// Sets the flags for the input
109    pub fn flags(mut self, flags: InputTextFlags) -> Self {
110        self.flags = flags;
111        self
112    }
113
114    /// Builds the float input widget
115    pub fn build(self, value: &mut f32) -> bool {
116        let format = self.format.as_deref().unwrap_or("%.3f");
117        let (label_ptr, format_ptr) = self.ui.scratch_txt_two(self.label.as_ref(), format);
118
119        unsafe {
120            sys::igInputFloat(
121                label_ptr,
122                value as *mut f32,
123                self.step,
124                self.step_fast,
125                format_ptr,
126                self.flags.raw(),
127            )
128        }
129    }
130}
131
132/// Builder for double input widget
133#[derive(Debug)]
134#[must_use]
135pub struct InputDouble<'ui> {
136    ui: &'ui Ui,
137    label: Cow<'ui, str>,
138    step: f64,
139    step_fast: f64,
140    format: Option<Cow<'ui, str>>,
141    flags: InputTextFlags,
142}
143
144impl<'ui> InputDouble<'ui> {
145    /// Creates a new double input builder
146    pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>) -> Self {
147        Self {
148            ui,
149            label: label.into(),
150            step: 0.0,
151            step_fast: 0.0,
152            format: None,
153            flags: InputTextFlags::NONE,
154        }
155    }
156
157    /// Sets the step value
158    pub fn step(mut self, step: f64) -> Self {
159        self.step = step;
160        self
161    }
162
163    /// Sets the fast step value
164    pub fn step_fast(mut self, step_fast: f64) -> Self {
165        self.step_fast = step_fast;
166        self
167    }
168
169    /// Sets the display format
170    pub fn format(mut self, format: impl Into<Cow<'ui, str>>) -> Self {
171        self.format = Some(format.into());
172        self
173    }
174
175    /// Sets the flags for the input
176    pub fn flags(mut self, flags: InputTextFlags) -> Self {
177        self.flags = flags;
178        self
179    }
180
181    /// Builds the double input widget
182    pub fn build(self, value: &mut f64) -> bool {
183        let format = self.format.as_deref().unwrap_or("%.6f");
184        let (label_ptr, format_ptr) = self.ui.scratch_txt_two(self.label.as_ref(), format);
185
186        unsafe {
187            sys::igInputDouble(
188                label_ptr,
189                value as *mut f64,
190                self.step,
191                self.step_fast,
192                format_ptr,
193                self.flags.raw(),
194            )
195        }
196    }
197}
198
199/// Builder for an input scalar widget.
200#[must_use]
201pub struct InputScalar<'ui, 'p, T, L, F = &'static str> {
202    value: &'p mut T,
203    label: L,
204    step: Option<T>,
205    step_fast: Option<T>,
206    display_format: Option<F>,
207    flags: InputTextFlags,
208    ui: &'ui Ui,
209}
210
211impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind> InputScalar<'ui, 'p, T, L> {
212    /// Constructs a new input scalar builder.
213    #[doc(alias = "InputScalar")]
214    pub fn new(ui: &'ui Ui, label: L, value: &'p mut T) -> Self {
215        InputScalar {
216            value,
217            label,
218            step: None,
219            step_fast: None,
220            display_format: None,
221            flags: InputTextFlags::empty(),
222            ui,
223        }
224    }
225}
226
227impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind, F: AsRef<str>> InputScalar<'ui, 'p, T, L, F> {
228    /// Sets the display format using *a C-style printf string*
229    pub fn display_format<F2: AsRef<str>>(
230        self,
231        display_format: F2,
232    ) -> InputScalar<'ui, 'p, T, L, F2> {
233        InputScalar {
234            value: self.value,
235            label: self.label,
236            step: self.step,
237            step_fast: self.step_fast,
238            display_format: Some(display_format),
239            flags: self.flags,
240            ui: self.ui,
241        }
242    }
243
244    /// Sets the step value for the input
245    #[inline]
246    pub fn step(mut self, value: T) -> Self {
247        self.step = Some(value);
248        self
249    }
250
251    /// Sets the fast step value for the input
252    #[inline]
253    pub fn step_fast(mut self, value: T) -> Self {
254        self.step_fast = Some(value);
255        self
256    }
257
258    /// Sets the input text flags
259    #[inline]
260    pub fn flags(mut self, flags: InputTextFlags) -> Self {
261        self.flags = flags;
262        self
263    }
264
265    /// Builds an input scalar that is bound to the given value.
266    ///
267    /// Returns true if the value was changed.
268    pub fn build(self) -> bool {
269        unsafe {
270            let (one, two) = self
271                .ui
272                .scratch_txt_with_opt(self.label, self.display_format);
273
274            sys::igInputScalar(
275                one,
276                T::KIND as i32,
277                self.value as *mut T as *mut c_void,
278                self.step
279                    .as_ref()
280                    .map(|step| step as *const T)
281                    .unwrap_or(ptr::null()) as *const c_void,
282                self.step_fast
283                    .as_ref()
284                    .map(|step| step as *const T)
285                    .unwrap_or(ptr::null()) as *const c_void,
286                two,
287                self.flags.raw(),
288            )
289        }
290    }
291}
292
293/// Builder for an input scalar array widget.
294#[must_use]
295pub struct InputScalarN<'ui, 'p, T, L, F = &'static str> {
296    values: &'p mut [T],
297    label: L,
298    step: Option<T>,
299    step_fast: Option<T>,
300    display_format: Option<F>,
301    flags: InputTextFlags,
302    ui: &'ui Ui,
303}
304
305impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind> InputScalarN<'ui, 'p, T, L> {
306    /// Constructs a new input scalar array builder.
307    #[doc(alias = "InputScalarN")]
308    pub fn new(ui: &'ui Ui, label: L, values: &'p mut [T]) -> Self {
309        InputScalarN {
310            values,
311            label,
312            step: None,
313            step_fast: None,
314            display_format: None,
315            flags: InputTextFlags::empty(),
316            ui,
317        }
318    }
319}
320
321impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind, F: AsRef<str>> InputScalarN<'ui, 'p, T, L, F> {
322    /// Sets the display format using *a C-style printf string*
323    pub fn display_format<F2: AsRef<str>>(
324        self,
325        display_format: F2,
326    ) -> InputScalarN<'ui, 'p, T, L, F2> {
327        InputScalarN {
328            values: self.values,
329            label: self.label,
330            step: self.step,
331            step_fast: self.step_fast,
332            display_format: Some(display_format),
333            flags: self.flags,
334            ui: self.ui,
335        }
336    }
337
338    /// Sets the step value for the input
339    #[inline]
340    pub fn step(mut self, value: T) -> Self {
341        self.step = Some(value);
342        self
343    }
344
345    /// Sets the fast step value for the input
346    #[inline]
347    pub fn step_fast(mut self, value: T) -> Self {
348        self.step_fast = Some(value);
349        self
350    }
351
352    /// Sets the input text flags
353    #[inline]
354    pub fn flags(mut self, flags: InputTextFlags) -> Self {
355        self.flags = flags;
356        self
357    }
358
359    /// Builds a horizontal array of multiple input scalars attached to the given slice.
360    ///
361    /// Returns true if any value was changed.
362    pub fn build(self) -> bool {
363        let count = match i32::try_from(self.values.len()) {
364            Ok(n) => n,
365            Err(_) => return false,
366        };
367        unsafe {
368            let (one, two) = self
369                .ui
370                .scratch_txt_with_opt(self.label, self.display_format);
371
372            sys::igInputScalarN(
373                one,
374                T::KIND as i32,
375                self.values.as_mut_ptr() as *mut c_void,
376                count,
377                self.step
378                    .as_ref()
379                    .map(|step| step as *const T)
380                    .unwrap_or(ptr::null()) as *const c_void,
381                self.step_fast
382                    .as_ref()
383                    .map(|step| step as *const T)
384                    .unwrap_or(ptr::null()) as *const c_void,
385                two,
386                self.flags.raw(),
387            )
388        }
389    }
390}
391
392/// Builder for a 2-component float input widget.
393#[must_use]
394pub struct InputFloat2<'ui, 'p, L, F = &'static str> {
395    label: L,
396    value: &'p mut [f32; 2],
397    display_format: Option<F>,
398    flags: InputTextFlags,
399    ui: &'ui Ui,
400}
401
402impl<'ui, 'p, L: AsRef<str>> InputFloat2<'ui, 'p, L> {
403    /// Constructs a new input float2 builder.
404    #[doc(alias = "InputFloat2")]
405    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 2]) -> Self {
406        InputFloat2 {
407            label,
408            value,
409            display_format: None,
410            flags: InputTextFlags::empty(),
411            ui,
412        }
413    }
414}
415
416impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat2<'ui, 'p, L, F> {
417    /// Sets the display format using *a C-style printf string*
418    pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat2<'ui, 'p, L, F2> {
419        InputFloat2 {
420            label: self.label,
421            value: self.value,
422            display_format: Some(display_format),
423            flags: self.flags,
424            ui: self.ui,
425        }
426    }
427
428    /// Sets the input text flags
429    #[inline]
430    pub fn flags(mut self, flags: InputTextFlags) -> Self {
431        self.flags = flags;
432        self
433    }
434
435    /// Builds the input float2 widget.
436    ///
437    /// Returns true if any value was changed.
438    pub fn build(self) -> bool {
439        unsafe {
440            let (one, two) = self
441                .ui
442                .scratch_txt_with_opt(self.label, self.display_format);
443
444            sys::igInputFloat2(one, self.value.as_mut_ptr(), two, self.flags.raw())
445        }
446    }
447}
448
449/// Builder for a 3-component float input widget.
450#[must_use]
451pub struct InputFloat3<'ui, 'p, L, F = &'static str> {
452    label: L,
453    value: &'p mut [f32; 3],
454    display_format: Option<F>,
455    flags: InputTextFlags,
456    ui: &'ui Ui,
457}
458
459impl<'ui, 'p, L: AsRef<str>> InputFloat3<'ui, 'p, L> {
460    /// Constructs a new input float3 builder.
461    #[doc(alias = "InputFloat3")]
462    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 3]) -> Self {
463        InputFloat3 {
464            label,
465            value,
466            display_format: None,
467            flags: InputTextFlags::empty(),
468            ui,
469        }
470    }
471}
472
473impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat3<'ui, 'p, L, F> {
474    /// Sets the display format using *a C-style printf string*
475    pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat3<'ui, 'p, L, F2> {
476        InputFloat3 {
477            label: self.label,
478            value: self.value,
479            display_format: Some(display_format),
480            flags: self.flags,
481            ui: self.ui,
482        }
483    }
484
485    /// Sets the input text flags
486    #[inline]
487    pub fn flags(mut self, flags: InputTextFlags) -> Self {
488        self.flags = flags;
489        self
490    }
491
492    /// Builds the input float3 widget.
493    ///
494    /// Returns true if any value was changed.
495    pub fn build(self) -> bool {
496        unsafe {
497            let (one, two) = self
498                .ui
499                .scratch_txt_with_opt(self.label, self.display_format);
500
501            sys::igInputFloat3(one, self.value.as_mut_ptr(), two, self.flags.raw())
502        }
503    }
504}
505
506/// Builder for a 4-component float input widget.
507#[must_use]
508pub struct InputFloat4<'ui, 'p, L, F = &'static str> {
509    label: L,
510    value: &'p mut [f32; 4],
511    display_format: Option<F>,
512    flags: InputTextFlags,
513    ui: &'ui Ui,
514}
515
516impl<'ui, 'p, L: AsRef<str>> InputFloat4<'ui, 'p, L> {
517    /// Constructs a new input float4 builder.
518    #[doc(alias = "InputFloat4")]
519    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 4]) -> Self {
520        InputFloat4 {
521            label,
522            value,
523            display_format: None,
524            flags: InputTextFlags::empty(),
525            ui,
526        }
527    }
528}
529
530impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat4<'ui, 'p, L, F> {
531    /// Sets the display format using *a C-style printf string*
532    pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat4<'ui, 'p, L, F2> {
533        InputFloat4 {
534            label: self.label,
535            value: self.value,
536            display_format: Some(display_format),
537            flags: self.flags,
538            ui: self.ui,
539        }
540    }
541
542    /// Sets the input text flags
543    #[inline]
544    pub fn flags(mut self, flags: InputTextFlags) -> Self {
545        self.flags = flags;
546        self
547    }
548
549    /// Builds the input float4 widget.
550    ///
551    /// Returns true if any value was changed.
552    pub fn build(self) -> bool {
553        unsafe {
554            let (one, two) = self
555                .ui
556                .scratch_txt_with_opt(self.label, self.display_format);
557
558            sys::igInputFloat4(one, self.value.as_mut_ptr(), two, self.flags.raw())
559        }
560    }
561}
562
563/// Builder for a 2-component int input widget.
564#[must_use]
565pub struct InputInt2<'ui, 'p, L> {
566    label: L,
567    value: &'p mut [i32; 2],
568    flags: InputTextFlags,
569    ui: &'ui Ui,
570}
571
572impl<'ui, 'p, L: AsRef<str>> InputInt2<'ui, 'p, L> {
573    /// Constructs a new input int2 builder.
574    #[doc(alias = "InputInt2")]
575    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 2]) -> Self {
576        InputInt2 {
577            label,
578            value,
579            flags: InputTextFlags::empty(),
580            ui,
581        }
582    }
583
584    /// Sets the input text flags
585    #[inline]
586    pub fn flags(mut self, flags: InputTextFlags) -> Self {
587        self.flags = flags;
588        self
589    }
590
591    /// Builds the input int2 widget.
592    ///
593    /// Returns true if any value was changed.
594    pub fn build(self) -> bool {
595        unsafe {
596            let label_cstr = self.ui.scratch_txt(self.label);
597
598            sys::igInputInt2(label_cstr, self.value.as_mut_ptr(), self.flags.raw())
599        }
600    }
601}
602
603/// Builder for a 3-component int input widget.
604#[must_use]
605pub struct InputInt3<'ui, 'p, L> {
606    label: L,
607    value: &'p mut [i32; 3],
608    flags: InputTextFlags,
609    ui: &'ui Ui,
610}
611
612impl<'ui, 'p, L: AsRef<str>> InputInt3<'ui, 'p, L> {
613    /// Constructs a new input int3 builder.
614    #[doc(alias = "InputInt3")]
615    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 3]) -> Self {
616        InputInt3 {
617            label,
618            value,
619            flags: InputTextFlags::empty(),
620            ui,
621        }
622    }
623
624    /// Sets the input text flags
625    #[inline]
626    pub fn flags(mut self, flags: InputTextFlags) -> Self {
627        self.flags = flags;
628        self
629    }
630
631    /// Builds the input int3 widget.
632    ///
633    /// Returns true if any value was changed.
634    pub fn build(self) -> bool {
635        unsafe {
636            let label_cstr = self.ui.scratch_txt(self.label);
637
638            sys::igInputInt3(label_cstr, self.value.as_mut_ptr(), self.flags.raw())
639        }
640    }
641}
642
643/// Builder for a 4-component int input widget.
644#[must_use]
645pub struct InputInt4<'ui, 'p, L> {
646    label: L,
647    value: &'p mut [i32; 4],
648    flags: InputTextFlags,
649    ui: &'ui Ui,
650}
651
652impl<'ui, 'p, L: AsRef<str>> InputInt4<'ui, 'p, L> {
653    /// Constructs a new input int4 builder.
654    #[doc(alias = "InputInt4")]
655    pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 4]) -> Self {
656        InputInt4 {
657            label,
658            value,
659            flags: InputTextFlags::empty(),
660            ui,
661        }
662    }
663
664    /// Sets the input text flags
665    #[inline]
666    pub fn flags(mut self, flags: InputTextFlags) -> Self {
667        self.flags = flags;
668        self
669    }
670
671    /// Builds the input int4 widget.
672    ///
673    /// Returns true if any value was changed.
674    pub fn build(self) -> bool {
675        unsafe {
676            let label_cstr = self.ui.scratch_txt(self.label);
677
678            sys::igInputInt4(label_cstr, self.value.as_mut_ptr(), self.flags.raw())
679        }
680    }
681}
682
683#[cfg(test)]
684mod tests {
685    use super::super::{zero_string_new_capacity, zero_string_spare_capacity};
686
687    #[test]
688    fn zero_string_spare_capacity_writes_nul_bytes() {
689        let mut s = String::with_capacity(16);
690        s.push_str("abc");
691        let len = s.len();
692        let cap = s.capacity();
693
694        zero_string_spare_capacity(&mut s);
695
696        unsafe {
697            let bytes = std::slice::from_raw_parts(s.as_ptr(), cap);
698            assert_eq!(&bytes[..len], b"abc");
699            assert!(bytes[len..].iter().all(|&b| b == 0));
700        }
701    }
702
703    #[test]
704    fn zero_string_new_capacity_writes_new_region() {
705        let mut s = String::with_capacity(4);
706        s.push_str("abc");
707        let old_cap = s.capacity();
708
709        s.reserve(64);
710        let new_cap = s.capacity();
711        assert!(new_cap > old_cap);
712
713        zero_string_new_capacity(&mut s, old_cap);
714
715        unsafe {
716            let tail = std::slice::from_raw_parts(s.as_ptr().add(old_cap), new_cap - old_cap);
717            assert!(tail.iter().all(|&b| b == 0));
718        }
719    }
720}