element.rs

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