Introduce Custom variants for every style in the built-in Theme

This commit is contained in:
Héctor Ramón Jiménez 2022-11-09 04:05:31 +01:00
parent 8102f96f12
commit 18fb74f200
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
34 changed files with 576 additions and 286 deletions

View file

@ -79,10 +79,14 @@ impl Application for SolarSystem {
} }
fn style(&self) -> theme::Application { fn style(&self) -> theme::Application {
theme::Application::Custom(|_theme| application::Appearance { fn dark_background(_theme: &Theme) -> application::Appearance {
background_color: Color::BLACK, application::Appearance {
text_color: Color::WHITE, background_color: Color::BLACK,
}) text_color: Color::WHITE,
}
}
theme::Application::from(dark_background as fn(&Theme) -> _)
} }
fn subscription(&self) -> Subscription<Message> { fn subscription(&self) -> Subscription<Message> {

View file

@ -178,7 +178,7 @@ where
font, font,
text_size, text_size,
padding, padding,
style, style: style.clone(),
})); }));
state.tree.diff(&container as &dyn Widget<_, _>); state.tree.diff(&container as &dyn Widget<_, _>);
@ -288,7 +288,7 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
) { ) {
let appearance = theme.appearance(self.style); let appearance = theme.appearance(&self.style);
let bounds = layout.bounds(); let bounds = layout.bounds();
renderer.fill_quad( renderer.fill_quad(
@ -460,7 +460,7 @@ where
_cursor_position: Point, _cursor_position: Point,
viewport: &Rectangle, viewport: &Rectangle,
) { ) {
let appearance = theme.appearance(self.style); let appearance = theme.appearance(&self.style);
let bounds = layout.bounds(); let bounds = layout.bounds();
let text_size = let text_size =

View file

@ -231,7 +231,7 @@ where
cursor_position, cursor_position,
self.on_press.is_some(), self.on_press.is_some(),
theme, theme,
self.style, &self.style,
|| tree.state.downcast_ref::<State>(), || tree.state.downcast_ref::<State>(),
); );
@ -361,7 +361,7 @@ pub fn draw<'a, Renderer: crate::Renderer>(
style_sheet: &dyn StyleSheet< style_sheet: &dyn StyleSheet<
Style = <Renderer::Theme as StyleSheet>::Style, Style = <Renderer::Theme as StyleSheet>::Style,
>, >,
style: <Renderer::Theme as StyleSheet>::Style, style: &<Renderer::Theme as StyleSheet>::Style,
state: impl FnOnce() -> &'a State, state: impl FnOnce() -> &'a State,
) -> Appearance ) -> Appearance
where where

View file

