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