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