1#![allow(
28 clippy::cast_possible_truncation,
29 clippy::cast_sign_loss,
30 clippy::as_conversions
31)]
32use crate::InputTextFlags;
37use crate::internal::DataTypeKind;
38use crate::string::ImString;
39use crate::sys;
40use crate::ui::Ui;
41use std::borrow::Cow;
42use std::ffi::{c_int, c_void};
43use std::marker::PhantomData;
44use std::ptr;
45
46fn zero_string_spare_capacity(buf: &mut String) {
47 let len = buf.len();
48 let cap = buf.capacity();
49 if cap > len {
50 unsafe {
51 let dst = buf.as_mut_ptr().add(len);
52 ptr::write_bytes(dst, 0, cap - len);
53 }
54 }
55}
56
57fn zero_string_new_capacity(buf: &mut String, old_cap: usize) {
58 let new_cap = buf.capacity();
59 if new_cap > old_cap {
60 unsafe {
61 let dst = buf.as_mut_ptr().add(old_cap);
62 ptr::write_bytes(dst, 0, new_cap - old_cap);
63 }
64 }
65}
66
67impl Ui {
69 #[doc(alias = "InputText", alias = "InputTextWithHint")]
83 pub fn input_text<'ui, 'p>(
84 &'ui self,
85 label: impl Into<Cow<'ui, str>>,
86 buf: &'p mut String,
87 ) -> InputText<'ui, 'p> {
88 InputText::new(self, label, buf)
89 }
90
91 pub fn input_text_imstr<'ui, 'p>(
93 &'ui self,
94 label: impl Into<Cow<'ui, str>>,
95 buf: &'p mut ImString,
96 ) -> InputTextImStr<'ui, 'p> {
97 InputTextImStr::new(self, label, buf)
98 }
99
100 #[doc(alias = "InputTextMultiline")]
114 pub fn input_text_multiline<'ui, 'p>(
115 &'ui self,
116 label: impl Into<Cow<'ui, str>>,
117 buf: &'p mut String,
118 size: impl Into<[f32; 2]>,
119 ) -> InputTextMultiline<'ui, 'p> {
120 InputTextMultiline::new(self, label, buf, size)
121 }
122
123 pub fn input_text_multiline_imstr<'ui, 'p>(
125 &'ui self,
126 label: impl Into<Cow<'ui, str>>,
127 buf: &'p mut ImString,
128 size: impl Into<[f32; 2]>,
129 ) -> InputTextMultilineImStr<'ui, 'p> {
130 InputTextMultilineImStr::new(self, label, buf, size)
131 }
132
133 #[doc(alias = "InputInt")]
137 pub fn input_int(&self, label: impl AsRef<str>, value: &mut i32) -> bool {
138 self.input_int_config(label.as_ref()).build(value)
139 }
140
141 #[doc(alias = "InputFloat")]
145 pub fn input_float(&self, label: impl AsRef<str>, value: &mut f32) -> bool {
146 self.input_float_config(label.as_ref()).build(value)
147 }
148
149 #[doc(alias = "InputDouble")]
153 pub fn input_double(&self, label: impl AsRef<str>, value: &mut f64) -> bool {
154 self.input_double_config(label.as_ref()).build(value)
155 }
156
157 pub fn input_int_config<'ui>(&'ui self, label: impl Into<Cow<'ui, str>>) -> InputInt<'ui> {
159 InputInt::new(self, label)
160 }
161
162 pub fn input_float_config<'ui>(&'ui self, label: impl Into<Cow<'ui, str>>) -> InputFloat<'ui> {
164 InputFloat::new(self, label)
165 }
166
167 pub fn input_double_config<'ui>(
169 &'ui self,
170 label: impl Into<Cow<'ui, str>>,
171 ) -> InputDouble<'ui> {
172 InputDouble::new(self, label)
173 }
174
175 #[doc(alias = "InputScalar")]
178 pub fn input_scalar<'p, L, T>(&self, label: L, value: &'p mut T) -> InputScalar<'_, 'p, T, L>
179 where
180 L: AsRef<str>,
181 T: DataTypeKind,
182 {
183 InputScalar::new(self, label, value)
184 }
185
186 #[doc(alias = "InputScalarN")]
190 pub fn input_scalar_n<'p, L, T>(
191 &self,
192 label: L,
193 values: &'p mut [T],
194 ) -> InputScalarN<'_, 'p, T, L>
195 where
196 L: AsRef<str>,
197 T: DataTypeKind,
198 {
199 InputScalarN::new(self, label, values)
200 }
201
202 #[doc(alias = "InputFloat2")]
204 pub fn input_float2<'p, L>(&self, label: L, value: &'p mut [f32; 2]) -> InputFloat2<'_, 'p, L>
205 where
206 L: AsRef<str>,
207 {
208 InputFloat2::new(self, label, value)
209 }
210
211 #[doc(alias = "InputFloat3")]
213 pub fn input_float3<'p, L>(&self, label: L, value: &'p mut [f32; 3]) -> InputFloat3<'_, 'p, L>
214 where
215 L: AsRef<str>,
216 {
217 InputFloat3::new(self, label, value)
218 }
219
220 #[doc(alias = "InputFloat4")]
222 pub fn input_float4<'p, L>(&self, label: L, value: &'p mut [f32; 4]) -> InputFloat4<'_, 'p, L>
223 where
224 L: AsRef<str>,
225 {
226 InputFloat4::new(self, label, value)
227 }
228
229 #[doc(alias = "InputInt2")]
231 pub fn input_int2<'p, L>(&self, label: L, value: &'p mut [i32; 2]) -> InputInt2<'_, 'p, L>
232 where
233 L: AsRef<str>,
234 {
235 InputInt2::new(self, label, value)
236 }
237
238 #[doc(alias = "InputInt3")]
240 pub fn input_int3<'p, L>(&self, label: L, value: &'p mut [i32; 3]) -> InputInt3<'_, 'p, L>
241 where
242 L: AsRef<str>,
243 {
244 InputInt3::new(self, label, value)
245 }
246
247 #[doc(alias = "InputInt4")]
249 pub fn input_int4<'p, L>(&self, label: L, value: &'p mut [i32; 4]) -> InputInt4<'_, 'p, L>
250 where
251 L: AsRef<str>,
252 {
253 InputInt4::new(self, label, value)
254 }
255}
256
257#[must_use]
259pub struct InputText<'ui, 'p, L = Cow<'ui, str>, H = Cow<'ui, str>, T = PassthroughCallback> {
260 ui: &'ui Ui,
261 label: L,
262 buf: &'p mut String,
263 flags: InputTextFlags,
264 capacity_hint: Option<usize>,
265 hint: Option<H>,
266 callback_handler: T,
267 _phantom: PhantomData<&'ui ()>,
268}
269
270#[must_use]
272pub struct InputTextImStr<'ui, 'p, L = Cow<'ui, str>, H = Cow<'ui, str>, T = PassthroughCallback> {
273 ui: &'ui Ui,
274 label: L,
275 buf: &'p mut ImString,
276 flags: InputTextFlags,
277 hint: Option<H>,
278 callback_handler: T,
279 _phantom: PhantomData<&'ui ()>,
280}
281
282impl<'ui, 'p> InputTextImStr<'ui, 'p, Cow<'ui, str>, Cow<'ui, str>, PassthroughCallback> {
283 pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>, buf: &'p mut ImString) -> Self {
284 Self {
285 ui,
286 label: label.into(),
287 buf,
288 flags: InputTextFlags::empty(),
289 hint: None,
290 callback_handler: PassthroughCallback,
291 _phantom: PhantomData,
292 }
293 }
294}
295
296impl<'ui, 'p, L: AsRef<str>, H: AsRef<str>, T> InputTextImStr<'ui, 'p, L, H, T> {
297 pub fn flags(mut self, flags: InputTextFlags) -> Self {
298 self.flags = flags;
299 self
300 }
301 pub fn hint<H2: AsRef<str>>(self, hint: H2) -> InputTextImStr<'ui, 'p, L, H2, T> {
302 InputTextImStr {
303 ui: self.ui,
304 label: self.label,
305 buf: self.buf,
306 flags: self.flags,
307 hint: Some(hint),
308 callback_handler: self.callback_handler,
309 _phantom: PhantomData,
310 }
311 }
312 pub fn read_only(mut self, ro: bool) -> Self {
313 self.flags.set(InputTextFlags::READ_ONLY, ro);
314 self
315 }
316 pub fn password(mut self, pw: bool) -> Self {
317 self.flags.set(InputTextFlags::PASSWORD, pw);
318 self
319 }
320 pub fn auto_select_all(mut self, v: bool) -> Self {
321 self.flags.set(InputTextFlags::AUTO_SELECT_ALL, v);
322 self
323 }
324 pub fn enter_returns_true(mut self, v: bool) -> Self {
325 self.flags.set(InputTextFlags::ENTER_RETURNS_TRUE, v);
326 self
327 }
328
329 pub fn build(self) -> bool {
330 let (label_ptr, hint_ptr) = self.ui.scratch_txt_with_opt(
331 self.label.as_ref(),
332 self.hint.as_ref().map(|hint| hint.as_ref()),
333 );
334 let buf_size = self.buf.capacity_with_nul().max(1);
335 self.buf.ensure_buf_size(buf_size);
336 let buf_ptr = self.buf.as_mut_ptr();
337 let user_ptr = self.buf as *mut ImString as *mut c_void;
338
339 extern "C" fn resize_cb_imstr(data: *mut sys::ImGuiInputTextCallbackData) -> c_int {
340 if data.is_null() {
341 return 0;
342 }
343 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
344 if (*data).EventFlag == (sys::ImGuiInputTextFlags_CallbackResize as i32) {
345 let user_data = (*data).UserData as *mut ImString;
346 if user_data.is_null() {
347 return;
348 }
349
350 let im = &mut *user_data;
351 let requested_i32 = (*data).BufSize;
352 if requested_i32 < 0 {
353 return;
354 }
355 let requested = requested_i32 as usize;
356 im.ensure_buf_size(requested);
357 (*data).Buf = im.as_mut_ptr();
358 (*data).BufDirty = true;
359 }
360 }));
361 if res.is_err() {
362 eprintln!("dear-imgui-rs: panic in ImString resize callback");
363 std::process::abort();
364 }
365 0
366 }
367
368 let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
369 let result = unsafe {
370 if hint_ptr.is_null() {
371 sys::igInputText(
372 label_ptr,
373 buf_ptr,
374 buf_size,
375 flags.bits(),
376 Some(resize_cb_imstr),
377 user_ptr,
378 )
379 } else {
380 sys::igInputTextWithHint(
381 label_ptr,
382 hint_ptr,
383 buf_ptr,
384 buf_size,
385 flags.bits(),
386 Some(resize_cb_imstr),
387 user_ptr,
388 )
389 }
390 };
391 unsafe { self.buf.refresh_len() };
393 result
394 }
395}
396impl<'ui, 'p> InputText<'ui, 'p, Cow<'ui, str>, Cow<'ui, str>, PassthroughCallback> {
397 pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>, buf: &'p mut String) -> Self {
399 Self {
400 ui,
401 label: label.into(),
402 buf,
403 flags: InputTextFlags::NONE,
404 capacity_hint: None,
405 hint: None,
406 callback_handler: PassthroughCallback,
407 _phantom: PhantomData,
408 }
409 }
410}
411
412impl<'ui, 'p, L, H, T> InputText<'ui, 'p, L, H, T> {
413 pub fn flags(mut self, flags: InputTextFlags) -> Self {
415 self.flags = flags;
416 self
417 }
418
419 pub fn capacity_hint(mut self, cap: usize) -> Self {
421 self.capacity_hint = Some(cap);
422 self
423 }
424
425 pub fn hint(self, hint: impl Into<Cow<'ui, str>>) -> InputText<'ui, 'p, L, Cow<'ui, str>, T> {
427 InputText {
428 ui: self.ui,
429 label: self.label,
430 buf: self.buf,
431 flags: self.flags,
432 capacity_hint: self.capacity_hint,
433 hint: Some(hint.into()),
434 callback_handler: self.callback_handler,
435 _phantom: PhantomData,
436 }
437 }
438
439 pub fn callback<T2: InputTextCallbackHandler>(
441 self,
442 callback_handler: T2,
443 ) -> InputText<'ui, 'p, L, H, T2> {
444 InputText {
445 ui: self.ui,
446 label: self.label,
447 buf: self.buf,
448 flags: self.flags,
449 capacity_hint: self.capacity_hint,
450 hint: self.hint,
451 callback_handler,
452 _phantom: PhantomData,
453 }
454 }
455
456 pub fn callback_flags(mut self, callback_flags: InputTextCallback) -> Self {
458 self.flags |= InputTextFlags::from_bits_truncate(callback_flags.bits() as i32);
459 self
460 }
461
462 pub fn read_only(mut self, read_only: bool) -> Self {
464 self.flags.set(InputTextFlags::READ_ONLY, read_only);
465 self
466 }
467
468 pub fn password(mut self, password: bool) -> Self {
470 self.flags.set(InputTextFlags::PASSWORD, password);
471 self
472 }
473
474 pub fn auto_select_all(mut self, auto_select: bool) -> Self {
476 self.flags.set(InputTextFlags::AUTO_SELECT_ALL, auto_select);
477 self
478 }
479
480 pub fn enter_returns_true(mut self, enter_returns: bool) -> Self {
482 self.flags
483 .set(InputTextFlags::ENTER_RETURNS_TRUE, enter_returns);
484 self
485 }
486
487 pub fn chars_decimal(mut self, decimal: bool) -> Self {
489 self.flags.set(InputTextFlags::CHARS_DECIMAL, decimal);
490 self
491 }
492
493 pub fn chars_hexadecimal(mut self, hex: bool) -> Self {
495 self.flags.set(InputTextFlags::CHARS_HEXADECIMAL, hex);
496 self
497 }
498
499 pub fn chars_uppercase(mut self, uppercase: bool) -> Self {
501 self.flags.set(InputTextFlags::CHARS_UPPERCASE, uppercase);
502 self
503 }
504
505 pub fn chars_no_blank(mut self, no_blank: bool) -> Self {
507 self.flags.set(InputTextFlags::CHARS_NO_BLANK, no_blank);
508 self
509 }
510}
511
512impl<'ui, 'p, L, H, T> InputText<'ui, 'p, L, H, T>
514where
515 L: AsRef<str>,
516 H: AsRef<str>,
517 T: InputTextCallbackHandler,
518{
519 pub fn build(self) -> bool {
521 let (label_ptr, hint_ptr) = self.ui.scratch_txt_with_opt(
522 self.label.as_ref(),
523 self.hint.as_ref().map(|hint| hint.as_ref()),
524 );
525
526 if let Some(extra) = self.capacity_hint {
527 let needed = extra.saturating_sub(self.buf.capacity().saturating_sub(self.buf.len()));
528 if needed > 0 {
529 self.buf.reserve(needed);
530 }
531 }
532
533 self.buf.push('\0');
535 zero_string_spare_capacity(self.buf);
537 let capacity = self.buf.capacity();
538 let buf_ptr = self.buf.as_mut_ptr() as *mut std::os::raw::c_char;
539
540 #[repr(C)]
541 struct UserData<T> {
542 container: *mut String,
543 handler: T,
544 }
545
546 extern "C" fn callback_router<T: InputTextCallbackHandler>(
547 data: *mut sys::ImGuiInputTextCallbackData,
548 ) -> c_int {
549 if data.is_null() {
550 return 0;
551 }
552
553 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
554 let user_ptr = unsafe { (*data).UserData as *mut UserData<T> };
555 if user_ptr.is_null() {
556 return 0;
557 }
558 let user = unsafe { &mut *user_ptr };
559 if user.container.is_null() {
560 return 0;
561 }
562
563 let event_flag = unsafe { InputTextFlags::from_bits_truncate((*data).EventFlag) };
564 match event_flag {
565 InputTextFlags::CALLBACK_RESIZE => unsafe {
566 let requested_i32 = (*data).BufSize;
567 if requested_i32 < 0 {
568 return 0;
569 }
570 let requested = requested_i32 as usize;
571 let s = &mut *user.container;
572 debug_assert_eq!(s.as_ptr() as *const _, (*data).Buf);
573 if requested > s.capacity() {
574 let old_cap = s.capacity();
575 let additional = requested.saturating_sub(s.len());
576 s.reserve(additional);
577 zero_string_new_capacity(s, old_cap);
578 (*data).Buf = s.as_mut_ptr() as *mut _;
579 (*data).BufDirty = true;
580 }
581 0
582 },
583 InputTextFlags::CALLBACK_COMPLETION => {
584 let info = unsafe { TextCallbackData::new(data) };
585 user.handler.on_completion(info);
586 0
587 }
588 InputTextFlags::CALLBACK_HISTORY => {
589 let key = unsafe { (*data).EventKey };
590 let dir = if key == sys::ImGuiKey_UpArrow {
591 HistoryDirection::Up
592 } else {
593 HistoryDirection::Down
594 };
595 let info = unsafe { TextCallbackData::new(data) };
596 user.handler.on_history(dir, info);
597 0
598 }
599 InputTextFlags::CALLBACK_ALWAYS => {
600 let info = unsafe { TextCallbackData::new(data) };
601 user.handler.on_always(info);
602 0
603 }
604 InputTextFlags::CALLBACK_EDIT => {
605 let info = unsafe { TextCallbackData::new(data) };
606 user.handler.on_edit(info);
607 0
608 }
609 InputTextFlags::CALLBACK_CHAR_FILTER => {
610 let ch = unsafe {
611 std::char::from_u32((*data).EventChar as u32).unwrap_or('\0')
612 };
613 let new_ch = user.handler.char_filter(ch).map(|c| c as u32).unwrap_or(0);
614 unsafe {
615 (*data).EventChar =
616 sys::ImWchar::try_from(new_ch).unwrap_or(0 as sys::ImWchar);
617 }
618 0
619 }
620 _ => 0,
621 }
622 }));
623
624 match res {
625 Ok(v) => v,
626 Err(_) => {
627 eprintln!("dear-imgui-rs: panic in InputText callback");
628 std::process::abort();
629 }
630 }
631 }
632
633 let mut user_data = UserData {
634 container: self.buf as *mut String,
635 handler: self.callback_handler,
636 };
637 let user_ptr = &mut user_data as *mut _ as *mut c_void;
638
639 let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
640 let result = unsafe {
641 if hint_ptr.is_null() {
642 sys::igInputText(
643 label_ptr,
644 buf_ptr,
645 capacity,
646 flags.bits(),
647 Some(callback_router::<T>),
648 user_ptr,
649 )
650 } else {
651 sys::igInputTextWithHint(
652 label_ptr,
653 hint_ptr,
654 buf_ptr,
655 capacity,
656 flags.bits(),
657 Some(callback_router::<T>),
658 user_ptr,
659 )
660 }
661 };
662
663 let cap = unsafe { (&*user_data.container).capacity() };
665 let slice = unsafe { std::slice::from_raw_parts((&*user_data.container).as_ptr(), cap) };
666 if let Some(len) = slice.iter().position(|&b| b == 0) {
667 unsafe { (&mut *user_data.container).as_mut_vec().set_len(len) };
668 }
669 result
670 }
671}
672
673#[derive(Debug)]
675#[must_use]
676pub struct InputTextMultiline<'ui, 'p> {
677 ui: &'ui Ui,
678 label: Cow<'ui, str>,
679 buf: &'p mut String,
680 size: [f32; 2],
681 flags: InputTextFlags,
682 capacity_hint: Option<usize>,
683}
684
685#[derive(Debug)]
687#[must_use]
688pub struct InputTextMultilineImStr<'ui, 'p> {
689 ui: &'ui Ui,
690 label: Cow<'ui, str>,
691 buf: &'p mut ImString,
692 size: [f32; 2],
693 flags: InputTextFlags,
694}
695
696impl<'ui, 'p> InputTextMultilineImStr<'ui, 'p> {
697 pub fn new(
698 ui: &'ui Ui,
699 label: impl Into<Cow<'ui, str>>,
700 buf: &'p mut ImString,
701 size: impl Into<[f32; 2]>,
702 ) -> Self {
703 Self {
704 ui,
705 label: label.into(),
706 buf,
707 size: size.into(),
708 flags: InputTextFlags::NONE,
709 }
710 }
711 pub fn flags(mut self, flags: InputTextFlags) -> Self {
712 self.flags = flags;
713 self
714 }
715 pub fn read_only(mut self, v: bool) -> Self {
716 self.flags.set(InputTextFlags::READ_ONLY, v);
717 self
718 }
719 pub fn build(self) -> bool {
720 let label_ptr = self.ui.scratch_txt(self.label.as_ref());
721 let buf_size = self.buf.capacity_with_nul().max(1);
722 self.buf.ensure_buf_size(buf_size);
723 let buf_ptr = self.buf.as_mut_ptr();
724 let user_ptr = self.buf as *mut ImString as *mut c_void;
725 let size_vec: sys::ImVec2 = self.size.into();
726
727 extern "C" fn resize_cb_imstr(data: *mut sys::ImGuiInputTextCallbackData) -> c_int {
728 if data.is_null() {
729 return 0;
730 }
731 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
732 if (*data).EventFlag == (sys::ImGuiInputTextFlags_CallbackResize as i32) {
733 let user_data = (*data).UserData as *mut ImString;
734 if user_data.is_null() {
735 return;
736 }
737
738 let im = &mut *user_data;
739 let requested_i32 = (*data).BufSize;
740 if requested_i32 < 0 {
741 return;
742 }
743 let requested = requested_i32 as usize;
744 im.ensure_buf_size(requested);
745 (*data).Buf = im.as_mut_ptr();
746 (*data).BufDirty = true;
747 }
748 }));
749 if res.is_err() {
750 eprintln!("dear-imgui-rs: panic in ImString multiline resize callback");
751 std::process::abort();
752 }
753 0
754 }
755
756 let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
757 let result = unsafe {
758 sys::igInputTextMultiline(
759 label_ptr,
760 buf_ptr,
761 buf_size,
762 size_vec,
763 flags.bits(),
764 Some(resize_cb_imstr),
765 user_ptr,
766 )
767 };
768 unsafe { self.buf.refresh_len() };
770 result
771 }
772}
773impl<'ui, 'p> InputTextMultiline<'ui, 'p> {
774 pub fn new(
776 ui: &'ui Ui,
777 label: impl Into<Cow<'ui, str>>,
778 buf: &'p mut String,
779 size: impl Into<[f32; 2]>,
780 ) -> Self {
781 Self {
782 ui,
783 label: label.into(),
784 buf,
785 size: size.into(),
786 flags: InputTextFlags::NONE,
787 capacity_hint: None,
788 }
789 }
790
791 pub fn flags(mut self, flags: InputTextFlags) -> Self {
793 self.flags = flags;
794 self
795 }
796
797 pub fn capacity_hint(mut self, cap: usize) -> Self {
799 self.capacity_hint = Some(cap);
800 self
801 }
802
803 pub fn read_only(mut self, read_only: bool) -> Self {
805 self.flags.set(InputTextFlags::READ_ONLY, read_only);
806 self
807 }
808
809 pub fn build(self) -> bool {
811 let label_ptr = self.ui.scratch_txt(self.label.as_ref());
812
813 if let Some(extra) = self.capacity_hint {
815 let needed = extra.saturating_sub(self.buf.capacity().saturating_sub(self.buf.len()));
816 if needed > 0 {
817 self.buf.reserve(needed);
818 }
819 }
820
821 self.buf.push('\0');
823 zero_string_spare_capacity(self.buf);
825 let capacity = self.buf.capacity();
826 let buf_ptr = self.buf.as_mut_ptr() as *mut std::os::raw::c_char;
827
828 #[repr(C)]
829 struct UserData {
830 container: *mut String,
831 }
832
833 extern "C" fn callback_router(data: *mut sys::ImGuiInputTextCallbackData) -> c_int {
834 if data.is_null() {
835 return 0;
836 }
837
838 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
839 let event_flag = InputTextFlags::from_bits_truncate((*data).EventFlag);
840 match event_flag {
841 InputTextFlags::CALLBACK_RESIZE => {
842 let user_ptr = (*data).UserData as *mut UserData;
843 if user_ptr.is_null() {
844 return 0;
845 }
846 let requested_i32 = (*data).BufSize;
847 if requested_i32 < 0 {
848 return 0;
849 }
850 let requested = requested_i32 as usize;
851
852 let user = &mut *user_ptr;
853 if user.container.is_null() {
854 return 0;
855 }
856 let s = &mut *user.container;
857 debug_assert_eq!(s.as_ptr() as *const _, (*data).Buf);
858 if requested > s.capacity() {
859 let old_cap = s.capacity();
860 let additional = requested.saturating_sub(s.len());
861 s.reserve(additional);
862 zero_string_new_capacity(s, old_cap);
863 (*data).Buf = s.as_mut_ptr() as *mut _;
864 (*data).BufDirty = true;
865 }
866 0
867 }
868 _ => 0,
869 }
870 }));
871
872 match res {
873 Ok(v) => v,
874 Err(_) => {
875 eprintln!("dear-imgui-rs: panic in multiline InputText resize callback");
876 std::process::abort();
877 }
878 }
879 }
880
881 let mut user_data = UserData {
882 container: self.buf as *mut String,
883 };
884 let user_ptr = &mut user_data as *mut _ as *mut c_void;
885
886 let size_vec: sys::ImVec2 = self.size.into();
887 let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
888 let result = unsafe {
889 sys::igInputTextMultiline(
890 label_ptr,
891 buf_ptr,
892 capacity,
893 size_vec,
894 flags.bits(),
895 Some(callback_router),
896 user_ptr,
897 )
898 };
899
900 let cap = unsafe { (&*user_data.container).capacity() };
902 let slice = unsafe { std::slice::from_raw_parts((&*user_data.container).as_ptr(), cap) };
903 if let Some(len) = slice.iter().position(|&b| b == 0) {
904 unsafe { (&mut *user_data.container).as_mut_vec().set_len(len) };
905 }
906 result
907 }
908
909 pub fn callback<T2: InputTextCallbackHandler>(
911 mut self,
912 callbacks: InputTextCallback,
913 handler: T2,
914 ) -> InputTextMultilineWithCb<'ui, 'p, T2> {
915 if callbacks.contains(InputTextCallback::ALWAYS) {
918 self.flags.insert(InputTextFlags::CALLBACK_ALWAYS);
919 }
920 if callbacks.contains(InputTextCallback::CHAR_FILTER) {
921 self.flags.insert(InputTextFlags::CALLBACK_CHAR_FILTER);
922 }
923 if callbacks.contains(InputTextCallback::EDIT) {
924 self.flags.insert(InputTextFlags::CALLBACK_EDIT);
925 }
926
927 InputTextMultilineWithCb {
928 ui: self.ui,
929 label: self.label,
930 buf: self.buf,
931 size: self.size,
932 flags: self.flags,
933 capacity_hint: self.capacity_hint,
934 handler,
935 }
936 }
937}
938
939pub struct InputTextMultilineWithCb<'ui, 'p, T> {
941 ui: &'ui Ui,
942 label: Cow<'ui, str>,
943 buf: &'p mut String,
944 size: [f32; 2],
945 flags: InputTextFlags,
946 capacity_hint: Option<usize>,
947 handler: T,
948}
949
950impl<'ui, 'p, T: InputTextCallbackHandler> InputTextMultilineWithCb<'ui, 'p, T> {
951 pub fn build(self) -> bool {
952 let label_ptr = self.ui.scratch_txt(self.label.as_ref());
953
954 if let Some(extra) = self.capacity_hint {
955 let needed = extra.saturating_sub(self.buf.capacity().saturating_sub(self.buf.len()));
956 if needed > 0 {
957 self.buf.reserve(needed);
958 }
959 }
960
961 self.buf.push('\0');
963 zero_string_spare_capacity(self.buf);
965 let capacity = self.buf.capacity();
966 let buf_ptr = self.buf.as_mut_ptr() as *mut std::os::raw::c_char;
967
968 #[repr(C)]
969 struct UserData<T> {
970 container: *mut String,
971 handler: T,
972 }
973
974 extern "C" fn callback_router<T: InputTextCallbackHandler>(
975 data: *mut sys::ImGuiInputTextCallbackData,
976 ) -> c_int {
977 if data.is_null() {
978 return 0;
979 }
980
981 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
982 let user_ptr = unsafe { (*data).UserData as *mut UserData<T> };
983 if user_ptr.is_null() {
984 return 0;
985 }
986 let user = unsafe { &mut *user_ptr };
987 if user.container.is_null() {
988 return 0;
989 }
990
991 let event_flag = unsafe { InputTextFlags::from_bits_truncate((*data).EventFlag) };
992 match event_flag {
993 InputTextFlags::CALLBACK_RESIZE => unsafe {
994 let requested_i32 = (*data).BufSize;
995 if requested_i32 < 0 {
996 return 0;
997 }
998 let requested = requested_i32 as usize;
999 let s = &mut *user.container;
1000 debug_assert_eq!(s.as_ptr() as *const _, (*data).Buf);
1001 if requested > s.capacity() {
1002 let old_cap = s.capacity();
1003 let additional = requested.saturating_sub(s.len());
1004 s.reserve(additional);
1005 zero_string_new_capacity(s, old_cap);
1006 (*data).Buf = s.as_mut_ptr() as *mut _;
1007 (*data).BufDirty = true;
1008 }
1009 0
1010 },
1011 InputTextFlags::CALLBACK_COMPLETION => {
1012 let info = unsafe { TextCallbackData::new(data) };
1013 user.handler.on_completion(info);
1014 0
1015 }
1016 InputTextFlags::CALLBACK_HISTORY => {
1017 let key = unsafe { (*data).EventKey };
1018 let dir = if key == sys::ImGuiKey_UpArrow {
1019 HistoryDirection::Up
1020 } else {
1021 HistoryDirection::Down
1022 };
1023 let info = unsafe { TextCallbackData::new(data) };
1024 user.handler.on_history(dir, info);
1025 0
1026 }
1027 InputTextFlags::CALLBACK_ALWAYS => {
1028 let info = unsafe { TextCallbackData::new(data) };
1029 user.handler.on_always(info);
1030 0
1031 }
1032 InputTextFlags::CALLBACK_EDIT => {
1033 let info = unsafe { TextCallbackData::new(data) };
1034 user.handler.on_edit(info);
1035 0
1036 }
1037 InputTextFlags::CALLBACK_CHAR_FILTER => {
1038 let ch = unsafe {
1039 std::char::from_u32((*data).EventChar as u32).unwrap_or('\0')
1040 };
1041 let new_ch = user.handler.char_filter(ch).map(|c| c as u32).unwrap_or(0);
1042 unsafe {
1043 (*data).EventChar =
1044 sys::ImWchar::try_from(new_ch).unwrap_or(0 as sys::ImWchar);
1045 }
1046 0
1047 }
1048 _ => 0,
1049 }
1050 }));
1051
1052 match res {
1053 Ok(v) => v,
1054 Err(_) => {
1055 eprintln!("dear-imgui-rs: panic in InputText multiline callback");
1056 std::process::abort();
1057 }
1058 }
1059 }
1060
1061 let mut user_data = UserData {
1062 container: self.buf as *mut String,
1063 handler: self.handler,
1064 };
1065 let user_ptr = &mut user_data as *mut _ as *mut c_void;
1066
1067 let size_vec: sys::ImVec2 = self.size.into();
1068 let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
1069 let result = unsafe {
1070 sys::igInputTextMultiline(
1071 label_ptr,
1072 buf_ptr,
1073 capacity,
1074 size_vec,
1075 flags.bits(),
1076 Some(callback_router::<T>),
1077 user_ptr,
1078 )
1079 };
1080
1081 let cap = unsafe { (&*user_data.container).capacity() };
1083 let slice = unsafe { std::slice::from_raw_parts((&*user_data.container).as_ptr(), cap) };
1084 if let Some(len) = slice.iter().position(|&b| b == 0) {
1085 unsafe { (&mut *user_data.container).as_mut_vec().set_len(len) };
1086 }
1087 result
1088 }
1089}
1090
1091#[derive(Debug)]
1093#[must_use]
1094pub struct InputInt<'ui> {
1095 ui: &'ui Ui,
1096 label: Cow<'ui, str>,
1097 step: i32,
1098 step_fast: i32,
1099 flags: InputTextFlags,
1100}
1101
1102impl<'ui> InputInt<'ui> {
1103 pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>) -> Self {
1105 Self {
1106 ui,
1107 label: label.into(),
1108 step: 1,
1109 step_fast: 100,
1110 flags: InputTextFlags::NONE,
1111 }
1112 }
1113
1114 pub fn step(mut self, step: i32) -> Self {
1116 self.step = step;
1117 self
1118 }
1119
1120 pub fn step_fast(mut self, step_fast: i32) -> Self {
1122 self.step_fast = step_fast;
1123 self
1124 }
1125
1126 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1128 self.flags = flags;
1129 self
1130 }
1131
1132 pub fn build(self, value: &mut i32) -> bool {
1134 let label_ptr = self.ui.scratch_txt(self.label.as_ref());
1135 unsafe {
1136 sys::igInputInt(
1137 label_ptr,
1138 value as *mut i32,
1139 self.step,
1140 self.step_fast,
1141 self.flags.bits(),
1142 )
1143 }
1144 }
1145}
1146
1147#[derive(Debug)]
1149#[must_use]
1150pub struct InputFloat<'ui> {
1151 ui: &'ui Ui,
1152 label: Cow<'ui, str>,
1153 step: f32,
1154 step_fast: f32,
1155 format: Option<Cow<'ui, str>>,
1156 flags: InputTextFlags,
1157}
1158
1159impl<'ui> InputFloat<'ui> {
1160 pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>) -> Self {
1162 Self {
1163 ui,
1164 label: label.into(),
1165 step: 0.0,
1166 step_fast: 0.0,
1167 format: None,
1168 flags: InputTextFlags::NONE,
1169 }
1170 }
1171
1172 pub fn step(mut self, step: f32) -> Self {
1174 self.step = step;
1175 self
1176 }
1177
1178 pub fn step_fast(mut self, step_fast: f32) -> Self {
1180 self.step_fast = step_fast;
1181 self
1182 }
1183
1184 pub fn format(mut self, format: impl Into<Cow<'ui, str>>) -> Self {
1186 self.format = Some(format.into());
1187 self
1188 }
1189
1190 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1192 self.flags = flags;
1193 self
1194 }
1195
1196 pub fn build(self, value: &mut f32) -> bool {
1198 let format = self.format.as_deref().unwrap_or("%.3f");
1199 let (label_ptr, format_ptr) = self.ui.scratch_txt_two(self.label.as_ref(), format);
1200
1201 unsafe {
1202 sys::igInputFloat(
1203 label_ptr,
1204 value as *mut f32,
1205 self.step,
1206 self.step_fast,
1207 format_ptr,
1208 self.flags.bits(),
1209 )
1210 }
1211 }
1212}
1213
1214#[derive(Debug)]
1216#[must_use]
1217pub struct InputDouble<'ui> {
1218 ui: &'ui Ui,
1219 label: Cow<'ui, str>,
1220 step: f64,
1221 step_fast: f64,
1222 format: Option<Cow<'ui, str>>,
1223 flags: InputTextFlags,
1224}
1225
1226impl<'ui> InputDouble<'ui> {
1227 pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>) -> Self {
1229 Self {
1230 ui,
1231 label: label.into(),
1232 step: 0.0,
1233 step_fast: 0.0,
1234 format: None,
1235 flags: InputTextFlags::NONE,
1236 }
1237 }
1238
1239 pub fn step(mut self, step: f64) -> Self {
1241 self.step = step;
1242 self
1243 }
1244
1245 pub fn step_fast(mut self, step_fast: f64) -> Self {
1247 self.step_fast = step_fast;
1248 self
1249 }
1250
1251 pub fn format(mut self, format: impl Into<Cow<'ui, str>>) -> Self {
1253 self.format = Some(format.into());
1254 self
1255 }
1256
1257 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1259 self.flags = flags;
1260 self
1261 }
1262
1263 pub fn build(self, value: &mut f64) -> bool {
1265 let format = self.format.as_deref().unwrap_or("%.6f");
1266 let (label_ptr, format_ptr) = self.ui.scratch_txt_two(self.label.as_ref(), format);
1267
1268 unsafe {
1269 sys::igInputDouble(
1270 label_ptr,
1271 value as *mut f64,
1272 self.step,
1273 self.step_fast,
1274 format_ptr,
1275 self.flags.bits(),
1276 )
1277 }
1278 }
1279}
1280
1281bitflags::bitflags! {
1285 #[repr(transparent)]
1287 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1288 pub struct InputTextCallback: u32 {
1289 const COMPLETION = sys::ImGuiInputTextFlags_CallbackCompletion as u32;
1291 const HISTORY = sys::ImGuiInputTextFlags_CallbackHistory as u32;
1293 const ALWAYS = sys::ImGuiInputTextFlags_CallbackAlways as u32;
1295 const CHAR_FILTER = sys::ImGuiInputTextFlags_CallbackCharFilter as u32;
1297 const EDIT = sys::ImGuiInputTextFlags_CallbackEdit as u32;
1300 }
1301}
1302
1303#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1305pub enum HistoryDirection {
1306 Up,
1308 Down,
1310}
1311
1312pub trait InputTextCallbackHandler {
1317 fn char_filter(&mut self, _c: char) -> Option<char> {
1322 None
1323 }
1324
1325 fn on_completion(&mut self, _data: TextCallbackData) {}
1329
1330 fn on_history(&mut self, _direction: HistoryDirection, _data: TextCallbackData) {}
1334
1335 fn on_always(&mut self, _data: TextCallbackData) {}
1339
1340 fn on_edit(&mut self, _data: TextCallbackData) {}
1344}
1345
1346pub struct TextCallbackData(*mut sys::ImGuiInputTextCallbackData);
1350
1351impl TextCallbackData {
1352 unsafe fn new(data: *mut sys::ImGuiInputTextCallbackData) -> Self {
1354 Self(data)
1355 }
1356
1357 pub fn str(&self) -> &str {
1359 unsafe {
1360 std::str::from_utf8(std::slice::from_raw_parts(
1361 (*(self.0)).Buf as *const _,
1362 (*(self.0)).BufTextLen as usize,
1363 ))
1364 .expect("internal imgui error -- it boofed a utf8")
1365 }
1366 }
1367
1368 pub fn cursor_pos(&self) -> usize {
1370 unsafe { (*(self.0)).CursorPos as usize }
1371 }
1372
1373 pub fn set_cursor_pos(&mut self, pos: usize) {
1375 unsafe {
1376 (*(self.0)).CursorPos = pos as i32;
1377 }
1378 }
1379
1380 pub fn selection_start(&self) -> usize {
1382 unsafe { (*(self.0)).SelectionStart as usize }
1383 }
1384
1385 pub fn set_selection_start(&mut self, pos: usize) {
1387 unsafe {
1388 (*(self.0)).SelectionStart = pos as i32;
1389 }
1390 }
1391
1392 pub fn selection_end(&self) -> usize {
1394 unsafe { (*(self.0)).SelectionEnd as usize }
1395 }
1396
1397 pub fn set_selection_end(&mut self, pos: usize) {
1399 unsafe {
1400 (*(self.0)).SelectionEnd = pos as i32;
1401 }
1402 }
1403
1404 pub fn select_all(&mut self) {
1406 unsafe {
1407 (*(self.0)).SelectionStart = 0;
1408 (*(self.0)).SelectionEnd = (*(self.0)).BufTextLen;
1409 }
1410 }
1411
1412 pub fn clear_selection(&mut self) {
1414 unsafe {
1415 (*(self.0)).SelectionStart = (*(self.0)).CursorPos;
1416 (*(self.0)).SelectionEnd = (*(self.0)).CursorPos;
1417 }
1418 }
1419
1420 pub fn has_selection(&self) -> bool {
1422 unsafe { (*(self.0)).SelectionStart != (*(self.0)).SelectionEnd }
1423 }
1424
1425 pub fn remove_chars(&mut self, pos: usize, bytes_count: usize) {
1427 unsafe {
1428 sys::ImGuiInputTextCallbackData_DeleteChars(self.0, pos as i32, bytes_count as i32);
1429 }
1430 }
1431
1432 pub fn insert_chars(&mut self, pos: usize, text: &str) {
1434 let text_ptr = text.as_ptr() as *const std::os::raw::c_char;
1435 unsafe {
1436 sys::ImGuiInputTextCallbackData_InsertChars(
1437 self.0,
1438 pos as i32,
1439 text_ptr,
1440 text_ptr.add(text.len()),
1441 );
1442 }
1443 }
1444
1445 pub unsafe fn str_as_bytes_mut(&mut self) -> &mut [u8] {
1465 unsafe {
1466 assert!(
1467 !(*(self.0)).Buf.is_null(),
1468 "internal imgui error: Buf was null"
1469 );
1470 assert!(
1471 (*(self.0)).BufTextLen >= 0,
1472 "internal imgui error: BufTextLen was negative"
1473 );
1474 assert!(
1475 (*(self.0)).BufSize >= 0,
1476 "internal imgui error: BufSize was negative"
1477 );
1478 assert!(
1479 (*(self.0)).BufTextLen <= (*(self.0)).BufSize,
1480 "internal imgui error: BufTextLen exceeded BufSize"
1481 );
1482
1483 let str = std::str::from_utf8_mut(std::slice::from_raw_parts_mut(
1484 (*(self.0)).Buf as *mut u8,
1485 (*(self.0)).BufTextLen as usize,
1486 ))
1487 .expect("internal imgui error -- it boofed a utf8");
1488
1489 str.as_bytes_mut()
1490 }
1491 }
1492
1493 pub fn set_dirty(&mut self) {
1505 unsafe {
1506 (*(self.0)).BufDirty = true;
1507 }
1508 }
1509
1510 pub fn selected(&self) -> &str {
1513 let start = self.selection_start().min(self.selection_end());
1514 let end = self.selection_start().max(self.selection_end());
1515 &self.str()[start..end]
1516 }
1517
1518 pub fn push_str(&mut self, text: &str) {
1522 let current_len = unsafe { (*(self.0)).BufTextLen as usize };
1523 self.insert_chars(current_len, text);
1524 }
1525}
1526
1527pub struct PassthroughCallback;
1532impl InputTextCallbackHandler for PassthroughCallback {}
1533
1534extern "C" fn callback(data: *mut sys::ImGuiInputTextCallbackData) -> c_int {
1536 if data.is_null() {
1537 return 0;
1538 }
1539
1540 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
1541 let event_flag = InputTextFlags::from_bits_truncate((*data).EventFlag);
1542 let buffer_ptr = (*data).UserData as *mut String;
1543
1544 if buffer_ptr.is_null() {
1545 return;
1546 }
1547
1548 match event_flag {
1549 InputTextFlags::CALLBACK_RESIZE => {
1550 let requested_i32 = (*data).BufSize;
1551 if requested_i32 < 0 {
1552 return;
1553 }
1554 let requested_size = requested_i32 as usize;
1555 let buffer = &mut *buffer_ptr;
1556
1557 debug_assert_eq!(buffer.as_ptr() as *const _, (*data).Buf);
1558
1559 if requested_size > buffer.capacity() {
1560 let additional_bytes = requested_size.saturating_sub(buffer.len());
1561 buffer.reserve(additional_bytes);
1562
1563 (*data).Buf = buffer.as_mut_ptr() as *mut _;
1564 (*data).BufDirty = true;
1565 }
1566 }
1567 _ => {}
1568 }
1569 }));
1570
1571 if res.is_err() {
1572 eprintln!("dear-imgui-rs: panic in legacy InputText callback");
1573 std::process::abort();
1574 }
1575 0
1576}
1577
1578#[must_use]
1580pub struct InputScalar<'ui, 'p, T, L, F = &'static str> {
1581 value: &'p mut T,
1582 label: L,
1583 step: Option<T>,
1584 step_fast: Option<T>,
1585 display_format: Option<F>,
1586 flags: InputTextFlags,
1587 ui: &'ui Ui,
1588}
1589
1590impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind> InputScalar<'ui, 'p, T, L> {
1591 #[doc(alias = "InputScalar")]
1593 pub fn new(ui: &'ui Ui, label: L, value: &'p mut T) -> Self {
1594 InputScalar {
1595 value,
1596 label,
1597 step: None,
1598 step_fast: None,
1599 display_format: None,
1600 flags: InputTextFlags::empty(),
1601 ui,
1602 }
1603 }
1604}
1605
1606impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind, F: AsRef<str>> InputScalar<'ui, 'p, T, L, F> {
1607 pub fn display_format<F2: AsRef<str>>(
1609 self,
1610 display_format: F2,
1611 ) -> InputScalar<'ui, 'p, T, L, F2> {
1612 InputScalar {
1613 value: self.value,
1614 label: self.label,
1615 step: self.step,
1616 step_fast: self.step_fast,
1617 display_format: Some(display_format),
1618 flags: self.flags,
1619 ui: self.ui,
1620 }
1621 }
1622
1623 #[inline]
1625 pub fn step(mut self, value: T) -> Self {
1626 self.step = Some(value);
1627 self
1628 }
1629
1630 #[inline]
1632 pub fn step_fast(mut self, value: T) -> Self {
1633 self.step_fast = Some(value);
1634 self
1635 }
1636
1637 #[inline]
1639 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1640 self.flags = flags;
1641 self
1642 }
1643
1644 pub fn build(self) -> bool {
1648 unsafe {
1649 let (one, two) = self
1650 .ui
1651 .scratch_txt_with_opt(self.label, self.display_format);
1652
1653 sys::igInputScalar(
1654 one,
1655 T::KIND as i32,
1656 self.value as *mut T as *mut c_void,
1657 self.step
1658 .as_ref()
1659 .map(|step| step as *const T)
1660 .unwrap_or(ptr::null()) as *const c_void,
1661 self.step_fast
1662 .as_ref()
1663 .map(|step| step as *const T)
1664 .unwrap_or(ptr::null()) as *const c_void,
1665 two,
1666 self.flags.bits() as i32,
1667 )
1668 }
1669 }
1670}
1671
1672#[must_use]
1674pub struct InputScalarN<'ui, 'p, T, L, F = &'static str> {
1675 values: &'p mut [T],
1676 label: L,
1677 step: Option<T>,
1678 step_fast: Option<T>,
1679 display_format: Option<F>,
1680 flags: InputTextFlags,
1681 ui: &'ui Ui,
1682}
1683
1684impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind> InputScalarN<'ui, 'p, T, L> {
1685 #[doc(alias = "InputScalarN")]
1687 pub fn new(ui: &'ui Ui, label: L, values: &'p mut [T]) -> Self {
1688 InputScalarN {
1689 values,
1690 label,
1691 step: None,
1692 step_fast: None,
1693 display_format: None,
1694 flags: InputTextFlags::empty(),
1695 ui,
1696 }
1697 }
1698}
1699
1700impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind, F: AsRef<str>> InputScalarN<'ui, 'p, T, L, F> {
1701 pub fn display_format<F2: AsRef<str>>(
1703 self,
1704 display_format: F2,
1705 ) -> InputScalarN<'ui, 'p, T, L, F2> {
1706 InputScalarN {
1707 values: self.values,
1708 label: self.label,
1709 step: self.step,
1710 step_fast: self.step_fast,
1711 display_format: Some(display_format),
1712 flags: self.flags,
1713 ui: self.ui,
1714 }
1715 }
1716
1717 #[inline]
1719 pub fn step(mut self, value: T) -> Self {
1720 self.step = Some(value);
1721 self
1722 }
1723
1724 #[inline]
1726 pub fn step_fast(mut self, value: T) -> Self {
1727 self.step_fast = Some(value);
1728 self
1729 }
1730
1731 #[inline]
1733 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1734 self.flags = flags;
1735 self
1736 }
1737
1738 pub fn build(self) -> bool {
1742 let count = match i32::try_from(self.values.len()) {
1743 Ok(n) => n,
1744 Err(_) => return false,
1745 };
1746 unsafe {
1747 let (one, two) = self
1748 .ui
1749 .scratch_txt_with_opt(self.label, self.display_format);
1750
1751 sys::igInputScalarN(
1752 one,
1753 T::KIND as i32,
1754 self.values.as_mut_ptr() as *mut c_void,
1755 count,
1756 self.step
1757 .as_ref()
1758 .map(|step| step as *const T)
1759 .unwrap_or(ptr::null()) as *const c_void,
1760 self.step_fast
1761 .as_ref()
1762 .map(|step| step as *const T)
1763 .unwrap_or(ptr::null()) as *const c_void,
1764 two,
1765 self.flags.bits() as i32,
1766 )
1767 }
1768 }
1769}
1770
1771#[must_use]
1773pub struct InputFloat2<'ui, 'p, L, F = &'static str> {
1774 label: L,
1775 value: &'p mut [f32; 2],
1776 display_format: Option<F>,
1777 flags: InputTextFlags,
1778 ui: &'ui Ui,
1779}
1780
1781impl<'ui, 'p, L: AsRef<str>> InputFloat2<'ui, 'p, L> {
1782 #[doc(alias = "InputFloat2")]
1784 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 2]) -> Self {
1785 InputFloat2 {
1786 label,
1787 value,
1788 display_format: None,
1789 flags: InputTextFlags::empty(),
1790 ui,
1791 }
1792 }
1793}
1794
1795impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat2<'ui, 'p, L, F> {
1796 pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat2<'ui, 'p, L, F2> {
1798 InputFloat2 {
1799 label: self.label,
1800 value: self.value,
1801 display_format: Some(display_format),
1802 flags: self.flags,
1803 ui: self.ui,
1804 }
1805 }
1806
1807 #[inline]
1809 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1810 self.flags = flags;
1811 self
1812 }
1813
1814 pub fn build(self) -> bool {
1818 unsafe {
1819 let (one, two) = self
1820 .ui
1821 .scratch_txt_with_opt(self.label, self.display_format);
1822
1823 sys::igInputFloat2(one, self.value.as_mut_ptr(), two, self.flags.bits() as i32)
1824 }
1825 }
1826}
1827
1828#[must_use]
1830pub struct InputFloat3<'ui, 'p, L, F = &'static str> {
1831 label: L,
1832 value: &'p mut [f32; 3],
1833 display_format: Option<F>,
1834 flags: InputTextFlags,
1835 ui: &'ui Ui,
1836}
1837
1838impl<'ui, 'p, L: AsRef<str>> InputFloat3<'ui, 'p, L> {
1839 #[doc(alias = "InputFloat3")]
1841 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 3]) -> Self {
1842 InputFloat3 {
1843 label,
1844 value,
1845 display_format: None,
1846 flags: InputTextFlags::empty(),
1847 ui,
1848 }
1849 }
1850}
1851
1852impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat3<'ui, 'p, L, F> {
1853 pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat3<'ui, 'p, L, F2> {
1855 InputFloat3 {
1856 label: self.label,
1857 value: self.value,
1858 display_format: Some(display_format),
1859 flags: self.flags,
1860 ui: self.ui,
1861 }
1862 }
1863
1864 #[inline]
1866 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1867 self.flags = flags;
1868 self
1869 }
1870
1871 pub fn build(self) -> bool {
1875 unsafe {
1876 let (one, two) = self
1877 .ui
1878 .scratch_txt_with_opt(self.label, self.display_format);
1879
1880 sys::igInputFloat3(one, self.value.as_mut_ptr(), two, self.flags.bits() as i32)
1881 }
1882 }
1883}
1884
1885#[must_use]
1887pub struct InputFloat4<'ui, 'p, L, F = &'static str> {
1888 label: L,
1889 value: &'p mut [f32; 4],
1890 display_format: Option<F>,
1891 flags: InputTextFlags,
1892 ui: &'ui Ui,
1893}
1894
1895impl<'ui, 'p, L: AsRef<str>> InputFloat4<'ui, 'p, L> {
1896 #[doc(alias = "InputFloat4")]
1898 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 4]) -> Self {
1899 InputFloat4 {
1900 label,
1901 value,
1902 display_format: None,
1903 flags: InputTextFlags::empty(),
1904 ui,
1905 }
1906 }
1907}
1908
1909impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat4<'ui, 'p, L, F> {
1910 pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat4<'ui, 'p, L, F2> {
1912 InputFloat4 {
1913 label: self.label,
1914 value: self.value,
1915 display_format: Some(display_format),
1916 flags: self.flags,
1917 ui: self.ui,
1918 }
1919 }
1920
1921 #[inline]
1923 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1924 self.flags = flags;
1925 self
1926 }
1927
1928 pub fn build(self) -> bool {
1932 unsafe {
1933 let (one, two) = self
1934 .ui
1935 .scratch_txt_with_opt(self.label, self.display_format);
1936
1937 sys::igInputFloat4(one, self.value.as_mut_ptr(), two, self.flags.bits() as i32)
1938 }
1939 }
1940}
1941
1942#[must_use]
1944pub struct InputInt2<'ui, 'p, L> {
1945 label: L,
1946 value: &'p mut [i32; 2],
1947 flags: InputTextFlags,
1948 ui: &'ui Ui,
1949}
1950
1951impl<'ui, 'p, L: AsRef<str>> InputInt2<'ui, 'p, L> {
1952 #[doc(alias = "InputInt2")]
1954 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 2]) -> Self {
1955 InputInt2 {
1956 label,
1957 value,
1958 flags: InputTextFlags::empty(),
1959 ui,
1960 }
1961 }
1962
1963 #[inline]
1965 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1966 self.flags = flags;
1967 self
1968 }
1969
1970 pub fn build(self) -> bool {
1974 unsafe {
1975 let label_cstr = self.ui.scratch_txt(self.label);
1976
1977 sys::igInputInt2(
1978 label_cstr,
1979 self.value.as_mut_ptr(),
1980 self.flags.bits() as i32,
1981 )
1982 }
1983 }
1984}
1985
1986#[must_use]
1988pub struct InputInt3<'ui, 'p, L> {
1989 label: L,
1990 value: &'p mut [i32; 3],
1991 flags: InputTextFlags,
1992 ui: &'ui Ui,
1993}
1994
1995impl<'ui, 'p, L: AsRef<str>> InputInt3<'ui, 'p, L> {
1996 #[doc(alias = "InputInt3")]
1998 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 3]) -> Self {
1999 InputInt3 {
2000 label,
2001 value,
2002 flags: InputTextFlags::empty(),
2003 ui,
2004 }
2005 }
2006
2007 #[inline]
2009 pub fn flags(mut self, flags: InputTextFlags) -> Self {
2010 self.flags = flags;
2011 self
2012 }
2013
2014 pub fn build(self) -> bool {
2018 unsafe {
2019 let label_cstr = self.ui.scratch_txt(self.label);
2020
2021 sys::igInputInt3(
2022 label_cstr,
2023 self.value.as_mut_ptr(),
2024 self.flags.bits() as i32,
2025 )
2026 }
2027 }
2028}
2029
2030#[must_use]
2032pub struct InputInt4<'ui, 'p, L> {
2033 label: L,
2034 value: &'p mut [i32; 4],
2035 flags: InputTextFlags,
2036 ui: &'ui Ui,
2037}
2038
2039impl<'ui, 'p, L: AsRef<str>> InputInt4<'ui, 'p, L> {
2040 #[doc(alias = "InputInt4")]
2042 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 4]) -> Self {
2043 InputInt4 {
2044 label,
2045 value,
2046 flags: InputTextFlags::empty(),
2047 ui,
2048 }
2049 }
2050
2051 #[inline]
2053 pub fn flags(mut self, flags: InputTextFlags) -> Self {
2054 self.flags = flags;
2055 self
2056 }
2057
2058 pub fn build(self) -> bool {
2062 unsafe {
2063 let label_cstr = self.ui.scratch_txt(self.label);
2064
2065 sys::igInputInt4(
2066 label_cstr,
2067 self.value.as_mut_ptr(),
2068 self.flags.bits() as i32,
2069 )
2070 }
2071 }
2072}
2073
2074#[cfg(test)]
2075mod tests {
2076 use super::*;
2077
2078 #[test]
2079 fn zero_string_spare_capacity_writes_nul_bytes() {
2080 let mut s = String::with_capacity(16);
2081 s.push_str("abc");
2082 let len = s.len();
2083 let cap = s.capacity();
2084
2085 zero_string_spare_capacity(&mut s);
2086
2087 unsafe {
2088 let bytes = std::slice::from_raw_parts(s.as_ptr(), cap);
2089 assert_eq!(&bytes[..len], b"abc");
2090 assert!(bytes[len..].iter().all(|&b| b == 0));
2091 }
2092 }
2093
2094 #[test]
2095 fn zero_string_new_capacity_writes_new_region() {
2096 let mut s = String::with_capacity(4);
2097 s.push_str("abc");
2098 let old_cap = s.capacity();
2099
2100 s.reserve(64);
2101 let new_cap = s.capacity();
2102 assert!(new_cap > old_cap);
2103
2104 zero_string_new_capacity(&mut s, old_cap);
2105
2106 unsafe {
2107 let tail = std::slice::from_raw_parts(s.as_ptr().add(old_cap), new_cap - old_cap);
2108 assert!(tail.iter().all(|&b| b == 0));
2109 }
2110 }
2111}