diff options
Diffstat (limited to 'widget')
| -rw-r--r-- | widget/src/button.rs | 44 | ||||
| -rw-r--r-- | widget/src/checkbox.rs | 40 | ||||
| -rw-r--r-- | widget/src/combo_box.rs | 15 | ||||
| -rw-r--r-- | widget/src/container.rs | 67 | ||||
| -rw-r--r-- | widget/src/helpers.rs | 51 | ||||
| -rw-r--r-- | widget/src/overlay/menu.rs | 36 | ||||
| -rw-r--r-- | widget/src/pane_grid.rs | 36 | ||||
| -rw-r--r-- | widget/src/pane_grid/content.rs | 12 | ||||
| -rw-r--r-- | widget/src/pane_grid/title_bar.rs | 15 | ||||
| -rw-r--r-- | widget/src/pick_list.rs | 5 | ||||
| -rw-r--r-- | widget/src/progress_bar.rs | 36 | ||||
| -rw-r--r-- | widget/src/qr_code.rs | 36 | ||||
| -rw-r--r-- | widget/src/radio.rs | 36 | ||||
| -rw-r--r-- | widget/src/rule.rs | 40 | ||||
| -rw-r--r-- | widget/src/scrollable.rs | 47 | ||||
| -rw-r--r-- | widget/src/slider.rs | 36 | ||||
| -rw-r--r-- | widget/src/svg.rs | 2 | ||||
| -rw-r--r-- | widget/src/text_editor.rs | 36 | ||||
| -rw-r--r-- | widget/src/text_input.rs | 53 | ||||
| -rw-r--r-- | widget/src/toggler.rs | 34 | ||||
| -rw-r--r-- | widget/src/tooltip.rs | 12 | ||||
| -rw-r--r-- | widget/src/vertical_slider.rs | 13 | 
22 files changed, 449 insertions, 253 deletions
| diff --git a/widget/src/button.rs b/widget/src/button.rs index 798a8206..b5786baa 100644 --- a/widget/src/button.rs +++ b/widget/src/button.rs @@ -53,7 +53,6 @@ use crate::style::Theme;  #[allow(missing_debug_implementations)]  pub struct Button<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>  where -    Theme: Style,      Renderer: crate::core::Renderer,  {      content: Element<'a, Message, Theme, Renderer>, @@ -62,18 +61,20 @@ where      height: Length,      padding: Padding,      clip: bool, -    style: fn(&Theme, Status) -> Appearance, +    style: Style<Theme>,  }  impl<'a, Message, Theme, Renderer> Button<'a, Message, Theme, Renderer>  where -    Theme: Style,      Renderer: crate::core::Renderer,  {      /// Creates a new [`Button`] with the given content.      pub fn new(          content: impl Into<Element<'a, Message, Theme, Renderer>>, -    ) -> Self { +    ) -> Self +    where +        Style<Theme>: Default, +    {          let content = content.into();          let size = content.as_widget().size_hint(); @@ -84,7 +85,7 @@ where              height: size.height.fluid(),              padding: Padding::new(5.0),              clip: false, -            style: Theme::DEFAULT, +            style: Style::default(),          }      } @@ -125,7 +126,7 @@ where      /// Sets the style variant of this [`Button`].      pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self { -        self.style = style.into(); +        self.style = Style(style);          self      } @@ -146,7 +147,6 @@ impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>      for Button<'a, Message, Theme, Renderer>  where      Message: 'a + Clone, -    Theme: Style,      Renderer: 'a + crate::core::Renderer,  {      fn tag(&self) -> tree::Tag { @@ -306,7 +306,7 @@ where              Status::Active          }; -        let styling = (self.style)(theme, status); +        let styling = (self.style.0)(theme, status);          if styling.background.is_some()              || styling.border.width > 0.0 @@ -380,7 +380,7 @@ impl<'a, Message, Theme, Renderer> From<Button<'a, Message, Theme, Renderer>>      for Element<'a, Message, Theme, Renderer>  where      Message: Clone + 'a, -    Theme: Style + 'a, +    Theme: 'a,      Renderer: crate::core::Renderer + 'a,  {      fn from(button: Button<'a, Message, Theme, Renderer>) -> Self { @@ -428,14 +428,28 @@ impl std::default::Default for Appearance {      }  } -/// The default style of a [`Button`] for a given theme. -pub trait Style { -    /// The default style. -    const DEFAULT: fn(&Self, Status) -> Appearance; +/// The style of a [`Button`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme, Status) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(primary) +    }  } -impl Style for Theme { -    const DEFAULT: fn(&Self, Status) -> Appearance = primary; +impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme, Status) -> Appearance) -> Self { +        Style(f) +    }  }  /// A primary button; denoting a main action. diff --git a/widget/src/checkbox.rs b/widget/src/checkbox.rs index 91838291..e4fc2232 100644 --- a/widget/src/checkbox.rs +++ b/widget/src/checkbox.rs @@ -53,13 +53,12 @@ pub struct Checkbox<      text_shaping: text::Shaping,      font: Option<Renderer::Font>,      icon: Icon<Renderer::Font>, -    style: fn(&Theme, Status) -> Appearance, +    style: Style<Theme>,  }  impl<'a, Message, Theme, Renderer> Checkbox<'a, Message, Theme, Renderer>  where      Renderer: text::Renderer, -    Theme: Style,  {      /// The default size of a [`Checkbox`].      const DEFAULT_SIZE: f32 = 15.0; @@ -72,7 +71,10 @@ where      /// It expects:      ///   * the label of the [`Checkbox`]      ///   * a boolean describing whether the [`Checkbox`] is checked or not -    pub fn new(label: impl Into<String>, is_checked: bool) -> Self { +    pub fn new(label: impl Into<String>, is_checked: bool) -> Self +    where +        Style<Theme>: Default, +    {          Checkbox {              is_checked,              on_toggle: None, @@ -91,7 +93,7 @@ where                  line_height: text::LineHeight::default(),                  shaping: text::Shaping::Basic,              }, -            style: Theme::style(), +            style: Style::default(),          }      } @@ -175,7 +177,7 @@ where      /// Sets the style of the [`Checkbox`].      pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self { -        self.style = style.into(); +        self.style = Style(style);          self      }  } @@ -301,7 +303,7 @@ where              Status::Active { is_checked }          }; -        let appearance = (self.style)(theme, status); +        let appearance = (self.style.0)(theme, status);          {              let layout = children.next().unwrap(); @@ -423,15 +425,27 @@ pub struct Appearance {      pub text_color: Option<Color>,  } -/// A set of rules that dictate the style of a checkbox. -pub trait Style { -    /// The supported style of the [`StyleSheet`]. -    fn style() -> fn(&Self, Status) -> Appearance; +/// The style of a [`Checkbox`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme, Status) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(primary) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self, Status) -> Appearance { -        primary +impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme, Status) -> Appearance) -> Self { +        Style(f)      }  } diff --git a/widget/src/combo_box.rs b/widget/src/combo_box.rs index 533daab2..1140f1c6 100644 --- a/widget/src/combo_box.rs +++ b/widget/src/combo_box.rs @@ -1,5 +1,4 @@  //! Display a dropdown list of searchable and selectable options. -use crate::container;  use crate::core::event::{self, Event};  use crate::core::keyboard;  use crate::core::keyboard::key; @@ -14,7 +13,6 @@ use crate::core::{      Clipboard, Element, Length, Padding, Rectangle, Shell, Size, Vector,  };  use crate::overlay::menu; -use crate::scrollable;  use crate::style::Theme;  use crate::text::LineHeight;  use crate::text_input::{self, TextInput}; @@ -65,14 +63,16 @@ where          on_selected: impl Fn(T) -> Message + 'static,      ) -> Self      where -        Theme: text_input::Style,          Style<Theme>: Default,      {          let style = Style::<Theme>::default(); -        let text_input = TextInput::new(placeholder, &state.value()) -            .on_input(TextInputEvent::TextChanged) -            .style(style.text_input); +        let text_input = TextInput::with_style( +            placeholder, +            &state.value(), +            style.text_input, +        ) +        .on_input(TextInputEvent::TextChanged);          let selection = selection.map(T::to_string).unwrap_or_default(); @@ -294,7 +294,6 @@ impl<'a, T, Message, Theme, Renderer> Widget<Message, Theme, Renderer>  where      T: Display + Clone + 'static,      Message: Clone, -    Theme: scrollable::Style + container::Style,      Renderer: text::Renderer,  {      fn size(&self) -> Size<Length> { @@ -711,7 +710,7 @@ impl<'a, T, Message, Theme, Renderer>  where      T: Display + Clone + 'static,      Message: Clone + 'a, -    Theme: scrollable::Style + container::Style + 'a, +    Theme: 'a,      Renderer: text::Renderer + 'a,  {      fn from(combo_box: ComboBox<'a, T, Message, Theme, Renderer>) -> Self { diff --git a/widget/src/container.rs b/widget/src/container.rs index 58a24339..97b481a2 100644 --- a/widget/src/container.rs +++ b/widget/src/container.rs @@ -34,21 +34,30 @@ pub struct Container<      max_height: f32,      horizontal_alignment: alignment::Horizontal,      vertical_alignment: alignment::Vertical, -    style: fn(&Theme, Status) -> Appearance,      clip: bool,      content: Element<'a, Message, Theme, Renderer>, +    style: Style<Theme>,  }  impl<'a, Message, Theme, Renderer> Container<'a, Message, Theme, Renderer>  where      Renderer: crate::core::Renderer,  { -    /// Creates an empty [`Container`]. -    pub fn new<T>(content: T) -> Self +    /// Creates a [`Container`] with the given content. +    pub fn new( +        content: impl Into<Element<'a, Message, Theme, Renderer>>, +    ) -> Self      where -        Theme: Style, -        T: Into<Element<'a, Message, Theme, Renderer>>, +        Style<Theme>: Default,      { +        Self::with_style(content, Style::default().0) +    } + +    /// Creates a [`Container`] with the given content and style. +    pub fn with_style( +        content: impl Into<Element<'a, Message, Theme, Renderer>>, +        style: fn(&Theme, Status) -> Appearance, +    ) -> Self {          let content = content.into();          let size = content.as_widget().size_hint(); @@ -61,9 +70,9 @@ where              max_height: f32::INFINITY,              horizontal_alignment: alignment::Horizontal::Left,              vertical_alignment: alignment::Vertical::Top, -            style: Theme::style(),              clip: false,              content, +            style: Style(style),          }      } @@ -129,7 +138,7 @@ where      /// Sets the style of the [`Container`].      pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self { -        self.style = style; +        self.style = Style(style);          self      } @@ -267,7 +276,7 @@ where              Status::Idle          }; -        let style = (self.style)(theme, status); +        let style = (self.style.0)(theme, status);          if let Some(clipped_viewport) = bounds.intersection(viewport) {              draw_background(renderer, &style, bounds); @@ -537,26 +546,46 @@ pub enum Status {      Hovered,  } -/// The style of a [`Container`] for a theme. -pub trait Style { -    /// The default style of a [`Container`]. -    fn style() -> fn(&Self, Status) -> Appearance; +/// The style of a [`Container`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme, Status) -> Appearance); + +impl<Theme> Style<Theme> { +    /// Resolves the [`Style`] with the given `Theme` and [`Status`] to +    /// produce an [`Appearance`]. +    pub fn resolve(self, theme: &Theme, status: Status) -> Appearance { +        (self.0)(theme, status) +    } +} + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(transparent) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self, Status) -> Appearance { -        transparent +impl Default for Style<Appearance> { +    fn default() -> Self { +        Style(|appearance, _status| *appearance)      }  } -impl Style for Appearance { -    fn style() -> fn(&Self, Status) -> Appearance { -        |appearance, _status| *appearance +impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme, Status) -> Appearance) -> Self { +        Style(f)      }  }  /// A transparent [`Container`]. -pub fn transparent(_theme: &Theme, _status: Status) -> Appearance { +pub fn transparent<Theme>(_theme: &Theme, _status: Status) -> Appearance {      Appearance::default()  } diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index f63306c4..fdc9462d 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -14,7 +14,7 @@ use crate::rule::{self, Rule};  use crate::runtime::Command;  use crate::scrollable::{self, Scrollable};  use crate::slider::{self, Slider}; -use crate::text::{self, Text}; +use crate::text::Text;  use crate::text_editor::{self, TextEditor};  use crate::text_input::{self, TextInput};  use crate::toggler::{self, Toggler}; @@ -58,8 +58,8 @@ pub fn container<'a, Message, Theme, Renderer>(      content: impl Into<Element<'a, Message, Theme, Renderer>>,  ) -> Container<'a, Message, Theme, Renderer>  where -    Theme: container::Style,      Renderer: core::Renderer, +    container::Style<Theme>: Default,  {      Container::new(content)  } @@ -104,8 +104,8 @@ pub fn scrollable<'a, Message, Theme, Renderer>(      content: impl Into<Element<'a, Message, Theme, Renderer>>,  ) -> Scrollable<'a, Message, Theme, Renderer>  where -    Theme: scrollable::Style,      Renderer: core::Renderer, +    scrollable::Style<Theme>: Default,  {      Scrollable::new(content)  } @@ -118,7 +118,7 @@ pub fn button<'a, Message, Theme, Renderer>(  ) -> Button<'a, Message, Theme, Renderer>  where      Renderer: core::Renderer, -    Theme: button::Style, +    button::Style<Theme>: Default,  {      Button::new(content)  } @@ -134,8 +134,8 @@ pub fn tooltip<'a, Message, Theme, Renderer>(      position: tooltip::Position,  ) -> crate::Tooltip<'a, Message, Theme, Renderer>  where -    Theme: container::Style + text::StyleSheet,      Renderer: core::text::Renderer, +    container::Style<Theme>: Default,  {      Tooltip::new(content, tooltip, position)  } @@ -147,7 +147,6 @@ pub fn text<'a, Theme, Renderer>(      text: impl ToString,  ) -> Text<'a, Theme, Renderer>  where -    Theme: text::StyleSheet,      Renderer: core::text::Renderer,  {      Text::new(text.to_string()) @@ -161,8 +160,8 @@ pub fn checkbox<'a, Message, Theme, Renderer>(      is_checked: bool,  ) -> Checkbox<'a, Message, Theme, Renderer>  where -    Theme: checkbox::Style,      Renderer: core::text::Renderer, +    checkbox::Style<Theme>: Default,  {      Checkbox::new(label, is_checked)  } @@ -178,9 +177,9 @@ pub fn radio<Message, Theme, Renderer, V>(  ) -> Radio<Message, Theme, Renderer>  where      Message: Clone, -    Theme: radio::Style,      Renderer: core::text::Renderer,      V: Copy + Eq, +    radio::Style<Theme>: Default,  {      Radio::new(label, value, selected, on_click)  } @@ -195,7 +194,7 @@ pub fn toggler<'a, Message, Theme, Renderer>(  ) -> Toggler<'a, Message, Theme, Renderer>  where      Renderer: core::text::Renderer, -    Theme: toggler::Style, +    toggler::Style<Theme>: Default,  {      Toggler::new(label, is_checked, f)  } @@ -209,8 +208,8 @@ pub fn text_input<'a, Message, Theme, Renderer>(  ) -> TextInput<'a, Message, Theme, Renderer>  where      Message: Clone, -    Theme: text_input::Style,      Renderer: core::text::Renderer, +    text_input::Style<Theme>: Default,  {      TextInput::new(placeholder, value)  } @@ -223,8 +222,8 @@ pub fn text_editor<Message, Theme, Renderer>(  ) -> TextEditor<'_, core::text::highlighter::PlainText, Message, Theme, Renderer>  where      Message: Clone, -    Theme: text_editor::Style,      Renderer: core::text::Renderer, +    text_editor::Style<Theme>: Default,  {      TextEditor::new(content)  } @@ -240,7 +239,7 @@ pub fn slider<'a, T, Message, Theme>(  where      T: Copy + From<u8> + std::cmp::PartialOrd,      Message: Clone, -    Theme: slider::Style, +    slider::Style<Theme>: Default,  {      Slider::new(range, value, on_change)  } @@ -256,7 +255,7 @@ pub fn vertical_slider<'a, T, Message, Theme>(  where      T: Copy + From<u8> + std::cmp::PartialOrd,      Message: Clone, -    Theme: vertical_slider::Style, +    vertical_slider::Style<Theme>: Default,  {      VerticalSlider::new(range, value, on_change)  } @@ -291,7 +290,6 @@ pub fn combo_box<'a, T, Message, Theme, Renderer>(  ) -> ComboBox<'a, T, Message, Theme, Renderer>  where      T: std::fmt::Display + Clone, -    Theme: text_input::Style,      Renderer: core::text::Renderer,      combo_box::Style<Theme>: Default,  { @@ -319,7 +317,7 @@ pub fn vertical_space() -> Space {  /// [`Rule`]: crate::Rule  pub fn horizontal_rule<Theme>(height: impl Into<Pixels>) -> Rule<Theme>  where -    Theme: rule::Style, +    rule::Style<Theme>: Default,  {      Rule::horizontal(height)  } @@ -329,7 +327,7 @@ where  /// [`Rule`]: crate::Rule  pub fn vertical_rule<Theme>(width: impl Into<Pixels>) -> Rule<Theme>  where -    Theme: rule::Style, +    rule::Style<Theme>: Default,  {      Rule::vertical(width)  } @@ -346,7 +344,7 @@ pub fn progress_bar<Theme>(      value: f32,  ) -> ProgressBar<Theme>  where -    Theme: progress_bar::Style, +    progress_bar::Style<Theme>: Default,  {      ProgressBar::new(range, value)  } @@ -392,7 +390,7 @@ where  #[cfg(feature = "qr_code")]  pub fn qr_code<Theme>(data: &crate::qr_code::Data) -> crate::QRCode<'_, Theme>  where -    Theme: crate::qr_code::Style, +    crate::qr_code::Style<Theme>: Default,  {      crate::QRCode::new(data)  } @@ -435,13 +433,20 @@ where  }  /// A widget that applies any `Theme` to its contents. -pub fn themer<'a, Message, OldTheme, NewTheme, F, Renderer>( -    to_theme: F, +pub fn themer<'a, Message, OldTheme, NewTheme, Renderer>( +    new_theme: NewTheme,      content: impl Into<Element<'a, Message, NewTheme, Renderer>>, -) -> Themer<'a, Message, OldTheme, NewTheme, F, Renderer> +) -> Themer< +    'a, +    Message, +    OldTheme, +    NewTheme, +    impl Fn(&OldTheme) -> NewTheme, +    Renderer, +>  where -    F: Fn(&OldTheme) -> NewTheme,      Renderer: core::Renderer, +    NewTheme: Clone,  { -    Themer::new(to_theme, content) +    Themer::new(move |_| new_theme.clone(), content)  } diff --git a/widget/src/overlay/menu.rs b/widget/src/overlay/menu.rs index bb8ad0e0..e0887e59 100644 --- a/widget/src/overlay/menu.rs +++ b/widget/src/overlay/menu.rs @@ -46,7 +46,7 @@ impl<'a, T, Message, Theme, Renderer> Menu<'a, T, Message, Theme, Renderer>  where      T: ToString + Clone,      Message: 'a, -    Theme: container::Style + scrollable::Style + 'a, +    Theme: 'a,      Renderer: text::Renderer + 'a,  {      /// Creates a new [`Menu`] with the given [`State`], a list of options, and @@ -197,7 +197,7 @@ where  impl<'a, Message, Theme, Renderer> Overlay<'a, Message, Theme, Renderer>  where      Message: 'a, -    Theme: container::Style + scrollable::Style + 'a, +    Theme: 'a,      Renderer: text::Renderer + 'a,  {      pub fn new<T>( @@ -223,20 +223,24 @@ where              style,          } = menu; -        let container = Container::new( -            Scrollable::new(List { -                options, -                hovered_option, -                on_selected, -                on_option_hovered, -                font, -                text_size, -                text_line_height, -                text_shaping, -                padding, -                style: style.menu, -            }) -            .style(style.scrollable), +        let container = Container::with_style( +            Scrollable::with_direction_and_style( +                List { +                    options, +                    hovered_option, +                    on_selected, +                    on_option_hovered, +                    font, +                    text_size, +                    text_line_height, +                    text_shaping, +                    padding, +                    style: style.menu, +                }, +                scrollable::Direction::default(), +                style.scrollable, +            ), +            container::transparent,          );          state.tree.diff(&container as &dyn Widget<_, _, _>); diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs index 62067e66..ae9cd825 100644 --- a/widget/src/pane_grid.rs +++ b/widget/src/pane_grid.rs @@ -112,7 +112,7 @@ pub struct PaneGrid<      on_click: Option<Box<dyn Fn(Pane) -> Message + 'a>>,      on_drag: Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,      on_resize: Option<(f32, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>, -    style: fn(&Theme) -> Appearance, +    style: Style<Theme>,  }  impl<'a, Message, Theme, Renderer> PaneGrid<'a, Message, Theme, Renderer> @@ -128,7 +128,7 @@ where          view: impl Fn(Pane, &'a T, bool) -> Content<'a, Message, Theme, Renderer>,      ) -> Self      where -        Theme: Style, +        Style<Theme>: Default,      {          let contents = if let Some((pane, pane_state)) =              state.maximized.and_then(|pane| { @@ -160,7 +160,7 @@ where              on_click: None,              on_drag: None,              on_resize: None, -            style: Theme::style(), +            style: Style::default(),          }      } @@ -221,7 +221,7 @@ where      /// Sets the style of the [`PaneGrid`].      pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self { -        self.style = style; +        self.style = Style(style);          self      } @@ -679,7 +679,7 @@ where              None          }; -        let appearance = (self.style)(theme); +        let appearance = (self.style.0)(theme);          for ((id, (content, tree)), pane_layout) in              contents.zip(layout.children()) @@ -1147,15 +1147,27 @@ pub struct Line {      pub width: f32,  } -/// The definiton of the default style of a [`PaneGrid`]. -pub trait Style { -    /// Returns the default style of a [`PaneGrid`]. -    fn style() -> fn(&Self) -> Appearance; +/// The style of a [`PaneGrid`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(default) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self) -> Appearance { -        default +impl<Theme> From<fn(&Theme) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme) -> Appearance) -> Self { +        Style(f)      }  } diff --git a/widget/src/pane_grid/content.rs b/widget/src/pane_grid/content.rs index 25b64e17..ce29e8d0 100644 --- a/widget/src/pane_grid/content.rs +++ b/widget/src/pane_grid/content.rs @@ -24,7 +24,7 @@ pub struct Content<  {      title_bar: Option<TitleBar<'a, Message, Theme, Renderer>>,      body: Element<'a, Message, Theme, Renderer>, -    style: fn(&Theme, container::Status) -> container::Appearance, +    style: container::Style<Theme>,  }  impl<'a, Message, Theme, Renderer> Content<'a, Message, Theme, Renderer> @@ -34,12 +34,12 @@ where      /// Creates a new [`Content`] with the provided body.      pub fn new(body: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self      where -        Theme: container::Style, +        container::Style<Theme>: Default,      {          Self {              title_bar: None,              body: body.into(), -            style: Theme::style(), +            style: container::Style::default(),          }      } @@ -57,7 +57,7 @@ where          mut self,          style: fn(&Theme, container::Status) -> container::Appearance,      ) -> Self { -        self.style = style; +        self.style = style.into();          self      }  } @@ -114,7 +114,7 @@ where                      container::Status::Idle                  }; -                (self.style)(theme, status) +                self.style.resolve(theme, status)              };              container::draw_background(renderer, &style, bounds); @@ -403,8 +403,8 @@ impl<'a, T, Message, Theme, Renderer> From<T>      for Content<'a, Message, Theme, Renderer>  where      T: Into<Element<'a, Message, Theme, Renderer>>, -    Theme: container::Style,      Renderer: crate::core::Renderer, +    container::Style<Theme>: Default,  {      fn from(element: T) -> Self {          Self::new(element) diff --git a/widget/src/pane_grid/title_bar.rs b/widget/src/pane_grid/title_bar.rs index 787510cc..b1cdcde3 100644 --- a/widget/src/pane_grid/title_bar.rs +++ b/widget/src/pane_grid/title_bar.rs @@ -25,7 +25,7 @@ pub struct TitleBar<      controls: Option<Element<'a, Message, Theme, Renderer>>,      padding: Padding,      always_show_controls: bool, -    style: fn(&Theme, container::Status) -> container::Appearance, +    style: container::Style<Theme>,  }  impl<'a, Message, Theme, Renderer> TitleBar<'a, Message, Theme, Renderer> @@ -33,17 +33,18 @@ where      Renderer: crate::core::Renderer,  {      /// Creates a new [`TitleBar`] with the given content. -    pub fn new<E>(content: E) -> Self +    pub fn new( +        content: impl Into<Element<'a, Message, Theme, Renderer>>, +    ) -> Self      where -        Theme: container::Style, -        E: Into<Element<'a, Message, Theme, Renderer>>, +        container::Style<Theme>: Default,      {          Self {              content: content.into(),              controls: None,              padding: Padding::ZERO,              always_show_controls: false, -            style: Theme::style(), +            style: container::Style::default(),          }      } @@ -67,7 +68,7 @@ where          mut self,          style: fn(&Theme, container::Status) -> container::Appearance,      ) -> Self { -        self.style = style; +        self.style = style.into();          self      } @@ -137,7 +138,7 @@ where                  container::Status::Idle              }; -            (self.style)(theme, status) +            self.style.resolve(theme, status)          };          let inherited_style = renderer::Style { diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs index 546bf294..49daa89c 100644 --- a/widget/src/pick_list.rs +++ b/widget/src/pick_list.rs @@ -1,5 +1,4 @@  //! Display a dropdown list of selectable values. -use crate::container;  use crate::core::alignment;  use crate::core::event::{self, Event};  use crate::core::keyboard; @@ -15,7 +14,6 @@ use crate::core::{      Pixels, Point, Rectangle, Shell, Size, Vector, Widget,  };  use crate::overlay::menu::{self, Menu}; -use crate::scrollable;  use crate::style::Theme;  use std::borrow::Borrow; @@ -169,7 +167,6 @@ where      L: Borrow<[T]>,      V: Borrow<T>,      Message: Clone + 'a, -    Theme: scrollable::Style + container::Style,      Renderer: text::Renderer + 'a,  {      fn tag(&self) -> tree::Tag { @@ -426,7 +423,7 @@ where      L: Borrow<[T]> + 'a,      V: Borrow<T> + 'a,      Message: Clone + 'a, -    Theme: scrollable::Style + container::Style + 'a, +    Theme: 'a,      Renderer: text::Renderer + 'a,  {      fn from( diff --git a/widget/src/progress_bar.rs b/widget/src/progress_bar.rs index 889c5558..62d319f4 100644 --- a/widget/src/progress_bar.rs +++ b/widget/src/progress_bar.rs @@ -28,7 +28,7 @@ pub struct ProgressBar<Theme = crate::Theme> {      value: f32,      width: Length,      height: Option<Length>, -    style: fn(&Theme) -> Appearance, +    style: Style<Theme>,  }  impl<Theme> ProgressBar<Theme> { @@ -42,14 +42,14 @@ impl<Theme> ProgressBar<Theme> {      ///   * the current value of the [`ProgressBar`]      pub fn new(range: RangeInclusive<f32>, value: f32) -> Self      where -        Theme: Style, +        Style<Theme>: Default,      {          ProgressBar {              value: value.clamp(*range.start(), *range.end()),              range,              width: Length::Fill,              height: None, -            style: Theme::style(), +            style: Style::default(),          }      } @@ -67,7 +67,7 @@ impl<Theme> ProgressBar<Theme> {      /// Sets the style of the [`ProgressBar`].      pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self { -        self.style = style; +        self.style = style.into();          self      }  } @@ -117,7 +117,7 @@ where                  / (range_end - range_start)          }; -        let appearance = (self.style)(theme); +        let appearance = (self.style.0)(theme);          renderer.fill_quad(              renderer::Quad { @@ -169,15 +169,27 @@ pub struct Appearance {      pub border: Border,  } -/// The definiton of the default style of a [`ProgressBar`]. -pub trait Style { -    /// Returns the default style of a [`ProgressBar`]. -    fn style() -> fn(&Self) -> Appearance; +/// The style of a [`ProgressBar`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(primary) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self) -> Appearance { -        primary +impl<Theme> From<fn(&Theme) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme) -> Appearance) -> Self { +        Style(f)      }  } diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index f13c9102..b94e95f6 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -23,19 +23,19 @@ const QUIET_ZONE: usize = 2;  pub struct QRCode<'a, Theme = crate::Theme> {      data: &'a Data,      cell_size: u16, -    style: fn(&Theme) -> Appearance, +    style: Style<Theme>,  }  impl<'a, Theme> QRCode<'a, Theme> {      /// Creates a new [`QRCode`] with the provided [`Data`].      pub fn new(data: &'a Data) -> Self      where -        Theme: Style, +        Style<Theme>: Default,      {          Self {              data,              cell_size: DEFAULT_CELL_SIZE, -            style: Theme::style(), +            style: Style::default(),          }      } @@ -47,7 +47,7 @@ impl<'a, Theme> QRCode<'a, Theme> {      /// Sets the style of the [`QRCode`].      pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self { -        self.style = style; +        self.style = style.into();          self      }  } @@ -97,7 +97,7 @@ impl<'a, Message, Theme> Widget<Message, Theme, Renderer>          let bounds = layout.bounds();          let side_length = self.data.width + 2 * QUIET_ZONE; -        let appearance = (self.style)(theme); +        let appearance = (self.style.0)(theme);          let mut last_appearance = state.last_appearance.borrow_mut();          if Some(appearance) != *last_appearance { @@ -335,15 +335,27 @@ pub struct Appearance {      pub background: Color,  } -/// The definiton of the default style of a [`QRCode`]. -pub trait Style { -    /// Returns the default style of a [`QRCode`]. -    fn style() -> fn(&Self) -> Appearance; +/// The style of a [`QRCode`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(default) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self) -> Appearance { -        default +impl<Theme> From<fn(&Theme) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme) -> Appearance) -> Self { +        Style(f)      }  } diff --git a/widget/src/radio.rs b/widget/src/radio.rs index 90a10a0b..83d17f01 100644 --- a/widget/src/radio.rs +++ b/widget/src/radio.rs @@ -82,7 +82,7 @@ where      text_line_height: text::LineHeight,      text_shaping: text::Shaping,      font: Option<Renderer::Font>, -    style: fn(&Theme, Status) -> Appearance, +    style: Style<Theme>,  }  impl<Message, Theme, Renderer> Radio<Message, Theme, Renderer> @@ -111,7 +111,7 @@ where          f: F,      ) -> Self      where -        Theme: Style, +        Style<Theme>: Default,          V: Eq + Copy,          F: FnOnce(V) -> Message,      { @@ -126,7 +126,7 @@ where              text_line_height: text::LineHeight::default(),              text_shaping: text::Shaping::Basic,              font: None, -            style: Theme::style(), +            style: Style::default(),          }      } @@ -177,7 +177,7 @@ where      /// Sets the style of the [`Radio`] button.      pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self { -        self.style = style.into(); +        self.style = Style(style);          self      }  } @@ -298,7 +298,7 @@ where              Status::Active { is_selected }          }; -        let appearance = (self.style)(theme, status); +        let appearance = (self.style.0)(theme, status);          {              let layout = children.next().unwrap(); @@ -398,15 +398,27 @@ pub struct Appearance {      pub text_color: Option<Color>,  } -/// The definiton of the default style of a [`Radio`] button. -pub trait Style { -    /// Returns the default style of a [`Radio`] button. -    fn style() -> fn(&Self, Status) -> Appearance; +/// The style of a [`Radio`] button. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme, Status) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(default) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self, Status) -> Appearance { -        default +impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme, Status) -> Appearance) -> Self { +        Style(f)      }  } diff --git a/widget/src/rule.rs b/widget/src/rule.rs index 1a1ba106..53a077aa 100644 --- a/widget/src/rule.rs +++ b/widget/src/rule.rs @@ -15,39 +15,39 @@ pub struct Rule<Theme = crate::Theme> {      width: Length,      height: Length,      is_horizontal: bool, -    style: fn(&Theme) -> Appearance, +    style: Style<Theme>,  }  impl<Theme> Rule<Theme> {      /// Creates a horizontal [`Rule`] with the given height.      pub fn horizontal(height: impl Into<Pixels>) -> Self      where -        Theme: Style, +        Style<Theme>: Default,      {          Rule {              width: Length::Fill,              height: Length::Fixed(height.into().0),              is_horizontal: true, -            style: Theme::style(), +            style: Style::default(),          }      }      /// Creates a vertical [`Rule`] with the given width.      pub fn vertical(width: impl Into<Pixels>) -> Self      where -        Theme: Style, +        Style<Theme>: Default,      {          Rule {              width: Length::Fixed(width.into().0),              height: Length::Fill,              is_horizontal: false, -            style: Theme::style(), +            style: Style::default(),          }      }      /// Sets the style of the [`Rule`].      pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self { -        self.style = style; +        self.style = Style(style);          self      }  } @@ -83,7 +83,7 @@ where          _viewport: &Rectangle,      ) {          let bounds = layout.bounds(); -        let appearance = (self.style)(theme); +        let appearance = (self.style.0)(theme);          let bounds = if self.is_horizontal {              let line_y = (bounds.y + (bounds.height / 2.0) @@ -216,15 +216,27 @@ impl FillMode {      }  } -/// The definiton of the default style of a [`Rule`]. -pub trait Style { -    /// Returns the default style of a [`Rule`]. -    fn style() -> fn(&Self) -> Appearance; +/// The style of a [`Rule`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(default) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self) -> Appearance { -        default +impl<Theme> From<fn(&Theme) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme) -> Appearance) -> Self { +        Style(f)      }  } diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 9772855e..19a80ee2 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -37,7 +37,7 @@ pub struct Scrollable<      direction: Direction,      content: Element<'a, Message, Theme, Renderer>,      on_scroll: Option<Box<dyn Fn(Viewport) -> Message + 'a>>, -    style: fn(&Theme, Status) -> Appearance, +    style: Style<Theme>,  }  impl<'a, Message, Theme, Renderer> Scrollable<'a, Message, Theme, Renderer> @@ -49,7 +49,7 @@ where          content: impl Into<Element<'a, Message, Theme, Renderer>>,      ) -> Self      where -        Theme: Style, +        Style<Theme>: Default,      {          Self::with_direction(content, Direction::default())      } @@ -60,8 +60,17 @@ where          direction: Direction,      ) -> Self      where -        Theme: Style, +        Style<Theme>: Default,      { +        Self::with_direction_and_style(content, direction, Style::default().0) +    } + +    /// Creates a new [`Scrollable`] with the given [`Direction`] and style. +    pub fn with_direction_and_style( +        content: impl Into<Element<'a, Message, Theme, Renderer>>, +        direction: Direction, +        style: fn(&Theme, Status) -> Appearance, +    ) -> Self {          let content = content.into();          debug_assert!( @@ -83,7 +92,7 @@ where              direction,              content,              on_scroll: None, -            style: Theme::style(), +            style: style.into(),          }      } @@ -115,7 +124,7 @@ where      /// Sets the style of the [`Scrollable`] .      pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self { -        self.style = style; +        self.style = style.into();          self      }  } @@ -399,7 +408,7 @@ where              Status::Active          }; -        let appearance = (self.style)(theme, status); +        let appearance = (self.style.0)(theme, status);          container::draw_background(              renderer, @@ -1653,15 +1662,27 @@ pub struct Scroller {      pub border: Border,  } -/// The definition of the default style of a [`Scrollable`]. -pub trait Style { -    /// Returns the default style of a [`Scrollable`]. -    fn style() -> fn(&Self, Status) -> Appearance; +/// The style of a [`Scrollable`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme, Status) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(default) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self, Status) -> Appearance { -        default +impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme, Status) -> Appearance) -> Self { +        Style(f)      }  } diff --git a/widget/src/slider.rs b/widget/src/slider.rs index a40f8792..c48fe143 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -53,7 +53,7 @@ pub struct Slider<'a, T, Message, Theme = crate::Theme> {      on_release: Option<Message>,      width: Length,      height: f32, -    style: fn(&Theme, Status) -> Appearance, +    style: Style<Theme>,  }  impl<'a, T, Message, Theme> Slider<'a, T, Message, Theme> @@ -74,7 +74,7 @@ where      ///   `Message`.      pub fn new<F>(range: RangeInclusive<T>, value: T, on_change: F) -> Self      where -        Theme: Style, +        Style<Theme>: Default,          F: 'a + Fn(T) -> Message,      {          let value = if value >= *range.start() { @@ -99,7 +99,7 @@ where              on_release: None,              width: Length::Fill,              height: Self::DEFAULT_HEIGHT, -            style: Theme::style(), +            style: Style::default(),          }      } @@ -136,7 +136,7 @@ where      /// Sets the style of the [`Slider`].      pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self { -        self.style = style; +        self.style = style.into();          self      } @@ -350,7 +350,7 @@ where          let bounds = layout.bounds();          let is_mouse_over = cursor.is_over(bounds); -        let style = (self.style)( +        let style = (self.style.0)(              theme,              if state.is_dragging {                  Status::Dragged @@ -550,15 +550,27 @@ pub enum HandleShape {      },  } -/// The definiton of the default style of a [`TextInput`]. -pub trait Style { -    /// Returns the default style of a [`TextInput`]. -    fn style() -> fn(&Self, Status) -> Appearance; +/// The style of a [`Slider`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(pub(crate) fn(&Theme, Status) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(default) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self, Status) -> Appearance { -        default +impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme, Status) -> Appearance) -> Self { +        Style(f)      }  } diff --git a/widget/src/svg.rs b/widget/src/svg.rs index 8ac5a1cf..c80fa6b1 100644 --- a/widget/src/svg.rs +++ b/widget/src/svg.rs @@ -81,7 +81,7 @@ impl<Theme> Svg<Theme> {      /// Sets the style variant of this [`Svg`].      #[must_use]      pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self { -        self.style = style.into(); +        self.style = Style(style);          self      }  } diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 91670228..73b006fa 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -42,7 +42,7 @@ pub struct TextEditor<      width: Length,      height: Length,      padding: Padding, -    style: fn(&Theme, Status) -> Appearance, +    style: Style<Theme>,      on_edit: Option<Box<dyn Fn(Action) -> Message + 'a>>,      highlighter_settings: Highlighter::Settings,      highlighter_format: fn( @@ -59,7 +59,7 @@ where      /// Creates new [`TextEditor`] with the given [`Content`].      pub fn new(content: &'a Content<Renderer>) -> Self      where -        Theme: Style, +        Style<Theme>: Default,      {          Self {              content, @@ -69,7 +69,7 @@ where              width: Length::Fill,              height: Length::Shrink,              padding: Padding::new(5.0), -            style: Theme::style(), +            style: Style::default(),              on_edit: None,              highlighter_settings: (),              highlighter_format: |_highlight, _theme| { @@ -144,7 +144,7 @@ where      /// Sets the style of the [`TextEditor`].      pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self { -        self.style = style; +        self.style = style.into();          self      }  } @@ -506,7 +506,7 @@ where              Status::Active          }; -        let appearance = (self.style)(theme, status); +        let appearance = (self.style.0)(theme, status);          renderer.fill_quad(              renderer::Quad { @@ -809,15 +809,27 @@ pub struct Appearance {      pub selection: Color,  } -/// The definiton of the default style of a [`TextInput`]. -pub trait Style { -    /// Returns the default style of a [`TextInput`]. -    fn style() -> fn(&Self, Status) -> Appearance; +/// The style of a [`TextEditor`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme, Status) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(default) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self, Status) -> Appearance { -        default +impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme, Status) -> Appearance) -> Self { +        Style(f)      }  } diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index 11b0a5d5..bae84db7 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -77,7 +77,7 @@ pub struct TextInput<      on_paste: Option<Box<dyn Fn(String) -> Message + 'a>>,      on_submit: Option<Message>,      icon: Option<Icon<Renderer::Font>>, -    style: fn(&Theme, Status) -> Appearance, +    style: Style<Theme>,  }  /// The default [`Padding`] of a [`TextInput`]. @@ -88,15 +88,22 @@ where      Message: Clone,      Renderer: text::Renderer,  { -    /// Creates a new [`TextInput`]. -    /// -    /// It expects: -    /// - a placeholder, -    /// - the current value +    /// Creates a new [`TextInput`] with the given placeholder and +    /// its current value.      pub fn new(placeholder: &str, value: &str) -> Self      where -        Theme: Style, +        Style<Theme>: Default,      { +        Self::with_style(placeholder, value, Style::default().0) +    } + +    /// Creates a new [`TextInput`] with the given placeholder, +    /// its current value, and its style. +    pub fn with_style( +        placeholder: &str, +        value: &str, +        style: fn(&Theme, Status) -> Appearance, +    ) -> Self {          TextInput {              id: None,              placeholder: String::from(placeholder), @@ -111,7 +118,7 @@ where              on_paste: None,              on_submit: None,              icon: None, -            style: Theme::style(), +            style: style.into(),          }      } @@ -199,7 +206,7 @@ where      /// Sets the style of the [`TextInput`].      pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self { -        self.style = style; +        self.style = style.into();          self      } @@ -337,7 +344,7 @@ where              Status::Active          }; -        let appearance = (self.style)(theme, status); +        let appearance = (self.style.0)(theme, status);          renderer.fill_quad(              renderer::Quad { @@ -1406,15 +1413,27 @@ pub struct Appearance {      pub selection: Color,  } -/// The definiton of the default style of a [`TextInput`]. -pub trait Style { -    /// Returns the default style of a [`TextInput`]. -    fn style() -> fn(&Self, Status) -> Appearance; +/// The style of a [`TextInput`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme, Status) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(default) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self, Status) -> Appearance { -        default +impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme, Status) -> Appearance) -> Self { +        Style(f)      }  } diff --git a/widget/src/toggler.rs b/widget/src/toggler.rs index 1f19212d..cecd7b6c 100644 --- a/widget/src/toggler.rs +++ b/widget/src/toggler.rs @@ -50,7 +50,7 @@ pub struct Toggler<      text_shaping: text::Shaping,      spacing: f32,      font: Option<Renderer::Font>, -    style: fn(&Theme, Status) -> Appearance, +    style: Style<Theme>,  }  impl<'a, Message, Theme, Renderer> Toggler<'a, Message, Theme, Renderer> @@ -74,7 +74,7 @@ where          f: F,      ) -> Self      where -        Theme: Style, +        Style<Theme>: Default,          F: 'a + Fn(bool) -> Message,      {          Toggler { @@ -89,7 +89,7 @@ where              text_shaping: text::Shaping::Basic,              spacing: Self::DEFAULT_SIZE / 2.0,              font: None, -            style: Theme::style(), +            style: Style::default(),          }      } @@ -301,7 +301,7 @@ where              }          }; -        let appearance = (self.style)(theme, status); +        let appearance = (self.style.0)(theme, status);          let border_radius = bounds.height / BORDER_RADIUS_RATIO;          let space = SPACE_RATIO * bounds.height; @@ -399,15 +399,27 @@ pub struct Appearance {      pub foreground_border_color: Color,  } -/// The definiton of the default style of a [`Toggler`]. -pub trait Style { -    /// Returns the default style of a [`Toggler`]. -    fn style() -> fn(&Self, Status) -> Appearance; +/// The style of a [`Toggler`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme>(fn(&Theme, Status) -> Appearance); + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Style(default) +    }  } -impl Style for Theme { -    fn style() -> fn(&Self, Status) -> Appearance { -        default +impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> { +    fn from(f: fn(&Theme, Status) -> Appearance) -> Self { +        Style(f)      }  } diff --git a/widget/src/tooltip.rs b/widget/src/tooltip.rs index 956383da..4e026e8f 100644 --- a/widget/src/tooltip.rs +++ b/widget/src/tooltip.rs @@ -28,7 +28,7 @@ pub struct Tooltip<      gap: f32,      padding: f32,      snap_within_viewport: bool, -    style: fn(&Theme, container::Status) -> container::Appearance, +    style: container::Style<Theme>,  }  impl<'a, Message, Theme, Renderer> Tooltip<'a, Message, Theme, Renderer> @@ -47,7 +47,7 @@ where          position: Position,      ) -> Self      where -        Theme: container::Style, +        container::Style<Theme>: Default,      {          Tooltip {              content: content.into(), @@ -56,7 +56,7 @@ where              gap: 0.0,              padding: Self::DEFAULT_PADDING,              snap_within_viewport: true, -            style: Theme::style(), +            style: container::Style::default(),          }      } @@ -83,7 +83,7 @@ where          mut self,          style: fn(&Theme, container::Status) -> container::Appearance,      ) -> Self { -        self.style = style; +        self.style = style.into();          self      }  } @@ -309,7 +309,7 @@ where      positioning: Position,      gap: f32,      padding: f32, -    style: fn(&Theme, container::Status) -> container::Appearance, +    style: container::Style<Theme>,  }  impl<'a, 'b, Message, Theme, Renderer> @@ -424,7 +424,7 @@ where          layout: Layout<'_>,          cursor_position: mouse::Cursor,      ) { -        let style = (self.style)(theme, container::Status::Idle); +        let style = self.style.resolve(theme, container::Status::Idle);          container::draw_background(renderer, &style, layout.bounds()); diff --git a/widget/src/vertical_slider.rs b/widget/src/vertical_slider.rs index b51aa2bf..47c400c7 100644 --- a/widget/src/vertical_slider.rs +++ b/widget/src/vertical_slider.rs @@ -54,7 +54,7 @@ pub struct VerticalSlider<'a, T, Message, Theme = crate::Theme> {      on_release: Option<Message>,      width: f32,      height: Length, -    style: fn(&Theme, Status) -> Appearance, +    style: Style<Theme>,  }  impl<'a, T, Message, Theme> VerticalSlider<'a, T, Message, Theme> @@ -75,7 +75,7 @@ where      ///   `Message`.      pub fn new<F>(range: RangeInclusive<T>, value: T, on_change: F) -> Self      where -        Theme: Style, +        Style<Theme>: Default,          F: 'a + Fn(T) -> Message,      {          let value = if value >= *range.start() { @@ -100,7 +100,7 @@ where              on_release: None,              width: Self::DEFAULT_WIDTH,              height: Length::Fill, -            style: Theme::style(), +            style: Style::default(),          }      } @@ -136,10 +136,7 @@ where      }      /// Sets the style of the [`VerticalSlider`]. -    pub fn style( -        mut self, -        style: impl Into<fn(&Theme, Status) -> Appearance>, -    ) -> Self { +    pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {          self.style = style.into();          self      } @@ -357,7 +354,7 @@ where          let bounds = layout.bounds();          let is_mouse_over = cursor.is_over(bounds); -        let style = (self.style)( +        let style = (self.style.0)(              theme,              if state.is_dragging {                  Status::Dragged | 
