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