Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions examples/editor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,9 @@ impl Editor {
self.is_dirty.then_some(Message::SaveFile)
),
horizontal_space(),
toggler(
Some("Word Wrap"),
self.word_wrap,
Message::WordWrapToggled
),
toggler(self.word_wrap)
.label("Word Wrap")
.on_toggle(Message::WordWrapToggled),
pick_list(
highlighter::Theme::ALL,
Some(self.theme),
Expand Down
10 changes: 4 additions & 6 deletions examples/styling/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,10 @@ 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(self.toggler_value)
.label("Toggle me!")
.on_toggle(Message::TogglerToggled)
.spacing(10);

let content = column![
choose_theme,
Expand Down
10 changes: 5 additions & 5 deletions examples/tour/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,11 +357,11 @@ 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(self.toggler)
.label("Toggle me to continue...")
.on_toggle(Message::TogglerChanged),
)
.padding([0, 40]),
)
}
Expand Down
4 changes: 1 addition & 3 deletions widget/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,15 +767,13 @@ where
///
/// [`Toggler`]: crate::Toggler
pub fn toggler<'a, Message, Theme, Renderer>(
label: Option<impl text::IntoFragment<'a>>,
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(is_checked)
}

/// Creates a new [`TextInput`].
Expand Down
69 changes: 54 additions & 15 deletions widget/src/toggler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ use crate::core::{
///
/// let is_toggled = true;
///
/// Toggler::new(Some("Toggle me!"), is_toggled, |b| Message::TogglerToggled(b));
/// Toggler::new(is_toggled)
/// .label("Toggle me!")
/// .on_toggle(Message::TogglerToggled);
/// ```
#[allow(missing_debug_implementations)]
pub struct Toggler<
Expand All @@ -39,7 +41,7 @@ pub struct Toggler<
Renderer: text::Renderer,
{
is_toggled: bool,
on_toggle: Box<dyn Fn(bool) -> Message + 'a>,
on_toggle: Option<Box<dyn Fn(bool) -> Message + 'a>>,
label: Option<text::Fragment<'a>>,
width: Length,
size: f32,
Expand Down Expand Up @@ -69,18 +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<F>(
label: Option<impl text::IntoFragment<'a>>,
is_toggled: bool,
f: F,
) -> Self
where
F: 'a + Fn(bool) -> Message,
{
pub fn new(is_toggled: bool) -> Self {
Toggler {
is_toggled,
on_toggle: Box::new(f),
label: label.map(text::IntoFragment::into_fragment),
on_toggle: None,
label: None,
width: Length::Shrink,
size: Self::DEFAULT_SIZE,
text_size: None,
Expand All @@ -94,6 +89,36 @@ 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`].
///
/// 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<impl Fn(bool) -> 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<Pixels>) -> Self {
self.size = size.into().0;
Expand Down Expand Up @@ -244,13 +269,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 {
Expand All @@ -270,7 +299,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()
}
Expand Down Expand Up @@ -314,7 +347,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,
}
Expand Down Expand Up @@ -403,6 +438,8 @@ pub enum Status {
/// Indicates whether the [`Toggler`] is toggled.
is_toggled: bool,
},
/// The [`Toggler`] is disabled.
Disabled,
}

/// The appearance of a toggler.
Expand Down Expand Up @@ -463,6 +500,7 @@ pub fn default(theme: &Theme, status: Status) -> Style {
palette.background.strong.color
}
}
Status::Disabled => palette.background.weak.color,
};

let foreground = match status {
Expand All @@ -483,6 +521,7 @@ pub fn default(theme: &Theme, status: Status) -> Style {
palette.background.weak.color
}
}
Status::Disabled => palette.background.base.color,
};

Style {
Expand Down