element.rs

  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}