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