Skip to main content

iced_widget/
themer.rs

1use crate::container;
2use crate::core::layout;
3use crate::core::mouse;
4use crate::core::overlay;
5use crate::core::renderer;
6use crate::core::theme;
7use crate::core::widget::tree::{self, Tree};
8use crate::core::widget::{Meta, Operation};
9use crate::core::{
10    Background, Color, Element, Event, Layout, Length, Rectangle, Shell, Size, Vector, Widget,
11};
12
13/// A widget that applies any `Theme` to its contents.
14///
15/// This widget can be useful to leverage multiple `Theme`
16/// types in an application.
17pub struct Themer<'a, Message, Theme, Renderer = crate::Renderer> {
18    content: Element<'a, Message, Theme, Renderer>,
19    theme: Option<Theme>,
20    text_color: Option<fn(&Theme) -> Color>,
21    background: Option<fn(&Theme) -> Background>,
22}
23
24impl<'a, Message, Theme, Renderer> Themer<'a, Message, Theme, Renderer> {
25    /// Creates an empty [`Themer`] that applies the given `Theme`
26    /// to the provided `content`.
27    pub fn new(theme: Option<Theme>, content: impl Widget<Message, Theme, Renderer> + 'a) -> Self {
28        Self {
29            content: content._boxed(),
30            theme,
31            text_color: None,
32            background: None,
33        }
34    }
35
36    /// Sets the default text [`Color`] of the [`Themer`].
37    pub fn text_color(mut self, f: fn(&Theme) -> Color) -> Self {
38        self.text_color = Some(f);
39        self
40    }
41
42    /// Sets the [`Background`] of the [`Themer`].
43    pub fn background(mut self, f: fn(&Theme) -> Background) -> Self {
44        self.background = Some(f);
45        self
46    }
47}
48
49impl<Message, Theme, Renderer> Meta for Themer<'_, Message, Theme, Renderer> {}
50
51impl<Message, Theme, Renderer, AnyTheme> Widget<Message, AnyTheme, Renderer>
52    for Themer<'_, Message, Theme, Renderer>
53where
54    Theme: theme::Base,
55    AnyTheme: theme::Base,
56    Renderer: crate::core::Renderer,
57{
58    fn tag(&self) -> tree::Tag {
59        self.content.tag()
60    }
61
62    fn state(&self) -> tree::State {
63        self.content.state()
64    }
65
66    fn diff(&mut self, tree: &mut Tree) {
67        self.content.diff(tree);
68    }
69
70    fn size(&self) -> Size<Length> {
71        self.content.size()
72    }
73
74    fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
75        self.content.layout(tree, renderer, limits);
76    }
77
78    fn operate(
79        &mut self,
80        tree: &mut Tree,
81        layout: Layout,
82        viewport: &Rectangle,
83        renderer: &Renderer,
84        operation: &mut dyn Operation,
85    ) {
86        self.content
87            .operate(tree, layout, viewport, renderer, operation);
88    }
89
90    fn update(
91        &mut self,
92        tree: &mut Tree,
93        event: &Event,
94        layout: Layout,
95        cursor: mouse::Cursor,
96        renderer: &Renderer,
97        shell: &mut Shell<'_, Message>,
98        viewport: &Rectangle,
99    ) {
100        self.content
101            .update(tree, event, layout, cursor, renderer, shell, viewport);
102    }
103
104    fn mouse_interaction(
105        &self,
106        tree: &Tree,
107        layout: Layout,
108        cursor: mouse::Cursor,
109        viewport: &Rectangle,
110        renderer: &Renderer,
111    ) -> mouse::Interaction {
112        self.content
113            .mouse_interaction(tree, layout, cursor, viewport, renderer)
114    }
115
116    fn draw(
117        &self,
118        tree: &Tree,
119        renderer: &mut Renderer,
120        theme: &AnyTheme,
121        style: &renderer::Style,
122        layout: Layout,
123        cursor: mouse::Cursor,
124        viewport: &Rectangle,
125    ) {
126        let default_theme = theme::Base::default(theme.mode());
127        let theme = self.theme.as_ref().unwrap_or(&default_theme);
128
129        if let Some(background) = self.background {
130            container::draw_background(
131                renderer,
132                &container::Style {
133                    background: Some(background(theme)),
134                    ..container::Style::default()
135                },
136                layout.bounds(),
137            );
138        }
139
140        let style = if let Some(text_color) = self.text_color {
141            renderer::Style {
142                text_color: text_color(theme),
143            }
144        } else {
145            *style
146        };
147
148        self.content
149            .draw(tree, renderer, theme, &style, layout, cursor, viewport);
150    }
151
152    fn overlay<'b>(
153        &'b mut self,
154        tree: &'b mut Tree,
155        layout: Layout,
156        renderer: &Renderer,
157        viewport: &Rectangle,
158        translation: Vector,
159        window: Size,
160    ) -> Vec<overlay::Element<'b, Message, AnyTheme, Renderer>> {
161        struct Overlay<'a, Message, Theme, Renderer> {
162            theme: &'a Option<Theme>,
163            content: overlay::Element<'a, Message, Theme, Renderer>,
164        }
165
166        impl<Message, Theme, Renderer, AnyTheme> overlay::Overlay<Message, AnyTheme, Renderer>
167            for Overlay<'_, Message, Theme, Renderer>
168        where
169            Theme: theme::Base,
170            AnyTheme: theme::Base,
171        {
172            fn draw(
173                &self,
174                renderer: &mut Renderer,
175                theme: &AnyTheme,
176                style: &renderer::Style,
177                cursor: mouse::Cursor,
178            ) {
179                let default_theme = theme::Base::default(theme.mode());
180                let theme = self.theme.as_ref().unwrap_or(&default_theme);
181
182                self.content
183                    .as_overlay()
184                    .draw(renderer, theme, style, cursor);
185            }
186
187            fn update(
188                &mut self,
189                event: &Event,
190                cursor: mouse::Cursor,
191                renderer: &Renderer,
192                shell: &mut Shell<'_, Message>,
193            ) {
194                self.content
195                    .as_overlay_mut()
196                    .update(event, cursor, renderer, shell);
197            }
198
199            fn operate(&mut self, renderer: &Renderer, operation: &mut dyn Operation) {
200                self.content.as_overlay_mut().operate(renderer, operation);
201            }
202
203            fn mouse_interaction(
204                &self,
205                cursor: mouse::Cursor,
206                renderer: &Renderer,
207            ) -> mouse::Interaction {
208                self.content
209                    .as_overlay()
210                    .mouse_interaction(cursor, renderer)
211            }
212
213            fn index(&self) -> f32 {
214                self.content.as_overlay().index()
215            }
216
217            fn overlay<'c>(
218                &'c mut self,
219                renderer: &Renderer,
220            ) -> Vec<overlay::Element<'c, Message, AnyTheme, Renderer>> {
221                let theme = self.theme;
222
223                self.content
224                    .as_overlay_mut()
225                    .overlay(renderer)
226                    .into_iter()
227                    .map(|content| overlay::Element::new(Box::new(Overlay { theme, content })))
228                    .collect()
229            }
230        }
231
232        self.content
233            .overlay(tree, layout, renderer, viewport, translation, window)
234            .into_iter()
235            .map(|content| {
236                overlay::Element::new(Box::new(Overlay {
237                    theme: &self.theme,
238                    content,
239                }))
240            })
241            .collect()
242    }
243}