element.rs

  1use crate::{
  2    AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, ViewContext,
  3};
  4use derive_more::{Deref, DerefMut};
  5pub(crate) use smallvec::SmallVec;
  6use std::{any::Any, fmt::Debug, mem};
  7
  8pub trait Element<V: 'static> {
  9    type ElementState: 'static;
 10
 11    fn element_id(&self) -> Option<ElementId>;
 12
 13    /// Called to initialize this element for the current frame. If this
 14    /// element had state in a previous frame, it will be passed in for the 3rd argument.
 15    fn initialize(
 16        &mut self,
 17        view_state: &mut V,
 18        element_state: Option<Self::ElementState>,
 19        cx: &mut ViewContext<V>,
 20    ) -> Self::ElementState;
 21
 22    fn layout(
 23        &mut self,
 24        view_state: &mut V,
 25        element_state: &mut Self::ElementState,
 26        cx: &mut ViewContext<V>,
 27    ) -> LayoutId;
 28
 29    fn paint(
 30        &mut self,
 31        bounds: Bounds<Pixels>,
 32        view_state: &mut V,
 33        element_state: &mut Self::ElementState,
 34        cx: &mut ViewContext<V>,
 35    );
 36
 37    fn draw<T, R>(
 38        self,
 39        origin: Point<Pixels>,
 40        available_space: Size<T>,
 41        view_state: &mut V,
 42        cx: &mut ViewContext<V>,
 43        f: impl FnOnce(&Self::ElementState, &mut ViewContext<V>) -> R,
 44    ) -> R
 45    where
 46        Self: Sized,
 47        T: Clone + Default + Debug + Into<AvailableSpace>,
 48    {
 49        let mut element = RenderedElement {
 50            element: self,
 51            phase: ElementRenderPhase::Start,
 52        };
 53        element.draw(origin, available_space.map(Into::into), view_state, cx);
 54        if let ElementRenderPhase::Painted { frame_state } = &element.phase {
 55            if let Some(frame_state) = frame_state.as_ref() {
 56                f(&frame_state, cx)
 57            } else {
 58                let element_id = element
 59                    .element
 60                    .element_id()
 61                    .expect("we either have some frame_state or some element_id");
 62                cx.with_element_state(element_id, |element_state, cx| {
 63                    let element_state = element_state.unwrap();
 64                    let result = f(&element_state, cx);
 65                    (result, element_state)
 66                })
 67            }
 68        } else {
 69            unreachable!()
 70        }
 71    }
 72}
 73
 74#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 75pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
 76
 77pub trait ParentComponent<V: 'static> {
 78    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
 79
 80    fn child(mut self, child: impl Component<V>) -> Self
 81    where
 82        Self: Sized,
 83    {
 84        self.children_mut().push(child.render());
 85        self
 86    }
 87
 88    fn children(mut self, iter: impl IntoIterator<Item = impl Component<V>>) -> Self
 89    where
 90        Self: Sized,
 91    {
 92        self.children_mut()
 93            .extend(iter.into_iter().map(|item| item.render()));
 94        self
 95    }
 96}
 97
 98trait ElementObject<V> {
 99    fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
100    fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
101    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
102    fn measure(
103        &mut self,
104        available_space: Size<AvailableSpace>,
105        view_state: &mut V,
106        cx: &mut ViewContext<V>,
107    ) -> Size<Pixels>;
108    fn draw(
109        &mut self,
110        origin: Point<Pixels>,
111        available_space: Size<AvailableSpace>,
112        view_state: &mut V,
113        cx: &mut ViewContext<V>,
114    );
115}
116
117struct RenderedElement<V: 'static, E: Element<V>> {
118    element: E,
119    phase: ElementRenderPhase<E::ElementState>,
120}
121
122#[derive(Default)]
123enum ElementRenderPhase<V> {
124    #[default]
125    Start,
126    Initialized {
127        frame_state: Option<V>,
128    },
129    LayoutRequested {
130        layout_id: LayoutId,
131        frame_state: Option<V>,
132    },
133    LayoutComputed {
134        layout_id: LayoutId,
135        available_space: Size<AvailableSpace>,
136        frame_state: Option<V>,
137    },
138    Painted {
139        frame_state: Option<V>,
140    },
141}
142
143/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
144/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
145/// improved usability.
146impl<V, E: Element<V>> RenderedElement<V, E> {
147    fn new(element: E) -> Self {
148        RenderedElement {
149            element,
150            phase: ElementRenderPhase::Start,
151        }
152    }
153}
154
155impl<V, E> ElementObject<V> for RenderedElement<V, E>
156where
157    E: Element<V>,
158    E::ElementState: 'static,
159{
160    fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
161        let frame_state = if let Some(id) = self.element.element_id() {
162            cx.with_element_state(id, |element_state, cx| {
163                let element_state = self.element.initialize(view_state, element_state, cx);
164                ((), element_state)
165            });
166            None
167        } else {
168            let frame_state = self.element.initialize(view_state, None, cx);
169            Some(frame_state)
170        };
171
172        self.phase = ElementRenderPhase::Initialized { frame_state };
173    }
174
175    fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
176        let layout_id;
177        let mut frame_state;
178        match mem::take(&mut self.phase) {
179            ElementRenderPhase::Initialized {
180                frame_state: initial_frame_state,
181            } => {
182                frame_state = initial_frame_state;
183                if let Some(id) = self.element.element_id() {
184                    layout_id = cx.with_element_state(id, |element_state, cx| {
185                        let mut element_state = element_state.unwrap();
186                        let layout_id = self.element.layout(state, &mut element_state, cx);
187                        (layout_id, element_state)
188                    });
189                } else {
190                    layout_id = self
191                        .element
192                        .layout(state, frame_state.as_mut().unwrap(), cx);
193                }
194            }
195            ElementRenderPhase::Start => panic!("must call initialize before layout"),
196            ElementRenderPhase::LayoutRequested { .. }
197            | ElementRenderPhase::LayoutComputed { .. }
198            | ElementRenderPhase::Painted { .. } => {
199                panic!("element rendered twice")
200            }
201        };
202
203        self.phase = ElementRenderPhase::LayoutRequested {
204            layout_id,
205            frame_state,
206        };
207        layout_id
208    }
209
210    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
211        self.phase = match mem::take(&mut self.phase) {
212            ElementRenderPhase::LayoutRequested {
213                layout_id,
214                mut frame_state,
215            }
216            | ElementRenderPhase::LayoutComputed {
217                layout_id,
218                mut frame_state,
219                ..
220            } => {
221                let bounds = cx.layout_bounds(layout_id);
222                if let Some(id) = self.element.element_id() {
223                    cx.with_element_state(id, |element_state, cx| {
224                        let mut element_state = element_state.unwrap();
225                        self.element
226                            .paint(bounds, view_state, &mut element_state, cx);
227                        ((), element_state)
228                    });
229                } else {
230                    self.element
231                        .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
232                }
233                ElementRenderPhase::Painted { frame_state }
234            }
235
236            _ => panic!("must call layout before paint"),
237        };
238    }
239
240    fn measure(
241        &mut self,
242        available_space: Size<AvailableSpace>,
243        view_state: &mut V,
244        cx: &mut ViewContext<V>,
245    ) -> Size<Pixels> {
246        if matches!(&self.phase, ElementRenderPhase::Start) {
247            self.initialize(view_state, cx);
248        }
249
250        if matches!(&self.phase, ElementRenderPhase::Initialized { .. }) {
251            self.layout(view_state, cx);
252        }
253
254        let layout_id = match &mut self.phase {
255            ElementRenderPhase::LayoutRequested {
256                layout_id,
257                frame_state,
258            } => {
259                cx.compute_layout(*layout_id, available_space);
260                let layout_id = *layout_id;
261                self.phase = ElementRenderPhase::LayoutComputed {
262                    layout_id,
263                    available_space,
264                    frame_state: frame_state.take(),
265                };
266                layout_id
267            }
268            ElementRenderPhase::LayoutComputed {
269                layout_id,
270                available_space: prev_available_space,
271                ..
272            } => {
273                if available_space != *prev_available_space {
274                    cx.compute_layout(*layout_id, available_space);
275                    *prev_available_space = available_space;
276                }
277                *layout_id
278            }
279            _ => panic!("cannot measure after painting"),
280        };
281
282        cx.layout_bounds(layout_id).size
283    }
284
285    fn draw(
286        &mut self,
287        mut origin: Point<Pixels>,
288        available_space: Size<AvailableSpace>,
289        view_state: &mut V,
290        cx: &mut ViewContext<V>,
291    ) {
292        self.measure(available_space, view_state, cx);
293        // Ignore the element offset when drawing this element, as the origin is already specified
294        // in absolute terms.
295        origin -= cx.element_offset();
296        cx.with_element_offset(origin, |cx| self.paint(view_state, cx))
297    }
298}
299
300pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
301
302impl<V> AnyElement<V> {
303    pub fn new<E>(element: E) -> Self
304    where
305        V: 'static,
306        E: 'static + Element<V>,
307        E::ElementState: Any,
308    {
309        AnyElement(Box::new(RenderedElement::new(element)))
310    }
311
312    pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
313        self.0.initialize(view_state, cx);
314    }
315
316    pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
317        self.0.layout(view_state, cx)
318    }
319
320    pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
321        self.0.paint(view_state, cx)
322    }
323
324    /// Initializes this element and performs layout within the given available space to determine its size.
325    pub fn measure(
326        &mut self,
327        available_space: Size<AvailableSpace>,
328        view_state: &mut V,
329        cx: &mut ViewContext<V>,
330    ) -> Size<Pixels> {
331        self.0.measure(available_space, view_state, cx)
332    }
333
334    /// Initializes this element and performs layout in the available space, then paints it at the given origin.
335    pub fn draw(
336        &mut self,
337        origin: Point<Pixels>,
338        available_space: Size<AvailableSpace>,
339        view_state: &mut V,
340        cx: &mut ViewContext<V>,
341    ) {
342        self.0.draw(origin, available_space, view_state, cx)
343    }
344}
345
346pub trait Component<V> {
347    fn render(self) -> AnyElement<V>;
348
349    fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
350    where
351        Self: Sized,
352        U: Component<V>,
353    {
354        f(self)
355    }
356
357    fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
358    where
359        Self: Sized,
360    {
361        self.map(|this| if condition { then(this) } else { this })
362    }
363
364    fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
365    where
366        Self: Sized,
367    {
368        self.map(|this| {
369            if let Some(value) = option {
370                then(this, value)
371            } else {
372                this
373            }
374        })
375    }
376}
377
378impl<V> Component<V> for AnyElement<V> {
379    fn render(self) -> AnyElement<V> {
380        self
381    }
382}
383
384impl<V, E, F> Element<V> for Option<F>
385where
386    V: 'static,
387    E: 'static + Component<V>,
388    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
389{
390    type ElementState = AnyElement<V>;
391
392    fn element_id(&self) -> Option<ElementId> {
393        None
394    }
395
396    fn initialize(
397        &mut self,
398        view_state: &mut V,
399        _rendered_element: Option<Self::ElementState>,
400        cx: &mut ViewContext<V>,
401    ) -> Self::ElementState {
402        let render = self.take().unwrap();
403        let mut rendered_element = (render)(view_state, cx).render();
404        rendered_element.initialize(view_state, cx);
405        rendered_element
406    }
407
408    fn layout(
409        &mut self,
410        view_state: &mut V,
411        rendered_element: &mut Self::ElementState,
412        cx: &mut ViewContext<V>,
413    ) -> LayoutId {
414        rendered_element.layout(view_state, cx)
415    }
416
417    fn paint(
418        &mut self,
419        _bounds: Bounds<Pixels>,
420        view_state: &mut V,
421        rendered_element: &mut Self::ElementState,
422        cx: &mut ViewContext<V>,
423    ) {
424        rendered_element.paint(view_state, cx)
425    }
426}
427
428impl<V, E, F> Component<V> for Option<F>
429where
430    V: 'static,
431    E: 'static + Component<V>,
432    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
433{
434    fn render(self) -> AnyElement<V> {
435        AnyElement::new(self)
436    }
437}
438
439impl<V, E, F> Component<V> for F
440where
441    V: 'static,
442    E: 'static + Component<V>,
443    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
444{
445    fn render(self) -> AnyElement<V> {
446        AnyElement::new(Some(self))
447    }
448}