@ -224,9 +224,9 @@ where
let mut children = layout.children(); let mut children = layout.children();
let custom_style = if is_mouse_over { let custom_style = if is_mouse_over {
theme.hovered(self.style, self.is_checked) theme.hovered(&self.style, self.is_checked)
} else { } else {
theme.active(self.style, self.is_checked) theme.active(&self.style, self.is_checked)
}; };
{ {

View file

@ -228,7 +228,7 @@ where
cursor_position: Point, cursor_position: Point,
viewport: &Rectangle, viewport: &Rectangle,
) { ) {
let style = theme.appearance(self.style); let style = theme.appearance(&self.style);
draw_background(renderer, &style, layout.bounds()); draw_background(renderer, &style, layout.bounds());

View file

@ -1,4 +1,5 @@
//! Helper functions to create pure widgets. //! Helper functions to create pure widgets.
use crate::overlay;
use crate::widget; use crate::widget;
use crate::{Element, Length}; use crate::{Element, Length};
@ -84,6 +85,7 @@ pub fn button<'a, Message, Renderer>(
where where
Renderer: crate::Renderer, Renderer: crate::Renderer,
Renderer::Theme: widget::button::StyleSheet, Renderer::Theme: widget::button::StyleSheet,
<Renderer::Theme as widget::button::StyleSheet>::Style: Default,
{ {
widget::Button::new(content) widget::Button::new(content)
} }
@ -208,7 +210,12 @@ where
T: ToString + Eq + 'static, T: ToString + Eq + 'static,
[T]: ToOwned<Owned = Vec<T>>, [T]: ToOwned<Owned = Vec<T>>,
Renderer: crate::text::Renderer, Renderer: crate::text::Renderer,
Renderer::Theme: widget::pick_list::StyleSheet, Renderer::Theme: widget::pick_list::StyleSheet
+ widget::scrollable::StyleSheet
+ overlay::menu::StyleSheet
+ widget::container::StyleSheet,
<Renderer::Theme as overlay::menu::StyleSheet>::Style:
From<<Renderer::Theme as widget::pick_list::StyleSheet>::Style>,
{ {
widget::PickList::new(options, selected, on_selected) widget::PickList::new(options, selected, on_selected)
} }

View file

@ -401,7 +401,7 @@ where
viewport, viewport,
self.spacing, self.spacing,
self.on_resize.as_ref().map(|(leeway, _)| *leeway), self.on_resize.as_ref().map(|(leeway, _)| *leeway),
self.style, &self.style,
self.contents self.contents
.iter() .iter()
.zip(&tree.children) .zip(&tree.children)
@ -727,7 +727,7 @@ pub fn draw<Renderer, T>(
viewport: &Rectangle, viewport: &Rectangle,
spacing: u16, spacing: u16,
resize_leeway: Option<u16>, resize_leeway: Option<u16>,
style: <Renderer::Theme as StyleSheet>::Style, style: &<Renderer::Theme as StyleSheet>::Style,
contents: impl Iterator<Item = (Pane, T)>, contents: impl Iterator<Item = (Pane, T)>,
draw_pane: impl Fn( draw_pane: impl Fn(
T, T,

View file

@ -103,7 +103,7 @@ where
let bounds = layout.bounds(); let bounds = layout.bounds();
{ {
let style = theme.appearance(self.style); let style = theme.appearance(&self.style);
container::draw_background(renderer, &style, bounds); container::draw_background(renderer, &style, bounds);
} }

View file

@ -129,7 +129,7 @@ where
use container::StyleSheet; use container::StyleSheet;
let bounds = layout.bounds(); let bounds = layout.bounds();
let style = theme.appearance(self.style); let style = theme.appearance(&self.style);
let inherited_style = renderer::Style { let inherited_style = renderer::Style {
text_color: style.text_color.unwrap_or(inherited_style.text_color), text_color: style.text_color.unwrap_or(inherited_style.text_color),
}; };

View file

@ -9,6 +9,8 @@ use crate::overlay::menu::{self, Menu};
use crate::renderer; use crate::renderer;
use crate::text::{self, Text}; use crate::text::{self, Text};
use crate::touch; use crate::touch;
use crate::widget::container;
use crate::widget::scrollable;
use crate::widget::tree::{self, Tree}; use crate::widget::tree::{self, Tree};
use crate::{ use crate::{
Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Size, Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Size,
@ -42,7 +44,12 @@ where
T: ToString + Eq, T: ToString + Eq,
[T]: ToOwned<Owned = Vec<T>>, [T]: ToOwned<Owned = Vec<T>>,
Renderer: text::Renderer, Renderer: text::Renderer,
Renderer::Theme: StyleSheet, Renderer::Theme: StyleSheet
+ scrollable::StyleSheet
+ menu::StyleSheet
+ container::StyleSheet,
<Renderer::Theme as menu::StyleSheet>::Style:
From<<Renderer::Theme as StyleSheet>::Style>,
{ {
/// The default padding of a [`PickList`]. /// The default padding of a [`PickList`].
pub const DEFAULT_PADDING: Padding = Padding::new(5); pub const DEFAULT_PADDING: Padding = Padding::new(5);
@ -114,7 +121,12 @@ where
[T]: ToOwned<Owned = Vec<T>>, [T]: ToOwned<Owned = Vec<T>>,
Message: 'a, Message: 'a,
Renderer: text::Renderer + 'a, Renderer: text::Renderer + 'a,
Renderer::Theme: StyleSheet, Renderer::Theme: StyleSheet
+ scrollable::StyleSheet
+ menu::StyleSheet
+ container::StyleSheet,
<Renderer::Theme as menu::StyleSheet>::Style:
From<<Renderer::Theme as StyleSheet>::Style>,
{ {
fn tag(&self) -> tree::Tag { fn tag(&self) -> tree::Tag {
tree::Tag::of::<State<T>>() tree::Tag::of::<State<T>>()
@ -202,7 +214,7 @@ where
&self.font, &self.font,
self.placeholder.as_deref(), self.placeholder.as_deref(),
self.selected.as_ref(), self.selected.as_ref(),
self.style, &self.style,
) )
} }
@ -221,7 +233,7 @@ where
self.text_size, self.text_size,
self.font.clone(), self.font.clone(),
&self.options, &self.options,
self.style, self.style.clone(),
) )
} }
} }
@ -233,7 +245,12 @@ where
[T]: ToOwned<Owned = Vec<T>>, [T]: ToOwned<Owned = Vec<T>>,
Message: 'a, Message: 'a,
Renderer: text::Renderer + 'a, Renderer: text::Renderer + 'a,
Renderer::Theme: StyleSheet, Renderer::Theme: StyleSheet
+ scrollable::StyleSheet
+ menu::StyleSheet
+ container::StyleSheet,
<Renderer::Theme as menu::StyleSheet>::Style:
From<<Renderer::Theme as StyleSheet>::Style>,
{ {
fn from(pick_list: PickList<'a, T, Message, Renderer>) -> Self { fn from(pick_list: PickList<'a, T, Message, Renderer>) -> Self {
Self::new(pick_list) Self::new(pick_list)
@ -456,7 +473,12 @@ where
T: Clone + ToString, T: Clone + ToString,
Message: 'a, Message: 'a,
Renderer: text::Renderer + 'a, Renderer: text::Renderer + 'a,
Renderer::Theme: StyleSheet, Renderer::Theme: StyleSheet
+ scrollable::StyleSheet
+ menu::StyleSheet
+ container::StyleSheet,
<Renderer::Theme as menu::StyleSheet>::Style:
From<<Renderer::Theme as StyleSheet>::Style>,
{ {
if state.is_open { if state.is_open {
let bounds = layout.bounds(); let bounds = layout.bounds();
@ -493,7 +515,7 @@ pub fn draw<T, Renderer>(
font: &Renderer::Font, font: &Renderer::Font,
placeholder: Option<&str>, placeholder: Option<&str>,
selected: Option<&T>, selected: Option<&T>,
style: <Renderer::Theme as StyleSheet>::Style, style: &<Renderer::Theme as StyleSheet>::Style,
) where ) where
Renderer: text::Renderer, Renderer: text::Renderer,
Renderer::Theme: StyleSheet, Renderer::Theme: StyleSheet,

View file

@ -124,7 +124,7 @@ where
/ (range_end - range_start) / (range_end - range_start)
}; };
let style = theme.appearance(self.style); let style = theme.appearance(&self.style);
renderer.fill_quad( renderer.fill_quad(
renderer::Quad { renderer::Quad {

View file

@ -230,9 +230,9 @@ where
let mut children = layout.children(); let mut children = layout.children();
let custom_style = if is_mouse_over { let custom_style = if is_mouse_over {
theme.hovered(self.style, self.is_selected) theme.hovered(&self.style, self.is_selected)
} else { } else {
theme.active(self.style, self.is_selected) theme.active(&self.style, self.is_selected)
}; };
{ {

View file

@ -88,7 +88,7 @@ where
_viewport: &Rectangle, _viewport: &Rectangle,
) { ) {
let bounds = layout.bounds(); let bounds = layout.bounds();
let style = theme.style(self.style); let style = theme.appearance(&self.style);
let bounds = if self.is_horizontal { let bounds = if self.is_horizontal {
let line_y = (bounds.y + (bounds.height / 2.0) let line_y = (bounds.y + (bounds.height / 2.0)

View file

@ -233,7 +233,7 @@ where
self.scrollbar_width, self.scrollbar_width,
self.scrollbar_margin, self.scrollbar_margin,
self.scroller_width, self.scroller_width,
self.style, &self.style,
|renderer, layout, cursor_position, viewport| { |renderer, layout, cursor_position, viewport| {
self.content.as_widget().draw( self.content.as_widget().draw(
&tree.children[0], &tree.children[0],
@ -627,7 +627,7 @@ pub fn draw<Renderer>(
scrollbar_width: u16, scrollbar_width: u16,
scrollbar_margin: u16, scrollbar_margin: u16,
scroller_width: u16, scroller_width: u16,
style: <Renderer::Theme as StyleSheet>::Style, style: &<Renderer::Theme as StyleSheet>::Style,
draw_content: impl FnOnce(&mut Renderer, Layout<'_>, Point, &Rectangle), draw_content: impl FnOnce(&mut Renderer, Layout<'_>, Point, &Rectangle),
) where ) where
Renderer: crate::Renderer, Renderer: crate::Renderer,

View file

@ -222,7 +222,7 @@ where
self.value, self.value,
&self.range, &self.range,
theme, theme,
self.style, &self.style,
) )
} }
@ -353,7 +353,7 @@ pub fn draw<T, R>(
value: T, value: T,
range: &RangeInclusive<T>, range: &RangeInclusive<T>,
style_sheet: &dyn StyleSheet<Style = <R::Theme as StyleSheet>::Style>, style_sheet: &dyn StyleSheet<Style = <R::Theme as StyleSheet>::Style>,
style: <R::Theme as StyleSheet>::Style, style: &<R::Theme as StyleSheet>::Style,
) where ) where
T: Into<f64> + Copy, T: Into<f64> + Copy,
R: crate::Renderer, R: crate::Renderer,
@ -363,11 +363,11 @@ pub fn draw<T, R>(
let is_mouse_over = bounds.contains(cursor_position); let is_mouse_over = bounds.contains(cursor_position);
let style = if state.is_dragging { let style = if state.is_dragging {
style_sheet.dragging(style) style_sheet.dragging(&style)
} else if is_mouse_over { } else if is_mouse_over {
style_sheet.hovered(style) style_sheet.hovered(&style)
} else { } else {
style_sheet.active(style) style_sheet.active(&style)
}; };
let rail_y = bounds.y + (bounds.height / 2.0).round(); let rail_y = bounds.y + (bounds.height / 2.0).round();

View file

@ -188,7 +188,7 @@ where
self.size, self.size,
&self.font, &self.font,
self.is_secure, self.is_secure,
self.style, &self.style,
) )
} }
} }
@ -284,7 +284,7 @@ where
self.size, self.size,
&self.font, &self.font,
self.is_secure, self.is_secure,
self.style, &self.style,
) )
} }
@ -746,7 +746,7 @@ pub fn draw<Renderer>(
size: Option<u16>, size: Option<u16>,
font: &Renderer::Font, font: &Renderer::Font,
is_secure: bool, is_secure: bool,
style: <Renderer::Theme as StyleSheet>::Style, style: &<Renderer::Theme as StyleSheet>::Style,
) where ) where
Renderer: text::Renderer, Renderer: text::Renderer,
Renderer::Theme: StyleSheet, Renderer::Theme: StyleSheet,

View file

@ -260,9 +260,9 @@ where
let is_mouse_over = bounds.contains(cursor_position); let is_mouse_over = bounds.contains(cursor_position);
let style = if is_mouse_over { let style = if is_mouse_over {
theme.hovered(self.style, self.is_active) theme.hovered(&self.style, self.is_active)
} else { } else {
theme.active(self.style, self.is_active) theme.active(&self.style, self.is_active)
}; };
let border_radius = bounds.height as f32 / BORDER_RADIUS_RATIO; let border_radius = bounds.height as f32 / BORDER_RADIUS_RATIO;

View file

@ -201,7 +201,7 @@ where
self.gap, self.gap,
self.padding, self.padding,
self.snap_within_viewport, self.snap_within_viewport,
self.style, &self.style,
|renderer, limits| { |renderer, limits| {
Widget::<(), Renderer>::layout(tooltip, renderer, limits) Widget::<(), Renderer>::layout(tooltip, renderer, limits)
}, },
@ -275,7 +275,7 @@ pub fn draw<Renderer>(
gap: u16, gap: u16,
padding: u16, padding: u16,
snap_within_viewport: bool, snap_within_viewport: bool,
style: <Renderer::Theme as container::StyleSheet>::Style, style: &<Renderer::Theme as container::StyleSheet>::Style,
layout_text: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node, layout_text: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node,
draw_text: impl FnOnce( draw_text: impl FnOnce(
&mut Renderer, &mut Renderer,

View file

@ -1,9 +1,9 @@
use iced_core::Color; use iced_core::Color;
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
fn appearance(&self, style: Self::Style) -> Appearance; fn appearance(&self, style: &Self::Style) -> Appearance;
} }
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]

View file

@ -27,11 +27,11 @@ impl std::default::Default for Appearance {
/// A set of rules that dictate the style of a button. /// A set of rules that dictate the style of a button.
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
fn active(&self, style: Self::Style) -> Appearance; fn active(&self, style: &Self::Style) -> Appearance;
fn hovered(&self, style: Self::Style) -> Appearance { fn hovered(&self, style: &Self::Style) -> Appearance {
let active = self.active(style); let active = self.active(style);
Appearance { Appearance {
@ -40,14 +40,14 @@ pub trait StyleSheet {
} }
} }
fn pressed(&self, style: Self::Style) -> Appearance { fn pressed(&self, style: &Self::Style) -> Appearance {
Appearance { Appearance {
shadow_offset: Vector::default(), shadow_offset: Vector::default(),
..self.active(style) ..self.active(style)
} }
} }
fn disabled(&self, style: Self::Style) -> Appearance { fn disabled(&self, style: &Self::Style) -> Appearance {
let active = self.active(style); let active = self.active(style);
Appearance { Appearance {

View file

@ -14,9 +14,9 @@ pub struct Appearance {
/// A set of rules that dictate the style of a checkbox. /// A set of rules that dictate the style of a checkbox.
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
fn active(&self, style: Self::Style, is_checked: bool) -> Appearance; fn active(&self, style: &Self::Style, is_checked: bool) -> Appearance;
fn hovered(&self, style: Self::Style, is_checked: bool) -> Appearance; fn hovered(&self, style: &Self::Style, is_checked: bool) -> Appearance;
} }

View file

@ -25,8 +25,8 @@ impl std::default::Default for Appearance {
/// A set of rules that dictate the [`Appearance`] of a container. /// A set of rules that dictate the [`Appearance`] of a container.
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
/// Produces the [`Appearance`] of a container. /// Produces the [`Appearance`] of a container.
fn appearance(&self, style: Self::Style) -> Appearance; fn appearance(&self, style: &Self::Style) -> Appearance;
} }

View file

@ -13,7 +13,7 @@ pub struct Appearance {
} }
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default + Clone;
fn appearance(&self, style: Self::Style) -> Appearance; fn appearance(&self, style: &Self::Style) -> Appearance;
} }

View file

@ -4,13 +4,13 @@ use iced_core::Color;
/// A set of rules that dictate the style of a container. /// A set of rules that dictate the style of a container.
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
/// The [`Line`] to draw when a split is picked. /// The [`Line`] to draw when a split is picked.
fn picked_split(&self, style: Self::Style) -> Option<Line>; fn picked_split(&self, style: &Self::Style) -> Option<Line>;
/// The [`Line`] to draw when a split is hovered. /// The [`Line`] to draw when a split is hovered.
fn hovered_split(&self, style: Self::Style) -> Option<Line>; fn hovered_split(&self, style: &Self::Style) -> Option<Line>;
} }
/// A line. /// A line.

View file

@ -1,9 +1,5 @@
use iced_core::{Background, Color}; use iced_core::{Background, Color};
use crate::container;
use crate::menu;
use crate::scrollable;
/// The appearance of a pick list. /// The appearance of a pick list.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Appearance { pub struct Appearance {
@ -17,13 +13,10 @@ pub struct Appearance {
} }
/// A set of rules that dictate the style of a container. /// A set of rules that dictate the style of a container.
pub trait StyleSheet: pub trait StyleSheet {
container::StyleSheet + menu::StyleSheet + scrollable::StyleSheet type Style: Default + Clone;
{
type Style: Default + Copy + Into<<Self as menu::StyleSheet>::Style>;
fn active(&self, style: <Self as StyleSheet>::Style) -> Appearance; fn active(&self, style: &<Self as StyleSheet>::Style) -> Appearance;
/// Produces the style of a container. fn hovered(&self, style: &<Self as StyleSheet>::Style) -> Appearance;
fn hovered(&self, style: <Self as StyleSheet>::Style) -> Appearance;
} }

View file

@ -11,7 +11,7 @@ pub struct Appearance {
/// A set of rules that dictate the style of a progress bar. /// A set of rules that dictate the style of a progress bar.
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
fn appearance(&self, style: Self::Style) -> Appearance; fn appearance(&self, style: &Self::Style) -> Appearance;
} }

View file

@ -13,9 +13,9 @@ pub struct Appearance {
/// A set of rules that dictate the style of a radio button. /// A set of rules that dictate the style of a radio button.
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
fn active(&self, style: Self::Style, is_selected: bool) -> Appearance; fn active(&self, style: &Self::Style, is_selected: bool) -> Appearance;
fn hovered(&self, style: Self::Style, is_selected: bool) -> Appearance; fn hovered(&self, style: &Self::Style, is_selected: bool) -> Appearance;
} }

View file

@ -16,10 +16,10 @@ pub struct Appearance {
/// A set of rules that dictate the style of a rule. /// A set of rules that dictate the style of a rule.
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
/// Produces the style of a rule. /// Produces the style of a rule.
fn style(&self, style: Self::Style) -> Appearance; fn appearance(&self, style: &Self::Style) -> Appearance;
} }
/// The fill mode of a rule. /// The fill mode of a rule.

