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