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