easy_imgui/
lib.rs

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