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