element.rs

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