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