diff options
Diffstat (limited to 'widget/src/slider.rs')
-rw-r--r-- | widget/src/slider.rs | 93 |
1 files changed, 56 insertions, 37 deletions
diff --git a/widget/src/slider.rs b/widget/src/slider.rs index d3b46a98..a8f1d192 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -9,7 +9,7 @@ use crate::core::renderer; use crate::core::touch; use crate::core::widget::tree::{self, Tree}; use crate::core::{ - Border, Clipboard, Color, Element, Layout, Length, Pixels, Point, + self, Border, Clipboard, Color, Element, Layout, Length, Pixels, Point, Rectangle, Shell, Size, Theme, Widget, }; @@ -39,7 +39,10 @@ use std::ops::RangeInclusive; /// ///  #[allow(missing_debug_implementations)] -pub struct Slider<'a, T, Message, Theme = crate::Theme> { +pub struct Slider<'a, T, Message, Theme = crate::Theme> +where + Theme: Catalog, +{ range: RangeInclusive<T>, step: T, shift_step: Option<T>, @@ -49,13 +52,14 @@ pub struct Slider<'a, T, Message, Theme = crate::Theme> { on_release: Option<Message>, width: Length, height: f32, - style: Style<'a, Theme>, + class: Theme::Class<'a>, } impl<'a, T, Message, Theme> Slider<'a, T, Message, Theme> where T: Copy + From<u8> + PartialOrd, Message: Clone, + Theme: Catalog, { /// The default height of a [`Slider`]. pub const DEFAULT_HEIGHT: f32 = 16.0; @@ -70,7 +74,6 @@ where /// `Message`. pub fn new<F>(range: RangeInclusive<T>, value: T, on_change: F) -> Self where - Theme: DefaultStyle + 'a, F: 'a + Fn(T) -> Message, { let value = if value >= *range.start() { @@ -95,7 +98,7 @@ where on_release: None, width: Length::Fill, height: Self::DEFAULT_HEIGHT, - style: Box::new(Theme::default_style), + class: Theme::default(), } } @@ -130,15 +133,6 @@ where self } - /// Sets the style of the [`Slider`]. - pub fn style( - mut self, - style: impl Fn(&Theme, Status) -> Appearance + 'a, - ) -> Self { - self.style = Box::new(style); - self - } - /// Sets the step size of the [`Slider`]. pub fn step(mut self, step: impl Into<T>) -> Self { self.step = step.into(); @@ -152,6 +146,24 @@ where self.shift_step = Some(shift_step.into()); self } + + /// Sets the style of the [`Slider`]. + #[must_use] + pub fn style(mut self, style: impl Fn(&Theme, Status) -> 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 [`Slider`]. + #[cfg(feature = "advanced")] + #[must_use] + pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self { + self.class = class.into(); + self + } } impl<'a, T, Message, Theme, Renderer> Widget<Message, Theme, Renderer> @@ -159,7 +171,8 @@ impl<'a, T, Message, Theme, Renderer> Widget<Message, Theme, Renderer> where T: Copy + Into<f64> + num_traits::FromPrimitive, Message: Clone, - Renderer: crate::core::Renderer, + Theme: Catalog, + Renderer: core::Renderer, { fn tag(&self) -> tree::Tag { tree::Tag::of::<State>() @@ -349,8 +362,8 @@ where let bounds = layout.bounds(); let is_mouse_over = cursor.is_over(bounds); - let style = (self.style)( - theme, + let style = theme.style( + &self.class, if state.is_dragging { Status::Dragged } else if is_mouse_over { @@ -461,8 +474,8 @@ impl<'a, T, Message, Theme, Renderer> From<Slider<'a, T, Message, Theme>> where T: Copy + Into<f64> + num_traits::FromPrimitive + 'a, Message: Clone + 'a, - Theme: 'a, - Renderer: crate::core::Renderer + 'a, + Theme: Catalog + 'a, + Renderer: core::Renderer + 'a, { fn from( slider: Slider<'a, T, Message, Theme>, @@ -490,15 +503,15 @@ pub enum Status { /// The appearance of a slider. #[derive(Debug, Clone, Copy)] -pub struct Appearance { +pub struct Style { /// The colors of the rail of the slider. pub rail: Rail, /// The appearance of the [`Handle`] of the slider. pub handle: Handle, } -impl Appearance { - /// Changes the [`HandleShape`] of the [`Appearance`] to a circle +impl Style { + /// Changes the [`HandleShape`] of the [`Style`] to a circle /// with the given radius. pub fn with_circular_handle(mut self, radius: impl Into<Pixels>) -> Self { self.handle.shape = HandleShape::Circle { @@ -549,29 +562,35 @@ pub enum HandleShape { }, } -/// The style of a [`Slider`]. -pub type Style<'a, Theme> = Box<dyn Fn(&Theme, Status) -> Appearance + 'a>; +/// The theme catalog of a [`Slider`]. +pub trait Catalog: Sized { + /// The item class of the [`Catalog`]. + type Class<'a>; -/// The default style of a [`Slider`]. -pub trait DefaultStyle { - /// Returns the default style of a [`Slider`]. - fn default_style(&self, status: Status) -> 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<'_>, status: Status) -> Style; } -impl DefaultStyle for Theme { - fn default_style(&self, status: Status) -> Appearance { - default(self, status) +/// A styling function for a [`Slider`]. +pub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme, Status) -> 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, _status: Status) -> Appearance { - *self + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) } } /// The default style of a [`Slider`]. -pub fn default(theme: &Theme, status: Status) -> Appearance { +pub fn default(theme: &Theme, status: Status) -> Style { let palette = theme.extended_palette(); let color = match status { @@ -580,7 +599,7 @@ pub fn default(theme: &Theme, status: Status) -> Appearance { Status::Dragged => palette.primary.strong.color, }; - Appearance { + Style { rail: Rail { colors: (color, palette.secondary.base.color), width: 4.0, |