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}