Skip to main content

easy_imgui/
lib.rs

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