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