1use smallvec::SmallVec;
2
3use super::{Handle, Layout, LayoutId, Pixels, Point, Result, ViewContext, WindowContext};
4use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc};
5
6pub trait Element: 'static {
7 type State;
8 type FrameState;
9
10 fn layout(
11 &mut self,
12 state: &mut Self::State,
13 cx: &mut ViewContext<Self::State>,
14 ) -> Result<(LayoutId, Self::FrameState)>;
15
16 fn paint(
17 &mut self,
18 layout: Layout,
19 state: &mut Self::State,
20 frame_state: &mut Self::FrameState,
21 cx: &mut ViewContext<Self::State>,
22 ) -> Result<()>;
23}
24
25pub trait ParentElement<S> {
26 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<S>; 2]>;
27
28 fn child(mut self, child: impl IntoAnyElement<S>) -> Self
29 where
30 Self: Sized,
31 {
32 self.children_mut().push(child.into_any());
33 self
34 }
35
36 fn children(mut self, iter: impl IntoIterator<Item = impl IntoAnyElement<S>>) -> Self
37 where
38 Self: Sized,
39 {
40 self.children_mut()
41 .extend(iter.into_iter().map(|item| item.into_any()));
42 self
43 }
44}
45
46trait ElementObject<S> {
47 fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
48 fn paint(
49 &mut self,
50 parent_origin: super::Point<Pixels>,
51 state: &mut S,
52 cx: &mut ViewContext<S>,
53 ) -> Result<()>;
54}
55
56struct RenderedElement<E: Element> {
57 element: E,
58 phase: ElementRenderPhase<E::FrameState>,
59}
60
61#[derive(Default)]
62enum ElementRenderPhase<S> {
63 #[default]
64 Rendered,
65 LayoutRequested {
66 layout_id: LayoutId,
67 frame_state: S,
68 },
69 Painted {
70 layout: Layout,
71 frame_state: S,
72 },
73}
74
75/// Internal struct that wraps an element to store Layout and FrameState after the element is rendered.
76/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
77/// improved usability.
78impl<E: Element> RenderedElement<E> {
79 fn new(element: E) -> Self {
80 RenderedElement {
81 element,
82 phase: ElementRenderPhase::Rendered,
83 }
84 }
85}
86
87impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
88 fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
89 let (layout_id, frame_state) = self.element.layout(state, cx)?;
90 self.phase = ElementRenderPhase::LayoutRequested {
91 layout_id,
92 frame_state,
93 };
94 Ok(layout_id)
95 }
96
97 fn paint(
98 &mut self,
99 parent_origin: Point<Pixels>,
100 state: &mut E::State,
101 cx: &mut ViewContext<E::State>,
102 ) -> Result<()> {
103 self.phase = match std::mem::take(&mut self.phase) {
104 ElementRenderPhase::Rendered => panic!("must call layout before paint"),
105
106 ElementRenderPhase::LayoutRequested {
107 layout_id,
108 mut frame_state,
109 } => {
110 let mut layout = cx.layout(layout_id)?;
111 layout.bounds.origin += parent_origin;
112 self.element
113 .paint(layout.clone(), state, &mut frame_state, cx)?;
114 ElementRenderPhase::Painted {
115 layout,
116 frame_state,
117 }
118 }
119
120 ElementRenderPhase::Painted {
121 layout,
122 mut frame_state,
123 } => {
124 self.element
125 .paint(layout.clone(), state, &mut frame_state, cx)?;
126 ElementRenderPhase::Painted {
127 layout,
128 frame_state,
129 }
130 }
131 };
132
133 Ok(())
134 }
135}
136
137pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
138
139impl<S> AnyElement<S> {
140 pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
141 self.0.layout(state, cx)
142 }
143
144 pub fn paint(
145 &mut self,
146 parent_origin: Point<Pixels>,
147 state: &mut S,
148 cx: &mut ViewContext<S>,
149 ) -> Result<()> {
150 self.0.paint(parent_origin, state, cx)
151 }
152}
153
154pub trait IntoAnyElement<S> {
155 fn into_any(self) -> AnyElement<S>;
156}
157
158impl<E: Element> IntoAnyElement<E::State> for E {
159 fn into_any(self) -> AnyElement<E::State> {
160 AnyElement(Box::new(RenderedElement::new(self)))
161 }
162}
163
164impl<S> IntoAnyElement<S> for AnyElement<S> {
165 fn into_any(self) -> AnyElement<S> {
166 self
167 }
168}
169
170#[derive(Clone)]
171pub struct View<S> {
172 state: Handle<S>,
173 render: Rc<dyn Fn(&mut S, &mut ViewContext<S>) -> AnyElement<S>>,
174}
175
176pub fn view<S: 'static, E: Element<State = S>>(
177 state: Handle<S>,
178 render: impl 'static + Fn(&mut S, &mut ViewContext<S>) -> E,
179) -> View<S> {
180 View {
181 state,
182 render: Rc::new(move |state, cx| render(state, cx).into_any()),
183 }
184}
185
186impl<S: 'static> View<S> {
187 pub fn into_any<ParentState>(self) -> AnyView<ParentState> {
188 AnyView {
189 view: Rc::new(RefCell::new(self)),
190 parent_state_type: PhantomData,
191 }
192 }
193}
194
195impl<S: 'static> Element for View<S> {
196 type State = ();
197 type FrameState = AnyElement<S>;
198
199 fn layout(
200 &mut self,
201 _: &mut Self::State,
202 cx: &mut ViewContext<Self::State>,
203 ) -> Result<(LayoutId, Self::FrameState)> {
204 self.state.update(cx, |state, cx| {
205 let mut element = (self.render)(state, cx);
206 let layout_id = element.layout(state, cx)?;
207 Ok((layout_id, element))
208 })
209 }
210
211 fn paint(
212 &mut self,
213 layout: Layout,
214 _: &mut Self::State,
215 element: &mut Self::FrameState,
216 cx: &mut ViewContext<Self::State>,
217 ) -> Result<()> {
218 self.state.update(cx, |state, cx| {
219 element.paint(layout.bounds.origin, state, cx)
220 })
221 }
222}
223
224trait ViewObject {
225 fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)>;
226 fn paint(
227 &mut self,
228 layout: Layout,
229 element: &mut dyn Any,
230 cx: &mut WindowContext,
231 ) -> Result<()>;
232}
233
234impl<S: 'static> ViewObject for View<S> {
235 fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)> {
236 self.state.update(cx, |state, cx| {
237 let mut element = (self.render)(state, cx);
238 let layout_id = element.layout(state, cx)?;
239 let element = Box::new(element) as Box<dyn Any>;
240 Ok((layout_id, element))
241 })
242 }
243
244 fn paint(
245 &mut self,
246 layout: Layout,
247 element: &mut dyn Any,
248 cx: &mut WindowContext,
249 ) -> Result<()> {
250 self.state.update(cx, |state, cx| {
251 element
252 .downcast_mut::<AnyElement<S>>()
253 .unwrap()
254 .paint(layout.bounds.origin, state, cx)
255 })
256 }
257}
258
259pub struct AnyView<S> {
260 view: Rc<RefCell<dyn ViewObject>>,
261 parent_state_type: PhantomData<S>,
262}
263
264impl<S: 'static> Element for AnyView<S> {
265 type State = S;
266 type FrameState = Box<dyn Any>;
267
268 fn layout(
269 &mut self,
270 _: &mut Self::State,
271 cx: &mut ViewContext<Self::State>,
272 ) -> Result<(LayoutId, Self::FrameState)> {
273 self.view.borrow_mut().layout(cx)
274 }
275
276 fn paint(
277 &mut self,
278 layout: Layout,
279 _: &mut Self::State,
280 element: &mut Self::FrameState,
281 cx: &mut ViewContext<Self::State>,
282 ) -> Result<()> {
283 self.view.borrow_mut().paint(layout, element, cx)
284 }
285}
286
287impl<S> Clone for AnyView<S> {
288 fn clone(&self) -> Self {
289 Self {
290 view: self.view.clone(),
291 parent_state_type: PhantomData,
292 }
293 }
294}