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, Point,
10 Rectangle, 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<'_>,
182 renderer: &Renderer,
183 translation: Vector,
184 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
185 struct Overlay<'a, Message, Theme, NewTheme, Renderer> {
186 to_theme: &'a dyn Fn(&Theme) -> NewTheme,
187 content: overlay::Element<'a, Message, NewTheme, Renderer>,
188 }
189
190 impl<Message, Theme, NewTheme, Renderer>
191 overlay::Overlay<Message, Theme, Renderer>
192 for Overlay<'_, Message, Theme, NewTheme, Renderer>
193 where
194 Renderer: crate::core::Renderer,
195 {
196 fn layout(
197 &mut self,
198 renderer: &Renderer,
199 bounds: Size,
200 ) -> layout::Node {
201 self.content.layout(renderer, bounds)
202 }
203
204 fn draw(
205 &self,
206 renderer: &mut Renderer,
207 theme: &Theme,
208 style: &renderer::Style,
209 layout: Layout<'_>,
210 cursor: mouse::Cursor,
211 ) {
212 self.content.draw(
213 renderer,
214 &(self.to_theme)(theme),
215 style,
216 layout,
217 cursor,
218 );
219 }
220
221 fn update(
222 &mut self,
223 event: &Event,
224 layout: Layout<'_>,
225 cursor: mouse::Cursor,
226 renderer: &Renderer,
227 clipboard: &mut dyn Clipboard,
228 shell: &mut Shell<'_, Message>,
229 ) {
230 self.content
231 .update(event, layout, cursor, renderer, clipboard, shell);
232 }
233
234 fn operate(
235 &mut self,
236 layout: Layout<'_>,
237 renderer: &Renderer,
238 operation: &mut dyn Operation,
239 ) {
240 self.content.operate(layout, renderer, operation);
241 }
242
243 fn mouse_interaction(
244 &self,
245 layout: Layout<'_>,
246 cursor: mouse::Cursor,
247 viewport: &Rectangle,
248 renderer: &Renderer,
249 ) -> mouse::Interaction {
250 self.content
251 .mouse_interaction(layout, cursor, viewport, renderer)
252 }
253
254 fn is_over(
255 &self,
256 layout: Layout<'_>,
257 renderer: &Renderer,
258 cursor_position: Point,
259 ) -> bool {
260 self.content.is_over(layout, renderer, cursor_position)
261 }
262
263 fn overlay<'b>(
264 &'b mut self,
265 layout: Layout<'_>,
266 renderer: &Renderer,
267 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>>
268 {
269 self.content
270 .overlay(layout, renderer)
271 .map(|content| Overlay {
272 to_theme: &self.to_theme,
273 content,
274 })
275 .map(|overlay| overlay::Element::new(Box::new(overlay)))
276 }
277 }
278
279 self.content
280 .as_widget_mut()
281 .overlay(tree, layout, renderer, translation)
282 .map(|content| Overlay {
283 to_theme: &self.to_theme,
284 content,
285 })
286 .map(|overlay| overlay::Element::new(Box::new(overlay)))
287 }
288}
289
290impl<'a, Message, Theme, NewTheme, F, Renderer>
291 From<Themer<'a, Message, Theme, NewTheme, F, Renderer>>
292 for Element<'a, Message, Theme, Renderer>
293where
294 Message: 'a,
295 Theme: 'a,
296 NewTheme: 'a,
297 F: Fn(&Theme) -> NewTheme + 'a,
298 Renderer: 'a + crate::core::Renderer,
299{
300 fn from(
301 themer: Themer<'a, Message, Theme, NewTheme, F, Renderer>,
302 ) -> Element<'a, Message, Theme, Renderer> {
303 Element::new(themer)
304 }
305}