diff options
Diffstat (limited to 'style/src/theme.rs')
-rw-r--r-- | style/src/theme.rs | 861 |
1 files changed, 589 insertions, 272 deletions
diff --git a/style/src/theme.rs b/style/src/theme.rs index ea538c3a..271d9a29 100644 --- a/style/src/theme.rs +++ b/style/src/theme.rs @@ -1,5 +1,7 @@ +//! Use the built-in theme and styles. pub mod palette; +use self::palette::Extended; pub use self::palette::Palette; use crate::application; @@ -14,56 +16,83 @@ use crate::radio; use crate::rule; use crate::scrollable; use crate::slider; +use crate::svg; use crate::text; use crate::text_input; use crate::toggler; -use iced_core::{Background, Color}; +use iced_core::{Background, Color, Vector}; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +use std::rc::Rc; + +/// A built-in theme. +#[derive(Debug, Clone, PartialEq, Default)] pub enum Theme { + /// The built-in light variant. + #[default] Light, + /// The built-in dark variant. Dark, + /// A [`Theme`] that uses a [`Custom`] palette. + Custom(Box<Custom>), } impl Theme { - pub fn palette(self) -> Palette { + /// Creates a new custom [`Theme`] from the given [`Palette`]. + pub fn custom(palette: Palette) -> Self { + Self::Custom(Box::new(Custom::new(palette))) + } + + /// Returns the [`Palette`] of the [`Theme`]. + pub fn palette(&self) -> Palette { match self { Self::Light => Palette::LIGHT, Self::Dark => Palette::DARK, + Self::Custom(custom) => custom.palette, } } + /// Returns the [`palette::Extended`] of the [`Theme`]. pub fn extended_palette(&self) -> &palette::Extended { match self { Self::Light => &palette::EXTENDED_LIGHT, Self::Dark => &palette::EXTENDED_DARK, + Self::Custom(custom) => &custom.extended, } } } -impl Default for Theme { - fn default() -> Self { - Self::Light +/// A [`Theme`] with a customized [`Palette`]. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Custom { + palette: Palette, + extended: Extended, +} + +impl Custom { + /// Creates a [`Custom`] theme from the given [`Palette`]. + pub fn new(palette: Palette) -> Self { + Self { + palette, + extended: Extended::generate(palette), + } } } -#[derive(Debug, Clone, Copy)] +/// The style of an application. +#[derive(Default)] pub enum Application { + /// The default style. + #[default] Default, - Custom(fn(Theme) -> application::Appearance), -} - -impl Default for Application { - fn default() -> Self { - Self::Default - } + /// A custom style. + Custom(Box<dyn application::StyleSheet<Style = Theme>>), } impl application::StyleSheet for Theme { type Style = Application; - fn appearance(&self, style: Self::Style) -> application::Appearance { + fn appearance(&self, style: &Self::Style) -> application::Appearance { let palette = self.extended_palette(); match style { @@ -71,33 +100,49 @@ impl application::StyleSheet for Theme { background_color: palette.background.base.color, text_color: palette.background.base.text, }, - Application::Custom(f) => f(*self), + Application::Custom(custom) => custom.appearance(self), } } } -/* - * Button - */ -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +impl application::StyleSheet for fn(&Theme) -> application::Appearance { + type Style = Theme; + + fn appearance(&self, style: &Self::Style) -> application::Appearance { + (self)(style) + } +} + +impl From<fn(&Theme) -> application::Appearance> for Application { + fn from(f: fn(&Theme) -> application::Appearance) -> Self { + Self::Custom(Box::new(f)) + } +} + +/// The style of a button. +#[derive(Default)] pub enum Button { + /// The primary style. + #[default] Primary, + /// The secondary style. Secondary, + /// The positive style. Positive, + /// The destructive style. Destructive, + /// The text style. + /// + /// Useful for links! Text, -} - -impl Default for Button { - fn default() -> Self { - Self::Primary - } + /// A custom style. + Custom(Box<dyn button::StyleSheet<Style = Theme>>), } impl button::StyleSheet for Theme { type Style = Button; - fn active(&self, style: Self::Style) -> button::Appearance { + fn active(&self, style: &Self::Style) -> button::Appearance { let palette = self.extended_palette(); let appearance = button::Appearance { @@ -120,19 +165,25 @@ impl button::StyleSheet for Theme { text_color: palette.background.base.text, ..appearance }, + Button::Custom(custom) => custom.active(self), } } - fn hovered(&self, style: Self::Style) -> button::Appearance { - let active = self.active(style); + fn hovered(&self, style: &Self::Style) -> button::Appearance { let palette = self.extended_palette(); + if let Button::Custom(custom) = style { + return custom.hovered(self); + } + + let active = self.active(style); + let background = match style { Button::Primary => Some(palette.primary.base.color), Button::Secondary => Some(palette.background.strong.color), Button::Positive => Some(palette.success.strong.color), Button::Destructive => Some(palette.danger.strong.color), - Button::Text => None, + Button::Text | Button::Custom(_) => None, }; button::Appearance { @@ -140,23 +191,56 @@ impl button::StyleSheet for Theme { ..active } } + + fn pressed(&self, style: &Self::Style) -> button::Appearance { + if let Button::Custom(custom) = style { + return custom.pressed(self); + } + + button::Appearance { + shadow_offset: Vector::default(), + ..self.active(style) + } + } + + fn disabled(&self, style: &Self::Style) -> button::Appearance { + if let Button::Custom(custom) = style { + return custom.disabled(self); + } + + let active = self.active(style); + + button::Appearance { + shadow_offset: Vector::default(), + background: active.background.map(|background| match background { + Background::Color(color) => Background::Color(Color { + a: color.a * 0.5, + ..color + }), + }), + text_color: Color { + a: active.text_color.a * 0.5, + ..active.text_color + }, + ..active + } + } } -/* - * Checkbox - */ -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// The style of a checkbox. +#[derive(Default)] pub enum Checkbox { + /// The primary style. + #[default] Primary, + /// The secondary style. Secondary, + /// The success style. Success, + /// The danger style. Danger, -} - -impl Default for Checkbox { - fn default() -> Self { - Self::Primary - } + /// A custom style. + Custom(Box<dyn checkbox::StyleSheet<Style = Theme>>), } impl checkbox::StyleSheet for Theme { @@ -164,7 +248,7 @@ impl checkbox::StyleSheet for Theme { fn active( &self, - style: Self::Style, + style: &Self::Style, is_checked: bool, ) -> checkbox::Appearance { let palette = self.extended_palette(); @@ -194,12 +278,13 @@ impl checkbox::StyleSheet for Theme { palette.danger.base, is_checked, ), + Checkbox::Custom(custom) => custom.active(self, is_checked), } } fn hovered( &self, - style: Self::Style, + style: &Self::Style, is_checked: bool, ) -> checkbox::Appearance { let palette = self.extended_palette(); @@ -229,6 +314,7 @@ impl checkbox::StyleSheet for Theme { palette.danger.base, is_checked, ), + Checkbox::Custom(custom) => custom.hovered(self, is_checked), } } } @@ -253,32 +339,28 @@ fn checkbox_appearance( } } -/* - * Container - */ -#[derive(Clone, Copy)] +/// The style of a container. +#[derive(Default)] pub enum Container { + /// No style. + #[default] Transparent, + /// A simple box. Box, - Custom(fn(&Theme) -> container::Appearance), -} - -impl Default for Container { - fn default() -> Self { - Self::Transparent - } + /// A custom style. + Custom(Box<dyn container::StyleSheet<Style = Theme>>), } impl From<fn(&Theme) -> container::Appearance> for Container { fn from(f: fn(&Theme) -> container::Appearance) -> Self { - Self::Custom(f) + Self::Custom(Box::new(f)) } } impl container::StyleSheet for Theme { type Style = Container; - fn appearance(&self, style: Self::Style) -> container::Appearance { + fn appearance(&self, style: &Self::Style) -> container::Appearance { match style { Container::Transparent => Default::default(), Container::Box => { @@ -292,257 +374,389 @@ impl container::StyleSheet for Theme { border_color: Color::TRANSPARENT, } } - Container::Custom(f) => f(self), + Container::Custom(custom) => custom.appearance(self), } } } -/* - * Slider - */ -impl slider::StyleSheet for Theme { - type Style = (); +impl container::StyleSheet for fn(&Theme) -> container::Appearance { + type Style = Theme; - fn active(&self, _style: Self::Style) -> slider::Appearance { - let palette = self.extended_palette(); + fn appearance(&self, style: &Self::Style) -> container::Appearance { + (self)(style) + } +} - let handle = slider::Handle { - shape: slider::HandleShape::Rectangle { - width: 8, - border_radius: 4.0, - }, - color: Color::WHITE, - border_color: Color::WHITE, - border_width: 1.0, - }; +/// The style of a slider. +#[derive(Default)] +pub enum Slider { + /// The default style. + #[default] + Default, + /// A custom style. + Custom(Box<dyn slider::StyleSheet<Style = Theme>>), +} - slider::Appearance { - rail_colors: (palette.primary.base.color, Color::TRANSPARENT), - handle: slider::Handle { - color: palette.background.base.color, - border_color: palette.primary.base.color, - ..handle - }, +impl slider::StyleSheet for Theme { + type Style = Slider; + + fn active(&self, style: &Self::Style) -> slider::Appearance { + match style { + Slider::Default => { + let palette = self.extended_palette(); + + let handle = slider::Handle { + shape: slider::HandleShape::Rectangle { + width: 8, + border_radius: 4.0, + }, + color: Color::WHITE, + border_color: Color::WHITE, + border_width: 1.0, + }; + + slider::Appearance { + rail_colors: ( + palette.primary.base.color, + Color::TRANSPARENT, + ), + handle: slider::Handle { + color: palette.background.base.color, + border_color: palette.primary.base.color, + ..handle + }, + } + } + Slider::Custom(custom) => custom.active(self), } } - fn hovered(&self, style: Self::Style) -> slider::Appearance { - let active = self.active(style); - let palette = self.extended_palette(); + fn hovered(&self, style: &Self::Style) -> slider::Appearance { + match style { + Slider::Default => { + let active = self.active(style); + let palette = self.extended_palette(); - slider::Appearance { - handle: slider::Handle { - color: palette.primary.weak.color, - ..active.handle - }, - ..active + slider::Appearance { + handle: slider::Handle { + color: palette.primary.weak.color, + ..active.handle + }, + ..active + } + } + Slider::Custom(custom) => custom.hovered(self), } } - fn dragging(&self, style: Self::Style) -> slider::Appearance { - let active = self.active(style); - let palette = self.extended_palette(); + fn dragging(&self, style: &Self::Style) -> slider::Appearance { + match style { + Slider::Default => { + let active = self.active(style); + let palette = self.extended_palette(); - slider::Appearance { - handle: slider::Handle { - color: palette.primary.base.color, - ..active.handle - }, - ..active + slider::Appearance { + handle: slider::Handle { + color: palette.primary.base.color, + ..active.handle + }, + ..active + } + } + Slider::Custom(custom) => custom.dragging(self), } } } -/* - * Menu - */ +/// The style of a menu. +#[derive(Clone, Default)] +pub enum Menu { + /// The default style. + #[default] + Default, + /// A custom style. + Custom(Rc<dyn menu::StyleSheet<Style = Theme>>), +} + impl menu::StyleSheet for Theme { - type Style = (); + type Style = Menu; - fn appearance(&self, _style: Self::Style) -> menu::Appearance { - let palette = self.extended_palette(); + fn appearance(&self, style: &Self::Style) -> menu::Appearance { + match style { + Menu::Default => { + let palette = self.extended_palette(); - menu::Appearance { - text_color: palette.background.weak.text, - background: palette.background.weak.color.into(), - border_width: 1.0, - border_radius: 0.0, - border_color: palette.background.strong.color, - selected_text_color: palette.primary.strong.text, - selected_background: palette.primary.strong.color.into(), + menu::Appearance { + text_color: palette.background.weak.text, + background: palette.background.weak.color.into(), + border_width: 1.0, + border_radius: 0.0, + border_color: palette.background.strong.color, + selected_text_color: palette.primary.strong.text, + selected_background: palette.primary.strong.color.into(), + } + } + Menu::Custom(custom) => custom.appearance(self), } } } -/* - * Pick List - */ +impl From<PickList> for Menu { + fn from(pick_list: PickList) -> Self { + match pick_list { + PickList::Default => Self::Default, + PickList::Custom(_, menu) => Self::Custom(menu), + } + } +} + +/// The style of a pick list. +#[derive(Clone, Default)] +pub enum PickList { + /// The default style. + #[default] + Default, + /// A custom style. + Custom( + Rc<dyn pick_list::StyleSheet<Style = Theme>>, + Rc<dyn menu::StyleSheet<Style = Theme>>, + ), +} + impl pick_list::StyleSheet for Theme { - type Style = (); + type Style = PickList; - fn active(&self, _style: ()) -> pick_list::Appearance { - let palette = self.extended_palette(); + fn active(&self, style: &Self::Style) -> pick_list::Appearance { + match style { + PickList::Default => { + let palette = self.extended_palette(); - pick_list::Appearance { - text_color: palette.background.weak.text, - background: palette.background.weak.color.into(), - placeholder_color: palette.background.strong.color, - border_radius: 2.0, - border_width: 1.0, - border_color: palette.background.strong.color, - icon_size: 0.7, + pick_list::Appearance { + text_color: palette.background.weak.text, + background: palette.background.weak.color.into(), + placeholder_color: palette.background.strong.color, + border_radius: 2.0, + border_width: 1.0, + border_color: palette.background.strong.color, + icon_size: 0.7, + } + } + PickList::Custom(custom, _) => custom.active(self), } } - fn hovered(&self, _style: ()) -> pick_list::Appearance { - let palette = self.extended_palette(); + fn hovered(&self, style: &Self::Style) -> pick_list::Appearance { + match style { + PickList::Default => { + let palette = self.extended_palette(); - pick_list::Appearance { - text_color: palette.background.weak.text, - background: palette.background.weak.color.into(), - placeholder_color: palette.background.strong.color, - border_radius: 2.0, - border_width: 1.0, - border_color: palette.primary.strong.color, - icon_size: 0.7, + pick_list::Appearance { + text_color: palette.background.weak.text, + background: palette.background.weak.color.into(), + placeholder_color: palette.background.strong.color, + border_radius: 2.0, + border_width: 1.0, + border_color: palette.primary.strong.color, + icon_size: 0.7, + } + } + PickList::Custom(custom, _) => custom.hovered(self), } } } -/* - * Radio - */ +/// The style of a radio button. +#[derive(Default)] +pub enum Radio { + /// The default style. + #[default] + Default, + /// A custom style. + Custom(Box<dyn radio::StyleSheet<Style = Theme>>), +} + impl radio::StyleSheet for Theme { - type Style = (); + type Style = Radio; fn active( &self, - _style: Self::Style, - _is_selected: bool, + style: &Self::Style, + is_selected: bool, ) -> radio::Appearance { - let palette = self.extended_palette(); + match style { + Radio::Default => { + let palette = self.extended_palette(); - radio::Appearance { - background: Color::TRANSPARENT.into(), - dot_color: palette.primary.strong.color, - border_width: 1.0, - border_color: palette.primary.strong.color, - text_color: None, + radio::Appearance { + background: Color::TRANSPARENT.into(), + dot_color: palette.primary.strong.color, + border_width: 1.0, + border_color: palette.primary.strong.color, + text_color: None, + } + } + Radio::Custom(custom) => custom.active(self, is_selected), } } fn hovered( &self, - style: Self::Style, + style: &Self::Style, is_selected: bool, ) -> radio::Appearance { - let active = self.active(style, is_selected); - let palette = self.extended_palette(); + match style { + Radio::Default => { + let active = self.active(style, is_selected); + let palette = self.extended_palette(); - radio::Appearance { - dot_color: palette.primary.strong.color, - background: palette.primary.weak.color.into(), - ..active + radio::Appearance { + dot_color: palette.primary.strong.color, + background: palette.primary.weak.color.into(), + ..active + } + } + Radio::Custom(custom) => custom.hovered(self, is_selected), } } } -/* - * Toggler - */ +/// The style of a toggler. +#[derive(Default)] +pub enum Toggler { + /// The default style. + #[default] + Default, + /// A custom style. + Custom(Box<dyn toggler::StyleSheet<Style = Theme>>), +} + impl toggler::StyleSheet for Theme { - type Style = (); + type Style = Toggler; fn active( &self, - _style: Self::Style, + style: &Self::Style, is_active: bool, ) -> toggler::Appearance { - let palette = self.extended_palette(); + match style { + Toggler::Default => { + let palette = self.extended_palette(); - toggler::Appearance { - background: if is_active { - palette.primary.strong.color - } else { - palette.background.strong.color - }, - background_border: None, - foreground: if is_active { - palette.primary.strong.text - } else { - palette.background.base.color - }, - foreground_border: None, + toggler::Appearance { + background: if is_active { + palette.primary.strong.color + } else { + palette.background.strong.color + }, + background_border: None, + foreground: if is_active { + palette.primary.strong.text + } else { + palette.background.base.color + }, + foreground_border: None, + } + } + Toggler::Custom(custom) => custom.active(self, is_active), } } fn hovered( &self, - style: Self::Style, + style: &Self::Style, is_active: bool, ) -> toggler::Appearance { - let palette = self.extended_palette(); + match style { + Toggler::Default => { + let palette = self.extended_palette(); - toggler::Appearance { - foreground: if is_active { - Color { - a: 0.5, - ..palette.primary.strong.text + toggler::Appearance { + foreground: if is_active { + Color { + a: 0.5, + ..palette.primary.strong.text + } + } else { + palette.background.weak.color + }, + ..self.active(style, is_active) } - } else { - palette.background.weak.color - }, - ..self.active(style, is_active) + } + Toggler::Custom(custom) => custom.hovered(self, is_active), } } } -/* - * Pane Grid - */ +/// The style of a pane grid. +#[derive(Default)] +pub enum PaneGrid { + /// The default style. + #[default] + Default, + /// A custom style. + Custom(Box<dyn pane_grid::StyleSheet<Style = Theme>>), +} + impl pane_grid::StyleSheet for Theme { - type Style = (); + type Style = PaneGrid; - fn picked_split(&self, _style: Self::Style) -> Option<pane_grid::Line> { - let palette = self.extended_palette(); + fn picked_split(&self, style: &Self::Style) -> Option<pane_grid::Line> { + match style { + PaneGrid::Default => { + let palette = self.extended_palette(); - Some(pane_grid::Line { - color: palette.primary.strong.color, - width: 2.0, - }) + Some(pane_grid::Line { + color: palette.primary.strong.color, + width: 2.0, + }) + } + PaneGrid::Custom(custom) => custom.picked_split(self), + } } - fn hovered_split(&self, _style: Self::Style) -> Option<pane_grid::Line> { - let palette = self.extended_palette(); + fn hovered_split(&self, style: &Self::Style) -> Option<pane_grid::Line> { + match style { + PaneGrid::Default => { + let palette = self.extended_palette(); - Some(pane_grid::Line { - color: palette.primary.base.color, - width: 2.0, - }) + Some(pane_grid::Line { + color: palette.primary.base.color, + width: 2.0, + }) + } + PaneGrid::Custom(custom) => custom.hovered_split(self), + } } } -/* - * Progress Bar - */ -#[derive(Clone, Copy)] +/// The style of a progress bar. +#[derive(Default)] pub enum ProgressBar { + /// The primary style. + #[default] Primary, + /// The success style. Success, + /// The danger style. Danger, - Custom(fn(&Theme) -> progress_bar::Appearance), + /// A custom style. + Custom(Box<dyn progress_bar::StyleSheet<Style = Theme>>), } -impl Default for ProgressBar { - fn default() -> Self { - Self::Primary +impl From<fn(&Theme) -> progress_bar::Appearance> for ProgressBar { + fn from(f: fn(&Theme) -> progress_bar::Appearance) -> Self { + Self::Custom(Box::new(f)) } } impl progress_bar::StyleSheet for Theme { type Style = ProgressBar; - fn appearance(&self, style: Self::Style) -> progress_bar::Appearance { + fn appearance(&self, style: &Self::Style) -> progress_bar::Appearance { + if let ProgressBar::Custom(custom) = style { + return custom.appearance(self); + } + let palette = self.extended_palette(); let from_palette = |bar: Color| progress_bar::Appearance { @@ -555,30 +769,39 @@ impl progress_bar::StyleSheet for Theme { ProgressBar::Primary => from_palette(palette.primary.base.color), ProgressBar::Success => from_palette(palette.success.base.color), ProgressBar::Danger => from_palette(palette.danger.base.color), - ProgressBar::Custom(f) => f(self), + ProgressBar::Custom(custom) => custom.appearance(self), } } } -/* - * Rule - */ -#[derive(Clone, Copy)] +impl progress_bar::StyleSheet for fn(&Theme) -> progress_bar::Appearance { + type Style = Theme; + + fn appearance(&self, style: &Self::Style) -> progress_bar::Appearance { + (self)(style) + } +} + +/// The style of a rule. +#[derive(Default)] pub enum Rule { + /// The default style. + #[default] Default, - Custom(fn(&Theme) -> rule::Appearance), + /// A custom style. + Custom(Box<dyn rule::StyleSheet<Style = Theme>>), } -impl Default for Rule { - fn default() -> Self { - Self::Default +impl From<fn(&Theme) -> rule::Appearance> for Rule { + fn from(f: fn(&Theme) -> rule::Appearance) -> Self { + Self::Custom(Box::new(f)) } } impl rule::StyleSheet for Theme { type Style = Rule; - fn style(&self, style: Self::Style) -> rule::Appearance { + fn appearance(&self, style: &Self::Style) -> rule::Appearance { let palette = self.extended_palette(); match style { @@ -588,66 +811,130 @@ impl rule::StyleSheet for Theme { radius: 0.0, fill_mode: rule::FillMode::Full, }, - Rule::Custom(f) => f(self), + Rule::Custom(custom) => custom.appearance(self), } } } -/* - * Scrollable +impl rule::StyleSheet for fn(&Theme) -> rule::Appearance { + type Style = Theme; + + fn appearance(&self, style: &Self::Style) -> rule::Appearance { + (self)(style) + } +} + +/** + * Svg */ +#[derive(Default)] +pub enum Svg { + /// No filtering to the rendered SVG. + #[default] + Default, + /// A custom style. + Custom(Box<dyn svg::StyleSheet<Style = Theme>>), +} + +impl Svg { + /// Creates a custom [`Svg`] style. + pub fn custom_fn(f: fn(&Theme) -> svg::Appearance) -> Self { + Self::Custom(Box::new(f)) + } +} + +impl svg::StyleSheet for Theme { + type Style = Svg; + + fn appearance(&self, style: &Self::Style) -> svg::Appearance { + match style { + Svg::Default => Default::default(), + Svg::Custom(custom) => custom.appearance(self), + } + } +} + +impl svg::StyleSheet for fn(&Theme) -> svg::Appearance { + type Style = Theme; + + fn appearance(&self, style: &Self::Style) -> svg::Appearance { + (self)(style) + } +} + +/// The style of a scrollable. +#[derive(Default)] +pub enum Scrollable { + /// The default style. + #[default] + Default, + /// A custom style. + Custom(Box<dyn scrollable::StyleSheet<Style = Theme>>), +} + impl scrollable::StyleSheet for Theme { - type Style = (); + type Style = Scrollable; - fn active(&self, _style: Self::Style) -> scrollable::Scrollbar { - let palette = self.extended_palette(); + fn active(&self, style: &Self::Style) -> scrollable::Scrollbar { + match style { + Scrollable::Default => { + let palette = self.extended_palette(); - scrollable::Scrollbar { - background: palette.background.weak.color.into(), - border_radius: 2.0, - border_width: 0.0, - border_color: Color::TRANSPARENT, - scroller: scrollable::Scroller { - color: palette.background.strong.color, - border_radius: 2.0, - border_width: 0.0, - border_color: Color::TRANSPARENT, - }, + scrollable::Scrollbar { + background: palette.background.weak.color.into(), + border_radius: 2.0, + border_width: 0.0, + border_color: Color::TRANSPARENT, + scroller: scrollable::Scroller { + color: palette.background.strong.color, + border_radius: 2.0, + border_width: 0.0, + border_color: Color::TRANSPARENT, + }, + } + } + Scrollable::Custom(custom) => custom.active(self), } } - fn hovered(&self, _style: Self::Style) -> scrollable::Scrollbar { - let palette = self.extended_palette(); + fn hovered(&self, style: &Self::Style) -> scrollable::Scrollbar { + match style { + Scrollable::Default => { + let palette = self.extended_palette(); - scrollable::Scrollbar { - background: palette.background.weak.color.into(), - border_radius: 2.0, - border_width: 0.0, - border_color: Color::TRANSPARENT, - scroller: scrollable::Scroller { - color: palette.primary.strong.color, - border_radius: 2.0, - border_width: 0.0, - border_color: Color::TRANSPARENT, - }, + scrollable::Scrollbar { + background: palette.background.weak.color.into(), + border_radius: 2.0, + border_width: 0.0, + border_color: Color::TRANSPARENT, + scroller: scrollable::Scroller { + color: palette.primary.strong.color, + border_radius: 2.0, + border_width: 0.0, + border_color: Color::TRANSPARENT, + }, + } + } + Scrollable::Custom(custom) => custom.hovered(self), + } + } + + fn dragging(&self, style: &Self::Style) -> scrollable::Scrollbar { + match style { + Scrollable::Default => self.hovered(style), + Scrollable::Custom(custom) => custom.dragging(self), } } } -/* - * Text - */ -#[derive(Clone, Copy)] +/// The style of text. +#[derive(Clone, Copy, Default)] pub enum Text { + /// The default style. + #[default] Default, + /// Colored text. Color(Color), - Custom(fn(&Theme) -> text::Appearance), -} - -impl Default for Text { - fn default() -> Self { - Self::Default - } } impl From<Color> for Text { @@ -663,18 +950,28 @@ impl text::StyleSheet for Theme { match style { Text::Default => Default::default(), Text::Color(c) => text::Appearance { color: Some(c) }, - Text::Custom(f) => f(self), } } } -/* - * Text Input - */ +/// The style of a text input. +#[derive(Default)] +pub enum TextInput { + /// The default style. + #[default] + Default, + /// A custom style. + Custom(Box<dyn text_input::StyleSheet<Style = Theme>>), +} + impl text_input::StyleSheet for Theme { - type Style = (); + type Style = TextInput; + + fn active(&self, style: &Self::Style) -> text_input::Appearance { + if let TextInput::Custom(custom) = style { + return custom.active(self); + } - fn active(&self, _style: Self::Style) -> text_input::Appearance { let palette = self.extended_palette(); text_input::Appearance { @@ -685,7 +982,11 @@ impl text_input::StyleSheet for Theme { } } - fn hovered(&self, _style: Self::Style) -> text_input::Appearance { + fn hovered(&self, style: &Self::Style) -> text_input::Appearance { + if let TextInput::Custom(custom) = style { + return custom.hovered(self); + } + let palette = self.extended_palette(); text_input::Appearance { @@ -696,7 +997,11 @@ impl text_input::StyleSheet for Theme { } } - fn focused(&self, _style: Self::Style) -> text_input::Appearance { + fn focused(&self, style: &Self::Style) -> text_input::Appearance { + if let TextInput::Custom(custom) = style { + return custom.focused(self); + } + let palette = self.extended_palette(); text_input::Appearance { @@ -707,19 +1012,31 @@ impl text_input::StyleSheet for Theme { } } - fn placeholder_color(&self, _style: Self::Style) -> Color { + fn placeholder_color(&self, style: &Self::Style) -> Color { + if let TextInput::Custom(custom) = style { + return custom.placeholder_color(self); + } + let palette = self.extended_palette(); palette.background.strong.color } - fn value_color(&self, _style: Self::Style) -> Color { + fn value_color(&self, style: &Self::Style) -> Color { + if let TextInput::Custom(custom) = style { + return custom.value_color(self); + } + let palette = self.extended_palette(); palette.background.base.text } - fn selection_color(&self, _style: Self::Style) -> Color { + fn selection_color(&self, style: &Self::Style) -> Color { + if let TextInput::Custom(custom) = style { + return custom.selection_color(self); + } + let palette = self.extended_palette(); palette.primary.weak.color |