1use crate::{
2 AnyElement, Bounds, DispatchPhase, Element, Interactive, MouseDownEvent, MouseEventListeners,
3 MouseUpEvent, 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 Pressable<E: Styled> {
13 cascade_slot: CascadeSlot,
14 pressed_style: <E::Style as Refineable>::Refinement,
15 child: E,
16}
17
18pub struct PressableState<S> {
19 pressed: Arc<AtomicBool>,
20 child_state: S,
21}
22
23impl<E: Styled> Pressable<E> {
24 pub fn new(mut child: E) -> Self {
25 Self {
26 cascade_slot: child.style_cascade().reserve(),
27 pressed_style: Default::default(),
28 child,
29 }
30 }
31}
32
33impl<E> Styled for Pressable<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.pressed_style
45 }
46}
47
48impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Pressable<E> {
49 fn listeners(&mut self) -> &mut MouseEventListeners<S> {
50 self.child.listeners()
51 }
52}
53
54impl<E> Element for Pressable<E>
55where
56 E: Styled + StatefulElement,
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 = PressableState<E::ElementState>;
62
63 fn element_id(&self) -> Option<crate::ElementId> {
64 Some(StatefulElement::element_id(&self.child))
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 if let Some(element_state) = element_state {
74 let (id, child_state) = self
75 .child
76 .layout(state, Some(element_state.child_state), cx);
77 let element_state = PressableState {
78 pressed: element_state.pressed,
79 child_state,
80 };
81 (id, element_state)
82 } else {
83 let (id, child_state) = self.child.layout(state, None, cx);
84 let element_state = PressableState {
85 pressed: Default::default(),
86 child_state,
87 };
88 (id, element_state)
89 }
90 }
91
92 fn paint(
93 &mut self,
94 bounds: Bounds<Pixels>,
95 state: &mut Self::ViewState,
96 element_state: &mut Self::ElementState,
97 cx: &mut ViewContext<Self::ViewState>,
98 ) {
99 let style = element_state
100 .pressed
101 .load(SeqCst)
102 .then_some(self.pressed_style.clone());
103 let slot = self.cascade_slot;
104 self.style_cascade().set(slot, style);
105
106 let pressed = element_state.pressed.clone();
107 cx.on_mouse_event(move |_, event: &MouseDownEvent, phase, cx| {
108 if phase == DispatchPhase::Capture {
109 if bounds.contains_point(event.position) {
110 pressed.store(true, SeqCst);
111 cx.notify();
112 }
113 }
114 });
115 let pressed = element_state.pressed.clone();
116 cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
117 if phase == DispatchPhase::Capture {
118 if pressed.load(SeqCst) {
119 pressed.store(false, SeqCst);
120 cx.notify();
121 }
122 }
123 });
124
125 self.child
126 .paint(bounds, state, &mut element_state.child_state, cx);
127 }
128}
129
130impl<E: ParentElement + Styled> ParentElement for Pressable<E> {
131 type State = E::State;
132
133 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
134 self.child.children_mut()
135 }
136}
137
138impl<E> StatefulElement for Pressable<E>
139where
140 E: StatefulElement + Styled,
141 <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
142 <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
143{
144}