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