easy_imgui/
lib.rs

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