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