element.rs

  1use crate::{
  2    BorrowWindow, Bounds, ElementId, FocusHandle, InputHandlerView, LayoutId, Pixels, ViewContext,
  3    WindowInputHandler,
  4};
  5use derive_more::{Deref, DerefMut};
  6pub(crate) use smallvec::SmallVec;
  7use std::{any::Any, mem};
  8
  9pub trait Element<V: 'static> {
 10    type ElementState: 'static;
 11
 12    fn id(&self) -> Option<ElementId>;
 13
 14    /// Called to initialize this element for the current frame. If this
 15    /// element had state in a previous frame, it will be passed in for the 3rd argument.
 16    fn initialize(
 17        &mut self,
 18        view_state: &mut V,
 19        element_state: Option<Self::ElementState>,
 20        cx: &mut ViewContext<V>,
 21    ) -> Self::ElementState;
 22
 23    fn layout(
 24        &mut self,
 25        view_state: &mut V,
 26        element_state: &mut Self::ElementState,
 27        cx: &mut ViewContext<V>,
 28    ) -> LayoutId;
 29
 30    fn paint(
 31        &mut self,
 32        bounds: Bounds<Pixels>,
 33        view_state: &mut V,
 34        element_state: &mut Self::ElementState,
 35        cx: &mut ViewContext<V>,
 36    );
 37
 38    fn handle_text_input<'a>(
 39        &self,
 40        _view_state: &'a mut V,
 41        _cx: &mut ViewContext<V>,
 42    ) -> Option<(Box<dyn InputHandlerView>, &'a FocusHandle)> {
 43        None
 44    }
 45}
 46
 47#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 48pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
 49
 50pub trait ParentElement<V: 'static> {
 51    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
 52
 53    fn child(mut self, child: impl Component<V>) -> Self
 54    where
 55        Self: Sized,
 56    {
 57        self.children_mut().push(child.render());
 58        self
 59    }
 60
 61    fn children(mut self, iter: impl IntoIterator<Item = impl Component<V>>) -> Self
 62    where
 63        Self: Sized,
 64    {
 65        self.children_mut()
 66            .extend(iter.into_iter().map(|item| item.render()));
 67        self
 68    }
 69}
 70
 71trait ElementObject<V> {
 72    fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
 73    fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
 74    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
 75}
 76
 77struct RenderedElement<V: 'static, E: Element<V>> {
 78    element: E,
 79    phase: ElementRenderPhase<E::ElementState>,
 80}
 81
 82#[derive(Default)]
 83enum ElementRenderPhase<V> {
 84    #[default]
 85    Start,
 86    Initialized {
 87        frame_state: Option<V>,
 88    },
 89    LayoutRequested {
 90        layout_id: LayoutId,
 91        frame_state: Option<V>,
 92    },
 93    Painted,
 94}
 95
 96/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
 97/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
 98/// improved usability.
 99impl<V, E: Element<V>> RenderedElement<V, E> {
100    fn new(element: E) -> Self {
101        RenderedElement {
102            element,
103            phase: ElementRenderPhase::Start,
104        }
105    }
106}
107
108impl<V, E> ElementObject<V> for RenderedElement<V, E>
109where
110    E: Element<V>,
111    E::ElementState: 'static,
112{
113    fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
114        let frame_state = if let Some(id) = self.element.id() {
115            cx.with_element_state(id, |element_state, cx| {
116                let element_state = self.element.initialize(view_state, element_state, cx);
117                ((), element_state)
118            });
119            None
120        } else {
121            let frame_state = self.element.initialize(view_state, None, cx);
122            Some(frame_state)
123        };
124
125        self.phase = ElementRenderPhase::Initialized { frame_state };
126    }
127
128    fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
129        let layout_id;
130        let mut frame_state;
131        match mem::take(&mut self.phase) {
132            ElementRenderPhase::Initialized {
133                frame_state: initial_frame_state,
134            } => {
135                frame_state = initial_frame_state;
136                if let Some(id) = self.element.id() {
137                    layout_id = cx.with_element_state(id, |element_state, cx| {
138                        let mut element_state = element_state.unwrap();
139                        let layout_id = self.element.layout(state, &mut element_state, cx);
140                        (layout_id, element_state)
141                    });
142                } else {
143                    layout_id = self
144                        .element
145                        .layout(state, frame_state.as_mut().unwrap(), cx);
146                }
147            }
148            ElementRenderPhase::Start => panic!("must call initialize before layout"),
149            ElementRenderPhase::LayoutRequested { .. } | ElementRenderPhase::Painted => {
150                panic!("element rendered twice")
151            }
152        };
153
154        self.phase = ElementRenderPhase::LayoutRequested {
155            layout_id,
156            frame_state,
157        };
158        layout_id
159    }
160
161    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
162        self.phase = match mem::take(&mut self.phase) {
163            ElementRenderPhase::LayoutRequested {
164                layout_id,
165                mut frame_state,
166            } => {
167                let bounds = cx.layout_bounds(layout_id);
168                if let Some((input_handler, focus_handle)) =
169                    self.element.handle_text_input(view_state, cx)
170                {
171                    if focus_handle.is_focused(cx) {
172                        cx.window.requested_input_handler = Some(Box::new(WindowInputHandler {
173                            cx: cx.app.this.clone(),
174                            window: cx.window_handle(),
175                            input_handler,
176                            element_bounds: bounds,
177                        }));
178                    }
179                }
180                if let Some(id) = self.element.id() {
181                    cx.with_element_state(id, |element_state, cx| {
182                        let mut element_state = element_state.unwrap();
183                        self.element
184                            .paint(bounds, view_state, &mut element_state, cx);
185                        ((), element_state)
186                    });
187                } else {
188                    self.element
189                        .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
190                }
191                ElementRenderPhase::Painted
192            }
193
194            _ => panic!("must call layout before paint"),
195        };
196    }
197}
198
199pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
200
201impl<V> AnyElement<V> {
202    pub fn new<E>(element: E) -> Self
203    where
204        V: 'static,
205        E: 'static + Element<V>,
206        E::ElementState: Any,
207    {
208        AnyElement(Box::new(RenderedElement::new(element)))
209    }
210
211    pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
212        self.0.initialize(view_state, cx);
213    }
214
215    pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
216        self.0.layout(view_state, cx)
217    }
218
219    pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
220        self.0.paint(view_state, cx)
221    }
222}
223
224pub trait Component<V> {
225    fn render(self) -> AnyElement<V>;
226
227    fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
228    where
229        Self: Sized,
230        U: Component<V>,
231    {
232        f(self)
233    }
234
235    fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
236    where
237        Self: Sized,
238    {
239        self.map(|this| if condition { then(this) } else { this })
240    }
241
242    fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
243    where
244        Self: Sized,
245    {
246        self.map(|this| {
247            if let Some(value) = option {
248                then(this, value)
249            } else {
250                this
251            }
252        })
253    }
254}
255
256impl<V> Component<V> for AnyElement<V> {
257    fn render(self) -> AnyElement<V> {
258        self
259    }
260}
261
262impl<V, E, F> Element<V> for Option<F>
263where
264    V: 'static,
265    E: 'static + Component<V>,
266    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
267{
268    type ElementState = AnyElement<V>;
269
270    fn id(&self) -> Option<ElementId> {
271        None
272    }
273
274    fn initialize(
275        &mut self,
276        view_state: &mut V,
277        _rendered_element: Option<Self::ElementState>,
278        cx: &mut ViewContext<V>,
279    ) -> Self::ElementState {
280        let render = self.take().unwrap();
281        let mut rendered_element = (render)(view_state, cx).render();
282        rendered_element.initialize(view_state, cx);
283        rendered_element
284    }
285
286    fn layout(
287        &mut self,
288        view_state: &mut V,
289        rendered_element: &mut Self::ElementState,
290        cx: &mut ViewContext<V>,
291    ) -> LayoutId {
292        rendered_element.layout(view_state, cx)
293    }
294
295    fn paint(
296        &mut self,
297        _bounds: Bounds<Pixels>,
298        view_state: &mut V,
299        rendered_element: &mut Self::ElementState,
300        cx: &mut ViewContext<V>,
301    ) {
302        rendered_element.paint(view_state, cx)
303    }
304}
305
306impl<V, E, F> Component<V> for Option<F>
307where
308    V: 'static,
309    E: 'static + Component<V>,
310    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
311{
312    fn render(self) -> AnyElement<V> {
313        AnyElement::new(self)
314    }
315}
316
317impl<V, E, F> Component<V> for F
318where
319    V: 'static,
320    E: 'static + Component<V>,
321    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
322{
323    fn render(self) -> AnyElement<V> {
324        AnyElement::new(Some(self))
325    }
326}