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