element.rs

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