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