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