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 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 ParentElement<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.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.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.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        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        cx.with_element_offset(Some(origin), |cx| self.paint(view_state, cx))
256    }
257}
258
259pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
260
261impl<V> AnyElement<V> {
262    pub fn new<E>(element: E) -> Self
263    where
264        V: 'static,
265        E: 'static + Element<V>,
266        E::ElementState: Any,
267    {
268        AnyElement(Box::new(RenderedElement::new(element)))
269    }
270
271    pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
272        self.0.initialize(view_state, cx);
273    }
274
275    pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
276        self.0.layout(view_state, cx)
277    }
278
279    pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
280        self.0.paint(view_state, cx)
281    }
282
283    /// Initializes this element and performs layout within the given available space to determine its size.
284    pub fn measure(
285        &mut self,
286        available_space: Size<AvailableSpace>,
287        view_state: &mut V,
288        cx: &mut ViewContext<V>,
289    ) -> Size<Pixels> {
290        self.0.measure(available_space, view_state, cx)
291    }
292
293    /// Initializes this element and performs layout in the available space, then paints it at the given origin.
294    pub fn draw(
295        &mut self,
296        origin: Point<Pixels>,
297        available_space: Size<AvailableSpace>,
298        view_state: &mut V,
299        cx: &mut ViewContext<V>,
300    ) {
301        self.0.draw(origin, available_space, view_state, cx)
302    }
303}
304
305pub trait Component<V> {
306    fn render(self) -> AnyElement<V>;
307
308    fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
309    where
310        Self: Sized,
311        U: Component<V>,
312    {
313        f(self)
314    }
315
316    fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
317    where
318        Self: Sized,
319    {
320        self.map(|this| if condition { then(this) } else { this })
321    }
322
323    fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
324    where
325        Self: Sized,
326    {
327        self.map(|this| {
328            if let Some(value) = option {
329                then(this, value)
330            } else {
331                this
332            }
333        })
334    }
335}
336
337impl<V> Component<V> for AnyElement<V> {
338    fn render(self) -> AnyElement<V> {
339        self
340    }
341}
342
343impl<V, E, F> Element<V> for Option<F>
344where
345    V: 'static,
346    E: 'static + Component<V>,
347    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
348{
349    type ElementState = AnyElement<V>;
350
351    fn id(&self) -> Option<ElementId> {
352        None
353    }
354
355    fn initialize(
356        &mut self,
357        view_state: &mut V,
358        _rendered_element: Option<Self::ElementState>,
359        cx: &mut ViewContext<V>,
360    ) -> Self::ElementState {
361        let render = self.take().unwrap();
362        let mut rendered_element = (render)(view_state, cx).render();
363        rendered_element.initialize(view_state, cx);
364        rendered_element
365    }
366
367    fn layout(
368        &mut self,
369        view_state: &mut V,
370        rendered_element: &mut Self::ElementState,
371        cx: &mut ViewContext<V>,
372    ) -> LayoutId {
373        rendered_element.layout(view_state, cx)
374    }
375
376    fn paint(
377        &mut self,
378        _bounds: Bounds<Pixels>,
379        view_state: &mut V,
380        rendered_element: &mut Self::ElementState,
381        cx: &mut ViewContext<V>,
382    ) {
383        rendered_element.paint(view_state, cx)
384    }
385}
386
387impl<V, E, F> Component<V> for Option<F>
388where
389    V: 'static,
390    E: 'static + Component<V>,
391    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
392{
393    fn render(self) -> AnyElement<V> {
394        AnyElement::new(self)
395    }
396}
397
398impl<V, E, F> Component<V> for F
399where
400    V: 'static,
401    E: 'static + Component<V>,
402    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
403{
404    fn render(self) -> AnyElement<V> {
405        AnyElement::new(Some(self))
406    }
407}