element.rs

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