diff options
author | 2024-03-06 20:30:58 +0100 | |
---|---|---|
committer | 2024-03-06 20:30:58 +0100 | |
commit | 34e7c6593a9e0f56cee5db18b7258717cf6bc11b (patch) | |
tree | 7c65a58e9052f2f95a0025355679b13c7002eeab | |
parent | 8a63774b24488f71147a728123551ae72c080d14 (diff) | |
download | iced-34e7c6593a9e0f56cee5db18b7258717cf6bc11b.tar.gz iced-34e7c6593a9e0f56cee5db18b7258717cf6bc11b.tar.bz2 iced-34e7c6593a9e0f56cee5db18b7258717cf6bc11b.zip |
Use `Style` struct pattern instead of trait for all widgets
-rw-r--r-- | core/src/widget/text.rs | 39 | ||||
-rw-r--r-- | examples/gradient/src/main.rs | 2 | ||||
-rw-r--r-- | style/src/theme.rs | 3 | ||||
-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 |
25 files changed, 465 insertions, 281 deletions
diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs index 217ad8b3..e151476d 100644 --- a/core/src/widget/text.rs +++ b/core/src/widget/text.rs @@ -17,7 +17,6 @@ pub use text::{LineHeight, Shaping}; #[allow(missing_debug_implementations)] pub struct Text<'a, Theme, Renderer> where - Theme: StyleSheet, Renderer: text::Renderer, { content: Cow<'a, str>, @@ -34,7 +33,6 @@ where impl<'a, Theme, Renderer> Text<'a, Theme, Renderer> where - Theme: StyleSheet, Renderer: text::Renderer, { /// Create a new fragment of [`Text`] with the given contents. @@ -49,7 +47,7 @@ where horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, shaping: Shaping::Basic, - style: Style::Themed(Theme::default()), + style: Style::default(), } } @@ -135,7 +133,6 @@ pub struct State<P: Paragraph>(P); impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Text<'a, Theme, Renderer> where - Theme: StyleSheet, Renderer: text::Renderer, { fn tag(&self) -> tree::Tag { @@ -283,7 +280,7 @@ pub fn draw<Renderer>( impl<'a, Message, Theme, Renderer> From<Text<'a, Theme, Renderer>> for Element<'a, Message, Theme, Renderer> where - Theme: StyleSheet + 'a, + Theme: 'a, Renderer: text::Renderer + 'a, { fn from( @@ -295,7 +292,6 @@ where impl<'a, Theme, Renderer> Clone for Text<'a, Theme, Renderer> where - Theme: StyleSheet, Renderer: text::Renderer, { fn clone(&self) -> Self { @@ -316,7 +312,6 @@ where impl<'a, Theme, Renderer> From<&'a str> for Text<'a, Theme, Renderer> where - Theme: StyleSheet, Renderer: text::Renderer, { fn from(content: &'a str) -> Self { @@ -327,7 +322,7 @@ where impl<'a, Message, Theme, Renderer> From<&'a str> for Element<'a, Message, Theme, Renderer> where - Theme: StyleSheet + 'a, + Theme: 'a, Renderer: text::Renderer + 'a, { fn from(content: &'a str) -> Self { @@ -335,22 +330,6 @@ where } } -/// The style sheet of some text. -pub trait StyleSheet { - /// Returns the default styling strategy for [`Text`]. - fn default() -> fn(&Self) -> Appearance { - |_| Appearance::default() - } -} - -impl StyleSheet for Color { - fn default() -> fn(&Self) -> Appearance { - |color| Appearance { - color: Some(*color), - } - } -} - /// The apperance of some text. #[derive(Debug, Clone, Copy, Default)] pub struct Appearance { @@ -373,3 +352,15 @@ impl<Theme> Clone for Style<Theme> { } impl<Theme> Copy for Style<Theme> {} + +impl<Theme> Default for Style<Theme> { + fn default() -> Self { + Style::Colored(None) + } +} + +impl<Theme> From<fn(&Theme) -> Appearance> for Style<Theme> { + fn from(f: fn(&Theme) -> Appearance) -> Self { + Style::Themed(f) + } +} diff --git a/examples/gradient/src/main.rs b/examples/gradient/src/main.rs index 1a264063..3334bde9 100644 --- a/examples/gradient/src/main.rs +++ b/examples/gradient/src/main.rs @@ -84,7 +84,7 @@ impl Sandbox for Gradient { }; let gradient_box = themer( - move |_| appearance, + appearance, container(horizontal_space()) .width(Length::Fill) .height(Length::Fill), diff --git a/style/src/theme.rs b/style/src/theme.rs index fd93f776..41e76d99 100644 --- a/style/src/theme.rs +++ b/style/src/theme.rs @@ -4,7 +4,6 @@ pub mod palette; pub use palette::Palette; use crate::application; -use crate::core::widget::text; use std::fmt; use std::sync::Arc; @@ -265,5 +264,3 @@ impl<T: Fn(&Theme) -> application::Appearance> application::StyleSheet for T { (self)(style) } } - -impl text::StyleSheet for Theme {} 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 |