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