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