Skip to main content

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