element.rs

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