element.rs

  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}