diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index d453a88..8b472db 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -314,6 +314,53 @@ impl<'a> Default for Id<'a> { } } +impl<'ui> Ui<'ui> { + /// # Windows + /// Start constructing a window. + /// + /// This, like many objects in the library, uses the builder + /// pattern to set optional arguments (like window size, flags, + /// etc). Once all desired options are set, you must call either + /// [`Window::build`] or [`Window::begin`] must be called to + /// actually create the window. + /// + /// # Examples + /// + /// Create a window using the closure based [`Window::build`]: + /// ```no_run + /// # let mut ctx = imgui::Context::create(); + /// # let ui = ctx.frame(); + /// ui.window("Example Window") + /// .size([100.0, 50.0], imgui::Condition::FirstUseEver) + /// .build(|| { + /// ui.text("An example"); + /// }); + /// ``` + pub fn window>(&'ui self, name: Label) -> Window<'ui, '_, Label> { + Window::new(self, name) + } + + /// Same as [`Ui::window`] but using the "token based" `.begin()` approach. + /// + /// ``` + /// fn example(ui: &imgui::Ui) { + /// let wt = ui.window("Example Window") + /// .size([100.0, 50.0], imgui::Condition::FirstUseEver) + /// .begin(); + /// if wt.is_some() { + /// ui.text("Window is visible"); + /// } + /// // Window ends where where wt is dropped, + /// // or you could call + /// wt.unwrap().end() + /// } + /// ``` + pub fn child_window>(&'ui self, name: Label) -> ChildWindow<'ui, Label> { + ChildWindow::new(self, name) + } +} + + // Widgets: Input impl<'ui> Ui<'ui> { #[doc(alias = "InputText", alias = "InputTextWithHint")] diff --git a/imgui/src/window/child_window.rs b/imgui/src/window/child_window.rs index 413c28f..741c657 100644 --- a/imgui/src/window/child_window.rs +++ b/imgui/src/window/child_window.rs @@ -1,15 +1,15 @@ use std::f32; -use std::os::raw::{c_char, c_void}; use crate::sys; use crate::window::WindowFlags; -use crate::{Id, Ui}; +use crate::Ui; /// Builder for a child window #[derive(Copy, Clone, Debug)] #[must_use] -pub struct ChildWindow<'a> { - id: Id<'a>, +pub struct ChildWindow<'ui, Label> { + ui: &'ui Ui<'ui>, + name: Label, flags: WindowFlags, size: [f32; 2], content_size: [f32; 2], @@ -18,12 +18,13 @@ pub struct ChildWindow<'a> { border: bool, } -impl<'a> ChildWindow<'a> { +impl<'ui, Label: AsRef> ChildWindow<'ui, Label> { /// Creates a new child window builder with the given ID #[doc(alias = "BeginChildID")] - pub fn new>>(id: T) -> ChildWindow<'a> { + pub fn new(ui: &'ui Ui<'ui>, name: Label) -> ChildWindow<'ui, Label> { ChildWindow { - id: id.into(), + ui, + name, flags: WindowFlags::empty(), size: [0.0, 0.0], content_size: [0.0, 0.0], @@ -245,7 +246,7 @@ impl<'a> ChildWindow<'a> { /// rendered, the token must be ended by calling `.end()`. /// /// Returns `None` if the window is not visible and no content should be rendered. - pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option> { + pub fn begin(self) -> Option> { if self.content_size[0] != 0.0 || self.content_size[1] != 0.0 { unsafe { sys::igSetNextWindowContentSize(self.content_size.into()) }; } @@ -255,22 +256,16 @@ impl<'a> ChildWindow<'a> { if self.bg_alpha.is_finite() { unsafe { sys::igSetNextWindowBgAlpha(self.bg_alpha) }; } - let id = unsafe { - match self.id { - Id::Int(i) => sys::igGetID_Ptr(i as *const c_void), - Id::Ptr(p) => sys::igGetID_Ptr(p), - Id::Str(s) => { - let start = s.as_ptr() as *const c_char; - let end = start.add(s.len()); - sys::igGetID_StrStr(start, end) - } - } - }; let should_render = unsafe { - sys::igBeginChild_ID(id, self.size.into(), self.border, self.flags.bits() as i32) + sys::igBeginChild_Str( + self.ui.scratch_txt(self.name), + self.size.into(), + self.border, + self.flags.bits() as i32, + ) }; if should_render { - Some(ChildWindowToken::new(ui)) + Some(ChildWindowToken::new(self.ui)) } else { unsafe { sys::igEndChild() }; None @@ -281,8 +276,8 @@ impl<'a> ChildWindow<'a> { /// /// Note: the closure is not called if no window content is visible (e.g. window is collapsed /// or fully clipped). - pub fn build T>(self, ui: &Ui<'_>, f: F) -> Option { - self.begin(ui).map(|_window| f()) + pub fn build T>(self, f: F) -> Option { + self.begin().map(|_window| f()) } } diff --git a/imgui/src/window/mod.rs b/imgui/src/window/mod.rs index 04161cd..a0f873c 100644 --- a/imgui/src/window/mod.rs +++ b/imgui/src/window/mod.rs @@ -160,8 +160,9 @@ impl<'ui> Ui<'ui> { /// Builder for a window #[derive(Debug)] #[must_use] -pub struct Window<'a, T> { - name: T, +pub struct Window<'ui, 'a, Label> { + ui: &'ui Ui<'ui>, + name: Label, opened: Option<&'a mut bool>, flags: WindowFlags, pos: [f32; 2], @@ -177,10 +178,11 @@ pub struct Window<'a, T> { bg_alpha: f32, } -impl<'a, T: AsRef> Window<'a, T> { - /// Creates a new window builder with the given name - pub fn new(name: T) -> Self { +impl<'ui, 'a, Label: AsRef> Window<'ui, 'a, Label> { + /// Typically created via [`Ui::window`] + pub fn new(ui: &'ui Ui<'ui>, name: Label) -> Self { Window { + ui, name, opened: None, flags: WindowFlags::empty(), @@ -487,7 +489,7 @@ impl<'a, T: AsRef> Window<'a, T> { /// /// Returns `None` if the window is not visible and no content should be rendered. #[must_use] - pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option> { + pub fn begin(self) -> Option> { if self.pos_cond != Condition::Never { unsafe { sys::igSetNextWindowPos( @@ -525,7 +527,7 @@ impl<'a, T: AsRef> Window<'a, T> { } let should_render = unsafe { sys::igBegin( - ui.scratch_txt(self.name), + self.ui.scratch_txt(self.name), self.opened .map(|x| x as *mut bool) .unwrap_or(ptr::null_mut()), @@ -533,7 +535,7 @@ impl<'a, T: AsRef> Window<'a, T> { ) }; if should_render { - Some(WindowToken::new(ui)) + Some(WindowToken::new(self.ui)) } else { unsafe { sys::igEnd() }; None @@ -542,10 +544,10 @@ impl<'a, T: AsRef> Window<'a, T> { /// Creates a window and runs a closure to construct the contents. /// Returns the result of the closure, if it is called. /// - /// Note: the closure is not called if no window content is visible (e.g. window is collapsed - /// or fully clipped). - pub fn build R>(self, ui: &Ui<'_>, f: F) -> Option { - self.begin(ui).map(|_window| f()) + /// Note: the closure is only called if the window content is + /// visible (e.g. will not run if window is collapsed). + pub fn build R>(self, f: F) -> Option { + self.begin().map(|_window| f()) } }