1#![allow(clippy::needless_doctest_main)]
2
3#![allow(clippy::missing_safety_doc, clippy::too_many_arguments)]
165
166pub use cgmath;
167use easy_imgui_sys::*;
168use std::borrow::Cow;
169use std::cell::RefCell;
170use std::ffi::{CStr, CString, OsString, c_char, c_void};
171use std::marker::PhantomData;
172use std::mem::MaybeUninit;
173use std::ops::{Deref, DerefMut};
174use std::ptr::{NonNull, null, null_mut};
175use std::time::Duration;
176
177macro_rules! transparent_options {
179 ( $($options:ident)* ; $(#[$attr:meta])* $vis:vis struct $outer:ident ( $inner:ident); ) => {
180 $(#[$attr])*
181 #[repr(transparent)]
182 $vis struct $outer($inner);
183
184 $( transparent_options! { @OPTS $options $outer $inner } )*
185
186 impl $outer {
187 pub fn cast(r: &$inner) -> &$outer {
189 unsafe { &*<*const $inner>::cast(r) }
190 }
191
192 pub fn cast_mut(r: &mut $inner) -> &mut $outer {
196 unsafe { &mut *<*mut $inner>::cast(r) }
197 }
198 }
199 };
200
201 ( @OPTS Deref $outer:ident $inner:ident) => {
202 impl std::ops::Deref for $outer {
203 type Target = $inner;
204 fn deref(&self) -> &Self::Target {
205 &self.0
206 }
207 }
208
209 impl $outer {
210 pub fn get(&self) -> &$inner {
212 &self.0
213 }
214 }
215 };
216
217 ( @OPTS DerefMut $outer:ident $inner:ident) => {
218 impl std::ops::DerefMut for $outer {
219 fn deref_mut(&mut self) -> &mut $inner {
220 &mut self.0
221 }
222 }
223 impl $outer {
224 pub fn get_mut(&mut self) -> &mut $inner {
225 &mut self.0
226 }
227 }
228
229 };
230}
231
232macro_rules! transparent {
234 ( $($tt:tt)* ) => {
235 transparent_options! { Deref ; $($tt)* }
236 };
237}
238
239macro_rules! transparent_mut {
241 ( $($tt:tt)* ) => {
242 transparent_options! { Deref DerefMut ; $($tt)* }
243 };
244}
245
246pub type Vector2 = cgmath::Vector2<f32>;
251
252mod enums;
253mod fontloader;
254mod multisel;
255pub mod style;
256
257pub use easy_imgui_sys::{self, ImGuiID, ImGuiSelectionUserData};
258pub use enums::*;
259pub use fontloader::{GlyphBuildFlags, GlyphLoader, GlyphLoaderArg};
260pub use image;
261pub use mint;
262pub use multisel::*;
263
264use image::GenericImage;
265
266const GEN_BITS: u32 = 8;
272const GEN_ID_BITS: u32 = usize::BITS - GEN_BITS;
273const GEN_MASK: usize = (1 << GEN_BITS) - 1;
274const GEN_ID_MASK: usize = (1 << GEN_ID_BITS) - 1;
275
276fn merge_generation(id: usize, gen_id: usize) -> usize {
277 if (id & GEN_ID_MASK) != id {
278 panic!("UI callback overflow")
279 }
280 (gen_id << GEN_ID_BITS) | id
281}
282fn remove_generation(id: usize, gen_id: usize) -> Option<usize> {
283 if (id >> GEN_ID_BITS) != (gen_id & GEN_MASK) {
284 None
285 } else {
286 Some(id & GEN_ID_MASK)
287 }
288}
289
290pub fn to_v2(v: impl Into<mint::Vector2<f32>>) -> Vector2 {
292 let v = v.into();
293 Vector2 { x: v.x, y: v.y }
294}
295pub const fn vec2(x: f32, y: f32) -> Vector2 {
297 Vector2 { x, y }
298}
299pub const fn im_vec2(x: f32, y: f32) -> ImVec2 {
301 ImVec2 { x, y }
302}
303pub fn v2_to_im(v: impl Into<Vector2>) -> ImVec2 {
305 let v = v.into();
306 ImVec2 { x: v.x, y: v.y }
307}
308pub fn im_to_v2(v: impl Into<ImVec2>) -> Vector2 {
310 let v = v.into();
311 Vector2 { x: v.x, y: v.y }
312}
313
314#[derive(Debug, Copy, Clone, PartialEq)]
316#[repr(C)]
317pub struct Color {
318 pub r: f32,
320 pub g: f32,
322 pub b: f32,
324 pub a: f32,
326}
327impl Color {
328 pub const TRANSPARENT: Color = Color::new(0.0, 0.0, 0.0, 0.0);
331 pub const WHITE: Color = Color::new(1.0, 1.0, 1.0, 1.0);
333 pub const BLACK: Color = Color::new(0.0, 0.0, 0.0, 1.0);
335 pub const RED: Color = Color::new(1.0, 0.0, 0.0, 1.0);
337 pub const GREEN: Color = Color::new(0.0, 1.0, 0.0, 1.0);
339 pub const BLUE: Color = Color::new(0.0, 0.0, 1.0, 1.0);
341 pub const YELLOW: Color = Color::new(1.0, 1.0, 0.0, 1.0);
343 pub const MAGENTA: Color = Color::new(1.0, 0.0, 1.0, 1.0);
345 pub const CYAN: Color = Color::new(0.0, 1.0, 1.0, 1.0);
347
348 pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Color {
350 Color { r, g, b, a }
351 }
352 pub fn as_u32(&self) -> u32 {
354 unsafe { ImGui_ColorConvertFloat4ToU32(&(*self).into()) }
355 }
356}
357impl AsRef<[f32; 4]> for Color {
358 fn as_ref(&self) -> &[f32; 4] {
359 unsafe { std::mem::transmute::<&Color, &[f32; 4]>(self) }
361 }
362}
363impl AsMut<[f32; 4]> for Color {
364 fn as_mut(&mut self) -> &mut [f32; 4] {
365 unsafe { std::mem::transmute::<&mut Color, &mut [f32; 4]>(self) }
367 }
368}
369impl From<ImVec4> for Color {
370 #[inline]
371 fn from(c: ImVec4) -> Color {
372 Color::new(c.x, c.y, c.z, c.w)
373 }
374}
375impl From<Color> for ImVec4 {
376 #[inline]
377 fn from(c: Color) -> ImVec4 {
378 ImVec4 {
379 x: c.r,
380 y: c.g,
381 z: c.b,
382 w: c.a,
383 }
384 }
385}
386
387pub struct Context {
389 imgui: NonNull<RawContext>,
390 ini_file_name: Option<CString>,
391}
392
393pub struct CurrentContext<'a> {
395 ctx: &'a mut Context,
396}
397
398#[derive(Debug)]
402pub struct ContextBuilder {
403 docking: bool,
404 debug_highlight_id_conflicts: bool,
405 ini_file_name: Option<String>,
406}
407
408impl Default for ContextBuilder {
409 fn default() -> ContextBuilder {
410 ContextBuilder::new()
411 }
412}
413
414impl ContextBuilder {
415 pub fn new() -> ContextBuilder {
422 ContextBuilder {
423 docking: false,
424 debug_highlight_id_conflicts: cfg!(debug_assertions),
425 ini_file_name: None,
426 }
427 }
428 pub fn set_docking(&mut self, docking: bool) -> &mut Self {
430 self.docking = docking;
431 self
432 }
433 pub fn set_debug_highlight_id_conflicts(
435 &mut self,
436 debug_highlight_id_conflicts: bool,
437 ) -> &mut Self {
438 self.debug_highlight_id_conflicts = debug_highlight_id_conflicts;
439 self
440 }
441 pub fn set_ini_file_name(&mut self, ini_file_name: Option<&str>) -> &mut Self {
443 self.ini_file_name = ini_file_name.map(|s| s.to_string());
444 self
445 }
446 #[must_use]
450 pub unsafe fn build(&self) -> Context {
451 let imgui;
452 unsafe {
454 imgui = ImGui_CreateContext(null_mut());
455 ImGui_SetCurrentContext(imgui);
456 }
457 let imgui = NonNull::new(imgui).unwrap();
458 let mut ctx = Context {
459 imgui: imgui.cast(),
460 ini_file_name: None,
461 };
462 ctx.set_ini_file_name(self.ini_file_name.as_deref());
463
464 let io = ctx.io_mut();
465 io.font_atlas_mut().0.TexPixelsUseColors = true;
466
467 let io = unsafe { io.inner() };
468
469 if self.docking {
470 io.add_config_flags(ConfigFlags::DockingEnable);
471 }
472 io.ConfigDpiScaleFonts = true;
473 io.ConfigDebugHighlightIdConflicts = self.debug_highlight_id_conflicts;
474 ctx
475 }
476}
477
478impl Context {
479 pub unsafe fn new() -> Context {
484 unsafe { ContextBuilder::new().build() }
485 }
486
487 pub unsafe fn set_size(&mut self, size: Vector2, scale: f32) {
489 unsafe {
490 self.io_mut().inner().DisplaySize = v2_to_im(size);
491 if self.io().display_scale() != scale {
492 self.io_mut().inner().DisplayFramebufferScale = ImVec2 { x: scale, y: scale };
493 }
494 }
495 }
496
497 pub unsafe fn set_current(&mut self) -> CurrentContext<'_> {
502 unsafe {
503 ImGui_SetCurrentContext(self.imgui.as_mut().inner());
504 CurrentContext { ctx: self }
505 }
506 }
507
508 pub fn set_ini_file_name(&mut self, ini_file_name: Option<&str>) {
512 let Some(ini_file_name) = ini_file_name else {
513 self.ini_file_name = None;
514 unsafe {
515 self.io_mut().inner().IniFilename = null();
516 }
517 return;
518 };
519
520 let Ok(ini) = CString::new(ini_file_name) else {
521 return;
523 };
524
525 let ini = self.ini_file_name.insert(ini);
526 unsafe {
527 self.io_mut().inner().IniFilename = ini.as_ptr();
528 }
529 }
530 pub fn ini_file_name(&self) -> Option<&str> {
532 let ini = self.ini_file_name.as_deref()?.to_str().unwrap_or_default();
533 Some(ini)
534 }
535}
536
537impl CurrentContext<'_> {
538 pub unsafe fn do_frame<A: UiBuilder>(
544 &mut self,
545 app: &mut A,
546 pre_render: impl FnOnce(&mut Self),
547 render: impl FnOnce(&ImDrawData),
548 ) {
549 unsafe {
550 let mut ui = Ui {
551 imgui: self.ctx.imgui,
552 data: std::ptr::null_mut(),
553 generation: ImGui_GetFrameCount() as usize % 1000 + 1, callbacks: RefCell::new(Vec::new()),
555 };
556
557 self.io_mut().inner().BackendLanguageUserData =
558 (&raw const ui).cast::<c_void>().cast_mut();
559 struct UiPtrToNullGuard<'a, 'b>(&'a mut CurrentContext<'b>);
560 impl Drop for UiPtrToNullGuard<'_, '_> {
561 fn drop(&mut self) {
562 unsafe {
563 self.0.io_mut().inner().BackendLanguageUserData = null_mut();
564 }
565 }
566 }
567 let ctx_guard = UiPtrToNullGuard(self);
568
569 struct FrameGuard;
571 impl Drop for FrameGuard {
572 fn drop(&mut self) {
573 unsafe {
574 ImGui_EndFrame();
575 }
576 }
577 }
578
579 ImGui_NewFrame();
580
581 let end_frame_guard = FrameGuard;
582 app.do_ui(&ui);
583 std::mem::drop(end_frame_guard);
584
585 pre_render(ctx_guard.0);
586 app.pre_render(ctx_guard.0);
587
588 ImGui_Render();
589
590 ui.data = app;
591
592 ctx_guard.0.io_mut().inner().BackendLanguageUserData =
595 (&raw const ui).cast::<c_void>().cast_mut();
596
597 let draw_data = ImGui_GetDrawData();
598 render(&*draw_data);
599 }
600 }
601}
602
603impl Drop for Context {
604 fn drop(&mut self) {
605 unsafe {
606 ImGui_DestroyContext(self.imgui.as_mut().inner());
607 }
608 }
609}
610
611transparent! {
612 pub struct RawContext(ImGuiContext);
616}
617
618impl RawContext {
619 #[inline]
623 pub unsafe fn current<'a>() -> &'a RawContext {
624 unsafe { RawContext::cast(&*ImGui_GetCurrentContext()) }
625 }
626 #[inline]
628 pub unsafe fn from_ptr<'a>(ptr: *mut ImGuiContext) -> &'a RawContext {
629 unsafe { RawContext::cast(&*ptr) }
630 }
631 #[inline]
633 pub unsafe fn from_ptr_mut<'a>(ptr: *mut ImGuiContext) -> &'a mut RawContext {
634 unsafe { RawContext::cast_mut(&mut *ptr) }
635 }
636 #[inline]
638 pub unsafe fn inner(&mut self) -> &mut ImGuiContext {
639 &mut self.0
640 }
641 #[inline]
643 pub fn platform_io(&self) -> &PlatformIo {
644 PlatformIo::cast(&self.PlatformIO)
645 }
646 #[inline]
648 pub unsafe fn platform_io_mut(&mut self) -> &mut PlatformIo {
649 unsafe { PlatformIo::cast_mut(&mut self.inner().PlatformIO) }
650 }
651
652 #[inline]
654 pub fn io(&self) -> &Io {
655 Io::cast(&self.IO)
656 }
657 #[inline]
661 pub fn io_mut(&mut self) -> &mut IoMut {
662 unsafe { IoMut::cast_mut(&mut self.inner().IO) }
663 }
664 #[inline]
666 pub fn style(&self) -> &style::Style {
667 style::Style::cast(&self.Style)
668 }
669 #[inline]
671 pub fn style_mut(&mut self) -> &mut style::Style {
672 unsafe { style::Style::cast_mut(&mut self.inner().Style) }
675 }
676
677 pub fn get_main_viewport(&self) -> &Viewport {
679 unsafe {
680 let ptr = (*self.Viewports)[0];
681 Viewport::cast(&(*ptr)._base)
682 }
683 }
684}
685
686impl Deref for Context {
687 type Target = RawContext;
688 fn deref(&self) -> &RawContext {
689 unsafe { self.imgui.as_ref() }
690 }
691}
692impl DerefMut for Context {
693 fn deref_mut(&mut self) -> &mut RawContext {
694 unsafe { self.imgui.as_mut() }
695 }
696}
697
698impl Deref for CurrentContext<'_> {
699 type Target = RawContext;
700 fn deref(&self) -> &RawContext {
701 self.ctx
702 }
703}
704impl DerefMut for CurrentContext<'_> {
705 fn deref_mut(&mut self) -> &mut RawContext {
706 self.ctx
707 }
708}
709
710impl<A> Deref for Ui<A> {
711 type Target = RawContext;
712 fn deref(&self) -> &RawContext {
713 unsafe { self.imgui.as_ref() }
714 }
715}
716
717pub trait UiBuilder {
721 fn pre_render(&mut self, _ctx: &mut CurrentContext<'_>) {}
725 fn do_ui(&mut self, ui: &Ui<Self>);
729}
730
731enum TtfData {
732 Bytes(Cow<'static, [u8]>),
733 DefaultFont,
734 CustomLoader(fontloader::BoxGlyphLoader),
735}
736
737pub struct FontInfo {
739 ttf: TtfData,
740 size: f32,
741 name: String,
742 flags: FontFlags,
743}
744
745impl FontInfo {
746 pub fn new(ttf: impl Into<Cow<'static, [u8]>>) -> FontInfo {
748 FontInfo {
749 ttf: TtfData::Bytes(ttf.into()),
750 size: 0.0, name: String::new(),
752 flags: FontFlags::None,
753 }
754 }
755 pub fn set_name(mut self, name: impl Into<String>) -> Self {
759 self.name = name.into();
760 self
761 }
762 pub fn set_size(mut self, size: f32) -> Self {
768 self.size = size;
769 self
770 }
771 pub fn default_font() -> FontInfo {
773 FontInfo {
774 ttf: TtfData::DefaultFont,
775 size: 0.0,
776 name: String::new(),
777 flags: FontFlags::None,
778 }
779 }
780 pub fn custom<GL: GlyphLoader + 'static>(glyph_loader: GL) -> FontInfo {
784 let t = fontloader::BoxGlyphLoader::from(Box::new(glyph_loader));
785 FontInfo {
786 ttf: TtfData::CustomLoader(t),
787 size: 0.0,
788 name: String::new(),
789 flags: FontFlags::None,
790 }
791 }
792}
793
794pub trait IntoCStr: Sized {
796 type Temp: Deref<Target = CStr>;
798 fn into(self) -> Self::Temp;
800 fn into_cstring(self) -> CString;
802 fn len(&self) -> usize;
804 fn is_empty(&self) -> bool {
806 self.len() == 0
807 }
808
809 unsafe fn push_to_non_null_vec(self, bs: &mut Vec<u8>) {
814 let c = IntoCStr::into(self);
815 let c = c.to_bytes();
816 bs.extend(c);
817 }
818}
819
820impl IntoCStr for &str {
821 type Temp = CString;
822
823 fn into(self) -> Self::Temp {
824 CString::new(self).unwrap()
825 }
826 fn into_cstring(self) -> CString {
827 IntoCStr::into(self)
828 }
829 fn len(&self) -> usize {
830 str::len(self)
831 }
832 unsafe fn push_to_non_null_vec(self, bs: &mut Vec<u8>) {
833 let c = self.as_bytes();
834 if c.contains(&0) {
835 panic!("NUL error");
836 }
837 bs.extend(c);
838 }
839}
840impl IntoCStr for &String {
841 type Temp = CString;
842
843 fn into(self) -> Self::Temp {
844 CString::new(self.as_str()).unwrap()
845 }
846 fn into_cstring(self) -> CString {
847 IntoCStr::into(self)
848 }
849 fn len(&self) -> usize {
850 self.as_str().len()
851 }
852 unsafe fn push_to_non_null_vec(self, bs: &mut Vec<u8>) {
853 unsafe {
854 self.as_str().push_to_non_null_vec(bs);
855 }
856 }
857}
858impl IntoCStr for String {
859 type Temp = CString;
860
861 fn into(self) -> Self::Temp {
862 CString::new(self).unwrap()
863 }
864 fn into_cstring(self) -> CString {
865 IntoCStr::into(self)
866 }
867 fn len(&self) -> usize {
868 self.len()
869 }
870}
871impl IntoCStr for &CStr {
872 type Temp = Self;
873 fn into(self) -> Self {
874 self
875 }
876 fn into_cstring(self) -> CString {
877 self.to_owned()
878 }
879 fn len(&self) -> usize {
880 self.to_bytes().len()
881 }
882}
883impl IntoCStr for CString {
884 type Temp = Self;
885
886 fn into(self) -> Self {
887 self
888 }
889 fn into_cstring(self) -> CString {
890 self
891 }
892 fn len(&self) -> usize {
893 self.as_bytes().len()
894 }
895}
896impl<'a> IntoCStr for &'a CString {
897 type Temp = &'a CStr;
898
899 fn into(self) -> &'a CStr {
900 self.as_c_str()
901 }
902 fn into_cstring(self) -> CString {
903 self.clone()
904 }
905 fn len(&self) -> usize {
906 self.as_c_str().len()
907 }
908}
909
910impl<'a, B> IntoCStr for Cow<'a, B>
911where
912 B: 'a + ToOwned + ?Sized,
913 &'a B: IntoCStr,
914 B::Owned: IntoCStr,
915 <&'a B as IntoCStr>::Temp: Into<Cow<'a, CStr>>,
916{
917 type Temp = Cow<'a, CStr>;
918
919 fn into(self) -> Cow<'a, CStr> {
920 match self {
921 Cow::Owned(o) => Cow::Owned(IntoCStr::into_cstring(o)),
922 Cow::Borrowed(b) => IntoCStr::into(b).into(),
923 }
924 }
925 fn into_cstring(self) -> CString {
926 match self {
927 Cow::Owned(o) => o.into_cstring(),
928 Cow::Borrowed(b) => b.into_cstring(),
929 }
930 }
931 fn len(&self) -> usize {
932 match self {
933 Cow::Owned(o) => o.len(),
934 Cow::Borrowed(b) => b.len(),
935 }
936 }
937}
938
939pub struct Id<C: IntoCStr>(C);
945
946pub struct LblId<C: IntoCStr>(C);
954
955impl<C: IntoCStr> Id<C> {
956 pub fn into(self) -> C::Temp {
958 self.0.into()
959 }
960 pub fn into_inner(self) -> C {
962 self.0
963 }
964}
965
966impl<C: IntoCStr> LblId<C> {
967 pub fn into(self) -> C::Temp {
969 self.0.into()
970 }
971 pub fn into_inner(self) -> C {
973 self.0
974 }
975}
976
977pub fn id<C: IntoCStr>(c: C) -> Id<CString> {
981 let mut bs = Vec::with_capacity(c.len() + 4);
982 bs.push(b'#');
983 bs.push(b'#');
984 bs.push(b'#');
985 unsafe {
988 IntoCStr::push_to_non_null_vec(c, &mut bs);
989 Id(CString::from_vec_unchecked(bs))
990 }
991}
992
993pub fn raw_id<C: IntoCStr>(c: C) -> Id<C> {
995 Id(c)
996}
997
998impl<C: IntoCStr> From<C> for Id<C> {
1002 fn from(c: C) -> Id<C> {
1003 Id(c)
1004 }
1005}
1006
1007pub fn lbl<C: IntoCStr>(c: C) -> LblId<C> {
1014 LblId(c)
1015}
1016
1017pub fn lbl_id<C1: IntoCStr, C2: IntoCStr>(lbl: C1, id: C2) -> LblId<CString> {
1021 let lbl = lbl.into_cstring();
1022 let both = if id.is_empty() {
1023 lbl
1024 } else {
1025 let mut bs = lbl.into_bytes();
1026 bs.extend(b"###");
1027 unsafe {
1031 IntoCStr::push_to_non_null_vec(id, &mut bs);
1032 CString::from_vec_unchecked(bs)
1033 }
1034 };
1035 LblId(both)
1036}
1037
1038impl<C: IntoCStr> From<C> for LblId<C> {
1042 fn from(c: C) -> LblId<C> {
1043 LblId(c)
1044 }
1045}
1046
1047fn optional_str<S: Deref<Target = CStr>>(t: &Option<S>) -> *const c_char {
1051 t.as_ref().map(|s| s.as_ptr()).unwrap_or(null())
1052}
1053
1054fn optional_mut_bool(b: &mut Option<&mut bool>) -> *mut bool {
1055 b.as_mut().map(|x| *x as *mut bool).unwrap_or(null_mut())
1056}
1057
1058unsafe fn text_ptrs(text: &str) -> (*const c_char, *const c_char) {
1060 let btxt = text.as_bytes();
1061 let start = btxt.as_ptr() as *const c_char;
1062 let end = unsafe { start.add(btxt.len()) };
1063 (start, end)
1064}
1065
1066unsafe fn current_font_ptr(font: FontId) -> *mut ImFont {
1067 unsafe {
1068 let fonts = RawContext::current().io().font_atlas();
1069 fonts.font_ptr(font)
1070 }
1071}
1072
1073unsafe fn no_op() {}
1076
1077pub struct Ui<A>
1082where
1083 A: ?Sized,
1084{
1085 imgui: NonNull<RawContext>,
1086 data: *mut A, generation: usize,
1088 callbacks: RefCell<Vec<UiCallback<A>>>,
1089}
1090
1091type UiCallback<A> = Box<dyn FnMut(*mut A, *mut c_void)>;
1099
1100macro_rules! with_begin_end {
1101 ( $(#[$attr:meta])* $name:ident $begin:ident $end:ident ($($arg:ident ($($type:tt)*) ($pass:expr),)*) ) => {
1102 paste::paste! {
1103 $(#[$attr])*
1104 pub fn [< with_ $name >]<R>(&self, $($arg: $($type)*,)* f: impl FnOnce() -> R) -> R {
1105 unsafe { $begin( $( $pass, )* ) }
1106 struct EndGuard;
1107 impl Drop for EndGuard {
1108 fn drop(&mut self) {
1109 unsafe { $end() }
1110 }
1111 }
1112 let _guard = EndGuard;
1113 f()
1114 }
1115 }
1116 };
1117}
1118
1119macro_rules! with_begin_end_opt {
1120 ( $(#[$attr:meta])* $name:ident $begin:ident $end:ident ($($arg:ident ($($type:tt)*) ($pass:expr),)*) ) => {
1121 paste::paste! {
1122 $(#[$attr])*
1123 pub fn [< with_ $name >]<R>(&self, $($arg: $($type)*,)* f: impl FnOnce() -> R) -> Option<R> {
1124 self.[< with_always_ $name >]($($arg,)* move |opened| { opened.then(f) })
1125 }
1126 pub fn [< with_always_ $name >]<R>(&self, $($arg: $($type)*,)* f: impl FnOnce(bool) -> R) -> R {
1127 if !unsafe { $begin( $( $pass, )* ) } {
1128 return f(false);
1129 }
1130 struct EndGuard;
1131 impl Drop for EndGuard {
1132 fn drop(&mut self) {
1133 unsafe { $end() }
1134 }
1135 }
1136 let _guard = EndGuard;
1137 f(true)
1138 }
1139 }
1140 };
1141}
1142
1143macro_rules! decl_builder {
1144 ( $sname:ident -> $tres:ty, $func:ident ($($life:lifetime),*) ( $( $gen_n:ident : $gen_d:tt ),* )
1145 (
1146 $(
1147 $arg:ident ($($ty:tt)*) ($pass:expr),
1148 )*
1149 )
1150 { $($extra:tt)* }
1151 { $($constructor:tt)* }
1152 ) => {
1153 #[must_use]
1154 pub struct $sname<'s, $($life,)* $($gen_n : $gen_d, )* > {
1155 _pd: PhantomData<*const &'s ()>, $(
1157 $arg: $($ty)*,
1158 )*
1159 }
1160 impl <'s, $($life,)* $($gen_n : $gen_d, )* > $sname<'s, $($life,)* $($gen_n, )* > {
1161 pub fn build(self) -> $tres {
1162 let $sname { _pd, $($arg, )* } = self;
1163 unsafe {
1164 $func($($pass,)*)
1165 }
1166 }
1167 $($extra)*
1168 }
1169
1170 impl<A> Ui<A> {
1171 $($constructor)*
1172 }
1173 };
1174}
1175
1176macro_rules! decl_builder_setter_ex {
1177 ($name:ident: $ty:ty = $expr:expr) => {
1178 pub fn $name(mut self, $name: $ty) -> Self {
1179 self.$name = $expr;
1180 self
1181 }
1182 };
1183}
1184
1185macro_rules! decl_builder_setter {
1186 ($name:ident: $ty:ty) => {
1187 decl_builder_setter_ex! { $name: $ty = $name.into() }
1188 };
1189}
1190
1191macro_rules! decl_builder_setter_vector2 {
1192 ($name:ident: Vector2) => {
1193 decl_builder_setter_ex! { $name: Vector2 = v2_to_im($name) }
1194 };
1195}
1196
1197macro_rules! decl_builder_with_maybe_opt {
1198 ( $always_run_end:literal
1199 $sname:ident, $func_beg:ident, $func_end:ident ($($life:lifetime),*) ( $( $gen_n:ident : $gen_d:tt ),* )
1200 (
1201 $(
1202 $arg:ident ($($ty:tt)*) ($pass:expr),
1203 )*
1204 )
1205 { $($extra:tt)* }
1206 { $($constructor:tt)* }
1207 ) => {
1208 #[must_use]
1209 pub struct $sname< $($life,)* $($gen_n : $gen_d, )* P: Pushable = () > {
1210 $(
1211 $arg: $($ty)*,
1212 )*
1213 push: P,
1214 }
1215 impl <$($life,)* $($gen_n : $gen_d, )* P: Pushable > $sname<$($life,)* $($gen_n,)* P > {
1216 pub fn push_for_begin<P2: Pushable>(self, push: P2) -> $sname< $($life,)* $($gen_n,)* (P, P2) > {
1222 $sname {
1223 $(
1224 $arg: self.$arg,
1225 )*
1226 push: (self.push, push),
1227 }
1228 }
1229 pub fn with<R>(self, f: impl FnOnce() -> R) -> Option<R> {
1231 self.with_always(move |opened| { opened.then(f) })
1232 }
1233 pub fn with_always<R>(self, f: impl FnOnce(bool) -> R) -> R {
1236 #[allow(unused_mut)]
1238 let $sname { $(mut $arg, )* push } = self;
1239 let bres = unsafe {
1240 let _guard = push_guard(&push);
1241 $func_beg($($pass,)*)
1242 };
1243 struct EndGuard(bool);
1244 impl Drop for EndGuard {
1245 fn drop(&mut self) {
1246 if self.0 {
1247 unsafe { $func_end(); }
1248 }
1249 }
1250 }
1251 let _guard_2 = EndGuard($always_run_end || bres);
1252 f(bres)
1253 }
1254 $($extra)*
1255 }
1256
1257 impl<A> Ui<A> {
1258 $($constructor)*
1259 }
1260 };
1261}
1262
1263macro_rules! decl_builder_with {
1264 ($($args:tt)*) => {
1265 decl_builder_with_maybe_opt!{ true $($args)* }
1266 };
1267}
1268
1269macro_rules! decl_builder_with_opt {
1270 ($($args:tt)*) => {
1271 decl_builder_with_maybe_opt!{ false $($args)* }
1272 };
1273}
1274
1275decl_builder_with! {Child, ImGui_BeginChild, ImGui_EndChild () (S: IntoCStr)
1276 (
1277 name (S::Temp) (name.as_ptr()),
1278 size (ImVec2) (&size),
1279 child_flags (ChildFlags) (child_flags.bits()),
1280 window_flags (WindowFlags) (window_flags.bits()),
1281 )
1282 {
1283 decl_builder_setter_vector2!{size: Vector2}
1284 decl_builder_setter!{child_flags: ChildFlags}
1285 decl_builder_setter!{window_flags: WindowFlags}
1286 }
1287 {
1288 pub fn child_config<S: IntoCStr>(&self, name: LblId<S>) -> Child<S> {
1289 Child {
1290 name: name.into(),
1291 size: im_vec2(0.0, 0.0),
1292 child_flags: ChildFlags::None,
1293 window_flags: WindowFlags::None,
1294 push: (),
1295 }
1296 }
1297 }
1298}
1299
1300decl_builder_with! {Window, ImGui_Begin, ImGui_End ('v) (S: IntoCStr)
1301 (
1302 name (S::Temp) (name.as_ptr()),
1303 open (Option<&'v mut bool>) (optional_mut_bool(&mut open)),
1304 flags (WindowFlags) (flags.bits()),
1305 )
1306 {
1307 decl_builder_setter!{open: &'v mut bool}
1308 decl_builder_setter!{flags: WindowFlags}
1309 }
1310 {
1311 pub fn window_config<S: IntoCStr>(&self, name: LblId<S>) -> Window<'_, S> {
1312 Window {
1313 name: name.into(),
1314 open: None,
1315 flags: WindowFlags::None,
1316 push: (),
1317 }
1318 }
1319 }
1320}
1321
1322decl_builder! { MenuItem -> bool, ImGui_MenuItem () (S1: IntoCStr, S2: IntoCStr)
1323 (
1324 label (S1::Temp) (label.as_ptr()),
1325 shortcut (Option<S2::Temp>) (optional_str(&shortcut)),
1326 selected (bool) (selected),
1327 enabled (bool) (enabled),
1328 )
1329 {
1330 pub fn shortcut_opt<S3: IntoCStr>(self, shortcut: Option<S3>) -> MenuItem<'s, S1, S3> {
1331 MenuItem {
1332 _pd: PhantomData,
1333 label: self.label,
1334 shortcut: shortcut.map(|s| s.into()),
1335 selected: self.selected,
1336 enabled: self.enabled,
1337 }
1338 }
1339 pub fn shortcut<S3: IntoCStr>(self, shortcut: S3) -> MenuItem<'s, S1, S3> {
1340 self.shortcut_opt(Some(shortcut))
1341 }
1342 decl_builder_setter!{selected: bool}
1343 decl_builder_setter!{enabled: bool}
1344 }
1345 {
1346 pub fn menu_item_config<S: IntoCStr>(&self, label: LblId<S>) -> MenuItem<'_, S, &str> {
1347 MenuItem {
1348 _pd: PhantomData,
1349 label: label.into(),
1350 shortcut: None,
1351 selected: false,
1352 enabled: true,
1353 }
1354 }
1355 }
1356}
1357
1358decl_builder! { Button -> bool, ImGui_Button () (S: IntoCStr)
1359 (
1360 label (S::Temp) (label.as_ptr()),
1361 size (ImVec2) (&size),
1362 )
1363 {
1364 decl_builder_setter_vector2!{size: Vector2}
1365 }
1366 {
1367 pub fn button_config<S: IntoCStr>(&self, label: LblId<S>) -> Button<'_, S> {
1368 Button {
1369 _pd: PhantomData,
1370 label: label.into(),
1371 size: im_vec2(0.0, 0.0),
1372 }
1373 }
1374 pub fn button<S: IntoCStr>(&self, label: LblId<S>) -> bool {
1375 self.button_config(label).build()
1376 }
1377 }
1378}
1379
1380decl_builder! { SmallButton -> bool, ImGui_SmallButton () (S: IntoCStr)
1381 (
1382 label (S::Temp) (label.as_ptr()),
1383 )
1384 {}
1385 {
1386 pub fn small_button_config<S: IntoCStr>(&self, label: LblId<S>) -> SmallButton<'_, S> {
1387 SmallButton {
1388 _pd: PhantomData,
1389 label: label.into(),
1390 }
1391 }
1392 pub fn small_button<S: IntoCStr>(&self, label: LblId<S>) -> bool {
1393 self.small_button_config(label).build()
1394 }
1395 }
1396}
1397
1398decl_builder! { InvisibleButton -> bool, ImGui_InvisibleButton () (S: IntoCStr)
1399 (
1400 id (S::Temp) (id.as_ptr()),
1401 size (ImVec2) (&size),
1402 flags (ButtonFlags) (flags.bits()),
1403 )
1404 {
1405 decl_builder_setter_vector2!{size: Vector2}
1406 decl_builder_setter!{flags: ButtonFlags}
1407 }
1408 {
1409 pub fn invisible_button_config<S: IntoCStr>(&self, id: S) -> InvisibleButton<'_, S> {
1410 InvisibleButton {
1411 _pd: PhantomData,
1412 id: id.into(),
1413 size: im_vec2(0.0, 0.0),
1414 flags: ButtonFlags::MouseButtonLeft,
1415 }
1416 }
1417 }
1418}
1419
1420decl_builder! { ArrowButton -> bool, ImGui_ArrowButton () (S: IntoCStr)
1421 (
1422 id (S::Temp) (id.as_ptr()),
1423 dir (Dir) (dir.bits()),
1424 )
1425 {}
1426 {
1427 pub fn arrow_button_config<S: IntoCStr>(&self, id: S, dir: Dir) -> ArrowButton<'_, S> {
1428 ArrowButton {
1429 _pd: PhantomData,
1430 id: id.into(),
1431 dir,
1432 }
1433 }
1434 pub fn arrow_button<S: IntoCStr>(&self, id: S, dir: Dir) -> bool {
1435 self.arrow_button_config(id, dir).build()
1436 }
1437 }
1438}
1439
1440decl_builder! { Checkbox -> bool, ImGui_Checkbox ('v) (S: IntoCStr)
1441 (
1442 label (S::Temp) (label.as_ptr()),
1443 value (&'v mut bool) (value),
1444 )
1445 {}
1446 {
1447 pub fn checkbox_config<'v, S: IntoCStr>(&self, label: LblId<S>, value: &'v mut bool) -> Checkbox<'_, 'v, S> {
1448 Checkbox {
1449 _pd: PhantomData,
1450 label: label.into(),
1451 value,
1452 }
1453 }
1454 pub fn checkbox<S: IntoCStr>(&self, label: LblId<S>, value: &mut bool) -> bool {
1455 self.checkbox_config(label, value).build()
1456 }
1457 }
1458}
1459
1460decl_builder! { RadioButton -> bool, ImGui_RadioButton () (S: IntoCStr)
1461 (
1462 label (S::Temp) (label.as_ptr()),
1463 active (bool) (active),
1464 )
1465 {}
1466 {
1467 pub fn radio_button_config<S: IntoCStr>(&self, label: LblId<S>, active: bool) -> RadioButton<'_, S> {
1468 RadioButton {
1469 _pd: PhantomData,
1470 label: label.into(),
1471 active,
1472 }
1473 }
1474 }
1475}
1476
1477decl_builder! { ProgressBar -> (), ImGui_ProgressBar () (S: IntoCStr)
1478 (
1479 fraction (f32) (fraction),
1480 size (ImVec2) (&size),
1481 overlay (Option<S::Temp>) (optional_str(&overlay)),
1482 )
1483 {
1484 decl_builder_setter_vector2!{size: Vector2}
1485 pub fn overlay<S2: IntoCStr>(self, overlay: S2) -> ProgressBar<'s, S2> {
1486 ProgressBar {
1487 _pd: PhantomData,
1488 fraction: self.fraction,
1489 size: self.size,
1490 overlay: Some(overlay.into()),
1491 }
1492 }
1493 }
1494 {
1495 pub fn progress_bar_config<'a>(&self, fraction: f32) -> ProgressBar<'_, &'a str> {
1496 ProgressBar {
1497 _pd: PhantomData,
1498 fraction,
1499 size: im_vec2(-f32::MIN_POSITIVE, 0.0),
1500 overlay: None,
1501 }
1502 }
1503 }
1504}
1505
1506decl_builder! { Image -> (), ImGui_Image ('t) ()
1507 (
1508 texture_ref (TextureRef<'t>) (texture_ref.tex_ref()),
1509 size (ImVec2) (&size),
1510 uv0 (ImVec2) (&uv0),
1511 uv1 (ImVec2) (&uv1),
1512 )
1513 {
1514 decl_builder_setter_vector2!{uv0: Vector2}
1515 decl_builder_setter_vector2!{uv1: Vector2}
1516 }
1517 {
1518 pub fn image_config<'t>(&self, texture_ref: TextureRef<'t>, size: Vector2) -> Image<'_, 't> {
1519 Image {
1520 _pd: PhantomData,
1521 texture_ref,
1522 size: v2_to_im(size),
1523 uv0: im_vec2(0.0, 0.0),
1524 uv1: im_vec2(1.0, 1.0),
1525 }
1526 }
1527 pub fn image_with_custom_rect_config(&self, ridx: CustomRectIndex, scale: f32) -> Image<'_, '_> {
1528 let rr = self.get_custom_rect(ridx).unwrap();
1529 self.image_config(rr.tex_ref, vec2(scale * rr.rect.w as f32, scale * rr.rect.h as f32))
1530 .uv0(im_to_v2(rr.rect.uv0))
1531 .uv1(im_to_v2(rr.rect.uv1))
1532 }
1533 }
1534}
1535
1536decl_builder! { ImageWithBg -> (), ImGui_ImageWithBg ('t) ()
1537 (
1538 texture_ref (TextureRef<'t>) (texture_ref.tex_ref()),
1539 size (ImVec2) (&size),
1540 uv0 (ImVec2) (&uv0),
1541 uv1 (ImVec2) (&uv1),
1542 bg_col (ImVec4) (&bg_col),
1543 tint_col (ImVec4) (&tint_col),
1544 )
1545 {
1546 decl_builder_setter_vector2!{uv0: Vector2}
1547 decl_builder_setter_vector2!{uv1: Vector2}
1548 decl_builder_setter!{bg_col: Color}
1549 decl_builder_setter!{tint_col: Color}
1550 }
1551 {
1552 pub fn image_with_bg_config<'t>(&self, texture_ref: TextureRef<'t>, size: Vector2) -> ImageWithBg<'_, 't> {
1553 ImageWithBg {
1554 _pd: PhantomData,
1555 texture_ref,
1556 size: v2_to_im(size),
1557 uv0: im_vec2(0.0, 0.0),
1558 uv1: im_vec2(1.0, 1.0),
1559 bg_col: Color::TRANSPARENT.into(),
1560 tint_col: Color::WHITE.into(),
1561 }
1562 }
1563 pub fn image_with_bg_with_custom_rect_config(&self, ridx: CustomRectIndex, scale: f32) -> ImageWithBg<'_, '_> {
1564 let rr = self.get_custom_rect(ridx).unwrap();
1565 self.image_with_bg_config(self.get_atlas_texture_ref(), vec2(scale * rr.rect.w as f32, scale * rr.rect.h as f32))
1566 .uv0(im_to_v2(rr.rect.uv0))
1567 .uv1(im_to_v2(rr.rect.uv1))
1568 }
1569
1570 }
1571}
1572
1573decl_builder! { ImageButton -> bool, ImGui_ImageButton ('t) (S: IntoCStr)
1574 (
1575 str_id (S::Temp) (str_id.as_ptr()),
1576 texture_ref (TextureRef<'t>) (texture_ref.tex_ref()),
1577 size (ImVec2) (&size),
1578 uv0 (ImVec2) (&uv0),
1579 uv1 (ImVec2) (&uv1),
1580 bg_col (ImVec4) (&bg_col),
1581 tint_col (ImVec4) (&tint_col),
1582 )
1583 {
1584 decl_builder_setter_vector2!{uv0: Vector2}
1585 decl_builder_setter_vector2!{uv1: Vector2}
1586 decl_builder_setter!{bg_col: Color}
1587 decl_builder_setter!{tint_col: Color}
1588 }
1589 {
1590 pub fn image_button_config<'t, S: IntoCStr>(&self, str_id: Id<S>, texture_ref: TextureRef<'t>, size: Vector2) -> ImageButton<'_, 't, S> {
1591 ImageButton {
1592 _pd: PhantomData,
1593 str_id: str_id.into(),
1594 texture_ref,
1595 size: v2_to_im(size),
1596 uv0: im_vec2(0.0, 0.0),
1597 uv1: im_vec2(1.0, 1.0),
1598 bg_col: Color::TRANSPARENT.into(),
1599 tint_col: Color::WHITE.into(),
1600 }
1601 }
1602 pub fn image_button_with_custom_rect_config<S: IntoCStr>(&self, str_id: Id<S>, ridx: CustomRectIndex, scale: f32) -> ImageButton<'_, '_, S> {
1603 let rr = self.get_custom_rect(ridx).unwrap();
1604 self.image_button_config(str_id, rr.tex_ref, vec2(scale * rr.rect.w as f32, scale * rr.rect.h as f32))
1605 .uv0(im_to_v2(rr.rect.uv0))
1606 .uv1(im_to_v2(rr.rect.uv1))
1607 }
1608 }
1609}
1610
1611decl_builder! { Selectable -> bool, ImGui_Selectable () (S: IntoCStr)
1612 (
1613 label (S::Temp) (label.as_ptr()),
1614 selected (bool) (selected),
1615 flags (SelectableFlags) (flags.bits()),
1616 size (ImVec2) (&size),
1617 )
1618 {
1619 decl_builder_setter!{selected: bool}
1620 decl_builder_setter!{flags: SelectableFlags}
1621 decl_builder_setter_vector2!{size: Vector2}
1622 }
1623 {
1624 pub fn selectable_config<S: IntoCStr>(&self, label: LblId<S>) -> Selectable<'_, S> {
1625 Selectable {
1626 _pd: PhantomData,
1627 label: label.into(),
1628 selected: false,
1629 flags: SelectableFlags::None,
1630 size: im_vec2(0.0, 0.0),
1631 }
1632 }
1633 pub fn selectable<S: IntoCStr>(&self, label: LblId<S>) -> bool {
1634 self.selectable_config(label).build()
1635 }
1636 }
1637}
1638
1639macro_rules! decl_builder_drag {
1640 ($name:ident $func:ident $cfunc:ident $life:lifetime ($argty:ty) ($ty:ty) ($expr:expr)) => {
1641 decl_builder! { $name -> bool, $cfunc ($life) (S: IntoCStr)
1642 (
1643 label (S::Temp) (label.as_ptr()),
1644 value ($ty) ($expr(value)),
1645 speed (f32) (speed),
1646 min ($argty) (min),
1647 max ($argty) (max),
1648 format (Cow<'static, CStr>) (format.as_ptr()),
1649 flags (SliderFlags) (flags.bits()),
1650 )
1651 {
1652 decl_builder_setter!{speed: f32}
1653 pub fn range(mut self, min: $argty, max: $argty) -> Self {
1654 self.min = min;
1655 self.max = max;
1656 self
1657 }
1658 decl_builder_setter!{flags: SliderFlags}
1659 }
1660 {
1661 pub fn $func<$life, S: IntoCStr>(&self, label: LblId<S>, value: $ty) -> $name<'_, $life, S> {
1662 $name {
1663 _pd: PhantomData,
1664 label: label.into(),
1665 value,
1666 speed: 1.0,
1667 min: <$argty>::default(),
1668 max: <$argty>::default(),
1669 format: Cow::Borrowed(c"%.3f"),
1670 flags: SliderFlags::None,
1671 }
1672 }
1673 }
1674 }
1675 };
1676}
1677
1678macro_rules! impl_float_format {
1679 ($name:ident) => {
1680 impl_float_format! {$name c"%g" c"%.0f" c"%.3f" "%.{}f"}
1681 };
1682 ($name:ident $g:literal $f0:literal $f3:literal $f_n:literal) => {
1683 impl<S: IntoCStr> $name<'_, '_, S> {
1684 pub fn display_format(mut self, format: FloatFormat) -> Self {
1685 self.format = match format {
1686 FloatFormat::G => Cow::Borrowed($g),
1687 FloatFormat::F(0) => Cow::Borrowed($f0),
1688 FloatFormat::F(3) => Cow::Borrowed($f3),
1689 FloatFormat::F(n) => Cow::Owned(CString::new(format!($f_n, n)).unwrap()),
1690 };
1691 self
1692 }
1693 }
1694 };
1695}
1696
1697decl_builder_drag! { DragFloat drag_float_config ImGui_DragFloat 'v (f32) (&'v mut f32) (std::convert::identity)}
1698decl_builder_drag! { DragFloat2 drag_float_2_config ImGui_DragFloat2 'v (f32) (&'v mut [f32; 2]) (<[f32]>::as_mut_ptr)}
1699decl_builder_drag! { DragFloat3 drag_float_3_config ImGui_DragFloat3 'v (f32) (&'v mut [f32; 3]) (<[f32]>::as_mut_ptr)}
1700decl_builder_drag! { DragFloat4 drag_float_4_config ImGui_DragFloat4 'v (f32) (&'v mut [f32; 4]) (<[f32]>::as_mut_ptr)}
1701
1702impl_float_format! { DragFloat }
1703impl_float_format! { DragFloat2 }
1704impl_float_format! { DragFloat3 }
1705impl_float_format! { DragFloat4 }
1706
1707decl_builder_drag! { DragInt drag_int_config ImGui_DragInt 'v (i32) (&'v mut i32) (std::convert::identity)}
1708decl_builder_drag! { DragInt2 drag_int_2_config ImGui_DragInt2 'v (i32) (&'v mut [i32; 2]) (<[i32]>::as_mut_ptr)}
1709decl_builder_drag! { DragInt3 drag_int_3_config ImGui_DragInt3 'v (i32) (&'v mut [i32; 3]) (<[i32]>::as_mut_ptr)}
1710decl_builder_drag! { DragInt4 drag_int_4_config ImGui_DragInt4 'v (i32) (&'v mut [i32; 4]) (<[i32]>::as_mut_ptr)}
1711
1712macro_rules! decl_builder_slider {
1713 ($name:ident $func:ident $cfunc:ident $life:lifetime ($argty:ty) ($ty:ty) ($expr:expr)) => {
1714 decl_builder! { $name -> bool, $cfunc ($life) (S: IntoCStr)
1715 (
1716 label (S::Temp) (label.as_ptr()),
1717 value ($ty) ($expr(value)),
1718 min ($argty) (min),
1719 max ($argty) (max),
1720 format (Cow<'static, CStr>) (format.as_ptr()),
1721 flags (SliderFlags) (flags.bits()),
1722 )
1723 {
1724 pub fn range(mut self, min: $argty, max: $argty) -> Self {
1725 self.min = min;
1726 self.max = max;
1727 self
1728 }
1729 decl_builder_setter!{flags: SliderFlags}
1730 }
1731 {
1732 pub fn $func<$life, S: IntoCStr>(&self, label: LblId<S>, value: $ty) -> $name<'_, $life, S> {
1733 $name {
1734 _pd: PhantomData,
1735 label: label.into(),
1736 value,
1737 min: <$argty>::default(),
1738 max: <$argty>::default(),
1739 format: Cow::Borrowed(c"%.3f"),
1740 flags: SliderFlags::None,
1741 }
1742 }
1743 }
1744 }
1745 };
1746}
1747
1748decl_builder_slider! { SliderFloat slider_float_config ImGui_SliderFloat 'v (f32) (&'v mut f32) (std::convert::identity)}
1749decl_builder_slider! { SliderFloat2 slider_float_2_config ImGui_SliderFloat2 'v (f32) (&'v mut [f32; 2]) (<[f32]>::as_mut_ptr)}
1750decl_builder_slider! { SliderFloat3 slider_float_3_config ImGui_SliderFloat3 'v (f32) (&'v mut [f32; 3]) (<[f32]>::as_mut_ptr)}
1751decl_builder_slider! { SliderFloat4 slider_float_4_config ImGui_SliderFloat4 'v (f32) (&'v mut [f32; 4]) (<[f32]>::as_mut_ptr)}
1752
1753impl_float_format! { SliderFloat }
1754impl_float_format! { SliderFloat2 }
1755impl_float_format! { SliderFloat3 }
1756impl_float_format! { SliderFloat4 }
1757
1758decl_builder_slider! { SliderInt slider_int_config ImGui_SliderInt 'v (i32) (&'v mut i32) (std::convert::identity)}
1759decl_builder_slider! { SliderInt2 slider_int_2_config ImGui_SliderInt2 'v (i32) (&'v mut [i32; 2]) (<[i32]>::as_mut_ptr)}
1760decl_builder_slider! { SliderInt3 slider_int_3_config ImGui_SliderInt3 'v (i32) (&'v mut [i32; 3]) (<[i32]>::as_mut_ptr)}
1761decl_builder_slider! { SliderInt4 slider_int_4_config ImGui_SliderInt4 'v (i32) (&'v mut [i32; 4]) (<[i32]>::as_mut_ptr)}
1762
1763decl_builder! { SliderAngle -> bool, ImGui_SliderAngle ('v) (S: IntoCStr)
1764 (
1765 label (S::Temp) (label.as_ptr()),
1766 v_rad (&'v mut f32) (v_rad),
1767 v_degrees_min (f32) (v_degrees_min),
1768 v_degrees_max (f32) (v_degrees_max),
1769 format (Cow<'static, CStr>) (format.as_ptr()),
1770 flags (SliderFlags) (flags.bits()),
1771 )
1772 {
1773 decl_builder_setter!{v_degrees_max: f32}
1774 decl_builder_setter!{v_degrees_min: f32}
1775 decl_builder_setter!{flags: SliderFlags}
1776 }
1777 {
1778 pub fn slider_angle_config<'v, S: IntoCStr>(&self, label: LblId<S>, v_rad: &'v mut f32) -> SliderAngle<'_, 'v, S> {
1779 SliderAngle {
1780 _pd: PhantomData,
1781 label: label.into(),
1782 v_rad,
1783 v_degrees_min: -360.0,
1784 v_degrees_max: 360.0,
1785 format: Cow::Borrowed(c"%.0f deg"),
1786 flags: SliderFlags::None,
1787 }
1788 }
1789 }
1790}
1791
1792impl_float_format! { SliderAngle c"%g deg" c"%.0f deg" c"%.3f deg" "%.{}f deg"}
1793
1794decl_builder! { ColorEdit3 -> bool, ImGui_ColorEdit3 ('v) (S: IntoCStr)
1795 (
1796 label (S::Temp) (label.as_ptr()),
1797 color (&'v mut [f32; 3]) (color.as_mut_ptr()),
1798 flags (ColorEditFlags) (flags.bits()),
1799 )
1800 {
1801 decl_builder_setter!{flags: ColorEditFlags}
1802 }
1803 {
1804 pub fn color_edit_3_config<'v, S: IntoCStr>(&self, label: LblId<S>, color: &'v mut [f32; 3]) -> ColorEdit3<'_, 'v, S> {
1805 ColorEdit3 {
1806 _pd: PhantomData,
1807 label: label.into(),
1808 color,
1809 flags: ColorEditFlags::None,
1810 }
1811 }
1812 }
1813}
1814
1815decl_builder! { ColorEdit4 -> bool, ImGui_ColorEdit4 ('v) (S: IntoCStr)
1816 (
1817 label (S::Temp) (label.as_ptr()),
1818 color (&'v mut [f32; 4]) (color.as_mut_ptr()),
1819 flags (ColorEditFlags) (flags.bits()),
1820 )
1821 {
1822 decl_builder_setter!{flags: ColorEditFlags}
1823 }
1824 {
1825 pub fn color_edit_4_config<'v, S: IntoCStr>(&self, label: LblId<S>, color: &'v mut Color) -> ColorEdit4<'_, 'v, S> {
1826 ColorEdit4 {
1827 _pd: PhantomData,
1828 label: label.into(),
1829 color: color.as_mut(),
1830 flags: ColorEditFlags::None,
1831 }
1832 }
1833 }
1834}
1835
1836decl_builder! { ColorPicker3 -> bool, ImGui_ColorPicker3 ('v) (S: IntoCStr)
1837 (
1838 label (S::Temp) (label.as_ptr()),
1839 color (&'v mut [f32; 3]) (color.as_mut_ptr()),
1840 flags (ColorEditFlags) (flags.bits()),
1841 )
1842 {
1843 decl_builder_setter!{flags: ColorEditFlags}
1844 }
1845 {
1846 pub fn color_picker_3_config<'v, S: IntoCStr>(&self, label: LblId<S>, color: &'v mut [f32; 3]) -> ColorPicker3<'_, 'v, S> {
1847 ColorPicker3 {
1848 _pd: PhantomData,
1849 label: label.into(),
1850 color,
1851 flags: ColorEditFlags::None,
1852 }
1853 }
1854 }
1855}
1856
1857decl_builder! { ColorPicker4 -> bool, ImGui_ColorPicker4 ('v) (S: IntoCStr)
1858 (
1859 label (S::Temp) (label.as_ptr()),
1860 color (&'v mut [f32; 4]) (color.as_mut_ptr()),
1861 flags (ColorEditFlags) (flags.bits()),
1862 ref_col (Option<Color>) (ref_col.as_ref().map(|x| x.as_ref().as_ptr()).unwrap_or(null())),
1863 )
1864 {
1865 decl_builder_setter!{flags: ColorEditFlags}
1866 pub fn ref_color(mut self, ref_color: Color) -> Self {
1867 self.ref_col = Some(ref_color);
1868 self
1869 }
1870 }
1871 {
1872 pub fn color_picker_4_config<'v, S: IntoCStr>(&self, label: LblId<S>, color: &'v mut Color) -> ColorPicker4<'_, 'v, S> {
1873 ColorPicker4 {
1874 _pd: PhantomData,
1875 label: label.into(),
1876 color: color.as_mut(),
1877 flags: ColorEditFlags::None,
1878 ref_col: None,
1879 }
1880 }
1881 }
1882}
1883
1884unsafe extern "C" fn input_text_callback(data: *mut ImGuiInputTextCallbackData) -> i32 {
1885 unsafe {
1886 let data = &mut *data;
1887 if data.EventFlag == InputTextFlags::CallbackResize.bits() {
1888 let this = &mut *(data.UserData as *mut String);
1889 let extra = (data.BufSize as usize).saturating_sub(this.len());
1890 this.reserve(extra);
1891 data.Buf = this.as_mut_ptr() as *mut c_char;
1892 }
1893 0
1894 }
1895}
1896
1897#[inline]
1898fn text_pre_edit(text: &mut String) {
1899 text.push('\0');
1901}
1902
1903#[inline]
1904unsafe fn text_post_edit(text: &mut String) {
1905 unsafe {
1906 let buf = text.as_mut_vec();
1907 let len = CStr::from_ptr(buf.as_ptr() as *const c_char)
1909 .to_bytes()
1910 .len();
1911 buf.set_len(len);
1912 }
1913}
1914
1915unsafe fn input_text_wrapper(
1916 label: *const c_char,
1917 text: &mut String,
1918 flags: InputTextFlags,
1919) -> bool {
1920 unsafe {
1921 let flags = flags | InputTextFlags::CallbackResize;
1922
1923 text_pre_edit(text);
1924 let r = ImGui_InputText(
1925 label,
1926 text.as_mut_ptr() as *mut c_char,
1927 text.capacity(),
1928 flags.bits(),
1929 Some(input_text_callback),
1930 text as *mut String as *mut c_void,
1931 );
1932 text_post_edit(text);
1933 r
1934 }
1935}
1936
1937decl_builder! { InputText -> bool, input_text_wrapper ('v) (S: IntoCStr)
1938 (
1939 label (S::Temp) (label.as_ptr()),
1940 text (&'v mut String) (text),
1941 flags (InputTextFlags) (flags),
1942 )
1943 {
1944 decl_builder_setter!{flags: InputTextFlags}
1945 }
1946 {
1947 pub fn input_text_config<'v, S: IntoCStr>(&self, label: LblId<S>, text: &'v mut String) -> InputText<'_, 'v, S> {
1948 InputText {
1949 _pd: PhantomData,
1950 label: label.into(),
1951 text,
1952 flags: InputTextFlags::None,
1953 }
1954 }
1955 }
1956}
1957
1958unsafe fn input_os_string_wrapper(
1959 label: *const c_char,
1960 os_string: &mut OsString,
1961 flags: InputTextFlags,
1962) -> bool {
1963 unsafe {
1964 let s = std::mem::take(os_string).into_string();
1965 let mut s = match s {
1966 Ok(s) => s,
1967 Err(os) => os.to_string_lossy().into_owned(),
1968 };
1969 let res = input_text_wrapper(label, &mut s, flags);
1970 *os_string = OsString::from(s);
1971 res
1972 }
1973}
1974
1975decl_builder! { InputOsString -> bool, input_os_string_wrapper ('v) (S: IntoCStr)
1976 (
1977 label (S::Temp) (label.as_ptr()),
1978 text (&'v mut OsString) (text),
1979 flags (InputTextFlags) (flags),
1980 )
1981 {
1982 decl_builder_setter!{flags: InputTextFlags}
1983 }
1984 {
1985 pub fn input_os_string_config<'v, S: IntoCStr>(&self, label: LblId<S>, text: &'v mut OsString) -> InputOsString<'_, 'v, S> {
1986 InputOsString {
1987 _pd: PhantomData,
1988 label: label.into(),
1989 text,
1990 flags: InputTextFlags::None,
1991 }
1992 }
1993 }
1994}
1995
1996unsafe fn input_text_multiline_wrapper(
1997 label: *const c_char,
1998 text: &mut String,
1999 size: &ImVec2,
2000 flags: InputTextFlags,
2001) -> bool {
2002 unsafe {
2003 let flags = flags | InputTextFlags::CallbackResize;
2004 text_pre_edit(text);
2005 let r = ImGui_InputTextMultiline(
2006 label,
2007 text.as_mut_ptr() as *mut c_char,
2008 text.capacity(),
2009 size,
2010 flags.bits(),
2011 Some(input_text_callback),
2012 text as *mut String as *mut c_void,
2013 );
2014 text_post_edit(text);
2015 r
2016 }
2017}
2018
2019decl_builder! { InputTextMultiline -> bool, input_text_multiline_wrapper ('v) (S: IntoCStr)
2020 (
2021 label (S::Temp) (label.as_ptr()),
2022 text (&'v mut String) (text),
2023 size (ImVec2) (&size),
2024 flags (InputTextFlags) (flags),
2025 )
2026 {
2027 decl_builder_setter!{flags: InputTextFlags}
2028 decl_builder_setter_vector2!{size: Vector2}
2029 }
2030 {
2031 pub fn input_text_multiline_config<'v, S: IntoCStr>(&self, label: LblId<S>, text: &'v mut String) -> InputTextMultiline<'_, 'v, S> {
2032 InputTextMultiline {
2033 _pd: PhantomData,
2034 label:label.into(),
2035 text,
2036 flags: InputTextFlags::None,
2037 size: im_vec2(0.0, 0.0),
2038 }
2039 }
2040 }
2041}
2042
2043unsafe fn input_text_hint_wrapper(
2044 label: *const c_char,
2045 hint: *const c_char,
2046 text: &mut String,
2047 flags: InputTextFlags,
2048) -> bool {
2049 unsafe {
2050 let flags = flags | InputTextFlags::CallbackResize;
2051 text_pre_edit(text);
2052 let r = ImGui_InputTextWithHint(
2053 label,
2054 hint,
2055 text.as_mut_ptr() as *mut c_char,
2056 text.capacity(),
2057 flags.bits(),
2058 Some(input_text_callback),
2059 text as *mut String as *mut c_void,
2060 );
2061 text_post_edit(text);
2062 r
2063 }
2064}
2065
2066decl_builder! { InputTextHint -> bool, input_text_hint_wrapper ('v) (S1: IntoCStr, S2: IntoCStr)
2067 (
2068 label (S1::Temp) (label.as_ptr()),
2069 hint (S2::Temp) (hint.as_ptr()),
2070 text (&'v mut String) (text),
2071 flags (InputTextFlags) (flags),
2072 )
2073 {
2074 decl_builder_setter!{flags: InputTextFlags}
2075 }
2076 {
2077 pub fn input_text_hint_config<'v, S1: IntoCStr, S2: IntoCStr>(&self, label: LblId<S1>, hint: S2, text: &'v mut String) -> InputTextHint<'_, 'v, S1, S2> {
2078 InputTextHint {
2079 _pd: PhantomData,
2080 label:label.into(),
2081 hint: hint.into(),
2082 text,
2083 flags: InputTextFlags::None,
2084 }
2085 }
2086 }
2087}
2088
2089pub enum FloatFormat {
2093 F(u32),
2095 G,
2097}
2098
2099decl_builder! { InputFloat -> bool, ImGui_InputFloat ('v) (S: IntoCStr)
2100 (
2101 label (S::Temp) (label.as_ptr()),
2102 value (&'v mut f32) (value),
2103 step (f32) (step),
2104 step_fast (f32) (step_fast),
2105 format (Cow<'static, CStr>) (format.as_ptr()),
2106 flags (InputTextFlags) (flags.bits()),
2107 )
2108 {
2109 decl_builder_setter!{flags: InputTextFlags}
2110 decl_builder_setter!{step: f32}
2111 decl_builder_setter!{step_fast: f32}
2112 }
2113 {
2114 pub fn input_float_config<'v, S: IntoCStr>(&self, label: LblId<S>, value: &'v mut f32) -> InputFloat<'_, 'v, S> {
2115 InputFloat {
2116 _pd: PhantomData,
2117 label:label.into(),
2118 value,
2119 step: 0.0,
2120 step_fast: 0.0,
2121 format: Cow::Borrowed(c"%.3f"),
2122 flags: InputTextFlags::None,
2123 }
2124 }
2125 }
2126}
2127
2128decl_builder! { InputInt -> bool, ImGui_InputInt ('v) (S: IntoCStr)
2129 (
2130 label (S::Temp) (label.as_ptr()),
2131 value (&'v mut i32) (value),
2132 step (i32) (step),
2133 step_fast (i32) (step_fast),
2134 flags (InputTextFlags) (flags.bits()),
2135 )
2136 {
2137 decl_builder_setter!{flags: InputTextFlags}
2138 decl_builder_setter!{step: i32}
2139 decl_builder_setter!{step_fast: i32}
2140 }
2141 {
2142 pub fn input_int_config<'v, S: IntoCStr>(&self, label: LblId<S>, value: &'v mut i32) -> InputInt<'_, 'v, S> {
2143 InputInt {
2144 _pd: PhantomData,
2145 label:label.into(),
2146 value,
2147 step: 1,
2148 step_fast: 100,
2149 flags: InputTextFlags::None,
2150 }
2151 }
2152 }
2153}
2154
2155macro_rules! decl_builder_input_f {
2156 ($name:ident $func:ident $cfunc:ident $len:literal) => {
2157 decl_builder! { $name -> bool, $cfunc ('v) (S: IntoCStr)
2158 (
2159 label (S::Temp) (label.as_ptr()),
2160 value (&'v mut [f32; $len]) (value.as_mut_ptr()),
2161 format (Cow<'static, CStr>) (format.as_ptr()),
2162 flags (InputTextFlags) (flags.bits()),
2163 )
2164 {
2165 decl_builder_setter!{flags: InputTextFlags}
2166 }
2167 {
2168 pub fn $func<'v, S: IntoCStr>(&self, label: LblId<S>, value: &'v mut [f32; $len]) -> $name<'_, 'v, S> {
2169 $name {
2170 _pd: PhantomData,
2171 label: label.into(),
2172 value,
2173 format: Cow::Borrowed(c"%.3f"),
2174 flags: InputTextFlags::None,
2175 }
2176 }
2177 }
2178 }
2179
2180 };
2181}
2182
2183decl_builder_input_f! { InputFloat2 input_float_2_config ImGui_InputFloat2 2}
2184decl_builder_input_f! { InputFloat3 input_float_3_config ImGui_InputFloat3 3}
2185decl_builder_input_f! { InputFloat4 input_float_4_config ImGui_InputFloat4 4}
2186
2187impl_float_format! { InputFloat }
2188impl_float_format! { InputFloat2 }
2189impl_float_format! { InputFloat3 }
2190impl_float_format! { InputFloat4 }
2191
2192macro_rules! decl_builder_input_i {
2193 ($name:ident $func:ident $cfunc:ident $len:literal) => {
2194 decl_builder! { $name -> bool, $cfunc ('v) (S: IntoCStr)
2195 (
2196 label (S::Temp) (label.as_ptr()),
2197 value (&'v mut [i32; $len]) (value.as_mut_ptr()),
2198 flags (InputTextFlags) (flags.bits()),
2199 )
2200 {
2201 decl_builder_setter!{flags: InputTextFlags}
2202 }
2203 {
2204 pub fn $func<'v, S: IntoCStr>(&self, label: LblId<S>, value: &'v mut [i32; $len]) -> $name<'_, 'v, S> {
2205 $name {
2206 _pd: PhantomData,
2207 label: label.into(),
2208 value,
2209 flags: InputTextFlags::None,
2210 }
2211 }
2212 }
2213 }
2214
2215 };
2216}
2217
2218decl_builder_input_i! { InputInt2 input_int_2_config ImGui_InputInt2 2}
2219decl_builder_input_i! { InputInt3 input_int_3_config ImGui_InputInt3 3}
2220decl_builder_input_i! { InputInt4 input_int_4_config ImGui_InputInt4 4}
2221
2222decl_builder_with_opt! {Menu, ImGui_BeginMenu, ImGui_EndMenu () (S: IntoCStr)
2223 (
2224 name (S::Temp) (name.as_ptr()),
2225 enabled (bool) (enabled),
2226 )
2227 {
2228 decl_builder_setter!{enabled: bool}
2229 }
2230 {
2231 pub fn menu_config<S: IntoCStr>(&self, name: LblId<S>) -> Menu<S> {
2232 Menu {
2233 name: name.into(),
2234 enabled: true,
2235 push: (),
2236 }
2237 }
2238 }
2239}
2240
2241decl_builder_with_opt! {CollapsingHeader, ImGui_CollapsingHeader, no_op () (S: IntoCStr)
2242 (
2243 label (S::Temp) (label.as_ptr()),
2244 flags (TreeNodeFlags) (flags.bits()),
2245 )
2246 {
2247 decl_builder_setter!{flags: TreeNodeFlags}
2248 }
2249 {
2250 pub fn collapsing_header_config<S: IntoCStr>(&self, label: LblId<S>) -> CollapsingHeader<S> {
2251 CollapsingHeader {
2252 label: label.into(),
2253 flags: TreeNodeFlags::None,
2254 push: (),
2255 }
2256 }
2257 }
2258}
2259
2260enum LabelId<'a, S: IntoCStr, H: Hashable> {
2261 LblId(LblId<S>),
2262 LabelId(&'a str, H),
2263}
2264
2265unsafe fn tree_node_ex_helper<S: IntoCStr, H: Hashable>(
2266 label_id: LabelId<'_, S, H>,
2267 flags: TreeNodeFlags,
2268) -> bool {
2269 unsafe {
2270 match label_id {
2271 LabelId::LblId(lbl) => ImGui_TreeNodeEx(lbl.into().as_ptr(), flags.bits()),
2272 LabelId::LabelId(lbl, id) => {
2273 let (start, end) = text_ptrs(lbl);
2274 ImGui_TreeNodeBehavior(id.get_id(), flags.bits(), start, end)
2276 }
2277 }
2278 }
2279}
2280
2281decl_builder_with_opt! {TreeNode, tree_node_ex_helper, ImGui_TreePop ('a) (S: IntoCStr, H: Hashable)
2282 (
2283 label (LabelId<'a, S, H>) (label),
2284 flags (TreeNodeFlags) (flags),
2285 )
2286 {
2287 decl_builder_setter!{flags: TreeNodeFlags}
2288 }
2289 {
2290 pub fn tree_node_config<S: IntoCStr>(&self, label: LblId<S>) -> TreeNode<'static, S, usize> {
2291 TreeNode {
2292 label: LabelId::LblId(label),
2293 flags: TreeNodeFlags::None,
2294 push: (),
2295 }
2296 }
2297 pub fn tree_node_ex_config<'a, H: Hashable>(&self, id: H, label: &'a str) -> TreeNode<'a, &'a str, H> {
2298 TreeNode {
2299 label: LabelId::LabelId(label, id),
2300 flags: TreeNodeFlags::None,
2301 push: (),
2302 }
2303 }
2304 }
2305}
2306
2307decl_builder_with_opt! {Popup, ImGui_BeginPopup, ImGui_EndPopup () (S: IntoCStr)
2308 (
2309 str_id (S::Temp) (str_id.as_ptr()),
2310 flags (WindowFlags) (flags.bits()),
2311 )
2312 {
2313 decl_builder_setter!{flags: WindowFlags}
2314 }
2315 {
2316 pub fn popup_config<S: IntoCStr>(&self, str_id: Id<S>) -> Popup<S> {
2317 Popup {
2318 str_id: str_id.into(),
2319 flags: WindowFlags::None,
2320 push: (),
2321 }
2322 }
2323 }
2324}
2325
2326enum PopupOpened<'a> {
2327 Literal(bool),
2328 Reference(&'a mut bool),
2329 None,
2330}
2331
2332impl PopupOpened<'_> {
2333 unsafe fn pointer(&mut self) -> *mut bool {
2334 match self {
2335 PopupOpened::Literal(x) => x,
2336 PopupOpened::Reference(r) => *r,
2337 PopupOpened::None => std::ptr::null_mut(),
2338 }
2339 }
2340}
2341
2342decl_builder_with_opt! {PopupModal, ImGui_BeginPopupModal, ImGui_EndPopup ('a) (S: IntoCStr)
2343 (
2344 name (S::Temp) (name.as_ptr()),
2345 opened (PopupOpened<'a>) (opened.pointer()),
2346 flags (WindowFlags) (flags.bits()),
2347 )
2348 {
2349 decl_builder_setter!{flags: WindowFlags}
2350
2351 pub fn close_button(mut self, close_button: bool) -> Self {
2352 self.opened = if close_button { PopupOpened::Literal(true) } else { PopupOpened::None };
2353 self
2354 }
2355
2356 pub fn opened(self, opened: Option<&'a mut bool>) -> PopupModal<'a, S, P> {
2357 let opened = match opened {
2358 Some(b) => PopupOpened::Reference(b),
2359 None => PopupOpened::None,
2360 };
2361 PopupModal {
2362 opened,
2363 .. self
2364 }
2365 }
2366 }
2367 {
2368 pub fn popup_modal_config<S: IntoCStr>(&self, name: LblId<S>) -> PopupModal<'static, S> {
2369 PopupModal {
2370 name: name.into(),
2371 opened: PopupOpened::None,
2372 flags: WindowFlags::None,
2373 push: (),
2374 }
2375 }
2376 }
2377}
2378
2379macro_rules! decl_builder_popup_context {
2380 ($struct:ident $begin:ident $do_function:ident) => {
2381 decl_builder_with_opt! {$struct, $begin, ImGui_EndPopup () (S: IntoCStr)
2382 (
2383 str_id (Option<S::Temp>) (optional_str(&str_id)),
2384 flags (PopupFlags) (flags.bits()),
2385 )
2386 {
2387 decl_builder_setter!{flags: PopupFlags}
2388 pub fn str_id<S2: IntoCStr>(self, str_id: LblId<S2>) -> $struct<S2, P> {
2389 $struct {
2390 str_id: Some(str_id.into()),
2391 flags: self.flags,
2392 push: self.push,
2393 }
2394 }
2395
2396 }
2397 {
2398 pub fn $do_function<'a>(&self) -> $struct<&'a str> {
2399 $struct {
2400 str_id: None,
2401 flags: PopupFlags::MouseButtonRight,
2402 push: (),
2403 }
2404 }
2405 }
2406 }
2407 };
2408}
2409
2410decl_builder_popup_context! {PopupContextItem ImGui_BeginPopupContextItem popup_context_item_config}
2411decl_builder_popup_context! {PopupContextWindow ImGui_BeginPopupContextWindow popup_context_window_config}
2412decl_builder_popup_context! {PopupContextVoid ImGui_BeginPopupContextVoid popup_context_void_config}
2413
2414decl_builder_with_opt! {Combo, ImGui_BeginCombo, ImGui_EndCombo () (S1: IntoCStr, S2: IntoCStr)
2415 (
2416 label (S1::Temp) (label.as_ptr()),
2417 preview_value (Option<S2::Temp>) (optional_str(&preview_value)),
2418 flags (ComboFlags) (flags.bits()),
2419 )
2420 {
2421 decl_builder_setter!{flags: ComboFlags}
2422 pub fn preview_value_opt<S3: IntoCStr>(self, preview_value: Option<S3>) -> Combo<S1, S3> {
2423 Combo {
2424 label: self.label,
2425 preview_value: preview_value.map(|x| x.into()),
2426 flags: ComboFlags::None,
2427 push: (),
2428 }
2429 }
2430 pub fn preview_value<S3: IntoCStr>(self, preview_value: S3) -> Combo<S1, S3> {
2431 self.preview_value_opt(Some(preview_value))
2432 }
2433 }
2434 {
2435 pub fn combo_config<'a, S: IntoCStr>(&self, label: LblId<S>) -> Combo<S, &'a str> {
2436 Combo {
2437 label: label.into(),
2438 preview_value: None,
2439 flags: ComboFlags::None,
2440 push: (),
2441 }
2442 }
2443 pub fn combo<V: Copy + PartialEq, S1: IntoCStr, S2: IntoCStr>(
2445 &self,
2446 label: LblId<S1>,
2447 values: impl IntoIterator<Item=V>,
2448 f_name: impl Fn(V) -> S2,
2449 current: &mut V
2450 ) -> bool
2451 {
2452 let mut changed = false;
2453 self.combo_config(label)
2454 .preview_value(f_name(*current))
2455 .with(|| {
2456 for (i, val) in values.into_iter().enumerate() {
2457 if self.selectable_config(lbl_id(f_name(val), i.to_string()))
2458 .selected(*current == val)
2459 .build()
2460 {
2461 *current = val;
2462 changed = true;
2463 }
2464 }
2465 });
2466 changed
2467 }
2468 }
2469}
2470
2471decl_builder_with_opt! {ListBox, ImGui_BeginListBox, ImGui_EndListBox () (S: IntoCStr)
2472 (
2473 label (S::Temp) (label.as_ptr()),
2474 size (ImVec2) (&size),
2475 )
2476 {
2477 decl_builder_setter_vector2!{size: Vector2}
2478 }
2479 {
2480 pub fn list_box_config<S: IntoCStr>(&self, label: LblId<S>) -> ListBox<S> {
2481 ListBox {
2482 label: label.into(),
2483 size: im_vec2(0.0, 0.0),
2484 push: (),
2485 }
2486 }
2487 pub fn list_box<V: Copy + PartialEq, S1: IntoCStr, S2: IntoCStr>(
2489 &self,
2490 label: LblId<S1>,
2491 mut height_in_items: i32,
2492 values: impl IntoIterator<Item=V>,
2493 f_name: impl Fn(V) -> S2,
2494 current: &mut V
2495 ) -> bool
2496 {
2497 if height_in_items < 0 {
2499 height_in_items = 7;
2501 }
2502 let height_in_items_f = height_in_items as f32 + 0.25;
2503 let height_in_pixels = self.get_text_line_height_with_spacing() * height_in_items_f + self.style().FramePadding.y * 2.0;
2504
2505 let mut changed = false;
2506 self.list_box_config(label)
2507 .size(vec2(0.0, height_in_pixels.floor()))
2508 .with(|| {
2509 for (i, val) in values.into_iter().enumerate() {
2510 if self.selectable_config(lbl_id(f_name(val), i.to_string()))
2511 .selected(*current == val)
2512 .build()
2513 {
2514 *current = val;
2515 changed = true;
2516 }
2517 }
2518 });
2519 changed
2520 }
2521 }
2522}
2523
2524decl_builder_with_opt! {TabBar, ImGui_BeginTabBar, ImGui_EndTabBar () (S: IntoCStr)
2525 (
2526 str_id (S::Temp) (str_id.as_ptr()),
2527 flags (TabBarFlags) (flags.bits()),
2528 )
2529 {
2530 decl_builder_setter!{flags: TabBarFlags}
2531 }
2532 {
2533 pub fn tab_bar_config<S: IntoCStr>(&self, str_id: LblId<S>) -> TabBar<S> {
2534 TabBar {
2535 str_id: str_id.into(),
2536 flags: TabBarFlags::None,
2537 push: (),
2538 }
2539 }
2540 }
2541}
2542
2543decl_builder_with_opt! {TabItem, ImGui_BeginTabItem, ImGui_EndTabItem ('o) (S: IntoCStr)
2544 (
2545 str_id (S::Temp) (str_id.as_ptr()),
2546 opened (Option<&'o mut bool>) (optional_mut_bool(&mut opened)),
2547 flags (TabItemFlags) (flags.bits()),
2548 )
2549 {
2550 decl_builder_setter!{flags: TabItemFlags}
2551 decl_builder_setter!{opened: &'o mut bool}
2552 }
2553 {
2554 pub fn tab_item_config<S: IntoCStr>(&self, str_id: LblId<S>) -> TabItem<'_, S> {
2555 TabItem {
2556 str_id: str_id.into(),
2557 opened: None,
2558 flags: TabItemFlags::None,
2559 push: (),
2560 }
2561 }
2562 pub fn tab_item_button(label: LblId<impl IntoCStr>, flags: TabItemFlags) -> bool {
2563 unsafe {
2564 ImGui_TabItemButton(label.into().as_ptr(), flags.bits())
2565 }
2566 }
2567 pub fn set_tab_item_closed(tab_or_docked_window_label: LblId<impl IntoCStr>) {
2568 unsafe {
2569 ImGui_SetTabItemClosed(tab_or_docked_window_label.into().as_ptr());
2570 }
2571 }
2572 }
2573}
2574
2575impl<A> Ui<A> {
2576 unsafe fn push_callback<X>(&self, mut cb: impl FnMut(*mut A, X) + 'static) -> usize {
2578 let cb = Box::new(move |data: *mut A, ptr: *mut c_void| {
2579 let x = ptr as *mut X;
2580 cb(data, unsafe { std::ptr::read(x) });
2581 });
2582 let mut callbacks = self.callbacks.borrow_mut();
2583 let id = callbacks.len();
2584
2585 callbacks.push(cb);
2586 merge_generation(id, self.generation)
2587 }
2588 unsafe fn run_callback<X>(id: usize, x: X) {
2589 unsafe {
2590 let user_data = RawContext::current().io().BackendLanguageUserData;
2591 if user_data.is_null() {
2592 return;
2593 }
2594 let ui = &*(user_data as *const Self);
2596 let Some(id) = remove_generation(id, ui.generation) else {
2597 eprintln!("lost generation callback");
2598 return;
2599 };
2600
2601 let mut callbacks = ui.callbacks.borrow_mut();
2602 let cb = &mut callbacks[id];
2603 let mut x = MaybeUninit::new(x);
2605 cb(ui.data, x.as_mut_ptr() as *mut c_void);
2606 }
2607 }
2608
2609 pub fn get_clipboard_text(&self) -> String {
2610 unsafe {
2611 CStr::from_ptr(ImGui_GetClipboardText())
2612 .to_string_lossy()
2613 .into_owned()
2614 }
2615 }
2616 pub fn set_clipboard_text(&self, text: impl IntoCStr) {
2617 let text = text.into();
2618 unsafe { ImGui_SetClipboardText(text.as_ptr()) }
2619 }
2620 pub fn set_next_window_size_constraints_callback(
2621 &self,
2622 size_min: Vector2,
2623 size_max: Vector2,
2624 mut cb: impl FnMut(SizeCallbackData<'_>) + 'static,
2625 ) {
2626 unsafe {
2627 let id = self.push_callback(move |_, scd| cb(scd));
2630 ImGui_SetNextWindowSizeConstraints(
2631 &v2_to_im(size_min),
2632 &v2_to_im(size_max),
2633 Some(call_size_callback::<A>),
2634 id as *mut c_void,
2635 );
2636 }
2637 }
2638 pub fn set_next_window_size_constraints(&self, size_min: Vector2, size_max: Vector2) {
2639 unsafe {
2640 ImGui_SetNextWindowSizeConstraints(
2641 &v2_to_im(size_min),
2642 &v2_to_im(size_max),
2643 None,
2644 null_mut(),
2645 );
2646 }
2647 }
2648 pub fn set_next_item_width(&self, item_width: f32) {
2649 unsafe {
2650 ImGui_SetNextItemWidth(item_width);
2651 }
2652 }
2653 pub fn set_next_item_open(&self, is_open: bool, cond: Cond) {
2654 unsafe {
2655 ImGui_SetNextItemOpen(is_open, cond.bits());
2656 }
2657 }
2658 pub fn set_keyboard_focus_here(&self, offset: i32) {
2659 unsafe { ImGui_SetKeyboardFocusHere(offset) }
2660 }
2661
2662 with_begin_end! {
2663 group ImGui_BeginGroup ImGui_EndGroup ()
2665 }
2666 with_begin_end! {
2667 disabled ImGui_BeginDisabled ImGui_EndDisabled (
2669 disabled (bool) (disabled),
2670 )
2671 }
2672 with_begin_end! {
2673 clip_rect ImGui_PushClipRect ImGui_PopClipRect (
2675 clip_rect_min (Vector2) (&v2_to_im(clip_rect_min)),
2676 clip_rect_max (Vector2) (&v2_to_im(clip_rect_max)),
2677 intersect_with_current_clip_rect (bool) (intersect_with_current_clip_rect),
2678 )
2679 }
2680
2681 with_begin_end_opt! {
2682 main_menu_bar ImGui_BeginMainMenuBar ImGui_EndMainMenuBar ()
2684 }
2685 with_begin_end_opt! {
2686 menu_bar ImGui_BeginMenuBar ImGui_EndMenuBar ()
2688 }
2689 with_begin_end_opt! {
2690 tooltip ImGui_BeginTooltip ImGui_EndTooltip ()
2692 }
2693 with_begin_end_opt! {
2694 item_tooltip ImGui_BeginItemTooltip ImGui_EndTooltip ()
2696 }
2697
2698 pub fn with_push<R>(&self, push: impl Pushable, f: impl FnOnce() -> R) -> R {
2700 unsafe {
2701 let _guard = push_guard(&push);
2702 f()
2703 }
2704 }
2705 pub fn show_demo_window(&self, mut show: Option<&mut bool>) {
2706 unsafe {
2707 ImGui_ShowDemoWindow(optional_mut_bool(&mut show));
2708 }
2709 }
2710 pub fn set_next_window_pos(&self, pos: Vector2, cond: Cond, pivot: Vector2) {
2711 unsafe {
2712 ImGui_SetNextWindowPos(&v2_to_im(pos), cond.bits(), &v2_to_im(pivot));
2713 }
2714 }
2715 pub fn set_next_window_size(&self, size: Vector2, cond: Cond) {
2716 unsafe {
2717 ImGui_SetNextWindowSize(&v2_to_im(size), cond.bits());
2718 }
2719 }
2720 pub fn set_next_window_content_size(&self, size: Vector2) {
2721 unsafe {
2722 ImGui_SetNextWindowContentSize(&v2_to_im(size));
2723 }
2724 }
2725
2726 pub fn set_next_window_collapsed(&self, collapsed: bool, cond: Cond) {
2727 unsafe {
2728 ImGui_SetNextWindowCollapsed(collapsed, cond.bits());
2729 }
2730 }
2731
2732 pub fn set_next_window_focus(&self) {
2733 unsafe {
2734 ImGui_SetNextWindowFocus();
2735 }
2736 }
2737
2738 pub fn set_next_window_scroll(&self, scroll: Vector2) {
2739 unsafe {
2740 ImGui_SetNextWindowScroll(&v2_to_im(scroll));
2741 }
2742 }
2743
2744 pub fn set_next_window_bg_alpha(&self, alpha: f32) {
2745 unsafe {
2746 ImGui_SetNextWindowBgAlpha(alpha);
2747 }
2748 }
2749 pub fn window_draw_list(&self) -> WindowDrawList<'_, A> {
2750 unsafe {
2751 let ptr = ImGui_GetWindowDrawList();
2752 WindowDrawList { ui: self, ptr }
2753 }
2754 }
2755 pub fn window_dpi_scale(&self) -> f32 {
2756 unsafe { ImGui_GetWindowDpiScale() }
2757 }
2758 pub fn foreground_draw_list(&self) -> WindowDrawList<'_, A> {
2759 unsafe {
2760 let ptr = ImGui_GetForegroundDrawList(std::ptr::null_mut());
2761 WindowDrawList { ui: self, ptr }
2762 }
2763 }
2764 pub fn background_draw_list(&self) -> WindowDrawList<'_, A> {
2765 unsafe {
2766 let ptr = ImGui_GetBackgroundDrawList(std::ptr::null_mut());
2767 WindowDrawList { ui: self, ptr }
2768 }
2769 }
2770 pub fn text(&self, text: &str) {
2771 unsafe {
2772 let (start, end) = text_ptrs(text);
2773 ImGui_TextUnformatted(start, end);
2774 }
2775 }
2776 pub fn text_colored(&self, color: Color, text: impl IntoCStr) {
2777 let text = text.into();
2778 unsafe { ImGui_TextColored(&color.into(), c"%s".as_ptr(), text.as_ptr()) }
2779 }
2780 pub fn text_disabled(&self, text: impl IntoCStr) {
2781 let text = text.into();
2782 unsafe { ImGui_TextDisabled(c"%s".as_ptr(), text.as_ptr()) }
2783 }
2784 pub fn text_wrapped(&self, text: impl IntoCStr) {
2785 let text = text.into();
2786 unsafe { ImGui_TextWrapped(c"%s".as_ptr(), text.as_ptr()) }
2787 }
2788 pub fn text_link(&self, label: LblId<impl IntoCStr>) -> bool {
2789 let label = label.into();
2790 unsafe { ImGui_TextLink(label.as_ptr()) }
2791 }
2792 pub fn text_link_open_url(&self, label: LblId<impl IntoCStr>, url: impl IntoCStr) -> bool {
2793 let label = label.into();
2794 let url = url.into();
2795 unsafe { ImGui_TextLinkOpenURL(label.as_ptr(), url.as_ptr()) }
2796 }
2797 pub fn label_text(&self, label: impl IntoCStr, text: impl IntoCStr) {
2798 let label = label.into();
2799 let text = text.into();
2800 unsafe { ImGui_LabelText(label.as_ptr(), c"%s".as_ptr(), text.as_ptr()) }
2801 }
2802 pub fn bullet_text(&self, text: impl IntoCStr) {
2803 let text = text.into();
2804 unsafe { ImGui_BulletText(c"%s".as_ptr(), text.as_ptr()) }
2805 }
2806 pub fn bullet(&self) {
2807 unsafe {
2808 ImGui_Bullet();
2809 }
2810 }
2811 pub fn separator_text(&self, text: impl IntoCStr) {
2812 let text = text.into();
2813 unsafe {
2814 ImGui_SeparatorText(text.as_ptr());
2815 }
2816 }
2817 pub fn separator(&self) {
2818 unsafe {
2819 ImGui_Separator();
2820 }
2821 }
2822
2823 pub fn set_item_default_focus(&self) {
2824 unsafe {
2825 ImGui_SetItemDefaultFocus();
2826 }
2827 }
2828 pub fn is_item_hovered(&self) -> bool {
2829 self.is_item_hovered_ex(HoveredFlags::None)
2830 }
2831 pub fn is_item_hovered_ex(&self, flags: HoveredFlags) -> bool {
2832 unsafe { ImGui_IsItemHovered(flags.bits()) }
2833 }
2834 pub fn is_item_active(&self) -> bool {
2835 unsafe { ImGui_IsItemActive() }
2836 }
2837 pub fn is_item_focused(&self) -> bool {
2838 unsafe { ImGui_IsItemFocused() }
2839 }
2840 pub fn is_item_clicked(&self, flags: MouseButton) -> bool {
2841 unsafe { ImGui_IsItemClicked(flags.bits()) }
2842 }
2843 pub fn is_item_visible(&self) -> bool {
2844 unsafe { ImGui_IsItemVisible() }
2845 }
2846 pub fn is_item_edited(&self) -> bool {
2847 unsafe { ImGui_IsItemEdited() }
2848 }
2849 pub fn is_item_activated(&self) -> bool {
2850 unsafe { ImGui_IsItemActivated() }
2851 }
2852 pub fn is_item_deactivated(&self) -> bool {
2853 unsafe { ImGui_IsItemDeactivated() }
2854 }
2855 pub fn is_item_deactivated_after_edit(&self) -> bool {
2856 unsafe { ImGui_IsItemDeactivatedAfterEdit() }
2857 }
2858 pub fn is_item_toggled_open(&self) -> bool {
2859 unsafe { ImGui_IsItemToggledOpen() }
2860 }
2861 pub fn is_any_item_hovered(&self) -> bool {
2862 unsafe { ImGui_IsAnyItemHovered() }
2863 }
2864 pub fn is_any_item_active(&self) -> bool {
2865 unsafe { ImGui_IsAnyItemActive() }
2866 }
2867 pub fn is_any_item_focused(&self) -> bool {
2868 unsafe { ImGui_IsAnyItemFocused() }
2869 }
2870 pub fn is_window_collapsed(&self) -> bool {
2871 unsafe { ImGui_IsWindowCollapsed() }
2872 }
2873 pub fn is_window_focused(&self, flags: FocusedFlags) -> bool {
2874 unsafe { ImGui_IsWindowFocused(flags.bits()) }
2875 }
2876 pub fn is_window_hovered(&self, flags: FocusedFlags) -> bool {
2877 unsafe { ImGui_IsWindowHovered(flags.bits()) }
2878 }
2879 pub fn get_item_id(&self) -> ImGuiID {
2880 unsafe { ImGui_GetItemID() }
2881 }
2882 pub fn get_id(&self, id: impl Hashable) -> ImGuiID {
2883 unsafe { id.get_id() }
2884 }
2885 pub fn get_item_rect_min(&self) -> Vector2 {
2886 unsafe { im_to_v2(ImGui_GetItemRectMin()) }
2887 }
2888 pub fn get_item_rect_max(&self) -> Vector2 {
2889 unsafe { im_to_v2(ImGui_GetItemRectMax()) }
2890 }
2891 pub fn get_item_rect_size(&self) -> Vector2 {
2892 unsafe { im_to_v2(ImGui_GetItemRectSize()) }
2893 }
2894 pub fn get_content_region_avail(&self) -> Vector2 {
2896 unsafe { im_to_v2(ImGui_GetContentRegionAvail()) }
2897 }
2898 pub fn get_window_pos(&self) -> Vector2 {
2899 unsafe { im_to_v2(ImGui_GetWindowPos()) }
2900 }
2901 pub fn get_window_width(&self) -> f32 {
2902 unsafe { ImGui_GetWindowWidth() }
2903 }
2904 pub fn get_window_height(&self) -> f32 {
2905 unsafe { ImGui_GetWindowHeight() }
2906 }
2907 pub fn get_scroll_x(&self) -> f32 {
2908 unsafe { ImGui_GetScrollX() }
2909 }
2910 pub fn get_scroll_y(&self) -> f32 {
2911 unsafe { ImGui_GetScrollY() }
2912 }
2913 pub fn set_scroll_x(&self, scroll_x: f32) {
2914 unsafe {
2915 ImGui_SetScrollX(scroll_x);
2916 }
2917 }
2918 pub fn set_scroll_y(&self, scroll_y: f32) {
2919 unsafe {
2920 ImGui_SetScrollY(scroll_y);
2921 }
2922 }
2923 pub fn get_scroll_max_x(&self) -> f32 {
2924 unsafe { ImGui_GetScrollMaxX() }
2925 }
2926 pub fn get_scroll_max_y(&self) -> f32 {
2927 unsafe { ImGui_GetScrollMaxY() }
2928 }
2929 pub fn set_scroll_here_x(&self, center_x_ratio: f32) {
2930 unsafe {
2931 ImGui_SetScrollHereX(center_x_ratio);
2932 }
2933 }
2934 pub fn set_scroll_here_y(&self, center_y_ratio: f32) {
2935 unsafe {
2936 ImGui_SetScrollHereY(center_y_ratio);
2937 }
2938 }
2939 pub fn set_scroll_from_pos_x(&self, local_x: f32, center_x_ratio: f32) {
2940 unsafe {
2941 ImGui_SetScrollFromPosX(local_x, center_x_ratio);
2942 }
2943 }
2944 pub fn set_scroll_from_pos_y(&self, local_y: f32, center_y_ratio: f32) {
2945 unsafe {
2946 ImGui_SetScrollFromPosY(local_y, center_y_ratio);
2947 }
2948 }
2949 pub fn set_window_pos(&self, pos: Vector2, cond: Cond) {
2950 unsafe {
2951 ImGui_SetWindowPos(&v2_to_im(pos), cond.bits());
2952 }
2953 }
2954 pub fn set_window_size(&self, size: Vector2, cond: Cond) {
2955 unsafe {
2956 ImGui_SetWindowSize(&v2_to_im(size), cond.bits());
2957 }
2958 }
2959 pub fn set_window_collapsed(&self, collapsed: bool, cond: Cond) {
2960 unsafe {
2961 ImGui_SetWindowCollapsed(collapsed, cond.bits());
2962 }
2963 }
2964 pub fn set_window_focus(&self) {
2965 unsafe {
2966 ImGui_SetWindowFocus();
2967 }
2968 }
2969 pub fn same_line(&self) {
2970 unsafe {
2971 ImGui_SameLine(0.0, -1.0);
2972 }
2973 }
2974 pub fn same_line_ex(&self, offset_from_start_x: f32, spacing: f32) {
2975 unsafe {
2976 ImGui_SameLine(offset_from_start_x, spacing);
2977 }
2978 }
2979 pub fn new_line(&self) {
2980 unsafe {
2981 ImGui_NewLine();
2982 }
2983 }
2984 pub fn spacing(&self) {
2985 unsafe {
2986 ImGui_Spacing();
2987 }
2988 }
2989 pub fn dummy(&self, size: Vector2) {
2990 unsafe {
2991 ImGui_Dummy(&v2_to_im(size));
2992 }
2993 }
2994 pub fn indent(&self, indent_w: f32) {
2995 unsafe {
2996 ImGui_Indent(indent_w);
2997 }
2998 }
2999 pub fn unindent(&self, indent_w: f32) {
3000 unsafe {
3001 ImGui_Unindent(indent_w);
3002 }
3003 }
3004 pub fn get_cursor_pos(&self) -> Vector2 {
3006 unsafe { im_to_v2(ImGui_GetCursorPos()) }
3007 }
3008 pub fn get_cursor_pos_x(&self) -> f32 {
3010 unsafe { ImGui_GetCursorPosX() }
3011 }
3012 pub fn get_cursor_pos_y(&self) -> f32 {
3014 unsafe { ImGui_GetCursorPosY() }
3015 }
3016 pub fn set_cursor_pos(&self, local_pos: Vector2) {
3018 unsafe {
3019 ImGui_SetCursorPos(&v2_to_im(local_pos));
3020 }
3021 }
3022 pub fn set_cursor_pos_x(&self, local_x: f32) {
3024 unsafe {
3025 ImGui_SetCursorPosX(local_x);
3026 }
3027 }
3028 pub fn set_cursor_pos_y(&self, local_y: f32) {
3030 unsafe {
3031 ImGui_SetCursorPosY(local_y);
3032 }
3033 }
3034 pub fn get_cursor_start_pos(&self) -> Vector2 {
3036 unsafe { im_to_v2(ImGui_GetCursorStartPos()) }
3037 }
3038 pub fn get_cursor_screen_pos(&self) -> Vector2 {
3040 unsafe { im_to_v2(ImGui_GetCursorScreenPos()) }
3041 }
3042 pub fn set_cursor_screen_pos(&self, pos: Vector2) {
3044 unsafe {
3045 ImGui_SetCursorScreenPos(&v2_to_im(pos));
3046 }
3047 }
3048 pub fn align_text_to_frame_padding(&self) {
3049 unsafe {
3050 ImGui_AlignTextToFramePadding();
3051 }
3052 }
3053 pub fn get_text_line_height(&self) -> f32 {
3054 unsafe { ImGui_GetTextLineHeight() }
3055 }
3056 pub fn get_text_line_height_with_spacing(&self) -> f32 {
3057 unsafe { ImGui_GetTextLineHeightWithSpacing() }
3058 }
3059 pub fn get_frame_height(&self) -> f32 {
3060 unsafe { ImGui_GetFrameHeight() }
3061 }
3062 pub fn get_frame_height_with_spacing(&self) -> f32 {
3063 unsafe { ImGui_GetFrameHeightWithSpacing() }
3064 }
3065 pub fn calc_item_width(&self) -> f32 {
3066 unsafe { ImGui_CalcItemWidth() }
3067 }
3068 pub fn calc_text_size(&self, text: &str) -> Vector2 {
3069 self.calc_text_size_ex(text, false, -1.0)
3070 }
3071 pub fn calc_text_size_ex(
3072 &self,
3073 text: &str,
3074 hide_text_after_double_hash: bool,
3075 wrap_width: f32,
3076 ) -> Vector2 {
3077 unsafe {
3078 let (start, end) = text_ptrs(text);
3079 im_to_v2(ImGui_CalcTextSize(
3080 start,
3081 end,
3082 hide_text_after_double_hash,
3083 wrap_width,
3084 ))
3085 }
3086 }
3087 pub fn set_color_edit_options(&self, flags: ColorEditFlags) {
3088 unsafe {
3089 ImGui_SetColorEditOptions(flags.bits());
3090 }
3091 }
3092 pub fn key_mods(&self) -> KeyMod {
3093 let mods = self.io().KeyMods;
3094 KeyMod::from_bits_truncate(mods & ImGuiKey::ImGuiMod_Mask_.0)
3095 }
3096 pub fn is_key_down(&self, key: Key) -> bool {
3097 unsafe { ImGui_IsKeyDown(key.bits()) }
3098 }
3099 pub fn is_key_pressed(&self, key: Key) -> bool {
3100 unsafe {
3101 ImGui_IsKeyPressed(key.bits(), true)
3102 }
3103 }
3104 pub fn is_key_pressed_no_repeat(&self, key: Key) -> bool {
3105 unsafe {
3106 ImGui_IsKeyPressed(key.bits(), false)
3107 }
3108 }
3109 pub fn is_key_released(&self, key: Key) -> bool {
3110 unsafe { ImGui_IsKeyReleased(key.bits()) }
3111 }
3112 pub fn get_key_pressed_amount(&self, key: Key, repeat_delay: f32, rate: f32) -> i32 {
3113 unsafe { ImGui_GetKeyPressedAmount(key.bits(), repeat_delay, rate) }
3114 }
3115 pub fn get_font_tex_uv_white_pixel(&self) -> Vector2 {
3116 unsafe { im_to_v2(ImGui_GetFontTexUvWhitePixel()) }
3117 }
3118 pub fn get_font_size(&self) -> f32 {
3121 unsafe { ImGui_GetFontSize() }
3122 }
3123 pub fn is_mouse_down(&self, button: MouseButton) -> bool {
3124 unsafe { ImGui_IsMouseDown(button.bits()) }
3125 }
3126 pub fn is_mouse_clicked(&self, button: MouseButton) -> bool {
3127 unsafe {
3128 ImGui_IsMouseClicked(button.bits(), false)
3129 }
3130 }
3131 pub fn is_mouse_clicked_repeat(&self, button: MouseButton) -> bool {
3132 unsafe {
3133 ImGui_IsMouseClicked(button.bits(), true)
3134 }
3135 }
3136 pub fn is_mouse_released(&self, button: MouseButton) -> bool {
3137 unsafe { ImGui_IsMouseReleased(button.bits()) }
3138 }
3139 pub fn is_mouse_double_clicked(&self, button: MouseButton) -> bool {
3140 unsafe { ImGui_IsMouseDoubleClicked(button.bits()) }
3141 }
3142 pub fn get_mouse_clicked_count(&self, button: MouseButton) -> i32 {
3143 unsafe { ImGui_GetMouseClickedCount(button.bits()) }
3144 }
3145 pub fn is_rect_visible_size(&self, size: Vector2) -> bool {
3146 unsafe { ImGui_IsRectVisible(&v2_to_im(size)) }
3147 }
3148 pub fn is_rect_visible(&self, rect_min: Vector2, rect_max: Vector2) -> bool {
3149 unsafe { ImGui_IsRectVisible1(&v2_to_im(rect_min), &v2_to_im(rect_max)) }
3150 }
3151 pub fn is_any_mouse_down(&self) -> bool {
3163 unsafe { ImGui_IsAnyMouseDown() }
3164 }
3165 pub fn get_mouse_pos(&self) -> Vector2 {
3166 unsafe { im_to_v2(ImGui_GetMousePos()) }
3167 }
3168 pub fn get_mouse_pos_on_opening_current_popup(&self) -> Vector2 {
3169 unsafe { im_to_v2(ImGui_GetMousePosOnOpeningCurrentPopup()) }
3170 }
3171 pub fn is_mouse_dragging(&self, button: MouseButton) -> bool {
3172 unsafe {
3173 ImGui_IsMouseDragging(button.bits(), -1.0)
3174 }
3175 }
3176 pub fn get_mouse_drag_delta(&self, button: MouseButton) -> Vector2 {
3177 unsafe {
3178 im_to_v2(ImGui_GetMouseDragDelta(
3179 button.bits(),
3180 -1.0,
3181 ))
3182 }
3183 }
3184 pub fn reset_mouse_drag_delta(&self, button: MouseButton) {
3185 unsafe {
3186 ImGui_ResetMouseDragDelta(button.bits());
3187 }
3188 }
3189 pub fn get_mouse_cursor(&self) -> MouseCursor {
3190 unsafe { MouseCursor::from_bits(ImGui_GetMouseCursor()).unwrap_or(MouseCursor::None) }
3191 }
3192 pub fn set_mouse_cursor(&self, cursor_type: MouseCursor) {
3193 unsafe {
3194 ImGui_SetMouseCursor(cursor_type.bits());
3195 }
3196 }
3197 pub fn get_time(&self) -> f64 {
3198 unsafe { ImGui_GetTime() }
3199 }
3200 pub fn get_frame_count(&self) -> i32 {
3201 unsafe { ImGui_GetFrameCount() }
3202 }
3203 pub fn is_popup_open(&self, str_id: Option<Id<impl IntoCStr>>) -> bool {
3204 self.is_popup_open_ex(str_id, PopupFlags::None)
3205 }
3206 pub fn is_popup_open_ex(&self, str_id: Option<Id<impl IntoCStr>>, flags: PopupFlags) -> bool {
3207 let temp;
3208 let str_id = match str_id {
3209 Some(s) => {
3210 temp = IntoCStr::into(s.0);
3211 temp.as_ptr()
3212 }
3213 None => null(),
3214 };
3215 unsafe { ImGui_IsPopupOpen(str_id, flags.bits()) }
3216 }
3217 pub fn is_below_blocking_modal(&self) -> bool {
3219 unsafe {
3221 let modal = ImGui_FindBlockingModal(self.CurrentWindow);
3222 !modal.is_null()
3223 }
3224 }
3225 pub fn is_blocking_modal(&self) -> bool {
3227 unsafe {
3229 let modal = ImGui_FindBlockingModal(std::ptr::null_mut());
3230 !modal.is_null()
3231 }
3232 }
3233 pub fn open_popup(&self, str_id: Id<impl IntoCStr>) {
3234 self.open_popup_ex(str_id, PopupFlags::None)
3235 }
3236 pub fn open_popup_ex(&self, str_id: Id<impl IntoCStr>, flags: PopupFlags) {
3237 let str_id = str_id.into();
3238 unsafe {
3239 ImGui_OpenPopup(str_id.as_ptr(), flags.bits());
3240 }
3241 }
3242 pub fn close_current_popup(&self) {
3243 unsafe {
3244 ImGui_CloseCurrentPopup();
3245 }
3246 }
3247 pub fn is_window_appearing(&self) -> bool {
3248 unsafe { ImGui_IsWindowAppearing() }
3249 }
3250 pub fn with_always_drag_drop_source<R>(
3251 &self,
3252 flags: DragDropSourceFlags,
3253 f: impl FnOnce(Option<DragDropPayloadSetter<'_>>) -> R,
3254 ) -> R {
3255 if !unsafe { ImGui_BeginDragDropSource(flags.bits()) } {
3256 return f(None);
3257 }
3258 let payload = DragDropPayloadSetter {
3259 _dummy: PhantomData,
3260 };
3261 let r = f(Some(payload));
3262 unsafe { ImGui_EndDragDropSource() }
3263 r
3264 }
3265 pub fn with_drag_drop_source<R>(
3266 &self,
3267 flags: DragDropSourceFlags,
3268 f: impl FnOnce(DragDropPayloadSetter<'_>) -> R,
3269 ) -> Option<R> {
3270 self.with_always_drag_drop_source(flags, move |r| r.map(f))
3271 }
3272 pub fn with_always_drag_drop_target<R>(
3273 &self,
3274 f: impl FnOnce(Option<DragDropPayloadGetter<'_>>) -> R,
3275 ) -> R {
3276 if !unsafe { ImGui_BeginDragDropTarget() } {
3277 return f(None);
3278 }
3279 let payload = DragDropPayloadGetter {
3280 _dummy: PhantomData,
3281 };
3282 let r = f(Some(payload));
3283 unsafe { ImGui_EndDragDropTarget() }
3284 r
3285 }
3286 pub fn with_drag_drop_target<R>(
3287 &self,
3288 f: impl FnOnce(DragDropPayloadGetter<'_>) -> R,
3289 ) -> Option<R> {
3290 self.with_always_drag_drop_target(move |r| r.map(f))
3291 }
3292
3293 #[must_use]
3294 pub fn list_clipper(&self, items_count: usize) -> ListClipper {
3295 ListClipper {
3296 items_count,
3297 items_height: -1.0,
3298 included_ranges: Vec::new(),
3299 }
3300 }
3301
3302 pub fn shortcut(&self, key_chord: impl Into<KeyChord>) -> bool {
3303 unsafe { ImGui_Shortcut(key_chord.into().bits(), 0) }
3304 }
3305 pub fn shortcut_ex(&self, key_chord: impl Into<KeyChord>, flags: InputFlags) -> bool {
3306 unsafe { ImGui_Shortcut(key_chord.into().bits(), flags.bits()) }
3307 }
3308 pub fn set_next_item_shortcut(&self, key_chord: impl Into<KeyChord>) {
3309 unsafe {
3310 ImGui_SetNextItemShortcut(key_chord.into().bits(), 0);
3311 }
3312 }
3313 pub fn set_next_item_shortcut_ex(&self, key_chord: impl Into<KeyChord>, flags: InputFlags) {
3314 unsafe {
3315 ImGui_SetNextItemShortcut(key_chord.into().bits(), flags.bits());
3316 }
3317 }
3318 pub fn is_keychord_pressed(&self, key_chord: impl Into<KeyChord>) -> bool {
3319 unsafe { ImGui_IsKeyChordPressed(key_chord.into().bits()) }
3320 }
3321
3322 pub fn get_font(&self, font_id: FontId) -> &Font {
3324 unsafe {
3325 let font = self.io().font_atlas().font_ptr(font_id);
3326 Font::cast(&*font)
3327 }
3328 }
3329
3330 pub fn get_font_baked(
3335 &self,
3336 font_id: FontId,
3337 font_size: f32,
3338 font_density: Option<f32>,
3339 ) -> &FontBaked {
3340 unsafe {
3341 let font = self.io().font_atlas().font_ptr(font_id);
3342 let baked = (*font).GetFontBaked(font_size, font_density.unwrap_or(-1.0));
3343 FontBaked::cast(&*baked)
3344 }
3345 }
3346
3347 pub fn get_atlas_texture_ref(&self) -> TextureRef<'_> {
3348 let tex_data = self.io().font_atlas().TexData;
3349 let tex_data = unsafe { &*tex_data };
3350 TextureRef::Ref(tex_data)
3351 }
3352
3353 pub fn get_custom_rect(&self, index: CustomRectIndex) -> Option<TextureRect<'_>> {
3354 let atlas = self.io().font_atlas();
3355 let rect = unsafe {
3356 let mut rect = MaybeUninit::zeroed();
3357 let ok = atlas.GetCustomRect(index.0, rect.as_mut_ptr());
3358 if !ok {
3359 return None;
3360 }
3361 rect.assume_init()
3362 };
3363
3364 let tex_ref = self.get_atlas_texture_ref();
3365 Some(TextureRect { rect, tex_ref })
3366 }
3367
3368 pub fn dock_space(
3369 &self,
3370 id: ImGuiID,
3371 size: Vector2,
3372 flags: DockNodeFlags, ) -> ImGuiID {
3374 unsafe { ImGui_DockSpace(id, &v2_to_im(size), flags.bits(), std::ptr::null()) }
3375 }
3376 pub fn dock_space_over_viewport(
3377 &self,
3378 dockspace_id: ImGuiID,
3379 viewport: &Viewport,
3380 flags: DockNodeFlags, ) -> ImGuiID {
3382 unsafe {
3383 ImGui_DockSpaceOverViewport(
3384 dockspace_id,
3385 viewport.get(),
3386 flags.bits(),
3387 std::ptr::null(), )
3389 }
3390 }
3391 pub fn set_next_window_dock_id(&self, dock_id: ImGuiID, cond: Cond) {
3392 unsafe {
3393 ImGui_SetNextWindowDockID(dock_id, cond.bits());
3394 }
3395 }
3396 pub fn get_window_dock_id(&self) -> ImGuiID {
3398 unsafe { ImGui_GetWindowDockID() }
3399 }
3400 pub fn is_window_docked(&self) -> bool {
3401 unsafe { ImGui_IsWindowDocked() }
3402 }
3403
3404 pub fn get_window_viewport(&self) -> &Viewport {
3405 unsafe { Viewport::cast(&*ImGui_GetWindowViewport()) }
3406 }
3407 pub fn set_next_window_viewport(&self, id: ImGuiID) {
3408 unsafe { ImGui_SetNextWindowViewport(id) }
3409 }
3410 pub fn viewport_foreground_draw_list(&self, viewport: &Viewport) -> WindowDrawList<'_, A> {
3411 unsafe {
3412 let ptr = ImGui_GetForegroundDrawList((&raw const *viewport.get()).cast_mut());
3413 WindowDrawList { ui: self, ptr }
3414 }
3415 }
3416 pub fn viewport_background_draw_list(&self, viewport: &Viewport) -> WindowDrawList<'_, A> {
3417 unsafe {
3418 let ptr = ImGui_GetBackgroundDrawList((&raw const *viewport.get()).cast_mut());
3419 WindowDrawList { ui: self, ptr }
3420 }
3421 }
3422}
3423
3424#[derive(Debug, Copy, Clone)]
3425pub struct TextureRect<'ui> {
3426 pub rect: ImFontAtlasRect,
3427 pub tex_ref: TextureRef<'ui>,
3428}
3429
3430pub struct ListClipper {
3431 items_count: usize,
3432 items_height: f32,
3433 included_ranges: Vec<std::ops::Range<usize>>,
3434}
3435
3436impl ListClipper {
3437 decl_builder_setter! {items_height: f32}
3438
3439 pub fn add_included_range(&mut self, range: std::ops::Range<usize>) {
3440 self.included_ranges.push(range);
3441 }
3442
3443 pub fn with(self, mut f: impl FnMut(usize)) {
3444 unsafe {
3445 let mut clip = ImGuiListClipper::new();
3446 clip.Begin(self.items_count as i32, self.items_height);
3447 for r in self.included_ranges {
3448 clip.IncludeItemsByIndex(r.start as i32, r.end as i32);
3449 }
3450 while clip.Step() {
3451 for i in clip.DisplayStart..clip.DisplayEnd {
3452 f(i as usize);
3453 }
3454 }
3455 }
3456 }
3457}
3458
3459transparent! {
3460 pub struct Font(ImFont);
3462}
3463
3464transparent! {
3465 pub struct FontGlyph(ImFontGlyph);
3466}
3467
3468impl FontGlyph {
3469 pub fn p0(&self) -> Vector2 {
3470 Vector2::new(self.0.X0, self.0.Y0)
3471 }
3472 pub fn p1(&self) -> Vector2 {
3473 Vector2::new(self.0.X1, self.0.Y1)
3474 }
3475 pub fn uv0(&self) -> Vector2 {
3476 Vector2::new(self.0.U0, self.0.V0)
3477 }
3478 pub fn uv1(&self) -> Vector2 {
3479 Vector2::new(self.0.U1, self.0.V1)
3480 }
3481 pub fn advance_x(&self) -> f32 {
3482 self.0.AdvanceX
3483 }
3484 pub fn visible(&self) -> bool {
3485 self.0.Visible() != 0
3486 }
3487 pub fn colored(&self) -> bool {
3488 self.0.Colored() != 0
3489 }
3490 pub fn codepoint(&self) -> char {
3491 char::try_from(self.0.Codepoint()).unwrap()
3492 }
3493}
3494
3495impl std::fmt::Debug for FontGlyph {
3496 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
3497 fmt.debug_struct("FontGlyph")
3498 .field("p0", &self.p0())
3499 .field("p1", &self.p1())
3500 .field("uv0", &self.uv0())
3501 .field("uv1", &self.uv1())
3502 .field("advance_x", &self.advance_x())
3503 .field("visible", &self.visible())
3504 .field("colored", &self.colored())
3505 .field("codepoint", &self.codepoint())
3506 .finish()
3507 }
3508}
3509
3510transparent! {
3511 #[derive(Debug)]
3512 pub struct FontBaked(ImFontBaked);
3513}
3514
3515impl FontBaked {
3516 pub fn find_glyph(&self, c: char) -> &FontGlyph {
3518 unsafe {
3519 FontGlyph::cast(&*ImFontBaked_FindGlyph(
3520 (&raw const self.0).cast_mut(),
3521 ImWchar::from(c),
3522 ))
3523 }
3524 }
3525
3526 pub fn find_glyph_no_fallback(&self, c: char) -> Option<&FontGlyph> {
3528 unsafe {
3529 let p =
3530 ImFontBaked_FindGlyphNoFallback((&raw const self.0).cast_mut(), ImWchar::from(c));
3531 p.as_ref().map(FontGlyph::cast)
3532 }
3533 }
3534
3535 pub unsafe fn inner(&mut self) -> &mut ImFontBaked {
3536 &mut self.0
3537 }
3538
3539 pub fn set_ascent(&mut self, ascent: f32) {
3541 self.0.Ascent = ascent;
3542 }
3543 pub fn set_descent(&mut self, descent: f32) {
3544 self.0.Descent = descent;
3545 }
3546}
3547
3548#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3552pub struct FontId(u32);
3553
3554#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3559pub struct CustomRectIndex(i32);
3560
3561impl Default for CustomRectIndex {
3562 fn default() -> Self {
3563 CustomRectIndex(-1)
3565 }
3566}
3567
3568transparent! {
3569 #[derive(Debug)]
3570 pub struct FontAtlas(ImFontAtlas);
3571}
3572
3573type PixelImage<'a> = image::ImageBuffer<image::Rgba<u8>, &'a mut [u8]>;
3574type SubPixelImage<'a, 'b> = image::SubImage<&'a mut PixelImage<'b>>;
3575
3576impl FontAtlas {
3577 pub unsafe fn texture_ref(&self) -> ImTextureRef {
3578 self.TexRef
3579 }
3580 pub unsafe fn inner(&mut self) -> &mut ImFontAtlas {
3581 &mut self.0
3582 }
3583
3584 pub fn current_texture_unique_id(&self) -> TextureUniqueId {
3585 unsafe {
3586 let id = (*self.TexRef._TexData).UniqueID;
3587 TextureUniqueId(id)
3588 }
3589 }
3590
3591 fn texture_unique_id(&self, uid: TextureUniqueId) -> Option<&ImTextureData> {
3592 unsafe {
3593 self.TexList
3594 .iter()
3595 .find(|x| (***x).UniqueID == uid.0)
3596 .map(|p| &**p)
3597 }
3598 }
3599
3600 unsafe fn font_ptr(&self, font: FontId) -> *mut ImFont {
3601 unsafe {
3602 *self
3604 .Fonts
3605 .iter()
3606 .find(|f| f.as_ref().map(|f| f.FontId) == Some(font.0))
3607 .unwrap_or(&self.Fonts[0])
3608 }
3609 }
3610
3611 pub fn check_texture_unique_id(&self, uid: TextureUniqueId) -> bool {
3612 self.texture_unique_id(uid).is_some_and(|x| {
3613 !matches!(
3614 x.Status,
3615 ImTextureStatus::ImTextureStatus_WantDestroy
3616 | ImTextureStatus::ImTextureStatus_Destroyed
3617 )
3618 })
3619 }
3620
3621 pub fn get_texture_by_unique_id(&self, uid: TextureUniqueId) -> Option<TextureId> {
3622 let p = self.texture_unique_id(uid)?;
3623 if p.Status == ImTextureStatus::ImTextureStatus_Destroyed || p.TexID == 0 {
3625 None
3626 } else {
3627 unsafe { Some(TextureId::from_id(p.TexID)) }
3628 }
3629 }
3630
3631 pub fn add_font(&mut self, font: FontInfo) -> FontId {
3636 self.add_font_priv(font, false)
3637 }
3638
3639 pub fn remove_font(&mut self, font_id: FontId) {
3640 unsafe {
3641 let f = self.font_ptr(font_id);
3642 self.0.RemoveFont(f);
3647 }
3648 }
3649
3650 pub fn add_font_collection(&mut self, fonts: impl IntoIterator<Item = FontInfo>) -> FontId {
3655 let mut fonts = fonts.into_iter();
3656 let first = fonts.next().expect("empty font collection");
3657 let id = self.add_font_priv(first, false);
3658 for font in fonts {
3659 self.add_font_priv(font, true);
3660 }
3661 id
3662 }
3663 fn add_font_priv(&mut self, font: FontInfo, merge: bool) -> FontId {
3664 unsafe {
3665 let mut fc = ImFontConfig::new();
3666 fc.FontDataOwnedByAtlas = false;
3668 fc.MergeMode = merge;
3669 if !font.name.is_empty() {
3670 let cname = font.name.as_bytes();
3671 let name_len = cname.len().min(fc.Name.len() - 1);
3672 fc.Name[..name_len]
3673 .copy_from_slice(std::mem::transmute::<&[u8], &[i8]>(&cname[..name_len]));
3674 fc.Name[name_len] = 0;
3675 }
3676 fc.Flags = font.flags.bits();
3677 fc.SizePixels = font.size;
3678
3679 let font_ptr = match font.ttf {
3680 TtfData::Bytes(bytes) => {
3681 self.0.AddFontFromMemoryTTF(
3682 bytes.as_ptr() as *mut _,
3683 bytes.len() as i32,
3684 0.0,
3685 &fc,
3686 std::ptr::null(),
3687 )
3688 }
3689 TtfData::DefaultFont => self.0.AddFontDefault(&fc),
3690 TtfData::CustomLoader(glyph_loader) => {
3691 let ptr = Box::into_raw(Box::new(glyph_loader));
3692 fc.FontLoader = &fontloader::FONT_LOADER.0;
3693 fc.FontData = ptr as *mut c_void;
3694 fc.FontDataOwnedByAtlas = true;
3695 self.0.AddFont(&fc)
3696 }
3697 };
3698 let Some(font) = font_ptr.as_ref() else {
3699 log::error!("Error loading font!");
3700 return FontId::default();
3701 };
3702 FontId(font.FontId)
3703 }
3704 }
3705
3706 pub fn add_custom_rect(
3710 &mut self,
3711 size: impl Into<mint::Vector2<u32>>,
3712 draw: impl FnOnce(&mut SubPixelImage<'_, '_>),
3713 ) -> CustomRectIndex {
3714 let size = size.into();
3715 unsafe {
3716 let mut rect = MaybeUninit::zeroed();
3717 let idx = self.0.AddCustomRect(
3718 i32::try_from(size.x).unwrap(),
3719 i32::try_from(size.y).unwrap(),
3720 rect.as_mut_ptr(),
3721 );
3722 let idx = CustomRectIndex(idx);
3723 let rect = rect.assume_init();
3724 let tex_data = &(*self.TexData);
3725
3726 let mut pixel_image = PixelImage::from_raw(
3727 tex_data.Width as u32,
3728 tex_data.Height as u32,
3729 std::slice::from_raw_parts_mut(
3730 tex_data.Pixels,
3731 tex_data.Width as usize
3732 * tex_data.Height as usize
3733 * tex_data.BytesPerPixel as usize,
3734 ),
3735 )
3736 .unwrap();
3737
3738 let mut sub_image =
3739 pixel_image.sub_image(rect.x as u32, rect.y as u32, rect.w as u32, rect.h as u32);
3740 draw(&mut sub_image);
3741
3742 idx
3743 }
3744 }
3745
3746 pub fn remove_custom_rect(&mut self, idx: CustomRectIndex) {
3747 if idx.0 < 0 {
3748 return;
3749 }
3750 unsafe {
3751 self.0.RemoveCustomRect(idx.0);
3752 }
3753 }
3754}
3755
3756transparent_mut! {
3757 #[derive(Debug)]
3758 pub struct Io(ImGuiIO);
3759}
3760
3761transparent! {
3762 #[derive(Debug)]
3766 pub struct IoMut(ImGuiIO);
3767}
3768
3769impl Io {
3770 pub fn font_atlas(&self) -> &FontAtlas {
3771 unsafe { FontAtlas::cast(&*self.Fonts) }
3772 }
3773
3774 pub fn want_capture_mouse(&self) -> bool {
3775 self.WantCaptureMouse
3776 }
3777 pub fn want_capture_keyboard(&self) -> bool {
3778 self.WantCaptureKeyboard
3779 }
3780 pub fn want_text_input(&self) -> bool {
3781 self.WantTextInput
3782 }
3783 pub fn display_size(&self) -> Vector2 {
3784 im_to_v2(self.DisplaySize)
3785 }
3786 pub fn display_scale(&self) -> f32 {
3787 self.DisplayFramebufferScale.x
3788 }
3789
3790 pub fn add_config_flags(&mut self, flags: ConfigFlags) {
3792 self.ConfigFlags |= flags.bits();
3793 }
3794 pub fn remove_config_flags(&mut self, flags: ConfigFlags) {
3795 self.ConfigFlags &= !flags.bits();
3796 }
3797 pub fn add_backend_flags(&mut self, flags: BackendFlags) {
3798 self.BackendFlags |= flags.bits();
3799 }
3800 pub fn remove_backend_flags(&mut self, flags: BackendFlags) {
3801 self.BackendFlags &= !flags.bits();
3802 }
3803 pub fn delta_time(&mut self) -> Duration {
3804 Duration::from_secs_f32(self.DeltaTime)
3805 }
3806 pub fn set_delta_time(&mut self, d: Duration) {
3807 self.DeltaTime = d.as_secs_f32()
3808 }
3809}
3810
3811impl IoMut {
3812 pub unsafe fn inner(&mut self) -> &mut Io {
3813 Io::cast_mut(&mut self.0)
3814 }
3815 pub fn set_allow_user_scaling(&mut self, val: bool) {
3816 self.0.FontAllowUserScaling = val;
3817 }
3818 pub fn nav_enable_keyboard(&mut self) {
3819 unsafe {
3820 self.inner()
3821 .add_config_flags(ConfigFlags::NavEnableKeyboard);
3822 }
3823 }
3824 pub fn nav_enable_gamepad(&mut self) {
3825 unsafe {
3826 self.inner().add_config_flags(ConfigFlags::NavEnableGamepad);
3827 }
3828 }
3829 pub fn font_atlas_mut(&mut self) -> &mut FontAtlas {
3830 unsafe { FontAtlas::cast_mut(&mut *self.Fonts) }
3831 }
3832}
3833
3834transparent_mut! {
3835 #[derive(Debug)]
3836 pub struct PlatformIo(ImGuiPlatformIO);
3837}
3838
3839impl PlatformIo {
3840 pub unsafe fn textures_mut(&mut self) -> impl Iterator<Item = &mut ImTextureData> {
3841 self.Textures.iter_mut().map(|t| unsafe { &mut **t })
3842 }
3843}
3844
3845#[derive(Debug)]
3846pub struct SizeCallbackData<'a> {
3847 ptr: &'a mut ImGuiSizeCallbackData,
3848}
3849
3850impl SizeCallbackData<'_> {
3851 pub fn pos(&self) -> Vector2 {
3852 im_to_v2(self.ptr.Pos)
3853 }
3854 pub fn current_size(&self) -> Vector2 {
3855 im_to_v2(self.ptr.CurrentSize)
3856 }
3857 pub fn desired_size(&self) -> Vector2 {
3858 im_to_v2(self.ptr.DesiredSize)
3859 }
3860 pub fn set_desired_size(&mut self, sz: Vector2) {
3861 self.ptr.DesiredSize = v2_to_im(sz);
3862 }
3863}
3864
3865unsafe extern "C" fn call_size_callback<A>(ptr: *mut ImGuiSizeCallbackData) {
3866 unsafe {
3867 let ptr = &mut *ptr;
3868 let id = ptr.UserData as usize;
3869 let data = SizeCallbackData { ptr };
3870 Ui::<A>::run_callback(id, data);
3871 }
3872}
3873
3874pub struct WindowDrawList<'ui, A> {
3875 ui: &'ui Ui<A>,
3876 ptr: *mut ImDrawList,
3877}
3878
3879impl<A> WindowDrawList<'_, A> {
3880 pub fn add_line(&self, p1: Vector2, p2: Vector2, color: Color, thickness: f32) {
3881 unsafe {
3882 ImDrawList_AddLine(
3883 self.ptr,
3884 &v2_to_im(p1),
3885 &v2_to_im(p2),
3886 color.as_u32(),
3887 thickness,
3888 );
3889 }
3890 }
3891 pub fn add_rect(
3892 &self,
3893 p_min: Vector2,
3894 p_max: Vector2,
3895 color: Color,
3896 rounding: f32,
3897 flags: DrawFlags,
3898 thickness: f32,
3899 ) {
3900 unsafe {
3901 ImDrawList_AddRect(
3902 self.ptr,
3903 &v2_to_im(p_min),
3904 &v2_to_im(p_max),
3905 color.as_u32(),
3906 rounding,
3907 flags.bits(),
3908 thickness,
3909 );
3910 }
3911 }
3912 pub fn add_rect_filled(
3913 &self,
3914 p_min: Vector2,
3915 p_max: Vector2,
3916 color: Color,
3917 rounding: f32,
3918 flags: DrawFlags,
3919 ) {
3920 unsafe {
3921 ImDrawList_AddRectFilled(
3922 self.ptr,
3923 &v2_to_im(p_min),
3924 &v2_to_im(p_max),
3925 color.as_u32(),
3926 rounding,
3927 flags.bits(),
3928 );
3929 }
3930 }
3931 pub fn add_rect_filled_multicolor(
3932 &self,
3933 p_min: Vector2,
3934 p_max: Vector2,
3935 col_upr_left: Color,
3936 col_upr_right: Color,
3937 col_bot_right: Color,
3938 col_bot_left: Color,
3939 ) {
3940 unsafe {
3941 ImDrawList_AddRectFilledMultiColor(
3942 self.ptr,
3943 &v2_to_im(p_min),
3944 &v2_to_im(p_max),
3945 col_upr_left.as_u32(),
3946 col_upr_right.as_u32(),
3947 col_bot_right.as_u32(),
3948 col_bot_left.as_u32(),
3949 );
3950 }
3951 }
3952 pub fn add_quad(
3953 &self,
3954 p1: Vector2,
3955 p2: Vector2,
3956 p3: Vector2,
3957 p4: Vector2,
3958 color: Color,
3959 thickness: f32,
3960 ) {
3961 unsafe {
3962 ImDrawList_AddQuad(
3963 self.ptr,
3964 &v2_to_im(p1),
3965 &v2_to_im(p2),
3966 &v2_to_im(p3),
3967 &v2_to_im(p4),
3968 color.as_u32(),
3969 thickness,
3970 );
3971 }
3972 }
3973 pub fn add_quad_filled(
3974 &self,
3975 p1: Vector2,
3976 p2: Vector2,
3977 p3: Vector2,
3978 p4: Vector2,
3979 color: Color,
3980 ) {
3981 unsafe {
3982 ImDrawList_AddQuadFilled(
3983 self.ptr,
3984 &v2_to_im(p1),
3985 &v2_to_im(p2),
3986 &v2_to_im(p3),
3987 &v2_to_im(p4),
3988 color.as_u32(),
3989 );
3990 }
3991 }
3992 pub fn add_triangle(
3993 &self,
3994 p1: Vector2,
3995 p2: Vector2,
3996 p3: Vector2,
3997 color: Color,
3998 thickness: f32,
3999 ) {
4000 unsafe {
4001 ImDrawList_AddTriangle(
4002 self.ptr,
4003 &v2_to_im(p1),
4004 &v2_to_im(p2),
4005 &v2_to_im(p3),
4006 color.as_u32(),
4007 thickness,
4008 );
4009 }
4010 }
4011 pub fn add_triangle_filled(&self, p1: Vector2, p2: Vector2, p3: Vector2, color: Color) {
4012 unsafe {
4013 ImDrawList_AddTriangleFilled(
4014 self.ptr,
4015 &v2_to_im(p1),
4016 &v2_to_im(p2),
4017 &v2_to_im(p3),
4018 color.as_u32(),
4019 );
4020 }
4021 }
4022 pub fn add_circle(
4023 &self,
4024 center: Vector2,
4025 radius: f32,
4026 color: Color,
4027 num_segments: i32,
4028 thickness: f32,
4029 ) {
4030 unsafe {
4031 ImDrawList_AddCircle(
4032 self.ptr,
4033 &v2_to_im(center),
4034 radius,
4035 color.as_u32(),
4036 num_segments,
4037 thickness,
4038 );
4039 }
4040 }
4041 pub fn add_circle_filled(&self, center: Vector2, radius: f32, color: Color, num_segments: i32) {
4042 unsafe {
4043 ImDrawList_AddCircleFilled(
4044 self.ptr,
4045 &v2_to_im(center),
4046 radius,
4047 color.as_u32(),
4048 num_segments,
4049 );
4050 }
4051 }
4052 pub fn add_ngon(
4053 &self,
4054 center: Vector2,
4055 radius: f32,
4056 color: Color,
4057 num_segments: i32,
4058 thickness: f32,
4059 ) {
4060 unsafe {
4061 ImDrawList_AddNgon(
4062 self.ptr,
4063 &v2_to_im(center),
4064 radius,
4065 color.as_u32(),
4066 num_segments,
4067 thickness,
4068 );
4069 }
4070 }
4071 pub fn add_ngon_filled(&self, center: Vector2, radius: f32, color: Color, num_segments: i32) {
4072 unsafe {
4073 ImDrawList_AddNgonFilled(
4074 self.ptr,
4075 &v2_to_im(center),
4076 radius,
4077 color.as_u32(),
4078 num_segments,
4079 );
4080 }
4081 }
4082 pub fn add_ellipse(
4083 &self,
4084 center: Vector2,
4085 radius: Vector2,
4086 color: Color,
4087 rot: f32,
4088 num_segments: i32,
4089 thickness: f32,
4090 ) {
4091 unsafe {
4092 ImDrawList_AddEllipse(
4093 self.ptr,
4094 &v2_to_im(center),
4095 &v2_to_im(radius),
4096 color.as_u32(),
4097 rot,
4098 num_segments,
4099 thickness,
4100 );
4101 }
4102 }
4103 pub fn add_ellipse_filled(
4104 &self,
4105 center: Vector2,
4106 radius: Vector2,
4107 color: Color,
4108 rot: f32,
4109 num_segments: i32,
4110 ) {
4111 unsafe {
4112 ImDrawList_AddEllipseFilled(
4113 self.ptr,
4114 &v2_to_im(center),
4115 &v2_to_im(radius),
4116 color.as_u32(),
4117 rot,
4118 num_segments,
4119 );
4120 }
4121 }
4122 pub fn add_text(&self, pos: Vector2, color: Color, text: &str) {
4123 unsafe {
4124 let (start, end) = text_ptrs(text);
4125 ImDrawList_AddText(self.ptr, &v2_to_im(pos), color.as_u32(), start, end);
4126 }
4127 }
4128 pub fn add_text_ex(
4129 &self,
4130 font: FontId,
4131 font_size: f32,
4132 pos: Vector2,
4133 color: Color,
4134 text: &str,
4135 wrap_width: f32,
4136 cpu_fine_clip_rect: Option<ImVec4>,
4137 ) {
4138 unsafe {
4139 let (start, end) = text_ptrs(text);
4140 ImDrawList_AddText1(
4141 self.ptr,
4142 self.ui.io().font_atlas().font_ptr(font),
4143 font_size,
4144 &v2_to_im(pos),
4145 color.as_u32(),
4146 start,
4147 end,
4148 wrap_width,
4149 cpu_fine_clip_rect
4150 .as_ref()
4151 .map(|x| x as *const _)
4152 .unwrap_or(null()),
4153 );
4154 }
4155 }
4156 pub fn add_polyline(&self, points: &[ImVec2], color: Color, flags: DrawFlags, thickness: f32) {
4157 unsafe {
4158 ImDrawList_AddPolyline(
4159 self.ptr,
4160 points.as_ptr(),
4161 points.len() as i32,
4162 color.as_u32(),
4163 flags.bits(),
4164 thickness,
4165 );
4166 }
4167 }
4168 pub fn add_convex_poly_filled(&self, points: &[ImVec2], color: Color) {
4169 unsafe {
4170 ImDrawList_AddConvexPolyFilled(
4171 self.ptr,
4172 points.as_ptr(),
4173 points.len() as i32,
4174 color.as_u32(),
4175 );
4176 }
4177 }
4178 pub fn add_concave_poly_filled(&self, points: &[ImVec2], color: Color) {
4179 unsafe {
4180 ImDrawList_AddConcavePolyFilled(
4181 self.ptr,
4182 points.as_ptr(),
4183 points.len() as i32,
4184 color.as_u32(),
4185 );
4186 }
4187 }
4188 pub fn add_bezier_cubic(
4189 &self,
4190 p1: Vector2,
4191 p2: Vector2,
4192 p3: Vector2,
4193 p4: Vector2,
4194 color: Color,
4195 thickness: f32,
4196 num_segments: i32,
4197 ) {
4198 unsafe {
4199 ImDrawList_AddBezierCubic(
4200 self.ptr,
4201 &v2_to_im(p1),
4202 &v2_to_im(p2),
4203 &v2_to_im(p3),
4204 &v2_to_im(p4),
4205 color.as_u32(),
4206 thickness,
4207 num_segments,
4208 );
4209 }
4210 }
4211 pub fn add_bezier_quadratic(
4212 &self,
4213 p1: Vector2,
4214 p2: Vector2,
4215 p3: Vector2,
4216 color: Color,
4217 thickness: f32,
4218 num_segments: i32,
4219 ) {
4220 unsafe {
4221 ImDrawList_AddBezierQuadratic(
4222 self.ptr,
4223 &v2_to_im(p1),
4224 &v2_to_im(p2),
4225 &v2_to_im(p3),
4226 color.as_u32(),
4227 thickness,
4228 num_segments,
4229 );
4230 }
4231 }
4232 pub fn add_image(
4233 &self,
4234 texture_ref: TextureRef,
4235 p_min: Vector2,
4236 p_max: Vector2,
4237 uv_min: Vector2,
4238 uv_max: Vector2,
4239 color: Color,
4240 ) {
4241 unsafe {
4242 ImDrawList_AddImage(
4243 self.ptr,
4244 texture_ref.tex_ref(),
4245 &v2_to_im(p_min),
4246 &v2_to_im(p_max),
4247 &v2_to_im(uv_min),
4248 &v2_to_im(uv_max),
4249 color.as_u32(),
4250 );
4251 }
4252 }
4253 pub fn add_image_quad(
4254 &self,
4255 texture_ref: TextureRef,
4256 p1: Vector2,
4257 p2: Vector2,
4258 p3: Vector2,
4259 p4: Vector2,
4260 uv1: Vector2,
4261 uv2: Vector2,
4262 uv3: Vector2,
4263 uv4: Vector2,
4264 color: Color,
4265 ) {
4266 unsafe {
4267 ImDrawList_AddImageQuad(
4268 self.ptr,
4269 texture_ref.tex_ref(),
4270 &v2_to_im(p1),
4271 &v2_to_im(p2),
4272 &v2_to_im(p3),
4273 &v2_to_im(p4),
4274 &v2_to_im(uv1),
4275 &v2_to_im(uv2),
4276 &v2_to_im(uv3),
4277 &v2_to_im(uv4),
4278 color.as_u32(),
4279 );
4280 }
4281 }
4282 pub fn add_image_rounded(
4283 &self,
4284 texture_ref: TextureRef,
4285 p_min: Vector2,
4286 p_max: Vector2,
4287 uv_min: Vector2,
4288 uv_max: Vector2,
4289 color: Color,
4290 rounding: f32,
4291 flags: DrawFlags,
4292 ) {
4293 unsafe {
4294 ImDrawList_AddImageRounded(
4295 self.ptr,
4296 texture_ref.tex_ref(),
4297 &v2_to_im(p_min),
4298 &v2_to_im(p_max),
4299 &v2_to_im(uv_min),
4300 &v2_to_im(uv_max),
4301 color.as_u32(),
4302 rounding,
4303 flags.bits(),
4304 );
4305 }
4306 }
4307
4308 pub fn add_callback(&self, cb: impl FnOnce(&mut A) + 'static) {
4309 let mut cb = Some(cb);
4313 unsafe {
4314 let id = self.ui.push_callback(move |a, _: ()| {
4315 if let Some(cb) = cb.take() {
4316 cb(&mut *a);
4317 }
4318 });
4319 ImDrawList_AddCallback(
4320 self.ptr,
4321 Some(call_drawlist_callback::<A>),
4322 id as *mut c_void,
4323 0,
4324 );
4325 }
4326 }
4327 pub fn add_draw_cmd(&self) {
4328 unsafe {
4329 ImDrawList_AddDrawCmd(self.ptr);
4330 }
4331 }
4332}
4333
4334unsafe extern "C" fn call_drawlist_callback<A>(
4335 _parent_list: *const ImDrawList,
4336 cmd: *const ImDrawCmd,
4337) {
4338 unsafe {
4339 let id = (*cmd).UserCallbackData as usize;
4340 Ui::<A>::run_callback(id, ());
4341 }
4342}
4343
4344pub trait Hashable {
4346 unsafe fn get_id(&self) -> ImGuiID;
4348 unsafe fn push(&self);
4349}
4350
4351impl Hashable for &str {
4352 unsafe fn get_id(&self) -> ImGuiID {
4353 unsafe {
4354 let (start, end) = text_ptrs(self);
4355 ImGui_GetID1(start, end)
4356 }
4357 }
4358 unsafe fn push(&self) {
4359 unsafe {
4360 let (start, end) = text_ptrs(self);
4361 ImGui_PushID1(start, end);
4362 }
4363 }
4364}
4365
4366impl Hashable for usize {
4367 unsafe fn get_id(&self) -> ImGuiID {
4368 unsafe { ImGui_GetID2(*self as *const c_void) }
4369 }
4370 unsafe fn push(&self) {
4371 unsafe {
4372 ImGui_PushID2(*self as *const c_void);
4373 }
4374 }
4375}
4376
4377pub trait Pushable {
4384 unsafe fn push(&self);
4385 unsafe fn pop(&self);
4386}
4387
4388struct PushableGuard<'a, P: Pushable>(&'a P);
4389
4390impl<P: Pushable> Drop for PushableGuard<'_, P> {
4391 fn drop(&mut self) {
4392 unsafe {
4393 self.0.pop();
4394 }
4395 }
4396}
4397
4398#[allow(clippy::needless_lifetimes)]
4399unsafe fn push_guard<'a, P: Pushable>(p: &'a P) -> PushableGuard<'a, P> {
4400 unsafe {
4401 p.push();
4402 PushableGuard(p)
4403 }
4404}
4405
4406impl Pushable for () {
4408 unsafe fn push(&self) {}
4409 unsafe fn pop(&self) {}
4410}
4411
4412impl<A: Pushable> Pushable for (A,) {
4413 unsafe fn push(&self) {
4414 unsafe {
4415 self.0.push();
4416 }
4417 }
4418 unsafe fn pop(&self) {
4419 unsafe {
4420 self.0.pop();
4421 }
4422 }
4423}
4424
4425impl<A: Pushable, B: Pushable> Pushable for (A, B) {
4426 unsafe fn push(&self) {
4427 unsafe {
4428 self.0.push();
4429 self.1.push();
4430 }
4431 }
4432 unsafe fn pop(&self) {
4433 unsafe {
4434 self.1.pop();
4435 self.0.pop();
4436 }
4437 }
4438}
4439
4440impl<A: Pushable, B: Pushable, C: Pushable> Pushable for (A, B, C) {
4441 unsafe fn push(&self) {
4442 unsafe {
4443 self.0.push();
4444 self.1.push();
4445 self.2.push();
4446 }
4447 }
4448 unsafe fn pop(&self) {
4449 unsafe {
4450 self.2.pop();
4451 self.1.pop();
4452 self.0.pop();
4453 }
4454 }
4455}
4456
4457impl<A: Pushable, B: Pushable, C: Pushable, D: Pushable> Pushable for (A, B, C, D) {
4458 unsafe fn push(&self) {
4459 unsafe {
4460 self.0.push();
4461 self.1.push();
4462 self.2.push();
4463 self.3.push();
4464 }
4465 }
4466 unsafe fn pop(&self) {
4467 unsafe {
4468 self.3.pop();
4469 self.2.pop();
4470 self.1.pop();
4471 self.0.pop();
4472 }
4473 }
4474}
4475
4476impl Pushable for &[&dyn Pushable] {
4477 unsafe fn push(&self) {
4478 unsafe {
4479 for st in *self {
4480 st.push();
4481 }
4482 }
4483 }
4484 unsafe fn pop(&self) {
4485 unsafe {
4486 for st in self.iter().rev() {
4487 st.pop();
4488 }
4489 }
4490 }
4491}
4492
4493impl<T: Pushable> Pushable for Option<T> {
4495 unsafe fn push(&self) {
4496 unsafe {
4497 if let Some(s) = self {
4498 s.push();
4499 }
4500 }
4501 }
4502 unsafe fn pop(&self) {
4503 unsafe {
4504 if let Some(s) = self {
4505 s.pop();
4506 }
4507 }
4508 }
4509}
4510
4511impl Pushable for FontId {
4513 unsafe fn push(&self) {
4514 unsafe {
4515 let font = current_font_ptr(*self);
4516 ImGui_PushFont(font, 0.0);
4517 }
4518 }
4519 unsafe fn pop(&self) {
4520 unsafe {
4521 ImGui_PopFont();
4522 }
4523 }
4524}
4525
4526pub struct FontSize(pub f32);
4527
4528impl Pushable for FontSize {
4529 unsafe fn push(&self) {
4530 unsafe {
4531 ImGui_PushFont(std::ptr::null_mut(), self.0);
4533 }
4534 }
4535 unsafe fn pop(&self) {
4536 unsafe {
4537 ImGui_PopFont();
4538 }
4539 }
4540}
4541
4542pub struct FontAndSize(pub FontId, pub f32);
4543
4544impl Pushable for FontAndSize {
4545 unsafe fn push(&self) {
4546 unsafe {
4547 ImGui_PushFont(current_font_ptr(self.0), self.1);
4548 }
4549 }
4550 unsafe fn pop(&self) {
4551 unsafe {
4552 ImGui_PopFont();
4553 }
4554 }
4555}
4556
4557pub type StyleColor = (ColorId, Color);
4558
4559#[derive(Copy, Clone, Debug)]
4560pub enum TextureRef<'a> {
4561 Id(TextureId),
4562 Ref(&'a ImTextureData),
4563}
4564
4565impl TextureRef<'_> {
4566 pub unsafe fn tex_ref(&self) -> ImTextureRef {
4567 match self {
4568 TextureRef::Id(TextureId(id)) => ImTextureRef {
4569 _TexData: null_mut(),
4570 _TexID: *id,
4571 },
4572 TextureRef::Ref(tex_data) => ImTextureRef {
4573 _TexData: (&raw const **tex_data).cast_mut(),
4574 _TexID: 0,
4575 },
4576 }
4577 }
4578
4579 pub unsafe fn tex_id(&self) -> TextureId {
4580 unsafe {
4581 match self {
4582 TextureRef::Id(tex_id) => *tex_id,
4583 TextureRef::Ref(tex_data) => {
4584 let id = tex_data.TexID;
4585 TextureId::from_id(id)
4586 }
4587 }
4588 }
4589 }
4590}
4591
4592#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4593pub struct TextureId(ImTextureID);
4594
4595impl TextureId {
4596 pub fn id(&self) -> ImTextureID {
4597 self.0
4598 }
4599 pub unsafe fn from_id(id: ImTextureID) -> Self {
4600 Self(id)
4601 }
4602}
4603
4604#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4605pub struct TextureUniqueId(i32);
4606
4607impl Pushable for StyleColor {
4608 unsafe fn push(&self) {
4609 unsafe {
4610 ImGui_PushStyleColor1(self.0.bits(), &self.1.into());
4611 }
4612 }
4613 unsafe fn pop(&self) {
4614 unsafe {
4615 ImGui_PopStyleColor(1);
4616 }
4617 }
4618}
4619
4620impl Pushable for [StyleColor] {
4621 unsafe fn push(&self) {
4622 unsafe {
4623 for sc in self {
4624 sc.push();
4625 }
4626 }
4627 }
4628 unsafe fn pop(&self) {
4629 unsafe {
4630 ImGui_PopStyleColor(self.len() as i32);
4631 }
4632 }
4633}
4634
4635impl<const N: usize> Pushable for [StyleColor; N] {
4636 unsafe fn push(&self) {
4637 unsafe {
4638 self.as_slice().push();
4639 }
4640 }
4641 unsafe fn pop(&self) {
4642 unsafe {
4643 self.as_slice().pop();
4644 }
4645 }
4646}
4647
4648pub type StyleColorF = (ColorId, ImVec4);
4649
4650impl Pushable for StyleColorF {
4651 unsafe fn push(&self) {
4652 unsafe {
4653 ImGui_PushStyleColor1(self.0.bits(), &self.1);
4654 }
4655 }
4656 unsafe fn pop(&self) {
4657 unsafe {
4658 ImGui_PopStyleColor(1);
4659 }
4660 }
4661}
4662
4663impl Pushable for [StyleColorF] {
4664 unsafe fn push(&self) {
4665 unsafe {
4666 for sc in self {
4667 sc.push();
4668 }
4669 }
4670 }
4671 unsafe fn pop(&self) {
4672 unsafe {
4673 ImGui_PopStyleColor(self.len() as i32);
4674 }
4675 }
4676}
4677
4678impl<const N: usize> Pushable for [StyleColorF; N] {
4679 unsafe fn push(&self) {
4680 unsafe {
4681 self.as_slice().push();
4682 }
4683 }
4684 unsafe fn pop(&self) {
4685 unsafe {
4686 self.as_slice().pop();
4687 }
4688 }
4689}
4690
4691#[derive(Debug, Copy, Clone)]
4692pub enum StyleValue {
4693 F32(f32),
4694 Vec2(Vector2),
4695 X(f32),
4696 Y(f32),
4697}
4698
4699pub type Style = (StyleVar, StyleValue);
4700
4701impl Pushable for Style {
4702 unsafe fn push(&self) {
4703 unsafe {
4704 match self.1 {
4705 StyleValue::F32(f) => ImGui_PushStyleVar(self.0.bits(), f),
4706 StyleValue::Vec2(v) => ImGui_PushStyleVar1(self.0.bits(), &v2_to_im(v)),
4707 StyleValue::X(x) => ImGui_PushStyleVarX(self.0.bits(), x),
4708 StyleValue::Y(y) => ImGui_PushStyleVarX(self.0.bits(), y),
4709 }
4710 }
4711 }
4712 unsafe fn pop(&self) {
4713 unsafe {
4714 ImGui_PopStyleVar(1);
4715 }
4716 }
4717}
4718
4719impl Pushable for [Style] {
4720 unsafe fn push(&self) {
4721 unsafe {
4722 for sc in self {
4723 sc.push();
4724 }
4725 }
4726 }
4727 unsafe fn pop(&self) {
4728 unsafe {
4729 ImGui_PopStyleVar(self.len() as i32);
4730 }
4731 }
4732}
4733
4734impl<const N: usize> Pushable for [Style; N] {
4735 unsafe fn push(&self) {
4736 unsafe {
4737 self.as_slice().push();
4738 }
4739 }
4740 unsafe fn pop(&self) {
4741 unsafe {
4742 self.as_slice().pop();
4743 }
4744 }
4745}
4746
4747#[derive(Debug, Copy, Clone)]
4748pub struct ItemWidth(pub f32);
4749
4750impl Pushable for ItemWidth {
4751 unsafe fn push(&self) {
4752 unsafe {
4753 ImGui_PushItemWidth(self.0);
4754 }
4755 }
4756 unsafe fn pop(&self) {
4757 unsafe {
4758 ImGui_PopItemWidth();
4759 }
4760 }
4761}
4762
4763#[derive(Debug, Copy, Clone)]
4764pub struct Indent(pub f32);
4765
4766impl Pushable for Indent {
4767 unsafe fn push(&self) {
4768 unsafe {
4769 ImGui_Indent(self.0);
4770 }
4771 }
4772 unsafe fn pop(&self) {
4773 unsafe {
4774 ImGui_Unindent(self.0);
4775 }
4776 }
4777}
4778
4779#[derive(Debug, Copy, Clone)]
4780pub struct TextWrapPos(pub f32);
4781
4782impl Pushable for TextWrapPos {
4783 unsafe fn push(&self) {
4784 unsafe {
4785 ImGui_PushTextWrapPos(self.0);
4786 }
4787 }
4788 unsafe fn pop(&self) {
4789 unsafe {
4790 ImGui_PopTextWrapPos();
4791 }
4792 }
4793}
4794
4795impl Pushable for (ItemFlags, bool) {
4796 unsafe fn push(&self) {
4797 unsafe {
4798 ImGui_PushItemFlag(self.0.bits(), self.1);
4799 }
4800 }
4801 unsafe fn pop(&self) {
4802 unsafe {
4803 ImGui_PopItemFlag();
4804 }
4805 }
4806}
4807
4808#[derive(Debug, Copy, Clone)]
4809pub struct ItemId<H: Hashable>(pub H);
4810
4811impl<H: Hashable> Pushable for ItemId<H> {
4812 unsafe fn push(&self) {
4813 unsafe {
4814 self.0.push();
4815 }
4816 }
4817 unsafe fn pop(&self) {
4818 unsafe {
4819 ImGui_PopID();
4820 }
4821 }
4822}
4823
4824transparent! {
4825 #[derive(Debug)]
4826 pub struct Viewport(ImGuiViewport);
4827}
4828
4829impl Viewport {
4830 pub fn flags(&self) -> ViewportFlags {
4831 ViewportFlags::from_bits_truncate(self.Flags)
4832 }
4833 pub fn pos(&self) -> Vector2 {
4834 im_to_v2(self.Pos)
4835 }
4836 pub fn size(&self) -> Vector2 {
4837 im_to_v2(self.Size)
4838 }
4839 pub fn work_pos(&self) -> Vector2 {
4840 im_to_v2(self.WorkPos)
4841 }
4842 pub fn work_size(&self) -> Vector2 {
4843 im_to_v2(self.WorkSize)
4844 }
4845}
4846
4847decl_builder_with_opt! { TableConfig, ImGui_BeginTable, ImGui_EndTable () (S: IntoCStr)
4848 (
4849 str_id (S::Temp) (str_id.as_ptr()),
4850 column (i32) (column),
4851 flags (TableFlags) (flags.bits()),
4852 outer_size (ImVec2) (&outer_size),
4853 inner_width (f32) (inner_width),
4854 )
4855 {
4856 decl_builder_setter!{flags: TableFlags}
4857 decl_builder_setter_vector2!{outer_size: Vector2}
4858 decl_builder_setter!{inner_width: f32}
4859 }
4860 {
4861 pub fn table_config<S: IntoCStr>(&self, str_id: LblId<S>, column: i32) -> TableConfig<S> {
4862 TableConfig {
4863 str_id: str_id.into(),
4864 column,
4865 flags: TableFlags::None,
4866 outer_size: im_vec2(0.0, 0.0),
4867 inner_width: 0.0,
4868 push: (),
4869 }
4870 }
4871 pub fn table_next_row(&self, flags: TableRowFlags, min_row_height: f32) {
4872 unsafe {
4873 ImGui_TableNextRow(flags.bits(), min_row_height);
4874 }
4875 }
4876 pub fn table_next_column(&self) -> bool {
4877 unsafe {
4878 ImGui_TableNextColumn()
4879 }
4880 }
4881 pub fn table_set_column_index(&self, column_n: i32) -> bool {
4882 unsafe {
4883 ImGui_TableSetColumnIndex(column_n)
4884 }
4885 }
4886 pub fn table_setup_column(&self, label: impl IntoCStr, flags: TableColumnFlags, init_width_or_weight: f32, user_id: ImGuiID) {
4887 unsafe {
4888 ImGui_TableSetupColumn(label.into().as_ptr(), flags.bits(), init_width_or_weight, user_id);
4889 }
4890 }
4891 pub fn table_setup_scroll_freeze(&self, cols: i32, rows: i32) {
4892 unsafe {
4893 ImGui_TableSetupScrollFreeze(cols, rows);
4894 }
4895 }
4896 pub fn table_headers_row(&self) {
4897 unsafe {
4898 ImGui_TableHeadersRow();
4899 }
4900 }
4901 pub fn table_angle_headers_row(&self) {
4902 unsafe {
4903 ImGui_TableAngledHeadersRow();
4904 }
4905 }
4906 pub fn table_get_columns_count(&self) -> i32 {
4907 unsafe {
4908 ImGui_TableGetColumnCount()
4909 }
4910 }
4911 pub fn table_get_column_index(&self) -> i32 {
4912 unsafe {
4913 ImGui_TableGetColumnIndex()
4914 }
4915 }
4916 pub fn table_get_hovered_column(&self) -> Option<i32> {
4918 unsafe {
4919 let res = ImGui_TableGetHoveredColumn();
4920 if res < 0 {
4921 None
4922 } else {
4923 Some(res)
4924 }
4925 }
4926 }
4927 pub fn table_get_row_index(&self) -> i32 {
4928 unsafe {
4929 ImGui_TableGetRowIndex()
4930 }
4931 }
4932 pub fn table_get_column_flags(&self, column_n: Option<i32>) -> TableColumnFlags {
4933 let bits = unsafe {
4934 ImGui_TableGetColumnFlags(column_n.unwrap_or(-1))
4935 };
4936 TableColumnFlags::from_bits_truncate(bits)
4937 }
4938 pub fn table_get_column_name(&self, column_n: Option<i32>) -> String {
4939 unsafe {
4940 let c_str = ImGui_TableGetColumnName(column_n.unwrap_or(-1));
4941 CStr::from_ptr(c_str).to_string_lossy().into_owned()
4942 }
4943 }
4944 pub fn table_set_column_enabled(&self, column_n: Option<i32>, enabled: bool) {
4945 unsafe {
4946 ImGui_TableSetColumnEnabled(column_n.unwrap_or(-1), enabled);
4947 };
4948 }
4949 pub fn table_set_bg_color(&self, target: TableBgTarget, color: Color, column_n: Option<i32>) {
4950 unsafe {
4951 ImGui_TableSetBgColor(target.bits(), color.as_u32(), column_n.unwrap_or(-1));
4952 };
4953 }
4954 pub fn table_with_sort_specs(&self, sort_fn: impl FnOnce(&[TableColumnSortSpec])) {
4955 self.table_with_sort_specs_always(|dirty, spec| {
4956 if dirty {
4957 sort_fn(spec);
4958 }
4959 false
4960 })
4961 }
4962 pub fn table_with_sort_specs_always(&self, sort_fn: impl FnOnce(bool, &[TableColumnSortSpec]) -> bool) {
4964 unsafe {
4965 let specs = ImGui_TableGetSortSpecs();
4966 if specs.is_null() {
4967 return;
4968 }
4969 let slice = {
4971 let len = (*specs).SpecsCount as usize;
4972 if len == 0 {
4973 &[]
4974 } else {
4975 let ptr = std::mem::transmute::<*const ImGuiTableColumnSortSpecs, *const TableColumnSortSpec>((*specs).Specs);
4976 std::slice::from_raw_parts(ptr, len)
4977 }
4978 };
4979 (*specs).SpecsDirty = sort_fn((*specs).SpecsDirty, slice);
4980 }
4981 }
4982 }
4983}
4984
4985pub struct DragDropPayloadSetter<'a> {
4987 _dummy: PhantomData<&'a ()>,
4988}
4989
4990pub enum DragDropPayloadCond {
4992 Always,
4993 Once,
4994}
4995
4996impl DragDropPayloadSetter<'_> {
4997 pub fn set(self, type_: impl IntoCStr, data: &[u8], cond: DragDropPayloadCond) -> bool {
4998 let ptr = if data.is_empty() {
5000 null()
5001 } else {
5002 data.as_ptr() as *const c_void
5003 };
5004 let len = data.len();
5005 let cond = match cond {
5006 DragDropPayloadCond::Always => Cond::Always,
5007 DragDropPayloadCond::Once => Cond::Once,
5008 };
5009 unsafe { ImGui_SetDragDropPayload(type_.into().as_ptr(), ptr, len, cond.bits()) }
5010 }
5011}
5012
5013pub struct DragDropPayloadGetter<'a> {
5015 _dummy: PhantomData<&'a ()>,
5016}
5017
5018pub struct DragDropPayload<'a> {
5022 pay: &'a ImGuiPayload,
5023}
5024
5025impl<'a> DragDropPayloadGetter<'a> {
5026 pub fn any(&self, flags: DragDropAcceptFlags) -> Option<DragDropPayload<'a>> {
5027 unsafe {
5028 let pay = ImGui_AcceptDragDropPayload(null(), flags.bits());
5029 if pay.is_null() {
5030 None
5031 } else {
5032 Some(DragDropPayload { pay: &*pay })
5033 }
5034 }
5035 }
5036 pub fn by_type(
5037 &self,
5038 type_: impl IntoCStr,
5039 flags: DragDropAcceptFlags,
5040 ) -> Option<DragDropPayload<'a>> {
5041 unsafe {
5042 let pay = ImGui_AcceptDragDropPayload(type_.into().as_ptr(), flags.bits());
5043 if pay.is_null() {
5044 None
5045 } else {
5046 Some(DragDropPayload { pay: &*pay })
5047 }
5048 }
5049 }
5050 pub fn peek(&self) -> Option<DragDropPayload<'a>> {
5051 unsafe {
5052 let pay = ImGui_GetDragDropPayload();
5053 if pay.is_null() {
5054 None
5055 } else {
5056 Some(DragDropPayload { pay: &*pay })
5057 }
5058 }
5059 }
5060}
5061
5062impl DragDropPayload<'_> {
5063 pub fn is_data_type(&self, type_: impl IntoCStr) -> bool {
5065 if self.pay.DataFrameCount == -1 {
5066 return false;
5067 }
5068 let data_type = unsafe { std::mem::transmute::<&[i8], &[u8]>(&self.pay.DataType) };
5069 let data_type = CStr::from_bytes_until_nul(data_type).unwrap();
5070 data_type == type_.into().as_ref()
5071 }
5072 pub fn type_(&self) -> Cow<'_, str> {
5073 let data_type = unsafe { std::mem::transmute::<&[i8], &[u8]>(&self.pay.DataType) };
5074 let data_type = CStr::from_bytes_until_nul(data_type).unwrap();
5075 data_type.to_string_lossy()
5076 }
5077 pub fn is_preview(&self) -> bool {
5078 self.pay.Preview
5079 }
5080 pub fn is_delivery(&self) -> bool {
5081 self.pay.Delivery
5082 }
5083 pub fn data(&self) -> &[u8] {
5084 if self.pay.Data.is_null() {
5085 &[]
5086 } else {
5087 unsafe {
5088 std::slice::from_raw_parts(self.pay.Data as *const u8, self.pay.DataSize as usize)
5089 }
5090 }
5091 }
5092}
5093
5094pub const PAYLOAD_TYPE_COLOR_3F: &CStr =
5095 unsafe { CStr::from_bytes_with_nul_unchecked(IMGUI_PAYLOAD_TYPE_COLOR_3F) };
5096pub const PAYLOAD_TYPE_COLOR_4F: &CStr =
5097 unsafe { CStr::from_bytes_with_nul_unchecked(IMGUI_PAYLOAD_TYPE_COLOR_4F) };
5098
5099#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5104pub struct KeyChord(ImGuiKey);
5105
5106impl KeyChord {
5107 pub fn new(mods: KeyMod, key: Key) -> KeyChord {
5108 KeyChord(ImGuiKey(mods.bits() | key.bits().0))
5109 }
5110 pub fn bits(&self) -> i32 {
5111 self.0.0
5112 }
5113 pub fn from_bits(bits: i32) -> Option<KeyChord> {
5114 let key = bits & !ImGuiKey::ImGuiMod_Mask_.0;
5116 let mods = bits & ImGuiKey::ImGuiMod_Mask_.0;
5117 match (Key::from_bits(ImGuiKey(key)), KeyMod::from_bits(mods)) {
5118 (Some(_), Some(_)) => Some(KeyChord(ImGuiKey(bits))),
5119 _ => None,
5120 }
5121 }
5122 pub fn key(&self) -> Key {
5123 let key = self.bits() & !ImGuiKey::ImGuiMod_Mask_.0;
5124 Key::from_bits(ImGuiKey(key)).unwrap_or(Key::None)
5125 }
5126 pub fn mods(&self) -> KeyMod {
5127 let mods = self.bits() & ImGuiKey::ImGuiMod_Mask_.0;
5128 KeyMod::from_bits_truncate(mods)
5129 }
5130}
5131
5132impl From<Key> for KeyChord {
5133 fn from(value: Key) -> Self {
5134 KeyChord::new(KeyMod::None, value)
5135 }
5136}
5137
5138impl From<(KeyMod, Key)> for KeyChord {
5139 fn from(value: (KeyMod, Key)) -> Self {
5140 KeyChord::new(value.0, value.1)
5141 }
5142}
5143
5144#[repr(transparent)]
5146pub struct TableColumnSortSpec(ImGuiTableColumnSortSpecs);
5147
5148impl std::fmt::Debug for TableColumnSortSpec {
5149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5150 f.debug_struct("TableColumnSortSpec")
5151 .field("id", &self.id())
5152 .field("index", &self.index())
5153 .field("sort_order", &self.sort_order())
5154 .field("sort_direction", &self.sort_direction())
5155 .finish()
5156 }
5157}
5158
5159impl TableColumnSortSpec {
5160 pub fn id(&self) -> ImGuiID {
5161 self.0.ColumnUserID
5162 }
5163 pub fn index(&self) -> usize {
5164 self.0.ColumnIndex as usize
5165 }
5166 pub fn sort_order(&self) -> usize {
5167 self.0.SortOrder as usize
5168 }
5169 pub fn sort_direction(&self) -> SortDirection {
5170 SortDirection::from_bits(self.0.SortDirection).unwrap_or(SortDirection::None)
5171 }
5172}