View file

@ -22,16 +22,16 @@ pub struct Scroller {
/// A set of rules that dictate the style of a scrollable. /// A set of rules that dictate the style of a scrollable.
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
/// Produces the style of an active scrollbar. /// Produces the style of an active scrollbar.
fn active(&self, style: Self::Style) -> Scrollbar; fn active(&self, style: &Self::Style) -> Scrollbar;
/// Produces the style of an hovered scrollbar. /// Produces the style of an hovered scrollbar.
fn hovered(&self, style: Self::Style) -> Scrollbar; fn hovered(&self, style: &Self::Style) -> Scrollbar;
/// Produces the style of a scrollbar that is being dragged. /// Produces the style of a scrollbar that is being dragged.
fn dragging(&self, style: Self::Style) -> Scrollbar { fn dragging(&self, style: &Self::Style) -> Scrollbar {
self.hovered(style) self.hovered(style)
} }
} }

View file

@ -26,14 +26,14 @@ pub enum HandleShape {
/// A set of rules that dictate the style of a slider. /// A set of rules that dictate the style of a slider.
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
/// Produces the style of an active slider. /// Produces the style of an active slider.
fn active(&self, style: Self::Style) -> Appearance; fn active(&self, style: &Self::Style) -> Appearance;
/// Produces the style of an hovered slider. /// Produces the style of an hovered slider.
fn hovered(&self, style: Self::Style) -> Appearance; fn hovered(&self, style: &Self::Style) -> Appearance;
/// Produces the style of a slider that is being dragged. /// Produces the style of a slider that is being dragged.
fn dragging(&self, style: Self::Style) -> Appearance; fn dragging(&self, style: &Self::Style) -> Appearance;
} }

