element.rs

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