Skip to content

Commit b85c504

Browse files
authored
theme: Use boxed functions instead fn pointers (#99)
This is more general, and necessary if the custom theming is dynamically generated. Iced's builtin theme also uses `Box`ed `Fn`, or `Rc` where clone is required, so this seems reasonable. Only `Text` is left using `fn`, since it needs to be `Copy`. Hopefully that can be changed in Iced at some point. `::custom` methods are added to make these variants a little more convenient to construct. This replaces a couple `From` implementations, which are potentially problematic with a generic.
1 parent c878e24 commit b85c504

File tree

11 files changed

+65
-63
lines changed

11 files changed

+65
-63
lines changed

examples/cosmic/src/window.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ impl Window {
277277
.spacing(16),
278278
)
279279
.padding([20, 24])
280-
.style(theme::Container::Custom(list::column::style)),
280+
.style(theme::Container::custom(list::column::style)),
281281
)
282282
.padding(0)
283283
.style(theme::Button::Transparent)

src/applet/mod.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,18 @@ pub use cosmic_panel_config;
1919

2020
const APPLET_PADDING: u32 = 8;
2121

22-
pub const APPLET_BUTTON_THEME: Button = Button::Custom {
23-
active: |t| iced_style::button::Appearance {
24-
border_radius: BorderRadius::from(0.0),
25-
..t.active(&Button::Text)
26-
},
27-
hover: |t| iced_style::button::Appearance {
28-
border_radius: BorderRadius::from(0.0),
29-
..t.hovered(&Button::Text)
30-
},
31-
};
22+
pub fn applet_button_theme() -> Button {
23+
Button::Custom {
24+
active: Box::new(|t| iced_style::button::Appearance {
25+
border_radius: BorderRadius::from(0.0),
26+
..t.active(&Button::Text)
27+
}),
28+
hover: Box::new(|t| iced_style::button::Appearance {
29+
border_radius: BorderRadius::from(0.0),
30+
..t.hovered(&Button::Text)
31+
}),
32+
}
33+
}
3234

