element.rs

  1use crate::{
  2    BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners, LayoutId,
  3    MouseDownEvent, Pixels, Point, Style, StyleRefinement, ViewContext, WindowContext,
  4};
  5use derive_more::{Deref, DerefMut};
  6use refineable::Refineable;
  7pub(crate) use smallvec::SmallVec;
  8use std::{marker::PhantomData, mem};
  9
 10pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
 11    type ViewState: 'static + Send + Sync;
 12    type ElementState: 'static + Send + Sync;
 13
 14    fn id(&self) -> Option<ElementId>;
 15
 16    fn initialize(
 17        &mut self,
 18        view_state: &mut Self::ViewState,
 19        element_state: Option<Self::ElementState>,
 20        cx: &mut ViewContext<Self::ViewState>,
 21    ) -> Self::ElementState;
 22
 23    fn layout(
 24        &mut self,
 25        view_state: &mut Self::ViewState,
 26        element_state: &mut Self::ElementState,
 27        cx: &mut ViewContext<Self::ViewState>,
 28    ) -> LayoutId;
 29
 30    fn paint(
 31        &mut self,
 32        bounds: Bounds<Pixels>,
 33        view_state: &mut Self::ViewState,
 34        element_state: &mut Self::ElementState,
 35        cx: &mut ViewContext<Self::ViewState>,
 36    );
 37}
 38
 39#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 40pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
 41
 42pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync {
 43    fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>;
 44
 45    fn initialize<R>(
 46        &self,
 47        cx: &mut ViewContext<V>,
 48        f: impl FnOnce(Option<GlobalElementId>, &mut ViewContext<V>) -> R,
 49    ) -> R {
 50        if let Some(identified) = self.as_stateful() {
 51            cx.with_element_id(identified.id.clone(), |global_id, cx| {
 52                f(Some(global_id), cx)
 53            })
 54        } else {
 55            f(None, cx)
 56        }
 57    }
 58}
 59
 60#[derive(Deref, DerefMut)]
 61pub struct StatefulInteractivity<V: 'static + Send + Sync> {
 62    pub id: ElementId,
 63    #[deref]
 64    #[deref_mut]
 65    common: StatelessInteractivity<V>,
 66}
 67
 68impl<V> ElementInteractivity<V> for StatefulInteractivity<V>
 69where
 70    V: 'static + Send + Sync,
 71{
 72    fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
 73        Some(self)
 74    }
 75}
 76
 77impl<V> From<ElementId> for StatefulInteractivity<V>
 78where
 79    V: 'static + Send + Sync,
 80{
 81    fn from(id: ElementId) -> Self {
 82        Self {
 83            id,
 84            common: StatelessInteractivity::default(),
 85        }
 86    }
 87}
 88
 89pub struct StatelessInteractivity<V>(PhantomData<V>);
 90
 91impl<V> Default for StatelessInteractivity<V> {
 92    fn default() -> Self {
 93        Self(PhantomData)
 94    }
 95}
 96
 97impl<V> ElementInteractivity<V> for StatelessInteractivity<V>
 98where
 99    V: 'static + Send + Sync,
