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#[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 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 pub fn step(mut self, step: i32) -> Self {
34 self.step = step;
35 self
36 }
37
38 pub fn step_fast(mut self, step_fast: i32) -> Self {
40 self.step_fast = step_fast;
41 self
42 }
43
44 pub fn flags(mut self, flags: InputTextFlags) -> Self {
46 self.flags = flags;
47 self
48 }
49
50 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#[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 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 pub fn step(mut self, step: f32) -> Self {
92 self.step = step;
93 self
94 }
95
96 pub fn step_fast(mut self, step_fast: f32) -> Self {
98 self.step_fast = step_fast;
99 self
100 }
101
102 pub fn format(mut self, format: impl Into<Cow<'ui, str>>) -> Self {
104 self.format = Some(format.into());
105 self
106 }
107
108 pub fn flags(mut self, flags: InputTextFlags) -> Self {
110 self.flags = flags;
111 self
112 }
113
114 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#[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 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 pub fn step(mut self, step: f64) -> Self {
159 self.step = step;
160 self
161 }
162
163 pub fn step_fast(mut self, step_fast: f64) -> Self {
165 self.step_fast = step_fast;
166 self
167 }
168
169 pub fn format(mut self, format: impl Into<Cow<'ui, str>>) -> Self {
171 self.format = Some(format.into());
172 self
173 }
174
175 pub fn flags(mut self, flags: InputTextFlags) -> Self {
177 self.flags = flags;
178 self
179 }
180
181 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#[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 #[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 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 #[inline]
246 pub fn step(mut self, value: T) -> Self {
247 self.step = Some(value);
248 self
249 }
250
251 #[inline]
253 pub fn step_fast(mut self, value: T) -> Self {
254 self.step_fast = Some(value);
255 self
256 }
257
258 #[inline]
260 pub fn flags(mut self, flags: InputTextFlags) -> Self {
261 self.flags = flags;
262 self
263 }
264
265 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#[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 #[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 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 #[inline]
340 pub fn step(mut self, value: T) -> Self {
341 self.step = Some(value);
342 self
343 }
344
345 #[inline]
347 pub fn step_fast(mut self, value: T) -> Self {
348 self.step_fast = Some(value);
349 self
350 }
351
352 #[inline]
354 pub fn flags(mut self, flags: InputTextFlags) -> Self {
355 self.flags = flags;
356 self
357 }
358
359 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#[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 #[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 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 #[inline]
430 pub fn flags(mut self, flags: InputTextFlags) -> Self {
431 self.flags = flags;
432 self
433 }
434
435 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#[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 #[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 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 #[inline]
487 pub fn flags(mut self, flags: InputTextFlags) -> Self {
488 self.flags = flags;
489 self
490 }
491
492 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#[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 #[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 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 #[inline]
544 pub fn flags(mut self, flags: InputTextFlags) -> Self {
545 self.flags = flags;
546 self
547 }
548
549 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#[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 #[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 #[inline]
586 pub fn flags(mut self, flags: InputTextFlags) -> Self {
587 self.flags = flags;
588 self
589 }
590
591 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#[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 #[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 #[inline]
626 pub fn flags(mut self, flags: InputTextFlags) -> Self {
627 self.flags = flags;
628 self
629 }
630
631 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#[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 #[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 #[inline]
666 pub fn flags(mut self, flags: InputTextFlags) -> Self {
667 self.flags = flags;
668 self
669 }
670
671 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}