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