element.rs

  1use crate::{
  2    ArenaRef, AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size,
  3    ViewContext, WindowContext, ELEMENT_ARENA,
  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_and_update_state<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(&mut 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(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
154        let mut 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
373impl<E> ElementObject for Option<DrawableElement<E>>
374where
375    E: Element,
376    E::State: 'static,
377{
378    fn element_id(&self) -> Option<ElementId> {
379        self.as_ref().unwrap().element_id()
380    }
381
382    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
383        DrawableElement::layout(self.as_mut().unwrap(), cx)
384    }
385
386    fn paint(&mut self, cx: &mut WindowContext) {
387        DrawableElement::paint(self.take().unwrap(), cx);
388    }
389
390    fn measure(
391        &mut self,
392        available_space: Size<AvailableSpace>,
393        cx: &mut WindowContext,
394    ) -> Size<Pixels> {
395        DrawableElement::measure(self.as_mut().unwrap(), available_space, cx)
396    }
397
398    fn draw(
399        &mut self,
400        origin: Point<Pixels>,
401        available_space: Size<AvailableSpace>,
402        cx: &mut WindowContext,
403    ) {
404        DrawableElement::draw(self.take().unwrap(), origin, available_space, cx);
405    }
406}
407
408pub struct AnyElement(ArenaRef<dyn ElementObject>);
409
410impl AnyElement {
411    pub fn new<E>(element: E) -> Self
412    where
413        E: 'static + Element,
414        E::State: Any,
415    {
416        let element = ELEMENT_ARENA
417            .with_borrow_mut(|arena| arena.alloc(|| Some(DrawableElement::new(element))))
418            .map(|element| element as &mut dyn ElementObject);
419        AnyElement(element)
420    }
421
422    pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
423        self.0.layout(cx)
424    }
425
426    pub fn paint(&mut self, cx: &mut WindowContext) {
427        self.0.paint(cx)
428    }
429
430    /// Initializes this element and performs layout within the given available space to determine its size.
431    pub fn measure(
432        &mut self,
433        available_space: Size<AvailableSpace>,
434        cx: &mut WindowContext,
435    ) -> Size<Pixels> {
436        self.0.measure(available_space, cx)
437    }
438
439    /// Initializes this element and performs layout in the available space, then paints it at the given origin.
440    pub fn draw(
441        &mut self,
442        origin: Point<Pixels>,
443        available_space: Size<AvailableSpace>,
444        cx: &mut WindowContext,
445    ) {
446        self.0.draw(origin, available_space, cx)
447    }
448
449    pub fn inner_id(&self) -> Option<ElementId> {
450        self.0.element_id()
451    }
452}
453
454impl Element for AnyElement {
455    type State = ();
456
457    fn layout(
458        &mut self,
459        _: Option<Self::State>,
460        cx: &mut WindowContext,
461    ) -> (LayoutId, Self::State) {
462        let layout_id = self.layout(cx);
463        (layout_id, ())
464    }
465
466    fn paint(&mut self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut WindowContext) {
467        self.paint(cx)
468    }
469}
470
471impl IntoElement for AnyElement {
472    type Element = Self;
473
474    fn element_id(&self) -> Option<ElementId> {
475        None
476    }
477
478    fn into_element(self) -> Self::Element {
479        self
480    }
481
482    fn into_any_element(self) -> AnyElement {
483        self
484    }
485}
486
487/// The empty element, which renders nothing.
488pub type Empty = ();
489
490impl IntoElement for () {
491    type Element = Self;
492
493    fn element_id(&self) -> Option<ElementId> {
494        None
495    }
496
497    fn into_element(self) -> Self::Element {
498        self
499    }
500}
501
502impl Element for () {
503    type State = ();
504
505    fn layout(
506        &mut self,
507        _state: Option<Self::State>,
508        cx: &mut WindowContext,
509    ) -> (LayoutId, Self::State) {
510        (cx.request_layout(&crate::Style::default(), None), ())
511    }
512
513    fn paint(
514        &mut self,
515        _bounds: Bounds<Pixels>,
516        _state: &mut Self::State,
517        _cx: &mut WindowContext,
518    ) {
519    }
520}