summaryrefslogtreecommitdiffstats
path: root/widget/src/rule.rs
diff options
context:
space:
mode:
Diffstat (limited to 'widget/src/rule.rs')
-rw-r--r--widget/src/rule.rs109
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(),