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 ( $(#[$attr:meta])* $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:item)* }
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 decl_builder!{ @CONSTRUCTOR $(#[$attr])* ( $($constructor)* ) }
1230 }
1231 };
1232 ( @CONSTRUCTOR $(#[$attr:meta])* ( $constructor_0:item $($constructor:item)* ) ) => {
1233 $(#[$attr])* $constructor_0
1234 decl_builder!{ @CONSTRUCTOR $(#[$attr])* ( $($constructor)* ) }
1235 };
1236 ( @CONSTRUCTOR $(#[$attr:meta])* () ) => {
1237 };
1238}
1239
1240macro_rules! decl_builder_setter_ex {
1241 ($name:ident: $ty:ty = $expr:expr) => {
1242 pub fn $name(mut self, $name: $ty) -> Self {
1243 self.$name = $expr;
1244 self
1245 }
1246 };
1247}
1248
1249macro_rules! decl_builder_setter {
1250 ($name:ident: $ty:ty) => {
1251 decl_builder_setter_ex! { $name: $ty = $name.into() }
1252 };
1253}
1254
1255macro_rules! decl_builder_setter_vector2 {
1256 ($name:ident: Vector2) => {
1257 decl_builder_setter_ex! { $name: Vector2 = v2_to_im($name) }
1258 };
1259}
1260
1261macro_rules! decl_builder_with_maybe_opt {
1262 ( $always_run_end:literal
1263 $(#[$attr:meta])*
1264 $sname:ident, $func_beg:ident, $func_end:ident ($($life:lifetime),*) ( $( $gen_n:ident : $gen_d:tt ),* )
1265 (
1266 $(
1267 $arg:ident ($($ty:tt)*) ($pass:expr),
1268 )*
1269 )
1270 { $($extra:tt)* }
1271 { $($constructor:tt)* }
1272 ) => {
1273 #[must_use]
1274 pub struct $sname< $($life,)* $($gen_n : $gen_d, )* P: Pushable = () > {
1275 $(
1276 $arg: $($ty)*,
1277 )*
1278 push: P,
1279 }
1280 impl <$($life,)* $($gen_n : $gen_d, )* P: Pushable > $sname<$($life,)* $($gen_n,)* P > {
1281 pub fn push_for_begin<P2: Pushable>(self, push: P2) -> $sname< $($life,)* $($gen_n,)* (P, P2) > {
1287 $sname {
1288 $(
1289 $arg: self.$arg,
1290 )*
1291 push: (self.push, push),
1292 }
1293 }
1294 pub fn with<R>(self, f: impl FnOnce() -> R) -> Option<R> {
1296 self.with_always(move |opened| { opened.then(f) })
1297 }
1298 pub fn with_always<R>(self, f: impl FnOnce(bool) -> R) -> R {
1301 #[allow(unused_mut)]
1303 let $sname { $(mut $arg, )* push } = self;
1304 let bres = unsafe {
1305 let _guard = push_guard(&push);
1306 $func_beg($($pass,)*)
1307 };
1308 struct EndGuard(bool);
1309 impl Drop for EndGuard {
1310 fn drop(&mut self) {
1311 if self.0 {
1312 unsafe { $func_end(); }
1313 }
1314 }
1315 }
1316 let _guard_2 = EndGuard($always_run_end || bres);
1317 f(bres)
1318 }
1319 $($extra)*
1320 }
1321
1322 impl<A> Ui<A> {
1323 $(#[$attr])*
1324 $($constructor)*
1325 }
1326 };
1327}
1328
1329macro_rules! decl_builder_with {
1330 ( $(#[$attr:meta])* $sname:ident, $($args:tt)* ) => {
1331 decl_builder_with_maybe_opt!{ true $(#[$attr])* $sname, $($args)* }
1332 };
1333}
1334
1335macro_rules! decl_builder_with_opt {
1336 ( $(#[$attr:meta])* $sname:ident, $($args:tt)* ) => {
1337 decl_builder_with_maybe_opt!{ false $(#[$attr])* $sname, $($args)* }
1338 };
1339}
1340
1341decl_builder_with! {Child, ImGui_BeginChild, ImGui_EndChild () (S: IntoCStr)
1342 (
1343 name (S::Temp) (name.as_ptr()),
1344 size (ImVec2) (&size),
1345 child_flags (ChildFlags) (child_flags.bits()),
1346 window_flags (WindowFlags) (window_flags.bits()),
1347 )
1348 {
1349 decl_builder_setter_vector2!{size: Vector2}
1350 decl_builder_setter!{child_flags: ChildFlags}
1351 decl_builder_setter!{window_flags: WindowFlags}
1352 }
1353 {
1354 pub fn child_config<S: IntoCStr>(&self, name: LblId<S>) -> Child<S> {
1355 Child {
1356 name: name.into(),
1357 size: im_vec2(0.0, 0.0),
1358 child_flags: ChildFlags::None,
1359 window_flags: WindowFlags::None,
1360 push: (),
1361 }
1362 }
1363 }
1364}
1365
1366decl_builder_with! {
1367 Window, ImGui_Begin, ImGui_End ('v) (S: IntoCStr)
1369 (
1370 name (S::Temp) (name.as_ptr()),
1371 open (Option<&'v mut bool>) (optional_mut_bool(&mut open)),
1372 flags (WindowFlags) (flags.bits()),
1373 )
1374 {
1375 decl_builder_setter!{open: &'v mut bool}
1376 decl_builder_setter!{flags: WindowFlags}
1377 }
1378 {
1379 pub fn window_config<S: IntoCStr>(&self, name: LblId<S>) -> Window<'_, S> {
1380 Window {
1381 name: name.into(),
1382 open: None,
1383 flags: WindowFlags::None,
1384 push: (),
1385 }
1386 }
1387 }
1388}
1389
1390decl_builder! { MenuItem -> bool, ImGui_MenuItem () (S1: IntoCStr, S2: IntoCStr)
1391 (
1392 label (S1::Temp) (label.as_ptr()),
1393 shortcut (Option<S2::Temp>) (optional_str(&shortcut)),
1394 selected (bool) (selected),
1395 enabled (bool) (enabled),
1396 )
1397 {
1398 pub fn shortcut_opt<S3: IntoCStr>(self, shortcut: Option<S3>) -> MenuItem<'s, S1, S3> {
1399 MenuItem {
1400 _pd: PhantomData,
1401 label: self.label,
1402 shortcut: shortcut.map(|s| s.into()),
1403 selected: self.selected,
1404 enabled: self.enabled,
1405 }
1406 }
1407 pub fn shortcut<S3: IntoCStr>(self, shortcut: S3) -> MenuItem<'s, S1, S3> {
1408 self.shortcut_opt(Some(shortcut))
1409 }
1410 decl_builder_setter!{selected: bool}
1411 decl_builder_setter!{enabled: bool}
1412 }
1413 {
1414 pub fn menu_item_config<S: IntoCStr>(&self, label: LblId<S>) -> MenuItem<'_, S, &str> {
1415 MenuItem {
1416 _pd: PhantomData,
1417 label: label.into(),
1418 shortcut: None,
1419 selected: false,
1420 enabled: true,
1421 }
1422 }
1423 }
1424}
1425
1426decl_builder! {
1427 Button -> bool, ImGui_Button () (S: IntoCStr)
1428 (
1429 label (S::Temp) (label.as_ptr()),
1430 size (ImVec2) (&size),
1431 )
1432 {
1433 decl_builder_setter_vector2!{size: Vector2}
1434 }
1435 {
1436 pub fn button_config<S: IntoCStr>(&self, label: LblId<S>) -> Button<'_, S> {
1437 Button {
1438 _pd: PhantomData,
1439 label: label.into(),
1440 size: im_vec2(0.0, 0.0),
1441 }
1442 }
1443 pub fn button<S: IntoCStr>(&self, label: LblId<S>) -> bool {
1444 self.button_config(label).build()
1445 }
1446 }
1447}
1448
1449decl_builder! {
1450 SmallButton -> bool, ImGui_SmallButton () (S: IntoCStr)
1452 (
1453 label (S::Temp) (label.as_ptr()),
1454 )
1455 {}
1456 {
1457 pub fn small_button_config<S: IntoCStr>(&self, label: LblId<S>) -> SmallButton<'_, S> {
1458 SmallButton {
1459 _pd: PhantomData,
1460 label: label.into(),
1461 }
1462 }
1463 pub fn small_button<S: IntoCStr>(&self, label: LblId<S>) -> bool {
1464 self.small_button_config(label).build()
1465 }
1466 }
1467}
1468
1469decl_builder! {
1470 InvisibleButton -> bool, ImGui_InvisibleButton () (S: IntoCStr)
1472 (
1473 id (S::Temp) (id.as_ptr()),
1474 size (ImVec2) (&size),
1475 flags (ButtonFlags) (flags.bits()),
1476 )
1477 {
1478 decl_builder_setter_vector2!{size: Vector2}
1479 decl_builder_setter!{flags: ButtonFlags}
1480 }
1481 {
1482 pub fn invisible_button_config<S: IntoCStr>(&self, id: S) -> InvisibleButton<'_, S> {
1483 InvisibleButton {
1484 _pd: PhantomData,
1485 id: id.into(),
1486 size: im_vec2(0.0, 0.0),
1487 flags: ButtonFlags::MouseButtonLeft,
1488 }
1489 }
1490 }
1491}
1492
1493decl_builder! {
1494 ArrowButton -> bool, ImGui_ArrowButton () (S: IntoCStr)
1496 (
1497 id (S::Temp) (id.as_ptr()),
1498 dir (Dir) (dir.bits()),
1499 )
1500 {}
1501 {
1502 pub fn arrow_button_config<S: IntoCStr>(&self, id: S, dir: Dir) -> ArrowButton<'_, S> {
1503 ArrowButton {
1504 _pd: PhantomData,
1505 id: id.into(),
1506 dir,
1507 }
1508 }
1509 pub fn arrow_button<S: IntoCStr>(&self, id: S, dir: Dir) -> bool {
1510 self.arrow_button_config(id, dir).build()
1511 }
1512 }
1513}
1514
1515decl_builder! {
1516 Checkbox -> bool, ImGui_Checkbox ('v) (S: IntoCStr)
1517 (
1518 label (S::Temp) (label.as_ptr()),
1519 value (&'v mut bool) (value),
1520 )
1521 {}
1522 {
1523 pub fn checkbox_config<'v, S: IntoCStr>(&self, label: LblId<S>, value: &'v mut bool) -> Checkbox<'_, 'v, S> {
1524 Checkbox {
1525 _pd: PhantomData,
1526 label: label.into(),
1527 value,
1528 }
1529 }
1530 pub fn checkbox<S: IntoCStr>(&self, label: LblId<S>, value: &mut bool) -> bool {
1531 self.checkbox_config(label, value).build()
1532 }
1533 }
1534}
1535
1536decl_builder! { RadioButton -> bool, ImGui_RadioButton () (S: IntoCStr)
1537 (
1538 label (S::Temp) (label.as_ptr()),
1539 active (bool) (active),
1540 )
1541 {}
1542 {
1543 pub fn radio_button_config<S: IntoCStr>(&self, label: LblId<S>, active: bool) -> RadioButton<'_, S> {
1544 RadioButton {
1545 _pd: PhantomData,
1546 label: label.into(),
1547 active,
1548 }
1549 }
1550 }
1551}
1552
1553decl_builder! { ProgressBar -> (), ImGui_ProgressBar () (S: IntoCStr)
1554 (
1555 fraction (f32) (fraction),
1556 size (ImVec2) (&size),
1557 overlay (Option<S::Temp>) (optional_str(&overlay)),
1558 )
1559 {
1560 decl_builder_setter_vector2!{size: Vector2}
1561 pub fn overlay<S2: IntoCStr>(self, overlay: S2) -> ProgressBar<'s, S2> {
1562 ProgressBar {
1563 _pd: PhantomData,
1564 fraction: self.fraction,
1565 size: self.size,
1566 overlay: Some(overlay.into()),
1567 }
1568 }
1569 }
1570 {
1571 pub fn progress_bar_config<'a>(&self, fraction: f32) -> ProgressBar<'_, &'a str> {
1572 ProgressBar {
1573 _pd: PhantomData,
1574 fraction,
1575 size: im_vec2(-f32::MIN_POSITIVE, 0.0),
1576 overlay: None,
1577 }
1578 }
1579 }
1580}
1581
1582decl_builder! {
1583 Image -> (), ImGui_Image ('t) ()
1584 (
1585 texture_ref (TextureRef<'t>) (texture_ref.tex_ref()),
1586 size (ImVec2) (&size),
1587 uv0 (ImVec2) (&uv0),
1588 uv1 (ImVec2) (&uv1),
1589 )
1590 {
1591 decl_builder_setter_vector2!{uv0: Vector2}
1592 decl_builder_setter_vector2!{uv1: Vector2}
1593 }
1594 {
1595 pub fn image_config<'t>(&self, texture_ref: TextureRef<'t>, size: Vector2) -> Image<'_, 't> {
1596 Image {
1597 _pd: PhantomData,
1598 texture_ref,
1599 size: v2_to_im(size),
1600 uv0: im_vec2(0.0, 0.0),
1601 uv1: im_vec2(1.0, 1.0),
1602 }
1603 }
1604 pub fn image_with_custom_rect_config(&self, ridx: CustomRectIndex, scale: f32) -> Image<'_, '_> {
1605 let rr = self.get_custom_rect(ridx).unwrap();
1606 self.image_config(rr.tex_ref, vec2(scale * rr.rect.w as f32, scale * rr.rect.h as f32))
1607 .uv0(im_to_v2(rr.rect.uv0))
1608 .uv1(im_to_v2(rr.rect.uv1))
1609 }
1610 }
1611}
1612
1613decl_builder! {
1614 ImageWithBg -> (), ImGui_ImageWithBg ('t) ()
1616 (
1617 texture_ref (TextureRef<'t>) (texture_ref.tex_ref()),
1618 size (ImVec2) (&size),
1619 uv0 (ImVec2) (&uv0),
1620 uv1 (ImVec2) (&uv1),
1621 bg_col (ImVec4) (&bg_col),
1622 tint_col (ImVec4) (&tint_col),
1623 )
1624 {
1625 decl_builder_setter_vector2!{uv0: Vector2}
1626 decl_builder_setter_vector2!{uv1: Vector2}
1627 decl_builder_setter!{bg_col: Color}
1628 decl_builder_setter!{tint_col: Color}
1629 }
1630 {
1631 pub fn image_with_bg_config<'t>(&self, texture_ref: TextureRef<'t>, size: Vector2) -> ImageWithBg<'_, 't> {
1632 ImageWithBg {
1633 _pd: PhantomData,
1634 texture_ref,
1635 size: v2_to_im(size),
1636 uv0: im_vec2(0.0, 0.0),
1637 uv1: im_vec2(1.0, 1.0),
1638 bg_col: Color::TRANSPARENT.into(),
1639 tint_col: Color::WHITE.into(),
1640 }
1641 }
1642 pub fn image_with_bg_with_custom_rect_config(&self, ridx: CustomRectIndex, scale: f32) -> ImageWithBg<'_, '_> {
1643 let rr = self.get_custom_rect(ridx).unwrap();
1644 self.image_with_bg_config(self.get_atlas_texture_ref(), vec2(scale * rr.rect.w as f32, scale * rr.rect.h as f32))
1645 .uv0(im_to_v2(rr.rect.uv0))
1646 .uv1(im_to_v2(rr.rect.uv1))
1647 }
1648
1649 }
1650}
1651
1652decl_builder! {
1653 ImageButton -> bool, ImGui_ImageButton ('t) (S: IntoCStr)
1654 (
1655 str_id (S::Temp) (str_id.as_ptr()),
1656 texture_ref (TextureRef<'t>) (texture_ref.tex_ref()),
1657 size (ImVec2) (&size),
1658 uv0 (ImVec2) (&uv0),
1659 uv1 (ImVec2) (&uv1),
1660 bg_col (ImVec4) (&bg_col),
1661 tint_col (ImVec4) (&tint_col),
1662 )
1663 {
1664 decl_builder_setter_vector2!{uv0: Vector2}
1665 decl_builder_setter_vector2!{uv1: Vector2}
1666 decl_builder_setter!{bg_col: Color}
1667 decl_builder_setter!{tint_col: Color}
1668 }
1669 {
1670 pub fn image_button_config<'t, S: IntoCStr>(&self, str_id: Id<S>, texture_ref: TextureRef<'t>, size: Vector2) -> ImageButton<'_, 't, S> {
1671 ImageButton {
1672 _pd: PhantomData,
1673 str_id: str_id.into(),
1674 texture_ref,
1675 size: v2_to_im(size),
1676 uv0: im_vec2(0.0, 0.0),
1677 uv1: im_vec2(1.0, 1.0),
1678 bg_col: Color::TRANSPARENT.into(),
1679 tint_col: Color::WHITE.into(),
1680 }
1681 }
1682 pub fn image_button_with_custom_rect_config<S: IntoCStr>(&self, str_id: Id<S>, ridx: CustomRectIndex, scale: f32) -> ImageButton<'_, '_, S> {
1683 let rr = self.get_custom_rect(ridx).unwrap();
1684 self.image_button_config(str_id, rr.tex_ref, vec2(scale * rr.rect.w as f32, scale * rr.rect.h as f32))
1685 .uv0(im_to_v2(rr.rect.uv0))
1686 .uv1(im_to_v2(rr.rect.uv1))
1687 }
1688 }
1689}
1690
1691decl_builder! {
1692 Selectable -> bool, ImGui_Selectable () (S: IntoCStr)
1693 (
1694 label (S::Temp) (label.as_ptr()),
1695 selected (bool) (selected),
1696 flags (SelectableFlags) (flags.bits()),
1697 size (ImVec2) (&size),
1698 )
1699 {
1700 decl_builder_setter!{selected: bool}
1701 decl_builder_setter!{flags: SelectableFlags}
1702 decl_builder_setter_vector2!{size: Vector2}
1703 }
1704 {
1705 pub fn selectable_config<S: IntoCStr>(&self, label: LblId<S>) -> Selectable<'_, S> {
1706 Selectable {
1707 _pd: PhantomData,
1708 label: label.into(),
1709 selected: false,
1710 flags: SelectableFlags::None,
1711 size: im_vec2(0.0, 0.0),
1712 }
1713 }
1714 pub fn selectable<S: IntoCStr>(&self, label: LblId<S>) -> bool {
1715 self.selectable_config(label).build()
1716 }
1717 }
1718}
1719
1720macro_rules! decl_builder_drag {
1721 ( $(#[$attr:meta])* $name:ident $func:ident $cfunc:ident $life:lifetime ($argty:ty) ($ty:ty) ($expr:expr)) => {
1722 decl_builder! {
1723 $(#[$attr])*
1724 $name -> bool, $cfunc ($life) (S: IntoCStr)
1725 (
1726 label (S::Temp) (label.as_ptr()),
1727 value ($ty) ($expr(value)),
1728 speed (f32) (speed),
1729 min ($argty) (min),
1730 max ($argty) (max),
1731 format (Cow<'static, CStr>) (format.as_ptr()),
1732 flags (SliderFlags) (flags.bits()),
1733 )
1734 {
1735 decl_builder_setter!{speed: f32}
1736 pub fn range(mut self, min: $argty, max: $argty) -> Self {
1737 self.min = min;
1738 self.max = max;
1739 self
1740 }
1741 decl_builder_setter!{flags: SliderFlags}
1742 }
1743 {
1744 pub fn $func<$life, S: IntoCStr>(&self, label: LblId<S>, value: $ty) -> $name<'_, $life, S> {
1745 $name {
1746 _pd: PhantomData,
1747 label: label.into(),
1748 value,
1749 speed: 1.0,
1750 min: <$argty>::default(),
1751 max: <$argty>::default(),
1752 format: Cow::Borrowed(c"%.3f"),
1753 flags: SliderFlags::None,
1754 }
1755 }
1756 }
1757 }
1758 };
1759}
1760
1761macro_rules! impl_float_format {
1762 ($name:ident) => {
1763 impl_float_format! {$name c"%g" c"%.0f" c"%.3f" "%.{}f"}
1764 };
1765 ($name:ident $g:literal $f0:literal $f3:literal $f_n:literal) => {
1766 impl<S: IntoCStr> $name<'_, '_, S> {
1767 pub fn display_format(mut self, format: FloatFormat) -> Self {
1768 self.format = match format {
1769 FloatFormat::G => Cow::Borrowed($g),
1770 FloatFormat::F(0) => Cow::Borrowed($f0),
1771 FloatFormat::F(3) => Cow::Borrowed($f3),
1772 FloatFormat::F(n) => Cow::Owned(CString::new(format!($f_n, n)).unwrap()),
1773 };
1774 self
1775 }
1776 }
1777 };
1778}
1779
1780decl_builder_drag! {
1781DragFloat drag_float_config ImGui_DragFloat 'v (f32) (&'v mut f32) (std::convert::identity)}
1782decl_builder_drag! {
1783DragFloat2 drag_float_2_config ImGui_DragFloat2 'v (f32) (&'v mut [f32; 2]) (<[f32]>::as_mut_ptr)}
1784decl_builder_drag! {
1785DragFloat3 drag_float_3_config ImGui_DragFloat3 'v (f32) (&'v mut [f32; 3]) (<[f32]>::as_mut_ptr)}
1786decl_builder_drag! {
1787DragFloat4 drag_float_4_config ImGui_DragFloat4 'v (f32) (&'v mut [f32; 4]) (<[f32]>::as_mut_ptr)}
1788
1789impl_float_format! { DragFloat }
1790impl_float_format! { DragFloat2 }
1791impl_float_format! { DragFloat3 }
1792impl_float_format! { DragFloat4 }
1793
1794decl_builder_drag! { DragInt drag_int_config ImGui_DragInt 'v (i32) (&'v mut i32) (std::convert::identity)}
1795decl_builder_drag! { DragInt2 drag_int_2_config ImGui_DragInt2 'v (i32) (&'v mut [i32; 2]) (<[i32]>::as_mut_ptr)}
1796decl_builder_drag! { DragInt3 drag_int_3_config ImGui_DragInt3 'v (i32) (&'v mut [i32; 3]) (<[i32]>::as_mut_ptr)}
1797decl_builder_drag! { DragInt4 drag_int_4_config ImGui_DragInt4 'v (i32) (&'v mut [i32; 4]) (<[i32]>::as_mut_ptr)}
1798
1799macro_rules! decl_builder_slider {
1800 ( $(#[$attr:meta])* $name:ident $func:ident $cfunc:ident $life:lifetime ($argty:ty) ($ty:ty) ($expr:expr)) => {
1801 decl_builder! {
1802 $(#[$attr])*
1803 $name -> bool, $cfunc ($life) (S: IntoCStr)
1804 (
1805 label (S::Temp) (label.as_ptr()),
1806 value ($ty) ($expr(value)),
1807 min ($argty) (min),
1808 max ($argty) (max),
1809 format (Cow<'static, CStr>) (format.as_ptr()),
1810 flags (SliderFlags) (flags.bits()),
1811 )
1812 {
1813 pub fn range(mut self, min: $argty, max: $argty) -> Self {
1814 self.min = min;
1815 self.max = max;
1816 self
1817 }
1818 decl_builder_setter!{flags: SliderFlags}
1819 }
1820 {
1821 pub fn $func<$life, S: IntoCStr>(&self, label: LblId<S>, value: $ty) -> $name<'_, $life, S> {
1822 $name {
1823 _pd: PhantomData,
1824 label: label.into(),
1825 value,
1826 min: <$argty>::default(),
1827 max: <$argty>::default(),
1828 format: Cow::Borrowed(c"%.3f"),
1829 flags: SliderFlags::None,
1830 }
1831 }
1832 }
1833 }
1834 };
1835}
1836
1837decl_builder_slider! {
1838SliderFloat slider_float_config ImGui_SliderFloat 'v (f32) (&'v mut f32) (std::convert::identity)}
1839decl_builder_slider! {
1840SliderFloat2 slider_float_2_config ImGui_SliderFloat2 'v (f32) (&'v mut [f32; 2]) (<[f32]>::as_mut_ptr)}
1841decl_builder_slider! {
1842SliderFloat3 slider_float_3_config ImGui_SliderFloat3 'v (f32) (&'v mut [f32; 3]) (<[f32]>::as_mut_ptr)}
1843decl_builder_slider! {
1844SliderFloat4 slider_float_4_config ImGui_SliderFloat4 'v (f32) (&'v mut [f32; 4]) (<[f32]>::as_mut_ptr)}
1845
1846impl_float_format! { SliderFloat }
1847impl_float_format! { SliderFloat2 }
1848impl_float_format! { SliderFloat3 }
1849impl_float_format! { SliderFloat4 }
1850
1851decl_builder_slider! {
1852SliderInt slider_int_config ImGui_SliderInt 'v (i32) (&'v mut i32) (std::convert::identity)}
1853decl_builder_slider! {
1854SliderInt2 slider_int_2_config ImGui_SliderInt2 'v (i32) (&'v mut [i32; 2]) (<[i32]>::as_mut_ptr)}
1855decl_builder_slider! {
1856SliderInt3 slider_int_3_config ImGui_SliderInt3 'v (i32) (&'v mut [i32; 3]) (<[i32]>::as_mut_ptr)}
1857decl_builder_slider! {
1858SliderInt4 slider_int_4_config ImGui_SliderInt4 'v (i32) (&'v mut [i32; 4]) (<[i32]>::as_mut_ptr)}
1859
1860decl_builder! {
1861 SliderAngle -> bool, ImGui_SliderAngle ('v) (S: IntoCStr)
1863 (
1864 label (S::Temp) (label.as_ptr()),
1865 v_rad (&'v mut f32) (v_rad),
1866 v_degrees_min (f32) (v_degrees_min),
1867 v_degrees_max (f32) (v_degrees_max),
1868 format (Cow<'static, CStr>) (format.as_ptr()),
1869 flags (SliderFlags) (flags.bits()),
1870 )
1871 {
1872 decl_builder_setter!{v_degrees_max: f32}
1873 decl_builder_setter!{v_degrees_min: f32}
1874 decl_builder_setter!{flags: SliderFlags}
1875 }
1876 {
1877 pub fn slider_angle_config<'v, S: IntoCStr>(&self, label: LblId<S>, v_rad: &'v mut f32) -> SliderAngle<'_, 'v, S> {
1878 SliderAngle {
1879 _pd: PhantomData,
1880 label: label.into(),
1881 v_rad,
1882 v_degrees_min: -360.0,
1883 v_degrees_max: 360.0,
1884 format: Cow::Borrowed(c"%.0f deg"),
1885 flags: SliderFlags::None,
1886 }
1887 }
1888 }
1889}
1890
1891impl_float_format! { SliderAngle c"%g deg" c"%.0f deg" c"%.3f deg" "%.{}f deg"}
1892
1893decl_builder! {
1894 ColorEdit3 -> bool, ImGui_ColorEdit3 ('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_edit_3_config<'v, S: IntoCStr>(&self, label: LblId<S>, color: &'v mut [f32; 3]) -> ColorEdit3<'_, 'v, S> {
1905 ColorEdit3 {
1906 _pd: PhantomData,
1907 label: label.into(),
1908 color,
1909 flags: ColorEditFlags::None,
1910 }
1911 }
1912 }
1913}
1914
1915decl_builder! {
1916 ColorEdit4 -> bool, ImGui_ColorEdit4 ('v) (S: IntoCStr)
1917 (
1918 label (S::Temp) (label.as_ptr()),
1919 color (&'v mut [f32; 4]) (color.as_mut_ptr()),
1920 flags (ColorEditFlags) (flags.bits()),
1921 )
1922 {
1923 decl_builder_setter!{flags: ColorEditFlags}
1924 }
1925 {
1926 pub fn color_edit_4_config<'v, S: IntoCStr>(&self, label: LblId<S>, color: &'v mut Color) -> ColorEdit4<'_, 'v, S> {
1927 ColorEdit4 {
1928 _pd: PhantomData,
1929 label: label.into(),
1930 color: color.as_mut(),
1931 flags: ColorEditFlags::None,
1932 }
1933 }
1934 }
1935}
1936
1937decl_builder! {
1938 ColorPicker3 -> bool, ImGui_ColorPicker3 ('v) (S: IntoCStr)
1939 (
1940 label (S::Temp) (label.as_ptr()),
1941 color (&'v mut [f32; 3]) (color.as_mut_ptr()),
1942 flags (ColorEditFlags) (flags.bits()),
1943 )
1944 {
1945 decl_builder_setter!{flags: ColorEditFlags}
1946 }
1947 {
1948 pub fn color_picker_3_config<'v, S: IntoCStr>(&self, label: LblId<S>, color: &'v mut [f32; 3]) -> ColorPicker3<'_, 'v, S> {
1949 ColorPicker3 {
1950 _pd: PhantomData,
1951 label: label.into(),
1952 color,
1953 flags: ColorEditFlags::None,
1954 }
1955 }
1956 }
1957}
1958
1959decl_builder! {
1960 ColorPicker4 -> bool, ImGui_ColorPicker4 ('v) (S: IntoCStr)
1961 (
1962 label (S::Temp) (label.as_ptr()),
1963 color (&'v mut [f32; 4]) (color.as_mut_ptr()),
1964 flags (ColorEditFlags) (flags.bits()),
1965 ref_col (Option<Color>) (ref_col.as_ref().map(|x| x.as_ref().as_ptr()).unwrap_or(null())),
1966 )
1967 {
1968 decl_builder_setter!{flags: ColorEditFlags}
1969 pub fn ref_color(mut self, ref_color: Color) -> Self {
1970 self.ref_col = Some(ref_color);
1971 self
1972 }
1973 }
1974 {
1975 pub fn color_picker_4_config<'v, S: IntoCStr>(&self, label: LblId<S>, color: &'v mut Color) -> ColorPicker4<'_, 'v, S> {
1976 ColorPicker4 {
1977 _pd: PhantomData,
1978 label: label.into(),
1979 color: color.as_mut(),
1980 flags: ColorEditFlags::None,
1981 ref_col: None,
1982 }
1983 }
1984 }
1985}
1986
1987unsafe extern "C" fn input_text_callback(data: *mut ImGuiInputTextCallbackData) -> i32 {
1988 unsafe {
1989 let data = &mut *data;
1990 if data.EventFlag == InputTextFlags::CallbackResize.bits() {
1991 let this = &mut *(data.UserData as *mut String);
1992 let extra = (data.BufSize as usize).saturating_sub(this.len());
1993 this.reserve(extra);
1994 data.Buf = this.as_mut_ptr() as *mut c_char;
1995 }
1996 0
1997 }
1998}
1999
2000#[inline]
2001fn text_pre_edit(text: &mut String) {
2002 text.push('\0');
2004}
2005
2006#[inline]
2007unsafe fn text_post_edit(text: &mut String) {
2008 unsafe {
2009 let buf = text.as_mut_vec();
2010 let len = CStr::from_ptr(buf.as_ptr() as *const c_char)
2012 .to_bytes()
2013 .len();
2014 buf.set_len(len);
2015 }
2016}
2017
2018unsafe fn input_text_wrapper(
2019 label: *const c_char,
2020 text: &mut String,
2021 flags: InputTextFlags,
2022) -> bool {
2023 unsafe {
2024 let flags = flags | InputTextFlags::CallbackResize;
2025
2026 text_pre_edit(text);
2027 let r = ImGui_InputText(
2028 label,
2029 text.as_mut_ptr() as *mut c_char,
2030 text.capacity(),
2031 flags.bits(),
2032 Some(input_text_callback),
2033 text as *mut String as *mut c_void,
2034 );
2035 text_post_edit(text);
2036 r
2037 }
2038}
2039
2040decl_builder! {
2041 InputText -> bool, input_text_wrapper ('v) (S: IntoCStr)
2042 (
2043 label (S::Temp) (label.as_ptr()),
2044 text (&'v mut String) (text),
2045 flags (InputTextFlags) (flags),
2046 )
2047 {
2048 decl_builder_setter!{flags: InputTextFlags}
2049 }
2050 {
2051 pub fn input_text_config<'v, S: IntoCStr>(&self, label: LblId<S>, text: &'v mut String) -> InputText<'_, 'v, S> {
2052 InputText {
2053 _pd: PhantomData,
2054 label: label.into(),
2055 text,
2056 flags: InputTextFlags::None,
2057 }
2058 }
2059 }
2060}
2061
2062unsafe fn input_os_string_wrapper(
2063 label: *const c_char,
2064 os_string: &mut OsString,
2065 flags: InputTextFlags,
2066) -> bool {
2067 unsafe {
2068 let s = std::mem::take(os_string).into_string();
2069 let mut s = match s {
2070 Ok(s) => s,
2071 Err(os) => os.to_string_lossy().into_owned(),
2072 };
2073 let res = input_text_wrapper(label, &mut s, flags);
2074 *os_string = OsString::from(s);
2075 res
2076 }
2077}
2078
2079decl_builder! {
2080 InputOsString -> bool, input_os_string_wrapper ('v) (S: IntoCStr)
2081 (
2082 label (S::Temp) (label.as_ptr()),
2083 text (&'v mut OsString) (text),
2084 flags (InputTextFlags) (flags),
2085 )
2086 {
2087 decl_builder_setter!{flags: InputTextFlags}
2088 }
2089 {
2090 pub fn input_os_string_config<'v, S: IntoCStr>(&self, label: LblId<S>, text: &'v mut OsString) -> InputOsString<'_, 'v, S> {
2091 InputOsString {
2092 _pd: PhantomData,
2093 label: label.into(),
2094 text,
2095 flags: InputTextFlags::None,
2096 }
2097 }
2098 }
2099}
2100
2101unsafe fn input_text_multiline_wrapper(
2102 label: *const c_char,
2103 text: &mut String,
2104 size: &ImVec2,
2105 flags: InputTextFlags,
2106) -> bool {
2107 unsafe {
2108 let flags = flags | InputTextFlags::CallbackResize;
2109 text_pre_edit(text);
2110 let r = ImGui_InputTextMultiline(
2111 label,
2112 text.as_mut_ptr() as *mut c_char,
2113 text.capacity(),
2114 size,
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! {
2125 InputTextMultiline -> bool, input_text_multiline_wrapper ('v) (S: IntoCStr)
2126 (
2127 label (S::Temp) (label.as_ptr()),
2128 text (&'v mut String) (text),
2129 size (ImVec2) (&size),
2130 flags (InputTextFlags) (flags),
2131 )
2132 {
2133 decl_builder_setter!{flags: InputTextFlags}
2134 decl_builder_setter_vector2!{size: Vector2}
2135 }
2136 {
2137 pub fn input_text_multiline_config<'v, S: IntoCStr>(&self, label: LblId<S>, text: &'v mut String) -> InputTextMultiline<'_, 'v, S> {
2138 InputTextMultiline {
2139 _pd: PhantomData,
2140 label:label.into(),
2141 text,
2142 flags: InputTextFlags::None,
2143 size: im_vec2(0.0, 0.0),
2144 }
2145 }
2146 }
2147}
2148
2149unsafe fn input_text_hint_wrapper(
2150 label: *const c_char,
2151 hint: *const c_char,
2152 text: &mut String,
2153 flags: InputTextFlags,
2154) -> bool {
2155 unsafe {
2156 let flags = flags | InputTextFlags::CallbackResize;
2157 text_pre_edit(text);
2158 let r = ImGui_InputTextWithHint(
2159 label,
2160 hint,
2161 text.as_mut_ptr() as *mut c_char,
2162 text.capacity(),
2163 flags.bits(),
2164 Some(input_text_callback),
2165 text as *mut String as *mut c_void,
2166 );
2167 text_post_edit(text);
2168 r
2169 }
2170}
2171
2172decl_builder! {
2173 InputTextHint -> bool, input_text_hint_wrapper ('v) (S1: IntoCStr, S2: IntoCStr)
2174 (
2175 label (S1::Temp) (label.as_ptr()),
2176 hint (S2::Temp) (hint.as_ptr()),
2177 text (&'v mut String) (text),
2178 flags (InputTextFlags) (flags),
2179 )
2180 {
2181 decl_builder_setter!{flags: InputTextFlags}
2182 }
2183 {
2184 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> {
2185 InputTextHint {
2186 _pd: PhantomData,
2187 label:label.into(),
2188 hint: hint.into(),
2189 text,
2190 flags: InputTextFlags::None,
2191 }
2192 }
2193 }
2194}
2195
2196pub enum FloatFormat {
2200 F(u32),
2202 G,
2204}
2205
2206decl_builder! {
2207 InputFloat -> bool, ImGui_InputFloat ('v) (S: IntoCStr)
2209 (
2210 label (S::Temp) (label.as_ptr()),
2211 value (&'v mut f32) (value),
2212 step (f32) (step),
2213 step_fast (f32) (step_fast),
2214 format (Cow<'static, CStr>) (format.as_ptr()),
2215 flags (InputTextFlags) (flags.bits()),
2216 )
2217 {
2218 decl_builder_setter!{flags: InputTextFlags}
2219 decl_builder_setter!{step: f32}
2220 decl_builder_setter!{step_fast: f32}
2221 }
2222 {
2223 pub fn input_float_config<'v, S: IntoCStr>(&self, label: LblId<S>, value: &'v mut f32) -> InputFloat<'_, 'v, S> {
2224 InputFloat {
2225 _pd: PhantomData,
2226 label:label.into(),
2227 value,
2228 step: 0.0,
2229 step_fast: 0.0,
2230 format: Cow::Borrowed(c"%.3f"),
2231 flags: InputTextFlags::None,
2232 }
2233 }
2234 }
2235}
2236
2237decl_builder! {
2238 InputInt -> bool, ImGui_InputInt ('v) (S: IntoCStr)
2239 (
2240 label (S::Temp) (label.as_ptr()),
2241 value (&'v mut i32) (value),
2242 step (i32) (step),
2243 step_fast (i32) (step_fast),
2244 flags (InputTextFlags) (flags.bits()),
2245 )
2246 {
2247 decl_builder_setter!{flags: InputTextFlags}
2248 decl_builder_setter!{step: i32}
2249 decl_builder_setter!{step_fast: i32}
2250 }
2251 {
2252 pub fn input_int_config<'v, S: IntoCStr>(&self, label: LblId<S>, value: &'v mut i32) -> InputInt<'_, 'v, S> {
2254 InputInt {
2255 _pd: PhantomData,
2256 label:label.into(),
2257 value,
2258 step: 1,
2259 step_fast: 100,
2260 flags: InputTextFlags::None,
2261 }
2262 }
2263 }
2264}
2265
2266macro_rules! decl_builder_input_f {
2267 ( $(#[$attr:meta])* $name:ident $func:ident $cfunc:ident $len:literal) => {
2268 decl_builder! {
2269 $(#[$attr])*
2270 $name -> bool, $cfunc ('v) (S: IntoCStr)
2271 (
2272 label (S::Temp) (label.as_ptr()),
2273 value (&'v mut [f32; $len]) (value.as_mut_ptr()),
2274 format (Cow<'static, CStr>) (format.as_ptr()),
2275 flags (InputTextFlags) (flags.bits()),
2276 )
2277 {
2278 decl_builder_setter!{flags: InputTextFlags}
2279 }
2280 {
2281 pub fn $func<'v, S: IntoCStr>(&self, label: LblId<S>, value: &'v mut [f32; $len]) -> $name<'_, 'v, S> {
2282 $name {
2283 _pd: PhantomData,
2284 label: label.into(),
2285 value,
2286 format: Cow::Borrowed(c"%.3f"),
2287 flags: InputTextFlags::None,
2288 }
2289 }
2290 }
2291 }
2292 };
2293}
2294
2295decl_builder_input_f! {
2296InputFloat2 input_float_2_config ImGui_InputFloat2 2}
2298decl_builder_input_f! {
2299InputFloat3 input_float_3_config ImGui_InputFloat3 3}
2301decl_builder_input_f! {
2302InputFloat4 input_float_4_config ImGui_InputFloat4 4}
2304
2305impl_float_format! { InputFloat }
2306impl_float_format! { InputFloat2 }
2307impl_float_format! { InputFloat3 }
2308impl_float_format! { InputFloat4 }
2309
2310macro_rules! decl_builder_input_i {
2311 ( $(#[$attr:meta])* $name:ident $func:ident $cfunc:ident $len:literal) => {
2312 decl_builder! {
2313 $(#[$attr])*
2314 $name -> bool, $cfunc ('v) (S: IntoCStr)
2315 (
2316 label (S::Temp) (label.as_ptr()),
2317 value (&'v mut [i32; $len]) (value.as_mut_ptr()),
2318 flags (InputTextFlags) (flags.bits()),
2319 )
2320 {
2321 decl_builder_setter!{flags: InputTextFlags}
2322 }
2323 {
2324 pub fn $func<'v, S: IntoCStr>(&self, label: LblId<S>, value: &'v mut [i32; $len]) -> $name<'_, 'v, S> {
2325 $name {
2326 _pd: PhantomData,
2327 label: label.into(),
2328 value,
2329 flags: InputTextFlags::None,
2330 }
2331 }
2332 }
2333 }
2334 };
2335}
2336
2337decl_builder_input_i! {
2338InputInt2 input_int_2_config ImGui_InputInt2 2}
2340decl_builder_input_i! {
2341InputInt3 input_int_3_config ImGui_InputInt3 3}
2343decl_builder_input_i! {
2344InputInt4 input_int_4_config ImGui_InputInt4 4}
2346
2347decl_builder_with_opt! {
2348 Menu, ImGui_BeginMenu, ImGui_EndMenu () (S: IntoCStr)
2349 (
2350 name (S::Temp) (name.as_ptr()),
2351 enabled (bool) (enabled),
2352 )
2353 {
2354 decl_builder_setter!{enabled: bool}
2355 }
2356 {
2357 pub fn menu_config<S: IntoCStr>(&self, name: LblId<S>) -> Menu<S> {
2358 Menu {
2359 name: name.into(),
2360 enabled: true,
2361 push: (),
2362 }
2363 }
2364 }
2365}
2366
2367decl_builder_with_opt! {
2368 CollapsingHeader, ImGui_CollapsingHeader, no_op () (S: IntoCStr)
2369 (
2370 label (S::Temp) (label.as_ptr()),
2371 flags (TreeNodeFlags) (flags.bits()),
2372 )
2373 {
2374 decl_builder_setter!{flags: TreeNodeFlags}
2375 }
2376 {
2377 pub fn collapsing_header_config<S: IntoCStr>(&self, label: LblId<S>) -> CollapsingHeader<S> {
2378 CollapsingHeader {
2379 label: label.into(),
2380 flags: TreeNodeFlags::None,
2381 push: (),
2382 }
2383 }
2384 }
2385}
2386
2387enum LabelId<'a, S: IntoCStr, H: Hashable> {
2388 LblId(LblId<S>),
2389 LabelId(&'a str, H),
2390}
2391
2392unsafe fn tree_node_ex_helper<S: IntoCStr, H: Hashable>(
2393 label_id: LabelId<'_, S, H>,
2394 flags: TreeNodeFlags,
2395) -> bool {
2396 unsafe {
2397 match label_id {
2398 LabelId::LblId(lbl) => ImGui_TreeNodeEx(lbl.into().as_ptr(), flags.bits()),
2399 LabelId::LabelId(lbl, id) => {
2400 let (start, end) = text_ptrs(lbl);
2401 ImGui_TreeNodeBehavior(id.get_id(), flags.bits(), start, end)
2403 }
2404 }
2405 }
2406}
2407
2408decl_builder_with_opt! {
2409 TreeNode, tree_node_ex_helper, ImGui_TreePop ('a) (S: IntoCStr, H: Hashable)
2410 (
2411 label (LabelId<'a, S, H>) (label),
2412 flags (TreeNodeFlags) (flags),
2413 )
2414 {
2415 decl_builder_setter!{flags: TreeNodeFlags}
2416 }
2417 {
2418 pub fn tree_node_config<S: IntoCStr>(&self, label: LblId<S>) -> TreeNode<'static, S, usize> {
2419 TreeNode {
2420 label: LabelId::LblId(label),
2421 flags: TreeNodeFlags::None,
2422 push: (),
2423 }
2424 }
2425 pub fn tree_node_ex_config<'a, H: Hashable>(&self, id: H, label: &'a str) -> TreeNode<'a, &'a str, H> {
2426 TreeNode {
2427 label: LabelId::LabelId(label, id),
2428 flags: TreeNodeFlags::None,
2429 push: (),
2430 }
2431 }
2432 }
2433}
2434
2435decl_builder_with_opt! {
2436 Popup, ImGui_BeginPopup, ImGui_EndPopup () (S: IntoCStr)
2437 (
2438 str_id (S::Temp) (str_id.as_ptr()),
2439 flags (WindowFlags) (flags.bits()),
2440 )
2441 {
2442 decl_builder_setter!{flags: WindowFlags}
2443 }
2444 {
2445 pub fn popup_config<S: IntoCStr>(&self, str_id: Id<S>) -> Popup<S> {
2446 Popup {
2447 str_id: str_id.into(),
2448 flags: WindowFlags::None,
2449 push: (),
2450 }
2451 }
2452 }
2453}
2454
2455enum PopupOpened<'a> {
2456 Literal(bool),
2457 Reference(&'a mut bool),
2458 None,
2459}
2460
2461impl PopupOpened<'_> {
2462 unsafe fn pointer(&mut self) -> *mut bool {
2463 match self {
2464 PopupOpened::Literal(x) => x,
2465 PopupOpened::Reference(r) => *r,
2466 PopupOpened::None => std::ptr::null_mut(),
2467 }
2468 }
2469}
2470
2471decl_builder_with_opt! {
2472 PopupModal, ImGui_BeginPopupModal, ImGui_EndPopup ('a) (S: IntoCStr)
2474 (
2475 name (S::Temp) (name.as_ptr()),
2476 opened (PopupOpened<'a>) (opened.pointer()),
2477 flags (WindowFlags) (flags.bits()),
2478 )
2479 {
2480 decl_builder_setter!{flags: WindowFlags}
2481
2482 pub fn close_button(mut self, close_button: bool) -> Self {
2483 self.opened = if close_button { PopupOpened::Literal(true) } else { PopupOpened::None };
2484 self
2485 }
2486
2487 pub fn opened(self, opened: Option<&'a mut bool>) -> PopupModal<'a, S, P> {
2488 let opened = match opened {
2489 Some(b) => PopupOpened::Reference(b),
2490 None => PopupOpened::None,
2491 };
2492 PopupModal {
2493 opened,
2494 .. self
2495 }
2496 }
2497 }
2498 {
2499 pub fn popup_modal_config<S: IntoCStr>(&self, name: LblId<S>) -> PopupModal<'static, S> {
2500 PopupModal {
2501 name: name.into(),
2502 opened: PopupOpened::None,
2503 flags: WindowFlags::None,
2504 push: (),
2505 }
2506 }
2507 }
2508}
2509
2510macro_rules! decl_builder_popup_context {
2511 ($struct:ident $begin:ident $do_function:ident) => {
2512 decl_builder_with_opt! {
2513 $struct, $begin, ImGui_EndPopup () (S: IntoCStr)
2515 (
2516 str_id (Option<S::Temp>) (optional_str(&str_id)),
2517 flags (PopupFlags) (flags.bits()),
2518 )
2519 {
2520 decl_builder_setter!{flags: PopupFlags}
2521 pub fn str_id<S2: IntoCStr>(self, str_id: LblId<S2>) -> $struct<S2, P> {
2522 $struct {
2523 str_id: Some(str_id.into()),
2524 flags: self.flags,
2525 push: self.push,
2526 }
2527 }
2528
2529 }
2530 {
2531 pub fn $do_function<'a>(&self) -> $struct<&'a str> {
2532 $struct {
2539 str_id: None,
2540 flags: PopupFlags::None,
2541 push: (),
2542 }
2543 }
2544 }
2545 }
2546 };
2547}
2548
2549decl_builder_popup_context! {PopupContextItem ImGui_BeginPopupContextItem popup_context_item_config}
2550decl_builder_popup_context! {PopupContextWindow ImGui_BeginPopupContextWindow popup_context_window_config}
2551decl_builder_popup_context! {PopupContextVoid ImGui_BeginPopupContextVoid popup_context_void_config}
2552
2553decl_builder_with_opt! {
2554 Combo, ImGui_BeginCombo, ImGui_EndCombo () (S1: IntoCStr, S2: IntoCStr)
2556 (
2557 label (S1::Temp) (label.as_ptr()),
2558 preview_value (Option<S2::Temp>) (optional_str(&preview_value)),
2559 flags (ComboFlags) (flags.bits()),
2560 )
2561 {
2562 decl_builder_setter!{flags: ComboFlags}
2563 pub fn preview_value_opt<S3: IntoCStr>(self, preview_value: Option<S3>) -> Combo<S1, S3> {
2564 Combo {
2565 label: self.label,
2566 preview_value: preview_value.map(|x| x.into()),
2567 flags: ComboFlags::None,
2568 push: (),
2569 }
2570 }
2571 pub fn preview_value<S3: IntoCStr>(self, preview_value: S3) -> Combo<S1, S3> {
2572 self.preview_value_opt(Some(preview_value))
2573 }
2574 }
2575 {
2576 pub fn combo_config<'a, S: IntoCStr>(&self, label: LblId<S>) -> Combo<S, &'a str> {
2577 Combo {
2578 label: label.into(),
2579 preview_value: None,
2580 flags: ComboFlags::None,
2581 push: (),
2582 }
2583 }
2584 pub fn combo<V: Copy + PartialEq, S1: IntoCStr, S2: IntoCStr>(
2586 &self,
2587 label: LblId<S1>,
2588 values: impl IntoIterator<Item=V>,
2589 f_name: impl Fn(V) -> S2,
2590 current: &mut V
2591 ) -> bool
2592 {
2593 let mut changed = false;
2594 self.combo_config(label)
2595 .preview_value(f_name(*current))
2596 .with(|| {
2597 for (i, val) in values.into_iter().enumerate() {
2598 if self.selectable_config(lbl_id(f_name(val), i.to_string()))
2599 .selected(*current == val)
2600 .build()
2601 {
2602 *current = val;
2603 changed = true;
2604 }
2605 }
2606 });
2607 changed
2608 }
2609 }
2610}
2611
2612decl_builder_with_opt! {
2613 ListBox, ImGui_BeginListBox, ImGui_EndListBox () (S: IntoCStr)
2615 (
2616 label (S::Temp) (label.as_ptr()),
2617 size (ImVec2) (&size),
2618 )
2619 {
2620 decl_builder_setter_vector2!{size: Vector2}
2621 }
2622 {
2623 pub fn list_box_config<S: IntoCStr>(&self, label: LblId<S>) -> ListBox<S> {
2624 ListBox {
2625 label: label.into(),
2626 size: im_vec2(0.0, 0.0),
2627 push: (),
2628 }
2629 }
2630 pub fn list_box<V: Copy + PartialEq, S1: IntoCStr, S2: IntoCStr>(
2632 &self,
2633 label: LblId<S1>,
2634 mut height_in_items: i32,
2635 values: impl IntoIterator<Item=V>,
2636 f_name: impl Fn(V) -> S2,
2637 current: &mut V
2638 ) -> bool
2639 {
2640 if height_in_items < 0 {
2642 height_in_items = 7;
2644 }
2645 let height_in_items_f = height_in_items as f32 + 0.25;
2646 let height_in_pixels = self.get_text_line_height_with_spacing() * height_in_items_f + self.style().FramePadding.y * 2.0;
2647
2648 let mut changed = false;
2649 self.list_box_config(label)
2650 .size(vec2(0.0, height_in_pixels.floor()))
2651 .with(|| {
2652 for (i, val) in values.into_iter().enumerate() {
2653 if self.selectable_config(lbl_id(f_name(val), i.to_string()))
2654 .selected(*current == val)
2655 .build()
2656 {
2657 *current = val;
2658 changed = true;
2659 }
2660 }
2661 });
2662 changed
2663 }
2664 }
2665}
2666
2667decl_builder_with_opt! {
2668 TabBar, ImGui_BeginTabBar, ImGui_EndTabBar () (S: IntoCStr)
2670 (
2671 str_id (S::Temp) (str_id.as_ptr()),
2672 flags (TabBarFlags) (flags.bits()),
2673 )
2674 {
2675 decl_builder_setter!{flags: TabBarFlags}
2676 }
2677 {
2678 pub fn tab_bar_config<S: IntoCStr>(&self, str_id: LblId<S>) -> TabBar<S> {
2679 TabBar {
2680 str_id: str_id.into(),
2681 flags: TabBarFlags::None,
2682 push: (),
2683 }
2684 }
2685 }
2686}
2687
2688decl_builder_with_opt! {
2689 TabItem, ImGui_BeginTabItem, ImGui_EndTabItem ('o) (S: IntoCStr)
2691 (
2692 str_id (S::Temp) (str_id.as_ptr()),
2693 opened (Option<&'o mut bool>) (optional_mut_bool(&mut opened)),
2694 flags (TabItemFlags) (flags.bits()),
2695 )
2696 {
2697 decl_builder_setter!{flags: TabItemFlags}
2698 decl_builder_setter!{opened: &'o mut bool}
2699 }
2700 {
2701 pub fn tab_item_config<S: IntoCStr>(&self, str_id: LblId<S>) -> TabItem<'_, S> {
2702 TabItem {
2703 str_id: str_id.into(),
2704 opened: None,
2705 flags: TabItemFlags::None,
2706 push: (),
2707 }
2708 }
2709 pub fn tab_item_button(label: LblId<impl IntoCStr>, flags: TabItemFlags) -> bool {
2710 unsafe {
2711 ImGui_TabItemButton(label.into().as_ptr(), flags.bits())
2712 }
2713 }
2714 pub fn set_tab_item_closed(tab_or_docked_window_label: LblId<impl IntoCStr>) {
2715 unsafe {
2716 ImGui_SetTabItemClosed(tab_or_docked_window_label.into().as_ptr());
2717 }
2718 }
2719 }
2720}
2721
2722#[derive(Copy, Clone, Default, Debug)]
2724pub enum SameLine {
2725 #[default]
2727 Default,
2728 OffsetFromStart(f32),
2732 Spacing(f32),
2736}
2737
2738impl<A> Ui<A> {
2739 unsafe fn push_callback<X>(&self, mut cb: impl FnMut(*mut A, X) + 'static) -> usize {
2741 let cb = Box::new(move |data: *mut A, ptr: *mut c_void| {
2742 let x = ptr as *mut X;
2743 cb(data, unsafe { std::ptr::read(x) });
2744 });
2745 let mut callbacks = self.callbacks.borrow_mut();
2746 let id = callbacks.len();
2747
2748 callbacks.push(cb);
2749 merge_generation(id, self.generation)
2750 }
2751 unsafe fn run_callback<X>(id: usize, x: X) {
2752 unsafe {
2753 let user_data = RawContext::current().io().BackendLanguageUserData;
2754 if user_data.is_null() {
2755 return;
2756 }
2757 let ui = &*(user_data as *const Self);
2759 let Some(id) = remove_generation(id, ui.generation) else {
2760 eprintln!("lost generation callback");
2761 return;
2762 };
2763
2764 let mut callbacks = ui.callbacks.borrow_mut();
2765 let cb = &mut callbacks[id];
2766 let mut x = MaybeUninit::new(x);
2768 cb(ui.data, x.as_mut_ptr() as *mut c_void);
2769 }
2770 }
2771
2772 pub fn get_clipboard_text(&self) -> String {
2773 unsafe {
2774 CStr::from_ptr(ImGui_GetClipboardText())
2775 .to_string_lossy()
2776 .into_owned()
2777 }
2778 }
2779 pub fn set_clipboard_text(&self, text: impl IntoCStr) {
2780 let text = text.into();
2781 unsafe { ImGui_SetClipboardText(text.as_ptr()) }
2782 }
2783 pub fn set_next_window_size_constraints_callback(
2784 &self,
2785 size_min: Vector2,
2786 size_max: Vector2,
2787 mut cb: impl FnMut(SizeCallbackData<'_>) + 'static,
2788 ) {
2789 unsafe {
2790 let id = self.push_callback(move |_, scd| cb(scd));
2793 ImGui_SetNextWindowSizeConstraints(
2794 &v2_to_im(size_min),
2795 &v2_to_im(size_max),
2796 Some(call_size_callback::<A>),
2797 id as *mut c_void,
2798 );
2799 }
2800 }
2801 pub fn set_next_window_size_constraints(&self, size_min: Vector2, size_max: Vector2) {
2804 unsafe {
2805 ImGui_SetNextWindowSizeConstraints(
2806 &v2_to_im(size_min),
2807 &v2_to_im(size_max),
2808 None,
2809 null_mut(),
2810 );
2811 }
2812 }
2813 pub fn set_next_item_width(&self, item_width: f32) {
2816 unsafe {
2817 ImGui_SetNextItemWidth(item_width);
2818 }
2819 }
2820 pub fn set_next_item_open(&self, is_open: bool, cond: Cond) {
2822 unsafe {
2823 ImGui_SetNextItemOpen(is_open, cond.bits());
2824 }
2825 }
2826 pub fn set_next_item_storage_id(&self, id: ImGuiID) {
2828 unsafe { ImGui_SetNextItemStorageID(id) }
2829 }
2830 pub fn tree_node_to_label_spacing(&self) -> f32 {
2833 unsafe { ImGui_GetTreeNodeToLabelSpacing() }
2834 }
2835 pub fn tree_node_get_open(&self, id: ImGuiID) -> bool {
2837 unsafe { ImGui_TreeNodeGetOpen(id) }
2838 }
2839 pub fn set_keyboard_focus_here(&self, offset: i32) {
2842 unsafe { ImGui_SetKeyboardFocusHere(offset) }
2843 }
2844
2845 with_begin_end! {
2846 group ImGui_BeginGroup ImGui_EndGroup ()
2848 }
2849 with_begin_end! {
2850 disabled ImGui_BeginDisabled ImGui_EndDisabled (
2852 disabled (bool) (disabled),
2853 )
2854 }
2855 with_begin_end! {
2856 clip_rect ImGui_PushClipRect ImGui_PopClipRect (
2858 clip_rect_min (Vector2) (&v2_to_im(clip_rect_min)),
2859 clip_rect_max (Vector2) (&v2_to_im(clip_rect_max)),
2860 intersect_with_current_clip_rect (bool) (intersect_with_current_clip_rect),
2861 )
2862 }
2863
2864 with_begin_end_opt! {
2865 main_menu_bar ImGui_BeginMainMenuBar ImGui_EndMainMenuBar ()
2867 }
2868 with_begin_end_opt! {
2869 menu_bar ImGui_BeginMenuBar ImGui_EndMenuBar ()
2871 }
2872 with_begin_end_opt! {
2873 tooltip ImGui_BeginTooltip ImGui_EndTooltip ()
2875 }
2876 with_begin_end_opt! {
2877 item_tooltip ImGui_BeginItemTooltip ImGui_EndTooltip ()
2879 }
2880
2881 pub fn with_push<R>(&self, push: impl Pushable, f: impl FnOnce() -> R) -> R {
2883 unsafe {
2884 let _guard = push_guard(&push);
2885 f()
2886 }
2887 }
2888 pub fn show_demo_window(&self, mut show: Option<&mut bool>) {
2891 unsafe {
2892 ImGui_ShowDemoWindow(optional_mut_bool(&mut show));
2893 }
2894 }
2895 pub fn set_next_window_pos(&self, pos: Vector2, cond: Cond, pivot: Vector2) {
2897 unsafe {
2898 ImGui_SetNextWindowPos(&v2_to_im(pos), cond.bits(), &v2_to_im(pivot));
2899 }
2900 }
2901 pub fn set_next_window_size(&self, size: Vector2, cond: Cond) {
2903 unsafe {
2904 ImGui_SetNextWindowSize(&v2_to_im(size), cond.bits());
2905 }
2906 }
2907 pub fn set_next_window_content_size(&self, size: Vector2) {
2909 unsafe {
2910 ImGui_SetNextWindowContentSize(&v2_to_im(size));
2911 }
2912 }
2913
2914 pub fn set_next_window_collapsed(&self, collapsed: bool, cond: Cond) {
2916 unsafe {
2917 ImGui_SetNextWindowCollapsed(collapsed, cond.bits());
2918 }
2919 }
2920
2921 pub fn set_next_window_focus(&self) {
2923 unsafe {
2924 ImGui_SetNextWindowFocus();
2925 }
2926 }
2927
2928 pub fn set_next_window_scroll(&self, scroll: Vector2) {
2930 unsafe {
2931 ImGui_SetNextWindowScroll(&v2_to_im(scroll));
2932 }
2933 }
2934
2935 pub fn set_next_window_bg_alpha(&self, alpha: f32) {
2937 unsafe {
2938 ImGui_SetNextWindowBgAlpha(alpha);
2939 }
2940 }
2941 pub fn window_draw_list(&self) -> WindowDrawList<'_, A> {
2943 unsafe {
2944 let ptr = ImGui_GetWindowDrawList();
2945 WindowDrawList { ui: self, ptr }
2946 }
2947 }
2948 pub fn window_dpi_scale(&self) -> f32 {
2950 unsafe { ImGui_GetWindowDpiScale() }
2951 }
2952 pub fn foreground_draw_list(&self) -> WindowDrawList<'_, A> {
2955 unsafe {
2956 let ptr = ImGui_GetForegroundDrawList(std::ptr::null_mut());
2957 WindowDrawList { ui: self, ptr }
2958 }
2959 }
2960 pub fn background_draw_list(&self) -> WindowDrawList<'_, A> {
2963 unsafe {
2964 let ptr = ImGui_GetBackgroundDrawList(std::ptr::null_mut());
2965 WindowDrawList { ui: self, ptr }
2966 }
2967 }
2968 pub fn text(&self, text: &str) {
2970 unsafe {
2971 let (start, end) = text_ptrs(text);
2972 ImGui_TextUnformatted(start, end);
2973 }
2974 }
2975 pub fn text_colored(&self, color: Color, text: impl IntoCStr) {
2977 let text = text.into();
2978 unsafe { ImGui_TextColored(&color.into(), c"%s".as_ptr(), text.as_ptr()) }
2979 }
2980 pub fn text_disabled(&self, text: impl IntoCStr) {
2982 let text = text.into();
2983 unsafe { ImGui_TextDisabled(c"%s".as_ptr(), text.as_ptr()) }
2984 }
2985 pub fn text_wrapped(&self, text: impl IntoCStr) {
2987 let text = text.into();
2988 unsafe { ImGui_TextWrapped(c"%s".as_ptr(), text.as_ptr()) }
2989 }
2990 pub fn text_link(&self, label: LblId<impl IntoCStr>) -> bool {
2992 let label = label.into();
2993 unsafe { ImGui_TextLink(label.as_ptr()) }
2994 }
2995 pub fn text_link_open_url(&self, label: LblId<impl IntoCStr>, url: impl IntoCStr) -> bool {
2997 let label = label.into();
2998 let url = url.into();
2999 unsafe { ImGui_TextLinkOpenURL(label.as_ptr(), url.as_ptr()) }
3000 }
3001 pub fn label_text(&self, label: impl IntoCStr, text: impl IntoCStr) {
3003 let label = label.into();
3004 let text = text.into();
3005 unsafe { ImGui_LabelText(label.as_ptr(), c"%s".as_ptr(), text.as_ptr()) }
3006 }
3007 pub fn bullet_text(&self, text: impl IntoCStr) {
3009 let text = text.into();
3010 unsafe { ImGui_BulletText(c"%s".as_ptr(), text.as_ptr()) }
3011 }
3012 pub fn bullet(&self) {
3014 unsafe {
3015 ImGui_Bullet();
3016 }
3017 }
3018 pub fn separator_text(&self, text: impl IntoCStr) {
3020 let text = text.into();
3021 unsafe {
3022 ImGui_SeparatorText(text.as_ptr());
3023 }
3024 }
3025 pub fn separator(&self) {
3027 unsafe {
3028 ImGui_Separator();
3029 }
3030 }
3031
3032 pub fn set_item_default_focus(&self) {
3034 unsafe {
3035 ImGui_SetItemDefaultFocus();
3036 }
3037 }
3038 pub fn is_item_hovered(&self) -> bool {
3040 self.is_item_hovered_ex(HoveredFlags::None)
3041 }
3042 pub fn is_item_hovered_ex(&self, flags: HoveredFlags) -> bool {
3044 unsafe { ImGui_IsItemHovered(flags.bits()) }
3045 }
3046 pub fn is_item_active(&self) -> bool {
3048 unsafe { ImGui_IsItemActive() }
3049 }
3050 pub fn is_item_focused(&self) -> bool {
3052 unsafe { ImGui_IsItemFocused() }
3053 }
3054 pub fn is_item_clicked(&self, flags: MouseButton) -> bool {
3056 unsafe { ImGui_IsItemClicked(flags.bits()) }
3057 }
3058 pub fn is_item_visible(&self) -> bool {
3060 unsafe { ImGui_IsItemVisible() }
3061 }
3062 pub fn is_item_edited(&self) -> bool {
3064 unsafe { ImGui_IsItemEdited() }
3065 }
3066 pub fn is_item_activated(&self) -> bool {
3068 unsafe { ImGui_IsItemActivated() }
3069 }
3070 pub fn is_item_deactivated(&self) -> bool {
3072 unsafe { ImGui_IsItemDeactivated() }
3073 }
3074 pub fn is_item_deactivated_after_edit(&self) -> bool {
3076 unsafe { ImGui_IsItemDeactivatedAfterEdit() }
3077 }
3078 pub fn is_item_toggled_open(&self) -> bool {
3080 unsafe { ImGui_IsItemToggledOpen() }
3081 }
3082 pub fn is_any_item_hovered(&self) -> bool {
3084 unsafe { ImGui_IsAnyItemHovered() }
3085 }
3086 pub fn is_any_item_active(&self) -> bool {
3088 unsafe { ImGui_IsAnyItemActive() }
3089 }
3090 pub fn is_any_item_focused(&self) -> bool {
3092 unsafe { ImGui_IsAnyItemFocused() }
3093 }
3094 pub fn is_window_collapsed(&self) -> bool {
3096 unsafe { ImGui_IsWindowCollapsed() }
3097 }
3098 pub fn is_window_focused(&self, flags: FocusedFlags) -> bool {
3100 unsafe { ImGui_IsWindowFocused(flags.bits()) }
3101 }
3102 pub fn is_window_hovered(&self, flags: FocusedFlags) -> bool {
3104 unsafe { ImGui_IsWindowHovered(flags.bits()) }
3105 }
3106 pub fn get_item_id(&self) -> ImGuiID {
3108 unsafe { ImGui_GetItemID() }
3109 }
3110 pub fn get_id(&self, id: impl Hashable) -> ImGuiID {
3112 unsafe { id.get_id() }
3113 }
3114 pub fn get_item_rect_min(&self) -> Vector2 {
3116 unsafe { im_to_v2(ImGui_GetItemRectMin()) }
3117 }
3118 pub fn get_item_rect_max(&self) -> Vector2 {
3120 unsafe { im_to_v2(ImGui_GetItemRectMax()) }
3121 }
3122 pub fn get_item_rect_size(&self) -> Vector2 {
3124 unsafe { im_to_v2(ImGui_GetItemRectSize()) }
3125 }
3126 pub fn get_item_flags(&self) -> ItemFlags {
3128 unsafe { ItemFlags::from_bits_truncate(ImGui_GetItemFlags()) }
3129 }
3130 pub fn get_content_region_avail(&self) -> Vector2 {
3133 unsafe { im_to_v2(ImGui_GetContentRegionAvail()) }
3134 }
3135 pub fn get_window_pos(&self) -> Vector2 {
3137 unsafe { im_to_v2(ImGui_GetWindowPos()) }
3138 }
3139 pub fn get_window_width(&self) -> f32 {
3141 unsafe { ImGui_GetWindowWidth() }
3142 }
3143 pub fn get_window_height(&self) -> f32 {
3145 unsafe { ImGui_GetWindowHeight() }
3146 }
3147 pub fn get_scroll_x(&self) -> f32 {
3149 unsafe { ImGui_GetScrollX() }
3150 }
3151 pub fn get_scroll_y(&self) -> f32 {
3153 unsafe { ImGui_GetScrollY() }
3154 }
3155 pub fn set_scroll_x(&self, scroll_x: f32) {
3157 unsafe {
3158 ImGui_SetScrollX(scroll_x);
3159 }
3160 }
3161 pub fn set_scroll_y(&self, scroll_y: f32) {
3163 unsafe {
3164 ImGui_SetScrollY(scroll_y);
3165 }
3166 }
3167 pub fn get_scroll_max_x(&self) -> f32 {
3169 unsafe { ImGui_GetScrollMaxX() }
3170 }
3171 pub fn get_scroll_max_y(&self) -> f32 {
3173 unsafe { ImGui_GetScrollMaxY() }
3174 }
3175 pub fn set_scroll_here_x(&self, center_x_ratio: f32) {
3177 unsafe {
3178 ImGui_SetScrollHereX(center_x_ratio);
3179 }
3180 }
3181 pub fn set_scroll_here_y(&self, center_y_ratio: f32) {
3183 unsafe {
3184 ImGui_SetScrollHereY(center_y_ratio);
3185 }
3186 }
3187 pub fn set_scroll_from_pos_x(&self, local_x: f32, center_x_ratio: f32) {
3189 unsafe {
3190 ImGui_SetScrollFromPosX(local_x, center_x_ratio);
3191 }
3192 }
3193 pub fn set_scroll_from_pos_y(&self, local_y: f32, center_y_ratio: f32) {
3195 unsafe {
3196 ImGui_SetScrollFromPosY(local_y, center_y_ratio);
3197 }
3198 }
3199 pub fn set_window_pos(&self, pos: Vector2, cond: Cond) {
3201 unsafe {
3202 ImGui_SetWindowPos(&v2_to_im(pos), cond.bits());
3203 }
3204 }
3205 pub fn set_window_size(&self, size: Vector2, cond: Cond) {
3207 unsafe {
3208 ImGui_SetWindowSize(&v2_to_im(size), cond.bits());
3209 }
3210 }
3211 pub fn set_window_collapsed(&self, collapsed: bool, cond: Cond) {
3213 unsafe {
3214 ImGui_SetWindowCollapsed(collapsed, cond.bits());
3215 }
3216 }
3217 pub fn set_window_focus(&self) {
3219 unsafe {
3220 ImGui_SetWindowFocus();
3221 }
3222 }
3223 pub fn same_line(&self) {
3227 self.same_line_ex(SameLine::Default);
3228 }
3229 pub fn same_line_ex(&self, same_line: SameLine) {
3233 let (offset_from_start_x, spacing) = match same_line {
3234 SameLine::Default => (0.0, -1.0),
3235 SameLine::OffsetFromStart(offs) => {
3238 if offs != 0.0 {
3239 (offs, 0.0)
3240 } else {
3241 (-f32::MIN_POSITIVE, f32::MIN_POSITIVE)
3242 }
3243 }
3244 SameLine::Spacing(spc) => (0.0, spc.max(0.0)),
3246 };
3247 unsafe {
3248 ImGui_SameLine(offset_from_start_x, spacing);
3249 }
3250 }
3251 pub fn new_line(&self) {
3253 unsafe {
3254 ImGui_NewLine();
3255 }
3256 }
3257 pub fn spacing(&self) {
3259 unsafe {
3260 ImGui_Spacing();
3261 }
3262 }
3263 pub fn dummy(&self, size: Vector2) {
3265 unsafe {
3266 ImGui_Dummy(&v2_to_im(size));
3267 }
3268 }
3269 pub fn indent(&self, indent_w: f32) {
3271 unsafe {
3272 ImGui_Indent(indent_w);
3273 }
3274 }
3275 pub fn unindent(&self, indent_w: f32) {
3277 unsafe {
3278 ImGui_Unindent(indent_w);
3279 }
3280 }
3281 pub fn get_cursor_pos(&self) -> Vector2 {
3283 unsafe { im_to_v2(ImGui_GetCursorPos()) }
3284 }
3285 pub fn get_cursor_pos_x(&self) -> f32 {
3287 unsafe { ImGui_GetCursorPosX() }
3288 }
3289 pub fn get_cursor_pos_y(&self) -> f32 {
3291 unsafe { ImGui_GetCursorPosY() }
3292 }
3293 pub fn set_cursor_pos(&self, local_pos: Vector2) {
3295 unsafe {
3296 ImGui_SetCursorPos(&v2_to_im(local_pos));
3297 }
3298 }
3299 pub fn set_cursor_pos_x(&self, local_x: f32) {
3301 unsafe {
3302 ImGui_SetCursorPosX(local_x);
3303 }
3304 }
3305 pub fn set_cursor_pos_y(&self, local_y: f32) {
3307 unsafe {
3308 ImGui_SetCursorPosY(local_y);
3309 }
3310 }
3311 pub fn get_cursor_start_pos(&self) -> Vector2 {
3313 unsafe { im_to_v2(ImGui_GetCursorStartPos()) }
3314 }
3315 pub fn get_cursor_screen_pos(&self) -> Vector2 {
3317 unsafe { im_to_v2(ImGui_GetCursorScreenPos()) }
3318 }
3319 pub fn set_cursor_screen_pos(&self, pos: Vector2) {
3321 unsafe {
3322 ImGui_SetCursorScreenPos(&v2_to_im(pos));
3323 }
3324 }
3325 pub fn align_text_to_frame_padding(&self) {
3328 unsafe {
3329 ImGui_AlignTextToFramePadding();
3330 }
3331 }
3332 pub fn get_text_line_height(&self) -> f32 {
3334 unsafe { ImGui_GetTextLineHeight() }
3335 }
3336 pub fn get_text_line_height_with_spacing(&self) -> f32 {
3339 unsafe { ImGui_GetTextLineHeightWithSpacing() }
3340 }
3341 pub fn get_frame_height(&self) -> f32 {
3343 unsafe { ImGui_GetFrameHeight() }
3344 }
3345 pub fn get_frame_height_with_spacing(&self) -> f32 {
3348 unsafe { ImGui_GetFrameHeightWithSpacing() }
3349 }
3350 pub fn calc_item_width(&self) -> f32 {
3353 unsafe { ImGui_CalcItemWidth() }
3354 }
3355 pub fn calc_text_size(&self, text: &str) -> Vector2 {
3356 self.calc_text_size_ex(text, false, -1.0)
3357 }
3358 pub fn calc_text_size_ex(
3359 &self,
3360 text: &str,
3361 hide_text_after_double_hash: bool,
3362 wrap_width: f32,
3363 ) -> Vector2 {
3364 unsafe {
3365 let (start, end) = text_ptrs(text);
3366 im_to_v2(ImGui_CalcTextSize(
3367 start,
3368 end,
3369 hide_text_after_double_hash,
3370 wrap_width,
3371 ))
3372 }
3373 }
3374 pub fn key_mods(&self) -> KeyMod {
3375 let mods = self.io().KeyMods;
3376 KeyMod::from_bits_truncate(mods & ImGuiKey::ImGuiMod_Mask_.0)
3377 }
3378 pub fn is_key_down(&self, key: Key) -> bool {
3380 unsafe { ImGui_IsKeyDown(key.bits()) }
3381 }
3382 pub fn is_key_pressed(&self, key: Key) -> bool {
3385 unsafe {
3386 ImGui_IsKeyPressed(key.bits(), true)
3387 }
3388 }
3389 pub fn is_key_pressed_no_repeat(&self, key: Key) -> bool {
3392 unsafe {
3393 ImGui_IsKeyPressed(key.bits(), false)
3394 }
3395 }
3396 pub fn is_key_released(&self, key: Key) -> bool {
3398 unsafe { ImGui_IsKeyReleased(key.bits()) }
3399 }
3400 pub fn get_key_pressed_amount(&self, key: Key, repeat_delay: Duration, rate: f32) -> i32 {
3403 unsafe { ImGui_GetKeyPressedAmount(key.bits(), repeat_delay.as_secs_f32(), rate) }
3404 }
3405 pub fn get_font_tex_uv_white_pixel(&self) -> Vector2 {
3408 unsafe { im_to_v2(ImGui_GetFontTexUvWhitePixel()) }
3409 }
3410 pub fn get_font_size(&self) -> f32 {
3418 unsafe { ImGui_GetFontSize() }
3419 }
3420 pub fn is_mouse_down(&self, button: MouseButton) -> bool {
3422 unsafe { ImGui_IsMouseDown(button.bits()) }
3423 }
3424 pub fn is_mouse_clicked(&self, button: MouseButton) -> bool {
3427 unsafe {
3428 ImGui_IsMouseClicked(button.bits(), false)
3429 }
3430 }
3431 pub fn is_mouse_clicked_repeat(&self, button: MouseButton) -> bool {
3434 unsafe {
3435 ImGui_IsMouseClicked(button.bits(), true)
3436 }
3437 }
3438 pub fn is_mouse_released(&self, button: MouseButton) -> bool {
3440 unsafe { ImGui_IsMouseReleased(button.bits()) }
3441 }
3442 pub fn is_mouse_double_clicked(&self, button: MouseButton) -> bool {
3445 unsafe { ImGui_IsMouseDoubleClicked(button.bits()) }
3446 }
3447 pub fn get_mouse_clicked_count(&self, button: MouseButton) -> i32 {
3450 unsafe { ImGui_GetMouseClickedCount(button.bits()) }
3451 }
3452 pub fn get_item_clicked_count_with_single_click_delay(
3457 &self,
3458 button: MouseButton,
3459 delay: Duration,
3460 ) -> i32 {
3461 unsafe { ImGui_GetItemClickedCountWithSingleClickDelay(button.bits(), delay.as_secs_f32()) }
3462 }
3463 pub fn is_mouse_released_with_delay(&self, button: MouseButton, delay: Duration) -> bool {
3469 unsafe { ImGui_IsMouseReleasedWithDelay(button.bits(), delay.as_secs_f32()) }
3470 }
3471 pub fn is_rect_visible_size(&self, size: Vector2) -> bool {
3474 unsafe { ImGui_IsRectVisible(&v2_to_im(size)) }
3475 }
3476 pub fn is_rect_visible(&self, rect_min: Vector2, rect_max: Vector2) -> bool {
3479 unsafe { ImGui_IsRectVisible1(&v2_to_im(rect_min), &v2_to_im(rect_max)) }
3480 }
3481 pub fn is_any_mouse_down(&self) -> bool {
3497 unsafe { ImGui_IsAnyMouseDown() }
3498 }
3499 pub fn get_mouse_pos(&self) -> Vector2 {
3502 unsafe { im_to_v2(ImGui_GetMousePos()) }
3503 }
3504 pub fn get_mouse_pos_on_opening_current_popup(&self) -> Vector2 {
3507 unsafe { im_to_v2(ImGui_GetMousePosOnOpeningCurrentPopup()) }
3508 }
3509 pub fn is_mouse_dragging(&self, button: MouseButton) -> bool {
3511 unsafe {
3512 ImGui_IsMouseDragging(button.bits(), -1.0)
3513 }
3514 }
3515 pub fn get_mouse_drag_delta(&self, button: MouseButton) -> Vector2 {
3519 unsafe {
3520 im_to_v2(ImGui_GetMouseDragDelta(
3521 button.bits(),
3522 -1.0,
3523 ))
3524 }
3525 }
3526 pub fn reset_mouse_drag_delta(&self, button: MouseButton) {
3528 unsafe {
3529 ImGui_ResetMouseDragDelta(button.bits());
3530 }
3531 }
3532 pub fn get_mouse_cursor(&self) -> MouseCursor {
3536 unsafe { MouseCursor::from_bits(ImGui_GetMouseCursor()).unwrap_or(MouseCursor::None) }
3537 }
3538 pub fn set_mouse_cursor(&self, cursor_type: MouseCursor) {
3540 unsafe {
3541 ImGui_SetMouseCursor(cursor_type.bits());
3542 }
3543 }
3544 pub fn get_time(&self) -> f64 {
3546 unsafe { ImGui_GetTime() }
3547 }
3548 pub fn get_frame_count(&self) -> i32 {
3550 unsafe { ImGui_GetFrameCount() }
3551 }
3552 pub fn is_popup_open(&self, str_id: Option<Id<impl IntoCStr>>) -> bool {
3554 self.is_popup_open_ex(str_id, PopupFlags::None)
3555 }
3556 pub fn is_popup_open_ex(&self, str_id: Option<Id<impl IntoCStr>>, flags: PopupFlags) -> bool {
3558 let temp;
3559 let str_id = match str_id {
3560 Some(s) => {
3561 temp = IntoCStr::into(s.0);
3562 temp.as_ptr()
3563 }
3564 None => null(),
3565 };
3566 unsafe { ImGui_IsPopupOpen(str_id, flags.bits()) }
3567 }
3568 pub fn is_below_blocking_modal(&self) -> bool {
3570 unsafe {
3572 let modal = ImGui_FindBlockingModal(self.CurrentWindow);
3573 !modal.is_null()
3574 }
3575 }
3576 pub fn is_blocking_modal(&self) -> bool {
3578 unsafe {
3580 let modal = ImGui_FindBlockingModal(std::ptr::null_mut());
3581 !modal.is_null()
3582 }
3583 }
3584 pub fn open_popup(&self, str_id: Id<impl IntoCStr>) -> bool {
3588 self.open_popup_ex(str_id, PopupFlags::None)
3589 }
3590 pub fn open_popup_ex(&self, str_id: Id<impl IntoCStr>, flags: PopupFlags) -> bool {
3594 let str_id = str_id.into();
3595 unsafe { ImGui_OpenPopup(str_id.as_ptr(), flags.bits()) }
3596 }
3597 pub fn close_current_popup(&self) {
3599 unsafe {
3600 ImGui_CloseCurrentPopup();
3601 }
3602 }
3603 pub fn open_popup_on_item_click(
3608 &self,
3609 str_id: Option<Id<impl IntoCStr>>,
3610 flags: PopupFlags,
3611 ) -> bool {
3612 let temp;
3613 let str_id = match str_id {
3614 Some(s) => {
3615 temp = IntoCStr::into(s.0);
3616 temp.as_ptr()
3617 }
3618 None => null(),
3619 };
3620 unsafe { ImGui_OpenPopupOnItemClick(str_id, flags.bits()) }
3621 }
3622 pub fn is_window_appearing(&self) -> bool {
3623 unsafe { ImGui_IsWindowAppearing() }
3624 }
3625 pub fn with_always_drag_drop_source<R>(
3628 &self,
3629 flags: DragDropSourceFlags,
3630 f: impl FnOnce(Option<DragDropPayloadSetter<'_>>) -> R,
3631 ) -> R {
3632 if !unsafe { ImGui_BeginDragDropSource(flags.bits()) } {
3633 return f(None);
3634 }
3635 let payload = DragDropPayloadSetter {
3636 _dummy: PhantomData,
3637 };
3638 let r = f(Some(payload));
3639 unsafe { ImGui_EndDragDropSource() }
3640 r
3641 }
3642 pub fn with_drag_drop_source<R>(
3645 &self,
3646 flags: DragDropSourceFlags,
3647 f: impl FnOnce(DragDropPayloadSetter<'_>) -> R,
3648 ) -> Option<R> {
3649 self.with_always_drag_drop_source(flags, move |r| r.map(f))
3650 }
3651 pub fn with_always_drag_drop_target<R>(
3654 &self,
3655 f: impl FnOnce(Option<DragDropPayloadGetter<'_>>) -> R,
3656 ) -> R {
3657 if !unsafe { ImGui_BeginDragDropTarget() } {
3658 return f(None);
3659 }
3660 let payload = DragDropPayloadGetter {
3661 _dummy: PhantomData,
3662 };
3663 let r = f(Some(payload));
3664 unsafe { ImGui_EndDragDropTarget() }
3665 r
3666 }
3667 pub fn with_drag_drop_target<R>(
3670 &self,
3671 f: impl FnOnce(DragDropPayloadGetter<'_>) -> R,
3672 ) -> Option<R> {
3673 self.with_always_drag_drop_target(move |r| r.map(f))
3674 }
3675
3676 #[must_use]
3677 pub fn list_clipper(&self, items_count: usize) -> ListClipper {
3678 ListClipper {
3679 items_count,
3680 items_height: -1.0,
3681 included_ranges: Vec::new(),
3682 }
3683 }
3684
3685 pub fn shortcut(&self, key_chord: impl Into<KeyChord>) -> bool {
3686 unsafe { ImGui_Shortcut(key_chord.into().bits(), 0) }
3687 }
3688 pub fn shortcut_ex(&self, key_chord: impl Into<KeyChord>, flags: InputFlags) -> bool {
3689 unsafe { ImGui_Shortcut(key_chord.into().bits(), flags.bits()) }
3690 }
3691 pub fn set_next_item_shortcut(&self, key_chord: impl Into<KeyChord>) {
3692 unsafe {
3693 ImGui_SetNextItemShortcut(key_chord.into().bits(), 0);
3694 }
3695 }
3696 pub fn set_next_item_shortcut_ex(&self, key_chord: impl Into<KeyChord>, flags: InputFlags) {
3697 unsafe {
3698 ImGui_SetNextItemShortcut(key_chord.into().bits(), flags.bits());
3699 }
3700 }
3701 pub fn is_keychord_pressed(&self, key_chord: impl Into<KeyChord>) -> bool {
3705 unsafe { ImGui_IsKeyChordPressed(key_chord.into().bits()) }
3706 }
3707
3708 pub fn get_font(&self, font_id: FontId) -> &Font {
3710 unsafe {
3711 let font = self.io().font_atlas().font_ptr(font_id);
3712 Font::cast(&*font)
3713 }
3714 }
3715
3716 pub fn get_font_baked(
3721 &self,
3722 font_id: FontId,
3723 font_size: f32,
3724 font_density: Option<f32>,
3725 ) -> &FontBaked {
3726 unsafe {
3727 let font = self.io().font_atlas().font_ptr(font_id);
3728 let baked = (*font).GetFontBaked(font_size, font_density.unwrap_or(-1.0));
3729 FontBaked::cast(&*baked)
3730 }
3731 }
3732
3733 pub fn get_atlas_texture_ref(&self) -> TextureRef<'_> {
3734 let tex_data = self.io().font_atlas().TexData;
3735 let tex_data = unsafe { &*tex_data };
3736 TextureRef::Ref(tex_data)
3737 }
3738
3739 pub fn get_custom_rect(&self, index: CustomRectIndex) -> Option<TextureRect<'_>> {
3740 let atlas = self.io().font_atlas();
3741 let rect = unsafe {
3742 let mut rect = MaybeUninit::zeroed();
3743 let ok = atlas.GetCustomRect(index.0, rect.as_mut_ptr());
3744 if !ok {
3745 return None;
3746 }
3747 rect.assume_init()
3748 };
3749
3750 let tex_ref = self.get_atlas_texture_ref();
3751 Some(TextureRect { rect, tex_ref })
3752 }
3753
3754 pub fn dock_space(
3755 &self,
3756 id: ImGuiID,
3757 size: Vector2,
3758 flags: DockNodeFlags,
3759 window_class: Option<&WindowClass>,
3760 ) -> ImGuiID {
3761 unsafe {
3762 ImGui_DockSpace(
3763 id,
3764 &v2_to_im(size),
3765 flags.bits(),
3766 window_class
3767 .as_ref()
3768 .map(|e| &raw const e.0)
3769 .unwrap_or_default(),
3770 )
3771 }
3772 }
3773 pub fn dock_space_over_viewport(
3774 &self,
3775 dockspace_id: ImGuiID,
3776 viewport: &Viewport,
3777 flags: DockNodeFlags,
3778 window_class: Option<&WindowClass>,
3779 ) -> ImGuiID {
3780 unsafe {
3781 ImGui_DockSpaceOverViewport(
3782 dockspace_id,
3783 viewport.get(),
3784 flags.bits(),
3785 window_class
3786 .as_ref()
3787 .map(|e| &raw const e.0)
3788 .unwrap_or_default(),
3789 )
3790 }
3791 }
3792 pub fn set_next_window_dock_id(&self, dock_id: ImGuiID, cond: Cond) {
3794 unsafe {
3795 ImGui_SetNextWindowDockID(dock_id, cond.bits());
3796 }
3797 }
3798 pub fn set_next_window_class(&self, window_class: &WindowClass) {
3801 unsafe {
3802 ImGui_SetNextWindowClass(&window_class.0);
3803 }
3804 }
3805 pub fn get_window_dock_id(&self) -> ImGuiID {
3807 unsafe { ImGui_GetWindowDockID() }
3808 }
3809 pub fn is_window_docked(&self) -> bool {
3811 unsafe { ImGui_IsWindowDocked() }
3812 }
3813
3814 pub fn dock_builder(
3823 &self,
3824 id: Option<ImGuiID>,
3825 flags: DockNodeFlags,
3826 fn_build: impl FnOnce(ImGuiID, &mut DockBuilder),
3827 ) {
3828 struct DockBuilderFinishGuard(ImGuiID);
3829 impl Drop for DockBuilderFinishGuard {
3830 fn drop(&mut self) {
3831 unsafe {
3832 ImGui_DockBuilderFinish(self.0);
3833 }
3834 }
3835 }
3836
3837 unsafe {
3838 let id = ImGui_DockBuilderAddNode(id.unwrap_or(0), flags.bits());
3839 let _guard = DockBuilderFinishGuard(id);
3840 let mut db = DockBuilder { _dummy: () };
3841 fn_build(id, &mut db);
3842 }
3843 }
3844
3845 pub fn get_window_viewport(&self) -> &Viewport {
3847 unsafe { Viewport::cast(&*ImGui_GetWindowViewport()) }
3848 }
3849 pub fn set_next_window_viewport(&self, id: ImGuiID) {
3851 unsafe { ImGui_SetNextWindowViewport(id) }
3852 }
3853 pub fn viewport_foreground_draw_list(&self, viewport: &Viewport) -> WindowDrawList<'_, A> {
3856 unsafe {
3857 let ptr = ImGui_GetForegroundDrawList((&raw const *viewport.get()).cast_mut());
3858 WindowDrawList { ui: self, ptr }
3859 }
3860 }
3861 pub fn viewport_background_draw_list(&self, viewport: &Viewport) -> WindowDrawList<'_, A> {
3864 unsafe {
3865 let ptr = ImGui_GetBackgroundDrawList((&raw const *viewport.get()).cast_mut());
3866 WindowDrawList { ui: self, ptr }
3867 }
3868 }
3869}
3870
3871#[derive(Debug, Copy, Clone)]
3872pub struct TextureRect<'ui> {
3873 pub rect: ImFontAtlasRect,
3874 pub tex_ref: TextureRef<'ui>,
3875}
3876
3877pub struct ListClipper {
3878 items_count: usize,
3879 items_height: f32,
3880 included_ranges: Vec<std::ops::Range<usize>>,
3881}
3882
3883impl ListClipper {
3884 decl_builder_setter! {items_height: f32}
3885
3886 pub fn add_included_range(&mut self, range: std::ops::Range<usize>) {
3887 self.included_ranges.push(range);
3888 }
3889
3890 pub fn with(self, mut f: impl FnMut(usize)) {
3891 unsafe {
3892 let mut clip = ImGuiListClipper::new();
3893 clip.Begin(self.items_count as i32, self.items_height);
3894 for r in self.included_ranges {
3895 clip.IncludeItemsByIndex(r.start as i32, r.end as i32);
3896 }
3897 while clip.Step() {
3898 for i in clip.DisplayStart..clip.DisplayEnd {
3899 f(i as usize);
3900 }
3901 }
3902 }
3903 }
3904}
3905
3906transparent! {
3907 pub struct Font(ImFont);
3909}
3910
3911transparent! {
3912 pub struct FontGlyph(ImFontGlyph);
3913}
3914
3915impl FontGlyph {
3916 pub fn p0(&self) -> Vector2 {
3917 Vector2::new(self.0.X0, self.0.Y0)
3918 }
3919 pub fn p1(&self) -> Vector2 {
3920 Vector2::new(self.0.X1, self.0.Y1)
3921 }
3922 pub fn uv0(&self) -> Vector2 {
3923 Vector2::new(self.0.U0, self.0.V0)
3924 }
3925 pub fn uv1(&self) -> Vector2 {
3926 Vector2::new(self.0.U1, self.0.V1)
3927 }
3928 pub fn advance_x(&self) -> f32 {
3929 self.0.AdvanceX
3930 }
3931 pub fn visible(&self) -> bool {
3932 self.0.Visible() != 0
3933 }
3934 pub fn colored(&self) -> bool {
3935 self.0.Colored() != 0
3936 }
3937 pub fn codepoint(&self) -> char {
3938 char::try_from(self.0.Codepoint()).unwrap()
3939 }
3940}
3941
3942impl std::fmt::Debug for FontGlyph {
3943 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
3944 fmt.debug_struct("FontGlyph")
3945 .field("p0", &self.p0())
3946 .field("p1", &self.p1())
3947 .field("uv0", &self.uv0())
3948 .field("uv1", &self.uv1())
3949 .field("advance_x", &self.advance_x())
3950 .field("visible", &self.visible())
3951 .field("colored", &self.colored())
3952 .field("codepoint", &self.codepoint())
3953 .finish()
3954 }
3955}
3956
3957transparent! {
3958 #[derive(Debug)]
3959 pub struct FontBaked(ImFontBaked);
3960}
3961
3962impl FontBaked {
3963 pub fn find_glyph(&self, c: char) -> &FontGlyph {
3965 unsafe {
3966 FontGlyph::cast(&*ImFontBaked_FindGlyph(
3967 (&raw const self.0).cast_mut(),
3968 ImWchar::from(c),
3969 ))
3970 }
3971 }
3972
3973 pub fn find_glyph_no_fallback(&self, c: char) -> Option<&FontGlyph> {
3975 unsafe {
3976 let p =
3977 ImFontBaked_FindGlyphNoFallback((&raw const self.0).cast_mut(), ImWchar::from(c));
3978 p.as_ref().map(FontGlyph::cast)
3979 }
3980 }
3981
3982 pub unsafe fn inner(&mut self) -> &mut ImFontBaked {
3983 &mut self.0
3984 }
3985
3986 pub fn set_ascent(&mut self, ascent: f32) {
3988 self.0.Ascent = ascent;
3989 }
3990 pub fn set_descent(&mut self, descent: f32) {
3991 self.0.Descent = descent;
3992 }
3993}
3994
3995#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3999pub struct FontId(u32);
4000
4001#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4006pub struct CustomRectIndex(i32);
4007
4008impl Default for CustomRectIndex {
4009 fn default() -> Self {
4010 CustomRectIndex(-1)
4012 }
4013}
4014
4015transparent! {
4016 #[derive(Debug)]
4017 pub struct FontAtlas(ImFontAtlas);
4018}
4019
4020type PixelImage<'a> = image::ImageBuffer<image::Rgba<u8>, &'a mut [u8]>;
4021type SubPixelImage<'a, 'b> = image::SubImage<&'a mut PixelImage<'b>>;
4022
4023impl FontAtlas {
4024 pub unsafe fn texture_ref(&self) -> ImTextureRef {
4025 self.TexRef
4026 }
4027 pub unsafe fn inner(&mut self) -> &mut ImFontAtlas {
4028 &mut self.0
4029 }
4030
4031 pub fn current_texture_unique_id(&self) -> TextureUniqueId {
4032 unsafe {
4033 let id = (*self.TexRef._TexData).UniqueID;
4034 TextureUniqueId(id)
4035 }
4036 }
4037
4038 fn texture_unique_id(&self, uid: TextureUniqueId) -> Option<&ImTextureData> {
4039 unsafe {
4040 self.TexList
4041 .iter()
4042 .find(|x| (***x).UniqueID == uid.0)
4043 .map(|p| &**p)
4044 }
4045 }
4046
4047 unsafe fn font_ptr(&self, font: FontId) -> *mut ImFont {
4048 unsafe {
4049 *self
4051 .Fonts
4052 .iter()
4053 .find(|f| f.as_ref().map(|f| f.FontId) == Some(font.0))
4054 .unwrap_or(&self.Fonts[0])
4055 }
4056 }
4057
4058 pub fn check_texture_unique_id(&self, uid: TextureUniqueId) -> bool {
4059 self.texture_unique_id(uid).is_some_and(|x| {
4060 !matches!(
4061 x.Status,
4062 ImTextureStatus::ImTextureStatus_WantDestroy
4063 | ImTextureStatus::ImTextureStatus_Destroyed
4064 )
4065 })
4066 }
4067
4068 pub fn get_texture_by_unique_id(&self, uid: TextureUniqueId) -> Option<TextureId> {
4069 let p = self.texture_unique_id(uid)?;
4070 if p.Status == ImTextureStatus::ImTextureStatus_Destroyed || p.TexID == 0 {
4072 None
4073 } else {
4074 unsafe { Some(TextureId::from_id(p.TexID)) }
4075 }
4076 }
4077
4078 pub fn add_font(&mut self, font: FontInfo) -> FontId {
4083 self.add_font_priv(font, false)
4084 }
4085
4086 pub fn remove_font(&mut self, font_id: FontId) {
4087 unsafe {
4088 let f = self.font_ptr(font_id);
4089 self.0.RemoveFont(f);
4094 }
4095 }
4096
4097 pub fn add_font_collection(&mut self, fonts: impl IntoIterator<Item = FontInfo>) -> FontId {
4102 let mut fonts = fonts.into_iter();
4103 let first = fonts.next().expect("empty font collection");
4104 let id = self.add_font_priv(first, false);
4105 for font in fonts {
4106 self.add_font_priv(font, true);
4107 }
4108 id
4109 }
4110 fn add_font_priv(&mut self, font: FontInfo, merge: bool) -> FontId {
4111 unsafe {
4112 let mut fc = ImFontConfig::new();
4113 fc.FontDataOwnedByAtlas = false;
4115 fc.MergeMode = merge;
4116 if !font.name.is_empty() {
4117 let cname = font.name.as_bytes();
4118 let name_len = cname.len().min(fc.Name.len() - 1);
4119 fc.Name[..name_len]
4120 .copy_from_slice(std::mem::transmute::<&[u8], &[c_char]>(&cname[..name_len]));
4121 fc.Name[name_len] = 0;
4122 }
4123 fc.Flags = font.flags.bits();
4124 fc.SizePixels = font.size;
4125
4126 let font_ptr = match font.ttf {
4127 TtfData::Bytes(bytes) => {
4128 self.0.AddFontFromMemoryTTF(
4129 bytes.as_ptr() as *mut _,
4130 bytes.len() as i32,
4131 0.0,
4132 &fc,
4133 std::ptr::null(),
4134 )
4135 }
4136 TtfData::DefaultFont(DefaultFontSelector::Auto) => self.0.AddFontDefault(&fc),
4137 TtfData::DefaultFont(DefaultFontSelector::Bitmap) => {
4138 self.0.AddFontDefaultBitmap(&fc)
4139 }
4140 TtfData::DefaultFont(DefaultFontSelector::Vector) => {
4141 self.0.AddFontDefaultVector(&fc)
4142 }
4143 TtfData::CustomLoader(glyph_loader) => {
4144 let ptr = Box::into_raw(Box::new(glyph_loader));
4145 fc.FontLoader = &fontloader::FONT_LOADER.0;
4146 fc.FontData = ptr as *mut c_void;
4147 fc.FontDataOwnedByAtlas = true;
4148 self.0.AddFont(&fc)
4149 }
4150 };
4151 let Some(font) = font_ptr.as_ref() else {
4152 log::error!("Error loading font!");
4153 return FontId::default();
4154 };
4155 FontId(font.FontId)
4156 }
4157 }
4158
4159 pub fn add_custom_rect(
4163 &mut self,
4164 size: impl Into<mint::Vector2<u32>>,
4165 draw: impl FnOnce(&mut SubPixelImage<'_, '_>),
4166 ) -> CustomRectIndex {
4167 let size = size.into();
4168 unsafe {
4169 let mut rect = MaybeUninit::zeroed();
4170 let idx = self.0.AddCustomRect(
4171 i32::try_from(size.x).unwrap(),
4172 i32::try_from(size.y).unwrap(),
4173 rect.as_mut_ptr(),
4174 );
4175 let idx = CustomRectIndex(idx);
4176 let rect = rect.assume_init();
4177 let tex_data = &(*self.TexData);
4178
4179 let mut pixel_image = PixelImage::from_raw(
4180 tex_data.Width as u32,
4181 tex_data.Height as u32,
4182 std::slice::from_raw_parts_mut(
4183 tex_data.Pixels,
4184 tex_data.Width as usize
4185 * tex_data.Height as usize
4186 * tex_data.BytesPerPixel as usize,
4187 ),
4188 )
4189 .unwrap();
4190
4191 let mut sub_image =
4192 pixel_image.sub_image(rect.x as u32, rect.y as u32, rect.w as u32, rect.h as u32);
4193 draw(&mut sub_image);
4194
4195 idx
4196 }
4197 }
4198
4199 pub fn remove_custom_rect(&mut self, idx: CustomRectIndex) {
4200 if idx.0 < 0 {
4201 return;
4202 }
4203 unsafe {
4204 self.0.RemoveCustomRect(idx.0);
4205 }
4206 }
4207}
4208
4209transparent_mut! {
4210 #[derive(Debug)]
4211 pub struct Io(ImGuiIO);
4212}
4213
4214transparent! {
4215 #[derive(Debug)]
4219 pub struct IoMut(ImGuiIO);
4220}
4221
4222impl Io {
4223 pub fn font_atlas(&self) -> &FontAtlas {
4224 unsafe { FontAtlas::cast(&*self.Fonts) }
4225 }
4226
4227 pub fn want_capture_mouse(&self) -> bool {
4228 self.WantCaptureMouse
4229 }
4230 pub fn want_capture_keyboard(&self) -> bool {
4231 self.WantCaptureKeyboard
4232 }
4233 pub fn want_text_input(&self) -> bool {
4234 self.WantTextInput
4235 }
4236 pub fn display_size(&self) -> Vector2 {
4237 im_to_v2(self.DisplaySize)
4238 }
4239 pub fn display_scale(&self) -> f32 {
4240 self.DisplayFramebufferScale.x
4241 }
4242
4243 pub fn config_color_edit_flags(&self) -> ColorEditFlags {
4245 ColorEditFlags::from_bits_truncate(self.ConfigColorEditFlags)
4246 }
4247 pub fn mouse_single_click_delay(&self) -> Duration {
4251 Duration::from_secs_f32(self.MouseSingleClickDelay)
4252 }
4253 pub fn config_ini_settings_save_last_used_date(&self) -> bool {
4257 self.ConfigIniSettingsSaveLastUsedDate
4258 }
4259 pub fn config_ini_settings_auto_discard_months(&self) -> i32 {
4263 self.ConfigIniSettingsAutoDiscardMonths
4264 }
4265
4266 pub fn add_config_flags(&mut self, flags: ConfigFlags) {
4268 self.ConfigFlags |= flags.bits();
4269 }
4270 pub fn remove_config_flags(&mut self, flags: ConfigFlags) {
4271 self.ConfigFlags &= !flags.bits();
4272 }
4273 pub fn add_backend_flags(&mut self, flags: BackendFlags) {
4274 self.BackendFlags |= flags.bits();
4275 }
4276 pub fn remove_backend_flags(&mut self, flags: BackendFlags) {
4277 self.BackendFlags &= !flags.bits();
4278 }
4279 pub fn delta_time(&mut self) -> Duration {
4280 Duration::from_secs_f32(self.DeltaTime)
4281 }
4282 pub fn set_delta_time(&mut self, d: Duration) {
4283 self.DeltaTime = d.as_secs_f32()
4284 }
4285}
4286
4287impl IoMut {
4288 pub unsafe fn inner(&mut self) -> &mut Io {
4289 Io::cast_mut(&mut self.0)
4290 }
4291 pub fn set_allow_user_scaling(&mut self, val: bool) {
4292 self.0.FontAllowUserScaling = val;
4293 }
4294 pub fn nav_enable_keyboard(&mut self, enable: bool) {
4295 unsafe {
4296 if enable {
4297 self.inner()
4298 .add_config_flags(ConfigFlags::NavEnableKeyboard);
4299 } else {
4300 self.inner()
4301 .remove_config_flags(ConfigFlags::NavEnableKeyboard);
4302 }
4303 }
4304 }
4305 pub fn nav_enable_gamepad(&mut self, enable: bool) {
4306 unsafe {
4307 if enable {
4308 self.inner().add_config_flags(ConfigFlags::NavEnableGamepad);
4309 } else {
4310 self.inner()
4311 .remove_config_flags(ConfigFlags::NavEnableGamepad);
4312 }
4313 }
4314 }
4315 pub fn enable_docking(&mut self, enable: bool) {
4317 unsafe {
4318 if enable {
4319 self.inner().add_config_flags(ConfigFlags::DockingEnable);
4320 } else {
4321 self.inner().remove_config_flags(ConfigFlags::DockingEnable);
4322 }
4323 }
4324 }
4325 pub fn enable_viewports(&mut self, enable: bool) {
4329 unsafe {
4330 if enable {
4331 self.inner().add_config_flags(ConfigFlags::ViewportsEnable);
4332 } else {
4333 self.inner()
4334 .remove_config_flags(ConfigFlags::ViewportsEnable);
4335 }
4336 }
4337 }
4338 pub fn font_atlas_mut(&mut self) -> &mut FontAtlas {
4339 unsafe { FontAtlas::cast_mut(&mut *self.Fonts) }
4340 }
4341 pub fn set_config_color_edit_flags(&mut self, flags: ColorEditFlags) {
4343 self.0.ConfigColorEditFlags = flags.bits();
4344 }
4345 pub fn set_mouse_single_click_delay(&mut self, delay: Duration) {
4348 self.0.MouseSingleClickDelay = delay.as_secs_f32();
4349 }
4350 pub fn set_config_ini_settings_save_last_used_date(&mut self, save: bool) {
4352 self.0.ConfigIniSettingsSaveLastUsedDate = save;
4353 }
4354 pub fn set_config_ini_settings_auto_discard_months(&mut self, months: i32) {
4356 self.0.ConfigIniSettingsAutoDiscardMonths = months;
4357 }
4358}
4359
4360transparent_mut! {
4361 #[derive(Debug)]
4362 pub struct PlatformIo(ImGuiPlatformIO);
4363}
4364
4365impl PlatformIo {
4366 pub unsafe fn textures_mut(&mut self) -> impl Iterator<Item = &mut ImTextureData> {
4367 self.Textures.iter_mut().map(|t| unsafe { &mut **t })
4368 }
4369}
4370
4371#[derive(Debug)]
4372pub struct SizeCallbackData<'a> {
4373 ptr: &'a mut ImGuiSizeCallbackData,
4374}
4375
4376impl SizeCallbackData<'_> {
4377 pub fn pos(&self) -> Vector2 {
4378 im_to_v2(self.ptr.Pos)
4379 }
4380 pub fn current_size(&self) -> Vector2 {
4381 im_to_v2(self.ptr.CurrentSize)
4382 }
4383 pub fn desired_size(&self) -> Vector2 {
4384 im_to_v2(self.ptr.DesiredSize)
4385 }
4386 pub fn set_desired_size(&mut self, sz: Vector2) {
4387 self.ptr.DesiredSize = v2_to_im(sz);
4388 }
4389}
4390
4391unsafe extern "C" fn call_size_callback<A>(ptr: *mut ImGuiSizeCallbackData) {
4392 unsafe {
4393 let ptr = &mut *ptr;
4394 let id = ptr.UserData as usize;
4395 let data = SizeCallbackData { ptr };
4396 Ui::<A>::run_callback(id, data);
4397 }
4398}
4399
4400pub struct WindowDrawList<'ui, A> {
4401 ui: &'ui Ui<A>,
4402 ptr: *mut ImDrawList,
4403}
4404
4405impl<A> WindowDrawList<'_, A> {
4406 pub fn add_line(&self, p1: Vector2, p2: Vector2, color: Color, thickness: f32) {
4407 unsafe {
4408 ImDrawList_AddLine(
4409 self.ptr,
4410 &v2_to_im(p1),
4411 &v2_to_im(p2),
4412 color.as_u32(),
4413 thickness,
4414 );
4415 }
4416 }
4417 pub fn add_line_h(&self, min_x: f32, max_x: f32, y: f32, color: Color, thickness: f32) {
4418 unsafe {
4419 ImDrawList_AddLineH(self.ptr, min_x, max_x, y, color.as_u32(), thickness);
4420 }
4421 }
4422 pub fn add_line_v(&self, x: f32, min_y: f32, max_y: f32, color: Color, thickness: f32) {
4423 unsafe {
4424 ImDrawList_AddLineV(self.ptr, x, min_y, max_y, color.as_u32(), thickness);
4425 }
4426 }
4427 pub fn add_rect(
4429 &self,
4430 p_min: Vector2,
4431 p_max: Vector2,
4432 color: Color,
4433 rounding: f32,
4434 thickness: f32,
4435 flags: DrawFlags,
4436 ) {
4437 unsafe {
4438 ImDrawList_AddRect(
4439 self.ptr,
4440 &v2_to_im(p_min),
4441 &v2_to_im(p_max),
4442 color.as_u32(),
4443 rounding,
4444 thickness,
4445 flags.bits(),
4446 );
4447 }
4448 }
4449 pub fn add_rect_filled(
4451 &self,
4452 p_min: Vector2,
4453 p_max: Vector2,
4454 color: Color,
4455 rounding: f32,
4456 flags: DrawFlags,
4457 ) {
4458 unsafe {
4459 ImDrawList_AddRectFilled(
4460 self.ptr,
4461 &v2_to_im(p_min),
4462 &v2_to_im(p_max),
4463 color.as_u32(),
4464 rounding,
4465 flags.bits(),
4466 );
4467 }
4468 }
4469 pub fn add_rect_filled_multicolor(
4470 &self,
4471 p_min: Vector2,
4472 p_max: Vector2,
4473 col_upr_left: Color,
4474 col_upr_right: Color,
4475 col_bot_right: Color,
4476 col_bot_left: Color,
4477 ) {
4478 unsafe {
4479 ImDrawList_AddRectFilledMultiColor(
4480 self.ptr,
4481 &v2_to_im(p_min),
4482 &v2_to_im(p_max),
4483 col_upr_left.as_u32(),
4484 col_upr_right.as_u32(),
4485 col_bot_right.as_u32(),
4486 col_bot_left.as_u32(),
4487 );
4488 }
4489 }
4490 pub fn add_quad(
4491 &self,
4492 p1: Vector2,
4493 p2: Vector2,
4494 p3: Vector2,
4495 p4: Vector2,
4496 color: Color,
4497 thickness: f32,
4498 ) {
4499 unsafe {
4500 ImDrawList_AddQuad(
4501 self.ptr,
4502 &v2_to_im(p1),
4503 &v2_to_im(p2),
4504 &v2_to_im(p3),
4505 &v2_to_im(p4),
4506 color.as_u32(),
4507 thickness,
4508 );
4509 }
4510 }
4511 pub fn add_quad_filled(
4512 &self,
4513 p1: Vector2,
4514 p2: Vector2,
4515 p3: Vector2,
4516 p4: Vector2,
4517 color: Color,
4518 ) {
4519 unsafe {
4520 ImDrawList_AddQuadFilled(
4521 self.ptr,
4522 &v2_to_im(p1),
4523 &v2_to_im(p2),
4524 &v2_to_im(p3),
4525 &v2_to_im(p4),
4526 color.as_u32(),
4527 );
4528 }
4529 }
4530 pub fn add_triangle(
4531 &self,
4532 p1: Vector2,
4533 p2: Vector2,
4534 p3: Vector2,
4535 color: Color,
4536 thickness: f32,
4537 ) {
4538 unsafe {
4539 ImDrawList_AddTriangle(
4540 self.ptr,
4541 &v2_to_im(p1),
4542 &v2_to_im(p2),
4543 &v2_to_im(p3),
4544 color.as_u32(),
4545 thickness,
4546 );
4547 }
4548 }
4549 pub fn add_triangle_filled(&self, p1: Vector2, p2: Vector2, p3: Vector2, color: Color) {
4550 unsafe {
4551 ImDrawList_AddTriangleFilled(
4552 self.ptr,
4553 &v2_to_im(p1),
4554 &v2_to_im(p2),
4555 &v2_to_im(p3),
4556 color.as_u32(),
4557 );
4558 }
4559 }
4560 pub fn add_circle(
4561 &self,
4562 center: Vector2,
4563 radius: f32,
4564 color: Color,
4565 num_segments: i32,
4566 thickness: f32,
4567 ) {
4568 unsafe {
4569 ImDrawList_AddCircle(
4570 self.ptr,
4571 &v2_to_im(center),
4572 radius,
4573 color.as_u32(),
4574 num_segments,
4575 thickness,
4576 );
4577 }
4578 }
4579 pub fn add_circle_filled(&self, center: Vector2, radius: f32, color: Color, num_segments: i32) {
4580 unsafe {
4581 ImDrawList_AddCircleFilled(
4582 self.ptr,
4583 &v2_to_im(center),
4584 radius,
4585 color.as_u32(),
4586 num_segments,
4587 );
4588 }
4589 }
4590 pub fn add_ngon(
4591 &self,
4592 center: Vector2,
4593 radius: f32,
4594 color: Color,
4595 num_segments: i32,
4596 thickness: f32,
4597 ) {
4598 unsafe {
4599 ImDrawList_AddNgon(
4600 self.ptr,
4601 &v2_to_im(center),
4602 radius,
4603 color.as_u32(),
4604 num_segments,
4605 thickness,
4606 );
4607 }
4608 }
4609 pub fn add_ngon_filled(&self, center: Vector2, radius: f32, color: Color, num_segments: i32) {
4610 unsafe {
4611 ImDrawList_AddNgonFilled(
4612 self.ptr,
4613 &v2_to_im(center),
4614 radius,
4615 color.as_u32(),
4616 num_segments,
4617 );
4618 }
4619 }
4620 pub fn add_ellipse(
4621 &self,
4622 center: Vector2,
4623 radius: Vector2,
4624 color: Color,
4625 rot: f32,
4626 num_segments: i32,
4627 thickness: f32,
4628 ) {
4629 unsafe {
4630 ImDrawList_AddEllipse(
4631 self.ptr,
4632 &v2_to_im(center),
4633 &v2_to_im(radius),
4634 color.as_u32(),
4635 rot,
4636 num_segments,
4637 thickness,
4638 );
4639 }
4640 }
4641 pub fn add_ellipse_filled(
4642 &self,
4643 center: Vector2,
4644 radius: Vector2,
4645 color: Color,
4646 rot: f32,
4647 num_segments: i32,
4648 ) {
4649 unsafe {
4650 ImDrawList_AddEllipseFilled(
4651 self.ptr,
4652 &v2_to_im(center),
4653 &v2_to_im(radius),
4654 color.as_u32(),
4655 rot,
4656 num_segments,
4657 );
4658 }
4659 }
4660 pub fn add_text(&self, pos: Vector2, color: Color, text: &str) {
4661 unsafe {
4662 let (start, end) = text_ptrs(text);
4663 ImDrawList_AddText(self.ptr, &v2_to_im(pos), color.as_u32(), start, end);
4664 }
4665 }
4666 pub fn add_text_ex(
4667 &self,
4668 font: FontId,
4669 font_size: f32,
4670 pos: Vector2,
4671 color: Color,
4672 text: &str,
4673 wrap_width: f32,
4674 cpu_fine_clip_rect: Option<ImVec4>,
4675 ) {
4676 unsafe {
4677 let (start, end) = text_ptrs(text);
4678 ImDrawList_AddText1(
4679 self.ptr,
4680 self.ui.io().font_atlas().font_ptr(font),
4681 font_size,
4682 &v2_to_im(pos),
4683 color.as_u32(),
4684 start,
4685 end,
4686 wrap_width,
4687 cpu_fine_clip_rect
4688 .as_ref()
4689 .map(|x| x as *const _)
4690 .unwrap_or(null()),
4691 );
4692 }
4693 }
4694 pub fn add_polyline(&self, points: &[ImVec2], color: Color, thickness: f32, flags: DrawFlags) {
4695 unsafe {
4696 ImDrawList_AddPolyline(
4697 self.ptr,
4698 points.as_ptr(),
4699 points.len() as i32,
4700 color.as_u32(),
4701 thickness,
4702 flags.bits(),
4703 );
4704 }
4705 }
4706 pub fn add_convex_poly_filled(&self, points: &[ImVec2], color: Color) {
4707 unsafe {
4708 ImDrawList_AddConvexPolyFilled(
4709 self.ptr,
4710 points.as_ptr(),
4711 points.len() as i32,
4712 color.as_u32(),
4713 );
4714 }
4715 }
4716 pub fn add_concave_poly_filled(&self, points: &[ImVec2], color: Color) {
4717 unsafe {
4718 ImDrawList_AddConcavePolyFilled(
4719 self.ptr,
4720 points.as_ptr(),
4721 points.len() as i32,
4722 color.as_u32(),
4723 );
4724 }
4725 }
4726 pub fn add_bezier_cubic(
4728 &self,
4729 p1: Vector2,
4730 p2: Vector2,
4731 p3: Vector2,
4732 p4: Vector2,
4733 color: Color,
4734 thickness: f32,
4735 num_segments: i32,
4736 ) {
4737 unsafe {
4738 ImDrawList_AddBezierCubic(
4739 self.ptr,
4740 &v2_to_im(p1),
4741 &v2_to_im(p2),
4742 &v2_to_im(p3),
4743 &v2_to_im(p4),
4744 color.as_u32(),
4745 thickness,
4746 num_segments,
4747 );
4748 }
4749 }
4750 pub fn add_bezier_quadratic(
4752 &self,
4753 p1: Vector2,
4754 p2: Vector2,
4755 p3: Vector2,
4756 color: Color,
4757 thickness: f32,
4758 num_segments: i32,
4759 ) {
4760 unsafe {
4761 ImDrawList_AddBezierQuadratic(
4762 self.ptr,
4763 &v2_to_im(p1),
4764 &v2_to_im(p2),
4765 &v2_to_im(p3),
4766 color.as_u32(),
4767 thickness,
4768 num_segments,
4769 );
4770 }
4771 }
4772 pub fn add_image(
4773 &self,
4774 texture_ref: TextureRef,
4775 p_min: Vector2,
4776 p_max: Vector2,
4777 uv_min: Vector2,
4778 uv_max: Vector2,
4779 color: Color,
4780 ) {
4781 unsafe {
4782 ImDrawList_AddImage(
4783 self.ptr,
4784 texture_ref.tex_ref(),
4785 &v2_to_im(p_min),
4786 &v2_to_im(p_max),
4787 &v2_to_im(uv_min),
4788 &v2_to_im(uv_max),
4789 color.as_u32(),
4790 );
4791 }
4792 }
4793 pub fn add_image_quad(
4794 &self,
4795 texture_ref: TextureRef,
4796 p1: Vector2,
4797 p2: Vector2,
4798 p3: Vector2,
4799 p4: Vector2,
4800 uv1: Vector2,
4801 uv2: Vector2,
4802 uv3: Vector2,
4803 uv4: Vector2,
4804 color: Color,
4805 ) {
4806 unsafe {
4807 ImDrawList_AddImageQuad(
4808 self.ptr,
4809 texture_ref.tex_ref(),
4810 &v2_to_im(p1),
4811 &v2_to_im(p2),
4812 &v2_to_im(p3),
4813 &v2_to_im(p4),
4814 &v2_to_im(uv1),
4815 &v2_to_im(uv2),
4816 &v2_to_im(uv3),
4817 &v2_to_im(uv4),
4818 color.as_u32(),
4819 );
4820 }
4821 }
4822 pub fn add_image_rounded(
4823 &self,
4824 texture_ref: TextureRef,
4825 p_min: Vector2,
4826 p_max: Vector2,
4827 uv_min: Vector2,
4828 uv_max: Vector2,
4829 color: Color,
4830 rounding: f32,
4831 flags: DrawFlags,
4832 ) {
4833 unsafe {
4834 ImDrawList_AddImageRounded(
4835 self.ptr,
4836 texture_ref.tex_ref(),
4837 &v2_to_im(p_min),
4838 &v2_to_im(p_max),
4839 &v2_to_im(uv_min),
4840 &v2_to_im(uv_max),
4841 color.as_u32(),
4842 rounding,
4843 flags.bits(),
4844 );
4845 }
4846 }
4847
4848 pub fn path_clear(&self) {
4850 unsafe {
4851 let path = &mut (&mut *self.ptr)._Path;
4852 path.Size = 0;
4853 }
4854 }
4855 pub fn path_line_to(&self, v: Vector2) {
4856 unsafe {
4857 let path = &mut (&mut *self.ptr)._Path;
4858 ImGui_ImVector_vec2_push_back(path, &v2_to_im(v));
4859 }
4860 }
4861 pub fn path_line_to_merge_duplicate(&self, v: Vector2) {
4862 unsafe {
4863 let path = &mut (&mut *self.ptr)._Path;
4864 if path.last().is_none_or(|d| d.x != v.x || d.y != v.y) {
4865 ImGui_ImVector_vec2_push_back(path, &v2_to_im(v));
4866 }
4867 }
4868 }
4869 pub fn path_fill_convex(&self, color: Color) {
4870 unsafe {
4871 let path = &mut (&mut *self.ptr)._Path;
4872 ImDrawList_AddConvexPolyFilled(self.ptr, path.Data, path.Size, color.as_u32());
4873 path.Size = 0;
4874 }
4875 }
4876 pub fn path_fill_concave(&self, color: Color) {
4877 unsafe {
4878 let path = &mut (&mut *self.ptr)._Path;
4879 ImDrawList_AddConcavePolyFilled(self.ptr, path.Data, path.Size, color.as_u32());
4880 path.Size = 0;
4881 }
4882 }
4883 pub fn path_stroke(&self, color: Color, thickness: f32, flags: DrawFlags) {
4884 unsafe {
4885 let path = &mut (&mut *self.ptr)._Path;
4886 ImDrawList_AddPolyline(
4887 self.ptr,
4888 path.Data,
4889 path.Size,
4890 color.as_u32(),
4891 thickness,
4892 flags.bits(),
4893 );
4894 path.Size = 0;
4895 }
4896 }
4897 pub fn path_arc_to(
4898 &self,
4899 center: Vector2,
4900 radius: f32,
4901 a_min: f32,
4902 a_max: f32,
4903 num_segments: i32,
4904 ) {
4905 unsafe {
4906 ImDrawList_PathArcTo(
4907 self.ptr,
4908 &v2_to_im(center),
4909 radius,
4910 a_min,
4911 a_max,
4912 num_segments,
4913 );
4914 }
4915 }
4916 pub fn path_arc_to_fast(
4918 &self,
4919 center: Vector2,
4920 radius: f32,
4921 a_min_of_12: i32,
4922 a_max_of_12: i32,
4923 ) {
4924 unsafe {
4925 ImDrawList_PathArcToFast(
4926 self.ptr,
4927 &v2_to_im(center),
4928 radius,
4929 a_min_of_12,
4930 a_max_of_12,
4931 );
4932 }
4933 }
4934 pub fn path_elliptical_arc_to(
4936 &self,
4937 center: Vector2,
4938 radius: Vector2,
4939 rot: f32,
4940 a_min: f32,
4941 a_max: f32,
4942 num_segments: i32,
4943 ) {
4944 unsafe {
4945 ImDrawList_PathEllipticalArcTo(
4946 self.ptr,
4947 &v2_to_im(center),
4948 &v2_to_im(radius),
4949 rot,
4950 a_min,
4951 a_max,
4952 num_segments,
4953 );
4954 }
4955 }
4956 pub fn path_bezier_cubic_curve_to(
4957 &self,
4958 p2: Vector2,
4959 p3: Vector2,
4960 p4: Vector2,
4961 num_segments: i32,
4962 ) {
4963 unsafe {
4964 ImDrawList_PathBezierCubicCurveTo(
4965 self.ptr,
4966 &v2_to_im(p2),
4967 &v2_to_im(p3),
4968 &v2_to_im(p4),
4969 num_segments,
4970 );
4971 }
4972 }
4973 pub fn path_bezier_quadratic_curve_to(&self, p2: Vector2, p3: Vector2, num_segments: i32) {
4974 unsafe {
4975 ImDrawList_PathBezierQuadraticCurveTo(
4976 self.ptr,
4977 &v2_to_im(p2),
4978 &v2_to_im(p3),
4979 num_segments,
4980 );
4981 }
4982 }
4983 pub fn path_rect(&self, rect_min: Vector2, rect_max: Vector2, rounding: f32, flags: DrawFlags) {
4984 unsafe {
4985 ImDrawList_PathRect(
4986 self.ptr,
4987 &v2_to_im(rect_min),
4988 &v2_to_im(rect_max),
4989 rounding,
4990 flags.bits(),
4991 );
4992 }
4993 }
4994
4995 pub fn add_callback(&self, cb: impl FnOnce(&mut A) + 'static) {
4996 let mut cb = Some(cb);
5000 unsafe {
5001 let id = self.ui.push_callback(move |a, _: ()| {
5002 if let Some(cb) = cb.take() {
5003 cb(&mut *a);
5004 }
5005 });
5006 ImDrawList_AddCallback(
5007 self.ptr,
5008 Some(call_drawlist_callback::<A>),
5009 id as *mut c_void,
5010 0,
5011 );
5012 }
5013 }
5014 pub fn add_draw_cmd(&self) {
5018 unsafe {
5019 ImDrawList_AddDrawCmd(self.ptr);
5020 }
5021 }
5022}
5023
5024unsafe extern "C" fn call_drawlist_callback<A>(
5025 _parent_list: *const ImDrawList,
5026 cmd: *const ImDrawCmd,
5027) {
5028 unsafe {
5029 let id = (*cmd).UserCallbackData as usize;
5030 Ui::<A>::run_callback(id, ());
5031 }
5032}
5033
5034pub trait Hashable {
5036 unsafe fn get_id(&self) -> ImGuiID;
5038 unsafe fn push(&self);
5039}
5040
5041impl Hashable for &str {
5042 unsafe fn get_id(&self) -> ImGuiID {
5043 unsafe {
5044 let (start, end) = text_ptrs(self);
5045 ImGui_GetID1(start, end)
5046 }
5047 }
5048 unsafe fn push(&self) {
5049 unsafe {
5050 let (start, end) = text_ptrs(self);
5051 ImGui_PushID1(start, end);
5052 }
5053 }
5054}
5055
5056impl Hashable for usize {
5057 unsafe fn get_id(&self) -> ImGuiID {
5058 unsafe { ImGui_GetID2(*self as *const c_void) }
5059 }
5060 unsafe fn push(&self) {
5061 unsafe {
5062 ImGui_PushID2(*self as *const c_void);
5063 }
5064 }
5065}
5066
5067pub trait Pushable {
5074 unsafe fn push(&self);
5075 unsafe fn pop(&self);
5076}
5077
5078struct PushableGuard<'a, P: Pushable + ?Sized>(&'a P);
5079
5080impl<P: Pushable + ?Sized> Drop for PushableGuard<'_, P> {
5081 fn drop(&mut self) {
5082 unsafe {
5083 self.0.pop();
5084 }
5085 }
5086}
5087
5088#[allow(clippy::needless_lifetimes)]
5089unsafe fn push_guard<'a, P: Pushable>(p: &'a P) -> PushableGuard<'a, P> {
5090 unsafe {
5091 p.push();
5092 PushableGuard(p)
5093 }
5094}
5095
5096impl Pushable for () {
5098 unsafe fn push(&self) {}
5099 unsafe fn pop(&self) {}
5100}
5101
5102impl<A: Pushable, B: Pushable> Pushable for Either<A, B> {
5103 unsafe fn push(&self) {
5104 unsafe {
5105 match self {
5106 Either::Left(a) => A::push(a),
5107 Either::Right(b) => B::push(b),
5108 }
5109 }
5110 }
5111 unsafe fn pop(&self) {
5112 unsafe {
5113 match self {
5114 Either::Left(a) => A::pop(a),
5115 Either::Right(b) => B::pop(b),
5116 }
5117 }
5118 }
5119}
5120
5121impl<A: Pushable> Pushable for (A,) {
5122 unsafe fn push(&self) {
5123 unsafe {
5124 self.0.push();
5125 }
5126 }
5127 unsafe fn pop(&self) {
5128 unsafe {
5129 self.0.pop();
5130 }
5131 }
5132}
5133
5134impl<P: Pushable + ?Sized> Pushable for &P {
5135 unsafe fn push(&self) {
5136 unsafe {
5137 P::push(self);
5138 }
5139 }
5140 unsafe fn pop(&self) {
5141 unsafe {
5142 P::pop(self);
5143 }
5144 }
5145}
5146
5147impl<A: Pushable, B: Pushable> Pushable for (A, B) {
5148 unsafe fn push(&self) {
5149 unsafe {
5150 self.0.push();
5151 self.1.push();
5152 }
5153 }
5154 unsafe fn pop(&self) {
5155 unsafe {
5156 self.1.pop();
5157 self.0.pop();
5158 }
5159 }
5160}
5161
5162impl<A: Pushable, B: Pushable, C: Pushable> Pushable for (A, B, C) {
5163 unsafe fn push(&self) {
5164 unsafe {
5165 self.0.push();
5166 self.1.push();
5167 self.2.push();
5168 }
5169 }
5170 unsafe fn pop(&self) {
5171 unsafe {
5172 self.2.pop();
5173 self.1.pop();
5174 self.0.pop();
5175 }
5176 }
5177}
5178
5179impl<A: Pushable, B: Pushable, C: Pushable, D: Pushable> Pushable for (A, B, C, D) {
5180 unsafe fn push(&self) {
5181 unsafe {
5182 self.0.push();
5183 self.1.push();
5184 self.2.push();
5185 self.3.push();
5186 }
5187 }
5188 unsafe fn pop(&self) {
5189 unsafe {
5190 self.3.pop();
5191 self.2.pop();
5192 self.1.pop();
5193 self.0.pop();
5194 }
5195 }
5196}
5197
5198impl Pushable for &[&dyn Pushable] {
5199 unsafe fn push(&self) {
5200 unsafe {
5201 for st in *self {
5202 st.push();
5203 }
5204 }
5205 }
5206 unsafe fn pop(&self) {
5207 unsafe {
5208 for st in self.iter().rev() {
5209 st.pop();
5210 }
5211 }
5212 }
5213}
5214
5215impl<T: Pushable> Pushable for Option<T> {
5217 unsafe fn push(&self) {
5218 unsafe {
5219 if let Some(s) = self {
5220 s.push();
5221 }
5222 }
5223 }
5224 unsafe fn pop(&self) {
5225 unsafe {
5226 if let Some(s) = self {
5227 s.pop();
5228 }
5229 }
5230 }
5231}
5232
5233impl Pushable for FontId {
5235 unsafe fn push(&self) {
5236 unsafe {
5237 let font = current_font_ptr(*self);
5238 ImGui_PushFont(font, 0.0);
5239 }
5240 }
5241 unsafe fn pop(&self) {
5242 unsafe {
5243 ImGui_PopFont();
5244 }
5245 }
5246}
5247
5248pub struct FontSize(pub f32);
5249
5250impl Pushable for FontSize {
5251 unsafe fn push(&self) {
5252 unsafe {
5253 ImGui_PushFont(std::ptr::null_mut(), self.0);
5255 }
5256 }
5257 unsafe fn pop(&self) {
5258 unsafe {
5259 ImGui_PopFont();
5260 }
5261 }
5262}
5263
5264pub struct FontAndSize(pub FontId, pub f32);
5265
5266impl Pushable for FontAndSize {
5267 unsafe fn push(&self) {
5268 unsafe {
5269 ImGui_PushFont(current_font_ptr(self.0), self.1);
5270 }
5271 }
5272 unsafe fn pop(&self) {
5273 unsafe {
5274 ImGui_PopFont();
5275 }
5276 }
5277}
5278
5279pub type StyleColor = (ColorId, Color);
5280
5281#[derive(Copy, Clone, Debug)]
5282pub enum TextureRef<'a> {
5283 Id(TextureId),
5284 Ref(&'a ImTextureData),
5285}
5286
5287impl TextureRef<'_> {
5288 pub unsafe fn tex_ref(&self) -> ImTextureRef {
5289 match self {
5290 TextureRef::Id(TextureId(id)) => ImTextureRef {
5291 _TexData: null_mut(),
5292 _TexID: *id,
5293 },
5294 TextureRef::Ref(tex_data) => ImTextureRef {
5295 _TexData: (&raw const **tex_data).cast_mut(),
5296 _TexID: 0,
5297 },
5298 }
5299 }
5300
5301 pub unsafe fn tex_id(&self) -> TextureId {
5302 unsafe {
5303 match self {
5304 TextureRef::Id(tex_id) => *tex_id,
5305 TextureRef::Ref(tex_data) => {
5306 let id = tex_data.TexID;
5307 TextureId::from_id(id)
5308 }
5309 }
5310 }
5311 }
5312}
5313
5314#[derive(Copy, Clone, Debug, PartialEq, Eq)]
5315pub struct TextureId(ImTextureID);
5316
5317impl TextureId {
5318 pub fn id(&self) -> ImTextureID {
5319 self.0
5320 }
5321 pub unsafe fn from_id(id: ImTextureID) -> Self {
5322 Self(id)
5323 }
5324}
5325
5326#[derive(Copy, Clone, Debug, PartialEq, Eq)]
5327pub struct TextureUniqueId(i32);
5328
5329impl Pushable for StyleColor {
5330 unsafe fn push(&self) {
5331 unsafe {
5332 ImGui_PushStyleColor1(self.0.bits(), &self.1.into());
5333 }
5334 }
5335 unsafe fn pop(&self) {
5336 unsafe {
5337 ImGui_PopStyleColor(1);
5338 }
5339 }
5340}
5341
5342impl Pushable for [StyleColor] {
5343 unsafe fn push(&self) {
5344 unsafe {
5345 for sc in self {
5346 sc.push();
5347 }
5348 }
5349 }
5350 unsafe fn pop(&self) {
5351 unsafe {
5352 ImGui_PopStyleColor(self.len() as i32);
5353 }
5354 }
5355}
5356
5357impl<const N: usize> Pushable for [StyleColor; N] {
5358 unsafe fn push(&self) {
5359 unsafe {
5360 self.as_slice().push();
5361 }
5362 }
5363 unsafe fn pop(&self) {
5364 unsafe {
5365 self.as_slice().pop();
5366 }
5367 }
5368}
5369
5370pub type StyleColorF = (ColorId, ImVec4);
5371
5372impl Pushable for StyleColorF {
5373 unsafe fn push(&self) {
5374 unsafe {
5375 ImGui_PushStyleColor1(self.0.bits(), &self.1);
5376 }
5377 }
5378 unsafe fn pop(&self) {
5379 unsafe {
5380 ImGui_PopStyleColor(1);
5381 }
5382 }
5383}
5384
5385impl Pushable for [StyleColorF] {
5386 unsafe fn push(&self) {
5387 unsafe {
5388 for sc in self {
5389 sc.push();
5390 }
5391 }
5392 }
5393 unsafe fn pop(&self) {
5394 unsafe {
5395 ImGui_PopStyleColor(self.len() as i32);
5396 }
5397 }
5398}
5399
5400impl<const N: usize> Pushable for [StyleColorF; N] {
5401 unsafe fn push(&self) {
5402 unsafe {
5403 self.as_slice().push();
5404 }
5405 }
5406 unsafe fn pop(&self) {
5407 unsafe {
5408 self.as_slice().pop();
5409 }
5410 }
5411}
5412
5413#[derive(Debug, Copy, Clone)]
5414pub enum StyleValue {
5415 F32(f32),
5416 Vec2(Vector2),
5417 X(f32),
5418 Y(f32),
5419}
5420
5421pub type Style = (StyleVar, StyleValue);
5422
5423impl Pushable for Style {
5424 unsafe fn push(&self) {
5425 unsafe {
5426 match self.1 {
5427 StyleValue::F32(f) => ImGui_PushStyleVar(self.0.bits(), f),
5428 StyleValue::Vec2(v) => ImGui_PushStyleVar1(self.0.bits(), &v2_to_im(v)),
5429 StyleValue::X(x) => ImGui_PushStyleVarX(self.0.bits(), x),
5430 StyleValue::Y(y) => ImGui_PushStyleVarX(self.0.bits(), y),
5431 }
5432 }
5433 }
5434 unsafe fn pop(&self) {
5435 unsafe {
5436 ImGui_PopStyleVar(1);
5437 }
5438 }
5439}
5440
5441impl Pushable for [Style] {
5442 unsafe fn push(&self) {
5443 unsafe {
5444 for sc in self {
5445 sc.push();
5446 }
5447 }
5448 }
5449 unsafe fn pop(&self) {
5450 unsafe {
5451 ImGui_PopStyleVar(self.len() as i32);
5452 }
5453 }
5454}
5455
5456impl<const N: usize> Pushable for [Style; N] {
5457 unsafe fn push(&self) {
5458 unsafe {
5459 self.as_slice().push();
5460 }
5461 }
5462 unsafe fn pop(&self) {
5463 unsafe {
5464 self.as_slice().pop();
5465 }
5466 }
5467}
5468
5469#[derive(Debug, Copy, Clone)]
5470pub struct ItemWidth(pub f32);
5471
5472impl Pushable for ItemWidth {
5473 unsafe fn push(&self) {
5474 unsafe {
5475 ImGui_PushItemWidth(self.0);
5476 }
5477 }
5478 unsafe fn pop(&self) {
5479 unsafe {
5480 ImGui_PopItemWidth();
5481 }
5482 }
5483}
5484
5485#[derive(Debug, Copy, Clone)]
5486pub struct Indent(pub f32);
5487
5488impl Pushable for Indent {
5489 unsafe fn push(&self) {
5490 unsafe {
5491 ImGui_Indent(self.0);
5492 }
5493 }
5494 unsafe fn pop(&self) {
5495 unsafe {
5496 ImGui_Unindent(self.0);
5497 }
5498 }
5499}
5500
5501#[derive(Debug, Copy, Clone)]
5502pub struct TextWrapPos(pub f32);
5503
5504impl Pushable for TextWrapPos {
5505 unsafe fn push(&self) {
5506 unsafe {
5507 ImGui_PushTextWrapPos(self.0);
5508 }
5509 }
5510 unsafe fn pop(&self) {
5511 unsafe {
5512 ImGui_PopTextWrapPos();
5513 }
5514 }
5515}
5516
5517impl Pushable for (ItemFlags, bool) {
5518 unsafe fn push(&self) {
5519 unsafe {
5520 ImGui_PushItemFlag(self.0.bits(), self.1);
5521 }
5522 }
5523 unsafe fn pop(&self) {
5524 unsafe {
5525 ImGui_PopItemFlag();
5526 }
5527 }
5528}
5529
5530#[derive(Debug, Copy, Clone)]
5531pub struct ItemId<H: Hashable>(pub H);
5532
5533impl<H: Hashable> Pushable for ItemId<H> {
5534 unsafe fn push(&self) {
5535 unsafe {
5536 self.0.push();
5537 }
5538 }
5539 unsafe fn pop(&self) {
5540 unsafe {
5541 ImGui_PopID();
5542 }
5543 }
5544}
5545
5546transparent! {
5547 #[derive(Debug)]
5548 pub struct Viewport(ImGuiViewport);
5549}
5550
5551impl Viewport {
5552 pub fn id(&self) -> ImGuiID {
5553 self.ID
5554 }
5555 pub fn flags(&self) -> ViewportFlags {
5556 ViewportFlags::from_bits_truncate(self.Flags)
5557 }
5558 pub fn pos(&self) -> Vector2 {
5559 im_to_v2(self.Pos)
5560 }
5561 pub fn size(&self) -> Vector2 {
5562 im_to_v2(self.Size)
5563 }
5564 pub fn work_pos(&self) -> Vector2 {
5565 im_to_v2(self.WorkPos)
5566 }
5567 pub fn work_size(&self) -> Vector2 {
5568 im_to_v2(self.WorkSize)
5569 }
5570 pub fn center(&self) -> Vector2 {
5571 self.pos() + self.size() / 2.0
5572 }
5573 pub fn work_center(&self) -> Vector2 {
5574 self.work_pos() + self.work_size() / 2.0
5575 }
5576}
5577
5578decl_builder_with_opt! { TableConfig, ImGui_BeginTable, ImGui_EndTable () (S: IntoCStr)
5579 (
5580 str_id (S::Temp) (str_id.as_ptr()),
5581 column (i32) (column),
5582 flags (TableFlags) (flags.bits()),
5583 outer_size (ImVec2) (&outer_size),
5584 inner_width (f32) (inner_width),
5585 )
5586 {
5587 decl_builder_setter!{flags: TableFlags}
5588 decl_builder_setter_vector2!{outer_size: Vector2}
5589 decl_builder_setter!{inner_width: f32}
5590 }
5591 {
5592 pub fn table_config<S: IntoCStr>(&self, str_id: LblId<S>, column: i32) -> TableConfig<S> {
5593 TableConfig {
5594 str_id: str_id.into(),
5595 column,
5596 flags: TableFlags::None,
5597 outer_size: im_vec2(0.0, 0.0),
5598 inner_width: 0.0,
5599 push: (),
5600 }
5601 }
5602 pub fn table_next_row(&self, flags: TableRowFlags, min_row_height: f32) {
5605 unsafe {
5606 ImGui_TableNextRow(flags.bits(), min_row_height);
5607 }
5608 }
5609 pub fn table_next_column(&self) -> bool {
5612 unsafe {
5613 ImGui_TableNextColumn()
5614 }
5615 }
5616 pub fn table_set_column_index(&self, column_n: i32) -> bool {
5619 unsafe {
5620 ImGui_TableSetColumnIndex(column_n)
5621 }
5622 }
5623 pub fn table_setup_column(&self, label: impl IntoCStr, flags: TableColumnFlags, init_width_or_weight: f32, user_id: ImGuiID) {
5624 unsafe {
5625 ImGui_TableSetupColumn(label.into().as_ptr(), flags.bits(), init_width_or_weight, user_id);
5626 }
5627 }
5628 pub fn table_setup_scroll_freeze(&self, cols: i32, rows: i32) {
5630 unsafe {
5631 ImGui_TableSetupScrollFreeze(cols, rows);
5632 }
5633 }
5634 pub fn table_headers_row(&self) {
5637 unsafe {
5638 ImGui_TableHeadersRow();
5639 }
5640 }
5641 pub fn table_angle_headers_row(&self) {
5644 unsafe {
5645 ImGui_TableAngledHeadersRow();
5646 }
5647 }
5648 pub fn table_get_columns_count(&self) -> i32 {
5650 unsafe {
5651 ImGui_TableGetColumnCount()
5652 }
5653 }
5654 pub fn table_get_column_index(&self) -> i32 {
5656 unsafe {
5657 ImGui_TableGetColumnIndex()
5658 }
5659 }
5660 pub fn table_get_hovered_column(&self) -> Option<i32> {
5662 unsafe {
5663 let res = ImGui_TableGetHoveredColumn();
5664 if res < 0 {
5665 None
5666 } else {
5667 Some(res)
5668 }
5669 }
5670 }
5671 pub fn table_get_row_index(&self) -> i32 {
5673 unsafe {
5674 ImGui_TableGetRowIndex()
5675 }
5676 }
5677 pub fn table_get_column_flags(&self, column_n: Option<i32>) -> TableColumnFlags {
5678 let bits = unsafe {
5679 ImGui_TableGetColumnFlags(column_n.unwrap_or(-1))
5680 };
5681 TableColumnFlags::from_bits_truncate(bits)
5682 }
5683 pub fn table_get_column_name(&self, column_n: Option<i32>) -> String {
5686 unsafe {
5687 let c_str = ImGui_TableGetColumnName(column_n.unwrap_or(-1));
5688 CStr::from_ptr(c_str).to_string_lossy().into_owned()
5689 }
5690 }
5691 pub fn table_set_column_enabled(&self, column_n: Option<i32>, enabled: bool) {
5695 unsafe {
5696 ImGui_TableSetColumnEnabled(column_n.unwrap_or(-1), enabled);
5697 };
5698 }
5699 pub fn table_set_bg_color(&self, target: TableBgTarget, color: Color, column_n: Option<i32>) {
5702 unsafe {
5703 ImGui_TableSetBgColor(target.bits(), color.as_u32(), column_n.unwrap_or(-1));
5704 };
5705 }
5706 pub fn table_with_sort_specs(&self, sort_fn: impl FnOnce(&[TableColumnSortSpec])) {
5709 self.table_with_sort_specs_always(|dirty, spec| {
5710 if dirty {
5711 sort_fn(spec);
5712 }
5713 false
5714 })
5715 }
5716 pub fn table_with_sort_specs_always(&self, sort_fn: impl FnOnce(bool, &[TableColumnSortSpec]) -> bool) {
5718 unsafe {
5719 let specs = ImGui_TableGetSortSpecs();
5720 if specs.is_null() {
5721 return;
5722 }
5723 let slice = {
5725 let len = (*specs).SpecsCount as usize;
5726 if len == 0 {
5727 &[]
5728 } else {
5729 let ptr = std::mem::transmute::<*const ImGuiTableColumnSortSpecs, *const TableColumnSortSpec>((*specs).Specs);
5730 std::slice::from_raw_parts(ptr, len)
5731 }
5732 };
5733 (*specs).SpecsDirty = sort_fn((*specs).SpecsDirty, slice);
5734 }
5735 }
5736 }
5737}
5738
5739pub struct DragDropPayloadSetter<'a> {
5741 _dummy: PhantomData<&'a ()>,
5742}
5743
5744pub enum DragDropPayloadCond {
5746 Always,
5747 Once,
5748}
5749
5750impl DragDropPayloadSetter<'_> {
5751 pub fn set(self, type_: impl IntoCStr, data: &[u8], cond: DragDropPayloadCond) -> bool {
5752 let ptr = if data.is_empty() {
5754 null()
5755 } else {
5756 data.as_ptr() as *const c_void
5757 };
5758 let len = data.len();
5759 let cond = match cond {
5760 DragDropPayloadCond::Always => Cond::Always,
5761 DragDropPayloadCond::Once => Cond::Once,
5762 };
5763 unsafe { ImGui_SetDragDropPayload(type_.into().as_ptr(), ptr, len, cond.bits()) }
5764 }
5765}
5766
5767pub struct DragDropPayloadGetter<'a> {
5769 _dummy: PhantomData<&'a ()>,
5770}
5771
5772pub struct DragDropPayload<'a> {
5776 pay: &'a ImGuiPayload,
5777}
5778
5779impl<'a> DragDropPayloadGetter<'a> {
5780 pub fn any(&self, flags: DragDropAcceptFlags) -> Option<DragDropPayload<'a>> {
5781 unsafe {
5782 let pay = ImGui_AcceptDragDropPayload(null(), flags.bits());
5783 if pay.is_null() {
5784 None
5785 } else {
5786 Some(DragDropPayload { pay: &*pay })
5787 }
5788 }
5789 }
5790 pub fn by_type(
5791 &self,
5792 type_: impl IntoCStr,
5793 flags: DragDropAcceptFlags,
5794 ) -> Option<DragDropPayload<'a>> {
5795 unsafe {
5796 let pay = ImGui_AcceptDragDropPayload(type_.into().as_ptr(), flags.bits());
5797 if pay.is_null() {
5798 None
5799 } else {
5800 Some(DragDropPayload { pay: &*pay })
5801 }
5802 }
5803 }
5804 pub fn peek(&self) -> Option<DragDropPayload<'a>> {
5805 unsafe {
5806 let pay = ImGui_GetDragDropPayload();
5807 if pay.is_null() {
5808 None
5809 } else {
5810 Some(DragDropPayload { pay: &*pay })
5811 }
5812 }
5813 }
5814}
5815
5816impl DragDropPayload<'_> {
5817 pub fn is_data_type(&self, type_: impl IntoCStr) -> bool {
5819 if self.pay.DataFrameCount == -1 {
5820 return false;
5821 }
5822 let data_type = unsafe { std::mem::transmute::<&[c_char], &[u8]>(&self.pay.DataType) };
5823 let data_type = CStr::from_bytes_until_nul(data_type).unwrap();
5824 data_type == type_.into().as_ref()
5825 }
5826 pub fn type_(&self) -> Cow<'_, str> {
5827 let data_type = unsafe { std::mem::transmute::<&[c_char], &[u8]>(&self.pay.DataType) };
5828 let data_type = CStr::from_bytes_until_nul(data_type).unwrap();
5829 data_type.to_string_lossy()
5830 }
5831 pub fn is_preview(&self) -> bool {
5832 self.pay.Preview
5833 }
5834 pub fn is_delivery(&self) -> bool {
5835 self.pay.Delivery
5836 }
5837 pub fn data(&self) -> &[u8] {
5838 if self.pay.Data.is_null() {
5839 &[]
5840 } else {
5841 unsafe {
5842 std::slice::from_raw_parts(self.pay.Data as *const u8, self.pay.DataSize as usize)
5843 }
5844 }
5845 }
5846}
5847
5848pub const PAYLOAD_TYPE_COLOR_3F: &CStr =
5849 unsafe { CStr::from_bytes_with_nul_unchecked(IMGUI_PAYLOAD_TYPE_COLOR_3F) };
5850pub const PAYLOAD_TYPE_COLOR_4F: &CStr =
5851 unsafe { CStr::from_bytes_with_nul_unchecked(IMGUI_PAYLOAD_TYPE_COLOR_4F) };
5852
5853#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5858pub struct KeyChord(ImGuiKey);
5859
5860impl KeyChord {
5861 pub fn new(mods: KeyMod, key: Key) -> KeyChord {
5862 KeyChord(ImGuiKey(mods.bits() | key.bits().0))
5863 }
5864 pub fn bits(&self) -> i32 {
5865 self.0.0
5866 }
5867 pub fn from_bits(bits: i32) -> Option<KeyChord> {
5868 let key = bits & !ImGuiKey::ImGuiMod_Mask_.0;
5870 let mods = bits & ImGuiKey::ImGuiMod_Mask_.0;
5871 match (Key::from_bits(ImGuiKey(key)), KeyMod::from_bits(mods)) {
5872 (Some(_), Some(_)) => Some(KeyChord(ImGuiKey(bits))),
5873 _ => None,
5874 }
5875 }
5876 pub fn key(&self) -> Key {
5877 let key = self.bits() & !ImGuiKey::ImGuiMod_Mask_.0;
5878 Key::from_bits(ImGuiKey(key)).unwrap_or(Key::None)
5879 }
5880 pub fn mods(&self) -> KeyMod {
5881 let mods = self.bits() & ImGuiKey::ImGuiMod_Mask_.0;
5882 KeyMod::from_bits_truncate(mods)
5883 }
5884}
5885
5886impl From<Key> for KeyChord {
5887 fn from(value: Key) -> Self {
5888 KeyChord::new(KeyMod::None, value)
5889 }
5890}
5891
5892impl From<(KeyMod, Key)> for KeyChord {
5893 fn from(value: (KeyMod, Key)) -> Self {
5894 KeyChord::new(value.0, value.1)
5895 }
5896}
5897
5898#[repr(transparent)]
5900pub struct TableColumnSortSpec(ImGuiTableColumnSortSpecs);
5901
5902impl std::fmt::Debug for TableColumnSortSpec {
5903 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5904 f.debug_struct("TableColumnSortSpec")
5905 .field("id", &self.id())
5906 .field("index", &self.index())
5907 .field("sort_order", &self.sort_order())
5908 .field("sort_direction", &self.sort_direction())
5909 .finish()
5910 }
5911}
5912
5913impl TableColumnSortSpec {
5914 pub fn id(&self) -> ImGuiID {
5915 self.0.ColumnUserID
5916 }
5917 pub fn index(&self) -> usize {
5918 self.0.ColumnIndex as usize
5919 }
5920 pub fn sort_order(&self) -> usize {
5921 self.0.SortOrder as usize
5922 }
5923 pub fn sort_direction(&self) -> SortDirection {
5924 SortDirection::from_bits(self.0.SortDirection).unwrap_or(SortDirection::None)
5925 }
5926}
5927
5928pub struct DockBuilder {
5929 _dummy: (),
5930}
5931
5932impl DockBuilder {
5933 pub fn set_node_size(&self, node_id: ImGuiID, size: Vector2) {
5934 unsafe {
5935 ImGui_DockBuilderSetNodeSize(node_id, v2_to_im(size));
5936 }
5937 }
5938 pub fn set_node_pos(&self, node_id: ImGuiID, pos: Vector2) {
5939 unsafe {
5940 ImGui_DockBuilderSetNodePos(node_id, v2_to_im(pos));
5941 }
5942 }
5943 pub fn split_node(&self, node_id: ImGuiID, dir: Dir, size_ratio: f32) -> (ImGuiID, ImGuiID) {
5944 unsafe {
5945 let mut id2 = 0;
5946 let id1 = ImGui_DockBuilderSplitNode(
5947 node_id,
5948 dir.bits(),
5949 size_ratio,
5950 std::ptr::null_mut(),
5951 &mut id2,
5952 );
5953 (id1, id2)
5954 }
5955 }
5956 pub fn dock_window(&self, window_name: Id<impl IntoCStr>, node_id: ImGuiID) {
5957 unsafe {
5958 ImGui_DockBuilderDockWindow(window_name.into().as_ptr(), node_id);
5959 }
5960 }
5961 pub fn get_node(&self, node_id: ImGuiID) -> Option<&DockNode> {
5962 unsafe {
5963 let ptr = ImGui_DockBuilderGetNode(node_id);
5964 ptr.as_ref().map(DockNode::cast)
5965 }
5966 }
5967 pub fn get_node_mut(&mut self, node_id: ImGuiID) -> Option<&mut DockNode> {
5968 unsafe {
5969 let ptr = ImGui_DockBuilderGetNode(node_id);
5970 ptr.as_mut().map(DockNode::cast_mut)
5971 }
5972 }
5973}
5974
5975transparent! {
5976 pub struct DockNode(ImGuiDockNode);
5977}
5978
5979impl DockNode {
5980 pub fn local_flags(&self) -> DockNodeFlags {
5981 DockNodeFlags::from_bits_truncate(self.LocalFlags)
5982 }
5983
5984 pub fn set_local_flags(&mut self, flags: DockNodeFlags) {
5985 self.0.LocalFlags = flags.bits();
5987 self.0.MergedFlags = self.0.SharedFlags | self.0.LocalFlags | self.0.LocalFlagsInWindows;
5988 }
5989}
5990
5991transparent_mut! {
5992 #[derive(Debug, Copy, Clone)]
5993 pub struct WindowClass(ImGuiWindowClass);
5994}
5995
5996impl Default for WindowClass {
5997 fn default() -> Self {
5998 WindowClass(ImGuiWindowClass {
6000 ClassId: 0,
6001 ParentViewportId: u32::MAX,
6002 FocusRouteParentWindowId: 0,
6003 ViewportFlagsOverrideSet: 0,
6004 ViewportFlagsOverrideClear: 0,
6005 TabItemFlagsOverrideSet: 0,
6006 DockNodeFlagsOverrideSet: 0,
6007 DockingAlwaysTabBar: false,
6008 DockingAllowUnclassed: true,
6009 PlatformIconData: std::ptr::null_mut(),
6010 })
6011 }
6012}
6013
6014impl WindowClass {
6015 pub fn new() -> Self {
6016 Self::default()
6017 }
6018 pub fn class_id(mut self, id: ImGuiID) -> Self {
6019 self.ClassId = id;
6020 self
6021 }
6022 pub fn parent_viewport_id(mut self, id: Option<ImGuiID>) -> Self {
6023 self.ParentViewportId = id.unwrap_or(u32::MAX);
6024 self
6025 }
6026 pub fn focus_route_parent_window_id(mut self, id: ImGuiID) -> Self {
6027 self.FocusRouteParentWindowId = id;
6028 self
6029 }
6030 pub fn dock_node_flags(mut self, set_flags: DockNodeFlags) -> Self {
6031 self.DockNodeFlagsOverrideSet = set_flags.bits();
6032 self
6033 }
6034 pub fn tab_item_flags(mut self, set_flags: TabItemFlags) -> Self {
6035 self.TabItemFlagsOverrideSet = set_flags.bits();
6036 self
6037 }
6038 pub fn viewport_flags(mut self, set_flags: ViewportFlags, clear_flags: ViewportFlags) -> Self {
6039 self.ViewportFlagsOverrideSet = set_flags.bits();
6040 self.ViewportFlagsOverrideClear = clear_flags.bits();
6041 self
6042 }
6043 pub fn docking_always_tab_bar(mut self, value: bool) -> Self {
6044 self.DockingAlwaysTabBar = value;
6045 self
6046 }
6047 pub fn docking_allow_unclassed(mut self, value: bool) -> Self {
6048 self.DockingAllowUnclassed = value;
6049 self
6050 }
6051}