diff options
Diffstat (limited to 'widget/src/button.rs')
-rw-r--r-- | widget/src/button.rs | 136 |
1 files changed, 104 insertions, 32 deletions
diff --git a/widget/src/button.rs b/widget/src/button.rs index 552298bb..11839d5e 100644 --- a/widget/src/button.rs +++ b/widget/src/button.rs @@ -17,7 +17,6 @@ //! } //! ``` use crate::core::border::{self, Border}; -use crate::core::event::{self, Event}; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; @@ -26,9 +25,10 @@ use crate::core::theme::palette; use crate::core::touch; use crate::core::widget::tree::{self, Tree}; use crate::core::widget::Operation; +use crate::core::window; use crate::core::{ - Background, Clipboard, Color, Element, Layout, Length, Padding, Rectangle, - Shadow, Shell, Size, Theme, Vector, Widget, + Background, Clipboard, Color, Element, Event, Layout, Length, Padding, + Rectangle, Shadow, Shell, Size, Theme, Vector, Widget, }; /// A generic widget that produces a message when pressed. @@ -81,6 +81,7 @@ where padding: Padding, clip: bool, class: Theme::Class<'a>, + status: Option<Status>, } enum OnPress<'a, Message> { @@ -88,7 +89,7 @@ enum OnPress<'a, Message> { Closure(Box<dyn Fn() -> Message + 'a>), } -impl<'a, Message: Clone> OnPress<'a, Message> { +impl<Message: Clone> OnPress<'_, Message> { fn get(&self) -> Message { match self { OnPress::Direct(message) => message.clone(), @@ -117,6 +118,7 @@ where padding: DEFAULT_PADDING, clip: false, class: Theme::default(), + status: None, } } @@ -270,7 +272,7 @@ where }); } - fn on_event( + fn update( &mut self, tree: &mut Tree, event: Event, @@ -280,8 +282,8 @@ where clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, viewport: &Rectangle, - ) -> event::Status { - if let event::Status::Captured = self.content.as_widget_mut().on_event( + ) { + self.content.as_widget_mut().update( &mut tree.children[0], event.clone(), layout.children().next().unwrap(), @@ -290,8 +292,10 @@ where clipboard, shell, viewport, - ) { - return event::Status::Captured; + ); + + if shell.is_event_captured() { + return; } match event { @@ -305,14 +309,13 @@ where state.is_pressed = true; - return event::Status::Captured; + shell.capture_event(); } } } Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) | Event::Touch(touch::Event::FingerLifted { .. }) => { - if let Some(on_press) = self.on_press.as_ref().map(OnPress::get) - { + if let Some(on_press) = &self.on_press { let state = tree.state.downcast_mut::<State>(); if state.is_pressed { @@ -321,10 +324,10 @@ where let bounds = layout.bounds(); if cursor.is_over(bounds) { - shell.publish(on_press); + shell.publish(on_press.get()); } - return event::Status::Captured; + shell.capture_event(); } } } @@ -336,7 +339,25 @@ where _ => {} } - event::Status::Ignored + let current_status = if self.on_press.is_none() { + Status::Disabled + } else if cursor.is_over(layout.bounds()) { + let state = tree.state.downcast_ref::<State>(); + + if state.is_pressed { + Status::Pressed + } else { + Status::Hovered + } + } else { + Status::Active + }; + + if let Event::Window(window::Event::RedrawRequested(_now)) = event { + self.status = Some(current_status); + } else if self.status.is_some_and(|status| status != current_status) { + shell.request_redraw(); + } } fn draw( @@ -351,23 +372,8 @@ where ) { let bounds = layout.bounds(); let content_layout = layout.children().next().unwrap(); - let is_mouse_over = cursor.is_over(bounds); - - let status = if self.on_press.is_none() { - Status::Disabled - } else if is_mouse_over { - let state = tree.state.downcast_ref::<State>(); - - if state.is_pressed { - Status::Pressed - } else { - Status::Hovered - } - } else { - Status::Active - }; - - let style = theme.style(&self.class, status); + let style = + theme.style(&self.class, self.status.unwrap_or(Status::Disabled)); if style.background.is_some() || style.border.width > 0.0 @@ -471,6 +477,9 @@ pub enum Status { } /// The style of a button. +/// +/// If not specified with [`Button::style`] +/// the theme will provide the style. #[derive(Debug, Clone, Copy, PartialEq)] pub struct Style { /// The [`Background`] of the button. @@ -505,6 +514,54 @@ impl Default for Style { } /// The theme catalog of a [`Button`]. +/// +/// All themes that can be used with [`Button`] +/// must implement this trait. +/// +/// # Example +/// ```no_run +/// # use iced_widget::core::{Color, Background}; +/// # use iced_widget::button::{Catalog, Status, Style}; +/// # struct MyTheme; +/// #[derive(Debug, Default)] +/// pub enum ButtonClass { +/// #[default] +/// Primary, +/// Secondary, +/// Danger +/// } +/// +/// impl Catalog for MyTheme { +/// type Class<'a> = ButtonClass; +/// +/// fn default<'a>() -> Self::Class<'a> { +/// ButtonClass::default() +/// } +/// +/// +/// fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { +/// let mut style = Style::default(); +/// +/// match class { +/// ButtonClass::Primary => { +/// style.background = Some(Background::Color(Color::from_rgb(0.529, 0.808, 0.921))); +/// }, +/// ButtonClass::Secondary => { +/// style.background = Some(Background::Color(Color::WHITE)); +/// }, +/// ButtonClass::Danger => { +/// style.background = Some(Background::Color(Color::from_rgb(0.941, 0.502, 0.502))); +/// }, +/// } +/// +/// style +/// } +/// } +/// ``` +/// +/// Although, in order to use [`Button::style`] +/// with `MyTheme`, [`Catalog::Class`] must implement +/// `From<StyleFn<'_, MyTheme>>`. pub trait Catalog { /// The item class of the [`Catalog`]. type Class<'a>; @@ -576,6 +633,21 @@ pub fn success(theme: &Theme, status: Status) -> Style { } } +/// A warning button; denoting a risky action. +pub fn warning(theme: &Theme, status: Status) -> Style { + let palette = theme.extended_palette(); + let base = styled(palette.warning.base); + + match status { + Status::Active | Status::Pressed => base, + Status::Hovered => Style { + background: Some(Background::Color(palette.warning.strong.color)), + ..base + }, + Status::Disabled => disabled(base), + } +} + /// A danger button; denoting a destructive action. pub fn danger(theme: &Theme, status: Status) -> Style { let palette = theme.extended_palette(); |