element.rs

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