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 Element<V>) -> Self
 69    where
 70        Self: Sized,
 71    {
 72        self.children_mut().push(child.into_any());
 73        self
 74    }
 75
 76    fn children(mut self, children: impl IntoIterator<Item = impl Element<V>>) -> Self
 77    where
 78        Self: Sized,
 79    {
 80        self.children_mut()
 81            .extend(children.into_iter().map(Element::into_any));
 82        self
 83    }
 84}
 85
 86trait ElementObject<V> {
 87    fn element_id(&self) -> Option<ElementId>;
 88    fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
 89    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
 90    fn measure(
 91        &mut self,
 92        available_space: Size<AvailableSpace>,
 93        view_state: &mut V,
 94        cx: &mut ViewContext<V>,
 95    ) -> Size<Pixels>;
 96    fn draw(
 97        &mut self,
 98        origin: Point<Pixels>,
 99        available_space: Size<AvailableSpace>,
100        view_state: &mut V,
101        cx: &mut ViewContext<V>,
102    );
103}
104
105pub struct DrawableElement<V: 'static, E: Element<V>> {
106    element: Option<E>,
107    phase: ElementDrawPhase<E::State>,
108}
109
110#[derive(Default)]
111enum ElementDrawPhase<V> {
112    #[default]
113    Start,
114    LayoutRequested {
115        layout_id: LayoutId,
116        frame_state: Option<V>,
117    },
118    LayoutComputed {
119        layout_id: LayoutId,
120        available_space: Size<AvailableSpace>,
121        frame_state: Option<V>,
122    },
123}
124
125/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
126/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
127/// improved usability.
128impl<V, E: Element<V>> DrawableElement<V, E> {
129    fn new(element: E) -> Self {
130        DrawableElement {
131            element: Some(element),
132            phase: ElementDrawPhase::Start,
133        }
134    }
135
136    fn element_id(&self) -> Option<ElementId> {
137        self.element.as_ref()?.element_id()
138    }
139
140    fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
141        let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
142        {
143            let layout_id = cx.with_element_state(id, |element_state, cx| {
144                self.element
145                    .as_mut()
146                    .unwrap()
147                    .layout(state, element_state, cx)
148            });
149            (layout_id, None)
150        } else {
151            let (layout_id, frame_state) = self.element.as_mut().unwrap().layout(state, None, cx);
152            (layout_id, Some(frame_state))
153        };
154
155        self.phase = ElementDrawPhase::LayoutRequested {
156            layout_id,
157            frame_state,
158        };
159        layout_id
160    }
161
162    fn paint(mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> Option<E::State> {
163        match self.phase {
164            ElementDrawPhase::LayoutRequested {
165                layout_id,
166                frame_state,
167            }
168            | ElementDrawPhase::LayoutComputed {
169                layout_id,
170                frame_state,
171                ..
172            } => {
173                let bounds = cx.layout_bounds(layout_id);
174
175                if let Some(mut frame_state) = frame_state {
176                    self.element
177                        .take()
178                        .unwrap()
179                        .paint(bounds, view_state, &mut frame_state, cx);
180                    Some(frame_state)
181                } else {
182                    let element_id = self
183                        .element
184                        .as_ref()
185                        .unwrap()
186                        .element_id()
187                        .expect("if we don't have frame state, we should have element state");
188                    cx.with_element_state(element_id, |element_state, cx| {
189                        let mut element_state = element_state.unwrap();
190                        self.element.take().unwrap().paint(
191                            bounds,
192                            view_state,
193                            &mut element_state,
194                            cx,
195                        );
196                        ((), element_state)
197                    });
198                    None
199                }
200            }
201
202            _ => panic!("must call layout before paint"),
203        }
204    }
205
206    fn measure(
207        &mut self,
208        available_space: Size<AvailableSpace>,
209        view_state: &mut V,
210        cx: &mut ViewContext<V>,
211    ) -> Size<Pixels> {
212        if matches!(&self.phase, ElementDrawPhase::Start) {
213            self.layout(view_state, cx);
214        }
215
216        let layout_id = match &mut self.phase {
217            ElementDrawPhase::LayoutRequested {
218                layout_id,
219                frame_state,
220            } => {
221                cx.compute_layout(*layout_id, available_space);
222                let layout_id = *layout_id;
223                self.phase = ElementDrawPhase::LayoutComputed {
224                    layout_id,
225                    available_space,
226                    frame_state: frame_state.take(),
227                };
228                layout_id
229            }
230            ElementDrawPhase::LayoutComputed {
231                layout_id,
232                available_space: prev_available_space,
233                ..
234            } => {
235                if available_space != *prev_available_space {
236                    cx.compute_layout(*layout_id, available_space);
237                    *prev_available_space = available_space;
238                }
239                *layout_id
240            }
241            _ => panic!("cannot measure after painting"),
242        };
243
244        cx.layout_bounds(layout_id).size
245    }
246
247    fn draw(
248        mut self,
249        origin: Point<Pixels>,
250        available_space: Size<AvailableSpace>,
251        view_state: &mut V,
252        cx: &mut ViewContext<V>,
253    ) -> Option<E::State> {
254        self.measure(available_space, view_state, cx);
255        cx.with_absolute_element_offset(origin, |cx| self.paint(view_state, cx))
256    }
257}
258
259impl<V, E> ElementObject<V> for Option<DrawableElement<V, E>>
260where
261    E: Element<V>,
262    E::State: 'static,
263{
264    fn element_id(&self) -> Option<ElementId> {
265        self.as_ref().unwrap().element_id()
266    }
267
268    fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
269        DrawableElement::layout(self.as_mut().unwrap(), view_state, cx)
270    }
271
272    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
273        DrawableElement::paint(self.take().unwrap(), view_state, cx);
274    }
275
276    fn measure(
277        &mut self,
278        available_space: Size<AvailableSpace>,
279        view_state: &mut V,
280        cx: &mut ViewContext<V>,
281    ) -> Size<Pixels> {
282        DrawableElement::measure(self.as_mut().unwrap(), available_space, view_state, cx)
283    }
284
285    fn draw(
286        &mut self,
287        origin: Point<Pixels>,
288        available_space: Size<AvailableSpace>,
289        view_state: &mut V,
290        cx: &mut ViewContext<V>,
291    ) {
292        DrawableElement::draw(
293            self.take().unwrap(),
294            origin,
295            available_space,
296            view_state,
297            cx,
298        );
299    }
300}
301
302pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
303
304impl<V> AnyElement<V> {
305    pub fn new<E>(element: E) -> Self
306    where
307        V: 'static,
308        E: 'static + Element<V>,
309        E::State: Any,
310    {
311        AnyElement(Box::new(Some(DrawableElement::new(element))) as Box<dyn ElementObject<V>>)
312    }
313
314    pub fn element_id(&self) -> Option<ElementId> {
315        self.0.element_id()
316    }
317
318    pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
319        self.0.layout(view_state, cx)
320    }
321
322    pub fn paint(mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
323        self.0.paint(view_state, cx)
324    }
325
326    /// Initializes this element and performs layout within the given available space to determine its size.
327    pub fn measure(
328        &mut self,
329        available_space: Size<AvailableSpace>,
330        view_state: &mut V,
331        cx: &mut ViewContext<V>,
332    ) -> Size<Pixels> {
333        self.0.measure(available_space, view_state, cx)
334    }
335
336    /// Initializes this element and performs layout in the available space, then paints it at the given origin.
337    pub fn draw(
338        mut self,
339        origin: Point<Pixels>,
340        available_space: Size<AvailableSpace>,
341        view_state: &mut V,
342        cx: &mut ViewContext<V>,
343    ) {
344        self.0.draw(origin, available_space, view_state, cx)
345    }
346}
347
348impl<V: 'static> Element<V> for AnyElement<V> {
349    type State = ();
350
351    fn element_id(&self) -> Option<ElementId> {
352        AnyElement::element_id(self)
353    }
354
355    fn layout(
356        &mut self,
357        view_state: &mut V,
358        _: Option<Self::State>,
359        cx: &mut ViewContext<V>,
360    ) -> (LayoutId, Self::State) {
361        let layout_id = self.layout(view_state, cx);
362        (layout_id, ())
363    }
364
365    fn paint(
366        self,
367        _bounds: Bounds<Pixels>,
368        view_state: &mut V,
369        _: &mut Self::State,
370        cx: &mut ViewContext<V>,
371    ) {
372        self.paint(view_state, cx);
373    }
374}
375
376pub trait Component<V> {
377    fn render(self) -> AnyElement<V>;
378
379    fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
380    where
381        Self: Sized,
382        U: Component<V>,
383    {
384        f(self)
385    }
386
387    fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
388    where
389        Self: Sized,
390    {
391        self.map(|this| if condition { then(this) } else { this })
392    }
393
394    fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
395    where
396        Self: Sized,
397    {
398        self.map(|this| {
399            if let Some(value) = option {
400                then(this, value)
401            } else {
402                this
403            }
404        })
405    }
406}
407
408impl<V> Component<V> for AnyElement<V> {
409    fn render(self) -> AnyElement<V> {
410        self
411    }
412}
413
414impl<V, E, F> Element<V> for Option<F>
415where
416    V: 'static,
417    E: 'static + Component<V>,
418    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
419{
420    type State = Option<AnyElement<V>>;
421
422    fn element_id(&self) -> Option<ElementId> {
423        None
424    }
425
426    fn layout(
427        &mut self,
428        view_state: &mut V,
429        _: Option<Self::State>,
430        cx: &mut ViewContext<V>,
431    ) -> (LayoutId, Self::State) {
432        let render = self.take().unwrap();
433        let mut rendered_element = (render)(view_state, cx).render();
434        let layout_id = rendered_element.layout(view_state, cx);
435        (layout_id, Some(rendered_element))
436    }
437
438    fn paint(
439        self,
440        _bounds: Bounds<Pixels>,
441        view_state: &mut V,
442        rendered_element: &mut Self::State,
443        cx: &mut ViewContext<V>,
444    ) {
445        rendered_element.take().unwrap().paint(view_state, cx);
446    }
447}
448
449impl<V, E, F> Component<V> for Option<F>
450where
451    V: 'static,
452    E: 'static + Component<V>,
453    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
454{
455    fn render(self) -> AnyElement<V> {
456        AnyElement::new(self)
457    }
458}
459
460impl<V, E, F> Component<V> for F
461where
462    V: 'static,
463    E: 'static + Component<V>,
464    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
465{
466    fn render(self) -> AnyElement<V> {
467        AnyElement::new(Some(self))
468    }
469}
470
471// impl<V, E, F> Element<V> for F
472// where
473//     V: 'static,
474//     E: 'static + Component<V>,
475//     F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
476// {
477//     type State = Option<AnyElement<V>>;
478
479//     fn element_id(&self) -> Option<ElementId> {
480//         None
481//     }
482
483//     fn layout(
484//         &mut self,
485//         view_state: &mut V,
486//         element_state: Option<Self::State>,
487//         cx: &mut ViewContext<V>,
488//     ) -> (LayoutId, Self::State) {
489
490//         self(view_state)
491
492//     }
493
494//     fn paint(
495//         self,
496//         bounds: Bounds<Pixels>,
497//         view_state: &mut V,
498//         element_state: &mut Self::State,
499//         cx: &mut ViewContext<V>,
500//     ) {
501//         todo!()
502//     }
503// }