element.rs

  1use crate::{
  2    AppContext, BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners,
  3    KeyDownEvent, KeyListener, KeyMatch, LayoutId, MouseClickEvent, MouseClickListener,
  4    MouseDownEvent, MouseDownListener, MouseMoveEvent, MouseMoveListener, MouseUpEvent,
  5    MouseUpListener, Pixels, Point, ScrollWheelEvent, ScrollWheelListener, SharedString, Style,
  6    StyleRefinement, ViewContext, WindowContext,
  7};
  8use collections::HashMap;
  9use derive_more::{Deref, DerefMut};
 10use parking_lot::Mutex;
 11use refineable::Refineable;
 12pub(crate) use smallvec::SmallVec;
 13use std::{any::TypeId, mem, sync::Arc};
 14
 15pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
 16    type ViewState: 'static + Send + Sync;
 17    type ElementState: 'static + Send + Sync;
 18
 19    fn id(&self) -> Option<ElementId>;
 20
 21    fn initialize(
 22        &mut self,
 23        view_state: &mut Self::ViewState,
 24        element_state: Option<Self::ElementState>,
 25        cx: &mut ViewContext<Self::ViewState>,
 26    ) -> Self::ElementState;
 27
 28    fn layout(
 29        &mut self,
 30        view_state: &mut Self::ViewState,
 31        element_state: &mut Self::ElementState,
 32        cx: &mut ViewContext<Self::ViewState>,
 33    ) -> LayoutId;
 34
 35    fn paint(
 36        &mut self,
 37        bounds: Bounds<Pixels>,
 38        view_state: &mut Self::ViewState,
 39        element_state: &mut Self::ElementState,
 40        cx: &mut ViewContext<Self::ViewState>,
 41    );
 42}
 43
 44#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 45pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
 46
 47pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync {
 48    fn as_stateless(&self) -> &StatelessInteractivity<V>;
 49    fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V>;
 50    fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>;
 51    fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>>;
 52
 53    fn initialize<R>(
 54        &mut self,
 55        cx: &mut ViewContext<V>,
 56        f: impl FnOnce(&mut ViewContext<V>) -> R,
 57    ) -> R {
 58        if let Some(stateful) = self.as_stateful_mut() {
 59            cx.with_element_id(stateful.id.clone(), |global_id, cx| {
 60                stateful.key_listeners.push((
 61                    TypeId::of::<KeyDownEvent>(),
 62                    Arc::new(move |_, key_down, context, phase, cx| {
 63                        if phase == DispatchPhase::Bubble {
 64                            let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap();
 65                            if let KeyMatch::Some(action) =
 66                                cx.match_keystroke(&global_id, &key_down.keystroke, context)
 67                            {
 68                                return Some(action);
 69                            }
 70                        }
 71
 72                        None
 73                    }),
 74                ));
 75                let result = stateful.stateless.initialize(cx, f);
 76                stateful.key_listeners.pop();
 77                result
 78            })
 79        } else {
 80            cx.with_key_listeners(&self.as_stateless().key_listeners, f)
 81        }
 82    }
 83
 84    fn refine_style(
 85        &self,
 86        style: &mut Style,
 87        bounds: Bounds<Pixels>,
 88        element_state: &InteractiveElementState,
 89        cx: &mut ViewContext<V>,
 90    ) {
 91        let mouse_position = cx.mouse_position();
 92        let stateless = self.as_stateless();
 93        if let Some(group_hover) = stateless.group_hover_style.as_ref() {
 94            if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
 95                if group_bounds.contains_point(&mouse_position) {
 96                    style.refine(&group_hover.style);
 97                }
 98            }
 99        }
100        if bounds.contains_point(&mouse_position) {
101            style.refine(&stateless.hover_style);
102        }
103
104        if let Some(stateful) = self.as_stateful() {
105            let active_state = element_state.active_state.lock();
106            if active_state.group {
107                if let Some(group_style) = stateful.group_active_style.as_ref() {
108                    style.refine(&group_style.style);
109                }
110            }
111            if active_state.element {
112                style.refine(&stateful.active_style);
113            }
114        }
115    }
116
117    fn paint(
118        &mut self,
119        bounds: Bounds<Pixels>,
120        element_state: &InteractiveElementState,
121        cx: &mut ViewContext<V>,
122    ) {
123        let stateless = self.as_stateless();
124        for listener in stateless.mouse_down_listeners.iter().cloned() {
125            cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
126                listener(state, event, &bounds, phase, cx);
127            })
128        }
129
130        for listener in stateless.mouse_up_listeners.iter().cloned() {
131            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
132                listener(state, event, &bounds, phase, cx);
133            })
134        }
135
136        for listener in stateless.mouse_move_listeners.iter().cloned() {
137            cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
138                listener(state, event, &bounds, phase, cx);
139            })
140        }
141
142        for listener in stateless.scroll_wheel_listeners.iter().cloned() {
143            cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
144                listener(state, event, &bounds, phase, cx);
145            })
146        }
147
148        let hover_group_bounds = stateless
149            .group_hover_style
150            .as_ref()
151            .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
152
153        if let Some(group_bounds) = hover_group_bounds {
154            paint_hover_listener(group_bounds, cx);
155        }
156
157        if stateless.hover_style.is_some() {
158            paint_hover_listener(bounds, cx);
159        }
160
161        if let Some(stateful) = self.as_stateful() {
162            let click_listeners = stateful.mouse_click_listeners.clone();
163
164            let pending_click = element_state.pending_click.clone();
165            let mouse_down = pending_click.lock().clone();
166            if let Some(mouse_down) = mouse_down {
167                cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
168                    if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
169                        let mouse_click = MouseClickEvent {
170                            down: mouse_down.clone(),
171                            up: event.clone(),
172                        };
173                        for listener in &click_listeners {
174                            listener(state, &mouse_click, cx);
175                        }
176                    }
177
178                    *pending_click.lock() = None;
179                });
180            } else {
181                cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
182                    if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
183                        *pending_click.lock() = Some(event.clone());
184                    }
185                });
186            }
187
188            let active_state = element_state.active_state.clone();
189            if active_state.lock().is_none() {
190                let active_group_bounds = stateful
191                    .group_active_style
192                    .as_ref()
193                    .and_then(|group_active| GroupBounds::get(&group_active.group, cx));
194                cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
195                    if phase == DispatchPhase::Bubble {
196                        let group = active_group_bounds
197                            .map_or(false, |bounds| bounds.contains_point(&down.position));
198                        let element = bounds.contains_point(&down.position);
199                        if group || element {
200                            *active_state.lock() = ActiveState { group, element };
201                            cx.notify();
202                        }
203                    }
204                });
205            } else {
206                cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
207                    if phase == DispatchPhase::Capture {
208                        *active_state.lock() = ActiveState::default();
209                        cx.notify();
210                    }
211                });
212            }
213        }
214    }
215}
216
217fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
218where
219    V: 'static + Send + Sync,
220{
221    let hovered = bounds.contains_point(&cx.mouse_position());
222    cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
223        if phase == DispatchPhase::Capture {
224            if bounds.contains_point(&event.position) != hovered {
225                cx.notify();
226            }
227        }
228    });
229}
230
231#[derive(Deref, DerefMut)]
232pub struct StatefulInteractivity<V: 'static + Send + Sync> {
233    pub id: ElementId,
234    #[deref]
235    #[deref_mut]
236    stateless: StatelessInteractivity<V>,
237    pub mouse_click_listeners: SmallVec<[MouseClickListener<V>; 2]>,
238    pub active_style: StyleRefinement,
239    pub group_active_style: Option<GroupStyle>,
240}
241
242impl<V> ElementInteractivity<V> for StatefulInteractivity<V>
243where
244    V: 'static + Send + Sync,
245{
246    fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
247        Some(self)
248    }
249
250    fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
251        Some(self)
252    }
253
254    fn as_stateless(&self) -> &StatelessInteractivity<V> {
255        &self.stateless
256    }
257
258    fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
259        &mut self.stateless
260    }
261}
262
263impl<V> From<ElementId> for StatefulInteractivity<V>
264where
265    V: 'static + Send + Sync,
266{
267    fn from(id: ElementId) -> Self {
268        Self {
269            id,
270            stateless: StatelessInteractivity::default(),
271            mouse_click_listeners: SmallVec::new(),
272            active_style: StyleRefinement::default(),
273            group_active_style: None,
274        }
275    }
276}
277
278pub struct StatelessInteractivity<V> {
279    pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
280    pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
281    pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
282    pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
283    pub key_listeners: SmallVec<[(TypeId, KeyListener<V>); 32]>,
284    pub hover_style: StyleRefinement,
285    pub group_hover_style: Option<GroupStyle>,
286}
287
288pub struct GroupStyle {
289    pub group: SharedString,
290    pub style: StyleRefinement,
291}
292
293#[derive(Default)]
294pub struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
295
296impl GroupBounds {
297    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
298        cx.default_global::<Self>()
299            .0
300            .get(name)
301            .and_then(|bounds_stack| bounds_stack.last())
302            .cloned()
303    }
304
305    pub fn push(name: SharedString, bounds: Bounds<Pixels>, cx: &mut AppContext) {
306        cx.default_global::<Self>()
307            .0
308            .entry(name)
309            .or_default()
310            .push(bounds);
311    }
312
313    pub fn pop(name: &SharedString, cx: &mut AppContext) {
314        cx.default_global::<GroupBounds>()
315            .0
316            .get_mut(name)
317            .unwrap()
318            .pop();
319    }
320}
321
322#[derive(Copy, Clone, Default, Eq, PartialEq)]
323struct ActiveState {
324    pub group: bool,
325    pub element: bool,
326}
327
328impl ActiveState {
329    pub fn is_none(&self) -> bool {
330        !self.group && !self.element
331    }
332}
333
334#[derive(Default)]
335pub struct InteractiveElementState {
336    active_state: Arc<Mutex<ActiveState>>,
337    pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
338}
339
340impl<V> Default for StatelessInteractivity<V> {
341    fn default() -> Self {
342        Self {
343            mouse_down_listeners: SmallVec::new(),
344            mouse_up_listeners: SmallVec::new(),
345            mouse_move_listeners: SmallVec::new(),
346            scroll_wheel_listeners: SmallVec::new(),
347            key_listeners: SmallVec::new(),
348            hover_style: StyleRefinement::default(),
349            group_hover_style: None,
350        }
351    }
352}
353
354impl<V> ElementInteractivity<V> for StatelessInteractivity<V>
355where
356    V: 'static + Send + Sync,
357{
358    fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
359        None
360    }
361
362    fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
363        None
364    }
365
366    fn as_stateless(&self) -> &StatelessInteractivity<V> {
367        self
368    }
369
370    fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
371        self
372    }
373}
374
375pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync {
376    fn as_focusable(&self) -> Option<&Focusable<V>>;
377
378    fn initialize<R>(
379        &self,
380        cx: &mut ViewContext<V>,
381        f: impl FnOnce(&mut ViewContext<V>) -> R,
382    ) -> R {
383        if let Some(focusable) = self.as_focusable() {
384            for listener in focusable.focus_listeners.iter().cloned() {
385                cx.on_focus_changed(move |view, event, cx| listener(view, event, cx));
386            }
387            cx.with_focus(focusable.focus_handle.clone(), |cx| f(cx))
388        } else {
389            f(cx)
390        }
391    }
392
393    fn refine_style(&self, style: &mut Style, cx: &WindowContext) {
394        if let Some(focusable) = self.as_focusable() {
395            if focusable.focus_handle.contains_focused(cx) {
396                style.refine(&focusable.focus_in_style);
397            }
398
399            if focusable.focus_handle.within_focused(cx) {
400                style.refine(&focusable.in_focus_style);
401            }
402
403            if focusable.focus_handle.is_focused(cx) {
404                style.refine(&focusable.focus_style);
405            }
406        }
407    }
408
409    fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
410        if let Some(focusable) = self.as_focusable() {
411            let focus_handle = focusable.focus_handle.clone();
412            cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
413                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
414                    if !cx.default_prevented() {
415                        cx.focus(&focus_handle);
416                        cx.prevent_default();
417                    }
418                }
419            })
420        }
421    }
422}
423
424pub struct Focusable<V: 'static + Send + Sync> {
425    pub focus_handle: FocusHandle,
426    pub focus_listeners: FocusListeners<V>,
427    pub focus_style: StyleRefinement,
428    pub focus_in_style: StyleRefinement,
429    pub in_focus_style: StyleRefinement,
430}
431
432impl<V> ElementFocusability<V> for Focusable<V>
433where
434    V: 'static + Send + Sync,
435{
436    fn as_focusable(&self) -> Option<&Focusable<V>> {
437        Some(self)
438    }
439}
440
441impl<V> From<FocusHandle> for Focusable<V>
442where
443    V: 'static + Send + Sync,
444{
445    fn from(value: FocusHandle) -> Self {
446        Self {
447            focus_handle: value,
448            focus_listeners: FocusListeners::default(),
449            focus_style: StyleRefinement::default(),
450            focus_in_style: StyleRefinement::default(),
451            in_focus_style: StyleRefinement::default(),
452        }
453    }
454}
455
456pub struct NonFocusable;
457
458impl<V> ElementFocusability<V> for NonFocusable
459where
460    V: 'static + Send + Sync,
461{
462    fn as_focusable(&self) -> Option<&Focusable<V>> {
463        None
464    }
465}
466
467pub trait ParentElement: Element {
468    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>;
469
470    fn child(mut self, child: impl IntoAnyElement<Self::ViewState>) -> Self
471    where
472        Self: Sized,
473    {
474        self.children_mut().push(child.into_any());
475        self
476    }
477
478    fn children(
479        mut self,
480        iter: impl IntoIterator<Item = impl IntoAnyElement<Self::ViewState>>,
481    ) -> Self
482    where
483        Self: Sized,
484    {
485        self.children_mut()
486            .extend(iter.into_iter().map(|item| item.into_any()));
487        self
488    }
489}
490
491trait ElementObject<V>: 'static + Send + Sync {
492    fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
493    fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
494    fn paint(&mut self, view_state: &mut V, offset: Option<Point<Pixels>>, cx: &mut ViewContext<V>);
495}
496
497struct RenderedElement<E: Element> {
498    element: E,
499    phase: ElementRenderPhase<E::ElementState>,
500}
501
502#[derive(Default)]
503enum ElementRenderPhase<V> {
504    #[default]
505    Start,
506    Initialized {
507        frame_state: Option<V>,
508    },
509    LayoutRequested {
510        layout_id: LayoutId,
511        frame_state: Option<V>,
512    },
513    Painted,
514}
515
516/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
517/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
518/// improved usability.
519impl<E: Element> RenderedElement<E> {
520    fn new(element: E) -> Self {
521        RenderedElement {
522            element,
523            phase: ElementRenderPhase::Start,
524        }
525    }
526}
527
528impl<E> ElementObject<E::ViewState> for RenderedElement<E>
529where
530    E: Element,
531{
532    fn initialize(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) {
533        let frame_state = if let Some(id) = self.element.id() {
534            cx.with_element_state(id, |element_state, cx| {
535                let element_state = self.element.initialize(view_state, element_state, cx);
536                ((), element_state)
537            });
538            None
539        } else {
540            let frame_state = self.element.initialize(view_state, None, cx);
541            Some(frame_state)
542        };
543
544        self.phase = ElementRenderPhase::Initialized { frame_state };
545    }
546
547    fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
548        let layout_id;
549        let mut frame_state;
550        match mem::take(&mut self.phase) {
551            ElementRenderPhase::Initialized {
552                frame_state: initial_frame_state,
553            } => {
554                frame_state = initial_frame_state;
555                if let Some(id) = self.element.id() {
556                    layout_id = cx.with_element_state(id, |element_state, cx| {
557                        let mut element_state = element_state.unwrap();
558                        let layout_id = self.element.layout(state, &mut element_state, cx);
559                        (layout_id, element_state)
560                    });
561                } else {
562                    layout_id = self
563                        .element
564                        .layout(state, frame_state.as_mut().unwrap(), cx);
565                }
566            }
567            _ => panic!("must call initialize before layout"),
568        };
569
570        self.phase = ElementRenderPhase::LayoutRequested {
571            layout_id,
572            frame_state,
573        };
574        layout_id
575    }
576
577    fn paint(
578        &mut self,
579        view_state: &mut E::ViewState,
580        offset: Option<Point<Pixels>>,
581        cx: &mut ViewContext<E::ViewState>,
582    ) {
583        self.phase = match mem::take(&mut self.phase) {
584            ElementRenderPhase::LayoutRequested {
585                layout_id,
586                mut frame_state,
587            } => {
588                let mut bounds = cx.layout_bounds(layout_id);
589                offset.map(|offset| bounds.origin += offset);
590                if let Some(id) = self.element.id() {
591                    cx.with_element_state(id, |element_state, cx| {
592                        let mut element_state = element_state.unwrap();
593                        self.element
594                            .paint(bounds, view_state, &mut element_state, cx);
595                        ((), element_state)
596                    });
597                } else {
598                    self.element
599                        .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
600                }
601                ElementRenderPhase::Painted
602            }
603
604            _ => panic!("must call layout before paint"),
605        };
606    }
607}
608
609pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
610
611impl<V: 'static + Send + Sync> AnyElement<V> {
612    pub fn new<E: Element<ViewState = V>>(element: E) -> Self {
613        AnyElement(Box::new(RenderedElement::new(element)))
614    }
615
616    pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
617        self.0.initialize(view_state, cx);
618    }
619
620    pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
621        self.0.layout(view_state, cx)
622    }
623
624    pub fn paint(
625        &mut self,
626        view_state: &mut V,
627        offset: Option<Point<Pixels>>,
628        cx: &mut ViewContext<V>,
629    ) {
630        self.0.paint(view_state, offset, cx)
631    }
632}
633
634pub trait IntoAnyElement<V> {
635    fn into_any(self) -> AnyElement<V>;
636}
637
638impl<V> IntoAnyElement<V> for AnyElement<V> {
639    fn into_any(self) -> AnyElement<V> {
640        self
641    }
642}