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_next_item_storage_id(&self, id: ImGuiID) {
2739 unsafe { ImGui_SetNextItemStorageID(id) }
2740 }
2741 pub fn tree_node_to_label_spacing(&self) -> f32 {
2742 unsafe { ImGui_GetTreeNodeToLabelSpacing() }
2743 }
2744 pub fn tree_node_get_open(&self, id: ImGuiID) -> bool {
2745 unsafe { ImGui_TreeNodeGetOpen(id) }
2746 }
2747 pub fn set_keyboard_focus_here(&self, offset: i32) {
2748 unsafe { ImGui_SetKeyboardFocusHere(offset) }
2749 }
2750
2751 with_begin_end! {
2752 group ImGui_BeginGroup ImGui_EndGroup ()
2754 }
2755 with_begin_end! {
2756 disabled ImGui_BeginDisabled ImGui_EndDisabled (
2758 disabled (bool) (disabled),
2759 )
2760 }
2761 with_begin_end! {
2762 clip_rect ImGui_PushClipRect ImGui_PopClipRect (
2764 clip_rect_min (Vector2) (&v2_to_im(clip_rect_min)),
2765 clip_rect_max (Vector2) (&v2_to_im(clip_rect_max)),
2766 intersect_with_current_clip_rect (bool) (intersect_with_current_clip_rect),
2767 )
2768 }
2769
2770 with_begin_end_opt! {
2771 main_menu_bar ImGui_BeginMainMenuBar ImGui_EndMainMenuBar ()
2773 }
2774 with_begin_end_opt! {
2775 menu_bar ImGui_BeginMenuBar ImGui_EndMenuBar ()
2777 }
2778 with_begin_end_opt! {
2779 tooltip ImGui_BeginTooltip ImGui_EndTooltip ()
2781 }
2782 with_begin_end_opt! {
2783 item_tooltip ImGui_BeginItemTooltip ImGui_EndTooltip ()
2785 }
2786
2787 pub fn with_push<R>(&self, push: impl Pushable, f: impl FnOnce() -> R) -> R {
2789 unsafe {
2790 let _guard = push_guard(&push);
2791 f()
2792 }
2793 }
2794 pub fn show_demo_window(&self, mut show: Option<&mut bool>) {
2795 unsafe {
2796 ImGui_ShowDemoWindow(optional_mut_bool(&mut show));
2797 }
2798 }
2799 pub fn set_next_window_pos(&self, pos: Vector2, cond: Cond, pivot: Vector2) {
2800 unsafe {
2801 ImGui_SetNextWindowPos(&v2_to_im(pos), cond.bits(), &v2_to_im(pivot));
2802 }
2803 }
2804 pub fn set_next_window_size(&self, size: Vector2, cond: Cond) {
2805 unsafe {
2806 ImGui_SetNextWindowSize(&v2_to_im(size), cond.bits());
2807 }
2808 }
2809 pub fn set_next_window_content_size(&self, size: Vector2) {
2810 unsafe {
2811 ImGui_SetNextWindowContentSize(&v2_to_im(size));
2812 }
2813 }
2814
2815 pub fn set_next_window_collapsed(&self, collapsed: bool, cond: Cond) {
2816 unsafe {
2817 ImGui_SetNextWindowCollapsed(collapsed, cond.bits());
2818 }
2819 }
2820
2821 pub fn set_next_window_focus(&self) {
2822 unsafe {
2823 ImGui_SetNextWindowFocus();
2824 }
2825 }
2826
2827 pub fn set_next_window_scroll(&self, scroll: Vector2) {
2828 unsafe {
2829 ImGui_SetNextWindowScroll(&v2_to_im(scroll));
2830 }
2831 }
2832
2833 pub fn set_next_window_bg_alpha(&self, alpha: f32) {
2834 unsafe {
2835 ImGui_SetNextWindowBgAlpha(alpha);
2836 }
2837 }
2838 pub fn window_draw_list(&self) -> WindowDrawList<'_, A> {
2839 unsafe {
2840 let ptr = ImGui_GetWindowDrawList();
2841 WindowDrawList { ui: self, ptr }
2842 }
2843 }
2844 pub fn window_dpi_scale(&self) -> f32 {
2845 unsafe { ImGui_GetWindowDpiScale() }
2846 }
2847 pub fn foreground_draw_list(&self) -> WindowDrawList<'_, A> {
2848 unsafe {
2849 let ptr = ImGui_GetForegroundDrawList(std::ptr::null_mut());
2850 WindowDrawList { ui: self, ptr }
2851 }
2852 }
2853 pub fn background_draw_list(&self) -> WindowDrawList<'_, A> {
2854 unsafe {
2855 let ptr = ImGui_GetBackgroundDrawList(std::ptr::null_mut());
2856 WindowDrawList { ui: self, ptr }
2857 }
2858 }
2859 pub fn text(&self, text: &str) {
2860 unsafe {
2861 let (start, end) = text_ptrs(text);
2862 ImGui_TextUnformatted(start, end);
2863 }
2864 }
2865 pub fn text_colored(&self, color: Color, text: impl IntoCStr) {
2866 let text = text.into();
2867 unsafe { ImGui_TextColored(&color.into(), c"%s".as_ptr(), text.as_ptr()) }
2868 }
2869 pub fn text_disabled(&self, text: impl IntoCStr) {
2870 let text = text.into();
2871 unsafe { ImGui_TextDisabled(c"%s".as_ptr(), text.as_ptr()) }
2872 }
2873 pub fn text_wrapped(&self, text: impl IntoCStr) {
2874 let text = text.into();
2875 unsafe { ImGui_TextWrapped(c"%s".as_ptr(), text.as_ptr()) }
2876 }
2877 pub fn text_link(&self, label: LblId<impl IntoCStr>) -> bool {
2878 let label = label.into();
2879 unsafe { ImGui_TextLink(label.as_ptr()) }
2880 }
2881 pub fn text_link_open_url(&self, label: LblId<impl IntoCStr>, url: impl IntoCStr) -> bool {
2882 let label = label.into();
2883 let url = url.into();
2884 unsafe { ImGui_TextLinkOpenURL(label.as_ptr(), url.as_ptr()) }
2885 }
2886 pub fn label_text(&self, label: impl IntoCStr, text: impl IntoCStr) {
2887 let label = label.into();
2888 let text = text.into();
2889 unsafe { ImGui_LabelText(label.as_ptr(), c"%s".as_ptr(), text.as_ptr()) }
2890 }
2891 pub fn bullet_text(&self, text: impl IntoCStr) {
2892 let text = text.into();
2893 unsafe { ImGui_BulletText(c"%s".as_ptr(), text.as_ptr()) }
2894 }
2895 pub fn bullet(&self) {
2896 unsafe {
2897 ImGui_Bullet();
2898 }
2899 }
2900 pub fn separator_text(&self, text: impl IntoCStr) {
2901 let text = text.into();
2902 unsafe {
2903 ImGui_SeparatorText(text.as_ptr());
2904 }
2905 }
2906 pub fn separator(&self) {
2907 unsafe {
2908 ImGui_Separator();
2909 }
2910 }
2911
2912 pub fn set_item_default_focus(&self) {
2913 unsafe {
2914 ImGui_SetItemDefaultFocus();
2915 }
2916 }
2917 pub fn is_item_hovered(&self) -> bool {
2918 self.is_item_hovered_ex(HoveredFlags::None)
2919 }
2920 pub fn is_item_hovered_ex(&self, flags: HoveredFlags) -> bool {
2921 unsafe { ImGui_IsItemHovered(flags.bits()) }
2922 }
2923 pub fn is_item_active(&self) -> bool {
2924 unsafe { ImGui_IsItemActive() }
2925 }
2926 pub fn is_item_focused(&self) -> bool {
2927 unsafe { ImGui_IsItemFocused() }
2928 }
2929 pub fn is_item_clicked(&self, flags: MouseButton) -> bool {
2930 unsafe { ImGui_IsItemClicked(flags.bits()) }
2931 }
2932 pub fn is_item_visible(&self) -> bool {
2933 unsafe { ImGui_IsItemVisible() }
2934 }
2935 pub fn is_item_edited(&self) -> bool {
2936 unsafe { ImGui_IsItemEdited() }
2937 }
2938 pub fn is_item_activated(&self) -> bool {
2939 unsafe { ImGui_IsItemActivated() }
2940 }
2941 pub fn is_item_deactivated(&self) -> bool {
2942 unsafe { ImGui_IsItemDeactivated() }
2943 }
2944 pub fn is_item_deactivated_after_edit(&self) -> bool {
2945 unsafe { ImGui_IsItemDeactivatedAfterEdit() }
2946 }
2947 pub fn is_item_toggled_open(&self) -> bool {
2948 unsafe { ImGui_IsItemToggledOpen() }
2949 }
2950 pub fn is_any_item_hovered(&self) -> bool {
2951 unsafe { ImGui_IsAnyItemHovered() }
2952 }
2953 pub fn is_any_item_active(&self) -> bool {
2954 unsafe { ImGui_IsAnyItemActive() }
2955 }
2956 pub fn is_any_item_focused(&self) -> bool {
2957 unsafe { ImGui_IsAnyItemFocused() }
2958 }
2959 pub fn is_window_collapsed(&self) -> bool {
2960 unsafe { ImGui_IsWindowCollapsed() }
2961 }
2962 pub fn is_window_focused(&self, flags: FocusedFlags) -> bool {
2963 unsafe { ImGui_IsWindowFocused(flags.bits()) }
2964 }
2965 pub fn is_window_hovered(&self, flags: FocusedFlags) -> bool {
2966 unsafe { ImGui_IsWindowHovered(flags.bits()) }
2967 }
2968 pub fn get_item_id(&self) -> ImGuiID {
2969 unsafe { ImGui_GetItemID() }
2970 }
2971 pub fn get_id(&self, id: impl Hashable) -> ImGuiID {
2972 unsafe { id.get_id() }
2973 }
2974 pub fn get_item_rect_min(&self) -> Vector2 {
2975 unsafe { im_to_v2(ImGui_GetItemRectMin()) }
2976 }
2977 pub fn get_item_rect_max(&self) -> Vector2 {
2978 unsafe { im_to_v2(ImGui_GetItemRectMax()) }
2979 }
2980 pub fn get_item_rect_size(&self) -> Vector2 {
2981 unsafe { im_to_v2(ImGui_GetItemRectSize()) }
2982 }
2983 pub fn get_item_flags(&self) -> ItemFlags {
2984 unsafe { ItemFlags::from_bits_truncate(ImGui_GetItemFlags()) }
2985 }
2986 pub fn get_content_region_avail(&self) -> Vector2 {
2988 unsafe { im_to_v2(ImGui_GetContentRegionAvail()) }
2989 }
2990 pub fn get_window_pos(&self) -> Vector2 {
2991 unsafe { im_to_v2(ImGui_GetWindowPos()) }
2992 }
2993 pub fn get_window_width(&self) -> f32 {
2994 unsafe { ImGui_GetWindowWidth() }
2995 }
2996 pub fn get_window_height(&self) -> f32 {
2997 unsafe { ImGui_GetWindowHeight() }
2998 }
2999 pub fn get_scroll_x(&self) -> f32 {
3000 unsafe { ImGui_GetScrollX() }
3001 }
3002 pub fn get_scroll_y(&self) -> f32 {
3003 unsafe { ImGui_GetScrollY() }
3004 }
3005 pub fn set_scroll_x(&self, scroll_x: f32) {
3006 unsafe {
3007 ImGui_SetScrollX(scroll_x);
3008 }
3009 }
3010 pub fn set_scroll_y(&self, scroll_y: f32) {
3011 unsafe {
3012 ImGui_SetScrollY(scroll_y);
3013 }
3014 }
3015 pub fn get_scroll_max_x(&self) -> f32 {
3016 unsafe { ImGui_GetScrollMaxX() }
3017 }
3018 pub fn get_scroll_max_y(&self) -> f32 {
3019 unsafe { ImGui_GetScrollMaxY() }
3020 }
3021 pub fn set_scroll_here_x(&self, center_x_ratio: f32) {
3022 unsafe {
3023 ImGui_SetScrollHereX(center_x_ratio);
3024 }
3025 }
3026 pub fn set_scroll_here_y(&self, center_y_ratio: f32) {
3027 unsafe {
3028 ImGui_SetScrollHereY(center_y_ratio);
3029 }
3030 }
3031 pub fn set_scroll_from_pos_x(&self, local_x: f32, center_x_ratio: f32) {
3032 unsafe {
3033 ImGui_SetScrollFromPosX(local_x, center_x_ratio);
3034 }
3035 }
3036 pub fn set_scroll_from_pos_y(&self, local_y: f32, center_y_ratio: f32) {
3037 unsafe {
3038 ImGui_SetScrollFromPosY(local_y, center_y_ratio);
3039 }
3040 }
3041 pub fn set_window_pos(&self, pos: Vector2, cond: Cond) {
3042 unsafe {
3043 ImGui_SetWindowPos(&v2_to_im(pos), cond.bits());
3044 }
3045 }
3046 pub fn set_window_size(&self, size: Vector2, cond: Cond) {
3047 unsafe {
3048 ImGui_SetWindowSize(&v2_to_im(size), cond.bits());
3049 }
3050 }
3051 pub fn set_window_collapsed(&self, collapsed: bool, cond: Cond) {
3052 unsafe {
3053 ImGui_SetWindowCollapsed(collapsed, cond.bits());
3054 }
3055 }
3056 pub fn set_window_focus(&self) {
3057 unsafe {
3058 ImGui_SetWindowFocus();
3059 }
3060 }
3061 pub fn same_line(&self) {
3063 self.same_line_ex(SameLine::Default);
3064 }
3065 pub fn same_line_ex(&self, same_line: SameLine) {
3067 let (offset_from_start_x, spacing) = match same_line {
3068 SameLine::Default => (0.0, -1.0),
3069 SameLine::OffsetFromStart(offs) => {
3072 if offs != 0.0 {
3073 (offs, 0.0)
3074 } else {
3075 (-f32::MIN_POSITIVE, f32::MIN_POSITIVE)
3076 }
3077 }
3078 SameLine::Spacing(spc) => (0.0, spc.max(0.0)),
3080 };
3081 unsafe {
3082 ImGui_SameLine(offset_from_start_x, spacing);
3083 }
3084 }
3085 pub fn new_line(&self) {
3086 unsafe {
3087 ImGui_NewLine();
3088 }
3089 }
3090 pub fn spacing(&self) {
3091 unsafe {
3092 ImGui_Spacing();
3093 }
3094 }
3095 pub fn dummy(&self, size: Vector2) {
3096 unsafe {
3097 ImGui_Dummy(&v2_to_im(size));
3098 }
3099 }
3100 pub fn indent(&self, indent_w: f32) {
3101 unsafe {
3102 ImGui_Indent(indent_w);
3103 }
3104 }
3105 pub fn unindent(&self, indent_w: f32) {
3106 unsafe {
3107 ImGui_Unindent(indent_w);
3108 }
3109 }
3110 pub fn get_cursor_pos(&self) -> Vector2 {
3112 unsafe { im_to_v2(ImGui_GetCursorPos()) }
3113 }
3114 pub fn get_cursor_pos_x(&self) -> f32 {
3116 unsafe { ImGui_GetCursorPosX() }
3117 }
3118 pub fn get_cursor_pos_y(&self) -> f32 {
3120 unsafe { ImGui_GetCursorPosY() }
3121 }
3122 pub fn set_cursor_pos(&self, local_pos: Vector2) {
3124 unsafe {
3125 ImGui_SetCursorPos(&v2_to_im(local_pos));
3126 }
3127 }
3128 pub fn set_cursor_pos_x(&self, local_x: f32) {
3130 unsafe {
3131 ImGui_SetCursorPosX(local_x);
3132 }
3133 }
3134 pub fn set_cursor_pos_y(&self, local_y: f32) {
3136 unsafe {
3137 ImGui_SetCursorPosY(local_y);
3138 }
3139 }
3140 pub fn get_cursor_start_pos(&self) -> Vector2 {
3142 unsafe { im_to_v2(ImGui_GetCursorStartPos()) }
3143 }
3144 pub fn get_cursor_screen_pos(&self) -> Vector2 {
3146 unsafe { im_to_v2(ImGui_GetCursorScreenPos()) }
3147 }
3148 pub fn set_cursor_screen_pos(&self, pos: Vector2) {
3150 unsafe {
3151 ImGui_SetCursorScreenPos(&v2_to_im(pos));
3152 }
3153 }
3154 pub fn align_text_to_frame_padding(&self) {
3155 unsafe {
3156 ImGui_AlignTextToFramePadding();
3157 }
3158 }
3159 pub fn get_text_line_height(&self) -> f32 {
3160 unsafe { ImGui_GetTextLineHeight() }
3161 }
3162 pub fn get_text_line_height_with_spacing(&self) -> f32 {
3163 unsafe { ImGui_GetTextLineHeightWithSpacing() }
3164 }
3165 pub fn get_frame_height(&self) -> f32 {
3166 unsafe { ImGui_GetFrameHeight() }
3167 }
3168 pub fn get_frame_height_with_spacing(&self) -> f32 {
3169 unsafe { ImGui_GetFrameHeightWithSpacing() }
3170 }
3171 pub fn calc_item_width(&self) -> f32 {
3172 unsafe { ImGui_CalcItemWidth() }
3173 }
3174 pub fn calc_text_size(&self, text: &str) -> Vector2 {
3175 self.calc_text_size_ex(text, false, -1.0)
3176 }
3177 pub fn calc_text_size_ex(
3178 &self,
3179 text: &str,
3180 hide_text_after_double_hash: bool,
3181 wrap_width: f32,
3182 ) -> Vector2 {
3183 unsafe {
3184 let (start, end) = text_ptrs(text);
3185 im_to_v2(ImGui_CalcTextSize(
3186 start,
3187 end,
3188 hide_text_after_double_hash,
3189 wrap_width,
3190 ))
3191 }
3192 }
3193 pub fn set_color_edit_options(&self, flags: ColorEditFlags) {
3194 unsafe {
3195 ImGui_SetColorEditOptions(flags.bits());
3196 }
3197 }
3198 pub fn key_mods(&self) -> KeyMod {
3199 let mods = self.io().KeyMods;
3200 KeyMod::from_bits_truncate(mods & ImGuiKey::ImGuiMod_Mask_.0)
3201 }
3202 pub fn is_key_down(&self, key: Key) -> bool {
3203 unsafe { ImGui_IsKeyDown(key.bits()) }
3204 }
3205 pub fn is_key_pressed(&self, key: Key) -> bool {
3206 unsafe {
3207 ImGui_IsKeyPressed(key.bits(), true)
3208 }
3209 }
3210 pub fn is_key_pressed_no_repeat(&self, key: Key) -> bool {
3211 unsafe {
3212 ImGui_IsKeyPressed(key.bits(), false)
3213 }
3214 }
3215 pub fn is_key_released(&self, key: Key) -> bool {
3216 unsafe { ImGui_IsKeyReleased(key.bits()) }
3217 }
3218 pub fn get_key_pressed_amount(&self, key: Key, repeat_delay: f32, rate: f32) -> i32 {
3219 unsafe { ImGui_GetKeyPressedAmount(key.bits(), repeat_delay, rate) }
3220 }
3221 pub fn get_font_tex_uv_white_pixel(&self) -> Vector2 {
3222 unsafe { im_to_v2(ImGui_GetFontTexUvWhitePixel()) }
3223 }
3224 pub fn get_font_size(&self) -> f32 {
3227 unsafe { ImGui_GetFontSize() }
3228 }
3229 pub fn is_mouse_down(&self, button: MouseButton) -> bool {
3230 unsafe { ImGui_IsMouseDown(button.bits()) }
3231 }
3232 pub fn is_mouse_clicked(&self, button: MouseButton) -> bool {
3233 unsafe {
3234 ImGui_IsMouseClicked(button.bits(), false)
3235 }
3236 }
3237 pub fn is_mouse_clicked_repeat(&self, button: MouseButton) -> bool {
3238 unsafe {
3239 ImGui_IsMouseClicked(button.bits(), true)
3240 }
3241 }
3242 pub fn is_mouse_released(&self, button: MouseButton) -> bool {
3243 unsafe { ImGui_IsMouseReleased(button.bits()) }
3244 }
3245 pub fn is_mouse_double_clicked(&self, button: MouseButton) -> bool {
3246 unsafe { ImGui_IsMouseDoubleClicked(button.bits()) }
3247 }
3248 pub fn get_mouse_clicked_count(&self, button: MouseButton) -> i32 {
3249 unsafe { ImGui_GetMouseClickedCount(button.bits()) }
3250 }
3251 pub fn is_rect_visible_size(&self, size: Vector2) -> bool {
3252 unsafe { ImGui_IsRectVisible(&v2_to_im(size)) }
3253 }
3254 pub fn is_rect_visible(&self, rect_min: Vector2, rect_max: Vector2) -> bool {
3255 unsafe { ImGui_IsRectVisible1(&v2_to_im(rect_min), &v2_to_im(rect_max)) }
3256 }
3257 pub fn is_any_mouse_down(&self) -> bool {
3269 unsafe { ImGui_IsAnyMouseDown() }
3270 }
3271 pub fn get_mouse_pos(&self) -> Vector2 {
3272 unsafe { im_to_v2(ImGui_GetMousePos()) }
3273 }
3274 pub fn get_mouse_pos_on_opening_current_popup(&self) -> Vector2 {
3275 unsafe { im_to_v2(ImGui_GetMousePosOnOpeningCurrentPopup()) }
3276 }
3277 pub fn is_mouse_dragging(&self, button: MouseButton) -> bool {
3278 unsafe {
3279 ImGui_IsMouseDragging(button.bits(), -1.0)
3280 }
3281 }
3282 pub fn get_mouse_drag_delta(&self, button: MouseButton) -> Vector2 {
3283 unsafe {
3284 im_to_v2(ImGui_GetMouseDragDelta(
3285 button.bits(),
3286 -1.0,
3287 ))
3288 }
3289 }
3290 pub fn reset_mouse_drag_delta(&self, button: MouseButton) {
3291 unsafe {
3292 ImGui_ResetMouseDragDelta(button.bits());
3293 }
3294 }
3295 pub fn get_mouse_cursor(&self) -> MouseCursor {
3296 unsafe { MouseCursor::from_bits(ImGui_GetMouseCursor()).unwrap_or(MouseCursor::None) }
3297 }
3298 pub fn set_mouse_cursor(&self, cursor_type: MouseCursor) {
3299 unsafe {
3300 ImGui_SetMouseCursor(cursor_type.bits());
3301 }
3302 }
3303 pub fn get_time(&self) -> f64 {
3304 unsafe { ImGui_GetTime() }
3305 }
3306 pub fn get_frame_count(&self) -> i32 {
3307 unsafe { ImGui_GetFrameCount() }
3308 }
3309 pub fn is_popup_open(&self, str_id: Option<Id<impl IntoCStr>>) -> bool {
3310 self.is_popup_open_ex(str_id, PopupFlags::None)
3311 }
3312 pub fn is_popup_open_ex(&self, str_id: Option<Id<impl IntoCStr>>, flags: PopupFlags) -> bool {
3313 let temp;
3314 let str_id = match str_id {
3315 Some(s) => {
3316 temp = IntoCStr::into(s.0);
3317 temp.as_ptr()
3318 }
3319 None => null(),
3320 };
3321 unsafe { ImGui_IsPopupOpen(str_id, flags.bits()) }
3322 }
3323 pub fn is_below_blocking_modal(&self) -> bool {
3325 unsafe {
3327 let modal = ImGui_FindBlockingModal(self.CurrentWindow);
3328 !modal.is_null()
3329 }
3330 }
3331 pub fn is_blocking_modal(&self) -> bool {
3333 unsafe {
3335 let modal = ImGui_FindBlockingModal(std::ptr::null_mut());
3336 !modal.is_null()
3337 }
3338 }
3339 pub fn open_popup(&self, str_id: Id<impl IntoCStr>) {
3340 self.open_popup_ex(str_id, PopupFlags::None)
3341 }
3342 pub fn open_popup_ex(&self, str_id: Id<impl IntoCStr>, flags: PopupFlags) {
3343 let str_id = str_id.into();
3344 unsafe {
3345 ImGui_OpenPopup(str_id.as_ptr(), flags.bits());
3346 }
3347 }
3348 pub fn close_current_popup(&self) {
3349 unsafe {
3350 ImGui_CloseCurrentPopup();
3351 }
3352 }
3353 pub fn is_window_appearing(&self) -> bool {
3354 unsafe { ImGui_IsWindowAppearing() }
3355 }
3356 pub fn with_always_drag_drop_source<R>(
3357 &self,
3358 flags: DragDropSourceFlags,
3359 f: impl FnOnce(Option<DragDropPayloadSetter<'_>>) -> R,
3360 ) -> R {
3361 if !unsafe { ImGui_BeginDragDropSource(flags.bits()) } {
3362 return f(None);
3363 }
3364 let payload = DragDropPayloadSetter {
3365 _dummy: PhantomData,
3366 };
3367 let r = f(Some(payload));
3368 unsafe { ImGui_EndDragDropSource() }
3369 r
3370 }
3371 pub fn with_drag_drop_source<R>(
3372 &self,
3373 flags: DragDropSourceFlags,
3374 f: impl FnOnce(DragDropPayloadSetter<'_>) -> R,
3375 ) -> Option<R> {
3376 self.with_always_drag_drop_source(flags, move |r| r.map(f))
3377 }
3378 pub fn with_always_drag_drop_target<R>(
3379 &self,
3380 f: impl FnOnce(Option<DragDropPayloadGetter<'_>>) -> R,
3381 ) -> R {
3382 if !unsafe { ImGui_BeginDragDropTarget() } {
3383 return f(None);
3384 }
3385 let payload = DragDropPayloadGetter {
3386 _dummy: PhantomData,
3387 };
3388 let r = f(Some(payload));
3389 unsafe { ImGui_EndDragDropTarget() }
3390 r
3391 }
3392 pub fn with_drag_drop_target<R>(
3393 &self,
3394 f: impl FnOnce(DragDropPayloadGetter<'_>) -> R,
3395 ) -> Option<R> {
3396 self.with_always_drag_drop_target(move |r| r.map(f))
3397 }
3398
3399 #[must_use]
3400 pub fn list_clipper(&self, items_count: usize) -> ListClipper {
3401 ListClipper {
3402 items_count,
3403 items_height: -1.0,
3404 included_ranges: Vec::new(),
3405 }
3406 }
3407
3408 pub fn shortcut(&self, key_chord: impl Into<KeyChord>) -> bool {
3409 unsafe { ImGui_Shortcut(key_chord.into().bits(), 0) }
3410 }
3411 pub fn shortcut_ex(&self, key_chord: impl Into<KeyChord>, flags: InputFlags) -> bool {
3412 unsafe { ImGui_Shortcut(key_chord.into().bits(), flags.bits()) }
3413 }
3414 pub fn set_next_item_shortcut(&self, key_chord: impl Into<KeyChord>) {
3415 unsafe {
3416 ImGui_SetNextItemShortcut(key_chord.into().bits(), 0);
3417 }
3418 }
3419 pub fn set_next_item_shortcut_ex(&self, key_chord: impl Into<KeyChord>, flags: InputFlags) {
3420 unsafe {
3421 ImGui_SetNextItemShortcut(key_chord.into().bits(), flags.bits());
3422 }
3423 }
3424 pub fn is_keychord_pressed(&self, key_chord: impl Into<KeyChord>) -> bool {
3425 unsafe { ImGui_IsKeyChordPressed(key_chord.into().bits()) }
3426 }
3427
3428 pub fn get_font(&self, font_id: FontId) -> &Font {
3430 unsafe {
3431 let font = self.io().font_atlas().font_ptr(font_id);
3432 Font::cast(&*font)
3433 }
3434 }
3435
3436 pub fn get_font_baked(
3441 &self,
3442 font_id: FontId,
3443 font_size: f32,
3444 font_density: Option<f32>,
3445 ) -> &FontBaked {
3446 unsafe {
3447 let font = self.io().font_atlas().font_ptr(font_id);
3448 let baked = (*font).GetFontBaked(font_size, font_density.unwrap_or(-1.0));
3449 FontBaked::cast(&*baked)
3450 }
3451 }
3452
3453 pub fn get_atlas_texture_ref(&self) -> TextureRef<'_> {
3454 let tex_data = self.io().font_atlas().TexData;
3455 let tex_data = unsafe { &*tex_data };
3456 TextureRef::Ref(tex_data)
3457 }
3458
3459 pub fn get_custom_rect(&self, index: CustomRectIndex) -> Option<TextureRect<'_>> {
3460 let atlas = self.io().font_atlas();
3461 let rect = unsafe {
3462 let mut rect = MaybeUninit::zeroed();
3463 let ok = atlas.GetCustomRect(index.0, rect.as_mut_ptr());
3464 if !ok {
3465 return None;
3466 }
3467 rect.assume_init()
3468 };
3469
3470 let tex_ref = self.get_atlas_texture_ref();
3471 Some(TextureRect { rect, tex_ref })
3472 }
3473
3474 pub fn dock_space(
3475 &self,
3476 id: ImGuiID,
3477 size: Vector2,
3478 flags: DockNodeFlags,
3479 window_class: Option<&WindowClass>,
3480 ) -> ImGuiID {
3481 unsafe {
3482 ImGui_DockSpace(
3483 id,
3484 &v2_to_im(size),
3485 flags.bits(),
3486 window_class
3487 .as_ref()
3488 .map(|e| &raw const e.0)
3489 .unwrap_or_default(),
3490 )
3491 }
3492 }
3493 pub fn dock_space_over_viewport(
3494 &self,
3495 dockspace_id: ImGuiID,
3496 viewport: &Viewport,
3497 flags: DockNodeFlags,
3498 window_class: Option<&WindowClass>,
3499 ) -> ImGuiID {
3500 unsafe {
3501 ImGui_DockSpaceOverViewport(
3502 dockspace_id,
3503 viewport.get(),
3504 flags.bits(),
3505 window_class
3506 .as_ref()
3507 .map(|e| &raw const e.0)
3508 .unwrap_or_default(),
3509 )
3510 }
3511 }
3512 pub fn set_next_window_dock_id(&self, dock_id: ImGuiID, cond: Cond) {
3513 unsafe {
3514 ImGui_SetNextWindowDockID(dock_id, cond.bits());
3515 }
3516 }
3517 pub fn set_next_window_class(&self, window_class: &WindowClass) {
3518 unsafe {
3519 ImGui_SetNextWindowClass(&window_class.0);
3520 }
3521 }
3522 pub fn get_window_dock_id(&self) -> ImGuiID {
3523 unsafe { ImGui_GetWindowDockID() }
3524 }
3525 pub fn is_window_docked(&self) -> bool {
3526 unsafe { ImGui_IsWindowDocked() }
3527 }
3528
3529 pub fn dock_builder(
3538 &self,
3539 id: Option<ImGuiID>,
3540 flags: DockNodeFlags,
3541 fn_build: impl FnOnce(ImGuiID, &mut DockBuilder),
3542 ) {
3543 struct DockBuilderFinishGuard(ImGuiID);
3544 impl Drop for DockBuilderFinishGuard {
3545 fn drop(&mut self) {
3546 unsafe {
3547 ImGui_DockBuilderFinish(self.0);
3548 }
3549 }
3550 }
3551
3552 unsafe {
3553 let id = ImGui_DockBuilderAddNode(id.unwrap_or(0), flags.bits());
3554 let _guard = DockBuilderFinishGuard(id);
3555 let mut db = DockBuilder { _dummy: () };
3556 fn_build(id, &mut db);
3557 }
3558 }
3559
3560 pub fn get_window_viewport(&self) -> &Viewport {
3561 unsafe { Viewport::cast(&*ImGui_GetWindowViewport()) }
3562 }
3563 pub fn set_next_window_viewport(&self, id: ImGuiID) {
3564 unsafe { ImGui_SetNextWindowViewport(id) }
3565 }
3566 pub fn viewport_foreground_draw_list(&self, viewport: &Viewport) -> WindowDrawList<'_, A> {
3567 unsafe {
3568 let ptr = ImGui_GetForegroundDrawList((&raw const *viewport.get()).cast_mut());
3569 WindowDrawList { ui: self, ptr }
3570 }
3571 }
3572 pub fn viewport_background_draw_list(&self, viewport: &Viewport) -> WindowDrawList<'_, A> {
3573 unsafe {
3574 let ptr = ImGui_GetBackgroundDrawList((&raw const *viewport.get()).cast_mut());
3575 WindowDrawList { ui: self, ptr }
3576 }
3577 }
3578}
3579
3580#[derive(Debug, Copy, Clone)]
3581pub struct TextureRect<'ui> {
3582 pub rect: ImFontAtlasRect,
3583 pub tex_ref: TextureRef<'ui>,
3584}
3585
3586pub struct ListClipper {
3587 items_count: usize,
3588 items_height: f32,
3589 included_ranges: Vec<std::ops::Range<usize>>,
3590}
3591
3592impl ListClipper {
3593 decl_builder_setter! {items_height: f32}
3594
3595 pub fn add_included_range(&mut self, range: std::ops::Range<usize>) {
3596 self.included_ranges.push(range);
3597 }
3598
3599 pub fn with(self, mut f: impl FnMut(usize)) {
3600 unsafe {
3601 let mut clip = ImGuiListClipper::new();
3602 clip.Begin(self.items_count as i32, self.items_height);
3603 for r in self.included_ranges {
3604 clip.IncludeItemsByIndex(r.start as i32, r.end as i32);
3605 }
3606 while clip.Step() {
3607 for i in clip.DisplayStart..clip.DisplayEnd {
3608 f(i as usize);
3609 }
3610 }
3611 }
3612 }
3613}
3614
3615transparent! {
3616 pub struct Font(ImFont);
3618}
3619
3620transparent! {
3621 pub struct FontGlyph(ImFontGlyph);
3622}
3623
3624impl FontGlyph {
3625 pub fn p0(&self) -> Vector2 {
3626 Vector2::new(self.0.X0, self.0.Y0)
3627 }
3628 pub fn p1(&self) -> Vector2 {
3629 Vector2::new(self.0.X1, self.0.Y1)
3630 }
3631 pub fn uv0(&self) -> Vector2 {
3632 Vector2::new(self.0.U0, self.0.V0)
3633 }
3634 pub fn uv1(&self) -> Vector2 {
3635 Vector2::new(self.0.U1, self.0.V1)
3636 }
3637 pub fn advance_x(&self) -> f32 {
3638 self.0.AdvanceX
3639 }
3640 pub fn visible(&self) -> bool {
3641 self.0.Visible() != 0
3642 }
3643 pub fn colored(&self) -> bool {
3644 self.0.Colored() != 0
3645 }
3646 pub fn codepoint(&self) -> char {
3647 char::try_from(self.0.Codepoint()).unwrap()
3648 }
3649}
3650
3651impl std::fmt::Debug for FontGlyph {
3652 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
3653 fmt.debug_struct("FontGlyph")
3654 .field("p0", &self.p0())
3655 .field("p1", &self.p1())
3656 .field("uv0", &self.uv0())
3657 .field("uv1", &self.uv1())
3658 .field("advance_x", &self.advance_x())
3659 .field("visible", &self.visible())
3660 .field("colored", &self.colored())
3661 .field("codepoint", &self.codepoint())
3662 .finish()
3663 }
3664}
3665
3666transparent! {
3667 #[derive(Debug)]
3668 pub struct FontBaked(ImFontBaked);
3669}
3670
3671impl FontBaked {
3672 pub fn find_glyph(&self, c: char) -> &FontGlyph {
3674 unsafe {
3675 FontGlyph::cast(&*ImFontBaked_FindGlyph(
3676 (&raw const self.0).cast_mut(),
3677 ImWchar::from(c),
3678 ))
3679 }
3680 }
3681
3682 pub fn find_glyph_no_fallback(&self, c: char) -> Option<&FontGlyph> {
3684 unsafe {
3685 let p =
3686 ImFontBaked_FindGlyphNoFallback((&raw const self.0).cast_mut(), ImWchar::from(c));
3687 p.as_ref().map(FontGlyph::cast)
3688 }
3689 }
3690
3691 pub unsafe fn inner(&mut self) -> &mut ImFontBaked {
3692 &mut self.0
3693 }
3694
3695 pub fn set_ascent(&mut self, ascent: f32) {
3697 self.0.Ascent = ascent;
3698 }
3699 pub fn set_descent(&mut self, descent: f32) {
3700 self.0.Descent = descent;
3701 }
3702}
3703
3704#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3708pub struct FontId(u32);
3709
3710#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3715pub struct CustomRectIndex(i32);
3716
3717impl Default for CustomRectIndex {
3718 fn default() -> Self {
3719 CustomRectIndex(-1)
3721 }
3722}
3723
3724transparent! {
3725 #[derive(Debug)]
3726 pub struct FontAtlas(ImFontAtlas);
3727}
3728
3729type PixelImage<'a> = image::ImageBuffer<image::Rgba<u8>, &'a mut [u8]>;
3730type SubPixelImage<'a, 'b> = image::SubImage<&'a mut PixelImage<'b>>;
3731
3732impl FontAtlas {
3733 pub unsafe fn texture_ref(&self) -> ImTextureRef {
3734 self.TexRef
3735 }
3736 pub unsafe fn inner(&mut self) -> &mut ImFontAtlas {
3737 &mut self.0
3738 }
3739
3740 pub fn current_texture_unique_id(&self) -> TextureUniqueId {
3741 unsafe {
3742 let id = (*self.TexRef._TexData).UniqueID;
3743 TextureUniqueId(id)
3744 }
3745 }
3746
3747 fn texture_unique_id(&self, uid: TextureUniqueId) -> Option<&ImTextureData> {
3748 unsafe {
3749 self.TexList
3750 .iter()
3751 .find(|x| (***x).UniqueID == uid.0)
3752 .map(|p| &**p)
3753 }
3754 }
3755
3756 unsafe fn font_ptr(&self, font: FontId) -> *mut ImFont {
3757 unsafe {
3758 *self
3760 .Fonts
3761 .iter()
3762 .find(|f| f.as_ref().map(|f| f.FontId) == Some(font.0))
3763 .unwrap_or(&self.Fonts[0])
3764 }
3765 }
3766
3767 pub fn check_texture_unique_id(&self, uid: TextureUniqueId) -> bool {
3768 self.texture_unique_id(uid).is_some_and(|x| {
3769 !matches!(
3770 x.Status,
3771 ImTextureStatus::ImTextureStatus_WantDestroy
3772 | ImTextureStatus::ImTextureStatus_Destroyed
3773 )
3774 })
3775 }
3776
3777 pub fn get_texture_by_unique_id(&self, uid: TextureUniqueId) -> Option<TextureId> {
3778 let p = self.texture_unique_id(uid)?;
3779 if p.Status == ImTextureStatus::ImTextureStatus_Destroyed || p.TexID == 0 {
3781 None
3782 } else {
3783 unsafe { Some(TextureId::from_id(p.TexID)) }
3784 }
3785 }
3786
3787 pub fn add_font(&mut self, font: FontInfo) -> FontId {
3792 self.add_font_priv(font, false)
3793 }
3794
3795 pub fn remove_font(&mut self, font_id: FontId) {
3796 unsafe {
3797 let f = self.font_ptr(font_id);
3798 self.0.RemoveFont(f);
3803 }
3804 }
3805
3806 pub fn add_font_collection(&mut self, fonts: impl IntoIterator<Item = FontInfo>) -> FontId {
3811 let mut fonts = fonts.into_iter();
3812 let first = fonts.next().expect("empty font collection");
3813 let id = self.add_font_priv(first, false);
3814 for font in fonts {
3815 self.add_font_priv(font, true);
3816 }
3817 id
3818 }
3819 fn add_font_priv(&mut self, font: FontInfo, merge: bool) -> FontId {
3820 unsafe {
3821 let mut fc = ImFontConfig::new();
3822 fc.FontDataOwnedByAtlas = false;
3824 fc.MergeMode = merge;
3825 if !font.name.is_empty() {
3826 let cname = font.name.as_bytes();
3827 let name_len = cname.len().min(fc.Name.len() - 1);
3828 fc.Name[..name_len]
3829 .copy_from_slice(std::mem::transmute::<&[u8], &[c_char]>(&cname[..name_len]));
3830 fc.Name[name_len] = 0;
3831 }
3832 fc.Flags = font.flags.bits();
3833 fc.SizePixels = font.size;
3834
3835 let font_ptr = match font.ttf {
3836 TtfData::Bytes(bytes) => {
3837 self.0.AddFontFromMemoryTTF(
3838 bytes.as_ptr() as *mut _,
3839 bytes.len() as i32,
3840 0.0,
3841 &fc,
3842 std::ptr::null(),
3843 )
3844 }
3845 TtfData::DefaultFont(DefaultFontSelector::Auto) => self.0.AddFontDefault(&fc),
3846 TtfData::DefaultFont(DefaultFontSelector::Bitmap) => {
3847 self.0.AddFontDefaultBitmap(&fc)
3848 }
3849 TtfData::DefaultFont(DefaultFontSelector::Vector) => {
3850 self.0.AddFontDefaultVector(&fc)
3851 }
3852 TtfData::CustomLoader(glyph_loader) => {
3853 let ptr = Box::into_raw(Box::new(glyph_loader));
3854 fc.FontLoader = &fontloader::FONT_LOADER.0;
3855 fc.FontData = ptr as *mut c_void;
3856 fc.FontDataOwnedByAtlas = true;
3857 self.0.AddFont(&fc)
3858 }
3859 };
3860 let Some(font) = font_ptr.as_ref() else {
3861 log::error!("Error loading font!");
3862 return FontId::default();
3863 };
3864 FontId(font.FontId)
3865 }
3866 }
3867
3868 pub fn add_custom_rect(
3872 &mut self,
3873 size: impl Into<mint::Vector2<u32>>,
3874 draw: impl FnOnce(&mut SubPixelImage<'_, '_>),
3875 ) -> CustomRectIndex {
3876 let size = size.into();
3877 unsafe {
3878 let mut rect = MaybeUninit::zeroed();
3879 let idx = self.0.AddCustomRect(
3880 i32::try_from(size.x).unwrap(),
3881 i32::try_from(size.y).unwrap(),
3882 rect.as_mut_ptr(),
3883 );
3884 let idx = CustomRectIndex(idx);
3885 let rect = rect.assume_init();
3886 let tex_data = &(*self.TexData);
3887
3888 let mut pixel_image = PixelImage::from_raw(
3889 tex_data.Width as u32,
3890 tex_data.Height as u32,
3891 std::slice::from_raw_parts_mut(
3892 tex_data.Pixels,
3893 tex_data.Width as usize
3894 * tex_data.Height as usize
3895 * tex_data.BytesPerPixel as usize,
3896 ),
3897 )
3898 .unwrap();
3899
3900 let mut sub_image =
3901 pixel_image.sub_image(rect.x as u32, rect.y as u32, rect.w as u32, rect.h as u32);
3902 draw(&mut sub_image);
3903
3904 idx
3905 }
3906 }
3907
3908 pub fn remove_custom_rect(&mut self, idx: CustomRectIndex) {
3909 if idx.0 < 0 {
3910 return;
3911 }
3912 unsafe {
3913 self.0.RemoveCustomRect(idx.0);
3914 }
3915 }
3916}
3917
3918transparent_mut! {
3919 #[derive(Debug)]
3920 pub struct Io(ImGuiIO);
3921}
3922
3923transparent! {
3924 #[derive(Debug)]
3928 pub struct IoMut(ImGuiIO);
3929}
3930
3931impl Io {
3932 pub fn font_atlas(&self) -> &FontAtlas {
3933 unsafe { FontAtlas::cast(&*self.Fonts) }
3934 }
3935
3936 pub fn want_capture_mouse(&self) -> bool {
3937 self.WantCaptureMouse
3938 }
3939 pub fn want_capture_keyboard(&self) -> bool {
3940 self.WantCaptureKeyboard
3941 }
3942 pub fn want_text_input(&self) -> bool {
3943 self.WantTextInput
3944 }
3945 pub fn display_size(&self) -> Vector2 {
3946 im_to_v2(self.DisplaySize)
3947 }
3948 pub fn display_scale(&self) -> f32 {
3949 self.DisplayFramebufferScale.x
3950 }
3951
3952 pub fn add_config_flags(&mut self, flags: ConfigFlags) {
3954 self.ConfigFlags |= flags.bits();
3955 }
3956 pub fn remove_config_flags(&mut self, flags: ConfigFlags) {
3957 self.ConfigFlags &= !flags.bits();
3958 }
3959 pub fn add_backend_flags(&mut self, flags: BackendFlags) {
3960 self.BackendFlags |= flags.bits();
3961 }
3962 pub fn remove_backend_flags(&mut self, flags: BackendFlags) {
3963 self.BackendFlags &= !flags.bits();
3964 }
3965 pub fn delta_time(&mut self) -> Duration {
3966 Duration::from_secs_f32(self.DeltaTime)
3967 }
3968 pub fn set_delta_time(&mut self, d: Duration) {
3969 self.DeltaTime = d.as_secs_f32()
3970 }
3971}
3972
3973impl IoMut {
3974 pub unsafe fn inner(&mut self) -> &mut Io {
3975 Io::cast_mut(&mut self.0)
3976 }
3977 pub fn set_allow_user_scaling(&mut self, val: bool) {
3978 self.0.FontAllowUserScaling = val;
3979 }
3980 pub fn nav_enable_keyboard(&mut self, enable: bool) {
3981 unsafe {
3982 if enable {
3983 self.inner()
3984 .add_config_flags(ConfigFlags::NavEnableKeyboard);
3985 } else {
3986 self.inner()
3987 .remove_config_flags(ConfigFlags::NavEnableKeyboard);
3988 }
3989 }
3990 }
3991 pub fn nav_enable_gamepad(&mut self, enable: bool) {
3992 unsafe {
3993 if enable {
3994 self.inner().add_config_flags(ConfigFlags::NavEnableGamepad);
3995 } else {
3996 self.inner()
3997 .remove_config_flags(ConfigFlags::NavEnableGamepad);
3998 }
3999 }
4000 }
4001 pub fn enable_docking(&mut self, enable: bool) {
4003 unsafe {
4004 if enable {
4005 self.inner().add_config_flags(ConfigFlags::DockingEnable);
4006 } else {
4007 self.inner().remove_config_flags(ConfigFlags::DockingEnable);
4008 }
4009 }
4010 }
4011 pub fn enable_viewports(&mut self, enable: bool) {
4015 unsafe {
4016 if enable {
4017 self.inner().add_config_flags(ConfigFlags::ViewportsEnable);
4018 } else {
4019 self.inner()
4020 .remove_config_flags(ConfigFlags::ViewportsEnable);
4021 }
4022 }
4023 }
4024 pub fn font_atlas_mut(&mut self) -> &mut FontAtlas {
4025 unsafe { FontAtlas::cast_mut(&mut *self.Fonts) }
4026 }
4027}
4028
4029transparent_mut! {
4030 #[derive(Debug)]
4031 pub struct PlatformIo(ImGuiPlatformIO);
4032}
4033
4034impl PlatformIo {
4035 pub unsafe fn textures_mut(&mut self) -> impl Iterator<Item = &mut ImTextureData> {
4036 self.Textures.iter_mut().map(|t| unsafe { &mut **t })
4037 }
4038}
4039
4040#[derive(Debug)]
4041pub struct SizeCallbackData<'a> {
4042 ptr: &'a mut ImGuiSizeCallbackData,
4043}
4044
4045impl SizeCallbackData<'_> {
4046 pub fn pos(&self) -> Vector2 {
4047 im_to_v2(self.ptr.Pos)
4048 }
4049 pub fn current_size(&self) -> Vector2 {
4050 im_to_v2(self.ptr.CurrentSize)
4051 }
4052 pub fn desired_size(&self) -> Vector2 {
4053 im_to_v2(self.ptr.DesiredSize)
4054 }
4055 pub fn set_desired_size(&mut self, sz: Vector2) {
4056 self.ptr.DesiredSize = v2_to_im(sz);
4057 }
4058}
4059
4060unsafe extern "C" fn call_size_callback<A>(ptr: *mut ImGuiSizeCallbackData) {
4061 unsafe {
4062 let ptr = &mut *ptr;
4063 let id = ptr.UserData as usize;
4064 let data = SizeCallbackData { ptr };
4065 Ui::<A>::run_callback(id, data);
4066 }
4067}
4068
4069pub struct WindowDrawList<'ui, A> {
4070 ui: &'ui Ui<A>,
4071 ptr: *mut ImDrawList,
4072}
4073
4074impl<A> WindowDrawList<'_, A> {
4075 pub fn add_line(&self, p1: Vector2, p2: Vector2, color: Color, thickness: f32) {
4076 unsafe {
4077 ImDrawList_AddLine(
4078 self.ptr,
4079 &v2_to_im(p1),
4080 &v2_to_im(p2),
4081 color.as_u32(),
4082 thickness,
4083 );
4084 }
4085 }
4086 pub fn add_rect(
4087 &self,
4088 p_min: Vector2,
4089 p_max: Vector2,
4090 color: Color,
4091 rounding: f32,
4092 flags: DrawFlags,
4093 thickness: f32,
4094 ) {
4095 unsafe {
4096 ImDrawList_AddRect(
4097 self.ptr,
4098 &v2_to_im(p_min),
4099 &v2_to_im(p_max),
4100 color.as_u32(),
4101 rounding,
4102 flags.bits(),
4103 thickness,
4104 );
4105 }
4106 }
4107 pub fn add_rect_filled(
4108 &self,
4109 p_min: Vector2,
4110 p_max: Vector2,
4111 color: Color,
4112 rounding: f32,
4113 flags: DrawFlags,
4114 ) {
4115 unsafe {
4116 ImDrawList_AddRectFilled(
4117 self.ptr,
4118 &v2_to_im(p_min),
4119 &v2_to_im(p_max),
4120 color.as_u32(),
4121 rounding,
4122 flags.bits(),
4123 );
4124 }
4125 }
4126 pub fn add_rect_filled_multicolor(
4127 &self,
4128 p_min: Vector2,
4129 p_max: Vector2,
4130 col_upr_left: Color,
4131 col_upr_right: Color,
4132 col_bot_right: Color,
4133 col_bot_left: Color,
4134 ) {
4135 unsafe {
4136 ImDrawList_AddRectFilledMultiColor(
4137 self.ptr,
4138 &v2_to_im(p_min),
4139 &v2_to_im(p_max),
4140 col_upr_left.as_u32(),
4141 col_upr_right.as_u32(),
4142 col_bot_right.as_u32(),
4143 col_bot_left.as_u32(),
4144 );
4145 }
4146 }
4147 pub fn add_quad(
4148 &self,
4149 p1: Vector2,
4150 p2: Vector2,
4151 p3: Vector2,
4152 p4: Vector2,
4153 color: Color,
4154 thickness: f32,
4155 ) {
4156 unsafe {
4157 ImDrawList_AddQuad(
4158 self.ptr,
4159 &v2_to_im(p1),
4160 &v2_to_im(p2),
4161 &v2_to_im(p3),
4162 &v2_to_im(p4),
4163 color.as_u32(),
4164 thickness,
4165 );
4166 }
4167 }
4168 pub fn add_quad_filled(
4169 &self,
4170 p1: Vector2,
4171 p2: Vector2,
4172 p3: Vector2,
4173 p4: Vector2,
4174 color: Color,
4175 ) {
4176 unsafe {
4177 ImDrawList_AddQuadFilled(
4178 self.ptr,
4179 &v2_to_im(p1),
4180 &v2_to_im(p2),
4181 &v2_to_im(p3),
4182 &v2_to_im(p4),
4183 color.as_u32(),
4184 );
4185 }
4186 }
4187 pub fn add_triangle(
4188 &self,
4189 p1: Vector2,
4190 p2: Vector2,
4191 p3: Vector2,
4192 color: Color,
4193 thickness: f32,
4194 ) {
4195 unsafe {
4196 ImDrawList_AddTriangle(
4197 self.ptr,
4198 &v2_to_im(p1),
4199 &v2_to_im(p2),
4200 &v2_to_im(p3),
4201 color.as_u32(),
4202 thickness,
4203 );
4204 }
4205 }
4206 pub fn add_triangle_filled(&self, p1: Vector2, p2: Vector2, p3: Vector2, color: Color) {
4207 unsafe {
4208 ImDrawList_AddTriangleFilled(
4209 self.ptr,
4210 &v2_to_im(p1),
4211 &v2_to_im(p2),
4212 &v2_to_im(p3),
4213 color.as_u32(),
4214 );
4215 }
4216 }
4217 pub fn add_circle(
4218 &self,
4219 center: Vector2,
4220 radius: f32,
4221 color: Color,
4222 num_segments: i32,
4223 thickness: f32,
4224 ) {
4225 unsafe {
4226 ImDrawList_AddCircle(
4227 self.ptr,
4228 &v2_to_im(center),
4229 radius,
4230 color.as_u32(),
4231 num_segments,
4232 thickness,
4233 );
4234 }
4235 }
4236 pub fn add_circle_filled(&self, center: Vector2, radius: f32, color: Color, num_segments: i32) {
4237 unsafe {
4238 ImDrawList_AddCircleFilled(
4239 self.ptr,
4240 &v2_to_im(center),
4241 radius,
4242 color.as_u32(),
4243 num_segments,
4244 );
4245 }
4246 }
4247 pub fn add_ngon(
4248 &self,
4249 center: Vector2,
4250 radius: f32,
4251 color: Color,
4252 num_segments: i32,
4253 thickness: f32,
4254 ) {
4255 unsafe {
4256 ImDrawList_AddNgon(
4257 self.ptr,
4258 &v2_to_im(center),
4259 radius,
4260 color.as_u32(),
4261 num_segments,
4262 thickness,
4263 );
4264 }
4265 }
4266 pub fn add_ngon_filled(&self, center: Vector2, radius: f32, color: Color, num_segments: i32) {
4267 unsafe {
4268 ImDrawList_AddNgonFilled(
4269 self.ptr,
4270 &v2_to_im(center),
4271 radius,
4272 color.as_u32(),
4273 num_segments,
4274 );
4275 }
4276 }
4277 pub fn add_ellipse(
4278 &self,
4279 center: Vector2,
4280 radius: Vector2,
4281 color: Color,
4282 rot: f32,
4283 num_segments: i32,
4284 thickness: f32,
4285 ) {
4286 unsafe {
4287 ImDrawList_AddEllipse(
4288 self.ptr,
4289 &v2_to_im(center),
4290 &v2_to_im(radius),
4291 color.as_u32(),
4292 rot,
4293 num_segments,
4294 thickness,
4295 );
4296 }
4297 }
4298 pub fn add_ellipse_filled(
4299 &self,
4300 center: Vector2,
4301 radius: Vector2,
4302 color: Color,
4303 rot: f32,
4304 num_segments: i32,
4305 ) {
4306 unsafe {
4307 ImDrawList_AddEllipseFilled(
4308 self.ptr,
4309 &v2_to_im(center),
4310 &v2_to_im(radius),
4311 color.as_u32(),
4312 rot,
4313 num_segments,
4314 );
4315 }
4316 }
4317 pub fn add_text(&self, pos: Vector2, color: Color, text: &str) {
4318 unsafe {
4319 let (start, end) = text_ptrs(text);
4320 ImDrawList_AddText(self.ptr, &v2_to_im(pos), color.as_u32(), start, end);
4321 }
4322 }
4323 pub fn add_text_ex(
4324 &self,
4325 font: FontId,
4326 font_size: f32,
4327 pos: Vector2,
4328 color: Color,
4329 text: &str,
4330 wrap_width: f32,
4331 cpu_fine_clip_rect: Option<ImVec4>,
4332 ) {
4333 unsafe {
4334 let (start, end) = text_ptrs(text);
4335 ImDrawList_AddText1(
4336 self.ptr,
4337 self.ui.io().font_atlas().font_ptr(font),
4338 font_size,
4339 &v2_to_im(pos),
4340 color.as_u32(),
4341 start,
4342 end,
4343 wrap_width,
4344 cpu_fine_clip_rect
4345 .as_ref()
4346 .map(|x| x as *const _)
4347 .unwrap_or(null()),
4348 );
4349 }
4350 }
4351 pub fn add_polyline(&self, points: &[ImVec2], color: Color, flags: DrawFlags, thickness: f32) {
4352 unsafe {
4353 ImDrawList_AddPolyline(
4354 self.ptr,
4355 points.as_ptr(),
4356 points.len() as i32,
4357 color.as_u32(),
4358 flags.bits(),
4359 thickness,
4360 );
4361 }
4362 }
4363 pub fn add_convex_poly_filled(&self, points: &[ImVec2], color: Color) {
4364 unsafe {
4365 ImDrawList_AddConvexPolyFilled(
4366 self.ptr,
4367 points.as_ptr(),
4368 points.len() as i32,
4369 color.as_u32(),
4370 );
4371 }
4372 }
4373 pub fn add_concave_poly_filled(&self, points: &[ImVec2], color: Color) {
4374 unsafe {
4375 ImDrawList_AddConcavePolyFilled(
4376 self.ptr,
4377 points.as_ptr(),
4378 points.len() as i32,
4379 color.as_u32(),
4380 );
4381 }
4382 }
4383 pub fn add_bezier_cubic(
4384 &self,
4385 p1: Vector2,
4386 p2: Vector2,
4387 p3: Vector2,
4388 p4: Vector2,
4389 color: Color,
4390 thickness: f32,
4391 num_segments: i32,
4392 ) {
4393 unsafe {
4394 ImDrawList_AddBezierCubic(
4395 self.ptr,
4396 &v2_to_im(p1),
4397 &v2_to_im(p2),
4398 &v2_to_im(p3),
4399 &v2_to_im(p4),
4400 color.as_u32(),
4401 thickness,
4402 num_segments,
4403 );
4404 }
4405 }
4406 pub fn add_bezier_quadratic(
4407 &self,
4408 p1: Vector2,
4409 p2: Vector2,
4410 p3: Vector2,
4411 color: Color,
4412 thickness: f32,
4413 num_segments: i32,
4414 ) {
4415 unsafe {
4416 ImDrawList_AddBezierQuadratic(
4417 self.ptr,
4418 &v2_to_im(p1),
4419 &v2_to_im(p2),
4420 &v2_to_im(p3),
4421 color.as_u32(),
4422 thickness,
4423 num_segments,
4424 );
4425 }
4426 }
4427 pub fn add_image(
4428 &self,
4429 texture_ref: TextureRef,
4430 p_min: Vector2,
4431 p_max: Vector2,
4432 uv_min: Vector2,
4433 uv_max: Vector2,
4434 color: Color,
4435 ) {
4436 unsafe {
4437 ImDrawList_AddImage(
4438 self.ptr,
4439 texture_ref.tex_ref(),
4440 &v2_to_im(p_min),
4441 &v2_to_im(p_max),
4442 &v2_to_im(uv_min),
4443 &v2_to_im(uv_max),
4444 color.as_u32(),
4445 );
4446 }
4447 }
4448 pub fn add_image_quad(
4449 &self,
4450 texture_ref: TextureRef,
4451 p1: Vector2,
4452 p2: Vector2,
4453 p3: Vector2,
4454 p4: Vector2,
4455 uv1: Vector2,
4456 uv2: Vector2,
4457 uv3: Vector2,
4458 uv4: Vector2,
4459 color: Color,
4460 ) {
4461 unsafe {
4462 ImDrawList_AddImageQuad(
4463 self.ptr,
4464 texture_ref.tex_ref(),
4465 &v2_to_im(p1),
4466 &v2_to_im(p2),
4467 &v2_to_im(p3),
4468 &v2_to_im(p4),
4469 &v2_to_im(uv1),
4470 &v2_to_im(uv2),
4471 &v2_to_im(uv3),
4472 &v2_to_im(uv4),
4473 color.as_u32(),
4474 );
4475 }
4476 }
4477 pub fn add_image_rounded(
4478 &self,
4479 texture_ref: TextureRef,
4480 p_min: Vector2,
4481 p_max: Vector2,
4482 uv_min: Vector2,
4483 uv_max: Vector2,
4484 color: Color,
4485 rounding: f32,
4486 flags: DrawFlags,
4487 ) {
4488 unsafe {
4489 ImDrawList_AddImageRounded(
4490 self.ptr,
4491 texture_ref.tex_ref(),
4492 &v2_to_im(p_min),
4493 &v2_to_im(p_max),
4494 &v2_to_im(uv_min),
4495 &v2_to_im(uv_max),
4496 color.as_u32(),
4497 rounding,
4498 flags.bits(),
4499 );
4500 }
4501 }
4502
4503 pub fn add_callback(&self, cb: impl FnOnce(&mut A) + 'static) {
4504 let mut cb = Some(cb);
4508 unsafe {
4509 let id = self.ui.push_callback(move |a, _: ()| {
4510 if let Some(cb) = cb.take() {
4511 cb(&mut *a);
4512 }
4513 });
4514 ImDrawList_AddCallback(
4515 self.ptr,
4516 Some(call_drawlist_callback::<A>),
4517 id as *mut c_void,
4518 0,
4519 );
4520 }
4521 }
4522 pub fn add_draw_cmd(&self) {
4523 unsafe {
4524 ImDrawList_AddDrawCmd(self.ptr);
4525 }
4526 }
4527}
4528
4529unsafe extern "C" fn call_drawlist_callback<A>(
4530 _parent_list: *const ImDrawList,
4531 cmd: *const ImDrawCmd,
4532) {
4533 unsafe {
4534 let id = (*cmd).UserCallbackData as usize;
4535 Ui::<A>::run_callback(id, ());
4536 }
4537}
4538
4539pub trait Hashable {
4541 unsafe fn get_id(&self) -> ImGuiID;
4543 unsafe fn push(&self);
4544}
4545
4546impl Hashable for &str {
4547 unsafe fn get_id(&self) -> ImGuiID {
4548 unsafe {
4549 let (start, end) = text_ptrs(self);
4550 ImGui_GetID1(start, end)
4551 }
4552 }
4553 unsafe fn push(&self) {
4554 unsafe {
4555 let (start, end) = text_ptrs(self);
4556 ImGui_PushID1(start, end);
4557 }
4558 }
4559}
4560
4561impl Hashable for usize {
4562 unsafe fn get_id(&self) -> ImGuiID {
4563 unsafe { ImGui_GetID2(*self as *const c_void) }
4564 }
4565 unsafe fn push(&self) {
4566 unsafe {
4567 ImGui_PushID2(*self as *const c_void);
4568 }
4569 }
4570}
4571
4572pub trait Pushable {
4579 unsafe fn push(&self);
4580 unsafe fn pop(&self);
4581}
4582
4583struct PushableGuard<'a, P: Pushable + ?Sized>(&'a P);
4584
4585impl<P: Pushable + ?Sized> Drop for PushableGuard<'_, P> {
4586 fn drop(&mut self) {
4587 unsafe {
4588 self.0.pop();
4589 }
4590 }
4591}
4592
4593#[allow(clippy::needless_lifetimes)]
4594unsafe fn push_guard<'a, P: Pushable>(p: &'a P) -> PushableGuard<'a, P> {
4595 unsafe {
4596 p.push();
4597 PushableGuard(p)
4598 }
4599}
4600
4601impl Pushable for () {
4603 unsafe fn push(&self) {}
4604 unsafe fn pop(&self) {}
4605}
4606
4607impl<A: Pushable, B: Pushable> Pushable for Either<A, B> {
4608 unsafe fn push(&self) {
4609 unsafe {
4610 match self {
4611 Either::Left(a) => A::push(a),
4612 Either::Right(b) => B::push(b),
4613 }
4614 }
4615 }
4616 unsafe fn pop(&self) {
4617 unsafe {
4618 match self {
4619 Either::Left(a) => A::pop(a),
4620 Either::Right(b) => B::pop(b),
4621 }
4622 }
4623 }
4624}
4625
4626impl<A: Pushable> Pushable for (A,) {
4627 unsafe fn push(&self) {
4628 unsafe {
4629 self.0.push();
4630 }
4631 }
4632 unsafe fn pop(&self) {
4633 unsafe {
4634 self.0.pop();
4635 }
4636 }
4637}
4638
4639impl<P: Pushable + ?Sized> Pushable for &P {
4640 unsafe fn push(&self) {
4641 unsafe {
4642 P::push(self);
4643 }
4644 }
4645 unsafe fn pop(&self) {
4646 unsafe {
4647 P::pop(self);
4648 }
4649 }
4650}
4651
4652impl<A: Pushable, B: Pushable> Pushable for (A, B) {
4653 unsafe fn push(&self) {
4654 unsafe {
4655 self.0.push();
4656 self.1.push();
4657 }
4658 }
4659 unsafe fn pop(&self) {
4660 unsafe {
4661 self.1.pop();
4662 self.0.pop();
4663 }
4664 }
4665}
4666
4667impl<A: Pushable, B: Pushable, C: Pushable> Pushable for (A, B, C) {
4668 unsafe fn push(&self) {
4669 unsafe {
4670 self.0.push();
4671 self.1.push();
4672 self.2.push();
4673 }
4674 }
4675 unsafe fn pop(&self) {
4676 unsafe {
4677 self.2.pop();
4678 self.1.pop();
4679 self.0.pop();
4680 }
4681 }
4682}
4683
4684impl<A: Pushable, B: Pushable, C: Pushable, D: Pushable> Pushable for (A, B, C, D) {
4685 unsafe fn push(&self) {
4686 unsafe {
4687 self.0.push();
4688 self.1.push();
4689 self.2.push();
4690 self.3.push();
4691 }
4692 }
4693 unsafe fn pop(&self) {
4694 unsafe {
4695 self.3.pop();
4696 self.2.pop();
4697 self.1.pop();
4698 self.0.pop();
4699 }
4700 }
4701}
4702
4703impl Pushable for &[&dyn Pushable] {
4704 unsafe fn push(&self) {
4705 unsafe {
4706 for st in *self {
4707 st.push();
4708 }
4709 }
4710 }
4711 unsafe fn pop(&self) {
4712 unsafe {
4713 for st in self.iter().rev() {
4714 st.pop();
4715 }
4716 }
4717 }
4718}
4719
4720impl<T: Pushable> Pushable for Option<T> {
4722 unsafe fn push(&self) {
4723 unsafe {
4724 if let Some(s) = self {
4725 s.push();
4726 }
4727 }
4728 }
4729 unsafe fn pop(&self) {
4730 unsafe {
4731 if let Some(s) = self {
4732 s.pop();
4733 }
4734 }
4735 }
4736}
4737
4738impl Pushable for FontId {
4740 unsafe fn push(&self) {
4741 unsafe {
4742 let font = current_font_ptr(*self);
4743 ImGui_PushFont(font, 0.0);
4744 }
4745 }
4746 unsafe fn pop(&self) {
4747 unsafe {
4748 ImGui_PopFont();
4749 }
4750 }
4751}
4752
4753pub struct FontSize(pub f32);
4754
4755impl Pushable for FontSize {
4756 unsafe fn push(&self) {
4757 unsafe {
4758 ImGui_PushFont(std::ptr::null_mut(), self.0);
4760 }
4761 }
4762 unsafe fn pop(&self) {
4763 unsafe {
4764 ImGui_PopFont();
4765 }
4766 }
4767}
4768
4769pub struct FontAndSize(pub FontId, pub f32);
4770
4771impl Pushable for FontAndSize {
4772 unsafe fn push(&self) {
4773 unsafe {
4774 ImGui_PushFont(current_font_ptr(self.0), self.1);
4775 }
4776 }
4777 unsafe fn pop(&self) {
4778 unsafe {
4779 ImGui_PopFont();
4780 }
4781 }
4782}
4783
4784pub type StyleColor = (ColorId, Color);
4785
4786#[derive(Copy, Clone, Debug)]
4787pub enum TextureRef<'a> {
4788 Id(TextureId),
4789 Ref(&'a ImTextureData),
4790}
4791
4792impl TextureRef<'_> {
4793 pub unsafe fn tex_ref(&self) -> ImTextureRef {
4794 match self {
4795 TextureRef::Id(TextureId(id)) => ImTextureRef {
4796 _TexData: null_mut(),
4797 _TexID: *id,
4798 },
4799 TextureRef::Ref(tex_data) => ImTextureRef {
4800 _TexData: (&raw const **tex_data).cast_mut(),
4801 _TexID: 0,
4802 },
4803 }
4804 }
4805
4806 pub unsafe fn tex_id(&self) -> TextureId {
4807 unsafe {
4808 match self {
4809 TextureRef::Id(tex_id) => *tex_id,
4810 TextureRef::Ref(tex_data) => {
4811 let id = tex_data.TexID;
4812 TextureId::from_id(id)
4813 }
4814 }
4815 }
4816 }
4817}
4818
4819#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4820pub struct TextureId(ImTextureID);
4821
4822impl TextureId {
4823 pub fn id(&self) -> ImTextureID {
4824 self.0
4825 }
4826 pub unsafe fn from_id(id: ImTextureID) -> Self {
4827 Self(id)
4828 }
4829}
4830
4831#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4832pub struct TextureUniqueId(i32);
4833
4834impl Pushable for StyleColor {
4835 unsafe fn push(&self) {
4836 unsafe {
4837 ImGui_PushStyleColor1(self.0.bits(), &self.1.into());
4838 }
4839 }
4840 unsafe fn pop(&self) {
4841 unsafe {
4842 ImGui_PopStyleColor(1);
4843 }
4844 }
4845}
4846
4847impl Pushable for [StyleColor] {
4848 unsafe fn push(&self) {
4849 unsafe {
4850 for sc in self {
4851 sc.push();
4852 }
4853 }
4854 }
4855 unsafe fn pop(&self) {
4856 unsafe {
4857 ImGui_PopStyleColor(self.len() as i32);
4858 }
4859 }
4860}
4861
4862impl<const N: usize> Pushable for [StyleColor; N] {
4863 unsafe fn push(&self) {
4864 unsafe {
4865 self.as_slice().push();
4866 }
4867 }
4868 unsafe fn pop(&self) {
4869 unsafe {
4870 self.as_slice().pop();
4871 }
4872 }
4873}
4874
4875pub type StyleColorF = (ColorId, ImVec4);
4876
4877impl Pushable for StyleColorF {
4878 unsafe fn push(&self) {
4879 unsafe {
4880 ImGui_PushStyleColor1(self.0.bits(), &self.1);
4881 }
4882 }
4883 unsafe fn pop(&self) {
4884 unsafe {
4885 ImGui_PopStyleColor(1);
4886 }
4887 }
4888}
4889
4890impl Pushable for [StyleColorF] {
4891 unsafe fn push(&self) {
4892 unsafe {
4893 for sc in self {
4894 sc.push();
4895 }
4896 }
4897 }
4898 unsafe fn pop(&self) {
4899 unsafe {
4900 ImGui_PopStyleColor(self.len() as i32);
4901 }
4902 }
4903}
4904
4905impl<const N: usize> Pushable for [StyleColorF; N] {
4906 unsafe fn push(&self) {
4907 unsafe {
4908 self.as_slice().push();
4909 }
4910 }
4911 unsafe fn pop(&self) {
4912 unsafe {
4913 self.as_slice().pop();
4914 }
4915 }
4916}
4917
4918#[derive(Debug, Copy, Clone)]
4919pub enum StyleValue {
4920 F32(f32),
4921 Vec2(Vector2),
4922 X(f32),
4923 Y(f32),
4924}
4925
4926pub type Style = (StyleVar, StyleValue);
4927
4928impl Pushable for Style {
4929 unsafe fn push(&self) {
4930 unsafe {
4931 match self.1 {
4932 StyleValue::F32(f) => ImGui_PushStyleVar(self.0.bits(), f),
4933 StyleValue::Vec2(v) => ImGui_PushStyleVar1(self.0.bits(), &v2_to_im(v)),
4934 StyleValue::X(x) => ImGui_PushStyleVarX(self.0.bits(), x),
4935 StyleValue::Y(y) => ImGui_PushStyleVarX(self.0.bits(), y),
4936 }
4937 }
4938 }
4939 unsafe fn pop(&self) {
4940 unsafe {
4941 ImGui_PopStyleVar(1);
4942 }
4943 }
4944}
4945
4946impl Pushable for [Style] {
4947 unsafe fn push(&self) {
4948 unsafe {
4949 for sc in self {
4950 sc.push();
4951 }
4952 }
4953 }
4954 unsafe fn pop(&self) {
4955 unsafe {
4956 ImGui_PopStyleVar(self.len() as i32);
4957 }
4958 }
4959}
4960
4961impl<const N: usize> Pushable for [Style; N] {
4962 unsafe fn push(&self) {
4963 unsafe {
4964 self.as_slice().push();
4965 }
4966 }
4967 unsafe fn pop(&self) {
4968 unsafe {
4969 self.as_slice().pop();
4970 }
4971 }
4972}
4973
4974#[derive(Debug, Copy, Clone)]
4975pub struct ItemWidth(pub f32);
4976
4977impl Pushable for ItemWidth {
4978 unsafe fn push(&self) {
4979 unsafe {
4980 ImGui_PushItemWidth(self.0);
4981 }
4982 }
4983 unsafe fn pop(&self) {
4984 unsafe {
4985 ImGui_PopItemWidth();
4986 }
4987 }
4988}
4989
4990#[derive(Debug, Copy, Clone)]
4991pub struct Indent(pub f32);
4992
4993impl Pushable for Indent {
4994 unsafe fn push(&self) {
4995 unsafe {
4996 ImGui_Indent(self.0);
4997 }
4998 }
4999 unsafe fn pop(&self) {
5000 unsafe {
5001 ImGui_Unindent(self.0);
5002 }
5003 }
5004}
5005
5006#[derive(Debug, Copy, Clone)]
5007pub struct TextWrapPos(pub f32);
5008
5009impl Pushable for TextWrapPos {
5010 unsafe fn push(&self) {
5011 unsafe {
5012 ImGui_PushTextWrapPos(self.0);
5013 }
5014 }
5015 unsafe fn pop(&self) {
5016 unsafe {
5017 ImGui_PopTextWrapPos();
5018 }
5019 }
5020}
5021
5022impl Pushable for (ItemFlags, bool) {
5023 unsafe fn push(&self) {
5024 unsafe {
5025 ImGui_PushItemFlag(self.0.bits(), self.1);
5026 }
5027 }
5028 unsafe fn pop(&self) {
5029 unsafe {
5030 ImGui_PopItemFlag();
5031 }
5032 }
5033}
5034
5035#[derive(Debug, Copy, Clone)]
5036pub struct ItemId<H: Hashable>(pub H);
5037
5038impl<H: Hashable> Pushable for ItemId<H> {
5039 unsafe fn push(&self) {
5040 unsafe {
5041 self.0.push();
5042 }
5043 }
5044 unsafe fn pop(&self) {
5045 unsafe {
5046 ImGui_PopID();
5047 }
5048 }
5049}
5050
5051transparent! {
5052 #[derive(Debug)]
5053 pub struct Viewport(ImGuiViewport);
5054}
5055
5056impl Viewport {
5057 pub fn id(&self) -> ImGuiID {
5058 self.ID
5059 }
5060 pub fn flags(&self) -> ViewportFlags {
5061 ViewportFlags::from_bits_truncate(self.Flags)
5062 }
5063 pub fn pos(&self) -> Vector2 {
5064 im_to_v2(self.Pos)
5065 }
5066 pub fn size(&self) -> Vector2 {
5067 im_to_v2(self.Size)
5068 }
5069 pub fn work_pos(&self) -> Vector2 {
5070 im_to_v2(self.WorkPos)
5071 }
5072 pub fn work_size(&self) -> Vector2 {
5073 im_to_v2(self.WorkSize)
5074 }
5075 pub fn center(&self) -> Vector2 {
5076 self.pos() + self.size() / 2.0
5077 }
5078 pub fn work_center(&self) -> Vector2 {
5079 self.work_pos() + self.work_size() / 2.0
5080 }
5081}
5082
5083decl_builder_with_opt! { TableConfig, ImGui_BeginTable, ImGui_EndTable () (S: IntoCStr)
5084 (
5085 str_id (S::Temp) (str_id.as_ptr()),
5086 column (i32) (column),
5087 flags (TableFlags) (flags.bits()),
5088 outer_size (ImVec2) (&outer_size),
5089 inner_width (f32) (inner_width),
5090 )
5091 {
5092 decl_builder_setter!{flags: TableFlags}
5093 decl_builder_setter_vector2!{outer_size: Vector2}
5094 decl_builder_setter!{inner_width: f32}
5095 }
5096 {
5097 pub fn table_config<S: IntoCStr>(&self, str_id: LblId<S>, column: i32) -> TableConfig<S> {
5098 TableConfig {
5099 str_id: str_id.into(),
5100 column,
5101 flags: TableFlags::None,
5102 outer_size: im_vec2(0.0, 0.0),
5103 inner_width: 0.0,
5104 push: (),
5105 }
5106 }
5107 pub fn table_next_row(&self, flags: TableRowFlags, min_row_height: f32) {
5108 unsafe {
5109 ImGui_TableNextRow(flags.bits(), min_row_height);
5110 }
5111 }
5112 pub fn table_next_column(&self) -> bool {
5113 unsafe {
5114 ImGui_TableNextColumn()
5115 }
5116 }
5117 pub fn table_set_column_index(&self, column_n: i32) -> bool {
5118 unsafe {
5119 ImGui_TableSetColumnIndex(column_n)
5120 }
5121 }
5122 pub fn table_setup_column(&self, label: impl IntoCStr, flags: TableColumnFlags, init_width_or_weight: f32, user_id: ImGuiID) {
5123 unsafe {
5124 ImGui_TableSetupColumn(label.into().as_ptr(), flags.bits(), init_width_or_weight, user_id);
5125 }
5126 }
5127 pub fn table_setup_scroll_freeze(&self, cols: i32, rows: i32) {
5128 unsafe {
5129 ImGui_TableSetupScrollFreeze(cols, rows);
5130 }
5131 }
5132 pub fn table_headers_row(&self) {
5133 unsafe {
5134 ImGui_TableHeadersRow();
5135 }
5136 }
5137 pub fn table_angle_headers_row(&self) {
5138 unsafe {
5139 ImGui_TableAngledHeadersRow();
5140 }
5141 }
5142 pub fn table_get_columns_count(&self) -> i32 {
5143 unsafe {
5144 ImGui_TableGetColumnCount()
5145 }
5146 }
5147 pub fn table_get_column_index(&self) -> i32 {
5148 unsafe {
5149 ImGui_TableGetColumnIndex()
5150 }
5151 }
5152 pub fn table_get_hovered_column(&self) -> Option<i32> {
5154 unsafe {
5155 let res = ImGui_TableGetHoveredColumn();
5156 if res < 0 {
5157 None
5158 } else {
5159 Some(res)
5160 }
5161 }
5162 }
5163 pub fn table_get_row_index(&self) -> i32 {
5164 unsafe {
5165 ImGui_TableGetRowIndex()
5166 }
5167 }
5168 pub fn table_get_column_flags(&self, column_n: Option<i32>) -> TableColumnFlags {
5169 let bits = unsafe {
5170 ImGui_TableGetColumnFlags(column_n.unwrap_or(-1))
5171 };
5172 TableColumnFlags::from_bits_truncate(bits)
5173 }
5174 pub fn table_get_column_name(&self, column_n: Option<i32>) -> String {
5175 unsafe {
5176 let c_str = ImGui_TableGetColumnName(column_n.unwrap_or(-1));
5177 CStr::from_ptr(c_str).to_string_lossy().into_owned()
5178 }
5179 }
5180 pub fn table_set_column_enabled(&self, column_n: Option<i32>, enabled: bool) {
5181 unsafe {
5182 ImGui_TableSetColumnEnabled(column_n.unwrap_or(-1), enabled);
5183 };
5184 }
5185 pub fn table_set_bg_color(&self, target: TableBgTarget, color: Color, column_n: Option<i32>) {
5186 unsafe {
5187 ImGui_TableSetBgColor(target.bits(), color.as_u32(), column_n.unwrap_or(-1));
5188 };
5189 }
5190 pub fn table_with_sort_specs(&self, sort_fn: impl FnOnce(&[TableColumnSortSpec])) {
5191 self.table_with_sort_specs_always(|dirty, spec| {
5192 if dirty {
5193 sort_fn(spec);
5194 }
5195 false
5196 })
5197 }
5198 pub fn table_with_sort_specs_always(&self, sort_fn: impl FnOnce(bool, &[TableColumnSortSpec]) -> bool) {
5200 unsafe {
5201 let specs = ImGui_TableGetSortSpecs();
5202 if specs.is_null() {
5203 return;
5204 }
5205 let slice = {
5207 let len = (*specs).SpecsCount as usize;
5208 if len == 0 {
5209 &[]
5210 } else {
5211 let ptr = std::mem::transmute::<*const ImGuiTableColumnSortSpecs, *const TableColumnSortSpec>((*specs).Specs);
5212 std::slice::from_raw_parts(ptr, len)
5213 }
5214 };
5215 (*specs).SpecsDirty = sort_fn((*specs).SpecsDirty, slice);
5216 }
5217 }
5218 }
5219}
5220
5221pub struct DragDropPayloadSetter<'a> {
5223 _dummy: PhantomData<&'a ()>,
5224}
5225
5226pub enum DragDropPayloadCond {
5228 Always,
5229 Once,
5230}
5231
5232impl DragDropPayloadSetter<'_> {
5233 pub fn set(self, type_: impl IntoCStr, data: &[u8], cond: DragDropPayloadCond) -> bool {
5234 let ptr = if data.is_empty() {
5236 null()
5237 } else {
5238 data.as_ptr() as *const c_void
5239 };
5240 let len = data.len();
5241 let cond = match cond {
5242 DragDropPayloadCond::Always => Cond::Always,
5243 DragDropPayloadCond::Once => Cond::Once,
5244 };
5245 unsafe { ImGui_SetDragDropPayload(type_.into().as_ptr(), ptr, len, cond.bits()) }
5246 }
5247}
5248
5249pub struct DragDropPayloadGetter<'a> {
5251 _dummy: PhantomData<&'a ()>,
5252}
5253
5254pub struct DragDropPayload<'a> {
5258 pay: &'a ImGuiPayload,
5259}
5260
5261impl<'a> DragDropPayloadGetter<'a> {
5262 pub fn any(&self, flags: DragDropAcceptFlags) -> Option<DragDropPayload<'a>> {
5263 unsafe {
5264 let pay = ImGui_AcceptDragDropPayload(null(), flags.bits());
5265 if pay.is_null() {
5266 None
5267 } else {
5268 Some(DragDropPayload { pay: &*pay })
5269 }
5270 }
5271 }
5272 pub fn by_type(
5273 &self,
5274 type_: impl IntoCStr,
5275 flags: DragDropAcceptFlags,
5276 ) -> Option<DragDropPayload<'a>> {
5277 unsafe {
5278 let pay = ImGui_AcceptDragDropPayload(type_.into().as_ptr(), flags.bits());
5279 if pay.is_null() {
5280 None
5281 } else {
5282 Some(DragDropPayload { pay: &*pay })
5283 }
5284 }
5285 }
5286 pub fn peek(&self) -> Option<DragDropPayload<'a>> {
5287 unsafe {
5288 let pay = ImGui_GetDragDropPayload();
5289 if pay.is_null() {
5290 None
5291 } else {
5292 Some(DragDropPayload { pay: &*pay })
5293 }
5294 }
5295 }
5296}
5297
5298impl DragDropPayload<'_> {
5299 pub fn is_data_type(&self, type_: impl IntoCStr) -> bool {
5301 if self.pay.DataFrameCount == -1 {
5302 return false;
5303 }
5304 let data_type = unsafe { std::mem::transmute::<&[c_char], &[u8]>(&self.pay.DataType) };
5305 let data_type = CStr::from_bytes_until_nul(data_type).unwrap();
5306 data_type == type_.into().as_ref()
5307 }
5308 pub fn type_(&self) -> Cow<'_, str> {
5309 let data_type = unsafe { std::mem::transmute::<&[c_char], &[u8]>(&self.pay.DataType) };
5310 let data_type = CStr::from_bytes_until_nul(data_type).unwrap();
5311 data_type.to_string_lossy()
5312 }
5313 pub fn is_preview(&self) -> bool {
5314 self.pay.Preview
5315 }
5316 pub fn is_delivery(&self) -> bool {
5317 self.pay.Delivery
5318 }
5319 pub fn data(&self) -> &[u8] {
5320 if self.pay.Data.is_null() {
5321 &[]
5322 } else {
5323 unsafe {
5324 std::slice::from_raw_parts(self.pay.Data as *const u8, self.pay.DataSize as usize)
5325 }
5326 }
5327 }
5328}
5329
5330pub const PAYLOAD_TYPE_COLOR_3F: &CStr =
5331 unsafe { CStr::from_bytes_with_nul_unchecked(IMGUI_PAYLOAD_TYPE_COLOR_3F) };
5332pub const PAYLOAD_TYPE_COLOR_4F: &CStr =
5333 unsafe { CStr::from_bytes_with_nul_unchecked(IMGUI_PAYLOAD_TYPE_COLOR_4F) };
5334
5335#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5340pub struct KeyChord(ImGuiKey);
5341
5342impl KeyChord {
5343 pub fn new(mods: KeyMod, key: Key) -> KeyChord {
5344 KeyChord(ImGuiKey(mods.bits() | key.bits().0))
5345 }
5346 pub fn bits(&self) -> i32 {
5347 self.0.0
5348 }
5349 pub fn from_bits(bits: i32) -> Option<KeyChord> {
5350 let key = bits & !ImGuiKey::ImGuiMod_Mask_.0;
5352 let mods = bits & ImGuiKey::ImGuiMod_Mask_.0;
5353 match (Key::from_bits(ImGuiKey(key)), KeyMod::from_bits(mods)) {
5354 (Some(_), Some(_)) => Some(KeyChord(ImGuiKey(bits))),
5355 _ => None,
5356 }
5357 }
5358 pub fn key(&self) -> Key {
5359 let key = self.bits() & !ImGuiKey::ImGuiMod_Mask_.0;
5360 Key::from_bits(ImGuiKey(key)).unwrap_or(Key::None)
5361 }
5362 pub fn mods(&self) -> KeyMod {
5363 let mods = self.bits() & ImGuiKey::ImGuiMod_Mask_.0;
5364 KeyMod::from_bits_truncate(mods)
5365 }
5366}
5367
5368impl From<Key> for KeyChord {
5369 fn from(value: Key) -> Self {
5370 KeyChord::new(KeyMod::None, value)
5371 }
5372}
5373
5374impl From<(KeyMod, Key)> for KeyChord {
5375 fn from(value: (KeyMod, Key)) -> Self {
5376 KeyChord::new(value.0, value.1)
5377 }
5378}
5379
5380#[repr(transparent)]
5382pub struct TableColumnSortSpec(ImGuiTableColumnSortSpecs);
5383
5384impl std::fmt::Debug for TableColumnSortSpec {
5385 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5386 f.debug_struct("TableColumnSortSpec")
5387 .field("id", &self.id())
5388 .field("index", &self.index())
5389 .field("sort_order", &self.sort_order())
5390 .field("sort_direction", &self.sort_direction())
5391 .finish()
5392 }
5393}
5394
5395impl TableColumnSortSpec {
5396 pub fn id(&self) -> ImGuiID {
5397 self.0.ColumnUserID
5398 }
5399 pub fn index(&self) -> usize {
5400 self.0.ColumnIndex as usize
5401 }
5402 pub fn sort_order(&self) -> usize {
5403 self.0.SortOrder as usize
5404 }
5405 pub fn sort_direction(&self) -> SortDirection {
5406 SortDirection::from_bits(self.0.SortDirection).unwrap_or(SortDirection::None)
5407 }
5408}
5409
5410pub struct DockBuilder {
5411 _dummy: (),
5412}
5413
5414impl DockBuilder {
5415 pub fn set_node_size(&self, node_id: ImGuiID, size: Vector2) {
5416 unsafe {
5417 ImGui_DockBuilderSetNodeSize(node_id, v2_to_im(size));
5418 }
5419 }
5420 pub fn set_node_pos(&self, node_id: ImGuiID, pos: Vector2) {
5421 unsafe {
5422 ImGui_DockBuilderSetNodePos(node_id, v2_to_im(pos));
5423 }
5424 }
5425 pub fn split_node(&self, node_id: ImGuiID, dir: Dir, size_ratio: f32) -> (ImGuiID, ImGuiID) {
5426 unsafe {
5427 let mut id2 = 0;
5428 let id1 = ImGui_DockBuilderSplitNode(
5429 node_id,
5430 dir.bits(),
5431 size_ratio,
5432 std::ptr::null_mut(),
5433 &mut id2,
5434 );
5435 (id1, id2)
5436 }
5437 }
5438 pub fn dock_window(&self, window_name: Id<impl IntoCStr>, node_id: ImGuiID) {
5439 unsafe {
5440 ImGui_DockBuilderDockWindow(window_name.into().as_ptr(), node_id);
5441 }
5442 }
5443 pub fn get_node(&self, node_id: ImGuiID) -> Option<&DockNode> {
5444 unsafe {
5445 let ptr = ImGui_DockBuilderGetNode(node_id);
5446 ptr.as_ref().map(DockNode::cast)
5447 }
5448 }
5449 pub fn get_node_mut(&mut self, node_id: ImGuiID) -> Option<&mut DockNode> {
5450 unsafe {
5451 let ptr = ImGui_DockBuilderGetNode(node_id);
5452 ptr.as_mut().map(DockNode::cast_mut)
5453 }
5454 }
5455}
5456
5457transparent! {
5458 pub struct DockNode(ImGuiDockNode);
5459}
5460
5461impl DockNode {
5462 pub fn local_flags(&self) -> DockNodeFlags {
5463 DockNodeFlags::from_bits_truncate(self.LocalFlags)
5464 }
5465
5466 pub fn set_local_flags(&mut self, flags: DockNodeFlags) {
5467 self.0.LocalFlags = flags.bits();
5469 self.0.MergedFlags = self.0.SharedFlags | self.0.LocalFlags | self.0.LocalFlagsInWindows;
5470 }
5471}
5472
5473transparent_mut! {
5474 #[derive(Debug, Copy, Clone)]
5475 pub struct WindowClass(ImGuiWindowClass);
5476}
5477
5478impl Default for WindowClass {
5479 fn default() -> Self {
5480 WindowClass(ImGuiWindowClass {
5482 ClassId: 0,
5483 ParentViewportId: u32::MAX,
5484 FocusRouteParentWindowId: 0,
5485 ViewportFlagsOverrideSet: 0,
5486 ViewportFlagsOverrideClear: 0,
5487 TabItemFlagsOverrideSet: 0,
5488 DockNodeFlagsOverrideSet: 0,
5489 DockingAlwaysTabBar: false,
5490 DockingAllowUnclassed: true,
5491 })
5492 }
5493}
5494
5495impl WindowClass {
5496 pub fn new() -> Self {
5497 Self::default()
5498 }
5499 pub fn class_id(mut self, id: ImGuiID) -> Self {
5500 self.ClassId = id;
5501 self
5502 }
5503 pub fn parent_viewport_id(mut self, id: Option<ImGuiID>) -> Self {
5504 self.ParentViewportId = id.unwrap_or(u32::MAX);
5505 self
5506 }
5507 pub fn focus_route_parent_window_id(mut self, id: ImGuiID) -> Self {
5508 self.FocusRouteParentWindowId = id;
5509 self
5510 }
5511 pub fn dock_node_flags(mut self, set_flags: DockNodeFlags) -> Self {
5512 self.DockNodeFlagsOverrideSet = set_flags.bits();
5513 self
5514 }
5515 pub fn tab_item_flags(mut self, set_flags: TabItemFlags) -> Self {
5516 self.TabItemFlagsOverrideSet = set_flags.bits();
5517 self
5518 }
5519 pub fn viewport_flags(mut self, set_flags: ViewportFlags, clear_flags: ViewportFlags) -> Self {
5520 self.ViewportFlagsOverrideSet = set_flags.bits();
5521 self.ViewportFlagsOverrideClear = clear_flags.bits();
5522 self
5523 }
5524 pub fn docking_always_tab_bar(mut self, value: bool) -> Self {
5525 self.DockingAlwaysTabBar = value;
5526 self
5527 }
5528 pub fn docking_allow_unclassed(mut self, value: bool) -> Self {
5529 self.DockingAllowUnclassed = value;
5530 self
5531 }
5532}