3335
#[derive(Debug, Clone)]
3436
pub struct CosmicAppletHelper {
@@ -130,7 +132,7 @@ impl CosmicAppletHelper {
130132
};
131133

132134
Container::<Message, Renderer>::new(Container::<Message, Renderer>::new(content).style(
133-
crate::theme::Container::Custom(|theme| Appearance {
135+
crate::theme::Container::custom(|theme| Appearance {
134136
text_color: Some(theme.cosmic().background.on.into()),
135137
background: Some(Color::from(theme.cosmic().background.base).into()),
136138
border_radius: 12.0,

src/theme/expander.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl std::default::Default for Appearance {
5252

5353
/// A set of rules that dictate the [`Appearance`] of a container.
5454
pub trait StyleSheet {
55-
type Style: Default + Copy;
55+
type Style: Default;
5656

5757
/// Produces the [`Appearance`] of a container.
5858
fn appearance(&self, style: Self::Style) -> Appearance;

src/theme/mod.rs

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod segmented_button;
66

77
use std::hash::Hash;
88
use std::hash::Hasher;
9+
use std::rc::Rc;
910

1011
pub use self::segmented_button::SegmentedButton;
1112

@@ -132,15 +133,16 @@ impl LayeredTheme for Theme {
132133
}
133134
}
134135

135-
#[derive(Clone, Copy)]
136+
#[derive(Default)]
136137
pub enum Application {
138+
#[default]
137139
Default,
138-
Custom(fn(&Theme) -> application::Appearance),
140+
Custom(Box<dyn Fn(&Theme) -> application::Appearance>),
139141
}
140142

141-
impl Default for Application {
142-
fn default() -> Self {
143-
Self::Default
143+
impl Application {
144+
pub fn custom<F: Fn(&Theme) -> application::Appearance + 'static>(f: F) -> Self {
145+
Self::Custom(Box::new(f))
144146
}
145147
}
146148

@@ -163,7 +165,6 @@ impl application::StyleSheet for Theme {
163165
/*
164166
* TODO: Button
165167
*/
166-
#[derive(Clone, Copy)]
167168
pub enum Button {
168169
Deactivated,
169170
Destructive,
@@ -175,8 +176,8 @@ pub enum Button {
175176
LinkActive,
176177
Transparent,
177178
Custom {
178-
active: fn(&Theme) -> button::Appearance,
179-
hover: fn(&Theme) -> button::Appearance,
179+
active: Box<dyn Fn(&Theme) -> button::Appearance>,
180+
hover: Box<dyn Fn(&Theme) -> button::Appearance>,
180181
},
181182
}
182183

@@ -439,21 +440,16 @@ impl checkbox::StyleSheet for Theme {
439440
}
440441
}
441442

442-
#[derive(Clone, Copy)]
443+
#[derive(Default)]
443444
pub enum Expander {
445+
#[default]
444446
Default,
445-
Custom(fn(&Theme) -> expander::Appearance),
446-
}
447-
448-
impl Default for Expander {
449-
fn default() -> Self {
450-
Self::Default
451-
}
447+
Custom(Box<dyn Fn(&Theme) -> expander::Appearance>),
452448
}
453449

454-
impl From<fn(&Theme) -> expander::Appearance> for Expander {
455-
fn from(f: fn(&Theme) -> expander::Appearance) -> Self {
456-
Self::Custom(f)
450+
impl Expander {
451+
pub fn custom<F: Fn(&Theme) -> expander::Appearance + 'static>(f: F) -> Self {
452+
Self::Custom(Box::new(f))
457453
}
458454
}
459455

@@ -471,24 +467,19 @@ impl expander::StyleSheet for Theme {
471467
/*
472468
* TODO: Container
473469
*/
474-
#[derive(Clone, Copy)]
470+
#[derive(Default)]
475471
pub enum Container {
476472
Background,
477473
Primary,
478474
Secondary,
475+
#[default]
479476
Transparent,
480-
Custom(fn(&Theme) -> container::Appearance),
481-
}
482-
483-
impl Default for Container {
484-
fn default() -> Self {
485-
Self::Transparent
486-
}
477+
Custom(Box<dyn Fn(&Theme) -> container::Appearance>),
487478
}
488479

489-
impl From<fn(&Theme) -> container::Appearance> for Container {
490-
fn from(_: fn(&Theme) -> container::Appearance) -> Self {
491-
Self::default()
480+
impl Container {
481+
pub fn custom<F: Fn(&Theme) -> container::Appearance + 'static>(f: F) -> Self {
482+
Self::Custom(Box::new(f))
492483
}
493484
}
494485

@@ -754,17 +745,18 @@ impl pane_grid::StyleSheet for Theme {
754745
/*
755746
* TODO: Progress Bar
756747
*/
757-
#[derive(Clone, Copy)]
748+
#[derive(Default)]
758749
pub enum ProgressBar {
750+
#[default]
759751
Primary,
760752
Success,
761753
Danger,
762-
Custom(fn(&Theme) -> progress_bar::Appearance),
754+
Custom(Box<dyn Fn(&Theme) -> progress_bar::Appearance>),
763755
}
764756

765-
impl Default for ProgressBar {
766-
fn default() -> Self {
767-
Self::Primary
757+
impl ProgressBar {
758+
pub fn custom<F: Fn(&Theme) -> progress_bar::Appearance + 'static>(f: F) -> Self {
759+
Self::Custom(Box::new(f))
768760
}
769761
}
770762

@@ -798,17 +790,18 @@ impl progress_bar::StyleSheet for Theme {
798790
/*
799791
* TODO: Rule
800792
*/
801-
#[derive(Clone, Copy)]
793+
#[derive(Default)]
802794
pub enum Rule {
795+
#[default]
803796
Default,
804797
LightDivider,
805798
HeavyDivider,
806-
Custom(fn(&Theme) -> rule::Appearance),
799+
Custom(Box<dyn Fn(&Theme) -> rule::Appearance>),
807800
}
808801

809-
impl Default for Rule {
810-
fn default() -> Self {
811-
Self::Default
802+
impl Rule {
803+
pub fn custom<F: Fn(&Theme) -> rule::Appearance + 'static>(f: F) -> Self {
804+
Self::Custom(Box::new(f))
812805
}
813806
}
814807

@@ -883,10 +876,10 @@ impl scrollable::StyleSheet for Theme {
883876
}
884877
}
885878

886-
#[derive(Default, Clone, Copy)]
879+
#[derive(Clone, Default)]
887880
pub enum Svg {
888881
/// Apply a custom appearance filter
889-
Custom(fn(&Theme) -> svg::Appearance),
882+
Custom(Rc<dyn Fn(&Theme) -> svg::Appearance>),
890883
/// No filtering is applied
891884
#[default]
892885
Default,
@@ -915,6 +908,12 @@ impl Hash for Svg {
915908
}
916909
}
917910

911+
impl Svg {
912+
pub fn custom<F: Fn(&Theme) -> svg::Appearance + 'static>(f: F) -> Self {
913+
Self::Custom(Rc::new(f))
914+
}
915+
}
916+
918917
impl svg::StyleSheet for Theme {
919918
type Style = Svg;
920919

@@ -948,6 +947,7 @@ pub enum Text {
948947
#[default]
949948
Default,
950949
Color(Color),
950+
// TODO: Can't use dyn Fn since this must be copy
951951
Custom(fn(&Theme) -> text::Appearance),
952952
}
953953

src/theme/segmented_button.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ use crate::{theme::Theme, widget::segmented_button::ItemStatusAppearance};
66
use iced_core::{Background, BorderRadius};
77
use palette::{rgb::Rgb, Alpha};
88

9-
#[derive(Clone, Copy, Default)]
9+
#[derive(Default)]
1010
pub enum SegmentedButton {
1111
/// A tabbed widget for switching between views in an interface.
1212
#[default]
1313
ViewSwitcher,
1414
/// A widget for multiple choice selection.
1515
Selection,
1616
/// Or implement any custom theme of your liking.
17-
Custom(fn(&Theme) -> Appearance),
17+
Custom(Box<dyn Fn(&Theme) -> Appearance>),
1818
}
1919

2020
impl StyleSheet for Theme {

src/widget/icon.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ impl<'a> Icon<'a> {
207207

208208
fn svg_element<Message: 'static>(&self, handle: svg::Handle) -> Element<'static, Message> {
209209
svg::Svg::<Renderer>::new(handle)
210-
.style(self.style)
210+
.style(self.style.clone())
211211
.width(self.width.unwrap_or(Length::Units(self.size)))
212212
.height(self.height.unwrap_or(Length::Units(self.size)))
213213
.content_fit(self.content_fit)

src/widget/list/column.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl<'a, Message: 'static> ListColumn<'a, Message> {
4545
.spacing(12)
4646
.apply(iced::widget::container)
4747
.padding([16, 6])
48-
.style(theme::Container::Custom(style))
48+
.style(theme::Container::custom(style))
4949
.into()
5050
}
5151
}

src/widget/nav_bar.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ where
3636
.apply(container)
3737
.height(Length::Fill)
3838
.padding(11)
39-
.style(theme::Container::Custom(nav_bar_style))
39+
.style(theme::Container::custom(nav_bar_style))
4040
}
4141

4242
#[must_use]

src/widget/search/field.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl<'a, Message: 'static + Clone> Field<'a, Message> {
5858
.spacing(8)
5959
.align_items(iced::Alignment::Center)
6060
.apply(container)
61-
.style(crate::theme::Container::Custom(active_style))
61+
.style(crate::theme::Container::custom(active_style))
6262
.into()
6363
}
6464
}

src/widget/spin_button/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ impl<'a, Message: 'static> SpinButton<'a, Message> {
8383
.align_y(Vertical::Center)
8484
.width(Length::Units(95))
8585
.height(Length::Units(32))
86-
.style(theme::Container::Custom(container_style))
86+
.style(theme::Container::custom(container_style))
8787
.apply(Element::from)
8888
.map(on_change)
8989
}

0 commit comments

Comments
 (0)