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 IntoElement: Sized {
 16    type Element: Element + 'static;
 17
 18    fn element_id(&self) -> Option<ElementId>;
 19
 20    fn into_element(self) -> Self::Element;
 21
 22    fn into_any_element(self) -> AnyElement {
 23        self.into_element().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.into_element();
 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: IntoElement,
 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 + IntoElement {
 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 RenderOnce: 'static {
103    type Rendered: IntoElement;
104
105    fn render(self, cx: &mut WindowContext) -> Self::Rendered;
106}
107
108pub struct Component<C> {
109    component: Option<C>,
110}
111
112pub struct CompositeElementState<C: RenderOnce> {
113    rendered_element: Option<<C::Rendered as IntoElement>::Element>,
114    rendered_element_state: <<C::Rendered as IntoElement>::Element as Element>::State,
115}
116
117impl<C> Component<C> {
118    pub fn new(component: C) -> Self {
119        Component {
120            component: Some(component),
121        }
122    }
123}
124
125impl<C: RenderOnce> Element for Component<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).into_element();
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: RenderOnce> IntoElement for Component<C> {
152    type Element = Self;
153
154    fn element_id(&self) -> Option<ElementId> {
155        None
156    }
157
158    fn into_element(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 IntoElement) -> Self
170    where
171        Self: Sized,
172    {
173        self.children_mut().push(child.into_element().into_any());
174        self
175    }
176
177    fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self
178    where
179        Self: Sized,
180    {
181        self.children_mut()
182            .extend(children.into_iter().map(|child| child.into_any_element()));
183        self
184    }
185}
186
187trait ElementObject {
188    fn element_id(&self) -> Option<ElementId>;
189
190    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId;
191
192    fn paint(&mut self, cx: &mut WindowContext);
193
194    fn measure(
195        &mut self,
196        available_space: Size<AvailableSpace>,
197        cx: &mut WindowContext,
198    ) -> Size<Pixels>;
199
200    fn draw(
201        &mut self,
202        origin: Point<Pixels>,
203        available_space: Size<AvailableSpace>,
204        cx: &mut WindowContext,
205    );
206}
207
208pub struct DrawableElement<E: Element> {
209    element: Option<E>,
210    phase: ElementDrawPhase<E::State>,
211}
212
213#[derive(Default)]
214enum ElementDrawPhase<S> {
215    #[default]
216    Start,
217    LayoutRequested {
218        layout_id: LayoutId,
219        frame_state: Option<S>,
220    },
221    LayoutComputed {
222        layout_id: LayoutId,
223        available_space: Size<AvailableSpace>,
224        frame_state: Option<S>,
225    },
226}
227
228/// A wrapper around an implementer of [Element] that allows it to be drawn in a window.
229impl<E: Element> DrawableElement<E> {
230    fn new(element: E) -> Self {
231        DrawableElement {
232            element: Some(element),
233            phase: ElementDrawPhase::Start,
234        }
235    }
236
237    fn element_id(&self) -> Option<ElementId> {
238        self.element.as_ref()?.element_id()
239    }
240
241    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
242        let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
243        {
244            let layout_id = cx.with_element_state(id, |element_state, cx| {
245                self.element.as_mut().unwrap().layout(element_state, cx)
246            });
247            (layout_id, None)
248        } else {
249            let (layout_id, frame_state) = self.element.as_mut().unwrap().layout(None, cx);
250            (layout_id, Some(frame_state))
251        };
252
253        self.phase = ElementDrawPhase::LayoutRequested {
254            layout_id,
255            frame_state,
256        };
257        layout_id
258    }
259
260    fn paint(mut self, cx: &mut WindowContext) -> Option<E::State> {
261        match self.phase {
262            ElementDrawPhase::LayoutRequested {
263                layout_id,
264                frame_state,
265            }
266            | ElementDrawPhase::LayoutComputed {
267                layout_id,
268                frame_state,
269                ..
270            } => {
271                let bounds = cx.layout_bounds(layout_id);
272
273                if let Some(mut frame_state) = frame_state {
274                    self.element
275                        .take()
276                        .unwrap()
277                        .paint(bounds, &mut frame_state, cx);
278                    Some(frame_state)
279                } else {
280                    let element_id = self
281                        .element
282                        .as_ref()
283                        .unwrap()
284                        .element_id()
285                        .expect("if we don't have frame state, we should have element state");
286                    cx.with_element_state(element_id, |element_state, cx| {
287                        let mut element_state = element_state.unwrap();
288                        self.element
289                            .take()
290                            .unwrap()
291                            .paint(bounds, &mut element_state, cx);
292                        ((), element_state)
293                    });
294                    None
295                }
296            }
297
298            _ => panic!("must call layout before paint"),
299        }
300    }
301
302    fn measure(
303        &mut self,
304        available_space: Size<AvailableSpace>,
305        cx: &mut WindowContext,
306    ) -> Size<Pixels> {
307        if matches!(&self.phase, ElementDrawPhase::Start) {
308            self.layout(cx);
309        }
310
311        let layout_id = match &mut self.phase {
312            ElementDrawPhase::LayoutRequested {
313                layout_id,
314                frame_state,
315            } => {
316                cx.compute_layout(*layout_id, available_space);
317                let layout_id = *layout_id;
318                self.phase = ElementDrawPhase::LayoutComputed {
319                    layout_id,
320                    available_space,
321                    frame_state: frame_state.take(),
322                };
323                layout_id
324            }
325            ElementDrawPhase::LayoutComputed {
326                layout_id,
327                available_space: prev_available_space,
328                ..
329            } => {
330                if available_space != *prev_available_space {
331                    cx.compute_layout(*layout_id, available_space);
332                    *prev_available_space = available_space;
333                }
334                *layout_id
335            }
336            _ => panic!("cannot measure after painting"),
337        };
338
339        cx.layout_bounds(layout_id).size
340    }
341
342    fn draw(
343        mut self,
344        origin: Point<Pixels>,
345        available_space: Size<AvailableSpace>,
346        cx: &mut WindowContext,
347    ) -> Option<E::State> {
348        self.measure(available_space, cx);
349        cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
350    }
351}
352
353// impl<V: 'static, E: Element> Element for DrawableElement<V, E> {
354//     type State = <E::Element as Element>::State;
355
356//     fn layout(
357//         &mut self,
358//         element_state: Option<Self::State>,
359//         cx: &mut WindowContext,
360//     ) -> (LayoutId, Self::State) {
361
362//     }
363
364//     fn paint(
365//         self,
366//         bounds: Bounds<Pixels>,
367//         element_state: &mut Self::State,
368//         cx: &mut WindowContext,
369//     ) {
370//         todo!()
371//     }
372// }
373
374// impl<V: 'static, E: 'static + Element> RenderOnce for DrawableElement<V, E> {
375//     type Element = Self;
376
377//     fn element_id(&self) -> Option<ElementId> {
378//         self.element.as_ref()?.element_id()
379//     }
380
381//     fn render_once(self) -> Self::Element {
382//         self
383//     }
384// }
385
386impl<E> ElementObject for Option<DrawableElement<E>>
387where
388    E: Element,
389    E::State: 'static,
390{
391    fn element_id(&self) -> Option<ElementId> {
392        self.as_ref().unwrap().element_id()
393    }
394
395    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
396        DrawableElement::layout(self.as_mut().unwrap(), cx)
397    }
398
399    fn paint(&mut self, cx: &mut WindowContext) {
400        DrawableElement::paint(self.take().unwrap(), cx);
401    }
402
403    fn measure(
404        &mut self,
405        available_space: Size<AvailableSpace>,
406        cx: &mut WindowContext,
407    ) -> Size<Pixels> {
408        DrawableElement::measure(self.as_mut().unwrap(), available_space, cx)
409    }
410
411    fn draw(
412        &mut self,
413        origin: Point<Pixels>,
414        available_space: Size<AvailableSpace>,
415        cx: &mut WindowContext,
416    ) {
417        DrawableElement::draw(self.take().unwrap(), origin, available_space, cx);
418    }
419}
420
421pub struct AnyElement(Box<dyn ElementObject>);
422
423impl AnyElement {
424    pub fn new<E>(element: E) -> Self
425    where
426        E: 'static + Element,
427        E::State: Any,
428    {
429        AnyElement(Box::new(Some(DrawableElement::new(element))) as Box<dyn ElementObject>)
430    }
431
432    pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
433        self.0.layout(cx)
434    }
435
436    pub fn paint(mut self, cx: &mut WindowContext) {
437        self.0.paint(cx)
438    }
439
440    /// Initializes this element and performs layout within the given available space to determine its size.
441    pub fn measure(
442        &mut self,
443        available_space: Size<AvailableSpace>,
444        cx: &mut WindowContext,
445    ) -> Size<Pixels> {
446        self.0.measure(available_space, cx)
447    }
448
449    /// Initializes this element and performs layout in the available space, then paints it at the given origin.
450    pub fn draw(
451        mut self,
452        origin: Point<Pixels>,
453        available_space: Size<AvailableSpace>,
454        cx: &mut WindowContext,
455    ) {
456        self.0.draw(origin, available_space, cx)
457    }
458
459    /// Converts this `AnyElement` into a trait object that can be stored and manipulated.
460    pub fn into_any(self) -> AnyElement {
461        AnyElement::new(self)
462    }
463
464    pub fn inner_id(&self) -> Option<ElementId> {
465        self.0.element_id()
466    }
467}
468
469impl Element for AnyElement {
470    type State = ();
471
472    fn layout(
473        &mut self,
474        _: Option<Self::State>,
475        cx: &mut WindowContext,
476    ) -> (LayoutId, Self::State) {
477        let layout_id = self.layout(cx);
478        (layout_id, ())
479    }
480
481    fn paint(self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut WindowContext) {
482        self.paint(cx);
483    }
484}
485
486impl IntoElement for AnyElement {
487    type Element = Self;
488
489    fn element_id(&self) -> Option<ElementId> {
490        None
491    }
492
493    fn into_element(self) -> Self::Element {
494        self
495    }
496}
497
498// impl<V, E, F> Element for Option<F>
499// where
500//     V: 'static,
501//     E: Element,
502//     F: FnOnce(&mut V, &mut WindowContext<'_, V>) -> E + 'static,
503// {
504//     type State = Option<AnyElement>;
505
506//     fn element_id(&self) -> Option<ElementId> {
507//         None
508//     }
509
510//     fn layout(
511//         &mut self,
512//         _: Option<Self::State>,
513//         cx: &mut WindowContext,
514//     ) -> (LayoutId, Self::State) {
515//         let render = self.take().unwrap();
516//         let mut element = (render)(view_state, cx).into_any();
517//         let layout_id = element.layout(view_state, cx);
518//         (layout_id, Some(element))
519//     }
520
521//     fn paint(
522//         self,
523//         _bounds: Bounds<Pixels>,
524//         rendered_element: &mut Self::State,
525//         cx: &mut WindowContext,
526//     ) {
527//         rendered_element.take().unwrap().paint(view_state, cx);
528//     }
529// }
530
531// impl<V, E, F> RenderOnce for Option<F>
532// where
533//     V: 'static,
534//     E: Element,
535//     F: FnOnce(&mut V, &mut WindowContext) -> E + 'static,
536// {
537//     type Element = Self;
538
539//     fn render(self) -> Self::Element {
540//         self
541//     }
542// }