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::Operation;
8use crate::core::widget::tree::{self, Tree};
9use crate::core::{
10 Background, Color, Element, Event, Layout, Length, Rectangle, Shell, Size, Vector, Widget,
11};
12
13pub struct Themer<'a, Message, Theme, Renderer = crate::Renderer>
18where
19 Renderer: crate::core::Renderer,
20{
21 content: Element<'a, Message, Theme, Renderer>,
22 theme: Option<Theme>,
23 text_color: Option<fn(&Theme) -> Color>,
24 background: Option<fn(&Theme) -> Background>,
25}
26
27impl<'a, Message, Theme, Renderer> Themer<'a, Message, Theme, Renderer>
28where
29 Renderer: crate::core::Renderer,
30{
31 pub fn new(
34 theme: Option<Theme>,
35 content: impl Into<Element<'a, Message, Theme, Renderer>>,
36 ) -> Self {
37 Self {
38 content: content.into(),
39 theme,
40 text_color: None,
41 background: None,
42 }
43 }
44
45 pub fn text_color(mut self, f: fn(&Theme) -> Color) -> Self {
47 self.text_color = Some(f);
48 self
49 }
50
51 pub fn background(mut self, f: fn(&Theme) -> Background) -> Self {
53 self.background = Some(f);
54 self
55 }
56}
57
58impl<Message, Theme, Renderer, AnyTheme> Widget<Message, AnyTheme, Renderer>
59 for Themer<'_, Message, Theme, Renderer>
60where
61 Theme: theme::Base,
62 AnyTheme: theme::Base,
63 Renderer: crate::core::Renderer,
64{
65 fn tag(&self) -> tree::Tag {
66 self.content.as_widget().tag()
67 }
68
69 fn state(&self) -> tree::State {
70 self.content.as_widget().state()
71 }
72
73 fn children(&self) -> Vec<Tree> {
74 self.content.as_widget().children()
75 }
76
77 fn diff(&self, tree: &mut Tree) {
78 self.content.as_widget().diff(tree);
79 }
80
81 fn size(&self) -> Size<Length> {
82 self.content.as_widget().size()
83 }
84
85 fn layout(
86 &mut self,
87 tree: &mut Tree,
88 renderer: &Renderer,
89 limits: &layout::Limits,
90 ) -> layout::Node {
91 self.content.as_widget_mut().layout(tree, renderer, limits)
92 }
93
94 fn operate(
95 &mut self,
96 tree: &mut Tree,
97 layout: Layout<'_>,
98 renderer: &Renderer,
99 operation: &mut dyn Operation,
100 ) {
101 self.content
102 .as_widget_mut()
103 .operate(tree, layout, renderer, operation);
104 }
105
106 fn update(
107 &mut self,
108 tree: &mut Tree,
109 event: &Event,
110 layout: Layout<'_>,
111 cursor: mouse::Cursor,
112 renderer: &Renderer,
113 shell: &mut Shell<'_, Message>,
114 viewport: &Rectangle,
115 ) {
116 self.content
117 .as_widget_mut()
118 .update(tree, event, layout, cursor, renderer, shell, viewport);
119 }
120
121 fn mouse_interaction(
122 &self,
123 tree: &Tree,
124 layout: Layout<'_>,
125 cursor: mouse::Cursor,
126 viewport: &Rectangle,
127 renderer: &Renderer,
128 ) -> mouse::Interaction {
129 self.content
130 .as_widget()
131 .mouse_interaction(tree, layout, cursor, viewport, renderer)
132 }
133
134 fn draw(
135 &self,
136 tree: &Tree,
137 renderer: &mut Renderer,
138 theme: &AnyTheme,
139 style: &renderer::Style,
140 layout: Layout<'_>,
141 cursor: mouse::Cursor,
142 viewport: &Rectangle,
143 ) {
144 let default_theme = theme::Base::default(theme.mode());
145 let theme = self.theme.as_ref().unwrap_or(&default_theme);
146
147 if let Some(background) = self.background {
148 container::draw_background(
149 renderer,
150 &container::Style {
151 background: Some(background(theme)),
152 ..container::Style::default()
153 },
154 layout.bounds(),
155 );
156 }
157
158 let style = if let Some(text_color) = self.text_color {
159 renderer::Style {
160 text_color: text_color(theme),
161 }
162 } else {
163 *style
164 };
165
166 self.content
167 .as_widget()
168 .draw(tree, renderer, theme, &style, layout, cursor, viewport);
169 }
170
171 fn overlay<'b>(
172 &'b mut self,
173 tree: &'b mut Tree,
174 layout: Layout<'b>,
175 renderer: &Renderer,
176 viewport: &Rectangle,
177 translation: Vector,
178 ) -> Option<overlay::Element<'b, Message, AnyTheme, Renderer>> {
179 struct Overlay<'a, Message, Theme, Renderer> {
180 theme: &'a Option<Theme>,
181 content: overlay::Element<'a, Message, Theme, Renderer>,
182 }
183
184 impl<Message, Theme, Renderer, AnyTheme> overlay::Overlay<Message, AnyTheme, Renderer>
185 for Overlay<'_, Message, Theme, Renderer>
186 where
187 Theme: theme::Base,
188 AnyTheme: theme::Base,
189 Renderer: crate::core::Renderer,
190 {
191 fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
192 self.content.as_overlay_mut().layout(renderer, bounds)
193 }
194
195 fn draw(
196 &self,
197 renderer: &mut Renderer,
198 theme: &AnyTheme,
199 style: &renderer::Style,
200 layout: Layout<'_>,
201 cursor: mouse::Cursor,
202 ) {
203 let default_theme = theme::Base::default(theme.mode());
204 let theme = self.theme.as_ref().unwrap_or(&default_theme);
205
206 self.content
207 .as_overlay()
208 .draw(renderer, theme, style, layout, cursor);
209 }
210
211 fn update(
212 &mut self,
213 event: &Event,
214 layout: Layout<'_>,
215 cursor: mouse::Cursor,
216 renderer: &Renderer,
217 shell: &mut Shell<'_, Message>,
218 ) {
219 self.content
220 .as_overlay_mut()
221 .update(event, layout, cursor, renderer, shell);
222 }
223
224 fn operate(
225 &mut self,
226 layout: Layout<'_>,
227 renderer: &Renderer,
228 operation: &mut dyn Operation,
229 ) {
230 self.content
231 .as_overlay_mut()
232 .operate(layout, renderer, operation);
233 }
234
235 fn mouse_interaction(
236 &self,
237 layout: Layout<'_>,
238 cursor: mouse::Cursor,
239 renderer: &Renderer,
240 ) -> mouse::Interaction {
241 self.content
242 .as_overlay()
243 .mouse_interaction(layout, cursor, renderer)
244 }
245
246 fn overlay<'b>(
247 &'b mut self,
248 layout: Layout<'b>,
249 renderer: &Renderer,
250 ) -> Option<overlay::Element<'b, Message, AnyTheme, Renderer>> {
251 self.content
252 .as_overlay_mut()
253 .overlay(layout, renderer)
254 .map(|content| Overlay {
255 theme: self.theme,
256 content,
257 })
258 .map(|overlay| overlay::Element::new(Box::new(overlay)))
259 }
260 }
261
262 self.content
263 .as_widget_mut()
264 .overlay(tree, layout, renderer, viewport, translation)
265 .map(|content| Overlay {
266 theme: &self.theme,
267 content,
268 })
269 .map(|overlay| overlay::Element::new(Box::new(overlay)))
270 }
271}
272
273impl<'a, Message, Theme, Renderer, AnyTheme> From<Themer<'a, Message, Theme, Renderer>>
274 for Element<'a, Message, AnyTheme, Renderer>
275where
276 Message: 'a,
277 Theme: theme::Base + 'a,
278 AnyTheme: theme::Base,
279 Renderer: 'a + crate::core::Renderer,
280{
281 fn from(
282 themer: Themer<'a, Message, Theme, Renderer>,
283 ) -> Element<'a, Message, AnyTheme, Renderer> {
284 Element::new(themer)
285 }
286}