1#![allow(deprecated)]
3use crate::core::layout::{self, Layout};
4use crate::core::mouse;
5use crate::core::overlay;
6use crate::core::renderer;
7use crate::core::widget;
8use crate::core::widget::tree::{self, Tree};
9use crate::core::{
10 self, Clipboard, Element, Length, Point, Rectangle, Shell, Size, Vector,
11 Widget,
12};
13use crate::runtime::overlay::Nested;
14
15use ouroboros::self_referencing;
16use std::cell::RefCell;
17use std::marker::PhantomData;
18use std::rc::Rc;
19
20#[cfg(feature = "lazy")]
47#[deprecated(
48 since = "0.13.0",
49 note = "components introduce encapsulated state and hamper the use of a single source of truth. \
50 Instead, leverage the Elm Architecture directly, or implement a custom widget"
51)]
52pub trait Component<Message, Theme = crate::Theme, Renderer = crate::Renderer> {
53 type State: Default;
55
56 type Event;
58
59 fn update(
63 &mut self,
64 state: &mut Self::State,
65 event: Self::Event,
66 ) -> Option<Message>;
67
68 fn view(
71 &self,
72 state: &Self::State,
73 ) -> Element<'_, Self::Event, Theme, Renderer>;
74
75 fn operate(
79 &self,
80 _bounds: Rectangle,
81 _state: &mut Self::State,
82 _operation: &mut dyn widget::Operation,
83 ) {
84 }
85
86 fn size_hint(&self) -> Size<Length> {
91 Size {
92 width: Length::Shrink,
93 height: Length::Shrink,
94 }
95 }
96}
97
98struct Tag<T>(T);
99
100pub fn view<'a, C, Message, Theme, Renderer>(
103 component: C,
104) -> Element<'a, Message, Theme, Renderer>
105where
106 C: Component<Message, Theme, Renderer> + 'a,
107 C::State: 'static,
108 Message: 'a,
109 Theme: 'a,
110 Renderer: core::Renderer + 'a,
111{
112 Element::new(Instance {
113 state: RefCell::new(Some(
114 StateBuilder {
115 component: Box::new(component),
116 message: PhantomData,
117 state: PhantomData,
118 element_builder: |_| None,
119 }
120 .build(),
121 )),
122 tree: RefCell::new(Rc::new(RefCell::new(None))),
123 })
124}
125
126struct Instance<'a, Message, Theme, Renderer, Event, S> {
127 state: RefCell<Option<State<'a, Message, Theme, Renderer, Event, S>>>,
128 tree: RefCell<Rc<RefCell<Option<Tree>>>>,
129}
130
131#[self_referencing]
132struct State<'a, Message: 'a, Theme: 'a, Renderer: 'a, Event: 'a, S: 'a> {
133 component: Box<
134 dyn Component<Message, Theme, Renderer, Event = Event, State = S> + 'a,
135 >,
136 message: PhantomData<Message>,
137 state: PhantomData<S>,
138
139 #[borrows(component)]
140 #[covariant]
141 element: Option<Element<'this, Event, Theme, Renderer>>,
142}
143
144impl<Message, Theme, Renderer, Event, S>
145 Instance<'_, Message, Theme, Renderer, Event, S>
146where
147 S: Default + 'static,
148 Renderer: renderer::Renderer,
149{
150 fn diff_self(&self) {
151 self.with_element(|element| {
152 self.tree
153 .borrow_mut()
154 .borrow_mut()
155 .as_mut()
156 .unwrap()
157 .diff_children(std::slice::from_ref(&element));
158 });
159 }
160
161 fn rebuild_element_if_necessary(&self) {
162 let inner = self.state.borrow_mut().take().unwrap();
163 if inner.borrow_element().is_none() {
164 let heads = inner.into_heads();
165
166 *self.state.borrow_mut() = Some(
167 StateBuilder {
168 component: heads.component,
169 message: PhantomData,
170 state: PhantomData,
171 element_builder: |component| {
172 Some(
173 component.view(
174 self.tree
175 .borrow()
176 .borrow()
177 .as_ref()
178 .unwrap()
179 .state
180 .downcast_ref::<S>(),
181 ),
182 )
183 },
184 }
185 .build(),
186 );
187 self.diff_self();
188 } else {
189 *self.state.borrow_mut() = Some(inner);
190 }
191 }
192
193 fn rebuild_element_with_operation(
194 &self,
195 layout: Layout<'_>,
196 operation: &mut dyn widget::Operation,
197 ) {
198 let heads = self.state.borrow_mut().take().unwrap().into_heads();
199
200 heads.component.operate(
201 layout.bounds(),
202 self.tree
203 .borrow_mut()
204 .borrow_mut()
205 .as_mut()
206 .unwrap()
207 .state
208 .downcast_mut(),
209 operation,
210 );
211
212 *self.state.borrow_mut() = Some(
213 StateBuilder {
214 component: heads.component,
215 message: PhantomData,
216 state: PhantomData,
217 element_builder: |component| {
218 Some(
219 component.view(
220 self.tree
221 .borrow()
222 .borrow()
223 .as_ref()
224 .unwrap()
225 .state
226 .downcast_ref(),
227 ),
228 )
229 },
230 }
231 .build(),
232 );
233 self.diff_self();
234 }
235
236 fn with_element<T>(
237 &self,
238 f: impl FnOnce(&Element<'_, Event, Theme, Renderer>) -> T,
239 ) -> T {
240 self.with_element_mut(|element| f(element))
241 }
242
243 fn with_element_mut<T>(
244 &self,
245 f: impl FnOnce(&mut Element<'_, Event, Theme, Renderer>) -> T,
246 ) -> T {
247 self.rebuild_element_if_necessary();
248 self.state
249 .borrow_mut()
250 .as_mut()
251 .unwrap()
252 .with_element_mut(|element| f(element.as_mut().unwrap()))
253 }
254}
255
256impl<Message, Theme, Renderer, Event, S> Widget<Message, Theme, Renderer>
257 for Instance<'_, Message, Theme, Renderer, Event, S>
258where
259 S: 'static + Default,
260 Renderer: core::Renderer,
261{
262 fn tag(&self) -> tree::Tag {
263 tree::Tag::of::<Tag<S>>()
264 }
265
266 fn state(&self) -> tree::State {
267 let state = Rc::new(RefCell::new(Some(Tree {
268 tag: tree::Tag::of::<Tag<S>>(),
269 state: tree::State::new(S::default()),
270 children: vec![Tree::empty()],
271 })));
272
273 *self.tree.borrow_mut() = state.clone();
274 self.diff_self();
275
276 tree::State::new(state)
277 }
278
279 fn children(&self) -> Vec<Tree> {
280 vec![]
281 }
282
283 fn diff(&self, tree: &mut Tree) {
284 let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();
285 *self.tree.borrow_mut() = tree.clone();
286 self.rebuild_element_if_necessary();
287 }
288
289 fn size(&self) -> Size<Length> {
290 self.with_element(|element| element.as_widget().size())
291 }
292
293 fn size_hint(&self) -> Size<Length> {
294 self.state
295 .borrow()
296 .as_ref()
297 .expect("Borrow instance state")
298 .borrow_component()
299 .size_hint()
300 }
301
302 fn layout(
303 &self,
304 tree: &mut Tree,
305 renderer: &Renderer,
306 limits: &layout::Limits,
307 ) -> layout::Node {
308 let t = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();
309
310 self.with_element(|element| {
311 element.as_widget().layout(
312 &mut t.borrow_mut().as_mut().unwrap().children[0],
313 renderer,
314 limits,
315 )
316 })
317 }
318
319 fn update(
320 &mut self,
321 tree: &mut Tree,
322 event: &core::Event,
323 layout: Layout<'_>,
324 cursor: mouse::Cursor,
325 renderer: &Renderer,
326 clipboard: &mut dyn Clipboard,
327 shell: &mut Shell<'_, Message>,
328 viewport: &Rectangle,
329 ) {
330 let mut local_messages = Vec::new();
331 let mut local_shell = Shell::new(&mut local_messages);
332
333 let t = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();
334 self.with_element_mut(|element| {
335 element.as_widget_mut().update(
336 &mut t.borrow_mut().as_mut().unwrap().children[0],
337 event,
338 layout,
339 cursor,
340 renderer,
341 clipboard,
342 &mut local_shell,
343 viewport,
344 );
345 });
346
347 if local_shell.is_event_captured() {
348 shell.capture_event();
349 }
350
351 local_shell.revalidate_layout(|| shell.invalidate_layout());
352 shell.request_redraw_at(local_shell.redraw_request());
353 shell.request_input_method(local_shell.input_method());
354
355 if !local_messages.is_empty() {
356 let mut heads = self.state.take().unwrap().into_heads();
357
358 for message in local_messages.into_iter().filter_map(|message| {
359 heads.component.update(
360 t.borrow_mut().as_mut().unwrap().state.downcast_mut(),
361 message,
362 )
363 }) {
364 shell.publish(message);
365 }
366
367 self.state = RefCell::new(Some(
368 StateBuilder {
369 component: heads.component,
370 message: PhantomData,
371 state: PhantomData,
372 element_builder: |_| None,
373 }
374 .build(),
375 ));
376
377 shell.invalidate_layout();
378 }
379 }
380
381 fn operate(
382 &self,
383 tree: &mut Tree,
384 layout: Layout<'_>,
385 renderer: &Renderer,
386 operation: &mut dyn widget::Operation,
387 ) {
388 self.rebuild_element_with_operation(layout, operation);
389
390 let tree = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();
391 self.with_element(|element| {
392 element.as_widget().operate(
393 &mut tree.borrow_mut().as_mut().unwrap().children[0],
394 layout,
395 renderer,
396 operation,
397 );
398 });
399 }
400
401 fn draw(
402 &self,
403 tree: &Tree,
404 renderer: &mut Renderer,
405 theme: &Theme,
406 style: &renderer::Style,
407 layout: Layout<'_>,
408 cursor: mouse::Cursor,
409 viewport: &Rectangle,
410 ) {
411 let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();
412 self.with_element(|element| {
413 element.as_widget().draw(
414 &tree.borrow().as_ref().unwrap().children[0],
415 renderer,
416 theme,
417 style,
418 layout,
419 cursor,
420 viewport,
421 );
422 });
423 }
424
425 fn mouse_interaction(
426 &self,
427 tree: &Tree,
428 layout: Layout<'_>,
429 cursor: mouse::Cursor,
430 viewport: &Rectangle,
431 renderer: &Renderer,
432 ) -> mouse::Interaction {
433 let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();
434 self.with_element(|element| {
435 element.as_widget().mouse_interaction(
436 &tree.borrow().as_ref().unwrap().children[0],
437 layout,
438 cursor,
439 viewport,
440 renderer,
441 )
442 })
443 }
444
445 fn overlay<'b>(
446 &'b mut self,
447 tree: &'b mut Tree,
448 layout: Layout<'_>,
449 renderer: &Renderer,
450 translation: Vector,
451 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
452 self.rebuild_element_if_necessary();
453
454 let state = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();
455 let tree = state.borrow_mut().take().unwrap();
456
457 let overlay = InnerBuilder {
458 instance: self,
459 tree,
460 types: PhantomData,
461 overlay_builder: |instance, tree| {
462 instance.state.get_mut().as_mut().unwrap().with_element_mut(
463 move |element| {
464 element
465 .as_mut()
466 .unwrap()
467 .as_widget_mut()
468 .overlay(
469 &mut tree.children[0],
470 layout,
471 renderer,
472 translation,
473 )
474 .map(|overlay| RefCell::new(Nested::new(overlay)))
475 },
476 )
477 },
478 }
479 .build();
480
481 #[allow(clippy::redundant_closure_for_method_calls)]
482 if overlay.with_overlay(|overlay| overlay.is_some()) {
483 Some(overlay::Element::new(Box::new(OverlayInstance {
484 overlay: Some(Overlay(Some(overlay))), })))
486 } else {
487 let heads = overlay.into_heads();
488
489 *state.borrow_mut() = Some(heads.tree);
493
494 None
495 }
496 }
497}
498
499struct Overlay<'a, 'b, Message, Theme, Renderer, Event, S>(
500 Option<Inner<'a, 'b, Message, Theme, Renderer, Event, S>>,
501);
502
503impl<Message, Theme, Renderer, Event, S> Drop
504 for Overlay<'_, '_, Message, Theme, Renderer, Event, S>
505{
506 fn drop(&mut self) {
507 if let Some(heads) = self.0.take().map(Inner::into_heads) {
508 *heads.instance.tree.borrow_mut().borrow_mut() = Some(heads.tree);
509 }
510 }
511}
512
513#[self_referencing]
514struct Inner<'a, 'b, Message, Theme, Renderer, Event, S> {
515 instance: &'a mut Instance<'b, Message, Theme, Renderer, Event, S>,
516 tree: Tree,
517 types: PhantomData<(Message, Event, S)>,
518
519 #[borrows(mut instance, mut tree)]
520 #[not_covariant]
521 overlay: Option<RefCell<Nested<'this, Event, Theme, Renderer>>>,
522}
523
524struct OverlayInstance<'a, 'b, Message, Theme, Renderer, Event, S> {
525 overlay: Option<Overlay<'a, 'b, Message, Theme, Renderer, Event, S>>,
526}
527
528impl<Message, Theme, Renderer, Event, S>
529 OverlayInstance<'_, '_, Message, Theme, Renderer, Event, S>
530{
531 fn with_overlay_maybe<T>(
532 &self,
533 f: impl FnOnce(&mut Nested<'_, Event, Theme, Renderer>) -> T,
534 ) -> Option<T> {
535 self.overlay
536 .as_ref()
537 .unwrap()
538 .0
539 .as_ref()
540 .unwrap()
541 .with_overlay(|overlay| {
542 overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut()))
543 })
544 }
545
546 fn with_overlay_mut_maybe<T>(
547 &mut self,
548 f: impl FnOnce(&mut Nested<'_, Event, Theme, Renderer>) -> T,
549 ) -> Option<T> {
550 self.overlay
551 .as_mut()
552 .unwrap()
553 .0
554 .as_mut()
555 .unwrap()
556 .with_overlay_mut(|overlay| {
557 overlay.as_mut().map(|nested| (f)(nested.get_mut()))
558 })
559 }
560}
561
562impl<Message, Theme, Renderer, Event, S>
563 overlay::Overlay<Message, Theme, Renderer>
564 for OverlayInstance<'_, '_, Message, Theme, Renderer, Event, S>
565where
566 Renderer: core::Renderer,
567 S: 'static + Default,
568{
569 fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
570 self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds))
571 .unwrap_or_default()
572 }
573
574 fn draw(
575 &self,
576 renderer: &mut Renderer,
577 theme: &Theme,
578 style: &renderer::Style,
579 layout: Layout<'_>,
580 cursor: mouse::Cursor,
581 ) {
582 let _ = self.with_overlay_maybe(|overlay| {
583 overlay.draw(renderer, theme, style, layout, cursor);
584 });
585 }
586
587 fn mouse_interaction(
588 &self,
589 layout: Layout<'_>,
590 cursor: mouse::Cursor,
591 viewport: &Rectangle,
592 renderer: &Renderer,
593 ) -> mouse::Interaction {
594 self.with_overlay_maybe(|overlay| {
595 overlay.mouse_interaction(layout, cursor, viewport, renderer)
596 })
597 .unwrap_or_default()
598 }
599
600 fn update(
601 &mut self,
602 event: &core::Event,
603 layout: Layout<'_>,
604 cursor: mouse::Cursor,
605 renderer: &Renderer,
606 clipboard: &mut dyn Clipboard,
607 shell: &mut Shell<'_, Message>,
608 ) {
609 let mut local_messages = Vec::new();
610 let mut local_shell = Shell::new(&mut local_messages);
611
612 let _ = self.with_overlay_mut_maybe(|overlay| {
613 overlay.update(
614 event,
615 layout,
616 cursor,
617 renderer,
618 clipboard,
619 &mut local_shell,
620 );
621 });
622
623 if local_shell.is_event_captured() {
624 shell.capture_event();
625 }
626
627 local_shell.revalidate_layout(|| shell.invalidate_layout());
628 shell.request_redraw_at(local_shell.redraw_request());
629 shell.request_input_method(local_shell.input_method());
630
631 if !local_messages.is_empty() {
632 let mut inner =
633 self.overlay.take().unwrap().0.take().unwrap().into_heads();
634 let mut heads = inner.instance.state.take().unwrap().into_heads();
635
636 for message in local_messages.into_iter().filter_map(|message| {
637 heads
638 .component
639 .update(inner.tree.state.downcast_mut(), message)
640 }) {
641 shell.publish(message);
642 }
643
644 *inner.instance.state.borrow_mut() = Some(
645 StateBuilder {
646 component: heads.component,
647 message: PhantomData,
648 state: PhantomData,
649 element_builder: |_| None,
650 }
651 .build(),
652 );
653
654 self.overlay = Some(Overlay(Some(
655 InnerBuilder {
656 instance: inner.instance,
657 tree: inner.tree,
658 types: PhantomData,
659 overlay_builder: |_, _| None,
660 }
661 .build(),
662 )));
663
664 shell.invalidate_layout();
665 }
666 }
667
668 fn is_over(
669 &self,
670 layout: Layout<'_>,
671 renderer: &Renderer,
672 cursor_position: Point,
673 ) -> bool {
674 self.with_overlay_maybe(|overlay| {
675 overlay.is_over(layout, renderer, cursor_position)
676 })
677 .unwrap_or_default()
678 }
679}