1use crate::Action;
3use crate::core::event;
4use crate::core::layout::{self, Layout};
5use crate::core::mouse;
6use crate::core::overlay;
7use crate::core::renderer;
8use crate::core::shell;
9use crate::core::widget;
10use crate::core::widget::tree::{self, Tree};
11use crate::core::window;
12use crate::core::{Element, Event, Length, Rectangle, Shell, Size, Vector, Widget};
13
14use std::cell::{Cell, RefCell};
15
16pub trait Component<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {
43 type State: Default + 'static;
45
46 type Event: 'static;
48
49 fn update(
53 &self,
54 state: &mut Self::State,
55 event: Self::Event,
56 renderer: &Renderer,
57 ) -> Option<Message>;
58
59 fn view(&self, state: &Self::State) -> impl crate::Widget<Self::Event, Theme, Renderer> + 'a;
62
63 fn listen(
70 &self,
71 _state: &Self::State,
72 _event: &Event,
73 _bounds: Rectangle,
74 _cursor: mouse::Cursor,
75 ) -> Action<Self::Event> {
76 Action::none()
77 }
78
79 fn mouse_interaction(&self, _state: &Self::State) -> mouse::Interaction {
86 mouse::Interaction::None
87 }
88
89 fn diff(&mut self, _state: &mut Self::State) {}
97
98 fn operate(
102 &self,
103 _state: &mut Self::State,
104 _bounds: Rectangle,
105 _operation: &mut dyn widget::Operation,
106 ) {
107 }
108}
109
110pub fn component<'a, C, Message, Theme, Renderer>(
113 component: C,
114) -> impl Widget<Message, Theme, Renderer> + 'a
115where
116 C: Component<'a, Message, Theme, Renderer> + 'a,
117 C::State: 'static,
118 Message: 'a,
119 Theme: 'a,
120 Renderer: 'a,
121{
122 Instance {
123 component,
124 view: crate::space()._boxed(),
125 limits: layout::Limits::new(Size::ZERO, Size::INFINITE),
126 is_outdated: Cell::new(true),
127 has_overlay: false,
128 }
129}
130
131struct Instance<'a, C, Message, Theme, Renderer>
132where
133 C: Component<'a, Message, Theme, Renderer> + 'a,
134{
135 component: C,
136 view: Element<'a, C::Event, Theme, Renderer>,
137 limits: layout::Limits,
138 is_outdated: Cell<bool>,
139 has_overlay: bool,
140}
141
142struct Internal<State, Event> {
143 state: State,
144 events: shell::Bus<Event>,
145}
146
147impl<'a, C, Message, Theme, Renderer> widget::Meta for Instance<'a, C, Message, Theme, Renderer> where
148 C: Component<'a, Message, Theme, Renderer> + 'a
149{
150}
151
152impl<'a, C, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
153 for Instance<'a, C, Message, Theme, Renderer>
154where
155 C: Component<'a, Message, Theme, Renderer> + 'a,
156{
157 fn tag(&self) -> tree::Tag {
158 tree::Tag::of::<RefCell<Internal<C::State, C::Event>>>()
159 }
160
161 fn state(&self) -> tree::State {
162 tree::State::new(RefCell::new(Internal {
163 state: C::State::default(),
164 events: shell::Bus::<C::Event>::new(),
165 }))
166 }
167
168 fn diff(&mut self, tree: &mut Tree) {
169 let mut internal = tree
170 .state
171 .downcast_mut::<RefCell<Internal<C::State, C::Event>>>()
172 .borrow_mut();
173
174 self.component.diff(&mut internal.state);
175
176 if self.is_outdated.get() {
177 self.view = self.component.view(&internal.state)._boxed();
178 drop(internal);
179
180 tree.diff_children(std::slice::from_mut(&mut self.view));
181
182 self.is_outdated.set(false);
183 self.limits = layout::Limits::new(Size::ZERO, Size::INFINITE);
184 }
185 }
186
187 fn size(&self) -> Size<Length> {
188 self.view.size()
189 }
190
191 fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
192 if &self.limits != limits {
193 self.limits = *limits;
194 self.view.layout(&mut tree.children[0], renderer, limits);
195 }
196
197 tree.size = tree.children[0].size;
198 }
199
200 fn update(
201 &mut self,
202 tree: &mut Tree,
203 event: &Event,
204 layout: Layout,
205 cursor: mouse::Cursor,
206 renderer: &Renderer,
207 shell: &mut Shell<'_, Message>,
208 viewport: &Rectangle,
209 ) {
210 let mut internal = tree
211 .state
212 .downcast_mut::<RefCell<Internal<C::State, C::Event>>>()
213 .borrow_mut();
214
215 let action = self
216 .component
217 .listen(&internal.state, event, layout.bounds(), cursor);
218
219 let (publish, redraw_request, event_status) = action.into_inner();
220
221 shell.request_redraw_at(redraw_request);
222
223 if let event::Status::Captured = event_status {
224 shell.capture_event();
225 }
226
227 if let Some(event) = publish {
228 let _ = internal.events.push(event);
229 }
230
231 let mut invalidation = shell::Invalidation::None;
232
233 if !shell.is_event_captured() {
234 let mut local_shell = shell.local(&mut internal.events);
235
236 self.view.update(
237 &mut tree.children[0],
238 event,
239 layout,
240 cursor,
241 renderer,
242 &mut local_shell,
243 viewport,
244 );
245
246 if local_shell.is_event_captured() {
247 shell.capture_event();
248 }
249
250 shell.request_redraw_at(local_shell.redraw_request());
251 shell.request_input_method(local_shell.input_method());
252 shell.clipboard_mut().merge(local_shell.clipboard_mut());
253
254 invalidation = local_shell.invalidation();
255 }
256
257 if internal.events.is_empty() && matches!(invalidation, shell::Invalidation::None) {
258 return;
259 }
260
261 let Internal { state, events } = &mut *internal;
262
263 for (event, receipt) in events.drain() {
264 if let Some(message) = self.component.update(state, event, renderer) {
265 shell.forward(message, receipt);
266 }
267 }
268
269 let previous_sizing = self.view.size();
270
271 self.view = self.component.view(state)._boxed();
272 drop(internal);
273
274 tree.diff_children(std::slice::from_mut(&mut self.view));
275
276 let previous_size = tree.size;
277
278 self.view
279 .layout(&mut tree.children[0], renderer, &self.limits);
280
281 tree.size = tree.children[0].size;
282
283 let new_sizing = self.view.size();
284
285 if new_sizing != previous_sizing {
294 shell.invalidate_widgets();
295 } else if (new_sizing.width.fill_factor() == 0 || new_sizing.height.fill_factor() == 0)
296 && previous_size != tree.size
297 {
298 shell.invalidate_layout();
299 } else {
300 shell.invalidate_overlay();
301 }
302
303 self.is_outdated.set(false);
304
305 if let Event::Window(window::Event::RedrawRequested(_)) = event {
306 let mut internal = tree
307 .state
308 .downcast_mut::<RefCell<Internal<C::State, C::Event>>>()
309 .borrow_mut();
310
311 let mut local_shell = shell.local(&mut internal.events);
312
313 self.view.update(
314 &mut tree.children[0],
315 event,
316 layout,
317 cursor,
318 renderer,
319 &mut local_shell,
320 viewport,
321 );
322
323 if internal.events.is_empty() {
324 return;
325 }
326 }
327
328 shell.request_redraw();
329 }
330
331 fn draw(
332 &self,
333 tree: &Tree,
334 renderer: &mut Renderer,
335 theme: &Theme,
336 style: &renderer::Style,
337 layout: Layout,
338 cursor: mouse::Cursor,
339 viewport: &Rectangle,
340 ) {
341 self.view.draw(
342 &tree.children[0],
343 renderer,
344 theme,
345 style,
346 layout,
347 cursor,
348 viewport,
349 );
350 }
351
352 fn mouse_interaction(
353 &self,
354 tree: &Tree,
355 layout: Layout,
356 cursor: mouse::Cursor,
357 viewport: &Rectangle,
358 renderer: &Renderer,
359 ) -> mouse::Interaction {
360 let internal = tree
361 .state
362 .downcast_ref::<RefCell<Internal<C::State, C::Event>>>()
363 .borrow();
364
365 let interaction = self.component.mouse_interaction(&internal.state);
366
367 if interaction != mouse::Interaction::None {
368 return interaction;
369 }
370
371 self.view
372 .mouse_interaction(&tree.children[0], layout, cursor, viewport, renderer)
373 }
374
375 fn operate(
376 &mut self,
377 tree: &mut Tree,
378 layout: Layout,
379 viewport: &Rectangle,
380 renderer: &Renderer,
381 operation: &mut dyn widget::Operation,
382 ) {
383 {
384 let internal = tree
385 .state
386 .downcast_mut::<RefCell<Internal<C::State, C::Event>>>()
387 .get_mut();
388
389 self.component
390 .operate(&mut internal.state, layout.bounds(), operation);
391 }
392
393 self.view
394 .operate(&mut tree.children[0], layout, viewport, renderer, operation);
395 }
396
397 fn overlay<'b>(
398 &'b mut self,
399 tree: &'b mut Tree,
400 layout: Layout,
401 renderer: &Renderer,
402 viewport: &Rectangle,
403 translation: Vector,
404 window: Size,
405 ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
406 let overlays = self.view.overlay(
407 &mut tree.children[0],
408 layout,
409 renderer,
410 viewport,
411 translation,
412 window,
413 );
414
415 self.has_overlay = !overlays.is_empty();
416
417 let internal = tree
418 .state
419 .downcast_ref::<RefCell<Internal<C::State, C::Event>>>();
420
421 overlays
422 .into_iter()
423 .map(|raw| {
424 overlay::Element::new(Box::new(Overlay {
425 component: &self.component,
426 internal,
427 is_outdated: &self.is_outdated,
428 raw,
429 }))
430 })
431 .collect()
432 }
433}
434
435struct Overlay<'a, 'b, C, Message, Theme, Renderer>
436where
437 C: Component<'a, Message, Theme, Renderer>,
438{
439 component: &'b C,
440 internal: &'b RefCell<Internal<C::State, C::Event>>,
441 is_outdated: &'b Cell<bool>,
442 raw: overlay::Element<'b, C::Event, Theme, Renderer>,
443}
444
445impl<'a, 'b, C, Message, Theme, Renderer> overlay::Overlay<Message, Theme, Renderer>
446 for Overlay<'a, 'b, C, Message, Theme, Renderer>
447where
448 C: Component<'a, Message, Theme, Renderer>,
449{
450 fn update(
451 &mut self,
452 event: &Event,
453 cursor: mouse::Cursor,
454 renderer: &Renderer,
455 shell: &mut Shell<'_, Message>,
456 ) {
457 let mut internal = self.internal.borrow_mut();
458 let mut local_shell = shell.local(&mut internal.events);
459
460 self.raw
461 .as_overlay_mut()
462 .update(event, cursor, renderer, &mut local_shell);
463
464 if local_shell.is_event_captured() {
465 shell.capture_event();
466 }
467
468 shell.invalidate(local_shell.invalidation());
469 shell.request_redraw_at(local_shell.redraw_request());
470 shell.request_input_method(local_shell.input_method());
471 shell.clipboard_mut().merge(local_shell.clipboard_mut());
472
473 if internal.events.is_empty() {
474 return;
475 }
476
477 let Internal { state, events } = &mut *internal;
478
479 for (event, receipt) in events.drain() {
480 if let Some(message) = self.component.update(state, event, renderer) {
481 shell.forward(message, receipt);
482 }
483 }
484
485 self.is_outdated.set(true);
486
487 shell.invalidate_layout_with(shell::Diff::Perform);
488 shell.request_redraw();
489 }
490
491 fn draw(
492 &self,
493 renderer: &mut Renderer,
494 theme: &Theme,
495 style: &renderer::Style,
496 cursor: mouse::Cursor,
497 ) {
498 self.raw.as_overlay().draw(renderer, theme, style, cursor);
499 }
500
501 fn mouse_interaction(&self, cursor: mouse::Cursor, renderer: &Renderer) -> mouse::Interaction {
502 self.raw.as_overlay().mouse_interaction(cursor, renderer)
503 }
504
505 fn index(&self) -> f32 {
506 self.raw.as_overlay().index()
507 }
508
509 fn operate(&mut self, renderer: &Renderer, operation: &mut dyn widget::Operation) {
510 self.raw.as_overlay_mut().operate(renderer, operation);
511 }
512
513 fn overlay<'c>(
514 &'c mut self,
515 renderer: &Renderer,
516 ) -> Vec<overlay::Element<'c, Message, Theme, Renderer>> {
517 let overlays = self.raw.as_overlay_mut().overlay(renderer);
518
519 if overlays.is_empty() {
520 return Vec::new();
521 }
522
523 overlays
524 .into_iter()
525 .map(|raw| {
526 overlay::Element::new(Box::new(Overlay {
527 component: self.component,
528 internal: self.internal,
529 is_outdated: self.is_outdated,
530 raw,
531 }))
532 })
533 .collect()
534 }
535}