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_line_h(&self, min_x: f32, max_x: f32, y: f32, color: Color, thickness: f32) {
4087 unsafe {
4088 ImDrawList_AddLineH(self.ptr, min_x, max_x, y, color.as_u32(), thickness);
4089 }
4090 }
4091 pub fn add_line_v(&self, x: f32, min_y: f32, max_y: f32, color: Color, thickness: f32) {
4092 unsafe {
4093 ImDrawList_AddLineV(self.ptr, x, min_y, max_y, color.as_u32(), thickness);
4094 }
4095 }
4096 pub fn add_rect(
4097 &self,
4098 p_min: Vector2,
4099 p_max: Vector2,
4100 color: Color,
4101 rounding: f32,
4102 thickness: f32,
4103 flags: DrawFlags,
4104 ) {
4105 unsafe {
4106 ImDrawList_AddRect(
4107 self.ptr,
4108 &v2_to_im(p_min),
4109 &v2_to_im(p_max),
4110 color.as_u32(),
4111 rounding,
4112 thickness,
4113 flags.bits(),
4114 );
4115 }
4116 }
4117 pub fn add_rect_filled(
4118 &self,
4119 p_min: Vector2,
4120 p_max: Vector2,
4121 color: Color,
4122 rounding: f32,
4123 flags: DrawFlags,
4124 ) {
4125 unsafe {
4126 ImDrawList_AddRectFilled(
4127 self.ptr,
4128 &v2_to_im(p_min),
4129 &v2_to_im(p_max),
4130 color.as_u32(),
4131 rounding,
4132 flags.bits(),
4133 );
4134 }
4135 }
4136 pub fn add_rect_filled_multicolor(
4137 &self,
4138 p_min: Vector2,
4139 p_max: Vector2,
4140 col_upr_left: Color,
4141 col_upr_right: Color,
4142 col_bot_right: Color,
4143 col_bot_left: Color,
4144 ) {
4145 unsafe {
4146 ImDrawList_AddRectFilledMultiColor(
4147 self.ptr,
4148 &v2_to_im(p_min),
4149 &v2_to_im(p_max),
4150 col_upr_left.as_u32(),
4151 col_upr_right.as_u32(),
4152 col_bot_right.as_u32(),
4153 col_bot_left.as_u32(),
4154 );
4155 }
4156 }
4157 pub fn add_quad(
4158 &self,
4159 p1: Vector2,
4160 p2: Vector2,
4161 p3: Vector2,
4162 p4: Vector2,
4163 color: Color,
4164 thickness: f32,
4165 ) {
4166 unsafe {
4167 ImDrawList_AddQuad(
4168 self.ptr,
4169 &v2_to_im(p1),
4170 &v2_to_im(p2),
4171 &v2_to_im(p3),
4172 &v2_to_im(p4),
4173 color.as_u32(),
4174 thickness,
4175 );
4176 }
4177 }
4178 pub fn add_quad_filled(
4179 &self,
4180 p1: Vector2,
4181 p2: Vector2,
4182 p3: Vector2,
4183 p4: Vector2,
4184 color: Color,
4185 ) {
4186 unsafe {
4187 ImDrawList_AddQuadFilled(
4188 self.ptr,
4189 &v2_to_im(p1),
4190 &v2_to_im(p2),
4191 &v2_to_im(p3),
4192 &v2_to_im(p4),
4193 color.as_u32(),
4194 );
4195 }
4196 }
4197 pub fn add_triangle(
4198 &self,
4199 p1: Vector2,
4200 p2: Vector2,
4201 p3: Vector2,
4202 color: Color,
4203 thickness: f32,
4204 ) {
4205 unsafe {
4206 ImDrawList_AddTriangle(
4207 self.ptr,
4208 &v2_to_im(p1),
4209 &v2_to_im(p2),
4210 &v2_to_im(p3),
4211 color.as_u32(),
4212 thickness,
4213 );
4214 }
4215 }
4216 pub fn add_triangle_filled(&self, p1: Vector2, p2: Vector2, p3: Vector2, color: Color) {
4217 unsafe {
4218 ImDrawList_AddTriangleFilled(
4219 self.ptr,
4220 &v2_to_im(p1),
4221 &v2_to_im(p2),
4222 &v2_to_im(p3),
4223 color.as_u32(),
4224 );
4225 }
4226 }
4227 pub fn add_circle(
4228 &self,
4229 center: Vector2,
4230 radius: f32,
4231 color: Color,
4232 num_segments: i32,
4233 thickness: f32,
4234 ) {
4235 unsafe {
4236 ImDrawList_AddCircle(
4237 self.ptr,
4238 &v2_to_im(center),
4239 radius,
4240 color.as_u32(),
4241 num_segments,
4242 thickness,
4243 );
4244 }
4245 }
4246 pub fn add_circle_filled(&self, center: Vector2, radius: f32, color: Color, num_segments: i32) {
4247 unsafe {
4248 ImDrawList_AddCircleFilled(
4249 self.ptr,
4250 &v2_to_im(center),
4251 radius,
4252 color.as_u32(),
4253 num_segments,
4254 );
4255 }
4256 }
4257 pub fn add_ngon(
4258 &self,
4259 center: Vector2,
4260 radius: f32,
4261 color: Color,
4262 num_segments: i32,
4263 thickness: f32,
4264 ) {
4265 unsafe {
4266 ImDrawList_AddNgon(
4267 self.ptr,
4268 &v2_to_im(center),
4269 radius,
4270 color.as_u32(),
4271 num_segments,
4272 thickness,
4273 );
4274 }
4275 }
4276 pub fn add_ngon_filled(&self, center: Vector2, radius: f32, color: Color, num_segments: i32) {
4277 unsafe {
4278 ImDrawList_AddNgonFilled(
4279 self.ptr,
4280 &v2_to_im(center),
4281 radius,
4282 color.as_u32(),
4283 num_segments,
4284 );
4285 }
4286 }
4287 pub fn add_ellipse(
4288 &self,
4289 center: Vector2,
4290 radius: Vector2,
4291 color: Color,
4292 rot: f32,
4293 num_segments: i32,
4294 thickness: f32,
4295 ) {
4296 unsafe {
4297 ImDrawList_AddEllipse(
4298 self.ptr,
4299 &v2_to_im(center),
4300 &v2_to_im(radius),
4301 color.as_u32(),
4302 rot,
4303 num_segments,
4304 thickness,
4305 );
4306 }
4307 }
4308 pub fn add_ellipse_filled(
4309 &self,
4310 center: Vector2,
4311 radius: Vector2,
4312 color: Color,
4313 rot: f32,
4314 num_segments: i32,
4315 ) {
4316 unsafe {
4317 ImDrawList_AddEllipseFilled(
4318 self.ptr,
4319 &v2_to_im(center),
4320 &v2_to_im(radius),
4321 color.as_u32(),
4322 rot,
4323 num_segments,
4324 );
4325 }
4326 }
4327 pub fn add_text(&self, pos: Vector2, color: Color, text: &str) {
4328 unsafe {
4329 let (start, end) = text_ptrs(text);
4330 ImDrawList_AddText(self.ptr, &v2_to_im(pos), color.as_u32(), start, end);
4331 }
4332 }
4333 pub fn add_text_ex(
4334 &self,
4335 font: FontId,
4336 font_size: f32,
4337 pos: Vector2,
4338 color: Color,
4339 text: &str,
4340 wrap_width: f32,
4341 cpu_fine_clip_rect: Option<ImVec4>,
4342 ) {
4343 unsafe {
4344 let (start, end) = text_ptrs(text);
4345 ImDrawList_AddText1(
4346 self.ptr,
4347 self.ui.io().font_atlas().font_ptr(font),
4348 font_size,
4349 &v2_to_im(pos),
4350 color.as_u32(),
4351 start,
4352 end,
4353 wrap_width,
4354 cpu_fine_clip_rect
4355 .as_ref()
4356 .map(|x| x as *const _)
4357 .unwrap_or(null()),
4358 );
4359 }
4360 }
4361 pub fn add_polyline(&self, points: &[ImVec2], color: Color, thickness: f32, flags: DrawFlags) {
4362 unsafe {
4363 ImDrawList_AddPolyline(
4364 self.ptr,
4365 points.as_ptr(),
4366 points.len() as i32,
4367 color.as_u32(),
4368 thickness,
4369 flags.bits(),
4370 );
4371 }
4372 }
4373 pub fn add_convex_poly_filled(&self, points: &[ImVec2], color: Color) {
4374 unsafe {
4375 ImDrawList_AddConvexPolyFilled(
4376 self.ptr,
4377 points.as_ptr(),
4378 points.len() as i32,
4379 color.as_u32(),
4380 );
4381 }
4382 }
4383 pub fn add_concave_poly_filled(&self, points: &[ImVec2], color: Color) {
4384 unsafe {
4385 ImDrawList_AddConcavePolyFilled(
4386 self.ptr,
4387 points.as_ptr(),
4388 points.len() as i32,
4389 color.as_u32(),
4390 );
4391 }
4392 }
4393 pub fn add_bezier_cubic(
4394 &self,
4395 p1: Vector2,
4396 p2: Vector2,
4397 p3: Vector2,
4398 p4: Vector2,
4399 color: Color,
4400 thickness: f32,
4401 num_segments: i32,
4402 ) {
4403 unsafe {
4404 ImDrawList_AddBezierCubic(
4405 self.ptr,
4406 &v2_to_im(p1),
4407 &v2_to_im(p2),
4408 &v2_to_im(p3),
4409 &v2_to_im(p4),
4410 color.as_u32(),
4411 thickness,
4412 num_segments,
4413 );
4414 }
4415 }
4416 pub fn add_bezier_quadratic(
4417 &self,
4418 p1: Vector2,
4419 p2: Vector2,
4420 p3: Vector2,
4421 color: Color,
4422 thickness: f32,
4423 num_segments: i32,
4424 ) {
4425 unsafe {
4426 ImDrawList_AddBezierQuadratic(
4427 self.ptr,
4428 &v2_to_im(p1),
4429 &v2_to_im(p2),
4430 &v2_to_im(p3),
4431 color.as_u32(),
4432 thickness,
4433 num_segments,
4434 );
4435 }
4436 }
4437 pub fn add_image(
4438 &self,
4439 texture_ref: TextureRef,
4440 p_min: Vector2,
4441 p_max: Vector2,
4442 uv_min: Vector2,
4443 uv_max: Vector2,
4444 color: Color,
4445 ) {
4446 unsafe {
4447 ImDrawList_AddImage(
4448 self.ptr,
4449 texture_ref.tex_ref(),
4450 &v2_to_im(p_min),
4451 &v2_to_im(p_max),
4452 &v2_to_im(uv_min),
4453 &v2_to_im(uv_max),
4454 color.as_u32(),
4455 );
4456 }
4457 }
4458 pub fn add_image_quad(
4459 &self,
4460 texture_ref: TextureRef,
4461 p1: Vector2,
4462 p2: Vector2,
4463 p3: Vector2,
4464 p4: Vector2,
4465 uv1: Vector2,
4466 uv2: Vector2,
4467 uv3: Vector2,
4468 uv4: Vector2,
4469 color: Color,
4470 ) {
4471 unsafe {
4472 ImDrawList_AddImageQuad(
4473 self.ptr,
4474 texture_ref.tex_ref(),
4475 &v2_to_im(p1),
4476 &v2_to_im(p2),
4477 &v2_to_im(p3),
4478 &v2_to_im(p4),
4479 &v2_to_im(uv1),
4480 &v2_to_im(uv2),
4481 &v2_to_im(uv3),
4482 &v2_to_im(uv4),
4483 color.as_u32(),
4484 );
4485 }
4486 }
4487 pub fn add_image_rounded(
4488 &self,
4489 texture_ref: TextureRef,
4490 p_min: Vector2,
4491 p_max: Vector2,
4492 uv_min: Vector2,
4493 uv_max: Vector2,
4494 color: Color,
4495 rounding: f32,
4496 flags: DrawFlags,
4497 ) {
4498 unsafe {
4499 ImDrawList_AddImageRounded(
4500 self.ptr,
4501 texture_ref.tex_ref(),
4502 &v2_to_im(p_min),
4503 &v2_to_im(p_max),
4504 &v2_to_im(uv_min),
4505 &v2_to_im(uv_max),
4506 color.as_u32(),
4507 rounding,
4508 flags.bits(),
4509 );
4510 }
4511 }
4512
4513 pub fn path_clear(&self) {
4515 unsafe {
4516 let path = &mut (&mut *self.ptr)._Path;
4517 path.Size = 0;
4518 }
4519 }
4520 pub fn path_line_to(&self, v: Vector2) {
4521 unsafe {
4522 let path = &mut (&mut *self.ptr)._Path;
4523 ImGui_ImVector_vec2_push_back(path, &v2_to_im(v));
4524 }
4525 }
4526 pub fn path_line_to_merge_duplicate(&self, v: Vector2) {
4527 unsafe {
4528 let path = &mut (&mut *self.ptr)._Path;
4529 if path.last().is_none_or(|d| d.x != v.x || d.y != v.y) {
4530 ImGui_ImVector_vec2_push_back(path, &v2_to_im(v));
4531 }
4532 }
4533 }
4534 pub fn path_fill_convex(&self, color: Color) {
4535 unsafe {
4536 let path = &mut (&mut *self.ptr)._Path;
4537 ImDrawList_AddConvexPolyFilled(self.ptr, path.Data, path.Size, color.as_u32());
4538 path.Size = 0;
4539 }
4540 }
4541 pub fn path_fill_concave(&self, color: Color) {
4542 unsafe {
4543 let path = &mut (&mut *self.ptr)._Path;
4544 ImDrawList_AddConcavePolyFilled(self.ptr, path.Data, path.Size, color.as_u32());
4545 path.Size = 0;
4546 }
4547 }
4548 pub fn path_stroke(&self, color: Color, thickness: f32, flags: DrawFlags) {
4549 unsafe {
4550 let path = &mut (&mut *self.ptr)._Path;
4551 ImDrawList_AddPolyline(
4552 self.ptr,
4553 path.Data,
4554 path.Size,
4555 color.as_u32(),
4556 thickness,
4557 flags.bits(),
4558 );
4559 path.Size = 0;
4560 }
4561 }
4562 pub fn path_arc_to(
4563 &self,
4564 center: Vector2,
4565 radius: f32,
4566 a_min: f32,
4567 a_max: f32,
4568 num_segments: i32,
4569 ) {
4570 unsafe {
4571 ImDrawList_PathArcTo(
4572 self.ptr,
4573 &v2_to_im(center),
4574 radius,
4575 a_min,
4576 a_max,
4577 num_segments,
4578 );
4579 }
4580 }
4581 pub fn path_arc_to_fast(
4582 &self,
4583 center: Vector2,
4584 radius: f32,
4585 a_min_of_12: i32,
4586 a_max_of_12: i32,
4587 ) {
4588 unsafe {
4589 ImDrawList_PathArcToFast(
4590 self.ptr,
4591 &v2_to_im(center),
4592 radius,
4593 a_min_of_12,
4594 a_max_of_12,
4595 );
4596 }
4597 }
4598 pub fn path_elliptical_arc_to(
4599 &self,
4600 center: Vector2,
4601 radius: Vector2,
4602 rot: f32,
4603 a_min: f32,
4604 a_max: f32,
4605 num_segments: i32,
4606 ) {
4607 unsafe {
4608 ImDrawList_PathEllipticalArcTo(
4609 self.ptr,
4610 &v2_to_im(center),
4611 &v2_to_im(radius),
4612 rot,
4613 a_min,
4614 a_max,
4615 num_segments,
4616 );
4617 }
4618 }
4619 pub fn path_bezier_cubic_curve_to(
4620 &self,
4621 p2: Vector2,
4622 p3: Vector2,
4623 p4: Vector2,
4624 num_segments: i32,
4625 ) {
4626 unsafe {
4627 ImDrawList_PathBezierCubicCurveTo(
4628 self.ptr,
4629 &v2_to_im(p2),
4630 &v2_to_im(p3),
4631 &v2_to_im(p4),
4632 num_segments,
4633 );
4634 }
4635 }
4636 pub fn path_bezier_quadratic_curve_to(&self, p2: Vector2, p3: Vector2, num_segments: i32) {
4637 unsafe {
4638 ImDrawList_PathBezierQuadraticCurveTo(
4639 self.ptr,
4640 &v2_to_im(p2),
4641 &v2_to_im(p3),
4642 num_segments,
4643 );
4644 }
4645 }
4646 pub fn path_rect(&self, rect_min: Vector2, rect_max: Vector2, rounding: f32, flags: DrawFlags) {
4647 unsafe {
4648 ImDrawList_PathRect(
4649 self.ptr,
4650 &v2_to_im(rect_min),
4651 &v2_to_im(rect_max),
4652 rounding,
4653 flags.bits(),
4654 );
4655 }
4656 }
4657
4658 pub fn add_callback(&self, cb: impl FnOnce(&mut A) + 'static) {
4659 let mut cb = Some(cb);
4663 unsafe {
4664 let id = self.ui.push_callback(move |a, _: ()| {
4665 if let Some(cb) = cb.take() {
4666 cb(&mut *a);
4667 }
4668 });
4669 ImDrawList_AddCallback(
4670 self.ptr,
4671 Some(call_drawlist_callback::<A>),
4672 id as *mut c_void,
4673 0,
4674 );
4675 }
4676 }
4677 pub fn add_draw_cmd(&self) {
4678 unsafe {
4679 ImDrawList_AddDrawCmd(self.ptr);
4680 }
4681 }
4682}
4683
4684unsafe extern "C" fn call_drawlist_callback<A>(
4685 _parent_list: *const ImDrawList,
4686 cmd: *const ImDrawCmd,
4687) {
4688 unsafe {
4689 let id = (*cmd).UserCallbackData as usize;
4690 Ui::<A>::run_callback(id, ());
4691 }
4692}
4693
4694pub trait Hashable {
4696 unsafe fn get_id(&self) -> ImGuiID;
4698 unsafe fn push(&self);
4699}
4700
4701impl Hashable for &str {
4702 unsafe fn get_id(&self) -> ImGuiID {
4703 unsafe {
4704 let (start, end) = text_ptrs(self);
4705 ImGui_GetID1(start, end)
4706 }
4707 }
4708 unsafe fn push(&self) {
4709 unsafe {
4710 let (start, end) = text_ptrs(self);
4711 ImGui_PushID1(start, end);
4712 }
4713 }
4714}
4715
4716impl Hashable for usize {
4717 unsafe fn get_id(&self) -> ImGuiID {
4718 unsafe { ImGui_GetID2(*self as *const c_void) }
4719 }
4720 unsafe fn push(&self) {
4721 unsafe {
4722 ImGui_PushID2(*self as *const c_void);
4723 }
4724 }
4725}
4726
4727pub trait Pushable {
4734 unsafe fn push(&self);
4735 unsafe fn pop(&self);
4736}
4737
4738struct PushableGuard<'a, P: Pushable + ?Sized>(&'a P);
4739
4740impl<P: Pushable + ?Sized> Drop for PushableGuard<'_, P> {
4741 fn drop(&mut self) {
4742 unsafe {
4743 self.0.pop();
4744 }
4745 }
4746}
4747
4748#[allow(clippy::needless_lifetimes)]
4749unsafe fn push_guard<'a, P: Pushable>(p: &'a P) -> PushableGuard<'a, P> {
4750 unsafe {
4751 p.push();
4752 PushableGuard(p)
4753 }
4754}
4755
4756impl Pushable for () {
4758 unsafe fn push(&self) {}
4759 unsafe fn pop(&self) {}
4760}
4761
4762impl<A: Pushable, B: Pushable> Pushable for Either<A, B> {
4763 unsafe fn push(&self) {
4764 unsafe {
4765 match self {
4766 Either::Left(a) => A::push(a),
4767 Either::Right(b) => B::push(b),
4768 }
4769 }
4770 }
4771 unsafe fn pop(&self) {
4772 unsafe {
4773 match self {
4774 Either::Left(a) => A::pop(a),
4775 Either::Right(b) => B::pop(b),
4776 }
4777 }
4778 }
4779}
4780
4781impl<A: Pushable> Pushable for (A,) {
4782 unsafe fn push(&self) {
4783 unsafe {
4784 self.0.push();
4785 }
4786 }
4787 unsafe fn pop(&self) {
4788 unsafe {
4789 self.0.pop();
4790 }
4791 }
4792}
4793
4794impl<P: Pushable + ?Sized> Pushable for &P {
4795 unsafe fn push(&self) {
4796 unsafe {
4797 P::push(self);
4798 }
4799 }
4800 unsafe fn pop(&self) {
4801 unsafe {
4802 P::pop(self);
4803 }
4804 }
4805}
4806
4807impl<A: Pushable, B: Pushable> Pushable for (A, B) {
4808 unsafe fn push(&self) {
4809 unsafe {
4810 self.0.push();
4811 self.1.push();
4812 }
4813 }
4814 unsafe fn pop(&self) {
4815 unsafe {
4816 self.1.pop();
4817 self.0.pop();
4818 }
4819 }
4820}
4821
4822impl<A: Pushable, B: Pushable, C: Pushable> Pushable for (A, B, C) {
4823 unsafe fn push(&self) {
4824 unsafe {
4825 self.0.push();
4826 self.1.push();
4827 self.2.push();
4828 }
4829 }
4830 unsafe fn pop(&self) {
4831 unsafe {
4832 self.2.pop();
4833 self.1.pop();
4834 self.0.pop();
4835 }
4836 }
4837}
4838
4839impl<A: Pushable, B: Pushable, C: Pushable, D: Pushable> Pushable for (A, B, C, D) {
4840 unsafe fn push(&self) {
4841 unsafe {
4842 self.0.push();
4843 self.1.push();
4844 self.2.push();
4845 self.3.push();
4846 }
4847 }
4848 unsafe fn pop(&self) {
4849 unsafe {
4850 self.3.pop();
4851 self.2.pop();
4852 self.1.pop();
4853 self.0.pop();
4854 }
4855 }
4856}
4857
4858impl Pushable for &[&dyn Pushable] {
4859 unsafe fn push(&self) {
4860 unsafe {
4861 for st in *self {
4862 st.push();
4863 }
4864 }
4865 }
4866 unsafe fn pop(&self) {
4867 unsafe {
4868 for st in self.iter().rev() {
4869 st.pop();
4870 }
4871 }
4872 }
4873}
4874
4875impl<T: Pushable> Pushable for Option<T> {
4877 unsafe fn push(&self) {
4878 unsafe {
4879 if let Some(s) = self {
4880 s.push();
4881 }
4882 }
4883 }
4884 unsafe fn pop(&self) {
4885 unsafe {
4886 if let Some(s) = self {
4887 s.pop();
4888 }
4889 }
4890 }
4891}
4892
4893impl Pushable for FontId {
4895 unsafe fn push(&self) {
4896 unsafe {
4897 let font = current_font_ptr(*self);
4898 ImGui_PushFont(font, 0.0);
4899 }
4900 }
4901 unsafe fn pop(&self) {
4902 unsafe {
4903 ImGui_PopFont();
4904 }
4905 }
4906}
4907
4908pub struct FontSize(pub f32);
4909
4910impl Pushable for FontSize {
4911 unsafe fn push(&self) {
4912 unsafe {
4913 ImGui_PushFont(std::ptr::null_mut(), self.0);
4915 }
4916 }
4917 unsafe fn pop(&self) {
4918 unsafe {
4919 ImGui_PopFont();
4920 }
4921 }
4922}
4923
4924pub struct FontAndSize(pub FontId, pub f32);
4925
4926impl Pushable for FontAndSize {
4927 unsafe fn push(&self) {
4928 unsafe {
4929 ImGui_PushFont(current_font_ptr(self.0), self.1);
4930 }
4931 }
4932 unsafe fn pop(&self) {
4933 unsafe {
4934 ImGui_PopFont();
4935 }
4936 }
4937}
4938
4939pub type StyleColor = (ColorId, Color);
4940
4941#[derive(Copy, Clone, Debug)]
4942pub enum TextureRef<'a> {
4943 Id(TextureId),
4944 Ref(&'a ImTextureData),
4945}
4946
4947impl TextureRef<'_> {
4948 pub unsafe fn tex_ref(&self) -> ImTextureRef {
4949 match self {
4950 TextureRef::Id(TextureId(id)) => ImTextureRef {
4951 _TexData: null_mut(),
4952 _TexID: *id,
4953 },
4954 TextureRef::Ref(tex_data) => ImTextureRef {
4955 _TexData: (&raw const **tex_data).cast_mut(),
4956 _TexID: 0,
4957 },
4958 }
4959 }
4960
4961 pub unsafe fn tex_id(&self) -> TextureId {
4962 unsafe {
4963 match self {
4964 TextureRef::Id(tex_id) => *tex_id,
4965 TextureRef::Ref(tex_data) => {
4966 let id = tex_data.TexID;
4967 TextureId::from_id(id)
4968 }
4969 }
4970 }
4971 }
4972}
4973
4974#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4975pub struct TextureId(ImTextureID);
4976
4977impl TextureId {
4978 pub fn id(&self) -> ImTextureID {
4979 self.0
4980 }
4981 pub unsafe fn from_id(id: ImTextureID) -> Self {
4982 Self(id)
4983 }
4984}
4985
4986#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4987pub struct TextureUniqueId(i32);
4988
4989impl Pushable for StyleColor {
4990 unsafe fn push(&self) {
4991 unsafe {
4992 ImGui_PushStyleColor1(self.0.bits(), &self.1.into());
4993 }
4994 }
4995 unsafe fn pop(&self) {
4996 unsafe {
4997 ImGui_PopStyleColor(1);
4998 }
4999 }
5000}
5001
5002impl Pushable for [StyleColor] {
5003 unsafe fn push(&self) {
5004 unsafe {
5005 for sc in self {
5006 sc.push();
5007 }
5008 }
5009 }
5010 unsafe fn pop(&self) {
5011 unsafe {
5012 ImGui_PopStyleColor(self.len() as i32);
5013 }
5014 }
5015}
5016
5017impl<const N: usize> Pushable for [StyleColor; N] {
5018 unsafe fn push(&self) {
5019 unsafe {
5020 self.as_slice().push();
5021 }
5022 }
5023 unsafe fn pop(&self) {
5024 unsafe {
5025 self.as_slice().pop();
5026 }
5027 }
5028}
5029
5030pub type StyleColorF = (ColorId, ImVec4);
5031
5032impl Pushable for StyleColorF {
5033 unsafe fn push(&self) {
5034 unsafe {
5035 ImGui_PushStyleColor1(self.0.bits(), &self.1);
5036 }
5037 }
5038 unsafe fn pop(&self) {
5039 unsafe {
5040 ImGui_PopStyleColor(1);
5041 }
5042 }
5043}
5044
5045impl Pushable for [StyleColorF] {
5046 unsafe fn push(&self) {
5047 unsafe {
5048 for sc in self {
5049 sc.push();
5050 }
5051 }
5052 }
5053 unsafe fn pop(&self) {
5054 unsafe {
5055 ImGui_PopStyleColor(self.len() as i32);
5056 }
5057 }
5058}
5059
5060impl<const N: usize> Pushable for [StyleColorF; N] {
5061 unsafe fn push(&self) {
5062 unsafe {
5063 self.as_slice().push();
5064 }
5065 }
5066 unsafe fn pop(&self) {
5067 unsafe {
5068 self.as_slice().pop();
5069 }
5070 }
5071}
5072
5073#[derive(Debug, Copy, Clone)]
5074pub enum StyleValue {
5075 F32(f32),
5076 Vec2(Vector2),
5077 X(f32),
5078 Y(f32),
5079}
5080
5081pub type Style = (StyleVar, StyleValue);
5082
5083impl Pushable for Style {
5084 unsafe fn push(&self) {
5085 unsafe {
5086 match self.1 {
5087 StyleValue::F32(f) => ImGui_PushStyleVar(self.0.bits(), f),
5088 StyleValue::Vec2(v) => ImGui_PushStyleVar1(self.0.bits(), &v2_to_im(v)),
5089 StyleValue::X(x) => ImGui_PushStyleVarX(self.0.bits(), x),
5090 StyleValue::Y(y) => ImGui_PushStyleVarX(self.0.bits(), y),
5091 }
5092 }
5093 }
5094 unsafe fn pop(&self) {
5095 unsafe {
5096 ImGui_PopStyleVar(1);
5097 }
5098 }
5099}
5100
5101impl Pushable for [Style] {
5102 unsafe fn push(&self) {
5103 unsafe {
5104 for sc in self {
5105 sc.push();
5106 }
5107 }
5108 }
5109 unsafe fn pop(&self) {
5110 unsafe {
5111 ImGui_PopStyleVar(self.len() as i32);
5112 }
5113 }
5114}
5115
5116impl<const N: usize> Pushable for [Style; N] {
5117 unsafe fn push(&self) {
5118 unsafe {
5119 self.as_slice().push();
5120 }
5121 }
5122 unsafe fn pop(&self) {
5123 unsafe {
5124 self.as_slice().pop();
5125 }
5126 }
5127}
5128
5129#[derive(Debug, Copy, Clone)]
5130pub struct ItemWidth(pub f32);
5131
5132impl Pushable for ItemWidth {
5133 unsafe fn push(&self) {
5134 unsafe {
5135 ImGui_PushItemWidth(self.0);
5136 }
5137 }
5138 unsafe fn pop(&self) {
5139 unsafe {
5140 ImGui_PopItemWidth();
5141 }
5142 }
5143}
5144
5145#[derive(Debug, Copy, Clone)]
5146pub struct Indent(pub f32);
5147
5148impl Pushable for Indent {
5149 unsafe fn push(&self) {
5150 unsafe {
5151 ImGui_Indent(self.0);
5152 }
5153 }
5154 unsafe fn pop(&self) {
5155 unsafe {
5156 ImGui_Unindent(self.0);
5157 }
5158 }
5159}
5160
5161#[derive(Debug, Copy, Clone)]
5162pub struct TextWrapPos(pub f32);
5163
5164impl Pushable for TextWrapPos {
5165 unsafe fn push(&self) {
5166 unsafe {
5167 ImGui_PushTextWrapPos(self.0);
5168 }
5169 }
5170 unsafe fn pop(&self) {
5171 unsafe {
5172 ImGui_PopTextWrapPos();
5173 }
5174 }
5175}
5176
5177impl Pushable for (ItemFlags, bool) {
5178 unsafe fn push(&self) {
5179 unsafe {
5180 ImGui_PushItemFlag(self.0.bits(), self.1);
5181 }
5182 }
5183 unsafe fn pop(&self) {
5184 unsafe {
5185 ImGui_PopItemFlag();
5186 }
5187 }
5188}
5189
5190#[derive(Debug, Copy, Clone)]
5191pub struct ItemId<H: Hashable>(pub H);
5192
5193impl<H: Hashable> Pushable for ItemId<H> {
5194 unsafe fn push(&self) {
5195 unsafe {
5196 self.0.push();
5197 }
5198 }
5199 unsafe fn pop(&self) {
5200 unsafe {
5201 ImGui_PopID();
5202 }
5203 }
5204}
5205
5206transparent! {
5207 #[derive(Debug)]
5208 pub struct Viewport(ImGuiViewport);
5209}
5210
5211impl Viewport {
5212 pub fn id(&self) -> ImGuiID {
5213 self.ID
5214 }
5215 pub fn flags(&self) -> ViewportFlags {
5216 ViewportFlags::from_bits_truncate(self.Flags)
5217 }
5218 pub fn pos(&self) -> Vector2 {
5219 im_to_v2(self.Pos)
5220 }
5221 pub fn size(&self) -> Vector2 {
5222 im_to_v2(self.Size)
5223 }
5224 pub fn work_pos(&self) -> Vector2 {
5225 im_to_v2(self.WorkPos)
5226 }
5227 pub fn work_size(&self) -> Vector2 {
5228 im_to_v2(self.WorkSize)
5229 }
5230 pub fn center(&self) -> Vector2 {
5231 self.pos() + self.size() / 2.0
5232 }
5233 pub fn work_center(&self) -> Vector2 {
5234 self.work_pos() + self.work_size() / 2.0
5235 }
5236}
5237
5238decl_builder_with_opt! { TableConfig, ImGui_BeginTable, ImGui_EndTable () (S: IntoCStr)
5239 (
5240 str_id (S::Temp) (str_id.as_ptr()),
5241 column (i32) (column),
5242 flags (TableFlags) (flags.bits()),
5243 outer_size (ImVec2) (&outer_size),
5244 inner_width (f32) (inner_width),
5245 )
5246 {
5247 decl_builder_setter!{flags: TableFlags}
5248 decl_builder_setter_vector2!{outer_size: Vector2}
5249 decl_builder_setter!{inner_width: f32}
5250 }
5251 {
5252 pub fn table_config<S: IntoCStr>(&self, str_id: LblId<S>, column: i32) -> TableConfig<S> {
5253 TableConfig {
5254 str_id: str_id.into(),
5255 column,
5256 flags: TableFlags::None,
5257 outer_size: im_vec2(0.0, 0.0),
5258 inner_width: 0.0,
5259 push: (),
5260 }
5261 }
5262 pub fn table_next_row(&self, flags: TableRowFlags, min_row_height: f32) {
5263 unsafe {
5264 ImGui_TableNextRow(flags.bits(), min_row_height);
5265 }
5266 }
5267 pub fn table_next_column(&self) -> bool {
5268 unsafe {
5269 ImGui_TableNextColumn()
5270 }
5271 }
5272 pub fn table_set_column_index(&self, column_n: i32) -> bool {
5273 unsafe {
5274 ImGui_TableSetColumnIndex(column_n)
5275 }
5276 }
5277 pub fn table_setup_column(&self, label: impl IntoCStr, flags: TableColumnFlags, init_width_or_weight: f32, user_id: ImGuiID) {
5278 unsafe {
5279 ImGui_TableSetupColumn(label.into().as_ptr(), flags.bits(), init_width_or_weight, user_id);
5280 }
5281 }
5282 pub fn table_setup_scroll_freeze(&self, cols: i32, rows: i32) {
5283 unsafe {
5284 ImGui_TableSetupScrollFreeze(cols, rows);
5285 }
5286 }
5287 pub fn table_headers_row(&self) {
5288 unsafe {
5289 ImGui_TableHeadersRow();
5290 }
5291 }
5292 pub fn table_angle_headers_row(&self) {
5293 unsafe {
5294 ImGui_TableAngledHeadersRow();
5295 }
5296 }
5297 pub fn table_get_columns_count(&self) -> i32 {
5298 unsafe {
5299 ImGui_TableGetColumnCount()
5300 }
5301 }
5302 pub fn table_get_column_index(&self) -> i32 {
5303 unsafe {
5304 ImGui_TableGetColumnIndex()
5305 }
5306 }
5307 pub fn table_get_hovered_column(&self) -> Option<i32> {
5309 unsafe {
5310 let res = ImGui_TableGetHoveredColumn();
5311 if res < 0 {
5312 None
5313 } else {
5314 Some(res)
5315 }
5316 }
5317 }
5318 pub fn table_get_row_index(&self) -> i32 {
5319 unsafe {
5320 ImGui_TableGetRowIndex()
5321 }
5322 }
5323 pub fn table_get_column_flags(&self, column_n: Option<i32>) -> TableColumnFlags {
5324 let bits = unsafe {
5325 ImGui_TableGetColumnFlags(column_n.unwrap_or(-1))
5326 };
5327 TableColumnFlags::from_bits_truncate(bits)
5328 }
5329 pub fn table_get_column_name(&self, column_n: Option<i32>) -> String {
5330 unsafe {
5331 let c_str = ImGui_TableGetColumnName(column_n.unwrap_or(-1));
5332 CStr::from_ptr(c_str).to_string_lossy().into_owned()
5333 }
5334 }
5335 pub fn table_set_column_enabled(&self, column_n: Option<i32>, enabled: bool) {
5336 unsafe {
5337 ImGui_TableSetColumnEnabled(column_n.unwrap_or(-1), enabled);
5338 };
5339 }
5340 pub fn table_set_bg_color(&self, target: TableBgTarget, color: Color, column_n: Option<i32>) {
5341 unsafe {
5342 ImGui_TableSetBgColor(target.bits(), color.as_u32(), column_n.unwrap_or(-1));
5343 };
5344 }
5345 pub fn table_with_sort_specs(&self, sort_fn: impl FnOnce(&[TableColumnSortSpec])) {
5346 self.table_with_sort_specs_always(|dirty, spec| {
5347 if dirty {
5348 sort_fn(spec);
5349 }
5350 false
5351 })
5352 }
5353 pub fn table_with_sort_specs_always(&self, sort_fn: impl FnOnce(bool, &[TableColumnSortSpec]) -> bool) {
5355 unsafe {
5356 let specs = ImGui_TableGetSortSpecs();
5357 if specs.is_null() {
5358 return;
5359 }
5360 let slice = {
5362 let len = (*specs).SpecsCount as usize;
5363 if len == 0 {
5364 &[]
5365 } else {
5366 let ptr = std::mem::transmute::<*const ImGuiTableColumnSortSpecs, *const TableColumnSortSpec>((*specs).Specs);
5367 std::slice::from_raw_parts(ptr, len)
5368 }
5369 };
5370 (*specs).SpecsDirty = sort_fn((*specs).SpecsDirty, slice);
5371 }
5372 }
5373 }
5374}
5375
5376pub struct DragDropPayloadSetter<'a> {
5378 _dummy: PhantomData<&'a ()>,
5379}
5380
5381pub enum DragDropPayloadCond {
5383 Always,
5384 Once,
5385}
5386
5387impl DragDropPayloadSetter<'_> {
5388 pub fn set(self, type_: impl IntoCStr, data: &[u8], cond: DragDropPayloadCond) -> bool {
5389 let ptr = if data.is_empty() {
5391 null()
5392 } else {
5393 data.as_ptr() as *const c_void
5394 };
5395 let len = data.len();
5396 let cond = match cond {
5397 DragDropPayloadCond::Always => Cond::Always,
5398 DragDropPayloadCond::Once => Cond::Once,
5399 };
5400 unsafe { ImGui_SetDragDropPayload(type_.into().as_ptr(), ptr, len, cond.bits()) }
5401 }
5402}
5403
5404pub struct DragDropPayloadGetter<'a> {
5406 _dummy: PhantomData<&'a ()>,
5407}
5408
5409pub struct DragDropPayload<'a> {
5413 pay: &'a ImGuiPayload,
5414}
5415
5416impl<'a> DragDropPayloadGetter<'a> {
5417 pub fn any(&self, flags: DragDropAcceptFlags) -> Option<DragDropPayload<'a>> {
5418 unsafe {
5419 let pay = ImGui_AcceptDragDropPayload(null(), flags.bits());
5420 if pay.is_null() {
5421 None
5422 } else {
5423 Some(DragDropPayload { pay: &*pay })
5424 }
5425 }
5426 }
5427 pub fn by_type(
5428 &self,
5429 type_: impl IntoCStr,
5430 flags: DragDropAcceptFlags,
5431 ) -> Option<DragDropPayload<'a>> {
5432 unsafe {
5433 let pay = ImGui_AcceptDragDropPayload(type_.into().as_ptr(), flags.bits());
5434 if pay.is_null() {
5435 None
5436 } else {
5437 Some(DragDropPayload { pay: &*pay })
5438 }
5439 }
5440 }
5441 pub fn peek(&self) -> Option<DragDropPayload<'a>> {
5442 unsafe {
5443 let pay = ImGui_GetDragDropPayload();
5444 if pay.is_null() {
5445 None
5446 } else {
5447 Some(DragDropPayload { pay: &*pay })
5448 }
5449 }
5450 }
5451}
5452
5453impl DragDropPayload<'_> {
5454 pub fn is_data_type(&self, type_: impl IntoCStr) -> bool {
5456 if self.pay.DataFrameCount == -1 {
5457 return false;
5458 }
5459 let data_type = unsafe { std::mem::transmute::<&[c_char], &[u8]>(&self.pay.DataType) };
5460 let data_type = CStr::from_bytes_until_nul(data_type).unwrap();
5461 data_type == type_.into().as_ref()
5462 }
5463 pub fn type_(&self) -> Cow<'_, str> {
5464 let data_type = unsafe { std::mem::transmute::<&[c_char], &[u8]>(&self.pay.DataType) };
5465 let data_type = CStr::from_bytes_until_nul(data_type).unwrap();
5466 data_type.to_string_lossy()
5467 }
5468 pub fn is_preview(&self) -> bool {
5469 self.pay.Preview
5470 }
5471 pub fn is_delivery(&self) -> bool {
5472 self.pay.Delivery
5473 }
5474 pub fn data(&self) -> &[u8] {
5475 if self.pay.Data.is_null() {
5476 &[]
5477 } else {
5478 unsafe {
5479 std::slice::from_raw_parts(self.pay.Data as *const u8, self.pay.DataSize as usize)
5480 }
5481 }
5482 }
5483}
5484
5485pub const PAYLOAD_TYPE_COLOR_3F: &CStr =
5486 unsafe { CStr::from_bytes_with_nul_unchecked(IMGUI_PAYLOAD_TYPE_COLOR_3F) };
5487pub const PAYLOAD_TYPE_COLOR_4F: &CStr =
5488 unsafe { CStr::from_bytes_with_nul_unchecked(IMGUI_PAYLOAD_TYPE_COLOR_4F) };
5489
5490#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5495pub struct KeyChord(ImGuiKey);
5496
5497impl KeyChord {
5498 pub fn new(mods: KeyMod, key: Key) -> KeyChord {
5499 KeyChord(ImGuiKey(mods.bits() | key.bits().0))
5500 }
5501 pub fn bits(&self) -> i32 {
5502 self.0.0
5503 }
5504 pub fn from_bits(bits: i32) -> Option<KeyChord> {
5505 let key = bits & !ImGuiKey::ImGuiMod_Mask_.0;
5507 let mods = bits & ImGuiKey::ImGuiMod_Mask_.0;
5508 match (Key::from_bits(ImGuiKey(key)), KeyMod::from_bits(mods)) {
5509 (Some(_), Some(_)) => Some(KeyChord(ImGuiKey(bits))),
5510 _ => None,
5511 }
5512 }
5513 pub fn key(&self) -> Key {
5514 let key = self.bits() & !ImGuiKey::ImGuiMod_Mask_.0;
5515 Key::from_bits(ImGuiKey(key)).unwrap_or(Key::None)
5516 }
5517 pub fn mods(&self) -> KeyMod {
5518 let mods = self.bits() & ImGuiKey::ImGuiMod_Mask_.0;
5519 KeyMod::from_bits_truncate(mods)
5520 }
5521}
5522
5523impl From<Key> for KeyChord {
5524 fn from(value: Key) -> Self {
5525 KeyChord::new(KeyMod::None, value)
5526 }
5527}
5528
5529impl From<(KeyMod, Key)> for KeyChord {
5530 fn from(value: (KeyMod, Key)) -> Self {
5531 KeyChord::new(value.0, value.1)
5532 }
5533}
5534
5535#[repr(transparent)]
5537pub struct TableColumnSortSpec(ImGuiTableColumnSortSpecs);
5538
5539impl std::fmt::Debug for TableColumnSortSpec {
5540 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5541 f.debug_struct("TableColumnSortSpec")
5542 .field("id", &self.id())
5543 .field("index", &self.index())
5544 .field("sort_order", &self.sort_order())
5545 .field("sort_direction", &self.sort_direction())
5546 .finish()
5547 }
5548}
5549
5550impl TableColumnSortSpec {
5551 pub fn id(&self) -> ImGuiID {
5552 self.0.ColumnUserID
5553 }
5554 pub fn index(&self) -> usize {
5555 self.0.ColumnIndex as usize
5556 }
5557 pub fn sort_order(&self) -> usize {
5558 self.0.SortOrder as usize
5559 }
5560 pub fn sort_direction(&self) -> SortDirection {
5561 SortDirection::from_bits(self.0.SortDirection).unwrap_or(SortDirection::None)
5562 }
5563}
5564
5565pub struct DockBuilder {
5566 _dummy: (),
5567}
5568
5569impl DockBuilder {
5570 pub fn set_node_size(&self, node_id: ImGuiID, size: Vector2) {
5571 unsafe {
5572 ImGui_DockBuilderSetNodeSize(node_id, v2_to_im(size));
5573 }
5574 }
5575 pub fn set_node_pos(&self, node_id: ImGuiID, pos: Vector2) {
5576 unsafe {
5577 ImGui_DockBuilderSetNodePos(node_id, v2_to_im(pos));
5578 }
5579 }
5580 pub fn split_node(&self, node_id: ImGuiID, dir: Dir, size_ratio: f32) -> (ImGuiID, ImGuiID) {
5581 unsafe {
5582 let mut id2 = 0;
5583 let id1 = ImGui_DockBuilderSplitNode(
5584 node_id,
5585 dir.bits(),
5586 size_ratio,
5587 std::ptr::null_mut(),
5588 &mut id2,
5589 );
5590 (id1, id2)
5591 }
5592 }
5593 pub fn dock_window(&self, window_name: Id<impl IntoCStr>, node_id: ImGuiID) {
5594 unsafe {
5595 ImGui_DockBuilderDockWindow(window_name.into().as_ptr(), node_id);
5596 }
5597 }
5598 pub fn get_node(&self, node_id: ImGuiID) -> Option<&DockNode> {
5599 unsafe {
5600 let ptr = ImGui_DockBuilderGetNode(node_id);
5601 ptr.as_ref().map(DockNode::cast)
5602 }
5603 }
5604 pub fn get_node_mut(&mut self, node_id: ImGuiID) -> Option<&mut DockNode> {
5605 unsafe {
5606 let ptr = ImGui_DockBuilderGetNode(node_id);
5607 ptr.as_mut().map(DockNode::cast_mut)
5608 }
5609 }
5610}
5611
5612transparent! {
5613 pub struct DockNode(ImGuiDockNode);
5614}
5615
5616impl DockNode {
5617 pub fn local_flags(&self) -> DockNodeFlags {
5618 DockNodeFlags::from_bits_truncate(self.LocalFlags)
5619 }
5620
5621 pub fn set_local_flags(&mut self, flags: DockNodeFlags) {
5622 self.0.LocalFlags = flags.bits();
5624 self.0.MergedFlags = self.0.SharedFlags | self.0.LocalFlags | self.0.LocalFlagsInWindows;
5625 }
5626}
5627
5628transparent_mut! {
5629 #[derive(Debug, Copy, Clone)]
5630 pub struct WindowClass(ImGuiWindowClass);
5631}
5632
5633impl Default for WindowClass {
5634 fn default() -> Self {
5635 WindowClass(ImGuiWindowClass {
5637 ClassId: 0,
5638 ParentViewportId: u32::MAX,
5639 FocusRouteParentWindowId: 0,
5640 ViewportFlagsOverrideSet: 0,
5641 ViewportFlagsOverrideClear: 0,
5642 TabItemFlagsOverrideSet: 0,
5643 DockNodeFlagsOverrideSet: 0,
5644 DockingAlwaysTabBar: false,
5645 DockingAllowUnclassed: true,
5646 PlatformIconData: std::ptr::null_mut(),
5647 })
5648 }
5649}
5650
5651impl WindowClass {
5652 pub fn new() -> Self {
5653 Self::default()
5654 }
5655 pub fn class_id(mut self, id: ImGuiID) -> Self {
5656 self.ClassId = id;
5657 self
5658 }
5659 pub fn parent_viewport_id(mut self, id: Option<ImGuiID>) -> Self {
5660 self.ParentViewportId = id.unwrap_or(u32::MAX);
5661 self
5662 }
5663 pub fn focus_route_parent_window_id(mut self, id: ImGuiID) -> Self {
5664 self.FocusRouteParentWindowId = id;
5665 self
5666 }
5667 pub fn dock_node_flags(mut self, set_flags: DockNodeFlags) -> Self {
5668 self.DockNodeFlagsOverrideSet = set_flags.bits();
5669 self
5670 }
5671 pub fn tab_item_flags(mut self, set_flags: TabItemFlags) -> Self {
5672 self.TabItemFlagsOverrideSet = set_flags.bits();
5673 self
5674 }
5675 pub fn viewport_flags(mut self, set_flags: ViewportFlags, clear_flags: ViewportFlags) -> Self {
5676 self.ViewportFlagsOverrideSet = set_flags.bits();
5677 self.ViewportFlagsOverrideClear = clear_flags.bits();
5678 self
5679 }
5680 pub fn docking_always_tab_bar(mut self, value: bool) -> Self {
5681 self.DockingAlwaysTabBar = value;
5682 self
5683 }
5684 pub fn docking_allow_unclassed(mut self, value: bool) -> Self {
5685 self.DockingAllowUnclassed = value;
5686 self
5687 }
5688}