element.rs

  1use super::{Layout, LayoutId, Pixels, Point, Result, ViewContext};
  2pub(crate) use smallvec::SmallVec;
  3use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc};
  4
  5pub trait Element: 'static {
  6    type State;
  7    type FrameState;
  8
  9    fn layout(
 10        &mut self,
 11        state: &mut Self::State,
 12        cx: &mut ViewContext<Self::State>,
 13    ) -> Result<(LayoutId, Self::FrameState)>;
 14
 15    fn paint(
 16        &mut self,
 17        layout: Layout,
 18        state: &mut Self::State,
 19        frame_state: &mut Self::FrameState,
 20        cx: &mut ViewContext<Self::State>,
 21    ) -> Result<()>;
 22}
 23
 24pub trait ParentElement<S> {
 25    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<S>; 2]>;
 26
 27    fn child(mut self, child: impl IntoAnyElement<S>) -> Self
 28    where
 29        Self: Sized,
 30    {
 31        self.children_mut().push(child.into_any());
 32        self
 33    }
 34
 35    fn children(mut self, iter: impl IntoIterator<Item = impl IntoAnyElement<S>>) -> Self
 36    where
 37        Self: Sized,
 38    {
 39        self.children_mut()
 40            .extend(iter.into_iter().map(|item| item.into_any()));
 41        self
 42    }
 43}
 44
 45trait ElementObject<S> {
 46    fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
 47    fn paint(
 48        &mut self,
 49        state: &mut S,
 50        offset: Option<Point<Pixels>>,
 51        cx: &mut ViewContext<S>,
 52    ) -> Result<()>;
 53}
 54
 55struct RenderedElement<E: Element> {
 56    element: E,
 57    phase: ElementRenderPhase<E::FrameState>,
 58}
 59
 60#[derive(Default)]
 61enum ElementRenderPhase<S> {
 62    #[default]
 63    Rendered,
 64    LayoutRequested {
 65        layout_id: LayoutId,
 66        frame_state: S,
 67    },
 68    Painted {
 69        layout: Layout,
 70        frame_state: S,
 71    },
 72}
 73
 74/// Internal struct that wraps an element to store Layout and FrameState after the element is rendered.
 75/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
 76/// improved usability.
 77impl<E: Element> RenderedElement<E> {
 78    fn new(element: E) -> Self {
 79        RenderedElement {
 80            element,
 81            phase: ElementRenderPhase::Rendered,
 82        }
 83    }
 84}
 85
 86impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
 87    fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
 88        let (layout_id, frame_state) = self.element.layout(state, cx)?;
 89        self.phase = ElementRenderPhase::LayoutRequested {
 90            layout_id,
 91            frame_state,
 92        };
 93        Ok(layout_id)
 94    }
 95
 96    fn paint(
 97        &mut self,
 98        state: &mut E::State,
 99        offset: Option<Point<Pixels>>,
100        cx: &mut ViewContext<E::State>,
101    ) -> Result<()> {
102        self.phase = match std::mem::take(&mut self.phase) {
103            ElementRenderPhase::Rendered => panic!("must call layout before paint"),
104
105            ElementRenderPhase::LayoutRequested {
106                layout_id,
107                mut frame_state,
108            } => {
109                let mut layout = cx.layout(layout_id)?.clone();
110                offset.map(|offset| layout.bounds.origin += offset);
111                self.element
112                    .paint(layout.clone(), state, &mut frame_state, cx)?;
113                ElementRenderPhase::Painted {
114                    layout,
115                    frame_state,
116                }
117            }
118
119            ElementRenderPhase::Painted {
120                layout,
121                mut frame_state,
122            } => {
123                self.element
124                    .paint(layout.clone(), state, &mut frame_state, cx)?;
125                ElementRenderPhase::Painted {
126                    layout,
127                    frame_state,
128                }
129            }
130        };
131
132        Ok(())
133    }
134}
135
136pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
137
138impl<S> AnyElement<S> {
139    pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
140        self.0.layout(state, cx)
141    }
142
143    pub fn paint(
144        &mut self,
145        state: &mut S,
146        offset: Option<Point<Pixels>>,
147        cx: &mut ViewContext<S>,
148    ) -> Result<()> {
149        self.0.paint(state, offset, cx)
150    }
151}
152
153pub trait IntoAnyElement<S> {
154    fn into_any(self) -> AnyElement<S>;
155}
156
157impl<E: Element> IntoAnyElement<E::State> for E {
158    fn into_any(self) -> AnyElement<E::State> {
159        AnyElement(Box::new(RenderedElement::new(self)))
160    }
161}
162
163impl<S> IntoAnyElement<S> for AnyElement<S> {
164    fn into_any(self) -> AnyElement<S> {
165        self
166    }
167}