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<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        state: &mut S,
 51        offset: Option<Point<Pixels>>,
 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        bounds: Bounds<Pixels>,
 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        state: &mut E::State,
100        offset: Option<Point<Pixels>>,
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 bounds = cx.layout_bounds(layout_id)?.clone();
111                offset.map(|offset| bounds.origin += offset);
112                self.element.paint(bounds, state, &mut frame_state, cx)?;
113                ElementRenderPhase::Painted {
114                    bounds,
115                    frame_state,
116                }
117            }
118
119            ElementRenderPhase::Painted {
120                bounds,
121                mut frame_state,
122            } => {
123                self.element
124                    .paint(bounds.clone(), state, &mut frame_state, cx)?;
125                ElementRenderPhase::Painted {
126                    bounds,
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}