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