imgui_ext/
lib.rs

1//! A derive-macro for [imgui](https://crates.io/crates/imgui).
2//!
3//! # Basic usage
4//!
5//! ```
6//! #[derive(imgui_ext::Gui)]
7//! struct Example {
8//!     #[imgui(slider(min = 0.0, max = 4.0))]
9//!     x: f32,
10//!     #[imgui(input(step = 2))]
11//!     y: i32,
12//!     #[imgui(drag(label = "Drag 2D"))]
13//!     drag_2d: [f32; 2],
14//!     #[imgui(checkbox(label = "Turbo mode"), display(label = "Is turbo enabled?"))]
15//!     turbo: bool,
16//! }
17//! ```
18//!
19//! ![][result]
20//!
21//! [result]: https://i.imgur.com/Xrl1Nt0.png
22//!
23//! # Input events
24//!
25//! Rendering a UI with `imgui` & `imgui-ext` returns a type with all the
26//! triggered input events which can be accessed either by field name or by
27//! method:
28//!
29//! ```
30//! use imgui_ext::UiExt;
31//!
32//! #[derive(imgui_ext::Gui)]
33//! struct Example {
34//!     #[imgui(checkbox(label = "Checkbox"))]
35//!     check: bool,
36//! }
37//!
38//! # struct A;
39//! # struct B;
40//! # impl A { fn draw_gui<T>(&self, _: &mut T) -> B { B } }
41//! # impl B { fn check(&self) -> bool { true } }
42//! # let ui = A;
43//! let mut example = Example { check: false };
44//!
45//! let events = ui.draw_gui(&mut example);
46//!
47//! if events.check() {
48//!     println!("checkbox state changed.");
49//! }
50//! ```
51//!
52//! The checkbox event is mapped to the method `check` on the returned type. The
53//! name of the method matches the name of the field on the Example type.
54//!
55//! You can override this default naming by defining the "catch" attribute on
56//! the annotation (all widgets support this attribute, not just checkbox):
57//!
58//! ```no_run
59//! use imgui_ext::UiExt;
60//!
61//! #[derive(imgui_ext::Gui)]
62//! struct Example {
63//!     #[imgui(checkbox(label = "Checkbox", catch = "checkbox_event"))]
64//!     check: bool,
65//! }
66//!
67//! # struct A;
68//! # struct B;
69//! # impl A { fn draw_gui<T>(&self, _: &mut T) -> B { B } }
70//! # impl B { fn checkbox_event(&self) -> bool { true } }
71//! # let ui = A;
72//! let mut example = Example { check: false };
73//!
74//! let events = ui.draw_gui(&mut example);
75//!
76//! if events.checkbox_event() {
77//!     println!("checkbox state changed.");
78//! }
79//! ```
80//!
81//! [repo]: https://github.com/germangb/imgui-ext
82#![deny(warnings)]
83
84use imgui::Ui;
85
86pub use imgui_ext_derive::Gui;
87
88include!("macros.rs");
89
90/// `vars(...)` docs.
91pub mod vars {
92    //!
93    //! Pushes style and color parameters to the stack, so they can be applied
94    //! to the widgets contained in the annotation.
95    //!
96    //! This is a rather complex annotation. It's not meant to be used
97    //! extensively though..
98    //!
99    //! # Params
100    //!
101    //! - `content(...)` widgets inside this annotation will have the style and
102    //!   color params applied.
103    //!
104    //! # Optional params
105    //!
106    //! - `style = "..."` path to a function returning style parameters.
107    //! - `color = "..."` path to a function returning color parameters.
108    //!
109    //! # Example
110    //!
111    //! ```
112    //! use imgui::{StyleColor, StyleVar};
113    //!
114    //! #[derive(imgui_ext::Gui)]
115    //! struct Example {
116    //!     #[imgui(vars(
117    //!         style = "example_style",
118    //!         color = "example_color",
119    //!         content(
120    //!             input(label = "foo##input"),
121    //!             drag(label = "foo##drag"),
122    //!             slider(label = "foo##slider", min = "-1.0", max = "1.0")
123    //!         )
124    //!     ))]
125    //!     foo: f32,
126    //! }
127    //!
128    //! fn example_style() -> &'static [StyleVar] {
129    //!     &[StyleVar::FrameRounding(4.0)]
130    //! }
131    //!
132    //! fn example_color() -> &'static [(StyleColor, [f32; 4])] {
133    //!     &[(StyleColor::Button, [1.0, 0.0, 1.0, 1.0])]
134    //! }
135    //! ```
136    //!
137    //! ## Result
138    //!
139    //! ![](https://i.imgur.com/TMmjOUg.png)
140}
141/// `tree(...)` docs.
142pub mod tree {
143    //!
144    //! Annotation to build static Tree UIs.
145    //!
146    //! This is a rather complex annotation. It's not meant to be used
147    //! extensively though..
148    //!
149    //! # Optional params
150    //!
151    //! - `label = ".."` mode label.
152    //! - `flags = ".."` path to a function returning [`ImGuiTreeNodeFlags`],
153    //!   which is used to customize how a tree node looks.
154    //! - `node(..)` list of widget annotations.
155    //! - `cond` One of the [`Condition`] variants.
156    //!
157    //! [`ImGuiCond`]: https://docs.rs/imgui/*/imgui/struct.Condition.html
158    //! [`ImGuiTreeNodeFlags`]: https://docs.rs/imgui/*/imgui/struct.ImGuiTreeNodeFlags.html
159    //!
160    //! # Example
161    //!
162    //! ```
163    //! use imgui::{ImGuiTreeNodeFlags, ImString};
164    //!
165    //! #[derive(imgui_ext::Gui)]
166    //! pub struct Tree {
167    //!     #[imgui(tree(
168    //!         label = "Sliders",
169    //!         cond = "FirstUseEver",
170    //!         flags = "flags",
171    //!         node(nested)
172    //!     ))]
173    //!     sliders: Sliders,
174    //!     #[imgui(tree(label = "Inputs", flags = "flags", node(nested)))]
175    //!     inputs: Inputs,
176    //!     #[imgui(tree(label = "Color picker", flags = "flags", node(color(picker))))]
177    //!     color: [f32; 3],
178    //! }
179    //!
180    //! fn flags() -> ImGuiTreeNodeFlags {
181    //!     ImGuiTreeNodeFlags::Framed
182    //! }
183    //!
184    //! #[derive(imgui_ext::Gui)]
185    //! pub struct Sliders {
186    //!     #[imgui(text("Slider widgets:"), slider(min = 0.0, max = 3.0))]
187    //!     s1: f32,
188    //!     #[imgui(slider(min = "-4", max = 4))]
189    //!     s2: [i32; 3],
190    //!     #[imgui(slider(min = "-1.0", max = 1.0))]
191    //!     s3: [f64; 2],
192    //! }
193    //!
194    //! #[derive(imgui_ext::Gui)]
195    //! pub struct Inputs {
196    //!     #[imgui(text("Input widgets:"), input)]
197    //!     i1: f32,
198    //!     #[imgui(input)]
199    //!     i2: imgui::ImString,
200    //!     #[imgui(input)]
201    //!     i3: [f32; 8],
202    //! }
203    //! ```
204    //!
205    //! # Result
206    //!
207    //! ![](https://i.imgur.com/Rn2RJJG.png)
208}
209/// `checkbox(...)` docs.
210pub mod checkbox;
211/// `color(...)` docs.
212pub mod color;
213/// `drag(...)` docs.
214pub mod drag;
215/// `image(...)` docs.
216pub mod image;
217/// `image_button(...)` docs.
218pub mod image_button;
219/// `input(...)` docs.
220pub mod input;
221/// `progress(...)` docs.
222pub mod progress;
223/// `slider(...)` docs.
224pub mod slider;
225/// `text(...)` & `text_wrap(...)` docs.
226pub mod text {
227    //!
228    //! # Variants
229    //!
230    //! - `text(...)` non-wrapping text.
231    //! - `text_wrap(...)` wrapping text.
232    //!
233    //! # Params
234    //!
235    //! * `lit` a string literal.
236    //!
237    //! You can also write this annotation as:
238    //!
239    //! * `#[imgui(text("literal..."))]`
240    //!
241    //! which is a shorthand for `text(lit = "literal...")`.
242    //!
243    //! # Example
244    //!
245    //! ```
246    //! #[derive(imgui_ext::Gui)]
247    //! struct Example {
248    //!     #[imgui(text_wrap("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc metus sem, facilisis hendrerit elementum et, egestas."),
249    //!             separator(),
250    //!             text("Input num:"),
251    //!             slider(min = "-1.0", max = 1.0),
252    //!             button(label = "Submit"))]
253    //!     number: f32,
254    //! }
255    //! ```
256    //!
257    //! # Result
258    //!
259    //! ![](https://i.imgur.com/0uvMFIm.png)
260}
261pub mod misc {
262    //! []()
263    //!
264    //! * `#[imgui(separator)]` inserts a separator
265    //! * `#[imgui(new_line)]` inserts an empty line
266}
267/// `display(...)` docs.
268pub mod display {
269    //!
270    //! `display(...)` is used to display and format a field.
271    //!
272    //! # Optional fields
273    //!
274    //! * `label` override widget label.
275    //! * `display` formatted text.
276    //!
277    //! # Example
278    //!
279    //! ```
280    //! #[derive(imgui_ext::Gui)]
281    //! struct Labels {
282    //!     #[imgui(display)]
283    //!     foo: f32,
284    //!
285    //!     // Use inner fields to format the text.
286    //!     #[imgui(display(label = "Tuple", display = "({}, {}, {})", 0, 1, 2))]
287    //!     bar: (f32, bool, usize),
288    //!
289    //!     // When display is the only annotation on a type, you may write it in this shorter form:
290    //!     #[imgui(label = "String param")]
291    //!     baz: String,
292    //! }
293    //! ```
294    //!
295    //! ![][result]
296    //!
297    //! [result]: https://i.imgur.com/Wf4Uze7.png
298}
299/// `nested(...)` docs (used to build nested UIs).
300pub mod nested {
301    //!
302    //! Types that `#[derive(Ui)]` can be nested.
303    //!
304    //! # Optional fields
305    //!
306    //! * `catch`
307    //!
308    //! # Example
309    //!
310    //! ```
311    //! #[derive(imgui_ext::Gui)]
312    //! struct Form {
313    //!     #[imgui(input)]
314    //!     user: imgui::ImString,
315    //!     #[imgui(
316    //!         input(flags = "passwd_flags"),
317    //!         button(label = "Login", catch = "login_btn")
318    //!     )]
319    //!     passwd: imgui::ImString,
320    //! }
321    //!
322    //! fn passwd_flags() -> imgui::ImGuiInputTextFlags {
323    //!     imgui::ImGuiInputTextFlags::Password
324    //! }
325    //!
326    //! #[derive(imgui_ext::Gui)]
327    //! struct Example {
328    //!     #[imgui(nested, separator)]
329    //!     login_form: Form,
330    //!     #[imgui(checkbox(label = "Remember login?"))]
331    //!     remember: bool,
332    //! }
333    //! ```
334    //!
335    //! ## Result
336    //!
337    //! ![][result]
338    //!
339    //! [result]: https://i.imgur.com/l6omyf4.png
340    //!
341    //! # Nested input events
342    //!
343    //! You can access input events from nested UIs:
344    //!
345    //! ```ignore
346    //! // initialize imgui (ui) ...
347    //!
348    //! let mut example = Example { ... };
349    //! let events: Events<Example> = ui.imgui_ext(&mut example);
350    //!
351    //! if events.login_form().login_btn() {
352    //!     validate_user(
353    //!         &example.login_form.user,
354    //!         &example.login_form.passwd,
355    //!     )
356    //! }
357    //! ```
358}
359/// `button(...)` docs.
360pub mod button {
361    //!
362    //! `button(...)` places a button on the UI.
363    //!
364    //! # Fields
365    //!
366    //! - `label` button name.
367    //!
368    //! # Optional fields
369    //!
370    //! - `size` path to a function that returns the button size.
371    //! - `catch`
372    //!
373    //! # Example
374    //!
375    //! ```
376    //! use imgui_ext::UiExt;
377    //!
378    //! #[derive(imgui_ext::Gui)]
379    //! struct Button {
380    //!     #[imgui(
381    //!         button(size = "button_size", label = "Click me!", catch = "click"),
382    //!         separator,
383    //!         display(label = "Clicks")
384    //!     )]
385    //!     count: i32,
386    //! }
387    //!
388    //! const fn button_size() -> [f32; 2] {
389    //!     [100.0, 20.0]
390    //! }
391    //!
392    //! # struct A;
393    //! # struct B;
394    //! # impl A { fn draw_gui<T>(&self, _: &mut T) -> B { B } }
395    //! # impl B { fn click(&self) -> bool { true } }
396    //! # let ui = A;
397    //! let mut buttons = Button { count: 0 };
398    //!
399    //! let events = ui.draw_gui(&mut buttons);
400    //!
401    //! if events.click() {
402    //!     buttons.count += 1;
403    //! }
404    //! ```
405    //!
406    //! ![][image]
407    //!
408    //! [image]: https://i.imgur.com/PpOcZK8.png
409}
410/// `bullet(...)` docs.
411pub mod bullet {
412    //!
413    //! Used to build bulleted lists. It has two variants:
414    //!
415    //! * `bullet(text = "...")` Bullet text.
416    //! * `bullet(...)` bullet widget.
417    //!
418    //! # Example
419    //!
420    //! ```
421    //! #[derive(imgui_ext::Gui)]
422    //! struct Bullet {
423    //!     #[imgui(
424    //!         bullet(text = "Be nice to others."),
425    //!         bullet(text = "Don't repeat your password"),
426    //!         bullet(text = "Kill all humans."),
427    //!         bullet(slider(min = 0.0, max = 1.0))
428    //!     )]
429    //!     foo: f32,
430    //! }
431    //! ```
432    //!
433    //! ## Result
434    //!
435    //! ![][result]
436    //!
437    //! [result]: https://i.imgur.com/CLPl993.png
438}
439
440/// Trait implemented by the derive macro.
441pub trait Gui {
442    type Events;
443    fn draw_gui(ui: &Ui, ext: &mut Self) -> Self::Events;
444}
445
446impl<T: Gui> Gui for Option<T> {
447    type Events = T::Events;
448
449    // TODO remove unsafe
450    fn draw_gui(ui: &Ui, ext: &mut Self) -> Self::Events {
451        if let Some(ref mut ext) = ext {
452            T::draw_gui(ui, ext)
453        } else {
454            unsafe { std::mem::zeroed() }
455        }
456    }
457}
458
459impl<T: Gui> Gui for Box<T> {
460    type Events = T::Events;
461    #[inline]
462    fn draw_gui(ui: &Ui, ext: &mut Self) -> Self::Events {
463        T::draw_gui(ui, ext.as_mut())
464    }
465}
466
467/// Extension trait for imgui's [`Ui`](https://docs.rs/imgui/*/imgui/struct.Ui.html).
468///
469/// ```
470/// use imgui_ext::UiExt;
471///
472/// #[derive(imgui_ext::Gui)]
473/// struct Example {
474///     // ...
475/// }
476///
477/// # struct A;
478/// # struct B;
479/// # impl A { fn draw_gui<T>(&self, _: &mut T) -> B { B } }
480/// # impl B { fn click(&self) -> bool { true } }
481/// # fn init_imgui() -> A { A }
482///
483/// // Initialize the imgui crate...
484/// let ui = init_imgui();
485///
486/// // initialize Example...
487/// let mut example = Example { /* ... */ };
488///
489/// ui.draw_gui(&mut example);
490/// ```
491pub trait UiExt {
492    fn draw_gui<U: Gui>(&self, ext: &mut U) -> U::Events;
493}
494
495impl UiExt for Ui<'_> {
496    #[inline]
497    fn draw_gui<U: Gui>(&self, ext: &mut U) -> U::Events {
498        U::draw_gui(self, ext)
499    }
500}