element.rs

  1use crate::{
  2    AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, ViewContext,
  3};
  4use derive_more::{Deref, DerefMut};
  5pub(crate) use smallvec::SmallVec;
  6use std::{any::Any, fmt::Debug};
  7
  8pub trait Element<V: 'static>: 'static + Sized {
  9    type State: 'static;
 10
 11    fn element_id(&self) -> Option<ElementId>;
 12
 13    fn layout(
 14        &mut self,
 15        view_state: &mut V,
 16        element_state: Option<Self::State>,
 17        cx: &mut ViewContext<V>,
 18    ) -> (LayoutId, Self::State);
 19
 20    fn paint(
 21        self,
 22        bounds: Bounds<Pixels>,
 23        view_state: &mut V,
 24        element_state: &mut Self::State,
 25        cx: &mut ViewContext<V>,
 26    );
 27
 28    fn into_any(self) -> AnyElement<V> {
 29        AnyElement::new(self)
 30    }
 31
 32    fn draw<T, R>(
 33        self,
 34        origin: Point<Pixels>,
 35        available_space: Size<T>,
 36        view_state: &mut V,
 37        cx: &mut ViewContext<V>,
 38        f: impl FnOnce(&mut Self::State, &mut ViewContext<V>) -> R,
 39    ) -> R
 40    where
 41        T: Clone + Default + Debug + Into<AvailableSpace>,
 42    {
 43        let element_id = self.element_id();
 44        let element = DrawableElement {
 45            element: Some(self),
 46            phase: ElementDrawPhase::Start,
 47        };
 48        let frame_state = element.draw(origin, available_space.map(Into::into), view_state, cx);
 49
 50        if let Some(mut frame_state) = frame_state {
 51            f(&mut frame_state, cx)
 52        } else {
 53            cx.with_element_state(element_id.unwrap(), |element_state, cx| {
 54                let mut element_state = element_state.unwrap();
 55                let result = f(&mut element_state, cx);
 56                (result, element_state)
 57            })
 58        }
 59    }
 60}
 61
 62#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 63pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
 64
 65pub trait ParentComponent<V: 'static> {
 66    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
 67
 68    fn child(mut self, child: impl Component<V>) -> Self
 69    where
 70        Self: Sized,
 71    {
 72        self.children_mut().push(child.render());
 73        self
 74    }
 75
 76    fn children(mut self, iter: impl IntoIterator<Item = impl Component<V>>) -> Self
 77    where
 78        Self: Sized,
 79    {
 80        self.children_mut()
 81            .extend(iter.into_iter().map(|item| item.render()));
 82        self
 83    }
 84}
 85
 86trait ElementObject<V> {
 87    fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
 88    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
 89    fn measure(
 90        &mut self,
 91        available_space: Size<AvailableSpace>,
 92        view_state: &mut V,
 93        cx: &mut ViewContext<V>,
 94    ) -> Size<Pixels>;
 95    fn draw(
 96        &mut self,
 97        origin: Point<Pixels>,
 98        available_space: Size<AvailableSpace>,
 99        view_state: &mut V,
100        cx: &mut ViewContext<V>,
101    );
102}
103
104pub struct DrawableElement<V: 'static, E: Element<V>> {
105    element: Option<E>,
106    phase: ElementDrawPhase<E::State>,
107}
108
109#[derive(Default)]
110enum ElementDrawPhase<V> {
111    #[default]
112    Start,
113    LayoutRequested {
114        layout_id: LayoutId,
115        frame_state: Option<V>,
116    },
117    LayoutComputed {
118        layout_id: LayoutId,
119        available_space: Size<AvailableSpace>,
120        frame_state: Option<V>,
121    },
122}
123
124/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
125/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
126/// improved usability.
127impl<V, E: Element<V>> DrawableElement<V, E> {
128    fn new(element: E) -> Self {
129        DrawableElement {
130            element: Some(element),
131            phase: ElementDrawPhase::Start,
132        }
133    }
134
135    fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
136        let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
137        {
138            let layout_id = cx.with_element_state(id, |element_state, cx| {
139                self.element
140                    .as_mut()
141                    .unwrap()
142                    .layout(state, element_state, cx)
143            });
144            (layout_id, None)
145        } else {
146            let (layout_id, frame_state) = self.element.as_mut().unwrap().layout(state, None, cx);
147            (layout_id, Some(frame_state))
148        };
149
150        self.phase = ElementDrawPhase::LayoutRequested {
151            layout_id,
152            frame_state,
153        };
154        layout_id
155    }
156
157    fn paint(mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> Option<E::State> {
158        match self.phase {
159            ElementDrawPhase::LayoutRequested {
160                layout_id,
161                frame_state,
162            }
163            | ElementDrawPhase::LayoutComputed {
164                layout_id,
165                frame_state,
166                ..
167            } => {
168                let bounds = cx.layout_bounds(layout_id);
169
170                if let Some(mut frame_state) = frame_state {
171                    self.element
172                        .take()
173                        .unwrap()
174                        .paint(bounds, view_state, &mut frame_state, cx);
175                    Some(frame_state)
176                } else {
177                    let element_id = self
178                        .element
179                        .as_ref()
180                        .unwrap()
181                        .element_id()
182                        .expect("if we don't have frame state, we should have element state");
183                    cx.with_element_state(element_id, |element_state, cx| {
184                        let mut element_state = element_state.unwrap();
185                        self.element.take().unwrap().paint(
186                            bounds,
187                            view_state,
188                            &mut element_state,
189                            cx,
190                        );
191                        ((), element_state)
192                    });
193                    None
194                }
195            }
196
197            _ => panic!("must call layout before paint"),
198        }
199    }
200
201    fn measure(
202        &mut self,
203        available_space: Size<AvailableSpace>,
204        view_state: &mut V,
205        cx: &mut ViewContext<V>,
206    ) -> Size<Pixels> {
207        if matches!(&self.phase, ElementDrawPhase::Start) {
208            self.layout(view_state, cx);
209        }
210
211        let layout_id = match &mut self.phase {
212            ElementDrawPhase::LayoutRequested {
213                layout_id,
214                frame_state,
215            } => {
216                cx.compute_layout(*layout_id, available_space);
217                let layout_id = *layout_id;
218                self.phase = ElementDrawPhase::LayoutComputed {
219                    layout_id,
220                    available_space,
221                    frame_state: frame_state.take(),
222                };
223                layout_id
224            }
225            ElementDrawPhase::LayoutComputed {
226                layout_id,
227                available_space: prev_available_space,
228                ..
229            } => {
230                if available_space != *prev_available_space {
231                    cx.compute_layout(*layout_id, available_space);
232                    *prev_available_space = available_space;
233                }
234                *layout_id
235            }
236            _ => panic!("cannot measure after painting"),
237        };
238
239        cx.layout_bounds(layout_id).size
240    }
241
242    fn draw(
243        mut self,
244        origin: Point<Pixels>,
245        available_space: Size<AvailableSpace>,
246        view_state: &mut V,
247        cx: &mut ViewContext<V>,
248    ) -> Option<E::State> {
249        self.measure(available_space, view_state, cx);
250        cx.with_absolute_element_offset(origin, |cx| self.paint(view_state, cx))
251    }
252}
253
254impl<V, E> ElementObject<V> for Option<DrawableElement<V, E>>
255where
256    E: Element<V>,
257    E::State: 'static,
258{
259    fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
260        DrawableElement::layout(self.as_mut().unwrap(), view_state, cx)
261    }
262
263    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
264        DrawableElement::paint(self.take().unwrap(), view_state, cx);
265    }
266
267    fn measure(
268        &mut self,
269        available_space: Size<AvailableSpace>,
270        view_state: &mut V,
271        cx: &mut ViewContext<V>,
272    ) -> Size<Pixels> {
273        DrawableElement::measure(self.as_mut().unwrap(), available_space, view_state, cx)
274    }
275
276    fn draw(
277        &mut self,
278        origin: Point<Pixels>,
279        available_space: Size<AvailableSpace>,
280        view_state: &mut V,
281        cx: &mut ViewContext<V>,
282    ) {
283        DrawableElement::draw(
284            self.take().unwrap(),
285            origin,
286            available_space,
287            view_state,
288            cx,
289        );
290    }
291}
292
293pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
294
295impl<V> AnyElement<V> {
296    pub fn new<E>(element: E) -> Self
297    where
298        V: 'static,
299        E: 'static + Element<V>,
300        E::State: Any,
301    {
302        AnyElement(Box::new(Some(DrawableElement::new(element))) as Box<dyn ElementObject<V>>)
303    }
304
305    pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
306        self.0.layout(view_state, cx)
307    }
308
309    pub fn paint(mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
310        self.0.paint(view_state, cx)
311    }
312
313    /// Initializes this element and performs layout within the given available space to determine its size.
314    pub fn measure(
315        &mut self,
316        available_space: Size<AvailableSpace>,
317        view_state: &mut V,
318        cx: &mut ViewContext<V>,
319    ) -> Size<Pixels> {
320        self.0.measure(available_space, view_state, cx)
321    }
322
323    /// Initializes this element and performs layout in the available space, then paints it at the given origin.
324    pub fn draw(
325        mut self,
326        origin: Point<Pixels>,
327        available_space: Size<AvailableSpace>,
328        view_state: &mut V,
329        cx: &mut ViewContext<V>,
330    ) {
331        self.0.draw(origin, available_space, view_state, cx)
332    }
333}
334
335pub trait Component<V> {
336    fn render(self) -> AnyElement<V>;
337
338    fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
339    where
340        Self: Sized,
341        U: Component<V>,
342    {
343        f(self)
344    }
345
346    fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
347    where
348        Self: Sized,
349    {
350        self.map(|this| if condition { then(this) } else { this })
351    }
352
353    fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
354    where
355        Self: Sized,
356    {
357        self.map(|this| {
358            if let Some(value) = option {
359                then(this, value)
360            } else {
361                this
362            }
363        })
364    }
365}
366
367impl<V> Component<V> for AnyElement<V> {
368    fn render(self) -> AnyElement<V> {
369        self
370    }
371}
372
373impl<V, E, F> Element<V> for Option<F>
374where
375    V: 'static,
376    E: 'static + Component<V>,
377    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
378{
379    type State = Option<AnyElement<V>>;
380
381    fn element_id(&self) -> Option<ElementId> {
382        None
383    }
384
385    fn layout(
386        &mut self,
387        view_state: &mut V,
388        _: Option<Self::State>,
389        cx: &mut ViewContext<V>,
390    ) -> (LayoutId, Self::State) {
391        let render = self.take().unwrap();
392        let mut rendered_element = (render)(view_state, cx).render();
393        let layout_id = rendered_element.layout(view_state, cx);
394        (layout_id, Some(rendered_element))
395    }
396
397    fn paint(
398        self,
399        _bounds: Bounds<Pixels>,
400        view_state: &mut V,
401        rendered_element: &mut Self::State,
402        cx: &mut ViewContext<V>,
403    ) {
404        rendered_element.take().unwrap().paint(view_state, cx);
405    }
406}
407
408impl<V, E, F> Component<V> for Option<F>
409where
410    V: 'static,
411    E: 'static + Component<V>,
412    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
413{
414    fn render(self) -> AnyElement<V> {
415        AnyElement::new(self)
416    }
417}
418
419impl<V, E, F> Component<V> for F
420where
421    V: 'static,
422    E: 'static + Component<V>,
423    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
424{
425    fn render(self) -> AnyElement<V> {
426        AnyElement::new(Some(self))
427    }
428}