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 }
377 }
378
379 fn operate(
380 &mut self,
381 tree: &mut Tree,
382 layout: Layout<'_>,
383 renderer: &Renderer,
384 operation: &mut dyn widget::Operation,
385 ) {
386 self.rebuild_element_with_operation(layout, operation);
387
388 let tree = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();
389 self.with_element_mut(|element| {
390 element.as_widget_mut().operate(
391 &mut tree.borrow_mut().as_mut().unwrap().children[0],
392 layout,
393 renderer,
394 operation,
395 );
396 });
397 }
398
399 fn draw(
400 &self,
401 tree: &Tree,
402 renderer: &mut Renderer,
403 theme: &Theme,
404 style: &renderer::Style,
405 layout: Layout<'_>,
406 cursor: mouse::Cursor,
407 viewport: &Rectangle,
408 ) {
409 let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();
410 self.with_element(|element| {
411 element.as_widget().draw(
412 &tree.borrow().as_ref().unwrap().children[0],
413 renderer,
414 theme,
415 style,
416 layout,
417 cursor,
418 viewport,
419 );
420 });
421 }
422
423 fn mouse_interaction(
424 &self,
425 tree: &Tree,
426 layout: Layout<'_>,
427 cursor: mouse::Cursor,
428 viewport: &Rectangle,
429 renderer: &Renderer,
430 ) -> mouse::Interaction {
431 let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();
432 self.with_element(|element| {
433 element.as_widget().mouse_interaction(
434 &tree.borrow().as_ref().unwrap().children[0],
435 layout,
436 cursor,
437 viewport,
438 renderer,
439 )
440 })
441 }
442
443 fn overlay<'b>(
444 &'b mut self,
445 tree: &'b mut Tree,
446 layout: Layout<'b>,
447 renderer: &Renderer,
448 viewport: &Rectangle,
449 translation: Vector,
450 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
451 self.rebuild_element_if_necessary();
452
453 let state = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();
454 let tree = state.borrow_mut().take().unwrap();
455
456 let overlay = InnerBuilder {
457 instance: self,
458 tree,
459 types: PhantomData,
460 overlay_builder: |instance, tree| {
461 instance.state.get_mut().as_mut().unwrap().with_element_mut(
462 move |element| {
463 element
464 .as_mut()
465 .unwrap()
466 .as_widget_mut()
467 .overlay(
468 &mut tree.children[0],
469 layout,
470 renderer,
471 viewport,
472 translation,
473 )
474 .map(|overlay| {
475 RefCell::new(overlay::Nested::new(overlay))
476 })
477 },
478 )
479 },
480 }
481 .build();
482
483 #[allow(clippy::redundant_closure_for_method_calls)]
484 if overlay.with_overlay(|overlay| overlay.is_some()) {
485 Some(overlay::Element::new(Box::new(OverlayInstance {
486 overlay: Some(Overlay(Some(overlay))), })))
488 } else {
489 let heads = overlay.into_heads();
490
491 *state.borrow_mut() = Some(heads.tree);
495
496 None
497 }
498 }
499}
500
501struct Overlay<'a, 'b, Message, Theme, Renderer, Event, S>(
502 Option<Inner<'a, 'b, Message, Theme, Renderer, Event, S>>,
503);
504
505impl<Message, Theme, Renderer, Event, S> Drop
506 for Overlay<'_, '_, Message, Theme, Renderer, Event, S>
507{
508 fn drop(&mut self) {
509 if let Some(heads) = self.0.take().map(Inner::into_heads) {
510 *heads.instance.tree.borrow_mut().borrow_mut() = Some(heads.tree);
511 }
512 }
513}
514
515#[self_referencing]
516struct Inner<'a, 'b, Message, Theme, Renderer, Event, S> {
517 instance: &'a mut Instance<'b, Message, Theme, Renderer, Event, S>,
518 tree: Tree,
519 types: PhantomData<(Message, Event, S)>,
520
521 #[borrows(mut instance, mut tree)]
522 #[not_covariant]
523 overlay: Option<RefCell<overlay::Nested<'this, Event, Theme, Renderer>>>,
524}
525
526struct OverlayInstance<'a, 'b, Message, Theme, Renderer, Event, S> {
527 overlay: Option<Overlay<'a, 'b, Message, Theme, Renderer, Event, S>>,
528}
529
530impl<Message, Theme, Renderer, Event, S>
531 OverlayInstance<'_, '_, Message, Theme, Renderer, Event, S>
532{
533 fn with_overlay_maybe<T>(
534 &self,
535 f: impl FnOnce(&mut overlay::Nested<'_, Event, Theme, Renderer>) -> T,
536 ) -> Option<T> {
537 self.overlay
538 .as_ref()
539 .unwrap()
540 .0
541 .as_ref()
542 .unwrap()
543 .with_overlay(|overlay| {
544 overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut()))
545 })
546 }
547
548 fn with_overlay_mut_maybe<T>(
549 &mut self,
550 f: impl FnOnce(&mut overlay::Nested<'_, Event, Theme, Renderer>) -> T,
551 ) -> Option<T> {
552 self.overlay
553 .as_mut()
554 .unwrap()
555 .0
556 .as_mut()
557 .unwrap()
558 .with_overlay_mut(|overlay| {
559 overlay.as_mut().map(|nested| (f)(nested.get_mut()))
560 })
561 }
562}
563
564impl<Message, Theme, Renderer, Event, S>
565 overlay::Overlay<Message, Theme, Renderer>
566 for OverlayInstance<'_, '_, Message, Theme, Renderer, Event, S>
567where
568 Renderer: core::Renderer,
569 S: 'static + Default,
570{
571 fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
572 self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds))
573 .unwrap_or_default()
574 }
575
576 fn draw(
577 &self,
578 renderer: &mut Renderer,
579 theme: &Theme,
580 style: &renderer::Style,
581 layout: Layout<'_>,
582 cursor: mouse::Cursor,
583 ) {
584 let _ = self.with_overlay_maybe(|overlay| {
585 overlay.draw(renderer, theme, style, layout, cursor);
586 });
587 }
588
589 fn mouse_interaction(
590 &self,
591 layout: Layout<'_>,
592 cursor: mouse::Cursor,
593 renderer: &Renderer,
594 ) -> mouse::Interaction {
595 self.with_overlay_maybe(|overlay| {
596 overlay.mouse_interaction(layout, cursor, renderer)
597 })
598 .unwrap_or_default()
599 }
600
601 fn update(
602 &mut self,
603 event: &core::Event,
604 layout: Layout<'_>,
605 cursor: mouse::Cursor,
606 renderer: &Renderer,
607 clipboard: &mut dyn Clipboard,
608 shell: &mut Shell<'_, Message>,
609 ) {
610 let mut local_messages = Vec::new();
611 let mut local_shell = Shell::new(&mut local_messages);
612
613 let _ = self.with_overlay_mut_maybe(|overlay| {
614 overlay.update(
615 event,
616 layout,
617 cursor,
618 renderer,
619 clipboard,
620 &mut local_shell,
621 );
622 });
623
624 if local_shell.is_event_captured() {
625 shell.capture_event();
626 }
627
628 local_shell.revalidate_layout(|| shell.invalidate_layout());
629 shell.request_redraw_at(local_shell.redraw_request());
630 shell.request_input_method(local_shell.input_method());
631
632 if !local_messages.is_empty() {
633 let mut inner =
634 self.overlay.take().unwrap().0.take().unwrap().into_heads();
635 let mut heads = inner.instance.state.take().unwrap().into_heads();
636
637 for message in local_messages.into_iter().filter_map(|message| {
638 heads
639 .component
640 .update(inner.tree.state.downcast_mut(), message)
641 }) {
642 shell.publish(message);
643 }
644
645 *inner.instance.state.borrow_mut() = Some(
646 StateBuilder {
647 component: heads.component,
648 message: PhantomData,
649 state: PhantomData,
650 element_builder: |_| None,
651 }
652 .build(),
653 );
654
655 self.overlay = Some(Overlay(Some(
656 InnerBuilder {
657 instance: inner.instance,
658 tree: inner.tree,
659 types: PhantomData,
660 overlay_builder: |_, _| None,
661 }
662 .build(),
663 )));
664
665 shell.invalidate_layout();
666 }
667 }
668}