From c741688b4c52dd2397880ca05b5f9a997d762246 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 11 Sep 2024 00:17:16 +0200 Subject: Add disabled state and `on_toggle` handler to `Toggler` Co-authored-by: Your Name here only --- examples/editor/src/main.rs | 7 ++---- examples/styling/src/main.rs | 9 +++---- examples/tour/src/main.rs | 9 +++---- widget/src/helpers.rs | 3 +-- widget/src/toggler.rs | 59 +++++++++++++++++++++++++++++++++++--------- 5 files changed, 57 insertions(+), 30 deletions(-) diff --git a/examples/editor/src/main.rs b/examples/editor/src/main.rs index 068782ba..c7d7eb26 100644 --- a/examples/editor/src/main.rs +++ b/examples/editor/src/main.rs @@ -150,11 +150,8 @@ impl Editor { self.is_dirty.then_some(Message::SaveFile) ), horizontal_space(), - toggler( - Some("Word Wrap"), - self.word_wrap, - Message::WordWrapToggled - ), + toggler(Some("Word Wrap"), self.word_wrap) + .on_toggle(Message::WordWrapToggled), pick_list( highlighter::Theme::ALL, Some(self.theme), diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs index e19d5cf7..222ab79d 100644 --- a/examples/styling/src/main.rs +++ b/examples/styling/src/main.rs @@ -77,12 +77,9 @@ impl Styling { let checkbox = checkbox("Check me!", self.checkbox_value) .on_toggle(Message::CheckboxToggled); - let toggler = toggler( - Some("Toggle me!"), - self.toggler_value, - Message::TogglerToggled, - ) - .spacing(10); + let toggler = toggler(Some("Toggle me!"), self.toggler_value) + .on_toggle(Message::TogglerToggled) + .spacing(10); let content = column![ choose_theme, diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs index 0dd588fe..fad5f0b1 100644 --- a/examples/tour/src/main.rs +++ b/examples/tour/src/main.rs @@ -357,11 +357,10 @@ impl Tour { Self::container("Toggler") .push("A toggler is mostly used to enable or disable something.") .push( - Container::new(toggler( - Some("Toggle me to continue..."), - self.toggler, - Message::TogglerChanged, - )) + Container::new( + toggler(Some("Toggle me to continue..."), self.toggler) + .on_toggle(Message::TogglerChanged), + ) .padding([0, 40]), ) } diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 349f02a6..e48ba328 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -769,13 +769,12 @@ where pub fn toggler<'a, Message, Theme, Renderer>( label: Option>, is_checked: bool, - f: impl Fn(bool) -> Message + 'a, ) -> Toggler<'a, Message, Theme, Renderer> where Theme: toggler::Catalog + 'a, Renderer: core::text::Renderer, { - Toggler::new(label, is_checked, f) + Toggler::new(label, is_checked) } /// Creates a new [`TextInput`]. diff --git a/widget/src/toggler.rs b/widget/src/toggler.rs index 57e142e8..a6b2ae92 100644 --- a/widget/src/toggler.rs +++ b/widget/src/toggler.rs @@ -26,7 +26,8 @@ use crate::core::{ /// /// let is_toggled = true; /// -/// Toggler::new(Some("Toggle me!"), is_toggled, |b| Message::TogglerToggled(b)); +/// Toggler::new(Some("Toggle me!"), is_toggled) +/// .on_toggle(Message::TogglerToggled); /// ``` #[allow(missing_debug_implementations)] pub struct Toggler< @@ -39,7 +40,7 @@ pub struct Toggler< Renderer: text::Renderer, { is_toggled: bool, - on_toggle: Box Message + 'a>, + on_toggle: Option Message + 'a>>, label: Option>, width: Length, size: f32, @@ -69,17 +70,13 @@ where /// * a function that will be called when the [`Toggler`] is toggled. It /// will receive the new state of the [`Toggler`] and must produce a /// `Message`. - pub fn new( + pub fn new( label: Option>, is_toggled: bool, - f: F, - ) -> Self - where - F: 'a + Fn(bool) -> Message, - { + ) -> Self { Toggler { is_toggled, - on_toggle: Box::new(f), + on_toggle: None, label: label.map(text::IntoFragment::into_fragment), width: Length::Shrink, size: Self::DEFAULT_SIZE, @@ -94,6 +91,30 @@ where } } + /// Sets the message that should be produced when a user toggles + /// the [`Toggler`]. + /// + /// If this method is not called, the [`Toggler`] will be disabled. + pub fn on_toggle( + mut self, + on_toggle: impl Fn(bool) -> Message + 'a, + ) -> Self { + self.on_toggle = Some(Box::new(on_toggle)); + self + } + + /// Sets the message that should be produced when a user toggles + /// the [`Toggler`], if `Some`. + /// + /// If `None`, the [`Toggler`] will be disabled. + pub fn on_toggle_maybe( + mut self, + on_toggle: Option Message + 'a>, + ) -> Self { + self.on_toggle = on_toggle.map(|on_toggle| Box::new(on_toggle) as _); + self + } + /// Sets the size of the [`Toggler`]. pub fn size(mut self, size: impl Into) -> Self { self.size = size.into().0; @@ -244,13 +265,17 @@ where shell: &mut Shell<'_, Message>, _viewport: &Rectangle, ) -> event::Status { + let Some(on_toggle) = &self.on_toggle else { + return event::Status::Ignored; + }; + match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) | Event::Touch(touch::Event::FingerPressed { .. }) => { let mouse_over = cursor.is_over(layout.bounds()); if mouse_over { - shell.publish((self.on_toggle)(!self.is_toggled)); + shell.publish(on_toggle(!self.is_toggled)); event::Status::Captured } else { @@ -270,7 +295,11 @@ where _renderer: &Renderer, ) -> mouse::Interaction { if cursor.is_over(layout.bounds()) { - mouse::Interaction::Pointer + if self.on_toggle.is_some() { + mouse::Interaction::Pointer + } else { + mouse::Interaction::NotAllowed + } } else { mouse::Interaction::default() } @@ -314,7 +343,9 @@ where let bounds = toggler_layout.bounds(); let is_mouse_over = cursor.is_over(layout.bounds()); - let status = if is_mouse_over { + let status = if self.on_toggle.is_none() { + Status::Disabled + } else if is_mouse_over { Status::Hovered { is_toggled: self.is_toggled, } @@ -403,6 +434,8 @@ pub enum Status { /// Indicates whether the [`Toggler`] is toggled. is_toggled: bool, }, + /// The [`Toggler`] is disabled. + Disabled, } /// The appearance of a toggler. @@ -463,6 +496,7 @@ pub fn default(theme: &Theme, status: Status) -> Style { palette.background.strong.color } } + Status::Disabled => palette.background.weak.color, }; let foreground = match status { @@ -483,6 +517,7 @@ pub fn default(theme: &Theme, status: Status) -> Style { palette.background.weak.color } } + Status::Disabled => palette.background.base.color, }; Style { -- cgit From 6e4970c01a9e42621a0ded340dcdccb4204ab5d2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 11 Sep 2024 00:20:23 +0200 Subject: Add `label` method to `Toggler` --- examples/editor/src/main.rs | 3 ++- examples/styling/src/main.rs | 3 ++- examples/tour/src/main.rs | 3 ++- widget/src/helpers.rs | 3 +-- widget/src/toggler.rs | 16 ++++++++++------ 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/examples/editor/src/main.rs b/examples/editor/src/main.rs index c7d7eb26..d55f9bdf 100644 --- a/examples/editor/src/main.rs +++ b/examples/editor/src/main.rs @@ -150,7 +150,8 @@ impl Editor { self.is_dirty.then_some(Message::SaveFile) ), horizontal_space(), - toggler(Some("Word Wrap"), self.word_wrap) + toggler(self.word_wrap) + .label("Word Wrap") .on_toggle(Message::WordWrapToggled), pick_list( highlighter::Theme::ALL, diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs index 222ab79d..534f5e32 100644 --- a/examples/styling/src/main.rs +++ b/examples/styling/src/main.rs @@ -77,7 +77,8 @@ impl Styling { let checkbox = checkbox("Check me!", self.checkbox_value) .on_toggle(Message::CheckboxToggled); - let toggler = toggler(Some("Toggle me!"), self.toggler_value) + let toggler = toggler(self.toggler_value) + .label("Toggle me!") .on_toggle(Message::TogglerToggled) .spacing(10); diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs index fad5f0b1..d8c0b29a 100644 --- a/examples/tour/src/main.rs +++ b/examples/tour/src/main.rs @@ -358,7 +358,8 @@ impl Tour { .push("A toggler is mostly used to enable or disable something.") .push( Container::new( - toggler(Some("Toggle me to continue..."), self.toggler) + toggler(self.toggler) + .label("Toggle me to continue...") .on_toggle(Message::TogglerChanged), ) .padding([0, 40]), diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index e48ba328..51978823 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -767,14 +767,13 @@ where /// /// [`Toggler`]: crate::Toggler pub fn toggler<'a, Message, Theme, Renderer>( - label: Option>, is_checked: bool, ) -> Toggler<'a, Message, Theme, Renderer> where Theme: toggler::Catalog + 'a, Renderer: core::text::Renderer, { - Toggler::new(label, is_checked) + Toggler::new(is_checked) } /// Creates a new [`TextInput`]. diff --git a/widget/src/toggler.rs b/widget/src/toggler.rs index a6b2ae92..1c425dc1 100644 --- a/widget/src/toggler.rs +++ b/widget/src/toggler.rs @@ -26,7 +26,8 @@ use crate::core::{ /// /// let is_toggled = true; /// -/// Toggler::new(Some("Toggle me!"), is_toggled) +/// Toggler::new(is_toggled) +/// .label("Toggle me!") /// .on_toggle(Message::TogglerToggled); /// ``` #[allow(missing_debug_implementations)] @@ -70,14 +71,11 @@ where /// * a function that will be called when the [`Toggler`] is toggled. It /// will receive the new state of the [`Toggler`] and must produce a /// `Message`. - pub fn new( - label: Option>, - is_toggled: bool, - ) -> Self { + pub fn new(is_toggled: bool) -> Self { Toggler { is_toggled, on_toggle: None, - label: label.map(text::IntoFragment::into_fragment), + label: None, width: Length::Shrink, size: Self::DEFAULT_SIZE, text_size: None, @@ -91,6 +89,12 @@ where } } + /// Sets the label of the [`Toggler`]. + pub fn label(mut self, label: impl text::IntoFragment<'a>) -> Self { + self.label = Some(label.into_fragment()); + self + } + /// Sets the message that should be produced when a user toggles /// the [`Toggler`]. /// -- cgit