summaryrefslogtreecommitdiffstats
path: root/widget/src/pick_list.rs
diff options
context:
space:
mode:
Diffstat (limited to 'widget/src/pick_list.rs')
-rw-r--r--widget/src/pick_list.rs106
1 files changed, 68 insertions, 38 deletions
diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs
index 52d54397..801e792b 100644
--- a/widget/src/pick_list.rs
+++ b/widget/src/pick_list.rs
@@ -32,6 +32,7 @@ pub struct PickList<
T: ToString + PartialEq + Clone,
L: Borrow<[T]> + 'a,
V: Borrow<T> + 'a,
+ Theme: Catalog,
Renderer: text::Renderer,
{
on_select: Box<dyn Fn(T) -> Message + 'a>,
@@ -47,7 +48,8 @@ pub struct PickList<
text_shaping: text::Shaping,
font: Option<Renderer::Font>,
handle: Handle<Renderer::Font>,
- style: Style<'a, Theme>,
+ class: <Theme as Catalog>::Class<'a>,
+ menu_class: <Theme as menu::Catalog>::Class<'a>,
}
impl<'a, T, L, V, Message, Theme, Renderer>
@@ -57,6 +59,7 @@ where
L: Borrow<[T]> + 'a,
V: Borrow<T> + 'a,
Message: Clone,
+ Theme: Catalog,
Renderer: text::Renderer,
{
/// Creates a new [`PickList`] with the given list of options, the current
@@ -65,10 +68,7 @@ where
options: L,
selected: Option<V>,
on_select: impl Fn(T) -> Message + 'a,
- ) -> Self
- where
- Theme: DefaultStyle,
- {
+ ) -> Self {
Self {
on_select: Box::new(on_select),
on_open: None,
@@ -83,7 +83,8 @@ where
text_shaping: text::Shaping::Basic,
font: None,
handle: Handle::default(),
- style: Theme::default_style(),
+ class: <Theme as Catalog>::default(),
+ menu_class: <Theme as Catalog>::default_menu(),
}
}
@@ -151,8 +152,23 @@ where
}
/// Sets the style of the [`PickList`].
- pub fn style(mut self, style: impl Into<Style<'a, Theme>>) -> Self {
- self.style = style.into();
+ #[must_use]
+ pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self
+ where
+ <Theme as Catalog>::Class<'a>: From<StyleFn<'a, Theme>>,
+ {
+ self.class = (Box::new(style) as StyleFn<'a, Theme>).into();
+ self
+ }
+
+ /// Sets the style class of the [`PickList`].
+ #[cfg(feature = "advanced")]
+ #[must_use]
+ pub fn class(
+ mut self,
+ class: impl Into<<Theme as Catalog>::Class<'a>>,
+ ) -> Self {
+ self.class = class.into();
self
}
}
@@ -164,6 +180,7 @@ where
L: Borrow<[T]>,
V: Borrow<T>,
Message: Clone + 'a,
+ Theme: Catalog + 'a,
Renderer: text::Renderer + 'a,
{
fn tag(&self) -> tree::Tag {
@@ -409,15 +426,15 @@ where
Status::Active
};
- let appearance = (self.style.field)(theme, status);
+ let style = Catalog::style(theme, &self.class, status);
renderer.fill_quad(
renderer::Quad {
bounds,
- border: appearance.border,
+ border: style.border,
..renderer::Quad::default()
},
- appearance.background,
+ style.background,
);
let handle = match &self.handle {
@@ -478,7 +495,7 @@ where
bounds.x + bounds.width - self.padding.right,
bounds.center_y(),
),
- appearance.handle_color,
+ style.handle_color,
*viewport,
);
}
@@ -505,9 +522,9 @@ where
},
Point::new(bounds.x + self.padding.left, bounds.center_y()),
if is_selected {
- appearance.text_color
+ style.text_color
} else {
- appearance.placeholder_color
+ style.placeholder_color
},
*viewport,
);
@@ -539,7 +556,7 @@ where
(on_select)(option)
},
None,
- &self.style.menu,
+ &self.menu_class,
)
.width(bounds.width)
.padding(self.padding)
@@ -565,7 +582,7 @@ where
L: Borrow<[T]> + 'a,
V: Borrow<T> + 'a,
Message: Clone + 'a,
- Theme: 'a,
+ Theme: Catalog + 'a,
Renderer: text::Renderer + 'a,
{
fn from(
@@ -662,7 +679,7 @@ pub enum Status {
/// The appearance of a pick list.
#[derive(Debug, Clone, Copy)]
-pub struct Appearance {
+pub struct Style {
/// The text [`Color`] of the pick list.
pub text_color: Color,
/// The placeholder [`Color`] of the pick list.
@@ -675,36 +692,49 @@ pub struct Appearance {
pub border: Border,
}
-/// The styles of the different parts of a [`PickList`].
-#[allow(missing_debug_implementations)]
-pub struct Style<'a, Theme> {
- /// The style of the [`PickList`] itself.
- pub field: Box<dyn Fn(&Theme, Status) -> Appearance + 'a>,
+/// The theme catalog of a [`PickList`].
+pub trait Catalog: menu::Catalog {
+ /// The item class of the [`Catalog`].
+ type Class<'a>;
- /// The style of the [`Menu`] of the pick list.
- pub menu: menu::Style<'a, Theme>,
-}
+ /// The default class produced by the [`Catalog`].
+ fn default<'a>() -> <Self as Catalog>::Class<'a>;
-/// The default style of a [`PickList`].
-pub trait DefaultStyle: Sized {
- /// Returns the default style of a [`PickList`].
- fn default_style() -> Style<'static, Self>;
+ /// The default class for the menu of the [`PickList`].
+ fn default_menu<'a>() -> <Self as menu::Catalog>::Class<'a> {
+ <Self as menu::Catalog>::default()
+ }
+
+ /// The [`Style`] of a class with the given status.
+ fn style(
+ &self,
+ class: &<Self as Catalog>::Class<'_>,
+ status: Status,
+ ) -> Style;
}
-impl DefaultStyle for Theme {
- fn default_style() -> Style<'static, Self> {
- Style {
- field: Box::new(default),
- menu: menu::DefaultStyle::default_style(),
- }
+/// A styling function for a [`PickList`].
+///
+/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`.
+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>() -> StyleFn<'a, Self> {
+ Box::new(default)
+ }
+
+ fn style(&self, class: &StyleFn<'_, Self>, status: Status) -> Style {
+ class(self, status)
}
}
/// The default style of the field of a [`PickList`].
-pub fn default(theme: &Theme, status: Status) -> Appearance {
+pub fn default(theme: &Theme, status: Status) -> Style {
let palette = theme.extended_palette();
- let active = Appearance {
+ let active = Style {
text_color: palette.background.weak.text,
background: palette.background.weak.color.into(),
placeholder_color: palette.background.strong.color,
@@ -718,7 +748,7 @@ pub fn default(theme: &Theme, status: Status) -> Appearance {
match status {
Status::Active => active,
- Status::Hovered | Status::Opened => Appearance {
+ Status::Hovered | Status::Opened => Style {
border: Border {
color: palette.primary.strong.color,
..active.border