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`](https://docs.rs/easy-imgui-renderer), that renders the UI using OpenGl, and a matching
8 * window-integrated library, [`easy-imgui-window`](https://docs.rs/easy-imgui-window/), that enables to build a full desktop
9 * application in just a few lines.
10 *
11 * If you don't know where to start, then start with the latter. Take a look at the [examples].
12 * The simplest `easy-imgui` program would be something like this:
13 *
14 * ## A note about labels and ids.
15 *
16 * In [Dear ImGui][1], many controls take a string argument as both a label and an identifier. You can
17 * use `##` or a `###` as a separator between the label and the idenfifier if you want to make them
18 * apart.
19 *
20 * In `easy_imgui`, since version 0.8, this is represented by the [`LblId`] type, not by a plain
21 * string.
22 *
23 * If you want to keep on using the same type just write `lbl("foo")`, `lbl("foo##bar")` or
24 * `"foo".into()` and it will behave the same as before. But if you want to use them
25 * separately, you can write `lbl_id("Label", "id")` and it will join the two strings for you,
26 * separated by `###`. This is particularly nice if you pretend to translate the UI: the labels change,
27 * but the ids should remain constant.
28 *
29 * Some functions only take an id, no label. Those will take an argument of type [`Id`], that you
30 * can construct with the function [`id`], that will prepend the `###` or [`raw_id`] to use the
31 * string as-is. Like before, you can also write `"id".into()` to behave as previous versions of
32 * this crate.
33 *
34 * [1]: https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system
35 *
36 * ```rust, no_run
37 * use easy_imgui_window::{
38 *     easy_imgui as imgui,
39 *     MainWindow,
40 *     MainWindowWithRenderer,
41 *     Application, AppHandler, Args, EventResult,
42 *     winit,
43 * };
44 * use winit::{
45 *     event_loop::{EventLoop, ActiveEventLoop},
46 *     event::WindowEvent,
47 * };
48 *
49 * // The App type, this will do the actual app. stuff.
50 * struct App;
51 *
52 * // This trait handles the UI building.
53 * impl imgui::UiBuilder for App {
54 *     // There are other function in this trait, but this is the only one
55 *     // mandatory and the most important: it build the UI.
56 *     fn do_ui(&mut self, ui: &imgui::Ui<Self>) {
57 *         ui.show_demo_window(None);
58 *     }
59 * }
60 *
61 * // This trait handles the application & event loop stuff.
62 * impl Application for App {
63 *     // The user event type, `()` if not needed.
64 *     type UserEvent = ();
65 *     // Custom data type, `()` if not needed.
66 *     type Data = ();
67 *
68 *     // Create the app object.
69 *     fn new(_: Args<()>) -> App {
70 *         App
71 *     }
72 *     // Handle one window event.
73 *     // There are a few other functions for other types of events.
74 *     fn window_event(&mut self, args: Args<()>, _event: WindowEvent, res: EventResult) {
75 *         if res.window_closed {
76 *             args.event_loop.exit();
77 *         }
78 *     }
79 * }
80 *
81 * fn main() {
82 *     // Create a `winit` event loop.
83 *     let event_loop = EventLoop::new().unwrap();
84 *     // Create an application handler.
85 *     let mut main = AppHandler::<App>::default();
86 *     // Optionally set up the window attributes.
87 *     main.attributes().title = String::from("Example");
88 *     // Run the loop
89 *     event_loop.run_app(&mut main);
90 * }
91 * ```
92 *
93 * # Alternatives
94 * This `crate` is similar to [`imgui-rs`][imguirs], and it is inpired by it, but with a few key
95 * differences:
96 *  * It doesn't use any C++-to-C api generator, as `rust-bindgen` is able to import simple C++
97 *    libraries directly.
98 *  * It is lower level, there are fewer high-level abstractions over the ImGui API. This means
99 *    that:
100 *      * This API is less Rusty than imgui-rs's.
101 *      * If you know how to use Dear ImGui, then you know how to use easy-imgui.
102 *      * It is far easier to upgrade to new Dear ImGui versions.
103 *
104 * # Features
105 * These are the available features for this crate:
106 *  * `freetype`: Uses an external _freetype_ font loader for Dear ImGui, instead of the embedded
107 *    `stb_truetype` library.
108 *
109 * # Usage
110 * It is easier to use one of the higher level crates [`easy-imgui-window`] or [`easy-imgui-renderer`].
111 * But if you intend to render the UI yourself, then you can use this directly.
112 *
113 * These are the main pieces of this crate:
114 *  * [`Context`]: It represents the ImGui context. In DearImgui this is a global variable. Here it
115 *    is a thread-local variable. Still, since it is implicit in most API calls, most uses of this
116 *    type are unsafe. If you use [`easy-imgui-window`] or [`easy-imgui-renderer`] you will rarely
117 *    need to touch this type directly.
118 *  * [`Ui`]: A frame that is being built. Most ImGui functions are members of `Ui`.
119 *  * [`UiBuilder`]: A trait that your application implements do build your user interface.
120 *
121 * If you want to use this library directly, just create a [`Context`], set up its properties, and
122 * when you want to render a frame do [`Context::set_current`] and then [`CurrentContext::do_frame`].
123 *
124 * If you use one of the helper crates then you will just implement `UiBuilder` and get a `Ui` for
125 * free.
126 *
127 * # Conventions
128 * This crate follows a series of naming conventions to make the API more predictable,
129 * particularly with the [`Ui`] member functions:
130 *  * A [`Pushable`] is any value that can be made active by a _push_ function and inactive by a
131 *    corresponding _pop_ function. Examples are styles, colors, fonts...
132 *  * A [`Hashable`] is any value that can be used to build an ImGui hash id. Ideally there should
133 *    be one of these everywhere, but the Dear ImGui API it not totally othogonal here...
134 *  * A function without special prefix or suffix does the same thing as its Dear ImGui
135 *    counterpart. For example [`Ui::button`] calls `ImGui_Button`.
136 *  * A function name that contains the `with` word takes a function that is called immediately. It
137 *    corresponds to a pair of `*Begin` and `*End` functions in Dear ImGui. The function is called
138 *    between these two functions. The value returned will be that of the function.
139 *      * If the function is called based on some condition, such as with `ImGui_BeginChild`, then there
140 *        will be another function with prefix `with_always_` that takes a function with a bool
141 *        argument `opened: bool`, that can be used if you need the function to be called even if the
142 *        condition is not met.
143 *  * A function name that ends as `_config` will create a builder object (with the `must_use`
144 *    annotation). This object will have a few properties to be set and a `build` or a
145 *    `with` function to create the actual UI element.
146 *  * Most builder object have a `push_for_begin` function, that will set up the pushable to be
147 *    used only for the `begin` part of the UI. This is useful for example to set up the style for a
148 *    window but not for its contents.
149 *
150 * When a function takes a value of type `String` this crate will usually take a generic `impl IntoCStr`.
151 * This is an optimization that allows you to pass either a `String`, a `&str`, a `CString` or a
152 * `&CStr`, avoiding an extra allocation if it is not really necessary. If you pass a constant
153 * string and have a recent Rust compiler you can pass a literal `CStr` with the new syntax `c"hello"`.
154 *
155 *
156 *
157 *
158 * [dearimgui]: https://github.com/ocornut/imgui
159 * [imguirs]: https://github.com/imgui-rs/imgui-rs
160 * [examples]: ../../../easy-imgui/examples
161 */
162
163// Too many unsafes ahead
164#![allow(clippy::missing_safety_doc, clippy::too_many_arguments)]
165
166pub use cgmath;
167use easy_imgui_sys::*;
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_keyboard_focus_here(&self, offset: i32) {
2739        unsafe { ImGui_SetKeyboardFocusHere(offset) }
2740    }
2741
2742    with_begin_end! {
2743        /// See `BeginGroup`, `EndGroup`.
2744        group ImGui_BeginGroup ImGui_EndGroup ()
2745    }
2746    with_begin_end! {
2747        /// See `BeginDisabled`, `EndDisabled`.
2748        disabled ImGui_BeginDisabled ImGui_EndDisabled (
2749            disabled (bool) (disabled),
2750        )
2751    }
2752    with_begin_end! {
2753        /// See `PushClipRect`, `PopClipRect`.
2754        clip_rect ImGui_PushClipRect ImGui_PopClipRect (
2755            clip_rect_min (Vector2) (&v2_to_im(clip_rect_min)),
2756            clip_rect_max (Vector2) (&v2_to_im(clip_rect_max)),
2757            intersect_with_current_clip_rect (bool) (intersect_with_current_clip_rect),
2758        )
2759    }
2760
2761    with_begin_end_opt! {
2762        /// See `BeginMainMenuBar`, `EndMainMenuBar`.
2763        main_menu_bar ImGui_BeginMainMenuBar ImGui_EndMainMenuBar ()
2764    }
2765    with_begin_end_opt! {
2766        /// See `BeginMenuBar`, `EndMenuBar`.
2767        menu_bar ImGui_BeginMenuBar ImGui_EndMenuBar ()
2768    }
2769    with_begin_end_opt! {
2770        /// See `BeginTooltip`, `EndTooltip`.
2771        tooltip ImGui_BeginTooltip ImGui_EndTooltip ()
2772    }
2773    with_begin_end_opt! {
2774        /// See `BeginItemTooltip`, `EndTooltip`. There is not `EndItemTooltip`.
2775        item_tooltip ImGui_BeginItemTooltip ImGui_EndTooltip ()
2776    }
2777
2778    /// Calls the `f` functions with the given `push`
2779    pub fn with_push<R>(&self, push: impl Pushable, f: impl FnOnce() -> R) -> R {
2780        unsafe {
2781            let _guard = push_guard(&push);
2782            f()
2783        }
2784    }
2785    pub fn show_demo_window(&self, mut show: Option<&mut bool>) {
2786        unsafe {
2787            ImGui_ShowDemoWindow(optional_mut_bool(&mut show));
2788        }
2789    }
2790    pub fn set_next_window_pos(&self, pos: Vector2, cond: Cond, pivot: Vector2) {
2791        unsafe {
2792            ImGui_SetNextWindowPos(&v2_to_im(pos), cond.bits(), &v2_to_im(pivot));
2793        }
2794    }
2795    pub fn set_next_window_size(&self, size: Vector2, cond: Cond) {
2796        unsafe {
2797            ImGui_SetNextWindowSize(&v2_to_im(size), cond.bits());
2798        }
2799    }
2800    pub fn set_next_window_content_size(&self, size: Vector2) {
2801        unsafe {
2802            ImGui_SetNextWindowContentSize(&v2_to_im(size));
2803        }
2804    }
2805
2806    pub fn set_next_window_collapsed(&self, collapsed: bool, cond: Cond) {
2807        unsafe {
2808            ImGui_SetNextWindowCollapsed(collapsed, cond.bits());
2809        }
2810    }
2811
2812    pub fn set_next_window_focus(&self) {
2813        unsafe {
2814            ImGui_SetNextWindowFocus();
2815        }
2816    }
2817
2818    pub fn set_next_window_scroll(&self, scroll: Vector2) {
2819        unsafe {
2820            ImGui_SetNextWindowScroll(&v2_to_im(scroll));
2821        }
2822    }
2823
2824    pub fn set_next_window_bg_alpha(&self, alpha: f32) {
2825        unsafe {
2826            ImGui_SetNextWindowBgAlpha(alpha);
2827        }
2828    }
2829    pub fn window_draw_list(&self) -> WindowDrawList<'_, A> {
2830        unsafe {
2831            let ptr = ImGui_GetWindowDrawList();
2832            WindowDrawList { ui: self, ptr }
2833        }
2834    }
2835    pub fn window_dpi_scale(&self) -> f32 {
2836        unsafe { ImGui_GetWindowDpiScale() }
2837    }
2838    pub fn foreground_draw_list(&self) -> WindowDrawList<'_, A> {
2839        unsafe {
2840            let ptr = ImGui_GetForegroundDrawList(std::ptr::null_mut());
2841            WindowDrawList { ui: self, ptr }
2842        }
2843    }
2844    pub fn background_draw_list(&self) -> WindowDrawList<'_, A> {
2845        unsafe {
2846            let ptr = ImGui_GetBackgroundDrawList(std::ptr::null_mut());
2847            WindowDrawList { ui: self, ptr }
2848        }
2849    }
2850    pub fn text(&self, text: &str) {
2851        unsafe {
2852            let (start, end) = text_ptrs(text);
2853            ImGui_TextUnformatted(start, end);
2854        }
2855    }
2856    pub fn text_colored(&self, color: Color, text: impl IntoCStr) {
2857        let text = text.into();
2858        unsafe { ImGui_TextColored(&color.into(), c"%s".as_ptr(), text.as_ptr()) }
2859    }
2860    pub fn text_disabled(&self, text: impl IntoCStr) {
2861        let text = text.into();
2862        unsafe { ImGui_TextDisabled(c"%s".as_ptr(), text.as_ptr()) }
2863    }
2864    pub fn text_wrapped(&self, text: impl IntoCStr) {
2865        let text = text.into();
2866        unsafe { ImGui_TextWrapped(c"%s".as_ptr(), text.as_ptr()) }
2867    }
2868    pub fn text_link(&self, label: LblId<impl IntoCStr>) -> bool {
2869        let label = label.into();
2870        unsafe { ImGui_TextLink(label.as_ptr()) }
2871    }
2872    pub fn text_link_open_url(&self, label: LblId<impl IntoCStr>, url: impl IntoCStr) -> bool {
2873        let label = label.into();
2874        let url = url.into();
2875        unsafe { ImGui_TextLinkOpenURL(label.as_ptr(), url.as_ptr()) }
2876    }
2877    pub fn label_text(&self, label: impl IntoCStr, text: impl IntoCStr) {
2878        let label = label.into();
2879        let text = text.into();
2880        unsafe { ImGui_LabelText(label.as_ptr(), c"%s".as_ptr(), text.as_ptr()) }
2881    }
2882    pub fn bullet_text(&self, text: impl IntoCStr) {
2883        let text = text.into();
2884        unsafe { ImGui_BulletText(c"%s".as_ptr(), text.as_ptr()) }
2885    }
2886    pub fn bullet(&self) {
2887        unsafe {
2888            ImGui_Bullet();
2889        }
2890    }
2891    pub fn separator_text(&self, text: impl IntoCStr) {
2892        let text = text.into();
2893        unsafe {
2894            ImGui_SeparatorText(text.as_ptr());
2895        }
2896    }
2897    pub fn separator(&self) {
2898        unsafe {
2899            ImGui_Separator();
2900        }
2901    }
2902
2903    pub fn set_item_default_focus(&self) {
2904        unsafe {
2905            ImGui_SetItemDefaultFocus();
2906        }
2907    }
2908    pub fn is_item_hovered(&self) -> bool {
2909        self.is_item_hovered_ex(HoveredFlags::None)
2910    }
2911    pub fn is_item_hovered_ex(&self, flags: HoveredFlags) -> bool {
2912        unsafe { ImGui_IsItemHovered(flags.bits()) }
2913    }
2914    pub fn is_item_active(&self) -> bool {
2915        unsafe { ImGui_IsItemActive() }
2916    }
2917    pub fn is_item_focused(&self) -> bool {
2918        unsafe { ImGui_IsItemFocused() }
2919    }
2920    pub fn is_item_clicked(&self, flags: MouseButton) -> bool {
2921        unsafe { ImGui_IsItemClicked(flags.bits()) }
2922    }
2923    pub fn is_item_visible(&self) -> bool {
2924        unsafe { ImGui_IsItemVisible() }
2925    }
2926    pub fn is_item_edited(&self) -> bool {
2927        unsafe { ImGui_IsItemEdited() }
2928    }
2929    pub fn is_item_activated(&self) -> bool {
2930        unsafe { ImGui_IsItemActivated() }
2931    }
2932    pub fn is_item_deactivated(&self) -> bool {
2933        unsafe { ImGui_IsItemDeactivated() }
2934    }
2935    pub fn is_item_deactivated_after_edit(&self) -> bool {
2936        unsafe { ImGui_IsItemDeactivatedAfterEdit() }
2937    }
2938    pub fn is_item_toggled_open(&self) -> bool {
2939        unsafe { ImGui_IsItemToggledOpen() }
2940    }
2941    pub fn is_any_item_hovered(&self) -> bool {
2942        unsafe { ImGui_IsAnyItemHovered() }
2943    }
2944    pub fn is_any_item_active(&self) -> bool {
2945        unsafe { ImGui_IsAnyItemActive() }
2946    }
2947    pub fn is_any_item_focused(&self) -> bool {
2948        unsafe { ImGui_IsAnyItemFocused() }
2949    }
2950    pub fn is_window_collapsed(&self) -> bool {
2951        unsafe { ImGui_IsWindowCollapsed() }
2952    }
2953    pub fn is_window_focused(&self, flags: FocusedFlags) -> bool {
2954        unsafe { ImGui_IsWindowFocused(flags.bits()) }
2955    }
2956    pub fn is_window_hovered(&self, flags: FocusedFlags) -> bool {
2957        unsafe { ImGui_IsWindowHovered(flags.bits()) }
2958    }
2959    pub fn get_item_id(&self) -> ImGuiID {
2960        unsafe { ImGui_GetItemID() }
2961    }
2962    pub fn get_id(&self, id: impl Hashable) -> ImGuiID {
2963        unsafe { id.get_id() }
2964    }
2965    pub fn get_item_rect_min(&self) -> Vector2 {
2966        unsafe { im_to_v2(ImGui_GetItemRectMin()) }
2967    }
2968    pub fn get_item_rect_max(&self) -> Vector2 {
2969        unsafe { im_to_v2(ImGui_GetItemRectMax()) }
2970    }
2971    pub fn get_item_rect_size(&self) -> Vector2 {
2972        unsafe { im_to_v2(ImGui_GetItemRectSize()) }
2973    }
2974    pub fn get_item_flags(&self) -> ItemFlags {
2975        unsafe { ItemFlags::from_bits_truncate(ImGui_GetItemFlags()) }
2976    }
2977    /// Available space from current position. This is your best friend!
2978    pub fn get_content_region_avail(&self) -> Vector2 {
2979        unsafe { im_to_v2(ImGui_GetContentRegionAvail()) }
2980    }
2981    pub fn get_window_pos(&self) -> Vector2 {
2982        unsafe { im_to_v2(ImGui_GetWindowPos()) }
2983    }
2984    pub fn get_window_width(&self) -> f32 {
2985        unsafe { ImGui_GetWindowWidth() }
2986    }
2987    pub fn get_window_height(&self) -> f32 {
2988        unsafe { ImGui_GetWindowHeight() }
2989    }
2990    pub fn get_scroll_x(&self) -> f32 {
2991        unsafe { ImGui_GetScrollX() }
2992    }
2993    pub fn get_scroll_y(&self) -> f32 {
2994        unsafe { ImGui_GetScrollY() }
2995    }
2996    pub fn set_scroll_x(&self, scroll_x: f32) {
2997        unsafe {
2998            ImGui_SetScrollX(scroll_x);
2999        }
3000    }
3001    pub fn set_scroll_y(&self, scroll_y: f32) {
3002        unsafe {
3003            ImGui_SetScrollY(scroll_y);
3004        }
3005    }
3006    pub fn get_scroll_max_x(&self) -> f32 {
3007        unsafe { ImGui_GetScrollMaxX() }
3008    }
3009    pub fn get_scroll_max_y(&self) -> f32 {
3010        unsafe { ImGui_GetScrollMaxY() }
3011    }
3012    pub fn set_scroll_here_x(&self, center_x_ratio: f32) {
3013        unsafe {
3014            ImGui_SetScrollHereX(center_x_ratio);
3015        }
3016    }
3017    pub fn set_scroll_here_y(&self, center_y_ratio: f32) {
3018        unsafe {
3019            ImGui_SetScrollHereY(center_y_ratio);
3020        }
3021    }
3022    pub fn set_scroll_from_pos_x(&self, local_x: f32, center_x_ratio: f32) {
3023        unsafe {
3024            ImGui_SetScrollFromPosX(local_x, center_x_ratio);
3025        }
3026    }
3027    pub fn set_scroll_from_pos_y(&self, local_y: f32, center_y_ratio: f32) {
3028        unsafe {
3029            ImGui_SetScrollFromPosY(local_y, center_y_ratio);
3030        }
3031    }
3032    pub fn set_window_pos(&self, pos: Vector2, cond: Cond) {
3033        unsafe {
3034            ImGui_SetWindowPos(&v2_to_im(pos), cond.bits());
3035        }
3036    }
3037    pub fn set_window_size(&self, size: Vector2, cond: Cond) {
3038        unsafe {
3039            ImGui_SetWindowSize(&v2_to_im(size), cond.bits());
3040        }
3041    }
3042    pub fn set_window_collapsed(&self, collapsed: bool, cond: Cond) {
3043        unsafe {
3044            ImGui_SetWindowCollapsed(collapsed, cond.bits());
3045        }
3046    }
3047    pub fn set_window_focus(&self) {
3048        unsafe {
3049            ImGui_SetWindowFocus();
3050        }
3051    }
3052    /// Forces the next control to be in the same line.
3053    pub fn same_line(&self) {
3054        self.same_line_ex(SameLine::Default);
3055    }
3056    /// Forces the next control to be in the same line, with custom spacing.
3057    pub fn same_line_ex(&self, same_line: SameLine) {
3058        let (offset_from_start_x, spacing) = match same_line {
3059            SameLine::Default => (0.0, -1.0),
3060            // The user asked for offset=0.0, but if we use (0.0, 0.0) then ImGui
3061            // will do as if Spacing(0.0). Move it just a little and compensate with spc.
3062            SameLine::OffsetFromStart(offs) => {
3063                if offs != 0.0 {
3064                    (offs, 0.0)
3065                } else {
3066                    (-f32::MIN_POSITIVE, f32::MIN_POSITIVE)
3067                }
3068            }
3069            // If spc were negative it would switch to default.
3070            SameLine::Spacing(spc) => (0.0, spc.max(0.0)),
3071        };
3072        unsafe {
3073            ImGui_SameLine(offset_from_start_x, spacing);
3074        }
3075    }
3076    pub fn new_line(&self) {
3077        unsafe {
3078            ImGui_NewLine();
3079        }
3080    }
3081    pub fn spacing(&self) {
3082        unsafe {
3083            ImGui_Spacing();
3084        }
3085    }
3086    pub fn dummy(&self, size: Vector2) {
3087        unsafe {
3088            ImGui_Dummy(&v2_to_im(size));
3089        }
3090    }
3091    pub fn indent(&self, indent_w: f32) {
3092        unsafe {
3093            ImGui_Indent(indent_w);
3094        }
3095    }
3096    pub fn unindent(&self, indent_w: f32) {
3097        unsafe {
3098            ImGui_Unindent(indent_w);
3099        }
3100    }
3101    /// Prefer `get_cursor_screen_pos` over this.
3102    pub fn get_cursor_pos(&self) -> Vector2 {
3103        unsafe { im_to_v2(ImGui_GetCursorPos()) }
3104    }
3105    /// Prefer `get_cursor_screen_pos` over this.
3106    pub fn get_cursor_pos_x(&self) -> f32 {
3107        unsafe { ImGui_GetCursorPosX() }
3108    }
3109    /// Prefer `get_cursor_screen_pos` over this.
3110    pub fn get_cursor_pos_y(&self) -> f32 {
3111        unsafe { ImGui_GetCursorPosY() }
3112    }
3113    /// Prefer `set_cursor_screen_pos` over this.
3114    pub fn set_cursor_pos(&self, local_pos: Vector2) {
3115        unsafe {
3116            ImGui_SetCursorPos(&v2_to_im(local_pos));
3117        }
3118    }
3119    /// Prefer `set_cursor_screen_pos` over this.
3120    pub fn set_cursor_pos_x(&self, local_x: f32) {
3121        unsafe {
3122            ImGui_SetCursorPosX(local_x);
3123        }
3124    }
3125    /// Prefer `set_cursor_screen_pos` over this.
3126    pub fn set_cursor_pos_y(&self, local_y: f32) {
3127        unsafe {
3128            ImGui_SetCursorPosY(local_y);
3129        }
3130    }
3131    /// Prefer `get_cursor_screen_pos` over this.
3132    pub fn get_cursor_start_pos(&self) -> Vector2 {
3133        unsafe { im_to_v2(ImGui_GetCursorStartPos()) }
3134    }
3135    /// Get cursor position in absolute coordinates. This is your best friend!
3136    pub fn get_cursor_screen_pos(&self) -> Vector2 {
3137        unsafe { im_to_v2(ImGui_GetCursorScreenPos()) }
3138    }
3139    /// Set cursor position in absolute coordinates. This is your best friend!
3140    pub fn set_cursor_screen_pos(&self, pos: Vector2) {
3141        unsafe {
3142            ImGui_SetCursorScreenPos(&v2_to_im(pos));
3143        }
3144    }
3145    pub fn align_text_to_frame_padding(&self) {
3146        unsafe {
3147            ImGui_AlignTextToFramePadding();
3148        }
3149    }
3150    pub fn get_text_line_height(&self) -> f32 {
3151        unsafe { ImGui_GetTextLineHeight() }
3152    }
3153    pub fn get_text_line_height_with_spacing(&self) -> f32 {
3154        unsafe { ImGui_GetTextLineHeightWithSpacing() }
3155    }
3156    pub fn get_frame_height(&self) -> f32 {
3157        unsafe { ImGui_GetFrameHeight() }
3158    }
3159    pub fn get_frame_height_with_spacing(&self) -> f32 {
3160        unsafe { ImGui_GetFrameHeightWithSpacing() }
3161    }
3162    pub fn calc_item_width(&self) -> f32 {
3163        unsafe { ImGui_CalcItemWidth() }
3164    }
3165    pub fn calc_text_size(&self, text: &str) -> Vector2 {
3166        self.calc_text_size_ex(text, false, -1.0)
3167    }
3168    pub fn calc_text_size_ex(
3169        &self,
3170        text: &str,
3171        hide_text_after_double_hash: bool,
3172        wrap_width: f32,
3173    ) -> Vector2 {
3174        unsafe {
3175            let (start, end) = text_ptrs(text);
3176            im_to_v2(ImGui_CalcTextSize(
3177                start,
3178                end,
3179                hide_text_after_double_hash,
3180                wrap_width,
3181            ))
3182        }
3183    }
3184    pub fn set_color_edit_options(&self, flags: ColorEditFlags) {
3185        unsafe {
3186            ImGui_SetColorEditOptions(flags.bits());
3187        }
3188    }
3189    pub fn key_mods(&self) -> KeyMod {
3190        let mods = self.io().KeyMods;
3191        KeyMod::from_bits_truncate(mods & ImGuiKey::ImGuiMod_Mask_.0)
3192    }
3193    pub fn is_key_down(&self, key: Key) -> bool {
3194        unsafe { ImGui_IsKeyDown(key.bits()) }
3195    }
3196    pub fn is_key_pressed(&self, key: Key) -> bool {
3197        unsafe {
3198            ImGui_IsKeyPressed(key.bits(), /*repeat*/ true)
3199        }
3200    }
3201    pub fn is_key_pressed_no_repeat(&self, key: Key) -> bool {
3202        unsafe {
3203            ImGui_IsKeyPressed(key.bits(), /*repeat*/ false)
3204        }
3205    }
3206    pub fn is_key_released(&self, key: Key) -> bool {
3207        unsafe { ImGui_IsKeyReleased(key.bits()) }
3208    }
3209    pub fn get_key_pressed_amount(&self, key: Key, repeat_delay: f32, rate: f32) -> i32 {
3210        unsafe { ImGui_GetKeyPressedAmount(key.bits(), repeat_delay, rate) }
3211    }
3212    pub fn get_font_tex_uv_white_pixel(&self) -> Vector2 {
3213        unsafe { im_to_v2(ImGui_GetFontTexUvWhitePixel()) }
3214    }
3215    //GetKeyName
3216    //SetNextFrameWantCaptureKeyboard
3217    pub fn get_font_size(&self) -> f32 {
3218        unsafe { ImGui_GetFontSize() }
3219    }
3220    pub fn is_mouse_down(&self, button: MouseButton) -> bool {
3221        unsafe { ImGui_IsMouseDown(button.bits()) }
3222    }
3223    pub fn is_mouse_clicked(&self, button: MouseButton) -> bool {
3224        unsafe {
3225            ImGui_IsMouseClicked(button.bits(), /*repeat*/ false)
3226        }
3227    }
3228    pub fn is_mouse_clicked_repeat(&self, button: MouseButton) -> bool {
3229        unsafe {
3230            ImGui_IsMouseClicked(button.bits(), /*repeat*/ true)
3231        }
3232    }
3233    pub fn is_mouse_released(&self, button: MouseButton) -> bool {
3234        unsafe { ImGui_IsMouseReleased(button.bits()) }
3235    }
3236    pub fn is_mouse_double_clicked(&self, button: MouseButton) -> bool {
3237        unsafe { ImGui_IsMouseDoubleClicked(button.bits()) }
3238    }
3239    pub fn get_mouse_clicked_count(&self, button: MouseButton) -> i32 {
3240        unsafe { ImGui_GetMouseClickedCount(button.bits()) }
3241    }
3242    pub fn is_rect_visible_size(&self, size: Vector2) -> bool {
3243        unsafe { ImGui_IsRectVisible(&v2_to_im(size)) }
3244    }
3245    pub fn is_rect_visible(&self, rect_min: Vector2, rect_max: Vector2) -> bool {
3246        unsafe { ImGui_IsRectVisible1(&v2_to_im(rect_min), &v2_to_im(rect_max)) }
3247    }
3248    /*
3249    pub fn is_mouse_hovering_rect(&self) -> bool {
3250        unsafe {
3251            ImGui_IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);
3252        }
3253    }
3254    pub fn is_mouse_pos_valid(&self) -> bool {
3255        unsafe {
3256            ImGui_IsMousePosValid(const ImVec2* mouse_pos = NULL);
3257        }
3258    }*/
3259    pub fn is_any_mouse_down(&self) -> bool {
3260        unsafe { ImGui_IsAnyMouseDown() }
3261    }
3262    pub fn get_mouse_pos(&self) -> Vector2 {
3263        unsafe { im_to_v2(ImGui_GetMousePos()) }
3264    }
3265    pub fn get_mouse_pos_on_opening_current_popup(&self) -> Vector2 {
3266        unsafe { im_to_v2(ImGui_GetMousePosOnOpeningCurrentPopup()) }
3267    }
3268    pub fn is_mouse_dragging(&self, button: MouseButton) -> bool {
3269        unsafe {
3270            ImGui_IsMouseDragging(button.bits(), /*lock_threshold*/ -1.0)
3271        }
3272    }
3273    pub fn get_mouse_drag_delta(&self, button: MouseButton) -> Vector2 {
3274        unsafe {
3275            im_to_v2(ImGui_GetMouseDragDelta(
3276                button.bits(),
3277                /*lock_threshold*/ -1.0,
3278            ))
3279        }
3280    }
3281    pub fn reset_mouse_drag_delta(&self, button: MouseButton) {
3282        unsafe {
3283            ImGui_ResetMouseDragDelta(button.bits());
3284        }
3285    }
3286    pub fn get_mouse_cursor(&self) -> MouseCursor {
3287        unsafe { MouseCursor::from_bits(ImGui_GetMouseCursor()).unwrap_or(MouseCursor::None) }
3288    }
3289    pub fn set_mouse_cursor(&self, cursor_type: MouseCursor) {
3290        unsafe {
3291            ImGui_SetMouseCursor(cursor_type.bits());
3292        }
3293    }
3294    pub fn get_time(&self) -> f64 {
3295        unsafe { ImGui_GetTime() }
3296    }
3297    pub fn get_frame_count(&self) -> i32 {
3298        unsafe { ImGui_GetFrameCount() }
3299    }
3300    pub fn is_popup_open(&self, str_id: Option<Id<impl IntoCStr>>) -> bool {
3301        self.is_popup_open_ex(str_id, PopupFlags::None)
3302    }
3303    pub fn is_popup_open_ex(&self, str_id: Option<Id<impl IntoCStr>>, flags: PopupFlags) -> bool {
3304        let temp;
3305        let str_id = match str_id {
3306            Some(s) => {
3307                temp = IntoCStr::into(s.0);
3308                temp.as_ptr()
3309            }
3310            None => null(),
3311        };
3312        unsafe { ImGui_IsPopupOpen(str_id, flags.bits()) }
3313    }
3314    /// Returns true if the current window is below a modal pop-up.
3315    pub fn is_below_blocking_modal(&self) -> bool {
3316        // Beware: internal API
3317        unsafe {
3318            let modal = ImGui_FindBlockingModal(self.CurrentWindow);
3319            !modal.is_null()
3320        }
3321    }
3322    /// Return true if there is any modal window opened
3323    pub fn is_blocking_modal(&self) -> bool {
3324        // Beware: internal API
3325        unsafe {
3326            let modal = ImGui_FindBlockingModal(std::ptr::null_mut());
3327            !modal.is_null()
3328        }
3329    }
3330    pub fn open_popup(&self, str_id: Id<impl IntoCStr>) {
3331        self.open_popup_ex(str_id, PopupFlags::None)
3332    }
3333    pub fn open_popup_ex(&self, str_id: Id<impl IntoCStr>, flags: PopupFlags) {
3334        let str_id = str_id.into();
3335        unsafe {
3336            ImGui_OpenPopup(str_id.as_ptr(), flags.bits());
3337        }
3338    }
3339    pub fn close_current_popup(&self) {
3340        unsafe {
3341            ImGui_CloseCurrentPopup();
3342        }
3343    }
3344    pub fn is_window_appearing(&self) -> bool {
3345        unsafe { ImGui_IsWindowAppearing() }
3346    }
3347    pub fn with_always_drag_drop_source<R>(
3348        &self,
3349        flags: DragDropSourceFlags,
3350        f: impl FnOnce(Option<DragDropPayloadSetter<'_>>) -> R,
3351    ) -> R {
3352        if !unsafe { ImGui_BeginDragDropSource(flags.bits()) } {
3353            return f(None);
3354        }
3355        let payload = DragDropPayloadSetter {
3356            _dummy: PhantomData,
3357        };
3358        let r = f(Some(payload));
3359        unsafe { ImGui_EndDragDropSource() }
3360        r
3361    }
3362    pub fn with_drag_drop_source<R>(
3363        &self,
3364        flags: DragDropSourceFlags,
3365        f: impl FnOnce(DragDropPayloadSetter<'_>) -> R,
3366    ) -> Option<R> {
3367        self.with_always_drag_drop_source(flags, move |r| r.map(f))
3368    }
3369    pub fn with_always_drag_drop_target<R>(
3370        &self,
3371        f: impl FnOnce(Option<DragDropPayloadGetter<'_>>) -> R,
3372    ) -> R {
3373        if !unsafe { ImGui_BeginDragDropTarget() } {
3374            return f(None);
3375        }
3376        let payload = DragDropPayloadGetter {
3377            _dummy: PhantomData,
3378        };
3379        let r = f(Some(payload));
3380        unsafe { ImGui_EndDragDropTarget() }
3381        r
3382    }
3383    pub fn with_drag_drop_target<R>(
3384        &self,
3385        f: impl FnOnce(DragDropPayloadGetter<'_>) -> R,
3386    ) -> Option<R> {
3387        self.with_always_drag_drop_target(move |r| r.map(f))
3388    }
3389
3390    #[must_use]
3391    pub fn list_clipper(&self, items_count: usize) -> ListClipper {
3392        ListClipper {
3393            items_count,
3394            items_height: -1.0,
3395            included_ranges: Vec::new(),
3396        }
3397    }
3398
3399    pub fn shortcut(&self, key_chord: impl Into<KeyChord>) -> bool {
3400        unsafe { ImGui_Shortcut(key_chord.into().bits(), 0) }
3401    }
3402    pub fn shortcut_ex(&self, key_chord: impl Into<KeyChord>, flags: InputFlags) -> bool {
3403        unsafe { ImGui_Shortcut(key_chord.into().bits(), flags.bits()) }
3404    }
3405    pub fn set_next_item_shortcut(&self, key_chord: impl Into<KeyChord>) {
3406        unsafe {
3407            ImGui_SetNextItemShortcut(key_chord.into().bits(), 0);
3408        }
3409    }
3410    pub fn set_next_item_shortcut_ex(&self, key_chord: impl Into<KeyChord>, flags: InputFlags) {
3411        unsafe {
3412            ImGui_SetNextItemShortcut(key_chord.into().bits(), flags.bits());
3413        }
3414    }
3415    pub fn is_keychord_pressed(&self, key_chord: impl Into<KeyChord>) -> bool {
3416        unsafe { ImGui_IsKeyChordPressed(key_chord.into().bits()) }
3417    }
3418
3419    /// Gets the font details for a `FontId`.
3420    pub fn get_font(&self, font_id: FontId) -> &Font {
3421        unsafe {
3422            let font = self.io().font_atlas().font_ptr(font_id);
3423            Font::cast(&*font)
3424        }
3425    }
3426
3427    /// Gets more information about a font.
3428    ///
3429    /// This is a member of `Ui` instead of `FontAtlas` because it requires the atlas to be fully
3430    /// built and that is only ensured during the frame, that is when there is a `&Ui`.
3431    pub fn get_font_baked(
3432        &self,
3433        font_id: FontId,
3434        font_size: f32,
3435        font_density: Option<f32>,
3436    ) -> &FontBaked {
3437        unsafe {
3438            let font = self.io().font_atlas().font_ptr(font_id);
3439            let baked = (*font).GetFontBaked(font_size, font_density.unwrap_or(-1.0));
3440            FontBaked::cast(&*baked)
3441        }
3442    }
3443
3444    pub fn get_atlas_texture_ref(&self) -> TextureRef<'_> {
3445        let tex_data = self.io().font_atlas().TexData;
3446        let tex_data = unsafe { &*tex_data };
3447        TextureRef::Ref(tex_data)
3448    }
3449
3450    pub fn get_custom_rect(&self, index: CustomRectIndex) -> Option<TextureRect<'_>> {
3451        let atlas = self.io().font_atlas();
3452        let rect = unsafe {
3453            let mut rect = MaybeUninit::zeroed();
3454            let ok = atlas.GetCustomRect(index.0, rect.as_mut_ptr());
3455            if !ok {
3456                return None;
3457            }
3458            rect.assume_init()
3459        };
3460
3461        let tex_ref = self.get_atlas_texture_ref();
3462        Some(TextureRect { rect, tex_ref })
3463    }
3464
3465    pub fn dock_space(
3466        &self,
3467        id: ImGuiID,
3468        size: Vector2,
3469        flags: DockNodeFlags,
3470        window_class: Option<&WindowClass>,
3471    ) -> ImGuiID {
3472        unsafe {
3473            ImGui_DockSpace(
3474                id,
3475                &v2_to_im(size),
3476                flags.bits(),
3477                window_class
3478                    .as_ref()
3479                    .map(|e| &raw const e.0)
3480                    .unwrap_or_default(),
3481            )
3482        }
3483    }
3484    pub fn dock_space_over_viewport(
3485        &self,
3486        dockspace_id: ImGuiID,
3487        viewport: &Viewport,
3488        flags: DockNodeFlags,
3489        window_class: Option<&WindowClass>,
3490    ) -> ImGuiID {
3491        unsafe {
3492            ImGui_DockSpaceOverViewport(
3493                dockspace_id,
3494                viewport.get(),
3495                flags.bits(),
3496                window_class
3497                    .as_ref()
3498                    .map(|e| &raw const e.0)
3499                    .unwrap_or_default(),
3500            )
3501        }
3502    }
3503    pub fn set_next_window_dock_id(&self, dock_id: ImGuiID, cond: Cond) {
3504        unsafe {
3505            ImGui_SetNextWindowDockID(dock_id, cond.bits());
3506        }
3507    }
3508    pub fn set_next_window_class(&self, window_class: &WindowClass) {
3509        unsafe {
3510            ImGui_SetNextWindowClass(&window_class.0);
3511        }
3512    }
3513    pub fn get_window_dock_id(&self) -> ImGuiID {
3514        unsafe { ImGui_GetWindowDockID() }
3515    }
3516    pub fn is_window_docked(&self) -> bool {
3517        unsafe { ImGui_IsWindowDocked() }
3518    }
3519
3520    /// This allows to build your own docking, and dock your windows.
3521    ///
3522    /// WARNING: Experimental DearImGui feature and experimental binding.
3523    ///
3524    /// You must follow these rules:
3525    /// * Call this function when you want to dock your windows, usually in the very first frame.
3526    ///   or in the "reset views" menu option. Do NOT call it on every frame!
3527    /// * Call after creating the dockings but before creating the windows.
3528    pub fn dock_builder(
3529        &self,
3530        id: Option<ImGuiID>,
3531        flags: DockNodeFlags,
3532        fn_build: impl FnOnce(ImGuiID, &mut DockBuilder),
3533    ) {
3534        struct DockBuilderFinishGuard(ImGuiID);
3535        impl Drop for DockBuilderFinishGuard {
3536            fn drop(&mut self) {
3537                unsafe {
3538                    ImGui_DockBuilderFinish(self.0);
3539                }
3540            }
3541        }
3542
3543        unsafe {
3544            let id = ImGui_DockBuilderAddNode(id.unwrap_or(0), flags.bits());
3545            let _guard = DockBuilderFinishGuard(id);
3546            let mut db = DockBuilder { _dummy: () };
3547            fn_build(id, &mut db);
3548        }
3549    }
3550
3551    pub fn get_window_viewport(&self) -> &Viewport {
3552        unsafe { Viewport::cast(&*ImGui_GetWindowViewport()) }
3553    }
3554    pub fn set_next_window_viewport(&self, id: ImGuiID) {
3555        unsafe { ImGui_SetNextWindowViewport(id) }
3556    }
3557    pub fn viewport_foreground_draw_list(&self, viewport: &Viewport) -> WindowDrawList<'_, A> {
3558        unsafe {
3559            let ptr = ImGui_GetForegroundDrawList((&raw const *viewport.get()).cast_mut());
3560            WindowDrawList { ui: self, ptr }
3561        }
3562    }
3563    pub fn viewport_background_draw_list(&self, viewport: &Viewport) -> WindowDrawList<'_, A> {
3564        unsafe {
3565            let ptr = ImGui_GetBackgroundDrawList((&raw const *viewport.get()).cast_mut());
3566            WindowDrawList { ui: self, ptr }
3567        }
3568    }
3569}
3570
3571#[derive(Debug, Copy, Clone)]
3572pub struct TextureRect<'ui> {
3573    pub rect: ImFontAtlasRect,
3574    pub tex_ref: TextureRef<'ui>,
3575}
3576
3577pub struct ListClipper {
3578    items_count: usize,
3579    items_height: f32,
3580    included_ranges: Vec<std::ops::Range<usize>>,
3581}
3582
3583impl ListClipper {
3584    decl_builder_setter! {items_height: f32}
3585
3586    pub fn add_included_range(&mut self, range: std::ops::Range<usize>) {
3587        self.included_ranges.push(range);
3588    }
3589
3590    pub fn with(self, mut f: impl FnMut(usize)) {
3591        unsafe {
3592            let mut clip = ImGuiListClipper::new();
3593            clip.Begin(self.items_count as i32, self.items_height);
3594            for r in self.included_ranges {
3595                clip.IncludeItemsByIndex(r.start as i32, r.end as i32);
3596            }
3597            while clip.Step() {
3598                for i in clip.DisplayStart..clip.DisplayEnd {
3599                    f(i as usize);
3600                }
3601            }
3602        }
3603    }
3604}
3605
3606transparent! {
3607    // TODO: do a proper impl Font?
3608    pub struct Font(ImFont);
3609}
3610
3611transparent! {
3612    pub struct FontGlyph(ImFontGlyph);
3613}
3614
3615impl FontGlyph {
3616    pub fn p0(&self) -> Vector2 {
3617        Vector2::new(self.0.X0, self.0.Y0)
3618    }
3619    pub fn p1(&self) -> Vector2 {
3620        Vector2::new(self.0.X1, self.0.Y1)
3621    }
3622    pub fn uv0(&self) -> Vector2 {
3623        Vector2::new(self.0.U0, self.0.V0)
3624    }
3625    pub fn uv1(&self) -> Vector2 {
3626        Vector2::new(self.0.U1, self.0.V1)
3627    }
3628    pub fn advance_x(&self) -> f32 {
3629        self.0.AdvanceX
3630    }
3631    pub fn visible(&self) -> bool {
3632        self.0.Visible() != 0
3633    }
3634    pub fn colored(&self) -> bool {
3635        self.0.Colored() != 0
3636    }
3637    pub fn codepoint(&self) -> char {
3638        char::try_from(self.0.Codepoint()).unwrap()
3639    }
3640}
3641
3642impl std::fmt::Debug for FontGlyph {
3643    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
3644        fmt.debug_struct("FontGlyph")
3645            .field("p0", &self.p0())
3646            .field("p1", &self.p1())
3647            .field("uv0", &self.uv0())
3648            .field("uv1", &self.uv1())
3649            .field("advance_x", &self.advance_x())
3650            .field("visible", &self.visible())
3651            .field("colored", &self.colored())
3652            .field("codepoint", &self.codepoint())
3653            .finish()
3654    }
3655}
3656
3657transparent! {
3658    #[derive(Debug)]
3659    pub struct FontBaked(ImFontBaked);
3660}
3661
3662impl FontBaked {
3663    /// Gets information about a glyph for a font.
3664    pub fn find_glyph(&self, c: char) -> &FontGlyph {
3665        unsafe {
3666            FontGlyph::cast(&*ImFontBaked_FindGlyph(
3667                (&raw const self.0).cast_mut(),
3668                ImWchar::from(c),
3669            ))
3670        }
3671    }
3672
3673    /// Just like `find_glyph` but doesn't use the fallback character for unavailable glyphs.
3674    pub fn find_glyph_no_fallback(&self, c: char) -> Option<&FontGlyph> {
3675        unsafe {
3676            let p =
3677                ImFontBaked_FindGlyphNoFallback((&raw const self.0).cast_mut(), ImWchar::from(c));
3678            p.as_ref().map(FontGlyph::cast)
3679        }
3680    }
3681
3682    pub unsafe fn inner(&mut self) -> &mut ImFontBaked {
3683        &mut self.0
3684    }
3685
3686    // The only safe values for a loader to set are these
3687    pub fn set_ascent(&mut self, ascent: f32) {
3688        self.0.Ascent = ascent;
3689    }
3690    pub fn set_descent(&mut self, descent: f32) {
3691        self.0.Descent = descent;
3692    }
3693}
3694
3695/// Identifier of a registered font.
3696///
3697/// `FontId::default()` will be the default font.
3698#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3699pub struct FontId(u32);
3700
3701/// Identifier for a registered custom rectangle.
3702///
3703/// The `CustomRectIndex::default()` is provided as a convenience, but it is always invalid, and
3704/// will panic if used.
3705#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3706pub struct CustomRectIndex(i32);
3707
3708impl Default for CustomRectIndex {
3709    fn default() -> Self {
3710        // Always invalid, do not use!
3711        CustomRectIndex(-1)
3712    }
3713}
3714
3715transparent! {
3716    #[derive(Debug)]
3717    pub struct FontAtlas(ImFontAtlas);
3718}
3719
3720type PixelImage<'a> = image::ImageBuffer<image::Rgba<u8>, &'a mut [u8]>;
3721type SubPixelImage<'a, 'b> = image::SubImage<&'a mut PixelImage<'b>>;
3722
3723impl FontAtlas {
3724    pub unsafe fn texture_ref(&self) -> ImTextureRef {
3725        self.TexRef
3726    }
3727    pub unsafe fn inner(&mut self) -> &mut ImFontAtlas {
3728        &mut self.0
3729    }
3730
3731    pub fn current_texture_unique_id(&self) -> TextureUniqueId {
3732        unsafe {
3733            let id = (*self.TexRef._TexData).UniqueID;
3734            TextureUniqueId(id)
3735        }
3736    }
3737
3738    fn texture_unique_id(&self, uid: TextureUniqueId) -> Option<&ImTextureData> {
3739        unsafe {
3740            self.TexList
3741                .iter()
3742                .find(|x| (***x).UniqueID == uid.0)
3743                .map(|p| &**p)
3744        }
3745    }
3746
3747    unsafe fn font_ptr(&self, font: FontId) -> *mut ImFont {
3748        unsafe {
3749            // fonts.Fonts is never empty, at least there is the default font
3750            *self
3751                .Fonts
3752                .iter()
3753                .find(|f| f.as_ref().map(|f| f.FontId) == Some(font.0))
3754                .unwrap_or(&self.Fonts[0])
3755        }
3756    }
3757
3758    pub fn check_texture_unique_id(&self, uid: TextureUniqueId) -> bool {
3759        self.texture_unique_id(uid).is_some_and(|x| {
3760            !matches!(
3761                x.Status,
3762                ImTextureStatus::ImTextureStatus_WantDestroy
3763                    | ImTextureStatus::ImTextureStatus_Destroyed
3764            )
3765        })
3766    }
3767
3768    pub fn get_texture_by_unique_id(&self, uid: TextureUniqueId) -> Option<TextureId> {
3769        let p = self.texture_unique_id(uid)?;
3770        // Allows for ImTextureStatus_WantDestroy, because the TexID may still be valid
3771        if p.Status == ImTextureStatus::ImTextureStatus_Destroyed || p.TexID == 0 {
3772            None
3773        } else {
3774            unsafe { Some(TextureId::from_id(p.TexID)) }
3775        }
3776    }
3777
3778    /// Adds the given font to the atlas.
3779    ///
3780    /// It returns the id to use this font. `FontId` implements `Pushable` so you can use it with
3781    /// [`Ui::with_push`].
3782    pub fn add_font(&mut self, font: FontInfo) -> FontId {
3783        self.add_font_priv(font, false)
3784    }
3785
3786    pub fn remove_font(&mut self, font_id: FontId) {
3787        unsafe {
3788            let f = self.font_ptr(font_id);
3789            // Do not delete the default font!
3790            /*if std::ptr::eq(f, self.Fonts[0]) {
3791                return;
3792            }*/
3793            self.0.RemoveFont(f);
3794        }
3795    }
3796
3797    /// Adds several fonts with as a single ImGui font.
3798    ///
3799    /// This is useful mainly if different TTF files have different charset coverage but you want
3800    /// to use them all as a unit.
3801    pub fn add_font_collection(&mut self, fonts: impl IntoIterator<Item = FontInfo>) -> FontId {
3802        let mut fonts = fonts.into_iter();
3803        let first = fonts.next().expect("empty font collection");
3804        let id = self.add_font_priv(first, false);
3805        for font in fonts {
3806            self.add_font_priv(font, true);
3807        }
3808        id
3809    }
3810    fn add_font_priv(&mut self, font: FontInfo, merge: bool) -> FontId {
3811        unsafe {
3812            let mut fc = ImFontConfig::new();
3813            // This is ours, do not free()
3814            fc.FontDataOwnedByAtlas = false;
3815            fc.MergeMode = merge;
3816            if !font.name.is_empty() {
3817                let cname = font.name.as_bytes();
3818                let name_len = cname.len().min(fc.Name.len() - 1);
3819                fc.Name[..name_len]
3820                    .copy_from_slice(std::mem::transmute::<&[u8], &[c_char]>(&cname[..name_len]));
3821                fc.Name[name_len] = 0;
3822            }
3823            fc.Flags = font.flags.bits();
3824            fc.SizePixels = font.size;
3825
3826            let font_ptr = match font.ttf {
3827                TtfData::Bytes(bytes) => {
3828                    self.0.AddFontFromMemoryTTF(
3829                        bytes.as_ptr() as *mut _,
3830                        bytes.len() as i32,
3831                        /* size_pixels */ 0.0,
3832                        &fc,
3833                        std::ptr::null(),
3834                    )
3835                }
3836                TtfData::DefaultFont(DefaultFontSelector::Auto) => self.0.AddFontDefault(&fc),
3837                TtfData::DefaultFont(DefaultFontSelector::Bitmap) => {
3838                    self.0.AddFontDefaultBitmap(&fc)
3839                }
3840                TtfData::DefaultFont(DefaultFontSelector::Vector) => {
3841                    self.0.AddFontDefaultVector(&fc)
3842                }
3843                TtfData::CustomLoader(glyph_loader) => {
3844                    let ptr = Box::into_raw(Box::new(glyph_loader));
3845                    fc.FontLoader = &fontloader::FONT_LOADER.0;
3846                    fc.FontData = ptr as *mut c_void;
3847                    fc.FontDataOwnedByAtlas = true;
3848                    self.0.AddFont(&fc)
3849                }
3850            };
3851            let Some(font) = font_ptr.as_ref() else {
3852                log::error!("Error loading font!");
3853                return FontId::default();
3854            };
3855            FontId(font.FontId)
3856        }
3857    }
3858
3859    /// Adds an arbitrary image to the font atlas.
3860    ///
3861    /// The returned `CustomRectIndex` can be used later to draw the image.
3862    pub fn add_custom_rect(
3863        &mut self,
3864        size: impl Into<mint::Vector2<u32>>,
3865        draw: impl FnOnce(&mut SubPixelImage<'_, '_>),
3866    ) -> CustomRectIndex {
3867        let size = size.into();
3868        unsafe {
3869            let mut rect = MaybeUninit::zeroed();
3870            let idx = self.0.AddCustomRect(
3871                i32::try_from(size.x).unwrap(),
3872                i32::try_from(size.y).unwrap(),
3873                rect.as_mut_ptr(),
3874            );
3875            let idx = CustomRectIndex(idx);
3876            let rect = rect.assume_init();
3877            let tex_data = &(*self.TexData);
3878
3879            let mut pixel_image = PixelImage::from_raw(
3880                tex_data.Width as u32,
3881                tex_data.Height as u32,
3882                std::slice::from_raw_parts_mut(
3883                    tex_data.Pixels,
3884                    tex_data.Width as usize
3885                        * tex_data.Height as usize
3886                        * tex_data.BytesPerPixel as usize,
3887                ),
3888            )
3889            .unwrap();
3890
3891            let mut sub_image =
3892                pixel_image.sub_image(rect.x as u32, rect.y as u32, rect.w as u32, rect.h as u32);
3893            draw(&mut sub_image);
3894
3895            idx
3896        }
3897    }
3898
3899    pub fn remove_custom_rect(&mut self, idx: CustomRectIndex) {
3900        if idx.0 < 0 {
3901            return;
3902        }
3903        unsafe {
3904            self.0.RemoveCustomRect(idx.0);
3905        }
3906    }
3907}
3908
3909transparent_mut! {
3910    #[derive(Debug)]
3911    pub struct Io(ImGuiIO);
3912}
3913
3914transparent! {
3915    /// Safe wrapper for `&mut Io`.
3916    ///
3917    /// Notably it doesn't implement DerefMut
3918    #[derive(Debug)]
3919    pub struct IoMut(ImGuiIO);
3920}
3921
3922impl Io {
3923    pub fn font_atlas(&self) -> &FontAtlas {
3924        unsafe { FontAtlas::cast(&*self.Fonts) }
3925    }
3926
3927    pub fn want_capture_mouse(&self) -> bool {
3928        self.WantCaptureMouse
3929    }
3930    pub fn want_capture_keyboard(&self) -> bool {
3931        self.WantCaptureKeyboard
3932    }
3933    pub fn want_text_input(&self) -> bool {
3934        self.WantTextInput
3935    }
3936    pub fn display_size(&self) -> Vector2 {
3937        im_to_v2(self.DisplaySize)
3938    }
3939    pub fn display_scale(&self) -> f32 {
3940        self.DisplayFramebufferScale.x
3941    }
3942
3943    // The following are not unsafe because if you have a `&mut Io` you alreay can do anything.
3944    pub fn add_config_flags(&mut self, flags: ConfigFlags) {
3945        self.ConfigFlags |= flags.bits();
3946    }
3947    pub fn remove_config_flags(&mut self, flags: ConfigFlags) {
3948        self.ConfigFlags &= !flags.bits();
3949    }
3950    pub fn add_backend_flags(&mut self, flags: BackendFlags) {
3951        self.BackendFlags |= flags.bits();
3952    }
3953    pub fn remove_backend_flags(&mut self, flags: BackendFlags) {
3954        self.BackendFlags &= !flags.bits();
3955    }
3956    pub fn delta_time(&mut self) -> Duration {
3957        Duration::from_secs_f32(self.DeltaTime)
3958    }
3959    pub fn set_delta_time(&mut self, d: Duration) {
3960        self.DeltaTime = d.as_secs_f32()
3961    }
3962}
3963
3964impl IoMut {
3965    pub unsafe fn inner(&mut self) -> &mut Io {
3966        Io::cast_mut(&mut self.0)
3967    }
3968    pub fn set_allow_user_scaling(&mut self, val: bool) {
3969        self.0.FontAllowUserScaling = val;
3970    }
3971    pub fn nav_enable_keyboard(&mut self, enable: bool) {
3972        unsafe {
3973            if enable {
3974                self.inner()
3975                    .add_config_flags(ConfigFlags::NavEnableKeyboard);
3976            } else {
3977                self.inner()
3978                    .remove_config_flags(ConfigFlags::NavEnableKeyboard);
3979            }
3980        }
3981    }
3982    pub fn nav_enable_gamepad(&mut self, enable: bool) {
3983        unsafe {
3984            if enable {
3985                self.inner().add_config_flags(ConfigFlags::NavEnableGamepad);
3986            } else {
3987                self.inner()
3988                    .remove_config_flags(ConfigFlags::NavEnableGamepad);
3989            }
3990        }
3991    }
3992    /// Enables the docking feature.
3993    pub fn enable_docking(&mut self, enable: bool) {
3994        unsafe {
3995            if enable {
3996                self.inner().add_config_flags(ConfigFlags::DockingEnable);
3997            } else {
3998                self.inner().remove_config_flags(ConfigFlags::DockingEnable);
3999            }
4000        }
4001    }
4002    /// Enables the viewport feature.
4003    ///
4004    /// Note that this will only work if your used backend supports viewports, which easy-imgui-window does not.
4005    pub fn enable_viewports(&mut self, enable: bool) {
4006        unsafe {
4007            if enable {
4008                self.inner().add_config_flags(ConfigFlags::ViewportsEnable);
4009            } else {
4010                self.inner()
4011                    .remove_config_flags(ConfigFlags::ViewportsEnable);
4012            }
4013        }
4014    }
4015    pub fn font_atlas_mut(&mut self) -> &mut FontAtlas {
4016        unsafe { FontAtlas::cast_mut(&mut *self.Fonts) }
4017    }
4018}
4019
4020transparent_mut! {
4021    #[derive(Debug)]
4022    pub struct PlatformIo(ImGuiPlatformIO);
4023}
4024
4025impl PlatformIo {
4026    pub unsafe fn textures_mut(&mut self) -> impl Iterator<Item = &mut ImTextureData> {
4027        self.Textures.iter_mut().map(|t| unsafe { &mut **t })
4028    }
4029}
4030
4031#[derive(Debug)]
4032pub struct SizeCallbackData<'a> {
4033    ptr: &'a mut ImGuiSizeCallbackData,
4034}
4035
4036impl SizeCallbackData<'_> {
4037    pub fn pos(&self) -> Vector2 {
4038        im_to_v2(self.ptr.Pos)
4039    }
4040    pub fn current_size(&self) -> Vector2 {
4041        im_to_v2(self.ptr.CurrentSize)
4042    }
4043    pub fn desired_size(&self) -> Vector2 {
4044        im_to_v2(self.ptr.DesiredSize)
4045    }
4046    pub fn set_desired_size(&mut self, sz: Vector2) {
4047        self.ptr.DesiredSize = v2_to_im(sz);
4048    }
4049}
4050
4051unsafe extern "C" fn call_size_callback<A>(ptr: *mut ImGuiSizeCallbackData) {
4052    unsafe {
4053        let ptr = &mut *ptr;
4054        let id = ptr.UserData as usize;
4055        let data = SizeCallbackData { ptr };
4056        Ui::<A>::run_callback(id, data);
4057    }
4058}
4059
4060pub struct WindowDrawList<'ui, A> {
4061    ui: &'ui Ui<A>,
4062    ptr: *mut ImDrawList,
4063}
4064
4065impl<A> WindowDrawList<'_, A> {
4066    pub fn add_line(&self, p1: Vector2, p2: Vector2, color: Color, thickness: f32) {
4067        unsafe {
4068            ImDrawList_AddLine(
4069                self.ptr,
4070                &v2_to_im(p1),
4071                &v2_to_im(p2),
4072                color.as_u32(),
4073                thickness,
4074            );
4075        }
4076    }
4077    pub fn add_rect(
4078        &self,
4079        p_min: Vector2,
4080        p_max: Vector2,
4081        color: Color,
4082        rounding: f32,
4083        flags: DrawFlags,
4084        thickness: f32,
4085    ) {
4086        unsafe {
4087            ImDrawList_AddRect(
4088                self.ptr,
4089                &v2_to_im(p_min),
4090                &v2_to_im(p_max),
4091                color.as_u32(),
4092                rounding,
4093                flags.bits(),
4094                thickness,
4095            );
4096        }
4097    }
4098    pub fn add_rect_filled(
4099        &self,
4100        p_min: Vector2,
4101        p_max: Vector2,
4102        color: Color,
4103        rounding: f32,
4104        flags: DrawFlags,
4105    ) {
4106        unsafe {
4107            ImDrawList_AddRectFilled(
4108                self.ptr,
4109                &v2_to_im(p_min),
4110                &v2_to_im(p_max),
4111                color.as_u32(),
4112                rounding,
4113                flags.bits(),
4114            );
4115        }
4116    }
4117    pub fn add_rect_filled_multicolor(
4118        &self,
4119        p_min: Vector2,
4120        p_max: Vector2,
4121        col_upr_left: Color,
4122        col_upr_right: Color,
4123        col_bot_right: Color,
4124        col_bot_left: Color,
4125    ) {
4126        unsafe {
4127            ImDrawList_AddRectFilledMultiColor(
4128                self.ptr,
4129                &v2_to_im(p_min),
4130                &v2_to_im(p_max),
4131                col_upr_left.as_u32(),
4132                col_upr_right.as_u32(),
4133                col_bot_right.as_u32(),
4134                col_bot_left.as_u32(),
4135            );
4136        }
4137    }
4138    pub fn add_quad(
4139        &self,
4140        p1: Vector2,
4141        p2: Vector2,
4142        p3: Vector2,
4143        p4: Vector2,
4144        color: Color,
4145        thickness: f32,
4146    ) {
4147        unsafe {
4148            ImDrawList_AddQuad(
4149                self.ptr,
4150                &v2_to_im(p1),
4151                &v2_to_im(p2),
4152                &v2_to_im(p3),
4153                &v2_to_im(p4),
4154                color.as_u32(),
4155                thickness,
4156            );
4157        }
4158    }
4159    pub fn add_quad_filled(
4160        &self,
4161        p1: Vector2,
4162        p2: Vector2,
4163        p3: Vector2,
4164        p4: Vector2,
4165        color: Color,
4166    ) {
4167        unsafe {
4168            ImDrawList_AddQuadFilled(
4169                self.ptr,
4170                &v2_to_im(p1),
4171                &v2_to_im(p2),
4172                &v2_to_im(p3),
4173                &v2_to_im(p4),
4174                color.as_u32(),
4175            );
4176        }
4177    }
4178    pub fn add_triangle(
4179        &self,
4180        p1: Vector2,
4181        p2: Vector2,
4182        p3: Vector2,
4183        color: Color,
4184        thickness: f32,
4185    ) {
4186        unsafe {
4187            ImDrawList_AddTriangle(
4188                self.ptr,
4189                &v2_to_im(p1),
4190                &v2_to_im(p2),
4191                &v2_to_im(p3),
4192                color.as_u32(),
4193                thickness,
4194            );
4195        }
4196    }
4197    pub fn add_triangle_filled(&self, p1: Vector2, p2: Vector2, p3: Vector2, color: Color) {
4198        unsafe {
4199            ImDrawList_AddTriangleFilled(
4200                self.ptr,
4201                &v2_to_im(p1),
4202                &v2_to_im(p2),
4203                &v2_to_im(p3),
4204                color.as_u32(),
4205            );
4206        }
4207    }
4208    pub fn add_circle(
4209        &self,
4210        center: Vector2,
4211        radius: f32,
4212        color: Color,
4213        num_segments: i32,
4214        thickness: f32,
4215    ) {
4216        unsafe {
4217            ImDrawList_AddCircle(
4218                self.ptr,
4219                &v2_to_im(center),
4220                radius,
4221                color.as_u32(),
4222                num_segments,
4223                thickness,
4224            );
4225        }
4226    }
4227    pub fn add_circle_filled(&self, center: Vector2, radius: f32, color: Color, num_segments: i32) {
4228        unsafe {
4229            ImDrawList_AddCircleFilled(
4230                self.ptr,
4231                &v2_to_im(center),
4232                radius,
4233                color.as_u32(),
4234                num_segments,
4235            );
4236        }
4237    }
4238    pub fn add_ngon(
4239        &self,
4240        center: Vector2,
4241        radius: f32,
4242        color: Color,
4243        num_segments: i32,
4244        thickness: f32,
4245    ) {
4246        unsafe {
4247            ImDrawList_AddNgon(
4248                self.ptr,
4249                &v2_to_im(center),
4250                radius,
4251                color.as_u32(),
4252                num_segments,
4253                thickness,
4254            );
4255        }
4256    }
4257    pub fn add_ngon_filled(&self, center: Vector2, radius: f32, color: Color, num_segments: i32) {
4258        unsafe {
4259            ImDrawList_AddNgonFilled(
4260                self.ptr,
4261                &v2_to_im(center),
4262                radius,
4263                color.as_u32(),
4264                num_segments,
4265            );
4266        }
4267    }
4268    pub fn add_ellipse(
4269        &self,
4270        center: Vector2,
4271        radius: Vector2,
4272        color: Color,
4273        rot: f32,
4274        num_segments: i32,
4275        thickness: f32,
4276    ) {
4277        unsafe {
4278            ImDrawList_AddEllipse(
4279                self.ptr,
4280                &v2_to_im(center),
4281                &v2_to_im(radius),
4282                color.as_u32(),
4283                rot,
4284                num_segments,
4285                thickness,
4286            );
4287        }
4288    }
4289    pub fn add_ellipse_filled(
4290        &self,
4291        center: Vector2,
4292        radius: Vector2,
4293        color: Color,
4294        rot: f32,
4295        num_segments: i32,
4296    ) {
4297        unsafe {
4298            ImDrawList_AddEllipseFilled(
4299                self.ptr,
4300                &v2_to_im(center),
4301                &v2_to_im(radius),
4302                color.as_u32(),
4303                rot,
4304                num_segments,
4305            );
4306        }
4307    }
4308    pub fn add_text(&self, pos: Vector2, color: Color, text: &str) {
4309        unsafe {
4310            let (start, end) = text_ptrs(text);
4311            ImDrawList_AddText(self.ptr, &v2_to_im(pos), color.as_u32(), start, end);
4312        }
4313    }
4314    pub fn add_text_ex(
4315        &self,
4316        font: FontId,
4317        font_size: f32,
4318        pos: Vector2,
4319        color: Color,
4320        text: &str,
4321        wrap_width: f32,
4322        cpu_fine_clip_rect: Option<ImVec4>,
4323    ) {
4324        unsafe {
4325            let (start, end) = text_ptrs(text);
4326            ImDrawList_AddText1(
4327                self.ptr,
4328                self.ui.io().font_atlas().font_ptr(font),
4329                font_size,
4330                &v2_to_im(pos),
4331                color.as_u32(),
4332                start,
4333                end,
4334                wrap_width,
4335                cpu_fine_clip_rect
4336                    .as_ref()
4337                    .map(|x| x as *const _)
4338                    .unwrap_or(null()),
4339            );
4340        }
4341    }
4342    pub fn add_polyline(&self, points: &[ImVec2], color: Color, flags: DrawFlags, thickness: f32) {
4343        unsafe {
4344            ImDrawList_AddPolyline(
4345                self.ptr,
4346                points.as_ptr(),
4347                points.len() as i32,
4348                color.as_u32(),
4349                flags.bits(),
4350                thickness,
4351            );
4352        }
4353    }
4354    pub fn add_convex_poly_filled(&self, points: &[ImVec2], color: Color) {
4355        unsafe {
4356            ImDrawList_AddConvexPolyFilled(
4357                self.ptr,
4358                points.as_ptr(),
4359                points.len() as i32,
4360                color.as_u32(),
4361            );
4362        }
4363    }
4364    pub fn add_concave_poly_filled(&self, points: &[ImVec2], color: Color) {
4365        unsafe {
4366            ImDrawList_AddConcavePolyFilled(
4367                self.ptr,
4368                points.as_ptr(),
4369                points.len() as i32,
4370                color.as_u32(),
4371            );
4372        }
4373    }
4374    pub fn add_bezier_cubic(
4375        &self,
4376        p1: Vector2,
4377        p2: Vector2,
4378        p3: Vector2,
4379        p4: Vector2,
4380        color: Color,
4381        thickness: f32,
4382        num_segments: i32,
4383    ) {
4384        unsafe {
4385            ImDrawList_AddBezierCubic(
4386                self.ptr,
4387                &v2_to_im(p1),
4388                &v2_to_im(p2),
4389                &v2_to_im(p3),
4390                &v2_to_im(p4),
4391                color.as_u32(),
4392                thickness,
4393                num_segments,
4394            );
4395        }
4396    }
4397    pub fn add_bezier_quadratic(
4398        &self,
4399        p1: Vector2,
4400        p2: Vector2,
4401        p3: Vector2,
4402        color: Color,
4403        thickness: f32,
4404        num_segments: i32,
4405    ) {
4406        unsafe {
4407            ImDrawList_AddBezierQuadratic(
4408                self.ptr,
4409                &v2_to_im(p1),
4410                &v2_to_im(p2),
4411                &v2_to_im(p3),
4412                color.as_u32(),
4413                thickness,
4414                num_segments,
4415            );
4416        }
4417    }
4418    pub fn add_image(
4419        &self,
4420        texture_ref: TextureRef,
4421        p_min: Vector2,
4422        p_max: Vector2,
4423        uv_min: Vector2,
4424        uv_max: Vector2,
4425        color: Color,
4426    ) {
4427        unsafe {
4428            ImDrawList_AddImage(
4429                self.ptr,
4430                texture_ref.tex_ref(),
4431                &v2_to_im(p_min),
4432                &v2_to_im(p_max),
4433                &v2_to_im(uv_min),
4434                &v2_to_im(uv_max),
4435                color.as_u32(),
4436            );
4437        }
4438    }
4439    pub fn add_image_quad(
4440        &self,
4441        texture_ref: TextureRef,
4442        p1: Vector2,
4443        p2: Vector2,
4444        p3: Vector2,
4445        p4: Vector2,
4446        uv1: Vector2,
4447        uv2: Vector2,
4448        uv3: Vector2,
4449        uv4: Vector2,
4450        color: Color,
4451    ) {
4452        unsafe {
4453            ImDrawList_AddImageQuad(
4454                self.ptr,
4455                texture_ref.tex_ref(),
4456                &v2_to_im(p1),
4457                &v2_to_im(p2),
4458                &v2_to_im(p3),
4459                &v2_to_im(p4),
4460                &v2_to_im(uv1),
4461                &v2_to_im(uv2),
4462                &v2_to_im(uv3),
4463                &v2_to_im(uv4),
4464                color.as_u32(),
4465            );
4466        }
4467    }
4468    pub fn add_image_rounded(
4469        &self,
4470        texture_ref: TextureRef,
4471        p_min: Vector2,
4472        p_max: Vector2,
4473        uv_min: Vector2,
4474        uv_max: Vector2,
4475        color: Color,
4476        rounding: f32,
4477        flags: DrawFlags,
4478    ) {
4479        unsafe {
4480            ImDrawList_AddImageRounded(
4481                self.ptr,
4482                texture_ref.tex_ref(),
4483                &v2_to_im(p_min),
4484                &v2_to_im(p_max),
4485                &v2_to_im(uv_min),
4486                &v2_to_im(uv_max),
4487                color.as_u32(),
4488                rounding,
4489                flags.bits(),
4490            );
4491        }
4492    }
4493
4494    pub fn add_callback(&self, cb: impl FnOnce(&mut A) + 'static) {
4495        // Callbacks are only called once, convert the FnOnce into an FnMut to register
4496        // They are called after `do_ui` so first argument pointer is valid.
4497        // The second argument is not used, set to `()``.
4498        let mut cb = Some(cb);
4499        unsafe {
4500            let id = self.ui.push_callback(move |a, _: ()| {
4501                if let Some(cb) = cb.take() {
4502                    cb(&mut *a);
4503                }
4504            });
4505            ImDrawList_AddCallback(
4506                self.ptr,
4507                Some(call_drawlist_callback::<A>),
4508                id as *mut c_void,
4509                0,
4510            );
4511        }
4512    }
4513    pub fn add_draw_cmd(&self) {
4514        unsafe {
4515            ImDrawList_AddDrawCmd(self.ptr);
4516        }
4517    }
4518}
4519
4520unsafe extern "C" fn call_drawlist_callback<A>(
4521    _parent_list: *const ImDrawList,
4522    cmd: *const ImDrawCmd,
4523) {
4524    unsafe {
4525        let id = (*cmd).UserCallbackData as usize;
4526        Ui::<A>::run_callback(id, ());
4527    }
4528}
4529
4530/// Represents any type that can be converted to a Dear ImGui hash id.
4531pub trait Hashable {
4532    // These are unsafe because they should be called only inside a frame (holding a &mut Ui)
4533    unsafe fn get_id(&self) -> ImGuiID;
4534    unsafe fn push(&self);
4535}
4536
4537impl Hashable for &str {
4538    unsafe fn get_id(&self) -> ImGuiID {
4539        unsafe {
4540            let (start, end) = text_ptrs(self);
4541            ImGui_GetID1(start, end)
4542        }
4543    }
4544    unsafe fn push(&self) {
4545        unsafe {
4546            let (start, end) = text_ptrs(self);
4547            ImGui_PushID1(start, end);
4548        }
4549    }
4550}
4551
4552impl Hashable for usize {
4553    unsafe fn get_id(&self) -> ImGuiID {
4554        unsafe { ImGui_GetID2(*self as *const c_void) }
4555    }
4556    unsafe fn push(&self) {
4557        unsafe {
4558            ImGui_PushID2(*self as *const c_void);
4559        }
4560    }
4561}
4562
4563/// Any value that can be applied with a _push_ function and unapplied with a _pop_ function.
4564///
4565/// Apply to the current frame using [`Ui::with_push`]. If you want to apply several values at the
4566/// same time use a tuple or an array.
4567/// Only tuples up to 4 values are supported, but you can apply arbitrarily many pushables by
4568/// creating tuples of tuples: `(A, B, C, (D, E, F, (G, H, I, J)))`.
4569pub trait Pushable {
4570    unsafe fn push(&self);
4571    unsafe fn pop(&self);
4572}
4573
4574struct PushableGuard<'a, P: Pushable + ?Sized>(&'a P);
4575
4576impl<P: Pushable + ?Sized> Drop for PushableGuard<'_, P> {
4577    fn drop(&mut self) {
4578        unsafe {
4579            self.0.pop();
4580        }
4581    }
4582}
4583
4584#[allow(clippy::needless_lifetimes)]
4585unsafe fn push_guard<'a, P: Pushable>(p: &'a P) -> PushableGuard<'a, P> {
4586    unsafe {
4587        p.push();
4588        PushableGuard(p)
4589    }
4590}
4591
4592/// A [`Pushable`] that does nothing.
4593impl Pushable for () {
4594    unsafe fn push(&self) {}
4595    unsafe fn pop(&self) {}
4596}
4597
4598impl<A: Pushable, B: Pushable> Pushable for Either<A, B> {
4599    unsafe fn push(&self) {
4600        unsafe {
4601            match self {
4602                Either::Left(a) => A::push(a),
4603                Either::Right(b) => B::push(b),
4604            }
4605        }
4606    }
4607    unsafe fn pop(&self) {
4608        unsafe {
4609            match self {
4610                Either::Left(a) => A::pop(a),
4611                Either::Right(b) => B::pop(b),
4612            }
4613        }
4614    }
4615}
4616
4617impl<A: Pushable> Pushable for (A,) {
4618    unsafe fn push(&self) {
4619        unsafe {
4620            self.0.push();
4621        }
4622    }
4623    unsafe fn pop(&self) {
4624        unsafe {
4625            self.0.pop();
4626        }
4627    }
4628}
4629
4630impl<P: Pushable + ?Sized> Pushable for &P {
4631    unsafe fn push(&self) {
4632        unsafe {
4633            P::push(self);
4634        }
4635    }
4636    unsafe fn pop(&self) {
4637        unsafe {
4638            P::pop(self);
4639        }
4640    }
4641}
4642
4643impl<A: Pushable, B: Pushable> Pushable for (A, B) {
4644    unsafe fn push(&self) {
4645        unsafe {
4646            self.0.push();
4647            self.1.push();
4648        }
4649    }
4650    unsafe fn pop(&self) {
4651        unsafe {
4652            self.1.pop();
4653            self.0.pop();
4654        }
4655    }
4656}
4657
4658impl<A: Pushable, B: Pushable, C: Pushable> Pushable for (A, B, C) {
4659    unsafe fn push(&self) {
4660        unsafe {
4661            self.0.push();
4662            self.1.push();
4663            self.2.push();
4664        }
4665    }
4666    unsafe fn pop(&self) {
4667        unsafe {
4668            self.2.pop();
4669            self.1.pop();
4670            self.0.pop();
4671        }
4672    }
4673}
4674
4675impl<A: Pushable, B: Pushable, C: Pushable, D: Pushable> Pushable for (A, B, C, D) {
4676    unsafe fn push(&self) {
4677        unsafe {
4678            self.0.push();
4679            self.1.push();
4680            self.2.push();
4681            self.3.push();
4682        }
4683    }
4684    unsafe fn pop(&self) {
4685        unsafe {
4686            self.3.pop();
4687            self.2.pop();
4688            self.1.pop();
4689            self.0.pop();
4690        }
4691    }
4692}
4693
4694impl Pushable for &[&dyn Pushable] {
4695    unsafe fn push(&self) {
4696        unsafe {
4697            for st in *self {
4698                st.push();
4699            }
4700        }
4701    }
4702    unsafe fn pop(&self) {
4703        unsafe {
4704            for st in self.iter().rev() {
4705                st.pop();
4706            }
4707        }
4708    }
4709}
4710
4711/// A [`Pushable`] that is applied optionally.
4712impl<T: Pushable> Pushable for Option<T> {
4713    unsafe fn push(&self) {
4714        unsafe {
4715            if let Some(s) = self {
4716                s.push();
4717            }
4718        }
4719    }
4720    unsafe fn pop(&self) {
4721        unsafe {
4722            if let Some(s) = self {
4723                s.pop();
4724            }
4725        }
4726    }
4727}
4728
4729//TODO rework the font pushables
4730impl Pushable for FontId {
4731    unsafe fn push(&self) {
4732        unsafe {
4733            let font = current_font_ptr(*self);
4734            ImGui_PushFont(font, 0.0);
4735        }
4736    }
4737    unsafe fn pop(&self) {
4738        unsafe {
4739            ImGui_PopFont();
4740        }
4741    }
4742}
4743
4744pub struct FontSize(pub f32);
4745
4746impl Pushable for FontSize {
4747    unsafe fn push(&self) {
4748        unsafe {
4749            // maybe this should get ui and do ui.scale()
4750            ImGui_PushFont(std::ptr::null_mut(), self.0);
4751        }
4752    }
4753    unsafe fn pop(&self) {
4754        unsafe {
4755            ImGui_PopFont();
4756        }
4757    }
4758}
4759
4760pub struct FontAndSize(pub FontId, pub f32);
4761
4762impl Pushable for FontAndSize {
4763    unsafe fn push(&self) {
4764        unsafe {
4765            ImGui_PushFont(current_font_ptr(self.0), self.1);
4766        }
4767    }
4768    unsafe fn pop(&self) {
4769        unsafe {
4770            ImGui_PopFont();
4771        }
4772    }
4773}
4774
4775pub type StyleColor = (ColorId, Color);
4776
4777#[derive(Copy, Clone, Debug)]
4778pub enum TextureRef<'a> {
4779    Id(TextureId),
4780    Ref(&'a ImTextureData),
4781}
4782
4783impl TextureRef<'_> {
4784    pub unsafe fn tex_ref(&self) -> ImTextureRef {
4785        match self {
4786            TextureRef::Id(TextureId(id)) => ImTextureRef {
4787                _TexData: null_mut(),
4788                _TexID: *id,
4789            },
4790            TextureRef::Ref(tex_data) => ImTextureRef {
4791                _TexData: (&raw const **tex_data).cast_mut(),
4792                _TexID: 0,
4793            },
4794        }
4795    }
4796
4797    pub unsafe fn tex_id(&self) -> TextureId {
4798        unsafe {
4799            match self {
4800                TextureRef::Id(tex_id) => *tex_id,
4801                TextureRef::Ref(tex_data) => {
4802                    let id = tex_data.TexID;
4803                    TextureId::from_id(id)
4804                }
4805            }
4806        }
4807    }
4808}
4809
4810#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4811pub struct TextureId(ImTextureID);
4812
4813impl TextureId {
4814    pub fn id(&self) -> ImTextureID {
4815        self.0
4816    }
4817    pub unsafe fn from_id(id: ImTextureID) -> Self {
4818        Self(id)
4819    }
4820}
4821
4822#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4823pub struct TextureUniqueId(i32);
4824
4825impl Pushable for StyleColor {
4826    unsafe fn push(&self) {
4827        unsafe {
4828            ImGui_PushStyleColor1(self.0.bits(), &self.1.into());
4829        }
4830    }
4831    unsafe fn pop(&self) {
4832        unsafe {
4833            ImGui_PopStyleColor(1);
4834        }
4835    }
4836}
4837
4838impl Pushable for [StyleColor] {
4839    unsafe fn push(&self) {
4840        unsafe {
4841            for sc in self {
4842                sc.push();
4843            }
4844        }
4845    }
4846    unsafe fn pop(&self) {
4847        unsafe {
4848            ImGui_PopStyleColor(self.len() as i32);
4849        }
4850    }
4851}
4852
4853impl<const N: usize> Pushable for [StyleColor; N] {
4854    unsafe fn push(&self) {
4855        unsafe {
4856            self.as_slice().push();
4857        }
4858    }
4859    unsafe fn pop(&self) {
4860        unsafe {
4861            self.as_slice().pop();
4862        }
4863    }
4864}
4865
4866pub type StyleColorF = (ColorId, ImVec4);
4867
4868impl Pushable for StyleColorF {
4869    unsafe fn push(&self) {
4870        unsafe {
4871            ImGui_PushStyleColor1(self.0.bits(), &self.1);
4872        }
4873    }
4874    unsafe fn pop(&self) {
4875        unsafe {
4876            ImGui_PopStyleColor(1);
4877        }
4878    }
4879}
4880
4881impl Pushable for [StyleColorF] {
4882    unsafe fn push(&self) {
4883        unsafe {
4884            for sc in self {
4885                sc.push();
4886            }
4887        }
4888    }
4889    unsafe fn pop(&self) {
4890        unsafe {
4891            ImGui_PopStyleColor(self.len() as i32);
4892        }
4893    }
4894}
4895
4896impl<const N: usize> Pushable for [StyleColorF; N] {
4897    unsafe fn push(&self) {
4898        unsafe {
4899            self.as_slice().push();
4900        }
4901    }
4902    unsafe fn pop(&self) {
4903        unsafe {
4904            self.as_slice().pop();
4905        }
4906    }
4907}
4908
4909#[derive(Debug, Copy, Clone)]
4910pub enum StyleValue {
4911    F32(f32),
4912    Vec2(Vector2),
4913    X(f32),
4914    Y(f32),
4915}
4916
4917pub type Style = (StyleVar, StyleValue);
4918
4919impl Pushable for Style {
4920    unsafe fn push(&self) {
4921        unsafe {
4922            match self.1 {
4923                StyleValue::F32(f) => ImGui_PushStyleVar(self.0.bits(), f),
4924                StyleValue::Vec2(v) => ImGui_PushStyleVar1(self.0.bits(), &v2_to_im(v)),
4925                StyleValue::X(x) => ImGui_PushStyleVarX(self.0.bits(), x),
4926                StyleValue::Y(y) => ImGui_PushStyleVarX(self.0.bits(), y),
4927            }
4928        }
4929    }
4930    unsafe fn pop(&self) {
4931        unsafe {
4932            ImGui_PopStyleVar(1);
4933        }
4934    }
4935}
4936
4937impl Pushable for [Style] {
4938    unsafe fn push(&self) {
4939        unsafe {
4940            for sc in self {
4941                sc.push();
4942            }
4943        }
4944    }
4945    unsafe fn pop(&self) {
4946        unsafe {
4947            ImGui_PopStyleVar(self.len() as i32);
4948        }
4949    }
4950}
4951
4952impl<const N: usize> Pushable for [Style; N] {
4953    unsafe fn push(&self) {
4954        unsafe {
4955            self.as_slice().push();
4956        }
4957    }
4958    unsafe fn pop(&self) {
4959        unsafe {
4960            self.as_slice().pop();
4961        }
4962    }
4963}
4964
4965#[derive(Debug, Copy, Clone)]
4966pub struct ItemWidth(pub f32);
4967
4968impl Pushable for ItemWidth {
4969    unsafe fn push(&self) {
4970        unsafe {
4971            ImGui_PushItemWidth(self.0);
4972        }
4973    }
4974    unsafe fn pop(&self) {
4975        unsafe {
4976            ImGui_PopItemWidth();
4977        }
4978    }
4979}
4980
4981#[derive(Debug, Copy, Clone)]
4982pub struct Indent(pub f32);
4983
4984impl Pushable for Indent {
4985    unsafe fn push(&self) {
4986        unsafe {
4987            ImGui_Indent(self.0);
4988        }
4989    }
4990    unsafe fn pop(&self) {
4991        unsafe {
4992            ImGui_Unindent(self.0);
4993        }
4994    }
4995}
4996
4997#[derive(Debug, Copy, Clone)]
4998pub struct TextWrapPos(pub f32);
4999
5000impl Pushable for TextWrapPos {
5001    unsafe fn push(&self) {
5002        unsafe {
5003            ImGui_PushTextWrapPos(self.0);
5004        }
5005    }
5006    unsafe fn pop(&self) {
5007        unsafe {
5008            ImGui_PopTextWrapPos();
5009        }
5010    }
5011}
5012
5013impl Pushable for (ItemFlags, bool) {
5014    unsafe fn push(&self) {
5015        unsafe {
5016            ImGui_PushItemFlag(self.0.bits(), self.1);
5017        }
5018    }
5019    unsafe fn pop(&self) {
5020        unsafe {
5021            ImGui_PopItemFlag();
5022        }
5023    }
5024}
5025
5026#[derive(Debug, Copy, Clone)]
5027pub struct ItemId<H: Hashable>(pub H);
5028
5029impl<H: Hashable> Pushable for ItemId<H> {
5030    unsafe fn push(&self) {
5031        unsafe {
5032            self.0.push();
5033        }
5034    }
5035    unsafe fn pop(&self) {
5036        unsafe {
5037            ImGui_PopID();
5038        }
5039    }
5040}
5041
5042transparent! {
5043    #[derive(Debug)]
5044    pub struct Viewport(ImGuiViewport);
5045}
5046
5047impl Viewport {
5048    pub fn id(&self) -> ImGuiID {
5049        self.ID
5050    }
5051    pub fn flags(&self) -> ViewportFlags {
5052        ViewportFlags::from_bits_truncate(self.Flags)
5053    }
5054    pub fn pos(&self) -> Vector2 {
5055        im_to_v2(self.Pos)
5056    }
5057    pub fn size(&self) -> Vector2 {
5058        im_to_v2(self.Size)
5059    }
5060    pub fn work_pos(&self) -> Vector2 {
5061        im_to_v2(self.WorkPos)
5062    }
5063    pub fn work_size(&self) -> Vector2 {
5064        im_to_v2(self.WorkSize)
5065    }
5066    pub fn center(&self) -> Vector2 {
5067        self.pos() + self.size() / 2.0
5068    }
5069    pub fn work_center(&self) -> Vector2 {
5070        self.work_pos() + self.work_size() / 2.0
5071    }
5072}
5073
5074decl_builder_with_opt! { TableConfig, ImGui_BeginTable, ImGui_EndTable () (S: IntoCStr)
5075    (
5076        str_id (S::Temp) (str_id.as_ptr()),
5077        column (i32) (column),
5078        flags (TableFlags) (flags.bits()),
5079        outer_size (ImVec2) (&outer_size),
5080        inner_width (f32) (inner_width),
5081    )
5082    {
5083        decl_builder_setter!{flags: TableFlags}
5084        decl_builder_setter_vector2!{outer_size: Vector2}
5085        decl_builder_setter!{inner_width: f32}
5086    }
5087    {
5088        pub fn table_config<S: IntoCStr>(&self, str_id: LblId<S>, column: i32) -> TableConfig<S> {
5089            TableConfig {
5090                str_id: str_id.into(),
5091                column,
5092                flags: TableFlags::None,
5093                outer_size: im_vec2(0.0, 0.0),
5094                inner_width: 0.0,
5095                push: (),
5096            }
5097        }
5098        pub fn table_next_row(&self, flags: TableRowFlags, min_row_height: f32) {
5099            unsafe {
5100                ImGui_TableNextRow(flags.bits(), min_row_height);
5101            }
5102        }
5103        pub fn table_next_column(&self) -> bool {
5104            unsafe {
5105                ImGui_TableNextColumn()
5106            }
5107        }
5108        pub fn table_set_column_index(&self, column_n: i32) -> bool {
5109            unsafe {
5110                ImGui_TableSetColumnIndex(column_n)
5111            }
5112        }
5113        pub fn table_setup_column(&self, label: impl IntoCStr, flags: TableColumnFlags, init_width_or_weight: f32, user_id: ImGuiID) {
5114            unsafe {
5115                ImGui_TableSetupColumn(label.into().as_ptr(), flags.bits(), init_width_or_weight, user_id);
5116            }
5117        }
5118        pub fn table_setup_scroll_freeze(&self, cols: i32, rows: i32) {
5119            unsafe {
5120                ImGui_TableSetupScrollFreeze(cols, rows);
5121            }
5122        }
5123        pub fn table_headers_row(&self) {
5124            unsafe {
5125                ImGui_TableHeadersRow();
5126            }
5127        }
5128        pub fn table_angle_headers_row(&self) {
5129            unsafe {
5130                ImGui_TableAngledHeadersRow();
5131            }
5132        }
5133        pub fn table_get_columns_count(&self) -> i32 {
5134            unsafe {
5135                ImGui_TableGetColumnCount()
5136            }
5137        }
5138        pub fn table_get_column_index(&self) -> i32 {
5139            unsafe {
5140                ImGui_TableGetColumnIndex()
5141            }
5142        }
5143        /// Can return one-pass the last column if hovering the empty space
5144        pub fn table_get_hovered_column(&self) -> Option<i32> {
5145            unsafe {
5146                let res = ImGui_TableGetHoveredColumn();
5147                if res < 0 {
5148                    None
5149                } else {
5150                    Some(res)
5151                }
5152            }
5153        }
5154        pub fn table_get_row_index(&self) -> i32 {
5155            unsafe {
5156                ImGui_TableGetRowIndex()
5157            }
5158        }
5159        pub fn table_get_column_flags(&self, column_n: Option<i32>) -> TableColumnFlags {
5160            let bits = unsafe {
5161                ImGui_TableGetColumnFlags(column_n.unwrap_or(-1))
5162            };
5163            TableColumnFlags::from_bits_truncate(bits)
5164        }
5165        pub fn table_get_column_name(&self, column_n: Option<i32>) -> String {
5166            unsafe {
5167                let c_str = ImGui_TableGetColumnName(column_n.unwrap_or(-1));
5168                CStr::from_ptr(c_str).to_string_lossy().into_owned()
5169            }
5170        }
5171        pub fn table_set_column_enabled(&self, column_n: Option<i32>, enabled: bool) {
5172            unsafe {
5173                ImGui_TableSetColumnEnabled(column_n.unwrap_or(-1), enabled);
5174            };
5175        }
5176        pub fn table_set_bg_color(&self, target: TableBgTarget, color: Color, column_n: Option<i32>) {
5177            unsafe {
5178                ImGui_TableSetBgColor(target.bits(), color.as_u32(), column_n.unwrap_or(-1));
5179            };
5180        }
5181        pub fn table_with_sort_specs(&self, sort_fn: impl FnOnce(&[TableColumnSortSpec])) {
5182            self.table_with_sort_specs_always(|dirty, spec| {
5183                if dirty {
5184                    sort_fn(spec);
5185                }
5186                false
5187            })
5188        }
5189        /// The `sort_fn` takes the old `dirty` and returns the new `dirty`.
5190        pub fn table_with_sort_specs_always(&self, sort_fn: impl FnOnce(bool, &[TableColumnSortSpec]) -> bool) {
5191            unsafe {
5192                let specs = ImGui_TableGetSortSpecs();
5193                if specs.is_null() {
5194                    return;
5195                }
5196                // SAFETY: TableColumnSortSpec is a repr(transparent), so this pointer cast should be ok
5197                let slice = {
5198                    let len = (*specs).SpecsCount as usize;
5199                    if len == 0 {
5200                        &[]
5201                    } else {
5202                        let ptr = std::mem::transmute::<*const ImGuiTableColumnSortSpecs, *const TableColumnSortSpec>((*specs).Specs);
5203                        std::slice::from_raw_parts(ptr, len)
5204                    }
5205                };
5206                (*specs).SpecsDirty = sort_fn((*specs).SpecsDirty, slice);
5207            }
5208        }
5209    }
5210}
5211
5212/// Helper token class that allows to set the drag&drop payload, once.
5213pub struct DragDropPayloadSetter<'a> {
5214    _dummy: PhantomData<&'a ()>,
5215}
5216
5217/// This is a sub-set of [`Cond`], only for drag&drop payloads.
5218pub enum DragDropPayloadCond {
5219    Always,
5220    Once,
5221}
5222
5223impl DragDropPayloadSetter<'_> {
5224    pub fn set(self, type_: impl IntoCStr, data: &[u8], cond: DragDropPayloadCond) -> bool {
5225        // For some reason ImGui does not accept a non-null pointer with length 0.
5226        let ptr = if data.is_empty() {
5227            null()
5228        } else {
5229            data.as_ptr() as *const c_void
5230        };
5231        let len = data.len();
5232        let cond = match cond {
5233            DragDropPayloadCond::Always => Cond::Always,
5234            DragDropPayloadCond::Once => Cond::Once,
5235        };
5236        unsafe { ImGui_SetDragDropPayload(type_.into().as_ptr(), ptr, len, cond.bits()) }
5237    }
5238}
5239
5240/// Helpar class to get the drag&drop payload.
5241pub struct DragDropPayloadGetter<'a> {
5242    _dummy: PhantomData<&'a ()>,
5243}
5244
5245/// The payload of a drag&drop operation.
5246///
5247/// It contains a "type", and a byte array.
5248pub struct DragDropPayload<'a> {
5249    pay: &'a ImGuiPayload,
5250}
5251
5252impl<'a> DragDropPayloadGetter<'a> {
5253    pub fn any(&self, flags: DragDropAcceptFlags) -> Option<DragDropPayload<'a>> {
5254        unsafe {
5255            let pay = ImGui_AcceptDragDropPayload(null(), flags.bits());
5256            if pay.is_null() {
5257                None
5258            } else {
5259                Some(DragDropPayload { pay: &*pay })
5260            }
5261        }
5262    }
5263    pub fn by_type(
5264        &self,
5265        type_: impl IntoCStr,
5266        flags: DragDropAcceptFlags,
5267    ) -> Option<DragDropPayload<'a>> {
5268        unsafe {
5269            let pay = ImGui_AcceptDragDropPayload(type_.into().as_ptr(), flags.bits());
5270            if pay.is_null() {
5271                None
5272            } else {
5273                Some(DragDropPayload { pay: &*pay })
5274            }
5275        }
5276    }
5277    pub fn peek(&self) -> Option<DragDropPayload<'a>> {
5278        unsafe {
5279            let pay = ImGui_GetDragDropPayload();
5280            if pay.is_null() {
5281                None
5282            } else {
5283                Some(DragDropPayload { pay: &*pay })
5284            }
5285        }
5286    }
5287}
5288
5289impl DragDropPayload<'_> {
5290    //WARNING: inline functions
5291    pub fn is_data_type(&self, type_: impl IntoCStr) -> bool {
5292        if self.pay.DataFrameCount == -1 {
5293            return false;
5294        }
5295        let data_type = unsafe { std::mem::transmute::<&[c_char], &[u8]>(&self.pay.DataType) };
5296        let data_type = CStr::from_bytes_until_nul(data_type).unwrap();
5297        data_type == type_.into().as_ref()
5298    }
5299    pub fn type_(&self) -> Cow<'_, str> {
5300        let data_type = unsafe { std::mem::transmute::<&[c_char], &[u8]>(&self.pay.DataType) };
5301        let data_type = CStr::from_bytes_until_nul(data_type).unwrap();
5302        data_type.to_string_lossy()
5303    }
5304    pub fn is_preview(&self) -> bool {
5305        self.pay.Preview
5306    }
5307    pub fn is_delivery(&self) -> bool {
5308        self.pay.Delivery
5309    }
5310    pub fn data(&self) -> &[u8] {
5311        if self.pay.Data.is_null() {
5312            &[]
5313        } else {
5314            unsafe {
5315                std::slice::from_raw_parts(self.pay.Data as *const u8, self.pay.DataSize as usize)
5316            }
5317        }
5318    }
5319}
5320
5321pub const PAYLOAD_TYPE_COLOR_3F: &CStr =
5322    unsafe { CStr::from_bytes_with_nul_unchecked(IMGUI_PAYLOAD_TYPE_COLOR_3F) };
5323pub const PAYLOAD_TYPE_COLOR_4F: &CStr =
5324    unsafe { CStr::from_bytes_with_nul_unchecked(IMGUI_PAYLOAD_TYPE_COLOR_4F) };
5325
5326/// This is an ImGuiKey plus several ImGuiMods.
5327///
5328/// Functions that use a `KeyChord` usually get a `impl Into<KeyChord>`. That is
5329/// implemented also for `Key` and `(KeyMod, Key)`.
5330#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5331pub struct KeyChord(ImGuiKey);
5332
5333impl KeyChord {
5334    pub fn new(mods: KeyMod, key: Key) -> KeyChord {
5335        KeyChord(ImGuiKey(mods.bits() | key.bits().0))
5336    }
5337    pub fn bits(&self) -> i32 {
5338        self.0.0
5339    }
5340    pub fn from_bits(bits: i32) -> Option<KeyChord> {
5341        // Validate that the bits are valid when building self
5342        let key = bits & !ImGuiKey::ImGuiMod_Mask_.0;
5343        let mods = bits & ImGuiKey::ImGuiMod_Mask_.0;
5344        match (Key::from_bits(ImGuiKey(key)), KeyMod::from_bits(mods)) {
5345            (Some(_), Some(_)) => Some(KeyChord(ImGuiKey(bits))),
5346            _ => None,
5347        }
5348    }
5349    pub fn key(&self) -> Key {
5350        let key = self.bits() & !ImGuiKey::ImGuiMod_Mask_.0;
5351        Key::from_bits(ImGuiKey(key)).unwrap_or(Key::None)
5352    }
5353    pub fn mods(&self) -> KeyMod {
5354        let mods = self.bits() & ImGuiKey::ImGuiMod_Mask_.0;
5355        KeyMod::from_bits_truncate(mods)
5356    }
5357}
5358
5359impl From<Key> for KeyChord {
5360    fn from(value: Key) -> Self {
5361        KeyChord::new(KeyMod::None, value)
5362    }
5363}
5364
5365impl From<(KeyMod, Key)> for KeyChord {
5366    fn from(value: (KeyMod, Key)) -> Self {
5367        KeyChord::new(value.0, value.1)
5368    }
5369}
5370
5371/// Return type for `Ui::table_get_sort_specs`.
5372#[repr(transparent)]
5373pub struct TableColumnSortSpec(ImGuiTableColumnSortSpecs);
5374
5375impl std::fmt::Debug for TableColumnSortSpec {
5376    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5377        f.debug_struct("TableColumnSortSpec")
5378            .field("id", &self.id())
5379            .field("index", &self.index())
5380            .field("sort_order", &self.sort_order())
5381            .field("sort_direction", &self.sort_direction())
5382            .finish()
5383    }
5384}
5385
5386impl TableColumnSortSpec {
5387    pub fn id(&self) -> ImGuiID {
5388        self.0.ColumnUserID
5389    }
5390    pub fn index(&self) -> usize {
5391        self.0.ColumnIndex as usize
5392    }
5393    pub fn sort_order(&self) -> usize {
5394        self.0.SortOrder as usize
5395    }
5396    pub fn sort_direction(&self) -> SortDirection {
5397        SortDirection::from_bits(self.0.SortDirection).unwrap_or(SortDirection::None)
5398    }
5399}
5400
5401pub struct DockBuilder {
5402    _dummy: (),
5403}
5404
5405impl DockBuilder {
5406    pub fn set_node_size(&self, node_id: ImGuiID, size: Vector2) {
5407        unsafe {
5408            ImGui_DockBuilderSetNodeSize(node_id, v2_to_im(size));
5409        }
5410    }
5411    pub fn set_node_pos(&self, node_id: ImGuiID, pos: Vector2) {
5412        unsafe {
5413            ImGui_DockBuilderSetNodePos(node_id, v2_to_im(pos));
5414        }
5415    }
5416    pub fn split_node(&self, node_id: ImGuiID, dir: Dir, size_ratio: f32) -> (ImGuiID, ImGuiID) {
5417        unsafe {
5418            let mut id2 = 0;
5419            let id1 = ImGui_DockBuilderSplitNode(
5420                node_id,
5421                dir.bits(),
5422                size_ratio,
5423                std::ptr::null_mut(),
5424                &mut id2,
5425            );
5426            (id1, id2)
5427        }
5428    }
5429    pub fn dock_window(&self, window_name: Id<impl IntoCStr>, node_id: ImGuiID) {
5430        unsafe {
5431            ImGui_DockBuilderDockWindow(window_name.into().as_ptr(), node_id);
5432        }
5433    }
5434    pub fn get_node(&self, node_id: ImGuiID) -> Option<&DockNode> {
5435        unsafe {
5436            let ptr = ImGui_DockBuilderGetNode(node_id);
5437            ptr.as_ref().map(DockNode::cast)
5438        }
5439    }
5440    pub fn get_node_mut(&mut self, node_id: ImGuiID) -> Option<&mut DockNode> {
5441        unsafe {
5442            let ptr = ImGui_DockBuilderGetNode(node_id);
5443            ptr.as_mut().map(DockNode::cast_mut)
5444        }
5445    }
5446}
5447
5448transparent! {
5449    pub struct DockNode(ImGuiDockNode);
5450}
5451
5452impl DockNode {
5453    pub fn local_flags(&self) -> DockNodeFlags {
5454        DockNodeFlags::from_bits_truncate(self.LocalFlags)
5455    }
5456
5457    pub fn set_local_flags(&mut self, flags: DockNodeFlags) {
5458        // inline function
5459        self.0.LocalFlags = flags.bits();
5460        self.0.MergedFlags = self.0.SharedFlags | self.0.LocalFlags | self.0.LocalFlagsInWindows;
5461    }
5462}
5463
5464transparent_mut! {
5465    #[derive(Debug, Copy, Clone)]
5466    pub struct WindowClass(ImGuiWindowClass);
5467}
5468
5469impl Default for WindowClass {
5470    fn default() -> Self {
5471        // Warning: inline C++ function
5472        WindowClass(ImGuiWindowClass {
5473            ClassId: 0,
5474            ParentViewportId: u32::MAX,
5475            FocusRouteParentWindowId: 0,
5476            ViewportFlagsOverrideSet: 0,
5477            ViewportFlagsOverrideClear: 0,
5478            TabItemFlagsOverrideSet: 0,
5479            DockNodeFlagsOverrideSet: 0,
5480            DockingAlwaysTabBar: false,
5481            DockingAllowUnclassed: true,
5482        })
5483    }
5484}
5485
5486impl WindowClass {
5487    pub fn new() -> Self {
5488        Self::default()
5489    }
5490    pub fn class_id(mut self, id: ImGuiID) -> Self {
5491        self.ClassId = id;
5492        self
5493    }
5494    pub fn parent_viewport_id(mut self, id: Option<ImGuiID>) -> Self {
5495        self.ParentViewportId = id.unwrap_or(u32::MAX);
5496        self
5497    }
5498    pub fn focus_route_parent_window_id(mut self, id: ImGuiID) -> Self {
5499        self.FocusRouteParentWindowId = id;
5500        self
5501    }
5502    pub fn dock_node_flags(mut self, set_flags: DockNodeFlags) -> Self {
5503        self.DockNodeFlagsOverrideSet = set_flags.bits();
5504        self
5505    }
5506    pub fn tab_item_flags(mut self, set_flags: TabItemFlags) -> Self {
5507        self.TabItemFlagsOverrideSet = set_flags.bits();
5508        self
5509    }
5510    pub fn viewport_flags(mut self, set_flags: ViewportFlags, clear_flags: ViewportFlags) -> Self {
5511        self.ViewportFlagsOverrideSet = set_flags.bits();
5512        self.ViewportFlagsOverrideClear = clear_flags.bits();
5513        self
5514    }
5515    pub fn docking_always_tab_bar(mut self, value: bool) -> Self {
5516        self.DockingAlwaysTabBar = value;
5517        self
5518    }
5519    pub fn docking_allow_unclassed(mut self, value: bool) -> Self {
5520        self.DockingAllowUnclassed = value;
5521        self
5522    }
5523}