1use crate::{
2 Bounds, DispatchPhase, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
3 ScrollWheelEvent, ViewContext,
4};
5use parking_lot::Mutex;
6use smallvec::SmallVec;
7use std::sync::Arc;
8
9pub trait Interactive<S: 'static + Send + Sync> {
10 fn listeners(&mut self) -> &mut MouseEventListeners<S>;
11
12 fn on_mouse_down(
13 mut self,
14 button: MouseButton,
15 handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
16 ) -> Self
17 where
18 Self: Sized,
19 {
20 self.listeners()
21 .mouse_down
22 .push(Arc::new(move |view, event, bounds, phase, cx| {
23 if phase == DispatchPhase::Bubble
24 && event.button == button
25 && bounds.contains_point(event.position)
26 {
27 handler(view, event, cx)
28 }
29 }));
30 self
31 }
32
33 fn on_mouse_up(
34 mut self,
35 button: MouseButton,
36 handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
37 ) -> Self
38 where
39 Self: Sized,
40 {
41 self.listeners()
42 .mouse_up
43 .push(Arc::new(move |view, event, bounds, phase, cx| {
44 if phase == DispatchPhase::Bubble
45 && event.button == button
46 && bounds.contains_point(event.position)
47 {
48 handler(view, event, cx)
49 }
50 }));
51 self
52 }
53
54 fn on_mouse_down_out(
55 mut self,
56 button: MouseButton,
57 handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
58 ) -> Self
59 where
60 Self: Sized,
61 {
62 self.listeners()
63 .mouse_down
64 .push(Arc::new(move |view, event, bounds, phase, cx| {
65 if phase == DispatchPhase::Capture
66 && event.button == button
67 && !bounds.contains_point(event.position)
68 {
69 handler(view, event, cx)
70 }
71 }));
72 self
73 }
74
75 fn on_mouse_up_out(
76 mut self,
77 button: MouseButton,
78 handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
79 ) -> Self
80 where
81 Self: Sized,
82 {
83 self.listeners()
84 .mouse_up
85 .push(Arc::new(move |view, event, bounds, phase, cx| {
86 if phase == DispatchPhase::Capture
87 && event.button == button
88 && !bounds.contains_point(event.position)
89 {
90 handler(view, event, cx);
91 }
92 }));
93 self
94 }
95
96 fn on_click(
97 self,
98 button: MouseButton,
99 handler: impl Fn(&mut S, (&MouseDownEvent, &MouseUpEvent), &mut ViewContext<S>)
100 + Send
101 + Sync
102 + 'static,
103 ) -> Self
104 where
105 Self: Sized,
106 {
107 let down_event = Arc::new(Mutex::new(None));
108 self.on_mouse_down(button, {
109 let down_event = down_event.clone();
110 move |_, event, _| {
111 down_event.lock().replace(event.clone());
112 }
113 })
114 .on_mouse_up_out(button, {
115 let down_event = down_event.clone();
116 move |_, _, _| {
117 down_event.lock().take();
118 }
119 })
120 .on_mouse_up(button, move |view, event, cx| {
121 if let Some(down_event) = down_event.lock().take() {
122 handler(view, (&down_event, event), cx);
123 }
124 })
125 }
126
127 fn on_mouse_move(
128 mut self,
129 handler: impl Fn(&mut S, &MouseMoveEvent, &mut ViewContext<S>) + Send + Sync + 'static,
130 ) -> Self
131 where
132 Self: Sized,
133 {
134 self.listeners()
135 .mouse_move
136 .push(Arc::new(move |view, event, bounds, phase, cx| {
137 if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
138 handler(view, event, cx);
139 }
140 }));
141 self
142 }
143
144 fn on_scroll_wheel(
145 mut self,
146 handler: impl Fn(&mut S, &ScrollWheelEvent, &mut ViewContext<S>) + Send + Sync + 'static,
147 ) -> Self
148 where
149 Self: Sized,
150 {
151 self.listeners()
152 .scroll_wheel
153 .push(Arc::new(move |view, event, bounds, phase, cx| {
154 if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
155 handler(view, event, cx);
156 }
157 }));
158 self
159 }
160}
161
162type MouseDownHandler<V> = Arc<
163 dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
164 + Send
165 + Sync
166 + 'static,
167>;
168type MouseUpHandler<V> = Arc<
169 dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
170 + Send
171 + Sync
172 + 'static,
173>;
174
175type MouseMoveHandler<V> = Arc<
176 dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
177 + Send
178 + Sync
179 + 'static,
180>;
181type ScrollWheelHandler<V> = Arc<
182 dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
183 + Send
184 + Sync
185 + 'static,
186>;
187
188pub struct MouseEventListeners<V: 'static> {
189 mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
190 mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
191 mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
192 scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
193}
194
195impl<S: Send + Sync + 'static> MouseEventListeners<S> {
196 pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<S>) {
197 for handler in self.mouse_down.iter().cloned() {
198 cx.on_mouse_event(move |view, event: &MouseDownEvent, phase, cx| {
199 handler(view, event, &bounds, phase, cx);
200 })
201 }
202 for handler in self.mouse_up.iter().cloned() {
203 cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
204 handler(view, event, &bounds, phase, cx);
205 })
206 }
207 for handler in self.mouse_move.iter().cloned() {
208 cx.on_mouse_event(move |view, event: &MouseMoveEvent, phase, cx| {
209 handler(view, event, &bounds, phase, cx);
210 })
211 }
212
213 for handler in self.scroll_wheel.iter().cloned() {
214 cx.on_mouse_event(move |view, event: &ScrollWheelEvent, phase, cx| {
215 handler(view, event, &bounds, phase, cx);
216 })
217 }
218 }
219}
220
221impl<V> Default for MouseEventListeners<V> {
222 fn default() -> Self {
223 Self {
224 mouse_down: Default::default(),
225 mouse_up: Default::default(),
226 mouse_move: Default::default(),
227 scroll_wheel: Default::default(),
228 }
229 }
230}