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