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: impl Into<ElementId>) -> Identified<Self>
 29    where
 30        Self: Sized,
 31    {
 32        Identified {
 33            element: self,
 34            id: id.into(),
 35        }
 36    }
 37}
 38
 39pub trait StatefulElement: Element {
 40    fn element_id(&self) -> ElementId {
 41        Element::element_id(self).unwrap()
 42    }
 43}
 44
 45#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 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>: 'static + Send + Sync {
 72    fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId;
 73    fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>);
 74}
 75
 76struct RenderedElement<E: Element> {
 77    element: E,
 78    phase: ElementRenderPhase<E::ElementState>,
 79}
 80
 81#[derive(Default)]
 82enum ElementRenderPhase<S> {
 83    #[default]
 84    Rendered,
 85    LayoutRequested {
 86        layout_id: LayoutId,
 87        frame_state: Option<S>,
 88    },
 89    Painted {
 90        bounds: Bounds<Pixels>,
 91        frame_state: Option<S>,
 92    },
 93}
 94
 95/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
 96/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
 97/// improved usability.
 98impl<E: Element> RenderedElement<E> {
 99    fn new(element: E) -> Self {
100        RenderedElement {
101            element,
102            phase: ElementRenderPhase::Rendered,
103        }
104    }
105
106    fn paint_with_element_state(
107        &mut self,
108        bounds: Bounds<Pixels>,
109        view_state: &mut E::ViewState,
110        frame_state: &mut Option<E::ElementState>,
111        cx: &mut ViewContext<E::ViewState>,
112    ) {
113        if let Some(id) = self.element.element_id() {
114            cx.with_element_state(id, |element_state, cx| {
115                let mut element_state = element_state.unwrap();
116                self.element
117                    .paint(bounds, view_state, &mut element_state, cx);
118                ((), element_state)
119            });
120        } else {
121            self.element
122                .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
123        }
124    }
125}
126
127impl<E, S> ElementObject<E::ViewState> for RenderedElement<E>
128where
129    E: Element<ElementState = S>,
130    S: 'static + Send + Sync,
131{
132    fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
133        let (layout_id, frame_state) = if let Some(id) = self.element.element_id() {
134            let layout_id = cx.with_element_state(id, |element_state, cx| {
135                self.element.layout(state, element_state, cx)
136            });
137            (layout_id, None)
138        } else {
139            let (layout_id, frame_state) = self.element.layout(state, None, cx);
140            (layout_id, Some(frame_state))
141        };
142
143        self.phase = ElementRenderPhase::LayoutRequested {
144            layout_id,
145            frame_state,
146        };
147
148        layout_id
149    }
150
151    fn paint(
152        &mut self,
153        view_state: &mut E::ViewState,
154        offset: Option<Point<Pixels>>,
155        cx: &mut ViewContext<E::ViewState>,
156    ) {
157        self.phase = match std::mem::take(&mut self.phase) {
158            ElementRenderPhase::Rendered => panic!("must call layout before paint"),
159
160            ElementRenderPhase::LayoutRequested {
161                layout_id,
162                mut frame_state,
163            } => {
164                let mut bounds = cx.layout_bounds(layout_id);
165                offset.map(|offset| bounds.origin += offset);
166                self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
167                ElementRenderPhase::Painted {
168                    bounds,
169                    frame_state,
170                }
171            }
172
173            ElementRenderPhase::Painted {
174                bounds,
175                mut frame_state,
176            } => {
177                self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
178                ElementRenderPhase::Painted {
179                    bounds,
180                    frame_state,
181                }
182            }
183        };
184    }
185}
186
187pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
188
189impl<S: 'static + Send + Sync> AnyElement<S> {
190    pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId {
191        self.0.layout(state, cx)
192    }
193
194    pub fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>) {
195        self.0.paint(state, offset, cx)
196    }
197}
198
199pub trait IntoAnyElement<S> {
200    fn into_any(self) -> AnyElement<S>;
201}
202
203impl<E: Element> IntoAnyElement<E::ViewState> for E {
204    fn into_any(self) -> AnyElement<E::ViewState> {
205        AnyElement(Box::new(RenderedElement::new(self)))
206    }
207}
208
209impl<S> IntoAnyElement<S> for AnyElement<S> {
210    fn into_any(self) -> AnyElement<S> {
211        self
212    }
213}