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::{self, Element, Event, Length, Point, 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) -> Element<'a, Self::Event, Theme, Renderer>;
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: &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) -> Element<'a, Message, Theme, Renderer>
115where
116 C: Component<'a, Message, Theme, Renderer> + 'a,
117 C::State: 'static,
118 Message: 'a,
119 Theme: 'a,
120 Renderer: core::Renderer + 'a,
121{
122 Element::new(Instance {
123 component,
124 view: crate::space().into(),
125 limits: layout::Limits::new(Size::ZERO, Size::INFINITE),
126 layout: layout::Node::new(Size::ZERO),
127 is_outdated: Cell::new(true),
128 has_overlay: false,
129 })
130}
131
132struct Instance<'a, C, Message, Theme, Renderer>
133where
134 C: Component<'a, Message, Theme, Renderer> + 'a,
135{
136 component: C,
137 view: Element<'a, C::Event, Theme, Renderer>,
138 limits: layout::Limits,
139 layout: layout::Node,
140 is_outdated: Cell<bool>,
141 has_overlay: bool,
142}
143
144struct Internal<State, Event> {
145 state: State,
146 events: shell::Bus<Event>,
147}
148
149impl<'a, C, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
150 for Instance<'a, C, Message, Theme, Renderer>
151where
152 C: Component<'a, Message, Theme, Renderer> + 'a,
153 Renderer: core::Renderer,
154{
155 fn tag(&self) -> tree::Tag {
156 tree::Tag::of::<RefCell<Internal<C::State, C::Event>>>()
157 }
158
159 fn state(&self) -> tree::State {
160 tree::State::new(RefCell::new(Internal {
161 state: C::State::default(),
162 events: shell::Bus::<C::Event>::new(),
163 }))
164 }
165
166 fn diff(&mut self, tree: &mut Tree) {
167 let mut internal = tree
168 .state
169 .downcast_mut::<RefCell<Internal<C::State, C::Event>>>()
170 .borrow_mut();
171
172 self.component.diff(&mut internal.state);
173
174 if self.is_outdated.get() {
175 self.view = self.component.view(&internal.state);
176 drop(internal);
177
178 tree.diff_children(std::slice::from_mut(&mut self.view));
179
180 self.is_outdated.set(false);
181 }
182 }
183
184 fn size(&self) -> Size<Length> {
185 self.view.as_widget().size()
186 }
187
188 fn layout(
189 &mut self,
190 tree: &mut Tree,
191 renderer: &Renderer,
192 limits: &layout::Limits,
193 ) -> layout::Node {
194 if &self.limits != limits {
195 self.limits = *limits;
196 self.layout = self
197 .view
198 .as_widget_mut()
199 .layout(&mut tree.children[0], renderer, limits);
200 }
201
202 layout::Node::new(self.layout.size())
203 }
204
205 fn update(
206 &mut self,
207 tree: &mut Tree,
208 event: &Event,
209 layout: Layout<'_>,
210 cursor: mouse::Cursor,
211 renderer: &Renderer,
212 shell: &mut Shell<'_, Message>,
213 viewport: &Rectangle,
214 ) {
215 let mut internal = tree
216 .state
217 .downcast_mut::<RefCell<Internal<C::State, C::Event>>>()
218 .borrow_mut();
219
220 let action = self
221 .component
222 .listen(&internal.state, event, layout.bounds(), cursor);
223
224 let (publish, redraw_request, event_status) = action.into_inner();
225
226 shell.request_redraw_at(redraw_request);
227
228 if let event::Status::Captured = event_status {
229 shell.capture_event();
230 }
231
232 if let Some(event) = publish {
233 let _ = internal.events.push(event);
234 }
235
236 if !shell.is_event_captured() {
237 let mut local_shell = shell.local(&mut internal.events);
238
239 self.view.as_widget_mut().update(
240 &mut tree.children[0],
241 event,
242 Layout::with_offset(layout.position() - Point::ORIGIN, &self.layout),
243 cursor,
244 renderer,
245 &mut local_shell,
246 viewport,
247 );
248
249 if local_shell.is_event_captured() {
250 shell.capture_event();
251 }
252
253 if let Some(diff) = local_shell.is_layout_invalid() {
254 shell.invalidate_layout_with(diff);
255 }
256
257 if local_shell.are_widgets_invalid() {
258 shell.invalidate_widgets();
259 }
260
261 shell.request_redraw_at(local_shell.redraw_request());
262 shell.request_input_method(local_shell.input_method());
263 shell.clipboard_mut().merge(local_shell.clipboard_mut());
264 }
265
266 if internal.events.is_empty() {
267 return;
268 }
269
270 let Internal { state, events } = &mut *internal;
271
272 for (event, receipt) in events.drain() {
273 if let Some(message) = self.component.update(state, event, renderer) {
274 shell.forward(message, receipt);
275 }
276 }
277
278 let previous_sizing = self.view.as_widget().size();
279
280 self.view = self.component.view(state);
281 drop(internal);
282
283 tree.diff_children(std::slice::from_mut(&mut self.view));
284
285 let previous_size = self.layout.size();
286 self.layout =
287 self.view
288 .as_widget_mut()
289 .layout(&mut tree.children[0], renderer, &self.limits);
290
291 let new_sizing = self.view.as_widget().size();
292
293 if new_sizing != previous_sizing {
306 shell.invalidate_widgets();
307 } else if (new_sizing.width == Length::Shrink || new_sizing.height == Length::Shrink)
308 && previous_size != self.layout.size()
309 {
310 shell.invalidate_layout();
311 } else {
312 let has_overlay = !self
313 .view
314 .as_widget_mut()
315 .overlay(
316 &mut tree.children[0],
317 Layout::with_offset(layout.position() - Point::ORIGIN, &self.layout),
318 renderer,
319 viewport,
320 Vector::ZERO,
321 )
322 .is_empty();
323
324 if self.has_overlay != has_overlay {
325 self.has_overlay = has_overlay;
326 shell.invalidate_layout();
327 }
328 }
329
330 self.is_outdated.set(false);
331
332 if let Event::Window(window::Event::RedrawRequested(_)) = event {
333 let mut internal = tree
334 .state
335 .downcast_mut::<RefCell<Internal<C::State, C::Event>>>()
336 .borrow_mut();
337
338 let mut local_shell = shell.local(&mut internal.events);
339
340 self.view.as_widget_mut().update(
341 &mut tree.children[0],
342 event,
343 Layout::with_offset(layout.position() - Point::ORIGIN, &self.layout),
344 cursor,
345 renderer,
346 &mut local_shell,
347 viewport,
348 );
349
350 if internal.events.is_empty() {
351 return;
352 }
353 }
354
355 shell.request_redraw();
356 }
357
358 fn draw(
359 &self,
360 tree: &Tree,
361 renderer: &mut Renderer,
362 theme: &Theme,
363 style: &renderer::Style,
364 layout: Layout<'_>,
365 cursor: mouse::Cursor,
366 viewport: &Rectangle,
367 ) {
368 self.view.as_widget().draw(
369 &tree.children[0],
370 renderer,
371 theme,
372 style,
373 Layout::with_offset(layout.position() - Point::ORIGIN, &self.layout),
374 cursor,
375 viewport,
376 );
377 }
378
379 fn mouse_interaction(
380 &self,
381 tree: &Tree,
382 layout: Layout<'_>,
383 cursor: mouse::Cursor,
384 viewport: &Rectangle,
385 renderer: &Renderer,
386 ) -> mouse::Interaction {
387 let internal = tree
388 .state
389 .downcast_ref::<RefCell<Internal<C::State, C::Event>>>()
390 .borrow();
391
392 let interaction = self.component.mouse_interaction(&internal.state);
393
394 if interaction != mouse::Interaction::None {
395 return interaction;
396 }
397
398 self.view.as_widget().mouse_interaction(
399 &tree.children[0],
400 Layout::with_offset(layout.position() - Point::ORIGIN, &self.layout),
401 cursor,
402 viewport,
403 renderer,
404 )
405 }
406
407 fn operate(
408 &mut self,
409 tree: &mut Tree,
410 layout: Layout<'_>,
411 renderer: &Renderer,
412 operation: &mut dyn widget::Operation,
413 ) {
414 let internal = tree
415 .state
416 .downcast_ref::<RefCell<Internal<C::State, C::Event>>>()
417 .borrow();
418
419 self.component
420 .operate(&internal.state, layout.bounds(), operation);
421
422 self.view.as_widget_mut().operate(
423 &mut tree.children[0],
424 Layout::with_offset(layout.position() - Point::ORIGIN, &self.layout),
425 renderer,
426 operation,
427 );
428 }
429
430 fn overlay<'b>(
431 &'b mut self,
432 tree: &'b mut Tree,
433 layout: Layout<'b>,
434 renderer: &Renderer,
435 viewport: &Rectangle,
436 translation: Vector,
437 ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
438 let overlays = self.view.as_widget_mut().overlay(
439 &mut tree.children[0],
440 Layout::with_offset(layout.position() - Point::ORIGIN, &self.layout),
441 renderer,
442 viewport,
443 translation,
444 );
445
446 self.has_overlay = !overlays.is_empty();
447
448 let internal = tree
449 .state
450 .downcast_ref::<RefCell<Internal<C::State, C::Event>>>();
451
452 overlays
453 .into_iter()
454 .map(|raw| {
455 overlay::Element::new(Box::new(Overlay {
456 component: &self.component,
457 internal,
458 is_outdated: &self.is_outdated,
459 raw,
460 }))
461 })
462 .collect()
463 }
464}
465
466struct Overlay<'a, 'b, C, Message, Theme, Renderer>
467where
468 C: Component<'a, Message, Theme, Renderer>,
469{
470 component: &'b C,
471 internal: &'b RefCell<Internal<C::State, C::Event>>,
472 is_outdated: &'b Cell<bool>,
473 raw: overlay::Element<'b, C::Event, Theme, Renderer>,
474}
475
476impl<'a, 'b, C, Message, Theme, Renderer> overlay::Overlay<Message, Theme, Renderer>
477 for Overlay<'a, 'b, C, Message, Theme, Renderer>
478where
479 C: Component<'a, Message, Theme, Renderer>,
480 Renderer: core::Renderer,
481{
482 fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
483 self.raw.as_overlay_mut().layout(renderer, bounds)
484 }
485
486 fn update(
487 &mut self,
488 event: &Event,
489 layout: Layout<'_>,
490 cursor: mouse::Cursor,
491 renderer: &Renderer,
492 shell: &mut Shell<'_, Message>,
493 ) {
494 let mut internal = self.internal.borrow_mut();
495 let mut local_shell = shell.local(&mut internal.events);
496
497 self.raw
498 .as_overlay_mut()
499 .update(event, layout, cursor, renderer, &mut local_shell);
500
501 if local_shell.is_event_captured() {
502 shell.capture_event();
503 }
504
505 if let Some(diff) = local_shell.is_layout_invalid() {
506 shell.invalidate_layout_with(diff);
507 }
508
509 if local_shell.are_widgets_invalid() {
510 shell.invalidate_widgets();
511 }
512
513 shell.request_redraw_at(local_shell.redraw_request());
514 shell.request_input_method(local_shell.input_method());
515 shell.clipboard_mut().merge(local_shell.clipboard_mut());
516
517 if internal.events.is_empty() {
518 return;
519 }
520
521 let Internal { state, events } = &mut *internal;
522
523 for (event, receipt) in events.drain() {
524 if let Some(message) = self.component.update(state, event, renderer) {
525 shell.forward(message, receipt);
526 }
527 }
528
529 self.is_outdated.set(true);
530
531 shell.invalidate_layout();
532 shell.request_redraw();
533 }
534
535 fn draw(
536 &self,
537 renderer: &mut Renderer,
538 theme: &Theme,
539 style: &renderer::Style,
540 layout: Layout<'_>,
541 cursor: mouse::Cursor,
542 ) {
543 self.raw
544 .as_overlay()
545 .draw(renderer, theme, style, layout, cursor);
546 }
547
548 fn mouse_interaction(
549 &self,
550 layout: Layout<'_>,
551 cursor: mouse::Cursor,
552 renderer: &Renderer,
553 ) -> mouse::Interaction {
554 self.raw
555 .as_overlay()
556 .mouse_interaction(layout, cursor, renderer)
557 }
558
559 fn index(&self) -> f32 {
560 self.raw.as_overlay().index()
561 }
562
563 fn operate(
564 &mut self,
565 layout: Layout<'_>,
566 renderer: &Renderer,
567 operation: &mut dyn widget::Operation,
568 ) {
569 self.raw
570 .as_overlay_mut()
571 .operate(layout, renderer, operation);
572 }
573
574 fn overlay<'c>(
575 &'c mut self,
576 layout: Layout<'c>,
577 renderer: &Renderer,
578 ) -> Vec<overlay::Element<'c, Message, Theme, Renderer>> {
579 let overlays = self.raw.as_overlay_mut().overlay(layout, renderer);
580
581 if overlays.is_empty() {
582 return Vec::new();
583 }
584
585 overlays
586 .into_iter()
587 .map(|raw| {
588 overlay::Element::new(Box::new(Overlay {
589 component: self.component,
590 internal: self.internal,
591 is_outdated: self.is_outdated,
592 raw,
593 }))
594 })
595 .collect()
596 }
597}