element.rs

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