View file

@ -12,22 +12,22 @@ pub struct Appearance {
/// A set of rules that dictate the style of a text input. /// A set of rules that dictate the style of a text input.
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
/// Produces the style of an active text input. /// Produces the style of an active text input.
fn active(&self, style: Self::Style) -> Appearance; fn active(&self, style: &Self::Style) -> Appearance;
/// Produces the style of a focused text input. /// Produces the style of a focused text input.
fn focused(&self, style: Self::Style) -> Appearance; fn focused(&self, style: &Self::Style) -> Appearance;
fn placeholder_color(&self, style: Self::Style) -> Color; fn placeholder_color(&self, style: &Self::Style) -> Color;
fn value_color(&self, style: Self::Style) -> Color; fn value_color(&self, style: &Self::Style) -> Color;
fn selection_color(&self, style: Self::Style) -> Color; fn selection_color(&self, style: &Self::Style) -> Color;
/// Produces the style of an hovered text input. /// Produces the style of an hovered text input.
fn hovered(&self, style: Self::Style) -> Appearance { fn hovered(&self, style: &Self::Style) -> Appearance {
self.focused(style) self.focused(style)
} }
} }

View file

@ -19,7 +19,9 @@ use crate::text;
use crate::text_input; use crate::text_input;
use crate::toggler; use crate::toggler;
use iced_core::{Background, Color}; use iced_core::{Background, Color, Vector};
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Theme { pub enum Theme {
@ -71,10 +73,9 @@ impl Custom {
} }
} }
#[derive(Debug, Clone, Copy)]
pub enum Application { pub enum Application {
Default, Default,
Custom(fn(Theme) -> application::Appearance), Custom(Box<dyn application::StyleSheet<Style = Theme>>),
} }
impl Default for Application { impl Default for Application {
@ -86,7 +87,7 @@ impl Default for Application {
impl application::StyleSheet for Theme { impl application::StyleSheet for Theme {
type Style = Application; type Style = Application;
fn appearance(&self, style: Self::Style) -> application::Appearance { fn appearance(&self, style: &Self::Style) -> application::Appearance {
let palette = self.extended_palette(); let palette = self.extended_palette();
match style { match style {
@ -94,21 +95,35 @@ impl application::StyleSheet for Theme {
background_color: palette.background.base.color, background_color: palette.background.base.color,
text_color: palette.background.base.text, text_color: palette.background.base.text,
}, },
Application::Custom(f) => f(self.clone()), Application::Custom(custom) => custom.appearance(self),
} }
} }
} }
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))
}
}
/* /*
* Button * Button
*/ */
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Button { pub enum Button {
Primary, Primary,
Secondary, Secondary,
Positive, Positive,
Destructive, Destructive,
Text, Text,
Custom(Box<dyn button::StyleSheet<Style = Theme>>),
} }
impl Default for Button { impl Default for Button {
@ -120,7 +135,7 @@ impl Default for Button {
impl button::StyleSheet for Theme { impl button::StyleSheet for Theme {
type Style = Button; 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 palette = self.extended_palette();
let appearance = button::Appearance { let appearance = button::Appearance {
@ -143,19 +158,25 @@ impl button::StyleSheet for Theme {
text_color: palette.background.base.text, text_color: palette.background.base.text,
..appearance ..appearance
}, },
Button::Custom(custom) => custom.active(self),
} }
} }
fn hovered(&self, style: Self::Style) -> button::Appearance { fn hovered(&self, style: &Self::Style) -> button::Appearance {
let active = self.active(style);
let palette = self.extended_palette(); let palette = self.extended_palette();
if let Button::Custom(custom) = style {
return custom.hovered(self);
}
let active = self.active(style);
let background = match style { let background = match style {
Button::Primary => Some(palette.primary.base.color), Button::Primary => Some(palette.primary.base.color),
Button::Secondary => Some(palette.background.strong.color), Button::Secondary => Some(palette.background.strong.color),
Button::Positive => Some(palette.success.strong.color), Button::Positive => Some(palette.success.strong.color),
Button::Destructive => Some(palette.danger.strong.color), Button::Destructive => Some(palette.danger.strong.color),
Button::Text => None, Button::Text | Button::Custom(_) => None,
}; };
button::Appearance { button::Appearance {
@ -163,17 +184,51 @@ impl button::StyleSheet for Theme {
..active ..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 * Checkbox
*/ */
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Checkbox { pub enum Checkbox {
Primary, Primary,
Secondary, Secondary,
Success, Success,
Danger, Danger,
Custom(Box<dyn checkbox::StyleSheet<Style = Theme>>),
} }
impl Default for Checkbox { impl Default for Checkbox {
@ -187,7 +242,7 @@ impl checkbox::StyleSheet for Theme {
fn active( fn active(
&self, &self,
style: Self::Style, style: &Self::Style,
is_checked: bool, is_checked: bool,
) -> checkbox::Appearance { ) -> checkbox::Appearance {
let palette = self.extended_palette(); let palette = self.extended_palette();
@ -217,12 +272,13 @@ impl checkbox::StyleSheet for Theme {
palette.danger.base, palette.danger.base,
is_checked, is_checked,
), ),
Checkbox::Custom(custom) => custom.active(self, is_checked),
} }
} }
fn hovered( fn hovered(
&self, &self,
style: Self::Style, style: &Self::Style,
is_checked: bool, is_checked: bool,
) -> checkbox::Appearance { ) -> checkbox::Appearance {
let palette = self.extended_palette(); let palette = self.extended_palette();
@ -252,6 +308,7 @@ impl checkbox::StyleSheet for Theme {
palette.danger.base, palette.danger.base,
is_checked, is_checked,
), ),
Checkbox::Custom(custom) => custom.hovered(self, is_checked),
} }
} }
} }
@ -279,11 +336,10 @@ fn checkbox_appearance(
/* /*
* Container * Container
*/ */
#[derive(Clone, Copy)]
pub enum Container { pub enum Container {
Transparent, Transparent,
Box, Box,
Custom(fn(&Theme) -> container::Appearance), Custom(Box<dyn container::StyleSheet<Style = Theme>>),
} }
impl Default for Container { impl Default for Container {
@ -294,14 +350,14 @@ impl Default for Container {
impl From<fn(&Theme) -> container::Appearance> for Container { impl From<fn(&Theme) -> container::Appearance> for Container {
fn from(f: fn(&Theme) -> container::Appearance) -> Self { fn from(f: fn(&Theme) -> container::Appearance) -> Self {
Self::Custom(f) Self::Custom(Box::new(f))
} }
} }
impl container::StyleSheet for Theme { impl container::StyleSheet for Theme {
type Style = Container; type Style = Container;
fn appearance(&self, style: Self::Style) -> container::Appearance { fn appearance(&self, style: &Self::Style) -> container::Appearance {
match style { match style {
Container::Transparent => Default::default(), Container::Transparent => Default::default(),
Container::Box => { Container::Box => {
@ -315,63 +371,96 @@ impl container::StyleSheet for Theme {
border_color: Color::TRANSPARENT, border_color: Color::TRANSPARENT,
} }
} }
Container::Custom(f) => f(self), Container::Custom(custom) => custom.appearance(self),
} }
} }
} }
impl container::StyleSheet for fn(&Theme) -> container::Appearance {
type Style = Theme;
fn appearance(&self, style: &Self::Style) -> container::Appearance {
(self)(style)
}
}
/* /*
* Slider * Slider
*/ */
#[derive(Default)]
pub enum Slider {
#[default]
Default,
Custom(Box<dyn slider::StyleSheet<Style = Theme>>),
}
impl slider::StyleSheet for Theme { impl slider::StyleSheet for Theme {
type Style = (); type Style = Slider;
fn active(&self, _style: Self::Style) -> slider::Appearance { fn active(&self, style: &Self::Style) -> slider::Appearance {
let palette = self.extended_palette(); match style {
Slider::Default => {
let palette = self.extended_palette();
let handle = slider::Handle { let handle = slider::Handle {
shape: slider::HandleShape::Rectangle { shape: slider::HandleShape::Rectangle {
width: 8, width: 8,
border_radius: 4.0, border_radius: 4.0,
}, },
color: Color::WHITE, color: Color::WHITE,
border_color: Color::WHITE, border_color: Color::WHITE,
border_width: 1.0, border_width: 1.0,
}; };
slider::Appearance { slider::Appearance {
rail_colors: (palette.primary.base.color, Color::TRANSPARENT), rail_colors: (
handle: slider::Handle { palette.primary.base.color,
color: palette.background.base.color, Color::TRANSPARENT,
border_color: palette.primary.base.color, ),
..handle 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 { fn hovered(&self, style: &Self::Style) -> slider::Appearance {
let active = self.active(style); match style {
let palette = self.extended_palette(); Slider::Default => {
let active = self.active(style);
let palette = self.extended_palette();
slider::Appearance { slider::Appearance {
handle: slider::Handle { handle: slider::Handle {
color: palette.primary.weak.color, color: palette.primary.weak.color,
..active.handle ..active.handle
}, },
..active ..active
}
}
Slider::Custom(custom) => custom.hovered(self),
} }
} }
fn dragging(&self, style: Self::Style) -> slider::Appearance { fn dragging(&self, style: &Self::Style) -> slider::Appearance {
let active = self.active(style); match style {
let palette = self.extended_palette(); Slider::Default => {
let active = self.active(style);
let palette = self.extended_palette();
slider::Appearance { slider::Appearance {
handle: slider::Handle { handle: slider::Handle {
color: palette.primary.base.color, color: palette.primary.base.color,
..active.handle ..active.handle
}, },
..active ..active
}
}
Slider::Custom(custom) => custom.dragging(self),
} }
} }
} }
@ -379,20 +468,41 @@ impl slider::StyleSheet for Theme {
/* /*
* Menu * Menu
*/ */
#[derive(Clone, Default)]
pub enum Menu {
#[default]
Default,
Custom(Rc<dyn menu::StyleSheet<Style = Theme>>),
}
impl menu::StyleSheet for Theme { impl menu::StyleSheet for Theme {
type Style = (); type Style = Menu;
fn appearance(&self, _style: Self::Style) -> menu::Appearance { fn appearance(&self, style: &Self::Style) -> menu::Appearance {
let palette = self.extended_palette(); match style {
Menu::Default => {
let palette = self.extended_palette();
menu::Appearance { menu::Appearance {
text_color: palette.background.weak.text, text_color: palette.background.weak.text,
background: palette.background.weak.color.into(), background: palette.background.weak.color.into(),
border_width: 1.0, border_width: 1.0,
border_radius: 0.0, border_radius: 0.0,
border_color: palette.background.strong.color, border_color: palette.background.strong.color,
selected_text_color: palette.primary.strong.text, selected_text_color: palette.primary.strong.text,
selected_background: palette.primary.strong.color.into(), selected_background: palette.primary.strong.color.into(),
}
}
Menu::Custom(custom) => custom.appearance(self),
}
}
}
impl From<PickList> for Menu {
fn from(pick_list: PickList) -> Self {
match pick_list {
PickList::Default => Self::Default,
PickList::Custom(_, menu) => Self::Custom(menu),
} }
} }
} }
@ -400,34 +510,54 @@ impl menu::StyleSheet for Theme {
/* /*
* Pick List * Pick List
*/ */
#[derive(Clone, Default)]
pub enum PickList {
#[default]
Default,
Custom(
Rc<dyn pick_list::StyleSheet<Style = Theme>>,
Rc<dyn menu::StyleSheet<Style = Theme>>,
),
}
impl pick_list::StyleSheet for Theme { impl pick_list::StyleSheet for Theme {
type Style = (); type Style = PickList;
fn active(&self, _style: ()) -> pick_list::Appearance { fn active(&self, style: &Self::Style) -> pick_list::Appearance {
let palette = self.extended_palette(); match style {
PickList::Default => {
let palette = self.extended_palette();
pick_list::Appearance { pick_list::Appearance {
text_color: palette.background.weak.text, text_color: palette.background.weak.text,
background: palette.background.weak.color.into(), background: palette.background.weak.color.into(),
placeholder_color: palette.background.strong.color, placeholder_color: palette.background.strong.color,
border_radius: 2.0, border_radius: 2.0,
border_width: 1.0, border_width: 1.0,
border_color: palette.background.strong.color, border_color: palette.background.strong.color,
icon_size: 0.7, icon_size: 0.7,
}
}
PickList::Custom(custom, _) => custom.active(self),
} }
} }
fn hovered(&self, _style: ()) -> pick_list::Appearance { fn hovered(&self, style: &Self::Style) -> pick_list::Appearance {
let palette = self.extended_palette(); match style {
PickList::Default => {
let palette = self.extended_palette();
pick_list::Appearance { pick_list::Appearance {
text_color: palette.background.weak.text, text_color: palette.background.weak.text,
background: palette.background.weak.color.into(), background: palette.background.weak.color.into(),
placeholder_color: palette.background.strong.color, placeholder_color: palette.background.strong.color,
border_radius: 2.0, border_radius: 2.0,
border_width: 1.0, border_width: 1.0,
border_color: palette.primary.strong.color, border_color: palette.primary.strong.color,
icon_size: 0.7, icon_size: 0.7,
}
}
PickList::Custom(custom, _) => custom.active(self),
} }
} }
} }
@ -435,37 +565,54 @@ impl pick_list::StyleSheet for Theme {
/* /*
* Radio * Radio
*/ */
#[derive(Default)]
pub enum Radio {
#[default]
Default,
Custom(Box<dyn radio::StyleSheet<Style = Theme>>),
}
impl radio::StyleSheet for Theme { impl radio::StyleSheet for Theme {
type Style = (); type Style = Radio;
fn active( fn active(
&self, &self,
_style: Self::Style, style: &Self::Style,
_is_selected: bool, is_selected: bool,
) -> radio::Appearance { ) -> radio::Appearance {
let palette = self.extended_palette(); match style {
Radio::Default => {
let palette = self.extended_palette();
radio::Appearance { radio::Appearance {
background: Color::TRANSPARENT.into(), background: Color::TRANSPARENT.into(),
dot_color: palette.primary.strong.color, dot_color: palette.primary.strong.color,
border_width: 1.0, border_width: 1.0,
border_color: palette.primary.strong.color, border_color: palette.primary.strong.color,
text_color: None, text_color: None,
}
}
Radio::Custom(custom) => custom.active(self, is_selected),
} }
} }
fn hovered( fn hovered(
&self, &self,
style: Self::Style, style: &Self::Style,
is_selected: bool, is_selected: bool,
) -> radio::Appearance { ) -> radio::Appearance {
let active = self.active(style, is_selected); match style {
let palette = self.extended_palette(); Radio::Default => {
let active = self.active(style, is_selected);
let palette = self.extended_palette();
radio::Appearance { radio::Appearance {
dot_color: palette.primary.strong.color, dot_color: palette.primary.strong.color,
background: palette.primary.weak.color.into(), background: palette.primary.weak.color.into(),
..active ..active
}
}
Radio::Custom(custom) => custom.hovered(self, is_selected),
} }
} }
} }
@ -473,49 +620,66 @@ impl radio::StyleSheet for Theme {
/* /*
* Toggler * Toggler
*/ */
#[derive(Default)]
pub enum Toggler {
#[default]
Default,
Custom(Box<dyn toggler::StyleSheet<Style = Theme>>),
}
impl toggler::StyleSheet for Theme { impl toggler::StyleSheet for Theme {
type Style = (); type Style = Toggler;
fn active( fn active(
&self, &self,
_style: Self::Style, style: &Self::Style,
is_active: bool, is_active: bool,
) -> toggler::Appearance { ) -> toggler::Appearance {
let palette = self.extended_palette(); match style {
Toggler::Default => {
let palette = self.extended_palette();
toggler::Appearance { toggler::Appearance {
background: if is_active { background: if is_active {
palette.primary.strong.color palette.primary.strong.color
} else { } else {
palette.background.strong.color palette.background.strong.color
}, },
background_border: None, background_border: None,
foreground: if is_active { foreground: if is_active {
palette.primary.strong.text palette.primary.strong.text
} else { } else {
palette.background.base.color palette.background.base.color
}, },
foreground_border: None, foreground_border: None,
}
}
Toggler::Custom(custom) => custom.active(self, is_active),
} }
} }
fn hovered( fn hovered(
&self, &self,
style: Self::Style, style: &Self::Style,
is_active: bool, is_active: bool,
) -> toggler::Appearance { ) -> toggler::Appearance {
let palette = self.extended_palette(); match style {
Toggler::Default => {
let palette = self.extended_palette();
toggler::Appearance { toggler::Appearance {
foreground: if is_active { foreground: if is_active {
Color { Color {
a: 0.5, a: 0.5,
..palette.primary.strong.text ..palette.primary.strong.text
}
} else {
palette.background.weak.color
},
..self.active(style, is_active)
} }
} else { }
palette.background.weak.color Toggler::Custom(custom) => custom.hovered(self, is_active),
},
..self.active(style, is_active)
} }
} }
} }
@ -523,37 +687,53 @@ impl toggler::StyleSheet for Theme {
/* /*
* Pane Grid * Pane Grid
*/ */
#[derive(Default)]
pub enum PaneGrid {
#[default]
Default,
Custom(Box<dyn pane_grid::StyleSheet<Style = Theme>>),
}
impl pane_grid::StyleSheet for Theme { impl pane_grid::StyleSheet for Theme {
type Style = (); type Style = PaneGrid;
fn picked_split(&self, _style: Self::Style) -> Option<pane_grid::Line> { fn picked_split(&self, style: &Self::Style) -> Option<pane_grid::Line> {
let palette = self.extended_palette(); match style {
PaneGrid::Default => {
let palette = self.extended_palette();
Some(pane_grid::Line { Some(pane_grid::Line {
color: palette.primary.strong.color, color: palette.primary.strong.color,
width: 2.0, width: 2.0,
}) })
}
PaneGrid::Custom(custom) => custom.picked_split(self),
}
} }
fn hovered_split(&self, _style: Self::Style) -> Option<pane_grid::Line> { fn hovered_split(&self, style: &Self::Style) -> Option<pane_grid::Line> {
let palette = self.extended_palette(); match style {
PaneGrid::Default => {
let palette = self.extended_palette();
Some(pane_grid::Line { Some(pane_grid::Line {
color: palette.primary.base.color, color: palette.primary.base.color,
width: 2.0, width: 2.0,
}) })
}
PaneGrid::Custom(custom) => custom.hovered_split(self),
}
} }
} }
/* /*
* Progress Bar * Progress Bar
*/ */
#[derive(Clone, Copy)]
pub enum ProgressBar { pub enum ProgressBar {
Primary, Primary,
Success, Success,
Danger, Danger,
Custom(fn(&Theme) -> progress_bar::Appearance), Custom(Box<dyn progress_bar::StyleSheet<Style = Theme>>),
} }
impl Default for ProgressBar { impl Default for ProgressBar {
@ -562,10 +742,20 @@ impl Default for ProgressBar {
} }
} }
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 { impl progress_bar::StyleSheet for Theme {
type Style = ProgressBar; 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 palette = self.extended_palette();
let from_palette = |bar: Color| progress_bar::Appearance { let from_palette = |bar: Color| progress_bar::Appearance {
@ -578,18 +768,25 @@ impl progress_bar::StyleSheet for Theme {
ProgressBar::Primary => from_palette(palette.primary.base.color), ProgressBar::Primary => from_palette(palette.primary.base.color),
ProgressBar::Success => from_palette(palette.success.base.color), ProgressBar::Success => from_palette(palette.success.base.color),
ProgressBar::Danger => from_palette(palette.danger.base.color), ProgressBar::Danger => from_palette(palette.danger.base.color),
ProgressBar::Custom(f) => f(self), ProgressBar::Custom(custom) => custom.appearance(self),
} }
} }
} }
impl progress_bar::StyleSheet for fn(&Theme) -> progress_bar::Appearance {
type Style = Theme;
fn appearance(&self, style: &Self::Style) -> progress_bar::Appearance {
(self)(style)
}
}
/* /*
* Rule * Rule
*/ */
#[derive(Clone, Copy)]
pub enum Rule { pub enum Rule {
Default, Default,
Custom(fn(&Theme) -> rule::Appearance), Custom(Box<dyn rule::StyleSheet<Style = Theme>>),
} }
impl Default for Rule { impl Default for Rule {
@ -598,10 +795,16 @@ impl Default for Rule {
} }
} }
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 { impl rule::StyleSheet for Theme {
type Style = Rule; type Style = Rule;
fn style(&self, style: Self::Style) -> rule::Appearance { fn appearance(&self, style: &Self::Style) -> rule::Appearance {
let palette = self.extended_palette(); let palette = self.extended_palette();
match style { match style {
@ -611,48 +814,80 @@ impl rule::StyleSheet for Theme {
radius: 0.0, radius: 0.0,
fill_mode: rule::FillMode::Full, fill_mode: rule::FillMode::Full,
}, },
Rule::Custom(f) => f(self), Rule::Custom(custom) => custom.appearance(self),
} }
} }
} }
impl rule::StyleSheet for fn(&Theme) -> rule::Appearance {
type Style = Theme;
fn appearance(&self, style: &Self::Style) -> rule::Appearance {
(self)(style)
}
}
/* /*
* Scrollable * Scrollable
*/ */
#[derive(Default)]
pub enum Scrollable {
#[default]
Default,
Custom(Box<dyn scrollable::StyleSheet<Style = Theme>>),
}
impl scrollable::StyleSheet for Theme { impl scrollable::StyleSheet for Theme {
type Style = (); type Style = Scrollable;
fn active(&self, _style: Self::Style) -> scrollable::Scrollbar { fn active(&self, style: &Self::Style) -> scrollable::Scrollbar {
let palette = self.extended_palette(); match style {
Scrollable::Default => {
let palette = self.extended_palette();
scrollable::Scrollbar { scrollable::Scrollbar {
background: palette.background.weak.color.into(), background: palette.background.weak.color.into(),
border_radius: 2.0, border_radius: 2.0,
border_width: 0.0, border_width: 0.0,
border_color: Color::TRANSPARENT, border_color: Color::TRANSPARENT,
scroller: scrollable::Scroller { scroller: scrollable::Scroller {
color: palette.background.strong.color, color: palette.background.strong.color,
border_radius: 2.0, border_radius: 2.0,
border_width: 0.0, border_width: 0.0,
border_color: Color::TRANSPARENT, border_color: Color::TRANSPARENT,
}, },
}
}
Scrollable::Custom(custom) => custom.active(self),
} }
} }
fn hovered(&self, _style: Self::Style) -> scrollable::Scrollbar { fn hovered(&self, style: &Self::Style) -> scrollable::Scrollbar {
let palette = self.extended_palette(); match style {
Scrollable::Default => {
let palette = self.extended_palette();
scrollable::Scrollbar { scrollable::Scrollbar {
background: palette.background.weak.color.into(), background: palette.background.weak.color.into(),
border_radius: 2.0, border_radius: 2.0,
border_width: 0.0, border_width: 0.0,
border_color: Color::TRANSPARENT, border_color: Color::TRANSPARENT,
scroller: scrollable::Scroller { scroller: scrollable::Scroller {
color: palette.primary.strong.color, color: palette.primary.strong.color,
border_radius: 2.0, border_radius: 2.0,
border_width: 0.0, border_width: 0.0,
border_color: Color::TRANSPARENT, 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),
} }
} }
} }
@ -664,7 +899,6 @@ impl scrollable::StyleSheet for Theme {
pub enum Text { pub enum Text {
Default, Default,
Color(Color), Color(Color),
Custom(fn(&Theme) -> text::Appearance),
} }
impl Default for Text { impl Default for Text {
@ -686,7 +920,6 @@ impl text::StyleSheet for Theme {
match style { match style {
Text::Default => Default::default(), Text::Default => Default::default(),
Text::Color(c) => text::Appearance { color: Some(c) }, Text::Color(c) => text::Appearance { color: Some(c) },
Text::Custom(f) => f(self),
} }
} }
} }
@ -694,10 +927,21 @@ impl text::StyleSheet for Theme {
/* /*
* Text Input * Text Input
*/ */
impl text_input::StyleSheet for Theme { #[derive(Default)]
type Style = (); pub enum TextInput {
#[default]
Default,
Custom(Box<dyn text_input::StyleSheet<Style = Theme>>),
}
impl text_input::StyleSheet for Theme {
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(); let palette = self.extended_palette();
text_input::Appearance { text_input::Appearance {
@ -708,7 +952,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(); let palette = self.extended_palette();
text_input::Appearance { text_input::Appearance {
@ -719,7 +967,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(); let palette = self.extended_palette();
text_input::Appearance { text_input::Appearance {
@ -730,19 +982,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(); let palette = self.extended_palette();
palette.background.strong.color 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(); let palette = self.extended_palette();
palette.background.base.text 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(); let palette = self.extended_palette();
palette.primary.weak.color palette.primary.weak.color

View file

@ -12,9 +12,9 @@ pub struct Appearance {
/// A set of rules that dictate the style of a toggler. /// A set of rules that dictate the style of a toggler.
pub trait StyleSheet { pub trait StyleSheet {
type Style: Default + Copy; type Style: Default;
fn active(&self, style: Self::Style, is_active: bool) -> Appearance; fn active(&self, style: &Self::Style, is_active: bool) -> Appearance;
fn hovered(&self, style: Self::Style, is_active: bool) -> Appearance; fn hovered(&self, style: &Self::Style, is_active: bool) -> Appearance;
} }

View file

@ -32,7 +32,7 @@ where
let title = application.title(); let title = application.title();
let scale_factor = application.scale_factor(); let scale_factor = application.scale_factor();
let theme = application.theme(); let theme = application.theme();
let appearance = theme.appearance(application.style()); let appearance = theme.appearance(&application.style());
let viewport = { let viewport = {
let physical_size = window.inner_size(); let physical_size = window.inner_size();
@ -210,6 +210,6 @@ where
// Update theme and appearance // Update theme and appearance
self.theme = application.theme(); self.theme = application.theme();
self.appearance = self.theme.appearance(application.style()); self.appearance = self.theme.appearance(&application.style());
} }
} }