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