From 5143968429a680f4e6bc5fbb313742861818f142 Mon Sep 17 00:00:00 2001 From: Jack Spira Date: Wed, 8 Sep 2021 09:05:30 -0700 Subject: [PATCH] updating more widgets. Wow this is boring! --- imgui-examples/examples/progress_bar.rs | 4 +- imgui-examples/examples/slider.rs | 2 +- imgui-examples/examples/test_window_impl.rs | 2 +- imgui/src/lib.rs | 8 ++ imgui/src/widget/progress_bar.rs | 36 +++--- imgui/src/widget/selectable.rs | 13 +- imgui/src/widget/slider.rs | 112 +++++++++--------- imgui/src/widget/tab.rs | 125 +++++++++++++------- imgui/src/widget/text.rs | 6 +- 9 files changed, 181 insertions(+), 127 deletions(-) diff --git a/imgui-examples/examples/progress_bar.rs b/imgui-examples/examples/progress_bar.rs index b5bd9db..65cbcd5 100644 --- a/imgui-examples/examples/progress_bar.rs +++ b/imgui-examples/examples/progress_bar.rs @@ -19,9 +19,7 @@ fn main() { ui.separator(); ui.text("This progress bar uses overlay text:"); - ProgressBar::new(0.8) - .overlay_text(im_str!("Lorem ipsum")) - .build(ui); + ProgressBar::new_with_overlay(0.8, "Lorem ipsum").build(ui); }); }); } diff --git a/imgui-examples/examples/slider.rs b/imgui-examples/examples/slider.rs index 2b3698e..00c1428 100644 --- a/imgui-examples/examples/slider.rs +++ b/imgui-examples/examples/slider.rs @@ -56,7 +56,7 @@ fn example_1(ui: &Ui, state: &mut State) { ui.separator(); ui.text("Value formatting can be customized with a C-style printf string:"); Slider::new(im_str!("f64 value with custom formatting"), -999_999_999.0, 999_999_999.0) - .display_format(im_str!("%09.0f")) + .display_format("%09.0f") .build(ui, &mut state.f64_formatted); ui.separator(); diff --git a/imgui-examples/examples/test_window_impl.rs b/imgui-examples/examples/test_window_impl.rs index 5e88788..0398b84 100644 --- a/imgui-examples/examples/test_window_impl.rs +++ b/imgui-examples/examples/test_window_impl.rs @@ -449,7 +449,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { ui.spacing(); Slider::new(im_str!("Wrap width"), -20.0, 600.0) - .display_format(im_str!("%.0f")) + .display_format("%.0f") .build(ui, &mut state.wrap_width); ui.text(im_str!("Test paragraph 1:")); diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index 82a2882..563883a 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -137,6 +137,14 @@ impl<'ui> Ui<'ui> { } } + /// Internal method to push an option text to our scratch buffer. + fn scratch_txt_opt(&self, txt: Option>) -> *const sys::cty::c_char { + match txt { + Some(v) => self.scratch_txt(v), + None => std::ptr::null(), + } + } + fn scratch_txt_two( &self, txt_0: impl AsRef, diff --git a/imgui/src/widget/progress_bar.rs b/imgui/src/widget/progress_bar.rs index 255399b..5a806af 100644 --- a/imgui/src/widget/progress_bar.rs +++ b/imgui/src/widget/progress_bar.rs @@ -1,7 +1,5 @@ -use std::ptr; - -use crate::string::ImStr; use crate::sys; +// use crate::ImStr; use crate::Ui; /// Builder for a progress bar widget. @@ -19,13 +17,13 @@ use crate::Ui; /// ``` #[derive(Copy, Clone, Debug)] #[must_use] -pub struct ProgressBar<'a> { +pub struct ProgressBar { fraction: f32, size: [f32; 2], - overlay_text: Option<&'a ImStr>, + overlay_text: Option, } -impl<'a> ProgressBar<'a> { +impl ProgressBar<&'static str> { /// Creates a progress bar with a given fraction showing /// the progress (0.0 = 0%, 1.0 = 100%). /// @@ -33,19 +31,29 @@ impl<'a> ProgressBar<'a> { /// custom size is specified. #[inline] #[doc(alias = "ProgressBar")] - pub const fn new(fraction: f32) -> ProgressBar<'a> { + pub fn new(fraction: f32) -> Self { ProgressBar { fraction, size: [-1.0, 0.0], overlay_text: None, } } +} - /// Sets an optional text that will be drawn over the progress bar. +impl> ProgressBar { + /// Creates a progress bar with a given fraction showing + /// the progress (0.0 = 0%, 1.0 = 100%). + /// + /// The progress bar will be automatically sized to fill the entire width of the window if no + /// custom size is specified. #[inline] - pub const fn overlay_text(mut self, overlay_text: &'a ImStr) -> ProgressBar { - self.overlay_text = Some(overlay_text); - self + #[doc(alias = "ProgressBar")] + pub fn new_with_overlay(fraction: f32, overlay_text: T) -> Self { + ProgressBar { + fraction, + size: [-1.0, 0.0], + overlay_text: Some(overlay_text), + } } /// Sets the size of the progress bar. @@ -53,18 +61,18 @@ impl<'a> ProgressBar<'a> { /// Negative values will automatically align to the end of the axis, zero will let the progress /// bar choose a size, and positive values will use the given size. #[inline] - pub const fn size(mut self, size: [f32; 2]) -> Self { + pub fn size(mut self, size: [f32; 2]) -> Self { self.size = size; self } /// Builds the progress bar - pub fn build(self, _: &Ui) { + pub fn build(self, ui: &Ui) { unsafe { sys::igProgressBar( self.fraction, self.size.into(), - self.overlay_text.map(|x| x.as_ptr()).unwrap_or(ptr::null()), + ui.scratch_txt_opt(self.overlay_text), ); } } diff --git a/imgui/src/widget/selectable.rs b/imgui/src/widget/selectable.rs index 83fd455..e266995 100644 --- a/imgui/src/widget/selectable.rs +++ b/imgui/src/widget/selectable.rs @@ -23,20 +23,20 @@ bitflags!( /// Builder for a selectable widget. #[derive(Copy, Clone, Debug)] #[must_use] -pub struct Selectable<'a> { - label: &'a str, +pub struct Selectable { + label: T, selected: bool, flags: SelectableFlags, size: [f32; 2], } -impl<'a> Selectable<'a> { +impl> Selectable { /// Constructs a new selectable builder. #[inline] #[doc(alias = "Selectable")] - pub fn new(label: &'a impl AsRef) -> Selectable<'a> { + pub fn new(label: T) -> Self { Selectable { - label: label.as_ref(), + label, selected: false, flags: SelectableFlags::empty(), size: [0.0, 0.0], @@ -117,10 +117,7 @@ impl<'a> Selectable<'a> { ) } } -} -/// # Convenience functions -impl<'a> Selectable<'a> { /// Builds the selectable using a mutable reference to selected state. pub fn build_with_ref(self, ui: &Ui, selected: &mut bool) -> bool { if self.selected(*selected).build(ui) { diff --git a/imgui/src/widget/slider.rs b/imgui/src/widget/slider.rs index 531b155..f08e026 100644 --- a/imgui/src/widget/slider.rs +++ b/imgui/src/widget/slider.rs @@ -1,9 +1,7 @@ use bitflags::bitflags; use std::os::raw::c_void; -use std::ptr; use crate::internal::DataTypeKind; -use crate::string::ImStr; use crate::sys; use crate::Ui; @@ -27,18 +25,18 @@ bitflags!( /// Builder for a slider widget. #[derive(Copy, Clone, Debug)] #[must_use] -pub struct Slider<'a, T: DataTypeKind> { - label: &'a ImStr, - min: T, - max: T, - display_format: Option<&'a ImStr>, +pub struct Slider<'a, T, K: DataTypeKind> { + label: T, + min: K, + max: K, + display_format: Option<&'a str>, flags: SliderFlags, } -impl<'a, T: DataTypeKind> Slider<'a, T> { +impl<'a, T: AsRef, K: DataTypeKind> Slider<'a, T, K> { /// Constructs a new slider builder with the given range. #[doc(alias = "SliderScalar", alias = "SliderScalarN")] - pub fn new(label: &ImStr, min: T, max: T) -> Slider { + pub fn new(label: T, min: K, max: K) -> Self { Slider { label, min, @@ -61,14 +59,14 @@ impl<'a, T: DataTypeKind> Slider<'a, T> { /// It is safe, though up to C++ Dear ImGui, on how to handle when /// `min > max`. #[inline] - pub fn range(mut self, min: T, max: T) -> Self { + pub fn range(mut self, min: K, max: K) -> Self { self.min = min; self.max = max; self } /// Sets the display format using *a C-style printf string* #[inline] - pub fn display_format(mut self, display_format: &'a ImStr) -> Self { + pub fn display_format(mut self, display_format: &'a str) -> Self { self.display_format = Some(display_format); self } @@ -81,17 +79,17 @@ impl<'a, T: DataTypeKind> Slider<'a, T> { /// Builds a slider that is bound to the given value. /// /// Returns true if the slider value was changed. - pub fn build(self, _: &Ui, value: &mut T) -> bool { + pub fn build(self, ui: &Ui, value: &mut K) -> bool { unsafe { + let (label, display_format) = ui.scratch_txt_with_opt(self.label, self.display_format); + sys::igSliderScalar( - self.label.as_ptr(), - T::KIND as i32, - value as *mut T as *mut c_void, - &self.min as *const T as *const c_void, - &self.max as *const T as *const c_void, - self.display_format - .map(ImStr::as_ptr) - .unwrap_or(ptr::null()), + label, + K::KIND as i32, + value as *mut K as *mut c_void, + &self.min as *const K as *const c_void, + &self.max as *const K as *const c_void, + display_format, self.flags.bits() as i32, ) } @@ -99,18 +97,18 @@ impl<'a, T: DataTypeKind> Slider<'a, T> { /// Builds a horizontal array of multiple sliders attached to the given slice. /// /// Returns true if any slider value was changed. - pub fn build_array(self, _: &Ui, values: &mut [T]) -> bool { + pub fn build_array(self, ui: &Ui, values: &mut [K]) -> bool { unsafe { + let (label, display_format) = ui.scratch_txt_with_opt(self.label, self.display_format); + sys::igSliderScalarN( - self.label.as_ptr(), - T::KIND as i32, + label, + K::KIND as i32, values.as_mut_ptr() as *mut c_void, values.len() as i32, - &self.min as *const T as *const c_void, - &self.max as *const T as *const c_void, - self.display_format - .map(ImStr::as_ptr) - .unwrap_or(ptr::null()), + &self.min as *const K as *const c_void, + &self.max as *const K as *const c_void, + display_format, self.flags.bits() as i32, ) } @@ -120,16 +118,16 @@ impl<'a, T: DataTypeKind> Slider<'a, T> { /// Builder for a vertical slider widget. #[derive(Clone, Debug)] #[must_use] -pub struct VerticalSlider<'a, T: DataTypeKind + Copy> { - label: &'a ImStr, +pub struct VerticalSlider<'a, T, K: DataTypeKind> { + label: T, size: [f32; 2], - min: T, - max: T, - display_format: Option<&'a ImStr>, + min: K, + max: K, + display_format: Option<&'a str>, flags: SliderFlags, } -impl<'a, T: DataTypeKind> VerticalSlider<'a, T> { +impl<'a, T: AsRef, K: DataTypeKind> VerticalSlider<'a, T, K> { /// Constructs a new vertical slider builder with the given size and range. /// /// ```rust @@ -143,7 +141,7 @@ impl<'a, T: DataTypeKind> VerticalSlider<'a, T> { /// It is safe, though up to C++ Dear ImGui, on how to handle when /// `min > max`. #[doc(alias = "VSliderScalar")] - pub fn new(label: &ImStr, size: [f32; 2], min: T, max: T) -> VerticalSlider { + pub fn new(label: T, size: [f32; 2], min: K, max: K) -> Self { VerticalSlider { label, size, @@ -167,14 +165,14 @@ impl<'a, T: DataTypeKind> VerticalSlider<'a, T> { /// It is safe, though up to C++ Dear ImGui, on how to handle when /// `min > max`. #[inline] - pub fn range(mut self, min: T, max: T) -> Self { + pub fn range(mut self, min: K, max: K) -> Self { self.min = min; self.max = max; self } /// Sets the display format using *a C-style printf string* #[inline] - pub fn display_format(mut self, display_format: &'a ImStr) -> Self { + pub fn display_format(mut self, display_format: &'a str) -> Self { self.display_format = Some(display_format); self } @@ -187,18 +185,18 @@ impl<'a, T: DataTypeKind> VerticalSlider<'a, T> { /// Builds a vertical slider that is bound to the given value. /// /// Returns true if the slider value was changed. - pub fn build(self, _: &Ui, value: &mut T) -> bool { + pub fn build(self, ui: &Ui, value: &mut K) -> bool { unsafe { + let (label, display_format) = ui.scratch_txt_with_opt(self.label, self.display_format); + sys::igVSliderScalar( - self.label.as_ptr(), + label, self.size.into(), - T::KIND as i32, - value as *mut T as *mut c_void, - &self.min as *const T as *const c_void, - &self.max as *const T as *const c_void, - self.display_format - .map(ImStr::as_ptr) - .unwrap_or(ptr::null()), + K::KIND as i32, + value as *mut K as *mut c_void, + &self.min as *const K as *const c_void, + &self.max as *const K as *const c_void, + display_format, self.flags.bits() as i32, ) } @@ -208,24 +206,24 @@ impl<'a, T: DataTypeKind> VerticalSlider<'a, T> { /// Builder for an angle slider widget. #[derive(Copy, Clone, Debug)] #[must_use] -pub struct AngleSlider<'a> { - label: &'a ImStr, +pub struct AngleSlider<'a, T> { + label: T, min_degrees: f32, max_degrees: f32, - display_format: &'a ImStr, + display_format: &'a str, flags: SliderFlags, } -impl<'a> AngleSlider<'a> { +impl<'a, T: AsRef> AngleSlider<'a, T> { /// Constructs a new angle slider builder, where its minimum defaults to -360.0 and /// maximum defaults to 360.0 #[doc(alias = "SliderAngle")] - pub fn new(label: &ImStr) -> AngleSlider { + pub fn new(label: T) -> Self { AngleSlider { label, min_degrees: -360.0, max_degrees: 360.0, - display_format: im_str!("%.0f deg"), + display_format: "%.0f deg", flags: SliderFlags::empty(), } } @@ -260,7 +258,7 @@ impl<'a> AngleSlider<'a> { } /// Sets the display format using *a C-style printf string* #[inline] - pub fn display_format(mut self, display_format: &'a ImStr) -> Self { + pub fn display_format(mut self, display_format: &'a str) -> Self { self.display_format = display_format; self } @@ -273,14 +271,16 @@ impl<'a> AngleSlider<'a> { /// Builds an angle slider that is bound to the given value (in radians). /// /// Returns true if the slider value was changed. - pub fn build(self, _: &Ui, value_rad: &mut f32) -> bool { + pub fn build(self, ui: &Ui, value_rad: &mut f32) -> bool { unsafe { + let (label, display_format) = ui.scratch_txt_two(self.label, self.display_format); + sys::igSliderAngle( - self.label.as_ptr(), + label, value_rad as *mut _, self.min_degrees, self.max_degrees, - self.display_format.as_ptr(), + display_format, self.flags.bits() as i32, ) } diff --git a/imgui/src/widget/tab.rs b/imgui/src/widget/tab.rs index 20f6ed2..5719443 100644 --- a/imgui/src/widget/tab.rs +++ b/imgui/src/widget/tab.rs @@ -1,5 +1,3 @@ -//! Safe wrapper around imgui-sys for tab menu. -//! //! # Examples // //! ```no_run @@ -19,7 +17,6 @@ //! ``` //! //! See `test_window_impl.rs` for a more complicated example. -use crate::string::ImStr; use crate::sys; use crate::Ui; use bitflags::bitflags; @@ -56,15 +53,15 @@ bitflags! { } /// Builder for a tab bar. -pub struct TabBar<'a> { - id: &'a ImStr, +pub struct TabBar { + id: T, flags: TabBarFlags, } -impl<'a> TabBar<'a> { +impl> TabBar { #[inline] #[doc(alias = "BeginTabBar")] - pub const fn new(id: &'a ImStr) -> Self { + pub fn new(id: T) -> Self { Self { id, flags: TabBarFlags::empty(), @@ -90,23 +87,15 @@ impl<'a> TabBar<'a> { } #[must_use] - pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option> { - let should_render = - unsafe { sys::igBeginTabBar(self.id.as_ptr(), self.flags.bits() as i32) }; - - if should_render { - Some(TabBarToken::new(ui)) - } else { - unsafe { sys::igEndTabBar() }; - None - } + pub fn begin<'ui>(self, ui: &'ui Ui<'_>) -> Option> { + ui.tab_bar_with_flags(self.id, self.flags) } /// Creates a tab bar 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 tabbar content is visible - pub fn build T>(self, ui: &Ui<'_>, f: F) -> Option { + pub fn build R>(self, ui: &Ui<'_>, f: F) -> Option { self.begin(ui).map(|_tab| f()) } } @@ -120,23 +109,23 @@ create_token!( drop { sys::igEndTabBar() } ); -pub struct TabItem<'a> { - name: &'a ImStr, +pub struct TabItem<'a, T> { + label: T, opened: Option<&'a mut bool>, flags: TabItemFlags, } -impl<'a> TabItem<'a> { +impl<'a, T: AsRef> TabItem<'a, T> { #[doc(alias = "BeginTabItem")] - pub fn new(name: &'a ImStr) -> Self { + pub fn new(name: T) -> Self { Self { - name, + label: name, opened: None, flags: TabItemFlags::empty(), } } - /// Will open or close the tab.\ + /// Will open or close the tab. /// /// True to display the tab. Tab item is visible by default. #[inline] @@ -155,29 +144,15 @@ impl<'a> TabItem<'a> { } #[must_use] - pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option> { - let should_render = unsafe { - sys::igBeginTabItem( - self.name.as_ptr(), - self.opened - .map(|x| x as *mut bool) - .unwrap_or(ptr::null_mut()), - self.flags.bits() as i32, - ) - }; - - if should_render { - Some(TabItemToken::new(ui)) - } else { - None - } + pub fn begin<'ui>(self, ui: &'ui Ui<'_>) -> Option> { + ui.tab_item_with_flags(self.label, self.opened, self.flags) } /// Creates a tab item 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 the tab item is not selected - pub fn build T>(self, ui: &Ui<'_>, f: F) -> Option { + pub fn build R>(self, ui: &Ui<'_>, f: F) -> Option { self.begin(ui).map(|_tab| f()) } } @@ -190,3 +165,71 @@ create_token!( /// Ends a tab bar item. drop { sys::igEndTabItem() } ); + +impl Ui<'_> { + /// Creates a tab bar and returns a tab bar token, allowing you to append + /// Tab items afterwards. This passes no flags. To pass flags explicitly, + /// use [tab_bar_with_flags]. + pub fn tab_bar(&self, id: impl AsRef) -> Option> { + self.tab_bar_with_flags(id, TabBarFlags::empty()) + } + // + /// Creates a tab bar and returns a tab bar token, allowing you to append + /// Tab items afterwards. + pub fn tab_bar_with_flags( + &self, + id: impl AsRef, + flags: TabBarFlags, + ) -> Option> { + let should_render = + unsafe { sys::igBeginTabBar(self.scratch_txt(id), flags.bits() as i32) }; + + if should_render { + Some(TabBarToken::new(self)) + } else { + unsafe { sys::igEndTabBar() }; + None + } + } + + /// Creates a new tab item and returns a token if its contents are visible. + /// + /// By default, this doesn't pass an opened bool nor any flags. See [tab_item_with_opened] + /// and `[tab_item_with_flags]` for more. + pub fn tab_item(&self, label: impl AsRef) -> Option> { + self.tab_item_with_flags(label, None, TabItemFlags::empty()) + } + + /// Creates a new tab item and returns a token if its contents are visible. + /// + /// By default, this doesn't pass any flags. See `[tab_item_with_flags]` for more. + pub fn tab_item_with_opened( + &self, + label: impl AsRef, + opened: &mut bool, + ) -> Option> { + self.tab_item_with_flags(label, Some(opened), TabItemFlags::empty()) + } + + /// Creates a new tab item and returns a token if its contents are visible. + pub fn tab_item_with_flags( + &self, + label: impl AsRef, + opened: Option<&mut bool>, + flags: TabItemFlags, + ) -> Option> { + let should_render = unsafe { + sys::igBeginTabItem( + self.scratch_txt(label), + opened.map(|x| x as *mut bool).unwrap_or(ptr::null_mut()), + flags.bits() as i32, + ) + }; + + if should_render { + Some(TabItemToken::new(self)) + } else { + None + } + } +} diff --git a/imgui/src/widget/text.rs b/imgui/src/widget/text.rs index 65f3849..7273ec4 100644 --- a/imgui/src/widget/text.rs +++ b/imgui/src/widget/text.rs @@ -1,6 +1,6 @@ use std::os::raw::c_char; -use crate::string::ImStr; +// use crate::string::ImStr; use crate::style::StyleColor; use crate::Ui; @@ -49,7 +49,7 @@ impl<'ui> Ui<'ui> { } /// Renders text with a little bullet aligned to the typical tree node #[doc(alias = "BulletText")] - pub fn bullet_text(&self, text: &ImStr) { - unsafe { sys::igBulletText(fmt_ptr(), text.as_ptr()) } + pub fn bullet_text(&self, text: impl AsRef) { + unsafe { sys::igBulletText(fmt_ptr(), self.scratch_txt(text)) } } }