summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-03-06 20:30:58 +0100
committerLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-03-06 20:30:58 +0100
commit34e7c6593a9e0f56cee5db18b7258717cf6bc11b (patch)
tree7c65a58e9052f2f95a0025355679b13c7002eeab
parent8a63774b24488f71147a728123551ae72c080d14 (diff)
downloadiced-34e7c6593a9e0f56cee5db18b7258717cf6bc11b.tar.gz
iced-34e7c6593a9e0f56cee5db18b7258717cf6bc11b.tar.bz2
iced-34e7c6593a9e0f56cee5db18b7258717cf6bc11b.zip
Use `Style` struct pattern instead of trait for all widgets
-rw-r--r--core/src/widget/text.rs39
-rw-r--r--examples/gradient/src/main.rs2
-rw-r--r--style/src/theme.rs3
-rw-r--r--widget/src/button.rs44
-rw-r--r--widget/src/checkbox.rs40
-rw-r--r--widget/src/combo_box.rs15
-rw-r--r--widget/src/container.rs67
-rw-r--r--widget/src/helpers.rs51
-rw-r--r--widget/src/overlay/menu.rs36
-rw-r--r--widget/src/pane_grid.rs36
-rw-r--r--widget/src/pane_grid/content.rs12
-rw-r--r--widget/src/pane_grid/title_bar.rs15
-rw-r--r--widget/src/pick_list.rs5
-rw-r--r--widget/src/progress_bar.rs36
-rw-r--r--widget/src/qr_code.rs36
-rw-r--r--widget/src/radio.rs36
-rw-r--r--widget/src/rule.rs40
-rw-r--r--widget/src/scrollable.rs47
-rw-r--r--widget/src/slider.rs36
-rw-r--r--widget/src/svg.rs2
-rw-r--r--widget/src/text_editor.rs36
-rw-r--r--widget/src/text_input.rs53
-rw-r--r--widget/src/toggler.rs34
-rw-r--r--widget/src/tooltip.rs12
-rw-r--r--widget/src/vertical_slider.rs13
25 files changed, 465 insertions, 281 deletions
diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs
index 217ad8b3..e151476d 100644
--- a/core/src/widget/text.rs
+++ b/core/src/widget/text.rs
@@ -17,7 +17,6 @@ pub use text::{LineHeight, Shaping};
#[allow(missing_debug_implementations)]
pub struct Text<'a, Theme, Renderer>
where
- Theme: StyleSheet,
Renderer: text::Renderer,
{
content: Cow<'a, str>,
@@ -34,7 +33,6 @@ where
impl<'a, Theme, Renderer> Text<'a, Theme, Renderer>
where
- Theme: StyleSheet,
Renderer: text::Renderer,
{
/// Create a new fragment of [`Text`] with the given contents.
@@ -49,7 +47,7 @@ where
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top,
shaping: Shaping::Basic,
- style: Style::Themed(Theme::default()),
+ style: Style::default(),
}
}
@@ -135,7 +133,6 @@ pub struct State<P: Paragraph>(P);
impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
for Text<'a, Theme, Renderer>
where
- Theme: StyleSheet,
Renderer: text::Renderer,
{
fn tag(&self) -> tree::Tag {
@@ -283,7 +280,7 @@ pub fn draw<Renderer>(
impl<'a, Message, Theme, Renderer> From<Text<'a, Theme, Renderer>>
for Element<'a, Message, Theme, Renderer>
where
- Theme: StyleSheet + 'a,
+ Theme: 'a,
Renderer: text::Renderer + 'a,
{
fn from(
@@ -295,7 +292,6 @@ where
impl<'a, Theme, Renderer> Clone for Text<'a, Theme, Renderer>
where
- Theme: StyleSheet,
Renderer: text::Renderer,
{
fn clone(&self) -> Self {
@@ -316,7 +312,6 @@ where
impl<'a, Theme, Renderer> From<&'a str> for Text<'a, Theme, Renderer>
where
- Theme: StyleSheet,
Renderer: text::Renderer,
{
fn from(content: &'a str) -> Self {
@@ -327,7 +322,7 @@ where
impl<'a, Message, Theme, Renderer> From<&'a str>
for Element<'a, Message, Theme, Renderer>
where
- Theme: StyleSheet + 'a,
+ Theme: 'a,
Renderer: text::Renderer + 'a,
{
fn from(content: &'a str) -> Self {
@@ -335,22 +330,6 @@ where
}
}
-/// The style sheet of some text.
-pub trait StyleSheet {
- /// Returns the default styling strategy for [`Text`].
- fn default() -> fn(&Self) -> Appearance {
- |_| Appearance::default()
- }
-}
-
-impl StyleSheet for Color {
- fn default() -> fn(&Self) -> Appearance {
- |color| Appearance {
- color: Some(*color),
- }
- }
-}
-
/// The apperance of some text.
#[derive(Debug, Clone, Copy, Default)]
pub struct Appearance {
@@ -373,3 +352,15 @@ impl<Theme> Clone for Style<Theme> {
}
impl<Theme> Copy for Style<Theme> {}
+
+impl<Theme> Default for Style<Theme> {
+ fn default() -> Self {
+ Style::Colored(None)
+ }
+}
+
+impl<Theme> From<fn(&Theme) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme) -> Appearance) -> Self {
+ Style::Themed(f)
+ }
+}
diff --git a/examples/gradient/src/main.rs b/examples/gradient/src/main.rs
index 1a264063..3334bde9 100644
--- a/examples/gradient/src/main.rs
+++ b/examples/gradient/src/main.rs
@@ -84,7 +84,7 @@ impl Sandbox for Gradient {
};
let gradient_box = themer(
- move |_| appearance,
+ appearance,
container(horizontal_space())
.width(Length::Fill)
.height(Length::Fill),
diff --git a/style/src/theme.rs b/style/src/theme.rs
index fd93f776..41e76d99 100644
--- a/style/src/theme.rs
+++ b/style/src/theme.rs
@@ -4,7 +4,6 @@ pub mod palette;
pub use palette::Palette;
use crate::application;
-use crate::core::widget::text;
use std::fmt;
use std::sync::Arc;
@@ -265,5 +264,3 @@ impl<T: Fn(&Theme) -> application::Appearance> application::StyleSheet for T {
(self)(style)
}
}
-
-impl text::StyleSheet for Theme {}
diff --git a/widget/src/button.rs b/widget/src/button.rs
index 798a8206..b5786baa 100644
--- a/widget/src/button.rs
+++ b/widget/src/button.rs
@@ -53,7 +53,6 @@ use crate::style::Theme;
#[allow(missing_debug_implementations)]
pub struct Button<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>
where
- Theme: Style,
Renderer: crate::core::Renderer,
{
content: Element<'a, Message, Theme, Renderer>,
@@ -62,18 +61,20 @@ where
height: Length,
padding: Padding,
clip: bool,
- style: fn(&Theme, Status) -> Appearance,
+ style: Style<Theme>,
}
impl<'a, Message, Theme, Renderer> Button<'a, Message, Theme, Renderer>
where
- Theme: Style,
Renderer: crate::core::Renderer,
{
/// Creates a new [`Button`] with the given content.
pub fn new(
content: impl Into<Element<'a, Message, Theme, Renderer>>,
- ) -> Self {
+ ) -> Self
+ where
+ Style<Theme>: Default,
+ {
let content = content.into();
let size = content.as_widget().size_hint();
@@ -84,7 +85,7 @@ where
height: size.height.fluid(),
padding: Padding::new(5.0),
clip: false,
- style: Theme::DEFAULT,
+ style: Style::default(),
}
}
@@ -125,7 +126,7 @@ where
/// Sets the style variant of this [`Button`].
pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {
- self.style = style.into();
+ self.style = Style(style);
self
}
@@ -146,7 +147,6 @@ impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
for Button<'a, Message, Theme, Renderer>
where
Message: 'a + Clone,
- Theme: Style,
Renderer: 'a + crate::core::Renderer,
{
fn tag(&self) -> tree::Tag {
@@ -306,7 +306,7 @@ where
Status::Active
};
- let styling = (self.style)(theme, status);
+ let styling = (self.style.0)(theme, status);
if styling.background.is_some()
|| styling.border.width > 0.0
@@ -380,7 +380,7 @@ impl<'a, Message, Theme, Renderer> From<Button<'a, Message, Theme, Renderer>>
for Element<'a, Message, Theme, Renderer>
where
Message: Clone + 'a,
- Theme: Style + 'a,
+ Theme: 'a,
Renderer: crate::core::Renderer + 'a,
{
fn from(button: Button<'a, Message, Theme, Renderer>) -> Self {
@@ -428,14 +428,28 @@ impl std::default::Default for Appearance {
}
}
-/// The default style of a [`Button`] for a given theme.
-pub trait Style {
- /// The default style.
- const DEFAULT: fn(&Self, Status) -> Appearance;
+/// The style of a [`Button`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme, Status) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(primary)
+ }
}
-impl Style for Theme {
- const DEFAULT: fn(&Self, Status) -> Appearance = primary;
+impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme, Status) -> Appearance) -> Self {
+ Style(f)
+ }
}
/// A primary button; denoting a main action.
diff --git a/widget/src/checkbox.rs b/widget/src/checkbox.rs
index 91838291..e4fc2232 100644
--- a/widget/src/checkbox.rs
+++ b/widget/src/checkbox.rs
@@ -53,13 +53,12 @@ pub struct Checkbox<
text_shaping: text::Shaping,
font: Option<Renderer::Font>,
icon: Icon<Renderer::Font>,
- style: fn(&Theme, Status) -> Appearance,
+ style: Style<Theme>,
}
impl<'a, Message, Theme, Renderer> Checkbox<'a, Message, Theme, Renderer>
where
Renderer: text::Renderer,
- Theme: Style,
{
/// The default size of a [`Checkbox`].
const DEFAULT_SIZE: f32 = 15.0;
@@ -72,7 +71,10 @@ where
/// It expects:
/// * the label of the [`Checkbox`]
/// * a boolean describing whether the [`Checkbox`] is checked or not
- pub fn new(label: impl Into<String>, is_checked: bool) -> Self {
+ pub fn new(label: impl Into<String>, is_checked: bool) -> Self
+ where
+ Style<Theme>: Default,
+ {
Checkbox {
is_checked,
on_toggle: None,
@@ -91,7 +93,7 @@ where
line_height: text::LineHeight::default(),
shaping: text::Shaping::Basic,
},
- style: Theme::style(),
+ style: Style::default(),
}
}
@@ -175,7 +177,7 @@ where
/// Sets the style of the [`Checkbox`].
pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {
- self.style = style.into();
+ self.style = Style(style);
self
}
}
@@ -301,7 +303,7 @@ where
Status::Active { is_checked }
};
- let appearance = (self.style)(theme, status);
+ let appearance = (self.style.0)(theme, status);
{
let layout = children.next().unwrap();
@@ -423,15 +425,27 @@ pub struct Appearance {
pub text_color: Option<Color>,
}
-/// A set of rules that dictate the style of a checkbox.
-pub trait Style {
- /// The supported style of the [`StyleSheet`].
- fn style() -> fn(&Self, Status) -> Appearance;
+/// The style of a [`Checkbox`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme, Status) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(primary)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self, Status) -> Appearance {
- primary
+impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme, Status) -> Appearance) -> Self {
+ Style(f)
}
}
diff --git a/widget/src/combo_box.rs b/widget/src/combo_box.rs
index 533daab2..1140f1c6 100644
--- a/widget/src/combo_box.rs
+++ b/widget/src/combo_box.rs
@@ -1,5 +1,4 @@
//! Display a dropdown list of searchable and selectable options.
-use crate::container;
use crate::core::event::{self, Event};
use crate::core::keyboard;
use crate::core::keyboard::key;
@@ -14,7 +13,6 @@ use crate::core::{
Clipboard, Element, Length, Padding, Rectangle, Shell, Size, Vector,
};
use crate::overlay::menu;
-use crate::scrollable;
use crate::style::Theme;
use crate::text::LineHeight;
use crate::text_input::{self, TextInput};
@@ -65,14 +63,16 @@ where
on_selected: impl Fn(T) -> Message + 'static,
) -> Self
where
- Theme: text_input::Style,
Style<Theme>: Default,
{
let style = Style::<Theme>::default();
- let text_input = TextInput::new(placeholder, &state.value())
- .on_input(TextInputEvent::TextChanged)
- .style(style.text_input);
+ let text_input = TextInput::with_style(
+ placeholder,
+ &state.value(),
+ style.text_input,
+ )
+ .on_input(TextInputEvent::TextChanged);
let selection = selection.map(T::to_string).unwrap_or_default();
@@ -294,7 +294,6 @@ impl<'a, T, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
where
T: Display + Clone + 'static,
Message: Clone,
- Theme: scrollable::Style + container::Style,
Renderer: text::Renderer,
{
fn size(&self) -> Size<Length> {
@@ -711,7 +710,7 @@ impl<'a, T, Message, Theme, Renderer>
where
T: Display + Clone + 'static,
Message: Clone + 'a,
- Theme: scrollable::Style + container::Style + 'a,
+ Theme: 'a,
Renderer: text::Renderer + 'a,
{
fn from(combo_box: ComboBox<'a, T, Message, Theme, Renderer>) -> Self {
diff --git a/widget/src/container.rs b/widget/src/container.rs
index 58a24339..97b481a2 100644
--- a/widget/src/container.rs
+++ b/widget/src/container.rs
@@ -34,21 +34,30 @@ pub struct Container<
max_height: f32,
horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical,
- style: fn(&Theme, Status) -> Appearance,
clip: bool,
content: Element<'a, Message, Theme, Renderer>,
+ style: Style<Theme>,
}
impl<'a, Message, Theme, Renderer> Container<'a, Message, Theme, Renderer>
where
Renderer: crate::core::Renderer,
{
- /// Creates an empty [`Container`].
- pub fn new<T>(content: T) -> Self
+ /// Creates a [`Container`] with the given content.
+ pub fn new(
+ content: impl Into<Element<'a, Message, Theme, Renderer>>,
+ ) -> Self
where
- Theme: Style,
- T: Into<Element<'a, Message, Theme, Renderer>>,
+ Style<Theme>: Default,
{
+ Self::with_style(content, Style::default().0)
+ }
+
+ /// Creates a [`Container`] with the given content and style.
+ pub fn with_style(
+ content: impl Into<Element<'a, Message, Theme, Renderer>>,
+ style: fn(&Theme, Status) -> Appearance,
+ ) -> Self {
let content = content.into();
let size = content.as_widget().size_hint();
@@ -61,9 +70,9 @@ where
max_height: f32::INFINITY,
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top,
- style: Theme::style(),
clip: false,
content,
+ style: Style(style),
}
}
@@ -129,7 +138,7 @@ where
/// Sets the style of the [`Container`].
pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {
- self.style = style;
+ self.style = Style(style);
self
}
@@ -267,7 +276,7 @@ where
Status::Idle
};
- let style = (self.style)(theme, status);
+ let style = (self.style.0)(theme, status);
if let Some(clipped_viewport) = bounds.intersection(viewport) {
draw_background(renderer, &style, bounds);
@@ -537,26 +546,46 @@ pub enum Status {
Hovered,
}
-/// The style of a [`Container`] for a theme.
-pub trait Style {
- /// The default style of a [`Container`].
- fn style() -> fn(&Self, Status) -> Appearance;
+/// The style of a [`Container`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme, Status) -> Appearance);
+
+impl<Theme> Style<Theme> {
+ /// Resolves the [`Style`] with the given `Theme` and [`Status`] to
+ /// produce an [`Appearance`].
+ pub fn resolve(self, theme: &Theme, status: Status) -> Appearance {
+ (self.0)(theme, status)
+ }
+}
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(transparent)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self, Status) -> Appearance {
- transparent
+impl Default for Style<Appearance> {
+ fn default() -> Self {
+ Style(|appearance, _status| *appearance)
}
}
-impl Style for Appearance {
- fn style() -> fn(&Self, Status) -> Appearance {
- |appearance, _status| *appearance
+impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme, Status) -> Appearance) -> Self {
+ Style(f)
}
}
/// A transparent [`Container`].
-pub fn transparent(_theme: &Theme, _status: Status) -> Appearance {
+pub fn transparent<Theme>(_theme: &Theme, _status: Status) -> Appearance {
Appearance::default()
}
diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs
index f63306c4..fdc9462d 100644
--- a/widget/src/helpers.rs
+++ b/widget/src/helpers.rs
@@ -14,7 +14,7 @@ use crate::rule::{self, Rule};
use crate::runtime::Command;
use crate::scrollable::{self, Scrollable};
use crate::slider::{self, Slider};
-use crate::text::{self, Text};
+use crate::text::Text;
use crate::text_editor::{self, TextEditor};
use crate::text_input::{self, TextInput};
use crate::toggler::{self, Toggler};
@@ -58,8 +58,8 @@ pub fn container<'a, Message, Theme, Renderer>(
content: impl Into<Element<'a, Message, Theme, Renderer>>,
) -> Container<'a, Message, Theme, Renderer>
where
- Theme: container::Style,
Renderer: core::Renderer,
+ container::Style<Theme>: Default,
{
Container::new(content)
}
@@ -104,8 +104,8 @@ pub fn scrollable<'a, Message, Theme, Renderer>(
content: impl Into<Element<'a, Message, Theme, Renderer>>,
) -> Scrollable<'a, Message, Theme, Renderer>
where
- Theme: scrollable::Style,
Renderer: core::Renderer,
+ scrollable::Style<Theme>: Default,
{
Scrollable::new(content)
}
@@ -118,7 +118,7 @@ pub fn button<'a, Message, Theme, Renderer>(
) -> Button<'a, Message, Theme, Renderer>
where
Renderer: core::Renderer,
- Theme: button::Style,
+ button::Style<Theme>: Default,
{
Button::new(content)
}
@@ -134,8 +134,8 @@ pub fn tooltip<'a, Message, Theme, Renderer>(
position: tooltip::Position,
) -> crate::Tooltip<'a, Message, Theme, Renderer>
where
- Theme: container::Style + text::StyleSheet,
Renderer: core::text::Renderer,
+ container::Style<Theme>: Default,
{
Tooltip::new(content, tooltip, position)
}
@@ -147,7 +147,6 @@ pub fn text<'a, Theme, Renderer>(
text: impl ToString,
) -> Text<'a, Theme, Renderer>
where
- Theme: text::StyleSheet,
Renderer: core::text::Renderer,
{
Text::new(text.to_string())
@@ -161,8 +160,8 @@ pub fn checkbox<'a, Message, Theme, Renderer>(
is_checked: bool,
) -> Checkbox<'a, Message, Theme, Renderer>
where
- Theme: checkbox::Style,
Renderer: core::text::Renderer,
+ checkbox::Style<Theme>: Default,
{
Checkbox::new(label, is_checked)
}
@@ -178,9 +177,9 @@ pub fn radio<Message, Theme, Renderer, V>(
) -> Radio<Message, Theme, Renderer>
where
Message: Clone,
- Theme: radio::Style,
Renderer: core::text::Renderer,
V: Copy + Eq,
+ radio::Style<Theme>: Default,
{
Radio::new(label, value, selected, on_click)
}
@@ -195,7 +194,7 @@ pub fn toggler<'a, Message, Theme, Renderer>(
) -> Toggler<'a, Message, Theme, Renderer>
where
Renderer: core::text::Renderer,
- Theme: toggler::Style,
+ toggler::Style<Theme>: Default,
{
Toggler::new(label, is_checked, f)
}
@@ -209,8 +208,8 @@ pub fn text_input<'a, Message, Theme, Renderer>(
) -> TextInput<'a, Message, Theme, Renderer>
where
Message: Clone,
- Theme: text_input::Style,
Renderer: core::text::Renderer,
+ text_input::Style<Theme>: Default,
{
TextInput::new(placeholder, value)
}
@@ -223,8 +222,8 @@ pub fn text_editor<Message, Theme, Renderer>(
) -> TextEditor<'_, core::text::highlighter::PlainText, Message, Theme, Renderer>
where
Message: Clone,
- Theme: text_editor::Style,
Renderer: core::text::Renderer,
+ text_editor::Style<Theme>: Default,
{
TextEditor::new(content)
}
@@ -240,7 +239,7 @@ pub fn slider<'a, T, Message, Theme>(
where
T: Copy + From<u8> + std::cmp::PartialOrd,
Message: Clone,
- Theme: slider::Style,
+ slider::Style<Theme>: Default,
{
Slider::new(range, value, on_change)
}
@@ -256,7 +255,7 @@ pub fn vertical_slider<'a, T, Message, Theme>(
where
T: Copy + From<u8> + std::cmp::PartialOrd,
Message: Clone,
- Theme: vertical_slider::Style,
+ vertical_slider::Style<Theme>: Default,
{
VerticalSlider::new(range, value, on_change)
}
@@ -291,7 +290,6 @@ pub fn combo_box<'a, T, Message, Theme, Renderer>(
) -> ComboBox<'a, T, Message, Theme, Renderer>
where
T: std::fmt::Display + Clone,
- Theme: text_input::Style,
Renderer: core::text::Renderer,
combo_box::Style<Theme>: Default,
{
@@ -319,7 +317,7 @@ pub fn vertical_space() -> Space {
/// [`Rule`]: crate::Rule
pub fn horizontal_rule<Theme>(height: impl Into<Pixels>) -> Rule<Theme>
where
- Theme: rule::Style,
+ rule::Style<Theme>: Default,
{
Rule::horizontal(height)
}
@@ -329,7 +327,7 @@ where
/// [`Rule`]: crate::Rule
pub fn vertical_rule<Theme>(width: impl Into<Pixels>) -> Rule<Theme>
where
- Theme: rule::Style,
+ rule::Style<Theme>: Default,
{
Rule::vertical(width)
}
@@ -346,7 +344,7 @@ pub fn progress_bar<Theme>(
value: f32,
) -> ProgressBar<Theme>
where
- Theme: progress_bar::Style,
+ progress_bar::Style<Theme>: Default,
{
ProgressBar::new(range, value)
}
@@ -392,7 +390,7 @@ where
#[cfg(feature = "qr_code")]
pub fn qr_code<Theme>(data: &crate::qr_code::Data) -> crate::QRCode<'_, Theme>
where
- Theme: crate::qr_code::Style,
+ crate::qr_code::Style<Theme>: Default,
{
crate::QRCode::new(data)
}
@@ -435,13 +433,20 @@ where
}
/// A widget that applies any `Theme` to its contents.
-pub fn themer<'a, Message, OldTheme, NewTheme, F, Renderer>(
- to_theme: F,
+pub fn themer<'a, Message, OldTheme, NewTheme, Renderer>(
+ new_theme: NewTheme,
content: impl Into<Element<'a, Message, NewTheme, Renderer>>,
-) -> Themer<'a, Message, OldTheme, NewTheme, F, Renderer>
+) -> Themer<
+ 'a,
+ Message,
+ OldTheme,
+ NewTheme,
+ impl Fn(&OldTheme) -> NewTheme,
+ Renderer,
+>
where
- F: Fn(&OldTheme) -> NewTheme,
Renderer: core::Renderer,
+ NewTheme: Clone,
{
- Themer::new(to_theme, content)
+ Themer::new(move |_| new_theme.clone(), content)
}
diff --git a/widget/src/overlay/menu.rs b/widget/src/overlay/menu.rs
index bb8ad0e0..e0887e59 100644
--- a/widget/src/overlay/menu.rs
+++ b/widget/src/overlay/menu.rs
@@ -46,7 +46,7 @@ impl<'a, T, Message, Theme, Renderer> Menu<'a, T, Message, Theme, Renderer>
where
T: ToString + Clone,
Message: 'a,
- Theme: container::Style + scrollable::Style + 'a,
+ Theme: 'a,
Renderer: text::Renderer + 'a,
{
/// Creates a new [`Menu`] with the given [`State`], a list of options, and
@@ -197,7 +197,7 @@ where
impl<'a, Message, Theme, Renderer> Overlay<'a, Message, Theme, Renderer>
where
Message: 'a,
- Theme: container::Style + scrollable::Style + 'a,
+ Theme: 'a,
Renderer: text::Renderer + 'a,
{
pub fn new<T>(
@@ -223,20 +223,24 @@ where
style,
} = menu;
- let container = Container::new(
- Scrollable::new(List {
- options,
- hovered_option,
- on_selected,
- on_option_hovered,
- font,
- text_size,
- text_line_height,
- text_shaping,
- padding,
- style: style.menu,
- })
- .style(style.scrollable),
+ let container = Container::with_style(
+ Scrollable::with_direction_and_style(
+ List {
+ options,
+ hovered_option,
+ on_selected,
+ on_option_hovered,
+ font,
+ text_size,
+ text_line_height,
+ text_shaping,
+ padding,
+ style: style.menu,
+ },
+ scrollable::Direction::default(),
+ style.scrollable,
+ ),
+ container::transparent,
);
state.tree.diff(&container as &dyn Widget<_, _, _>);
diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs
index 62067e66..ae9cd825 100644
--- a/widget/src/pane_grid.rs
+++ b/widget/src/pane_grid.rs
@@ -112,7 +112,7 @@ pub struct PaneGrid<
on_click: Option<Box<dyn Fn(Pane) -> Message + 'a>>,
on_drag: Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,
on_resize: Option<(f32, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>,
- style: fn(&Theme) -> Appearance,
+ style: Style<Theme>,
}
impl<'a, Message, Theme, Renderer> PaneGrid<'a, Message, Theme, Renderer>
@@ -128,7 +128,7 @@ where
view: impl Fn(Pane, &'a T, bool) -> Content<'a, Message, Theme, Renderer>,
) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
{
let contents = if let Some((pane, pane_state)) =
state.maximized.and_then(|pane| {
@@ -160,7 +160,7 @@ where
on_click: None,
on_drag: None,
on_resize: None,
- style: Theme::style(),
+ style: Style::default(),
}
}
@@ -221,7 +221,7 @@ where
/// Sets the style of the [`PaneGrid`].
pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self {
- self.style = style;
+ self.style = Style(style);
self
}
@@ -679,7 +679,7 @@ where
None
};
- let appearance = (self.style)(theme);
+ let appearance = (self.style.0)(theme);
for ((id, (content, tree)), pane_layout) in
contents.zip(layout.children())
@@ -1147,15 +1147,27 @@ pub struct Line {
pub width: f32,
}
-/// The definiton of the default style of a [`PaneGrid`].
-pub trait Style {
- /// Returns the default style of a [`PaneGrid`].
- fn style() -> fn(&Self) -> Appearance;
+/// The style of a [`PaneGrid`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(default)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self) -> Appearance {
- default
+impl<Theme> From<fn(&Theme) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme) -> Appearance) -> Self {
+ Style(f)
}
}
diff --git a/widget/src/pane_grid/content.rs b/widget/src/pane_grid/content.rs
index 25b64e17..ce29e8d0 100644
--- a/widget/src/pane_grid/content.rs
+++ b/widget/src/pane_grid/content.rs
@@ -24,7 +24,7 @@ pub struct Content<
{
title_bar: Option<TitleBar<'a, Message, Theme, Renderer>>,
body: Element<'a, Message, Theme, Renderer>,
- style: fn(&Theme, container::Status) -> container::Appearance,
+ style: container::Style<Theme>,
}
impl<'a, Message, Theme, Renderer> Content<'a, Message, Theme, Renderer>
@@ -34,12 +34,12 @@ where
/// Creates a new [`Content`] with the provided body.
pub fn new(body: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self
where
- Theme: container::Style,
+ container::Style<Theme>: Default,
{
Self {
title_bar: None,
body: body.into(),
- style: Theme::style(),
+ style: container::Style::default(),
}
}
@@ -57,7 +57,7 @@ where
mut self,
style: fn(&Theme, container::Status) -> container::Appearance,
) -> Self {
- self.style = style;
+ self.style = style.into();
self
}
}
@@ -114,7 +114,7 @@ where
container::Status::Idle
};
- (self.style)(theme, status)
+ self.style.resolve(theme, status)
};
container::draw_background(renderer, &style, bounds);
@@ -403,8 +403,8 @@ impl<'a, T, Message, Theme, Renderer> From<T>
for Content<'a, Message, Theme, Renderer>
where
T: Into<Element<'a, Message, Theme, Renderer>>,
- Theme: container::Style,
Renderer: crate::core::Renderer,
+ container::Style<Theme>: Default,
{
fn from(element: T) -> Self {
Self::new(element)
diff --git a/widget/src/pane_grid/title_bar.rs b/widget/src/pane_grid/title_bar.rs
index 787510cc..b1cdcde3 100644
--- a/widget/src/pane_grid/title_bar.rs
+++ b/widget/src/pane_grid/title_bar.rs
@@ -25,7 +25,7 @@ pub struct TitleBar<
controls: Option<Element<'a, Message, Theme, Renderer>>,
padding: Padding,
always_show_controls: bool,
- style: fn(&Theme, container::Status) -> container::Appearance,
+ style: container::Style<Theme>,
}
impl<'a, Message, Theme, Renderer> TitleBar<'a, Message, Theme, Renderer>
@@ -33,17 +33,18 @@ where
Renderer: crate::core::Renderer,
{
/// Creates a new [`TitleBar`] with the given content.
- pub fn new<E>(content: E) -> Self
+ pub fn new(
+ content: impl Into<Element<'a, Message, Theme, Renderer>>,
+ ) -> Self
where
- Theme: container::Style,
- E: Into<Element<'a, Message, Theme, Renderer>>,
+ container::Style<Theme>: Default,
{
Self {
content: content.into(),
controls: None,
padding: Padding::ZERO,
always_show_controls: false,
- style: Theme::style(),
+ style: container::Style::default(),
}
}
@@ -67,7 +68,7 @@ where
mut self,
style: fn(&Theme, container::Status) -> container::Appearance,
) -> Self {
- self.style = style;
+ self.style = style.into();
self
}
@@ -137,7 +138,7 @@ where
container::Status::Idle
};
- (self.style)(theme, status)
+ self.style.resolve(theme, status)
};
let inherited_style = renderer::Style {
diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs
index 546bf294..49daa89c 100644
--- a/widget/src/pick_list.rs
+++ b/widget/src/pick_list.rs
@@ -1,5 +1,4 @@
//! Display a dropdown list of selectable values.
-use crate::container;
use crate::core::alignment;
use crate::core::event::{self, Event};
use crate::core::keyboard;
@@ -15,7 +14,6 @@ use crate::core::{
Pixels, Point, Rectangle, Shell, Size, Vector, Widget,
};
use crate::overlay::menu::{self, Menu};
-use crate::scrollable;
use crate::style::Theme;
use std::borrow::Borrow;
@@ -169,7 +167,6 @@ where
L: Borrow<[T]>,
V: Borrow<T>,
Message: Clone + 'a,
- Theme: scrollable::Style + container::Style,
Renderer: text::Renderer + 'a,
{
fn tag(&self) -> tree::Tag {
@@ -426,7 +423,7 @@ where
L: Borrow<[T]> + 'a,
V: Borrow<T> + 'a,
Message: Clone + 'a,
- Theme: scrollable::Style + container::Style + 'a,
+ Theme: 'a,
Renderer: text::Renderer + 'a,
{
fn from(
diff --git a/widget/src/progress_bar.rs b/widget/src/progress_bar.rs
index 889c5558..62d319f4 100644
--- a/widget/src/progress_bar.rs
+++ b/widget/src/progress_bar.rs
@@ -28,7 +28,7 @@ pub struct ProgressBar<Theme = crate::Theme> {
value: f32,
width: Length,
height: Option<Length>,
- style: fn(&Theme) -> Appearance,
+ style: Style<Theme>,
}
impl<Theme> ProgressBar<Theme> {
@@ -42,14 +42,14 @@ impl<Theme> ProgressBar<Theme> {
/// * the current value of the [`ProgressBar`]
pub fn new(range: RangeInclusive<f32>, value: f32) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
{
ProgressBar {
value: value.clamp(*range.start(), *range.end()),
range,
width: Length::Fill,
height: None,
- style: Theme::style(),
+ style: Style::default(),
}
}
@@ -67,7 +67,7 @@ impl<Theme> ProgressBar<Theme> {
/// Sets the style of the [`ProgressBar`].
pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self {
- self.style = style;
+ self.style = style.into();
self
}
}
@@ -117,7 +117,7 @@ where
/ (range_end - range_start)
};
- let appearance = (self.style)(theme);
+ let appearance = (self.style.0)(theme);
renderer.fill_quad(
renderer::Quad {
@@ -169,15 +169,27 @@ pub struct Appearance {
pub border: Border,
}
-/// The definiton of the default style of a [`ProgressBar`].
-pub trait Style {
- /// Returns the default style of a [`ProgressBar`].
- fn style() -> fn(&Self) -> Appearance;
+/// The style of a [`ProgressBar`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(primary)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self) -> Appearance {
- primary
+impl<Theme> From<fn(&Theme) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme) -> Appearance) -> Self {
+ Style(f)
}
}
diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs
index f13c9102..b94e95f6 100644
--- a/widget/src/qr_code.rs
+++ b/widget/src/qr_code.rs
@@ -23,19 +23,19 @@ const QUIET_ZONE: usize = 2;
pub struct QRCode<'a, Theme = crate::Theme> {
data: &'a Data,
cell_size: u16,
- style: fn(&Theme) -> Appearance,
+ style: Style<Theme>,
}
impl<'a, Theme> QRCode<'a, Theme> {
/// Creates a new [`QRCode`] with the provided [`Data`].
pub fn new(data: &'a Data) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
{
Self {
data,
cell_size: DEFAULT_CELL_SIZE,
- style: Theme::style(),
+ style: Style::default(),
}
}
@@ -47,7 +47,7 @@ impl<'a, Theme> QRCode<'a, Theme> {
/// Sets the style of the [`QRCode`].
pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self {
- self.style = style;
+ self.style = style.into();
self
}
}
@@ -97,7 +97,7 @@ impl<'a, Message, Theme> Widget<Message, Theme, Renderer>
let bounds = layout.bounds();
let side_length = self.data.width + 2 * QUIET_ZONE;
- let appearance = (self.style)(theme);
+ let appearance = (self.style.0)(theme);
let mut last_appearance = state.last_appearance.borrow_mut();
if Some(appearance) != *last_appearance {
@@ -335,15 +335,27 @@ pub struct Appearance {
pub background: Color,
}
-/// The definiton of the default style of a [`QRCode`].
-pub trait Style {
- /// Returns the default style of a [`QRCode`].
- fn style() -> fn(&Self) -> Appearance;
+/// The style of a [`QRCode`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(default)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self) -> Appearance {
- default
+impl<Theme> From<fn(&Theme) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme) -> Appearance) -> Self {
+ Style(f)
}
}
diff --git a/widget/src/radio.rs b/widget/src/radio.rs
index 90a10a0b..83d17f01 100644
--- a/widget/src/radio.rs
+++ b/widget/src/radio.rs
@@ -82,7 +82,7 @@ where
text_line_height: text::LineHeight,
text_shaping: text::Shaping,
font: Option<Renderer::Font>,
- style: fn(&Theme, Status) -> Appearance,
+ style: Style<Theme>,
}
impl<Message, Theme, Renderer> Radio<Message, Theme, Renderer>
@@ -111,7 +111,7 @@ where
f: F,
) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
V: Eq + Copy,
F: FnOnce(V) -> Message,
{
@@ -126,7 +126,7 @@ where
text_line_height: text::LineHeight::default(),
text_shaping: text::Shaping::Basic,
font: None,
- style: Theme::style(),
+ style: Style::default(),
}
}
@@ -177,7 +177,7 @@ where
/// Sets the style of the [`Radio`] button.
pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {
- self.style = style.into();
+ self.style = Style(style);
self
}
}
@@ -298,7 +298,7 @@ where
Status::Active { is_selected }
};
- let appearance = (self.style)(theme, status);
+ let appearance = (self.style.0)(theme, status);
{
let layout = children.next().unwrap();
@@ -398,15 +398,27 @@ pub struct Appearance {
pub text_color: Option<Color>,
}
-/// The definiton of the default style of a [`Radio`] button.
-pub trait Style {
- /// Returns the default style of a [`Radio`] button.
- fn style() -> fn(&Self, Status) -> Appearance;
+/// The style of a [`Radio`] button.
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme, Status) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(default)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self, Status) -> Appearance {
- default
+impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme, Status) -> Appearance) -> Self {
+ Style(f)
}
}
diff --git a/widget/src/rule.rs b/widget/src/rule.rs
index 1a1ba106..53a077aa 100644
--- a/widget/src/rule.rs
+++ b/widget/src/rule.rs
@@ -15,39 +15,39 @@ pub struct Rule<Theme = crate::Theme> {
width: Length,
height: Length,
is_horizontal: bool,
- style: fn(&Theme) -> Appearance,
+ style: Style<Theme>,
}
impl<Theme> Rule<Theme> {
/// Creates a horizontal [`Rule`] with the given height.
pub fn horizontal(height: impl Into<Pixels>) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
{
Rule {
width: Length::Fill,
height: Length::Fixed(height.into().0),
is_horizontal: true,
- style: Theme::style(),
+ style: Style::default(),
}
}
/// Creates a vertical [`Rule`] with the given width.
pub fn vertical(width: impl Into<Pixels>) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
{
Rule {
width: Length::Fixed(width.into().0),
height: Length::Fill,
is_horizontal: false,
- style: Theme::style(),
+ style: Style::default(),
}
}
/// Sets the style of the [`Rule`].
pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self {
- self.style = style;
+ self.style = Style(style);
self
}
}
@@ -83,7 +83,7 @@ where
_viewport: &Rectangle,
) {
let bounds = layout.bounds();
- let appearance = (self.style)(theme);
+ let appearance = (self.style.0)(theme);
let bounds = if self.is_horizontal {
let line_y = (bounds.y + (bounds.height / 2.0)
@@ -216,15 +216,27 @@ impl FillMode {
}
}
-/// The definiton of the default style of a [`Rule`].
-pub trait Style {
- /// Returns the default style of a [`Rule`].
- fn style() -> fn(&Self) -> Appearance;
+/// The style of a [`Rule`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(default)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self) -> Appearance {
- default
+impl<Theme> From<fn(&Theme) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme) -> Appearance) -> Self {
+ Style(f)
}
}
diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs
index 9772855e..19a80ee2 100644
--- a/widget/src/scrollable.rs
+++ b/widget/src/scrollable.rs
@@ -37,7 +37,7 @@ pub struct Scrollable<
direction: Direction,
content: Element<'a, Message, Theme, Renderer>,
on_scroll: Option<Box<dyn Fn(Viewport) -> Message + 'a>>,
- style: fn(&Theme, Status) -> Appearance,
+ style: Style<Theme>,
}
impl<'a, Message, Theme, Renderer> Scrollable<'a, Message, Theme, Renderer>
@@ -49,7 +49,7 @@ where
content: impl Into<Element<'a, Message, Theme, Renderer>>,
) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
{
Self::with_direction(content, Direction::default())
}
@@ -60,8 +60,17 @@ where
direction: Direction,
) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
{
+ Self::with_direction_and_style(content, direction, Style::default().0)
+ }
+
+ /// Creates a new [`Scrollable`] with the given [`Direction`] and style.
+ pub fn with_direction_and_style(
+ content: impl Into<Element<'a, Message, Theme, Renderer>>,
+ direction: Direction,
+ style: fn(&Theme, Status) -> Appearance,
+ ) -> Self {
let content = content.into();
debug_assert!(
@@ -83,7 +92,7 @@ where
direction,
content,
on_scroll: None,
- style: Theme::style(),
+ style: style.into(),
}
}
@@ -115,7 +124,7 @@ where
/// Sets the style of the [`Scrollable`] .
pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {
- self.style = style;
+ self.style = style.into();
self
}
}
@@ -399,7 +408,7 @@ where
Status::Active
};
- let appearance = (self.style)(theme, status);
+ let appearance = (self.style.0)(theme, status);
container::draw_background(
renderer,
@@ -1653,15 +1662,27 @@ pub struct Scroller {
pub border: Border,
}
-/// The definition of the default style of a [`Scrollable`].
-pub trait Style {
- /// Returns the default style of a [`Scrollable`].
- fn style() -> fn(&Self, Status) -> Appearance;
+/// The style of a [`Scrollable`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme, Status) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(default)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self, Status) -> Appearance {
- default
+impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme, Status) -> Appearance) -> Self {
+ Style(f)
}
}
diff --git a/widget/src/slider.rs b/widget/src/slider.rs
index a40f8792..c48fe143 100644
--- a/widget/src/slider.rs
+++ b/widget/src/slider.rs
@@ -53,7 +53,7 @@ pub struct Slider<'a, T, Message, Theme = crate::Theme> {
on_release: Option<Message>,
width: Length,
height: f32,
- style: fn(&Theme, Status) -> Appearance,
+ style: Style<Theme>,
}
impl<'a, T, Message, Theme> Slider<'a, T, Message, Theme>
@@ -74,7 +74,7 @@ where
/// `Message`.
pub fn new<F>(range: RangeInclusive<T>, value: T, on_change: F) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
F: 'a + Fn(T) -> Message,
{
let value = if value >= *range.start() {
@@ -99,7 +99,7 @@ where
on_release: None,
width: Length::Fill,
height: Self::DEFAULT_HEIGHT,
- style: Theme::style(),
+ style: Style::default(),
}
}
@@ -136,7 +136,7 @@ where
/// Sets the style of the [`Slider`].
pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {
- self.style = style;
+ self.style = style.into();
self
}
@@ -350,7 +350,7 @@ where
let bounds = layout.bounds();
let is_mouse_over = cursor.is_over(bounds);
- let style = (self.style)(
+ let style = (self.style.0)(
theme,
if state.is_dragging {
Status::Dragged
@@ -550,15 +550,27 @@ pub enum HandleShape {
},
}
-/// The definiton of the default style of a [`TextInput`].
-pub trait Style {
- /// Returns the default style of a [`TextInput`].
- fn style() -> fn(&Self, Status) -> Appearance;
+/// The style of a [`Slider`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(pub(crate) fn(&Theme, Status) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(default)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self, Status) -> Appearance {
- default
+impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme, Status) -> Appearance) -> Self {
+ Style(f)
}
}
diff --git a/widget/src/svg.rs b/widget/src/svg.rs
index 8ac5a1cf..c80fa6b1 100644
--- a/widget/src/svg.rs
+++ b/widget/src/svg.rs
@@ -81,7 +81,7 @@ impl<Theme> Svg<Theme> {
/// Sets the style variant of this [`Svg`].
#[must_use]
pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {
- self.style = style.into();
+ self.style = Style(style);
self
}
}
diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs
index 91670228..73b006fa 100644
--- a/widget/src/text_editor.rs
+++ b/widget/src/text_editor.rs
@@ -42,7 +42,7 @@ pub struct TextEditor<
width: Length,
height: Length,
padding: Padding,
- style: fn(&Theme, Status) -> Appearance,
+ style: Style<Theme>,
on_edit: Option<Box<dyn Fn(Action) -> Message + 'a>>,
highlighter_settings: Highlighter::Settings,
highlighter_format: fn(
@@ -59,7 +59,7 @@ where
/// Creates new [`TextEditor`] with the given [`Content`].
pub fn new(content: &'a Content<Renderer>) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
{
Self {
content,
@@ -69,7 +69,7 @@ where
width: Length::Fill,
height: Length::Shrink,
padding: Padding::new(5.0),
- style: Theme::style(),
+ style: Style::default(),
on_edit: None,
highlighter_settings: (),
highlighter_format: |_highlight, _theme| {
@@ -144,7 +144,7 @@ where
/// Sets the style of the [`TextEditor`].
pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {
- self.style = style;
+ self.style = style.into();
self
}
}
@@ -506,7 +506,7 @@ where
Status::Active
};
- let appearance = (self.style)(theme, status);
+ let appearance = (self.style.0)(theme, status);
renderer.fill_quad(
renderer::Quad {
@@ -809,15 +809,27 @@ pub struct Appearance {
pub selection: Color,
}
-/// The definiton of the default style of a [`TextInput`].
-pub trait Style {
- /// Returns the default style of a [`TextInput`].
- fn style() -> fn(&Self, Status) -> Appearance;
+/// The style of a [`TextEditor`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme, Status) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(default)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self, Status) -> Appearance {
- default
+impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme, Status) -> Appearance) -> Self {
+ Style(f)
}
}
diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs
index 11b0a5d5..bae84db7 100644
--- a/widget/src/text_input.rs
+++ b/widget/src/text_input.rs
@@ -77,7 +77,7 @@ pub struct TextInput<
on_paste: Option<Box<dyn Fn(String) -> Message + 'a>>,
on_submit: Option<Message>,
icon: Option<Icon<Renderer::Font>>,
- style: fn(&Theme, Status) -> Appearance,
+ style: Style<Theme>,
}
/// The default [`Padding`] of a [`TextInput`].
@@ -88,15 +88,22 @@ where
Message: Clone,
Renderer: text::Renderer,
{
- /// Creates a new [`TextInput`].
- ///
- /// It expects:
- /// - a placeholder,
- /// - the current value
+ /// Creates a new [`TextInput`] with the given placeholder and
+ /// its current value.
pub fn new(placeholder: &str, value: &str) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
{
+ Self::with_style(placeholder, value, Style::default().0)
+ }
+
+ /// Creates a new [`TextInput`] with the given placeholder,
+ /// its current value, and its style.
+ pub fn with_style(
+ placeholder: &str,
+ value: &str,
+ style: fn(&Theme, Status) -> Appearance,
+ ) -> Self {
TextInput {
id: None,
placeholder: String::from(placeholder),
@@ -111,7 +118,7 @@ where
on_paste: None,
on_submit: None,
icon: None,
- style: Theme::style(),
+ style: style.into(),
}
}
@@ -199,7 +206,7 @@ where
/// Sets the style of the [`TextInput`].
pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {
- self.style = style;
+ self.style = style.into();
self
}
@@ -337,7 +344,7 @@ where
Status::Active
};
- let appearance = (self.style)(theme, status);
+ let appearance = (self.style.0)(theme, status);
renderer.fill_quad(
renderer::Quad {
@@ -1406,15 +1413,27 @@ pub struct Appearance {
pub selection: Color,
}
-/// The definiton of the default style of a [`TextInput`].
-pub trait Style {
- /// Returns the default style of a [`TextInput`].
- fn style() -> fn(&Self, Status) -> Appearance;
+/// The style of a [`TextInput`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme, Status) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(default)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self, Status) -> Appearance {
- default
+impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme, Status) -> Appearance) -> Self {
+ Style(f)
}
}
diff --git a/widget/src/toggler.rs b/widget/src/toggler.rs
index 1f19212d..cecd7b6c 100644
--- a/widget/src/toggler.rs
+++ b/widget/src/toggler.rs
@@ -50,7 +50,7 @@ pub struct Toggler<
text_shaping: text::Shaping,
spacing: f32,
font: Option<Renderer::Font>,
- style: fn(&Theme, Status) -> Appearance,
+ style: Style<Theme>,
}
impl<'a, Message, Theme, Renderer> Toggler<'a, Message, Theme, Renderer>
@@ -74,7 +74,7 @@ where
f: F,
) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
F: 'a + Fn(bool) -> Message,
{
Toggler {
@@ -89,7 +89,7 @@ where
text_shaping: text::Shaping::Basic,
spacing: Self::DEFAULT_SIZE / 2.0,
font: None,
- style: Theme::style(),
+ style: Style::default(),
}
}
@@ -301,7 +301,7 @@ where
}
};
- let appearance = (self.style)(theme, status);
+ let appearance = (self.style.0)(theme, status);
let border_radius = bounds.height / BORDER_RADIUS_RATIO;
let space = SPACE_RATIO * bounds.height;
@@ -399,15 +399,27 @@ pub struct Appearance {
pub foreground_border_color: Color,
}
-/// The definiton of the default style of a [`Toggler`].
-pub trait Style {
- /// Returns the default style of a [`Toggler`].
- fn style() -> fn(&Self, Status) -> Appearance;
+/// The style of a [`Toggler`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Style<Theme>(fn(&Theme, Status) -> Appearance);
+
+impl<Theme> Clone for Style<Theme> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<Theme> Copy for Style<Theme> {}
+
+impl Default for Style<Theme> {
+ fn default() -> Self {
+ Style(default)
+ }
}
-impl Style for Theme {
- fn style() -> fn(&Self, Status) -> Appearance {
- default
+impl<Theme> From<fn(&Theme, Status) -> Appearance> for Style<Theme> {
+ fn from(f: fn(&Theme, Status) -> Appearance) -> Self {
+ Style(f)
}
}
diff --git a/widget/src/tooltip.rs b/widget/src/tooltip.rs
index 956383da..4e026e8f 100644
--- a/widget/src/tooltip.rs
+++ b/widget/src/tooltip.rs
@@ -28,7 +28,7 @@ pub struct Tooltip<
gap: f32,
padding: f32,
snap_within_viewport: bool,
- style: fn(&Theme, container::Status) -> container::Appearance,
+ style: container::Style<Theme>,
}
impl<'a, Message, Theme, Renderer> Tooltip<'a, Message, Theme, Renderer>
@@ -47,7 +47,7 @@ where
position: Position,
) -> Self
where
- Theme: container::Style,
+ container::Style<Theme>: Default,
{
Tooltip {
content: content.into(),
@@ -56,7 +56,7 @@ where
gap: 0.0,
padding: Self::DEFAULT_PADDING,
snap_within_viewport: true,
- style: Theme::style(),
+ style: container::Style::default(),
}
}
@@ -83,7 +83,7 @@ where
mut self,
style: fn(&Theme, container::Status) -> container::Appearance,
) -> Self {
- self.style = style;
+ self.style = style.into();
self
}
}
@@ -309,7 +309,7 @@ where
positioning: Position,
gap: f32,
padding: f32,
- style: fn(&Theme, container::Status) -> container::Appearance,
+ style: container::Style<Theme>,
}
impl<'a, 'b, Message, Theme, Renderer>
@@ -424,7 +424,7 @@ where
layout: Layout<'_>,
cursor_position: mouse::Cursor,
) {
- let style = (self.style)(theme, container::Status::Idle);
+ let style = self.style.resolve(theme, container::Status::Idle);
container::draw_background(renderer, &style, layout.bounds());
diff --git a/widget/src/vertical_slider.rs b/widget/src/vertical_slider.rs
index b51aa2bf..47c400c7 100644
--- a/widget/src/vertical_slider.rs
+++ b/widget/src/vertical_slider.rs
@@ -54,7 +54,7 @@ pub struct VerticalSlider<'a, T, Message, Theme = crate::Theme> {
on_release: Option<Message>,
width: f32,
height: Length,
- style: fn(&Theme, Status) -> Appearance,
+ style: Style<Theme>,
}
impl<'a, T, Message, Theme> VerticalSlider<'a, T, Message, Theme>
@@ -75,7 +75,7 @@ where
/// `Message`.
pub fn new<F>(range: RangeInclusive<T>, value: T, on_change: F) -> Self
where
- Theme: Style,
+ Style<Theme>: Default,
F: 'a + Fn(T) -> Message,
{
let value = if value >= *range.start() {
@@ -100,7 +100,7 @@ where
on_release: None,
width: Self::DEFAULT_WIDTH,
height: Length::Fill,
- style: Theme::style(),
+ style: Style::default(),
}
}
@@ -136,10 +136,7 @@ where
}
/// Sets the style of the [`VerticalSlider`].
- pub fn style(
- mut self,
- style: impl Into<fn(&Theme, Status) -> Appearance>,
- ) -> Self {
+ pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {
self.style = style.into();
self
}
@@ -357,7 +354,7 @@ where
let bounds = layout.bounds();
let is_mouse_over = cursor.is_over(bounds);
- let style = (self.style)(
+ let style = (self.style.0)(
theme,
if state.is_dragging {
Status::Dragged