1use crate::{
2 AnyElement, Bounds, DispatchPhase, Element, ElementId, Identified, Interactive,
3 MouseEventListeners, MouseMoveEvent, ParentElement, Pixels, 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 layout(
57 &mut self,
58 state: &mut Self::State,
59 cx: &mut ViewContext<Self::State>,
60 ) -> Result<(crate::LayoutId, Self::FrameState)> {
61 Ok(self.child.layout(state, cx)?)
62 }
63
64 fn paint(
65 &mut self,
66 bounds: Bounds<Pixels>,
67 state: &mut Self::State,
68 frame_state: &mut Self::FrameState,
69 cx: &mut ViewContext<Self::State>,
70 ) -> Result<()> {
71 let hovered = bounds.contains_point(cx.mouse_position());
72 let slot = self.cascade_slot;
73 let style = hovered.then_some(self.hovered_style.clone());
74 self.style_cascade().set(slot, style);
75 self.hovered.store(hovered, SeqCst);
76
77 let hovered = self.hovered.clone();
78 cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
79 if phase == DispatchPhase::Capture {
80 if bounds.contains_point(event.position) != hovered.load(SeqCst) {
81 cx.notify();
82 }
83 }
84 });
85
86 self.child.paint(bounds, state, frame_state, cx)?;
87 Ok(())
88 }
89}
90
91impl<E: ParentElement + Styled> ParentElement for Hoverable<E> {
92 type State = E::State;
93
94 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
95 self.child.children_mut()
96 }
97}
98
99impl<E: Identified + Styled> Identified for Hoverable<E> {
100 fn id(&self) -> ElementId {
101 self.child.id()
102 }
103}