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