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