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