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 //! 
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 //! 
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 //! 
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}