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