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