element.rs

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