100{
101    fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
102        None
103    }
104}
105
106pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync {
107    fn as_focusable(&self) -> Option<&Focusable<V>>;
108
109    fn initialize<R>(
110        &self,
111        cx: &mut ViewContext<V>,
112        f: impl FnOnce(&mut ViewContext<V>) -> R,
113    ) -> R {
114        if let Some(focusable) = self.as_focusable() {
115            for listener in focusable.focus_listeners.iter().cloned() {
116                cx.on_focus_changed(move |view, event, cx| listener(view, event, cx));
117            }
118            cx.with_focus(focusable.focus_handle.clone(), |cx| f(cx))
119        } else {
120            f(cx)
121        }
122    }
123
124    fn refine_style(&self, style: &mut Style, cx: &WindowContext) {
125        if let Some(focusable) = self.as_focusable() {
126            if focusable.focus_handle.contains_focused(cx) {
127                style.refine(&focusable.focus_in_style);
128            }
129
130            if focusable.focus_handle.within_focused(cx) {
131                style.refine(&focusable.in_focus_style);
132            }
133
134            if focusable.focus_handle.is_focused(cx) {
135                style.refine(&focusable.focus_style);
136            }
137        }
138    }
139
140    fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
141        if let Some(focusable) = self.as_focusable() {
142            let focus_handle = focusable.focus_handle.clone();
143            cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
144                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
145                    if !cx.default_prevented() {
146                        cx.focus(&focus_handle);
147                        cx.prevent_default();
148                    }
149                }
150            })
151        }
152    }
153}
154
155pub struct Focusable<V: 'static + Send + Sync> {
156    pub focus_handle: FocusHandle,
157    pub focus_listeners: FocusListeners<V>,
158    pub focus_style: StyleRefinement,
159    pub focus_in_style: StyleRefinement,
160    pub in_focus_style: StyleRefinement,
161}
162
163impl<V> ElementFocusability<V> for Focusable<V>
164where
165    V: 'static + Send + Sync,
166{
167    fn as_focusable(&self) -> Option<&Focusable<V>> {
168        Some(self)
169    }
170}
171
172impl<V> From<FocusHandle> for Focusable<V>
173where
174    V: 'static + Send + Sync,
175{
176    fn from(value: FocusHandle) -> Self {
177        Self {
178            focus_handle: value,
179            focus_listeners: FocusListeners::default(),
180            focus_style: StyleRefinement::default(),
181            focus_in_style: StyleRefinement::default(),
182            in_focus_style: StyleRefinement::default(),
183        }
184    }
185}
186
187pub struct NonFocusable;
188
189impl<V> ElementFocusability<V> for NonFocusable
190where
191    V: 'static + Send + Sync,
192{
193    fn as_focusable(&self) -> Option<&Focusable<V>> {
194        None
195    }
196}
197
198pub trait ParentElement: Element {
199    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>;
200
201    fn child(mut self, child: impl IntoAnyElement<Self::ViewState>) -> Self
202    where
203        Self: Sized,
204    {
205        self.children_mut().push(child.into_any());
206        self
207    }
208
209    fn children(
210        mut self,
211        iter: impl IntoIterator<Item = impl IntoAnyElement<Self::ViewState>>,
212    ) -> Self
213    where
214        Self: Sized,
215    {
216        self.children_mut()
217            .extend(iter.into_iter().map(|item| item.into_any()));
218        self
219    }
220}
221
222trait ElementObject<V>: 'static + Send + Sync {
223    fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
224    fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
225    fn paint(&mut self, view_state: &mut V, offset: Option<Point<Pixels>>, cx: &mut ViewContext<V>);
226}
227
228struct RenderedElement<E: Element> {
229    element: E,
230    phase: ElementRenderPhase<E::ElementState>,
231}
232
233#[derive(Default)]
234enum ElementRenderPhase<V> {
235    #[default]
236    Start,
237    Initialized {
238        frame_state: Option<V>,
239    },
240    LayoutRequested {
241        layout_id: LayoutId,
242        frame_state: Option<V>,
243    },
244    Painted,
245}
246
247/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
248/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
249/// improved usability.
250impl<E: Element> RenderedElement<E> {
251    fn new(element: E) -> Self {
252        RenderedElement {
253            element,
254            phase: ElementRenderPhase::Start,
255        }
256    }
257}
258
259impl<E> ElementObject<E::ViewState> for RenderedElement<E>
260where
261    E: Element,
262{
263    fn initialize(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) {
264        let frame_state = if let Some(id) = self.element.id() {
265            cx.with_element_state(id, |element_state, cx| {
266                let element_state = self.element.initialize(view_state, element_state, cx);
267                ((), element_state)
268            });
269            None
270        } else {
271            let frame_state = self.element.initialize(view_state, None, cx);
272            Some(frame_state)
273        };
274
275        self.phase = ElementRenderPhase::Initialized { frame_state };
276    }
277
278    fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
279        let layout_id;
280        let mut frame_state;
281        match mem::take(&mut self.phase) {
282            ElementRenderPhase::Initialized {
283                frame_state: initial_frame_state,
284            } => {
285                frame_state = initial_frame_state;
286                if let Some(id) = self.element.id() {
287                    layout_id = cx.with_element_state(id, |element_state, cx| {
288                        let mut element_state = element_state.unwrap();
289                        let layout_id = self.element.layout(state, &mut element_state, cx);
290                        (layout_id, element_state)
291                    });
292                } else {
293                    layout_id = self
294                        .element
295                        .layout(state, frame_state.as_mut().unwrap(), cx);
296                }
297            }
298            _ => panic!("must call initialize before layout"),
299        };
300
301        self.phase = ElementRenderPhase::LayoutRequested {
302            layout_id,
303            frame_state,
304        };
305        layout_id
306    }
307
308    fn paint(
309        &mut self,
310        view_state: &mut E::ViewState,
311        offset: Option<Point<Pixels>>,
312        cx: &mut ViewContext<E::ViewState>,
313    ) {
314        self.phase = match mem::take(&mut self.phase) {
315            ElementRenderPhase::LayoutRequested {
316                layout_id,
317                mut frame_state,
318            } => {
319                let mut bounds = cx.layout_bounds(layout_id);
320                offset.map(|offset| bounds.origin += offset);
321                if let Some(id) = self.element.id() {
322                    cx.with_element_state(id, |element_state, cx| {
323                        let mut element_state = element_state.unwrap();
324                        self.element
325                            .paint(bounds, view_state, &mut element_state, cx);
326                        ((), element_state)
327                    });
328                } else {
329                    self.element
330                        .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
331                }
332                ElementRenderPhase::Painted
333            }
334
335            _ => panic!("must call layout before paint"),
336        };
337    }
338}
339
340pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
341
342impl<V: 'static + Send + Sync> AnyElement<V> {
343    pub fn new<E: Element<ViewState = V>>(element: E) -> Self {
344        AnyElement(Box::new(RenderedElement::new(element)))
345    }
346
347    pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
348        self.0.initialize(view_state, cx);
349    }
350
351    pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
352        self.0.layout(view_state, cx)
353    }
354
355    pub fn paint(
356        &mut self,
357        view_state: &mut V,
358        offset: Option<Point<Pixels>>,
359        cx: &mut ViewContext<V>,
360    ) {
361        self.0.paint(view_state, offset, cx)
362    }
363}
364
365pub trait IntoAnyElement<V> {
366    fn into_any(self) -> AnyElement<V>;
367}
368
369impl<V> IntoAnyElement<V> for AnyElement<V> {
370    fn into_any(self) -> AnyElement<V> {
371        self
372    }
373}