1use super::{Layout, LayoutId, Pixels, Point, Result, ViewContext};
2pub(crate) use smallvec::SmallVec;
3use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc};
4
5pub trait Element: 'static {
6 type State;
7 type FrameState;
8
9 fn layout(
10 &mut self,
11 state: &mut Self::State,
12 cx: &mut ViewContext<Self::State>,
13 ) -> Result<(LayoutId, Self::FrameState)>;
14
15 fn paint(
16 &mut self,
17 layout: Layout,
18 state: &mut Self::State,
19 frame_state: &mut Self::FrameState,
20 cx: &mut ViewContext<Self::State>,
21 ) -> Result<()>;
22}
23
24pub trait ParentElement<S> {
25 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<S>; 2]>;
26
27 fn child(mut self, child: impl IntoAnyElement<S>) -> Self
28 where
29 Self: Sized,
30 {
31 self.children_mut().push(child.into_any());
32 self
33 }
34
35 fn children(mut self, iter: impl IntoIterator<Item = impl IntoAnyElement<S>>) -> Self
36 where
37 Self: Sized,
38 {
39 self.children_mut()
40 .extend(iter.into_iter().map(|item| item.into_any()));
41 self
42 }
43}
44
45trait ElementObject<S> {
46 fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
47 fn paint(
48 &mut self,
49 state: &mut S,
50 offset: Option<Point<Pixels>>,
51 cx: &mut ViewContext<S>,
52 ) -> Result<()>;
53}
54
55struct RenderedElement<E: Element> {
56 element: E,
57 phase: ElementRenderPhase<E::FrameState>,
58}
59
60#[derive(Default)]
61enum ElementRenderPhase<S> {
62 #[default]
63 Rendered,
64 LayoutRequested {
65 layout_id: LayoutId,
66 frame_state: S,
67 },
68 Painted {
69 layout: Layout,
70 frame_state: S,
71 },
72}
73
74/// Internal struct that wraps an element to store Layout and FrameState after the element is rendered.
75/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
76/// improved usability.
77impl<E: Element> RenderedElement<E> {
78 fn new(element: E) -> Self {
79 RenderedElement {
80 element,
81 phase: ElementRenderPhase::Rendered,
82 }
83 }
84}
85
86impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
87 fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
88 let (layout_id, frame_state) = self.element.layout(state, cx)?;
89 self.phase = ElementRenderPhase::LayoutRequested {
90 layout_id,
91 frame_state,
92 };
93 Ok(layout_id)
94 }
95
96 fn paint(
97 &mut self,
98 state: &mut E::State,
99 offset: Option<Point<Pixels>>,
100 cx: &mut ViewContext<E::State>,
101 ) -> Result<()> {
102 self.phase = match std::mem::take(&mut self.phase) {
103 ElementRenderPhase::Rendered => panic!("must call layout before paint"),
104
105 ElementRenderPhase::LayoutRequested {
106 layout_id,
107 mut frame_state,
108 } => {
109 let mut layout = cx.layout(layout_id)?.clone();
110 offset.map(|offset| layout.bounds.origin += offset);
111 self.element
112 .paint(layout.clone(), state, &mut frame_state, cx)?;
113 ElementRenderPhase::Painted {
114 layout,
115 frame_state,
116 }
117 }
118
119 ElementRenderPhase::Painted {
120 layout,
121 mut frame_state,
122 } => {
123 self.element
124 .paint(layout.clone(), state, &mut frame_state, cx)?;
125 ElementRenderPhase::Painted {
126 layout,
127 frame_state,
128 }
129 }
130 };
131
132 Ok(())
133 }
134}
135
136pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
137
138impl<S> AnyElement<S> {
139 pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
140 self.0.layout(state, cx)
141 }
142
143 pub fn paint(
144 &mut self,
145 state: &mut S,
146 offset: Option<Point<Pixels>>,
147 cx: &mut ViewContext<S>,
148 ) -> Result<()> {
149 self.0.paint(state, offset, cx)
150 }
151}
152
153pub trait IntoAnyElement<S> {
154 fn into_any(self) -> AnyElement<S>;
155}
156
157impl<E: Element> IntoAnyElement<E::State> for E {
158 fn into_any(self) -> AnyElement<E::State> {
159 AnyElement(Box::new(RenderedElement::new(self)))
160 }
161}
162
163impl<S> IntoAnyElement<S> for AnyElement<S> {
164 fn into_any(self) -> AnyElement<S> {
165 self
166 }
167}