diff options
Diffstat (limited to 'widget/src/rule.rs')
-rw-r--r-- | widget/src/rule.rs | 109 |
1 files changed, 65 insertions, 44 deletions
diff --git a/widget/src/rule.rs b/widget/src/rule.rs index 9fa5f74f..1a536d2f 100644 --- a/widget/src/rule.rs +++ b/widget/src/rule.rs @@ -1,4 +1,5 @@ //! Display a horizontal or vertical rule for dividing content. +use crate::core; use crate::core::border::{self, Border}; use crate::core::layout; use crate::core::mouse; @@ -10,43 +11,55 @@ use crate::core::{ /// Display a horizontal or vertical rule for dividing content. #[allow(missing_debug_implementations)] -pub struct Rule<'a, Theme = crate::Theme> { +pub struct Rule<'a, Theme = crate::Theme> +where + Theme: Catalog, +{ width: Length, height: Length, is_horizontal: bool, - style: Style<'a, Theme>, + class: Theme::Class<'a>, } -impl<'a, Theme> Rule<'a, Theme> { +impl<'a, Theme> Rule<'a, Theme> +where + Theme: Catalog, +{ /// Creates a horizontal [`Rule`] with the given height. - pub fn horizontal(height: impl Into<Pixels>) -> Self - where - Theme: DefaultStyle + 'a, - { + pub fn horizontal(height: impl Into<Pixels>) -> Self { Rule { width: Length::Fill, height: Length::Fixed(height.into().0), is_horizontal: true, - style: Box::new(Theme::default_style), + class: Theme::default(), } } /// Creates a vertical [`Rule`] with the given width. - pub fn vertical(width: impl Into<Pixels>) -> Self - where - Theme: DefaultStyle + 'a, - { + pub fn vertical(width: impl Into<Pixels>) -> Self { Rule { width: Length::Fixed(width.into().0), height: Length::Fill, is_horizontal: false, - style: Box::new(Theme::default_style), + class: Theme::default(), } } /// Sets the style of the [`Rule`]. - pub fn style(mut self, style: impl Fn(&Theme) -> Appearance + 'a) -> Self { - self.style = Box::new(style); + #[must_use] + pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self + where + Theme::Class<'a>: From<StyleFn<'a, Theme>>, + { + self.class = (Box::new(style) as StyleFn<'a, Theme>).into(); + self + } + + /// Sets the style class of the [`Rule`]. + #[cfg(feature = "advanced")] + #[must_use] + pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self { + self.class = class.into(); self } } @@ -54,7 +67,8 @@ impl<'a, Theme> Rule<'a, Theme> { impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Rule<'a, Theme> where - Renderer: crate::core::Renderer, + Renderer: core::Renderer, + Theme: Catalog, { fn size(&self) -> Size<Length> { Size { @@ -83,35 +97,34 @@ where _viewport: &Rectangle, ) { let bounds = layout.bounds(); - let appearance = (self.style)(theme); + let style = theme.style(&self.class); let bounds = if self.is_horizontal { let line_y = (bounds.y + (bounds.height / 2.0) - - (appearance.width as f32 / 2.0)) + - (style.width as f32 / 2.0)) .round(); - let (offset, line_width) = appearance.fill_mode.fill(bounds.width); + let (offset, line_width) = style.fill_mode.fill(bounds.width); let line_x = bounds.x + offset; Rectangle { x: line_x, y: line_y, width: line_width, - height: appearance.width as f32, + height: style.width as f32, } } else { let line_x = (bounds.x + (bounds.width / 2.0) - - (appearance.width as f32 / 2.0)) + - (style.width as f32 / 2.0)) .round(); - let (offset, line_height) = - appearance.fill_mode.fill(bounds.height); + let (offset, line_height) = style.fill_mode.fill(bounds.height); let line_y = bounds.y + offset; Rectangle { x: line_x, y: line_y, - width: appearance.width as f32, + width: style.width as f32, height: line_height, } }; @@ -119,10 +132,10 @@ where renderer.fill_quad( renderer::Quad { bounds, - border: Border::rounded(appearance.radius), + border: Border::rounded(style.radius), ..renderer::Quad::default() }, - appearance.color, + style.color, ); } } @@ -131,8 +144,8 @@ impl<'a, Message, Theme, Renderer> From<Rule<'a, Theme>> for Element<'a, Message, Theme, Renderer> where Message: 'a, - Theme: 'a, - Renderer: 'a + crate::core::Renderer, + Theme: 'a + Catalog, + Renderer: 'a + core::Renderer, { fn from(rule: Rule<'a, Theme>) -> Element<'a, Message, Theme, Renderer> { Element::new(rule) @@ -141,7 +154,7 @@ where /// The appearance of a rule. #[derive(Debug, Clone, Copy)] -pub struct Appearance { +pub struct Style { /// The color of the rule. pub color: Color, /// The width (thickness) of the rule line. @@ -216,32 +229,40 @@ impl FillMode { } } -/// The style of a [`Rule`]. -pub type Style<'a, Theme> = Box<dyn Fn(&Theme) -> Appearance + 'a>; +/// The theme catalog of a [`Rule`]. +pub trait Catalog: Sized { + /// The item class of the [`Catalog`]. + type Class<'a>; -/// The default style of a [`Rule`]. -pub trait DefaultStyle { - /// Returns the default style of a [`Rule`]. - fn default_style(&self) -> Appearance; + /// The default class produced by the [`Catalog`]. + fn default<'a>() -> Self::Class<'a>; + + /// The [`Style`] of a class with the given status. + fn style(&self, class: &Self::Class<'_>) -> Style; } -impl DefaultStyle for Theme { - fn default_style(&self) -> Appearance { - default(self) +/// A styling function for a [`Rule`]. +/// +/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`. +pub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme) -> Style + 'a>; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) } -} -impl DefaultStyle for Appearance { - fn default_style(&self) -> Appearance { - *self + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) } } /// The default styling of a [`Rule`]. -pub fn default(theme: &Theme) -> Appearance { +pub fn default(theme: &Theme) -> Style { let palette = theme.extended_palette(); - Appearance { + Style { color: palette.background.strong.color, width: 1, radius: 0.0.into(), |