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 as i32) == (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.raw(),
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.raw(),
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 =
564 unsafe { InputTextFlags::from_bits_truncate((*data).EventFlag as i32) };
565 match event_flag {
566 InputTextFlags::CALLBACK_RESIZE => unsafe {
567 let requested_i32 = (*data).BufSize;
568 if requested_i32 < 0 {
569 return 0;
570 }
571 let requested = requested_i32 as usize;
572 let s = &mut *user.container;
573 debug_assert_eq!(s.as_ptr() as *const _, (*data).Buf);
574 if requested > s.capacity() {
575 let old_cap = s.capacity();
576 let additional = requested.saturating_sub(s.len());
577 s.reserve(additional);
578 zero_string_new_capacity(s, old_cap);
579 (*data).Buf = s.as_mut_ptr() as *mut _;
580 (*data).BufDirty = true;
581 }
582 0
583 },
584 InputTextFlags::CALLBACK_COMPLETION => {
585 let info = unsafe { TextCallbackData::new(data) };
586 user.handler.on_completion(info);
587 0
588 }
589 InputTextFlags::CALLBACK_HISTORY => {
590 let key = unsafe { (*data).EventKey };
591 let dir = if key == sys::ImGuiKey_UpArrow {
592 HistoryDirection::Up
593 } else {
594 HistoryDirection::Down
595 };
596 let info = unsafe { TextCallbackData::new(data) };
597 user.handler.on_history(dir, info);
598 0
599 }
600 InputTextFlags::CALLBACK_ALWAYS => {
601 let info = unsafe { TextCallbackData::new(data) };
602 user.handler.on_always(info);
603 0
604 }
605 InputTextFlags::CALLBACK_EDIT => {
606 let info = unsafe { TextCallbackData::new(data) };
607 user.handler.on_edit(info);
608 0
609 }
610 InputTextFlags::CALLBACK_CHAR_FILTER => {
611 let ch = unsafe {
612 std::char::from_u32((*data).EventChar as u32).unwrap_or('\0')
613 };
614 let new_ch = user.handler.char_filter(ch).map(|c| c as u32).unwrap_or(0);
615 unsafe {
616 (*data).EventChar =
617 sys::ImWchar::try_from(new_ch).unwrap_or(0 as sys::ImWchar);
618 }
619 0
620 }
621 _ => 0,
622 }
623 }));
624
625 match res {
626 Ok(v) => v,
627 Err(_) => {
628 eprintln!("dear-imgui-rs: panic in InputText callback");
629 std::process::abort();
630 }
631 }
632 }
633
634 let mut user_data = UserData {
635 container: self.buf as *mut String,
636 handler: self.callback_handler,
637 };
638 let user_ptr = &mut user_data as *mut _ as *mut c_void;
639
640 let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
641 let result = unsafe {
642 if hint_ptr.is_null() {
643 sys::igInputText(
644 label_ptr,
645 buf_ptr,
646 capacity,
647 flags.raw(),
648 Some(callback_router::<T>),
649 user_ptr,
650 )
651 } else {
652 sys::igInputTextWithHint(
653 label_ptr,
654 hint_ptr,
655 buf_ptr,
656 capacity,
657 flags.raw(),
658 Some(callback_router::<T>),
659 user_ptr,
660 )
661 }
662 };
663
664 let cap = unsafe { (&*user_data.container).capacity() };
666 let slice = unsafe { std::slice::from_raw_parts((&*user_data.container).as_ptr(), cap) };
667 if let Some(len) = slice.iter().position(|&b| b == 0) {
668 unsafe { (&mut *user_data.container).as_mut_vec().set_len(len) };
669 }
670 result
671 }
672}
673
674#[derive(Debug)]
676#[must_use]
677pub struct InputTextMultiline<'ui, 'p> {
678 ui: &'ui Ui,
679 label: Cow<'ui, str>,
680 buf: &'p mut String,
681 size: [f32; 2],
682 flags: InputTextFlags,
683 capacity_hint: Option<usize>,
684}
685
686#[derive(Debug)]
688#[must_use]
689pub struct InputTextMultilineImStr<'ui, 'p> {
690 ui: &'ui Ui,
691 label: Cow<'ui, str>,
692 buf: &'p mut ImString,
693 size: [f32; 2],
694 flags: InputTextFlags,
695}
696
697impl<'ui, 'p> InputTextMultilineImStr<'ui, 'p> {
698 pub fn new(
699 ui: &'ui Ui,
700 label: impl Into<Cow<'ui, str>>,
701 buf: &'p mut ImString,
702 size: impl Into<[f32; 2]>,
703 ) -> Self {
704 Self {
705 ui,
706 label: label.into(),
707 buf,
708 size: size.into(),
709 flags: InputTextFlags::NONE,
710 }
711 }
712 pub fn flags(mut self, flags: InputTextFlags) -> Self {
713 self.flags = flags;
714 self
715 }
716 pub fn read_only(mut self, v: bool) -> Self {
717 self.flags.set(InputTextFlags::READ_ONLY, v);
718 self
719 }
720 pub fn build(self) -> bool {
721 let label_ptr = self.ui.scratch_txt(self.label.as_ref());
722 let buf_size = self.buf.capacity_with_nul().max(1);
723 self.buf.ensure_buf_size(buf_size);
724 let buf_ptr = self.buf.as_mut_ptr();
725 let user_ptr = self.buf as *mut ImString as *mut c_void;
726 let size_vec: sys::ImVec2 = self.size.into();
727
728 extern "C" fn resize_cb_imstr(data: *mut sys::ImGuiInputTextCallbackData) -> c_int {
729 if data.is_null() {
730 return 0;
731 }
732 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
733 if ((*data).EventFlag as i32) == (sys::ImGuiInputTextFlags_CallbackResize as i32) {
734 let user_data = (*data).UserData as *mut ImString;
735 if user_data.is_null() {
736 return;
737 }
738
739 let im = &mut *user_data;
740 let requested_i32 = (*data).BufSize;
741 if requested_i32 < 0 {
742 return;
743 }
744 let requested = requested_i32 as usize;
745 im.ensure_buf_size(requested);
746 (*data).Buf = im.as_mut_ptr();
747 (*data).BufDirty = true;
748 }
749 }));
750 if res.is_err() {
751 eprintln!("dear-imgui-rs: panic in ImString multiline resize callback");
752 std::process::abort();
753 }
754 0
755 }
756
757 let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
758 let result = unsafe {
759 sys::igInputTextMultiline(
760 label_ptr,
761 buf_ptr,
762 buf_size,
763 size_vec,
764 flags.raw(),
765 Some(resize_cb_imstr),
766 user_ptr,
767 )
768 };
769 unsafe { self.buf.refresh_len() };
771 result
772 }
773}
774impl<'ui, 'p> InputTextMultiline<'ui, 'p> {
775 pub fn new(
777 ui: &'ui Ui,
778 label: impl Into<Cow<'ui, str>>,
779 buf: &'p mut String,
780 size: impl Into<[f32; 2]>,
781 ) -> Self {
782 Self {
783 ui,
784 label: label.into(),
785 buf,
786 size: size.into(),
787 flags: InputTextFlags::NONE,
788 capacity_hint: None,
789 }
790 }
791
792 pub fn flags(mut self, flags: InputTextFlags) -> Self {
794 self.flags = flags;
795 self
796 }
797
798 pub fn capacity_hint(mut self, cap: usize) -> Self {
800 self.capacity_hint = Some(cap);
801 self
802 }
803
804 pub fn read_only(mut self, read_only: bool) -> Self {
806 self.flags.set(InputTextFlags::READ_ONLY, read_only);
807 self
808 }
809
810 pub fn build(self) -> bool {
812 let label_ptr = self.ui.scratch_txt(self.label.as_ref());
813
814 if let Some(extra) = self.capacity_hint {
816 let needed = extra.saturating_sub(self.buf.capacity().saturating_sub(self.buf.len()));
817 if needed > 0 {
818 self.buf.reserve(needed);
819 }
820 }
821
822 self.buf.push('\0');
824 zero_string_spare_capacity(self.buf);
826 let capacity = self.buf.capacity();
827 let buf_ptr = self.buf.as_mut_ptr() as *mut std::os::raw::c_char;
828
829 #[repr(C)]
830 struct UserData {
831 container: *mut String,
832 }
833
834 extern "C" fn callback_router(data: *mut sys::ImGuiInputTextCallbackData) -> c_int {
835 if data.is_null() {
836 return 0;
837 }
838
839 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
840 let event_flag = InputTextFlags::from_bits_truncate((*data).EventFlag as i32);
841 match event_flag {
842 InputTextFlags::CALLBACK_RESIZE => {
843 let user_ptr = (*data).UserData as *mut UserData;
844 if user_ptr.is_null() {
845 return 0;
846 }
847 let requested_i32 = (*data).BufSize;
848 if requested_i32 < 0 {
849 return 0;
850 }
851 let requested = requested_i32 as usize;
852
853 let user = &mut *user_ptr;
854 if user.container.is_null() {
855 return 0;
856 }
857 let s = &mut *user.container;
858 debug_assert_eq!(s.as_ptr() as *const _, (*data).Buf);
859 if requested > s.capacity() {
860 let old_cap = s.capacity();
861 let additional = requested.saturating_sub(s.len());
862 s.reserve(additional);
863 zero_string_new_capacity(s, old_cap);
864 (*data).Buf = s.as_mut_ptr() as *mut _;
865 (*data).BufDirty = true;
866 }
867 0
868 }
869 _ => 0,
870 }
871 }));
872
873 match res {
874 Ok(v) => v,
875 Err(_) => {
876 eprintln!("dear-imgui-rs: panic in multiline InputText resize callback");
877 std::process::abort();
878 }
879 }
880 }
881
882 let mut user_data = UserData {
883 container: self.buf as *mut String,
884 };
885 let user_ptr = &mut user_data as *mut _ as *mut c_void;
886
887 let size_vec: sys::ImVec2 = self.size.into();
888 let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
889 let result = unsafe {
890 sys::igInputTextMultiline(
891 label_ptr,
892 buf_ptr,
893 capacity,
894 size_vec,
895 flags.raw(),
896 Some(callback_router),
897 user_ptr,
898 )
899 };
900
901 let cap = unsafe { (&*user_data.container).capacity() };
903 let slice = unsafe { std::slice::from_raw_parts((&*user_data.container).as_ptr(), cap) };
904 if let Some(len) = slice.iter().position(|&b| b == 0) {
905 unsafe { (&mut *user_data.container).as_mut_vec().set_len(len) };
906 }
907 result
908 }
909
910 pub fn callback<T2: InputTextCallbackHandler>(
912 mut self,
913 callbacks: InputTextCallback,
914 handler: T2,
915 ) -> InputTextMultilineWithCb<'ui, 'p, T2> {
916 if callbacks.contains(InputTextCallback::ALWAYS) {
919 self.flags.insert(InputTextFlags::CALLBACK_ALWAYS);
920 }
921 if callbacks.contains(InputTextCallback::CHAR_FILTER) {
922 self.flags.insert(InputTextFlags::CALLBACK_CHAR_FILTER);
923 }
924 if callbacks.contains(InputTextCallback::EDIT) {
925 self.flags.insert(InputTextFlags::CALLBACK_EDIT);
926 }
927
928 InputTextMultilineWithCb {
929 ui: self.ui,
930 label: self.label,
931 buf: self.buf,
932 size: self.size,
933 flags: self.flags,
934 capacity_hint: self.capacity_hint,
935 handler,
936 }
937 }
938}
939
940pub struct InputTextMultilineWithCb<'ui, 'p, T> {
942 ui: &'ui Ui,
943 label: Cow<'ui, str>,
944 buf: &'p mut String,
945 size: [f32; 2],
946 flags: InputTextFlags,
947 capacity_hint: Option<usize>,
948 handler: T,
949}
950
951impl<'ui, 'p, T: InputTextCallbackHandler> InputTextMultilineWithCb<'ui, 'p, T> {
952 pub fn build(self) -> bool {
953 let label_ptr = self.ui.scratch_txt(self.label.as_ref());
954
955 if let Some(extra) = self.capacity_hint {
956 let needed = extra.saturating_sub(self.buf.capacity().saturating_sub(self.buf.len()));
957 if needed > 0 {
958 self.buf.reserve(needed);
959 }
960 }
961
962 self.buf.push('\0');
964 zero_string_spare_capacity(self.buf);
966 let capacity = self.buf.capacity();
967 let buf_ptr = self.buf.as_mut_ptr() as *mut std::os::raw::c_char;
968
969 #[repr(C)]
970 struct UserData<T> {
971 container: *mut String,
972 handler: T,
973 }
974
975 extern "C" fn callback_router<T: InputTextCallbackHandler>(
976 data: *mut sys::ImGuiInputTextCallbackData,
977 ) -> c_int {
978 if data.is_null() {
979 return 0;
980 }
981
982 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
983 let user_ptr = unsafe { (*data).UserData as *mut UserData<T> };
984 if user_ptr.is_null() {
985 return 0;
986 }
987 let user = unsafe { &mut *user_ptr };
988 if user.container.is_null() {
989 return 0;
990 }
991
992 let event_flag =
993 unsafe { InputTextFlags::from_bits_truncate((*data).EventFlag as i32) };
994 match event_flag {
995 InputTextFlags::CALLBACK_RESIZE => unsafe {
996 let requested_i32 = (*data).BufSize;
997 if requested_i32 < 0 {
998 return 0;
999 }
1000 let requested = requested_i32 as usize;
1001 let s = &mut *user.container;
1002 debug_assert_eq!(s.as_ptr() as *const _, (*data).Buf);
1003 if requested > s.capacity() {
1004 let old_cap = s.capacity();
1005 let additional = requested.saturating_sub(s.len());
1006 s.reserve(additional);
1007 zero_string_new_capacity(s, old_cap);
1008 (*data).Buf = s.as_mut_ptr() as *mut _;
1009 (*data).BufDirty = true;
1010 }
1011 0
1012 },
1013 InputTextFlags::CALLBACK_COMPLETION => {
1014 let info = unsafe { TextCallbackData::new(data) };
1015 user.handler.on_completion(info);
1016 0
1017 }
1018 InputTextFlags::CALLBACK_HISTORY => {
1019 let key = unsafe { (*data).EventKey };
1020 let dir = if key == sys::ImGuiKey_UpArrow {
1021 HistoryDirection::Up
1022 } else {
1023 HistoryDirection::Down
1024 };
1025 let info = unsafe { TextCallbackData::new(data) };
1026 user.handler.on_history(dir, info);
1027 0
1028 }
1029 InputTextFlags::CALLBACK_ALWAYS => {
1030 let info = unsafe { TextCallbackData::new(data) };
1031 user.handler.on_always(info);
1032 0
1033 }
1034 InputTextFlags::CALLBACK_EDIT => {
1035 let info = unsafe { TextCallbackData::new(data) };
1036 user.handler.on_edit(info);
1037 0
1038 }
1039 InputTextFlags::CALLBACK_CHAR_FILTER => {
1040 let ch = unsafe {
1041 std::char::from_u32((*data).EventChar as u32).unwrap_or('\0')
1042 };
1043 let new_ch = user.handler.char_filter(ch).map(|c| c as u32).unwrap_or(0);
1044 unsafe {
1045 (*data).EventChar =
1046 sys::ImWchar::try_from(new_ch).unwrap_or(0 as sys::ImWchar);
1047 }
1048 0
1049 }
1050 _ => 0,
1051 }
1052 }));
1053
1054 match res {
1055 Ok(v) => v,
1056 Err(_) => {
1057 eprintln!("dear-imgui-rs: panic in InputText multiline callback");
1058 std::process::abort();
1059 }
1060 }
1061 }
1062
1063 let mut user_data = UserData {
1064 container: self.buf as *mut String,
1065 handler: self.handler,
1066 };
1067 let user_ptr = &mut user_data as *mut _ as *mut c_void;
1068
1069 let size_vec: sys::ImVec2 = self.size.into();
1070 let flags = self.flags | InputTextFlags::CALLBACK_RESIZE;
1071 let result = unsafe {
1072 sys::igInputTextMultiline(
1073 label_ptr,
1074 buf_ptr,
1075 capacity,
1076 size_vec,
1077 flags.raw(),
1078 Some(callback_router::<T>),
1079 user_ptr,
1080 )
1081 };
1082
1083 let cap = unsafe { (&*user_data.container).capacity() };
1085 let slice = unsafe { std::slice::from_raw_parts((&*user_data.container).as_ptr(), cap) };
1086 if let Some(len) = slice.iter().position(|&b| b == 0) {
1087 unsafe { (&mut *user_data.container).as_mut_vec().set_len(len) };
1088 }
1089 result
1090 }
1091}
1092
1093#[derive(Debug)]
1095#[must_use]
1096pub struct InputInt<'ui> {
1097 ui: &'ui Ui,
1098 label: Cow<'ui, str>,
1099 step: i32,
1100 step_fast: i32,
1101 flags: InputTextFlags,
1102}
1103
1104impl<'ui> InputInt<'ui> {
1105 pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>) -> Self {
1107 Self {
1108 ui,
1109 label: label.into(),
1110 step: 1,
1111 step_fast: 100,
1112 flags: InputTextFlags::NONE,
1113 }
1114 }
1115
1116 pub fn step(mut self, step: i32) -> Self {
1118 self.step = step;
1119 self
1120 }
1121
1122 pub fn step_fast(mut self, step_fast: i32) -> Self {
1124 self.step_fast = step_fast;
1125 self
1126 }
1127
1128 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1130 self.flags = flags;
1131 self
1132 }
1133
1134 pub fn build(self, value: &mut i32) -> bool {
1136 let label_ptr = self.ui.scratch_txt(self.label.as_ref());
1137 unsafe {
1138 sys::igInputInt(
1139 label_ptr,
1140 value as *mut i32,
1141 self.step,
1142 self.step_fast,
1143 self.flags.raw(),
1144 )
1145 }
1146 }
1147}
1148
1149#[derive(Debug)]
1151#[must_use]
1152pub struct InputFloat<'ui> {
1153 ui: &'ui Ui,
1154 label: Cow<'ui, str>,
1155 step: f32,
1156 step_fast: f32,
1157 format: Option<Cow<'ui, str>>,
1158 flags: InputTextFlags,
1159}
1160
1161impl<'ui> InputFloat<'ui> {
1162 pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>) -> Self {
1164 Self {
1165 ui,
1166 label: label.into(),
1167 step: 0.0,
1168 step_fast: 0.0,
1169 format: None,
1170 flags: InputTextFlags::NONE,
1171 }
1172 }
1173
1174 pub fn step(mut self, step: f32) -> Self {
1176 self.step = step;
1177 self
1178 }
1179
1180 pub fn step_fast(mut self, step_fast: f32) -> Self {
1182 self.step_fast = step_fast;
1183 self
1184 }
1185
1186 pub fn format(mut self, format: impl Into<Cow<'ui, str>>) -> Self {
1188 self.format = Some(format.into());
1189 self
1190 }
1191
1192 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1194 self.flags = flags;
1195 self
1196 }
1197
1198 pub fn build(self, value: &mut f32) -> bool {
1200 let format = self.format.as_deref().unwrap_or("%.3f");
1201 let (label_ptr, format_ptr) = self.ui.scratch_txt_two(self.label.as_ref(), format);
1202
1203 unsafe {
1204 sys::igInputFloat(
1205 label_ptr,
1206 value as *mut f32,
1207 self.step,
1208 self.step_fast,
1209 format_ptr,
1210 self.flags.raw(),
1211 )
1212 }
1213 }
1214}
1215
1216#[derive(Debug)]
1218#[must_use]
1219pub struct InputDouble<'ui> {
1220 ui: &'ui Ui,
1221 label: Cow<'ui, str>,
1222 step: f64,
1223 step_fast: f64,
1224 format: Option<Cow<'ui, str>>,
1225 flags: InputTextFlags,
1226}
1227
1228impl<'ui> InputDouble<'ui> {
1229 pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>) -> Self {
1231 Self {
1232 ui,
1233 label: label.into(),
1234 step: 0.0,
1235 step_fast: 0.0,
1236 format: None,
1237 flags: InputTextFlags::NONE,
1238 }
1239 }
1240
1241 pub fn step(mut self, step: f64) -> Self {
1243 self.step = step;
1244 self
1245 }
1246
1247 pub fn step_fast(mut self, step_fast: f64) -> Self {
1249 self.step_fast = step_fast;
1250 self
1251 }
1252
1253 pub fn format(mut self, format: impl Into<Cow<'ui, str>>) -> Self {
1255 self.format = Some(format.into());
1256 self
1257 }
1258
1259 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1261 self.flags = flags;
1262 self
1263 }
1264
1265 pub fn build(self, value: &mut f64) -> bool {
1267 let format = self.format.as_deref().unwrap_or("%.6f");
1268 let (label_ptr, format_ptr) = self.ui.scratch_txt_two(self.label.as_ref(), format);
1269
1270 unsafe {
1271 sys::igInputDouble(
1272 label_ptr,
1273 value as *mut f64,
1274 self.step,
1275 self.step_fast,
1276 format_ptr,
1277 self.flags.raw(),
1278 )
1279 }
1280 }
1281}
1282
1283bitflags::bitflags! {
1287 #[repr(transparent)]
1289 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1290 pub struct InputTextCallback: u32 {
1291 const COMPLETION = sys::ImGuiInputTextFlags_CallbackCompletion as u32;
1293 const HISTORY = sys::ImGuiInputTextFlags_CallbackHistory as u32;
1295 const ALWAYS = sys::ImGuiInputTextFlags_CallbackAlways as u32;
1297 const CHAR_FILTER = sys::ImGuiInputTextFlags_CallbackCharFilter as u32;
1299 const EDIT = sys::ImGuiInputTextFlags_CallbackEdit as u32;
1302 }
1303}
1304
1305#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1307pub enum HistoryDirection {
1308 Up,
1310 Down,
1312}
1313
1314pub trait InputTextCallbackHandler {
1319 fn char_filter(&mut self, _c: char) -> Option<char> {
1324 None
1325 }
1326
1327 fn on_completion(&mut self, _data: TextCallbackData) {}
1331
1332 fn on_history(&mut self, _direction: HistoryDirection, _data: TextCallbackData) {}
1336
1337 fn on_always(&mut self, _data: TextCallbackData) {}
1341
1342 fn on_edit(&mut self, _data: TextCallbackData) {}
1346}
1347
1348pub struct TextCallbackData(*mut sys::ImGuiInputTextCallbackData);
1352
1353impl TextCallbackData {
1354 unsafe fn new(data: *mut sys::ImGuiInputTextCallbackData) -> Self {
1356 Self(data)
1357 }
1358
1359 pub fn str(&self) -> &str {
1361 unsafe {
1362 std::str::from_utf8(std::slice::from_raw_parts(
1363 (*(self.0)).Buf as *const _,
1364 (*(self.0)).BufTextLen as usize,
1365 ))
1366 .expect("internal imgui error -- it boofed a utf8")
1367 }
1368 }
1369
1370 pub fn cursor_pos(&self) -> usize {
1372 unsafe { (*(self.0)).CursorPos as usize }
1373 }
1374
1375 pub fn set_cursor_pos(&mut self, pos: usize) {
1377 unsafe {
1378 (*(self.0)).CursorPos = pos as i32;
1379 }
1380 }
1381
1382 pub fn selection_start(&self) -> usize {
1384 unsafe { (*(self.0)).SelectionStart as usize }
1385 }
1386
1387 pub fn set_selection_start(&mut self, pos: usize) {
1389 unsafe {
1390 (*(self.0)).SelectionStart = pos as i32;
1391 }
1392 }
1393
1394 pub fn selection_end(&self) -> usize {
1396 unsafe { (*(self.0)).SelectionEnd as usize }
1397 }
1398
1399 pub fn set_selection_end(&mut self, pos: usize) {
1401 unsafe {
1402 (*(self.0)).SelectionEnd = pos as i32;
1403 }
1404 }
1405
1406 pub fn select_all(&mut self) {
1408 unsafe {
1409 (*(self.0)).SelectionStart = 0;
1410 (*(self.0)).SelectionEnd = (*(self.0)).BufTextLen;
1411 }
1412 }
1413
1414 pub fn clear_selection(&mut self) {
1416 unsafe {
1417 (*(self.0)).SelectionStart = (*(self.0)).CursorPos;
1418 (*(self.0)).SelectionEnd = (*(self.0)).CursorPos;
1419 }
1420 }
1421
1422 pub fn has_selection(&self) -> bool {
1424 unsafe { (*(self.0)).SelectionStart != (*(self.0)).SelectionEnd }
1425 }
1426
1427 pub fn remove_chars(&mut self, pos: usize, bytes_count: usize) {
1429 unsafe {
1430 sys::ImGuiInputTextCallbackData_DeleteChars(self.0, pos as i32, bytes_count as i32);
1431 }
1432 }
1433
1434 pub fn insert_chars(&mut self, pos: usize, text: &str) {
1436 let text_ptr = text.as_ptr() as *const std::os::raw::c_char;
1437 unsafe {
1438 sys::ImGuiInputTextCallbackData_InsertChars(
1439 self.0,
1440 pos as i32,
1441 text_ptr,
1442 text_ptr.add(text.len()),
1443 );
1444 }
1445 }
1446
1447 pub unsafe fn str_as_bytes_mut(&mut self) -> &mut [u8] {
1467 unsafe {
1468 assert!(
1469 !(*(self.0)).Buf.is_null(),
1470 "internal imgui error: Buf was null"
1471 );
1472 assert!(
1473 (*(self.0)).BufTextLen >= 0,
1474 "internal imgui error: BufTextLen was negative"
1475 );
1476 assert!(
1477 (*(self.0)).BufSize >= 0,
1478 "internal imgui error: BufSize was negative"
1479 );
1480 assert!(
1481 (*(self.0)).BufTextLen <= (*(self.0)).BufSize,
1482 "internal imgui error: BufTextLen exceeded BufSize"
1483 );
1484
1485 let str = std::str::from_utf8_mut(std::slice::from_raw_parts_mut(
1486 (*(self.0)).Buf as *mut u8,
1487 (*(self.0)).BufTextLen as usize,
1488 ))
1489 .expect("internal imgui error -- it boofed a utf8");
1490
1491 str.as_bytes_mut()
1492 }
1493 }
1494
1495 pub fn set_dirty(&mut self) {
1507 unsafe {
1508 (*(self.0)).BufDirty = true;
1509 }
1510 }
1511
1512 pub fn selected(&self) -> &str {
1515 let start = self.selection_start().min(self.selection_end());
1516 let end = self.selection_start().max(self.selection_end());
1517 &self.str()[start..end]
1518 }
1519
1520 pub fn push_str(&mut self, text: &str) {
1524 let current_len = unsafe { (*(self.0)).BufTextLen as usize };
1525 self.insert_chars(current_len, text);
1526 }
1527}
1528
1529pub struct PassthroughCallback;
1534impl InputTextCallbackHandler for PassthroughCallback {}
1535
1536extern "C" fn callback(data: *mut sys::ImGuiInputTextCallbackData) -> c_int {
1538 if data.is_null() {
1539 return 0;
1540 }
1541
1542 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
1543 let event_flag = InputTextFlags::from_bits_truncate((*data).EventFlag as i32);
1544 let buffer_ptr = (*data).UserData as *mut String;
1545
1546 if buffer_ptr.is_null() {
1547 return;
1548 }
1549
1550 match event_flag {
1551 InputTextFlags::CALLBACK_RESIZE => {
1552 let requested_i32 = (*data).BufSize;
1553 if requested_i32 < 0 {
1554 return;
1555 }
1556 let requested_size = requested_i32 as usize;
1557 let buffer = &mut *buffer_ptr;
1558
1559 debug_assert_eq!(buffer.as_ptr() as *const _, (*data).Buf);
1560
1561 if requested_size > buffer.capacity() {
1562 let additional_bytes = requested_size.saturating_sub(buffer.len());
1563 buffer.reserve(additional_bytes);
1564
1565 (*data).Buf = buffer.as_mut_ptr() as *mut _;
1566 (*data).BufDirty = true;
1567 }
1568 }
1569 _ => {}
1570 }
1571 }));
1572
1573 if res.is_err() {
1574 eprintln!("dear-imgui-rs: panic in legacy InputText callback");
1575 std::process::abort();
1576 }
1577 0
1578}
1579
1580#[must_use]
1582pub struct InputScalar<'ui, 'p, T, L, F = &'static str> {
1583 value: &'p mut T,
1584 label: L,
1585 step: Option<T>,
1586 step_fast: Option<T>,
1587 display_format: Option<F>,
1588 flags: InputTextFlags,
1589 ui: &'ui Ui,
1590}
1591
1592impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind> InputScalar<'ui, 'p, T, L> {
1593 #[doc(alias = "InputScalar")]
1595 pub fn new(ui: &'ui Ui, label: L, value: &'p mut T) -> Self {
1596 InputScalar {
1597 value,
1598 label,
1599 step: None,
1600 step_fast: None,
1601 display_format: None,
1602 flags: InputTextFlags::empty(),
1603 ui,
1604 }
1605 }
1606}
1607
1608impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind, F: AsRef<str>> InputScalar<'ui, 'p, T, L, F> {
1609 pub fn display_format<F2: AsRef<str>>(
1611 self,
1612 display_format: F2,
1613 ) -> InputScalar<'ui, 'p, T, L, F2> {
1614 InputScalar {
1615 value: self.value,
1616 label: self.label,
1617 step: self.step,
1618 step_fast: self.step_fast,
1619 display_format: Some(display_format),
1620 flags: self.flags,
1621 ui: self.ui,
1622 }
1623 }
1624
1625 #[inline]
1627 pub fn step(mut self, value: T) -> Self {
1628 self.step = Some(value);
1629 self
1630 }
1631
1632 #[inline]
1634 pub fn step_fast(mut self, value: T) -> Self {
1635 self.step_fast = Some(value);
1636 self
1637 }
1638
1639 #[inline]
1641 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1642 self.flags = flags;
1643 self
1644 }
1645
1646 pub fn build(self) -> bool {
1650 unsafe {
1651 let (one, two) = self
1652 .ui
1653 .scratch_txt_with_opt(self.label, self.display_format);
1654
1655 sys::igInputScalar(
1656 one,
1657 T::KIND as i32,
1658 self.value as *mut T as *mut c_void,
1659 self.step
1660 .as_ref()
1661 .map(|step| step as *const T)
1662 .unwrap_or(ptr::null()) as *const c_void,
1663 self.step_fast
1664 .as_ref()
1665 .map(|step| step as *const T)
1666 .unwrap_or(ptr::null()) as *const c_void,
1667 two,
1668 self.flags.raw(),
1669 )
1670 }
1671 }
1672}
1673
1674#[must_use]
1676pub struct InputScalarN<'ui, 'p, T, L, F = &'static str> {
1677 values: &'p mut [T],
1678 label: L,
1679 step: Option<T>,
1680 step_fast: Option<T>,
1681 display_format: Option<F>,
1682 flags: InputTextFlags,
1683 ui: &'ui Ui,
1684}
1685
1686impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind> InputScalarN<'ui, 'p, T, L> {
1687 #[doc(alias = "InputScalarN")]
1689 pub fn new(ui: &'ui Ui, label: L, values: &'p mut [T]) -> Self {
1690 InputScalarN {
1691 values,
1692 label,
1693 step: None,
1694 step_fast: None,
1695 display_format: None,
1696 flags: InputTextFlags::empty(),
1697 ui,
1698 }
1699 }
1700}
1701
1702impl<'ui, 'p, L: AsRef<str>, T: DataTypeKind, F: AsRef<str>> InputScalarN<'ui, 'p, T, L, F> {
1703 pub fn display_format<F2: AsRef<str>>(
1705 self,
1706 display_format: F2,
1707 ) -> InputScalarN<'ui, 'p, T, L, F2> {
1708 InputScalarN {
1709 values: self.values,
1710 label: self.label,
1711 step: self.step,
1712 step_fast: self.step_fast,
1713 display_format: Some(display_format),
1714 flags: self.flags,
1715 ui: self.ui,
1716 }
1717 }
1718
1719 #[inline]
1721 pub fn step(mut self, value: T) -> Self {
1722 self.step = Some(value);
1723 self
1724 }
1725
1726 #[inline]
1728 pub fn step_fast(mut self, value: T) -> Self {
1729 self.step_fast = Some(value);
1730 self
1731 }
1732
1733 #[inline]
1735 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1736 self.flags = flags;
1737 self
1738 }
1739
1740 pub fn build(self) -> bool {
1744 let count = match i32::try_from(self.values.len()) {
1745 Ok(n) => n,
1746 Err(_) => return false,
1747 };
1748 unsafe {
1749 let (one, two) = self
1750 .ui
1751 .scratch_txt_with_opt(self.label, self.display_format);
1752
1753 sys::igInputScalarN(
1754 one,
1755 T::KIND as i32,
1756 self.values.as_mut_ptr() as *mut c_void,
1757 count,
1758 self.step
1759 .as_ref()
1760 .map(|step| step as *const T)
1761 .unwrap_or(ptr::null()) as *const c_void,
1762 self.step_fast
1763 .as_ref()
1764 .map(|step| step as *const T)
1765 .unwrap_or(ptr::null()) as *const c_void,
1766 two,
1767 self.flags.raw(),
1768 )
1769 }
1770 }
1771}
1772
1773#[must_use]
1775pub struct InputFloat2<'ui, 'p, L, F = &'static str> {
1776 label: L,
1777 value: &'p mut [f32; 2],
1778 display_format: Option<F>,
1779 flags: InputTextFlags,
1780 ui: &'ui Ui,
1781}
1782
1783impl<'ui, 'p, L: AsRef<str>> InputFloat2<'ui, 'p, L> {
1784 #[doc(alias = "InputFloat2")]
1786 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 2]) -> Self {
1787 InputFloat2 {
1788 label,
1789 value,
1790 display_format: None,
1791 flags: InputTextFlags::empty(),
1792 ui,
1793 }
1794 }
1795}
1796
1797impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat2<'ui, 'p, L, F> {
1798 pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat2<'ui, 'p, L, F2> {
1800 InputFloat2 {
1801 label: self.label,
1802 value: self.value,
1803 display_format: Some(display_format),
1804 flags: self.flags,
1805 ui: self.ui,
1806 }
1807 }
1808
1809 #[inline]
1811 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1812 self.flags = flags;
1813 self
1814 }
1815
1816 pub fn build(self) -> bool {
1820 unsafe {
1821 let (one, two) = self
1822 .ui
1823 .scratch_txt_with_opt(self.label, self.display_format);
1824
1825 sys::igInputFloat2(one, self.value.as_mut_ptr(), two, self.flags.raw())
1826 }
1827 }
1828}
1829
1830#[must_use]
1832pub struct InputFloat3<'ui, 'p, L, F = &'static str> {
1833 label: L,
1834 value: &'p mut [f32; 3],
1835 display_format: Option<F>,
1836 flags: InputTextFlags,
1837 ui: &'ui Ui,
1838}
1839
1840impl<'ui, 'p, L: AsRef<str>> InputFloat3<'ui, 'p, L> {
1841 #[doc(alias = "InputFloat3")]
1843 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 3]) -> Self {
1844 InputFloat3 {
1845 label,
1846 value,
1847 display_format: None,
1848 flags: InputTextFlags::empty(),
1849 ui,
1850 }
1851 }
1852}
1853
1854impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat3<'ui, 'p, L, F> {
1855 pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat3<'ui, 'p, L, F2> {
1857 InputFloat3 {
1858 label: self.label,
1859 value: self.value,
1860 display_format: Some(display_format),
1861 flags: self.flags,
1862 ui: self.ui,
1863 }
1864 }
1865
1866 #[inline]
1868 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1869 self.flags = flags;
1870 self
1871 }
1872
1873 pub fn build(self) -> bool {
1877 unsafe {
1878 let (one, two) = self
1879 .ui
1880 .scratch_txt_with_opt(self.label, self.display_format);
1881
1882 sys::igInputFloat3(one, self.value.as_mut_ptr(), two, self.flags.raw())
1883 }
1884 }
1885}
1886
1887#[must_use]
1889pub struct InputFloat4<'ui, 'p, L, F = &'static str> {
1890 label: L,
1891 value: &'p mut [f32; 4],
1892 display_format: Option<F>,
1893 flags: InputTextFlags,
1894 ui: &'ui Ui,
1895}
1896
1897impl<'ui, 'p, L: AsRef<str>> InputFloat4<'ui, 'p, L> {
1898 #[doc(alias = "InputFloat4")]
1900 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [f32; 4]) -> Self {
1901 InputFloat4 {
1902 label,
1903 value,
1904 display_format: None,
1905 flags: InputTextFlags::empty(),
1906 ui,
1907 }
1908 }
1909}
1910
1911impl<'ui, 'p, L: AsRef<str>, F: AsRef<str>> InputFloat4<'ui, 'p, L, F> {
1912 pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> InputFloat4<'ui, 'p, L, F2> {
1914 InputFloat4 {
1915 label: self.label,
1916 value: self.value,
1917 display_format: Some(display_format),
1918 flags: self.flags,
1919 ui: self.ui,
1920 }
1921 }
1922
1923 #[inline]
1925 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1926 self.flags = flags;
1927 self
1928 }
1929
1930 pub fn build(self) -> bool {
1934 unsafe {
1935 let (one, two) = self
1936 .ui
1937 .scratch_txt_with_opt(self.label, self.display_format);
1938
1939 sys::igInputFloat4(one, self.value.as_mut_ptr(), two, self.flags.raw())
1940 }
1941 }
1942}
1943
1944#[must_use]
1946pub struct InputInt2<'ui, 'p, L> {
1947 label: L,
1948 value: &'p mut [i32; 2],
1949 flags: InputTextFlags,
1950 ui: &'ui Ui,
1951}
1952
1953impl<'ui, 'p, L: AsRef<str>> InputInt2<'ui, 'p, L> {
1954 #[doc(alias = "InputInt2")]
1956 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 2]) -> Self {
1957 InputInt2 {
1958 label,
1959 value,
1960 flags: InputTextFlags::empty(),
1961 ui,
1962 }
1963 }
1964
1965 #[inline]
1967 pub fn flags(mut self, flags: InputTextFlags) -> Self {
1968 self.flags = flags;
1969 self
1970 }
1971
1972 pub fn build(self) -> bool {
1976 unsafe {
1977 let label_cstr = self.ui.scratch_txt(self.label);
1978
1979 sys::igInputInt2(label_cstr, self.value.as_mut_ptr(), self.flags.raw())
1980 }
1981 }
1982}
1983
1984#[must_use]
1986pub struct InputInt3<'ui, 'p, L> {
1987 label: L,
1988 value: &'p mut [i32; 3],
1989 flags: InputTextFlags,
1990 ui: &'ui Ui,
1991}
1992
1993impl<'ui, 'p, L: AsRef<str>> InputInt3<'ui, 'p, L> {
1994 #[doc(alias = "InputInt3")]
1996 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 3]) -> Self {
1997 InputInt3 {
1998 label,
1999 value,
2000 flags: InputTextFlags::empty(),
2001 ui,
2002 }
2003 }
2004
2005 #[inline]
2007 pub fn flags(mut self, flags: InputTextFlags) -> Self {
2008 self.flags = flags;
2009 self
2010 }
2011
2012 pub fn build(self) -> bool {
2016 unsafe {
2017 let label_cstr = self.ui.scratch_txt(self.label);
2018
2019 sys::igInputInt3(label_cstr, self.value.as_mut_ptr(), self.flags.raw())
2020 }
2021 }
2022}
2023
2024#[must_use]
2026pub struct InputInt4<'ui, 'p, L> {
2027 label: L,
2028 value: &'p mut [i32; 4],
2029 flags: InputTextFlags,
2030 ui: &'ui Ui,
2031}
2032
2033impl<'ui, 'p, L: AsRef<str>> InputInt4<'ui, 'p, L> {
2034 #[doc(alias = "InputInt4")]
2036 pub fn new(ui: &'ui Ui, label: L, value: &'p mut [i32; 4]) -> Self {
2037 InputInt4 {
2038 label,
2039 value,
2040 flags: InputTextFlags::empty(),
2041 ui,
2042 }
2043 }
2044
2045 #[inline]
2047 pub fn flags(mut self, flags: InputTextFlags) -> Self {
2048 self.flags = flags;
2049 self
2050 }
2051
2052 pub fn build(self) -> bool {
2056 unsafe {
2057 let label_cstr = self.ui.scratch_txt(self.label);
2058
2059 sys::igInputInt4(label_cstr, self.value.as_mut_ptr(), self.flags.raw())
2060 }
2061 }
2062}
2063
2064#[cfg(test)]
2065mod tests {
2066 use super::*;
2067
2068 #[test]
2069 fn zero_string_spare_capacity_writes_nul_bytes() {
2070 let mut s = String::with_capacity(16);
2071 s.push_str("abc");
2072 let len = s.len();
2073 let cap = s.capacity();
2074
2075 zero_string_spare_capacity(&mut s);
2076
2077 unsafe {
2078 let bytes = std::slice::from_raw_parts(s.as_ptr(), cap);
2079 assert_eq!(&bytes[..len], b"abc");
2080 assert!(bytes[len..].iter().all(|&b| b == 0));
2081 }
2082 }
2083
2084 #[test]
2085 fn zero_string_new_capacity_writes_new_region() {
2086 let mut s = String::with_capacity(4);
2087 s.push_str("abc");
2088 let old_cap = s.capacity();
2089
2090 s.reserve(64);
2091 let new_cap = s.capacity();
2092 assert!(new_cap > old_cap);
2093
2094 zero_string_new_capacity(&mut s, old_cap);
2095
2096 unsafe {
2097 let tail = std::slice::from_raw_parts(s.as_ptr().add(old_cap), new_cap - old_cap);
2098 assert!(tail.iter().all(|&b| b == 0));
2099 }
2100 }
2101}