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