hoverable.rs

  1use crate::{
  2    AnyElement, Bounds, DispatchPhase, Element, ElementId, Interactive, MouseEventListeners,
  3    MouseMoveEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
  4};
  5use refineable::{CascadeSlot, Refineable, RefinementCascade};
  6use smallvec::SmallVec;
  7use std::sync::{
  8    atomic::{AtomicBool, Ordering::SeqCst},
  9    Arc,
 10};
 11
 12pub struct Hoverable<E: Styled>
 13// where
 14// <E::Style as Refineable>::Refinement: 'static + Send + Sync,
 15{
 16    hovered: Arc<AtomicBool>,
 17    cascade_slot: CascadeSlot,
 18    hovered_style: <E::Style as Refineable>::Refinement,
 19    child: E,
 20}
 21
 22impl<E: Styled> Hoverable<E> {
 23    pub fn new(mut child: E) -> Self {
 24        Self {
 25            hovered: Arc::new(AtomicBool::new(false)),
 26            cascade_slot: child.style_cascade().reserve(),
 27            hovered_style: Default::default(),
 28            child,
 29        }
 30    }
 31}
 32
 33impl<E> Styled for Hoverable<E>
 34where
 35    E: Styled,
 36{
 37    type Style = E::Style;
 38
 39    fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
 40        self.child.style_cascade()
 41    }
 42
 43    fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
 44        &mut self.hovered_style
 45    }
 46}
 47
 48impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Hoverable<E> {
 49    fn listeners(&mut self) -> &mut MouseEventListeners<S> {
 50        self.child.listeners()
 51    }
 52}
 53
 54impl<E> Element for Hoverable<E>
 55where
 56    E: Element + Styled,
 57    <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
 58    <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
 59{
 60    type ViewState = E::ViewState;
 61    type ElementState = E::ElementState;
 62
 63    fn element_id(&self) -> Option<ElementId> {
 64        self.child.element_id()
 65    }
 66
 67    fn layout(
 68        &mut self,
 69        state: &mut Self::ViewState,
 70        element_state: Option<Self::ElementState>,
 71        cx: &mut ViewContext<Self::ViewState>,
 72    ) -> (crate::LayoutId, Self::ElementState) {
 73        self.child.layout(state, element_state, cx)
 74    }
 75
 76    fn paint(
 77        &mut self,
 78        bounds: Bounds<Pixels>,
 79        state: &mut Self::ViewState,
 80        element_state: &mut Self::ElementState,
 81        cx: &mut ViewContext<Self::ViewState>,
 82    ) {
 83        let hovered = bounds.contains_point(cx.mouse_position());
 84        let slot = self.cascade_slot;
 85        let style = hovered.then_some(self.hovered_style.clone());
 86        self.style_cascade().set(slot, style);
 87        self.hovered.store(hovered, SeqCst);
 88
 89        let hovered = self.hovered.clone();
 90        cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
 91            if phase == DispatchPhase::Capture {
 92                if bounds.contains_point(event.position) != hovered.load(SeqCst) {
 93                    cx.notify();
 94                }
 95            }
 96        });
 97
 98        self.child.paint(bounds, state, element_state, cx);
 99    }
100}
101
102impl<E: ParentElement + Styled> ParentElement for Hoverable<E> {
103    type State = E::State;
104
105    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
106        self.child.children_mut()
107    }
108}
109
110impl<E> StatefulElement for Hoverable<E>
111where
112    E: StatefulElement + Styled,
113    <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
114    <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
115{
116}