element.rs

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