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