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