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