element.rs

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