1use crate::{
2 point, Action, Bounds, DispatchContext, DispatchPhase, Element, FocusHandle, Keystroke,
3 Modifiers, Pixels, Point, StatefulInteractivity, StatelessInteractivity, ViewContext,
4};
5use std::{
6 any::{Any, TypeId},
7 ops::Deref,
8 sync::Arc,
9};
10
11pub trait StatelesslyInteractive: Element {
12 fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<Self::ViewState>;
13
14 fn on_mouse_down(
15 mut self,
16 button: MouseButton,
17 handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
18 + Send
19 + Sync
20 + 'static,
21 ) -> Self
22 where
23 Self: Sized,
24 {
25 self.stateless_interactivity()
26 .mouse_down_listeners
27 .push(Arc::new(move |view, event, bounds, phase, cx| {
28 if phase == DispatchPhase::Bubble
29 && event.button == button
30 && bounds.contains_point(&event.position)
31 {
32 handler(view, event, cx)
33 }
34 }));
35 self
36 }
37
38 fn on_mouse_up(
39 mut self,
40 button: MouseButton,
41 handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
42 + Send
43 + Sync
44 + 'static,
45 ) -> Self
46 where
47 Self: Sized,
48 {
49 self.stateless_interactivity()
50 .mouse_up_listeners
51 .push(Arc::new(move |view, event, bounds, phase, cx| {
52 if phase == DispatchPhase::Bubble
53 && event.button == button
54 && bounds.contains_point(&event.position)
55 {
56 handler(view, event, cx)
57 }
58 }));
59 self
60 }
61
62 fn on_mouse_down_out(
63 mut self,
64 button: MouseButton,
65 handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
66 + Send
67 + Sync
68 + 'static,
69 ) -> Self
70 where
71 Self: Sized,
72 {
73 self.stateless_interactivity()
74 .mouse_down_listeners
75 .push(Arc::new(move |view, event, bounds, phase, cx| {
76 if phase == DispatchPhase::Capture
77 && event.button == button
78 && !bounds.contains_point(&event.position)
79 {
80 handler(view, event, cx)
81 }
82 }));
83 self
84 }
85
86 fn on_mouse_up_out(
87 mut self,
88 button: MouseButton,
89 handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
90 + Send
91 + Sync
92 + 'static,
93 ) -> Self
94 where
95 Self: Sized,
96 {
97 self.stateless_interactivity()
98 .mouse_up_listeners
99 .push(Arc::new(move |view, event, bounds, phase, cx| {
100 if phase == DispatchPhase::Capture
101 && event.button == button
102 && !bounds.contains_point(&event.position)
103 {
104 handler(view, event, cx);
105 }
106 }));
107 self
108 }
109
110 fn on_mouse_move(
111 mut self,
112 handler: impl Fn(&mut Self::ViewState, &MouseMoveEvent, &mut ViewContext<Self::ViewState>)
113 + Send
114 + Sync
115 + 'static,
116 ) -> Self
117 where
118 Self: Sized,
119 {
120 self.stateless_interactivity()
121 .mouse_move_listeners
122 .push(Arc::new(move |view, event, bounds, phase, cx| {
123 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
124 handler(view, event, cx);
125 }
126 }));
127 self
128 }
129
130 fn on_scroll_wheel(
131 mut self,
132 handler: impl Fn(&mut Self::ViewState, &ScrollWheelEvent, &mut ViewContext<Self::ViewState>)
133 + Send
134 + Sync
135 + 'static,
136 ) -> Self
137 where
138 Self: Sized,
139 {
140 self.stateless_interactivity()
141 .scroll_wheel_listeners
142 .push(Arc::new(move |view, event, bounds, phase, cx| {
143 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
144 handler(view, event, cx);
145 }
146 }));
147 self
148 }
149
150 fn on_key_down(
151 mut self,
152 listener: impl Fn(
153 &mut Self::ViewState,
154 &KeyDownEvent,
155 DispatchPhase,
156 &mut ViewContext<Self::ViewState>,
157 ) + Send
158 + Sync
159 + 'static,
160 ) -> Self
161 where
162 Self: Sized,
163 {
164 self.stateless_interactivity().key_listeners.push((
165 TypeId::of::<KeyDownEvent>(),
166 Arc::new(move |view, event, _, phase, cx| {
167 let event = event.downcast_ref().unwrap();
168 listener(view, event, phase, cx);
169 None
170 }),
171 ));
172 self
173 }
174
175 fn on_key_up(
176 mut self,
177 listener: impl Fn(&mut Self::ViewState, &KeyUpEvent, DispatchPhase, &mut ViewContext<Self::ViewState>)
178 + Send
179 + Sync
180 + 'static,
181 ) -> Self
182 where
183 Self: Sized,
184 {
185 self.stateless_interactivity().key_listeners.push((
186 TypeId::of::<KeyUpEvent>(),
187 Arc::new(move |view, event, _, phase, cx| {
188 let event = event.downcast_ref().unwrap();
189 listener(view, event, phase, cx);
190 None
191 }),
192 ));
193 self
194 }
195
196 fn on_action<A: 'static>(
197 mut self,
198 listener: impl Fn(&mut Self::ViewState, &A, DispatchPhase, &mut ViewContext<Self::ViewState>)
199 + Send
200 + Sync
201 + 'static,
202 ) -> Self
203 where
204 Self: Sized,
205 {
206 self.stateless_interactivity().key_listeners.push((
207 TypeId::of::<A>(),
208 Arc::new(move |view, event, _, phase, cx| {
209 let event = event.downcast_ref().unwrap();
210 listener(view, event, phase, cx);
211 None
212 }),
213 ));
214 self
215 }
216}
217
218pub trait StatefullyInteractive: StatelesslyInteractive {
219 fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState>;
220
221 fn on_click(
222 mut self,
223 handler: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
224 + Send
225 + Sync
226 + 'static,
227 ) -> Self
228 where
229 Self: Sized,
230 {
231 self.stateful_interactivity()
232 .mouse_click_listeners
233 .push(Arc::new(move |view, event, cx| handler(view, event, cx)));
234 self
235 }
236}
237
238#[derive(Clone, Debug, Eq, PartialEq)]
239pub struct KeyDownEvent {
240 pub keystroke: Keystroke,
241 pub is_held: bool,
242}
243
244#[derive(Clone, Debug)]
245pub struct KeyUpEvent {
246 pub keystroke: Keystroke,
247}
248
249#[derive(Clone, Debug, Default)]
250pub struct ModifiersChangedEvent {
251 pub modifiers: Modifiers,
252}
253
254impl Deref for ModifiersChangedEvent {
255 type Target = Modifiers;
256
257 fn deref(&self) -> &Self::Target {
258 &self.modifiers
259 }
260}
261
262/// The phase of a touch motion event.
263/// Based on the winit enum of the same name.
264#[derive(Clone, Copy, Debug)]
265pub enum TouchPhase {
266 Started,
267 Moved,
268 Ended,
269}
270
271#[derive(Clone, Debug, Default)]
272pub struct MouseDownEvent {
273 pub button: MouseButton,
274 pub position: Point<Pixels>,
275 pub modifiers: Modifiers,
276 pub click_count: usize,
277}
278
279#[derive(Clone, Debug, Default)]
280pub struct MouseUpEvent {
281 pub button: MouseButton,
282 pub position: Point<Pixels>,
283 pub modifiers: Modifiers,
284 pub click_count: usize,
285}
286
287#[derive(Clone, Debug, Default)]
288pub struct MouseClickEvent {
289 pub down: MouseDownEvent,
290 pub up: MouseUpEvent,
291}
292
293#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
294pub enum MouseButton {
295 Left,
296 Right,
297 Middle,
298 Navigate(NavigationDirection),
299}
300
301impl MouseButton {
302 pub fn all() -> Vec<Self> {
303 vec![
304 MouseButton::Left,
305 MouseButton::Right,
306 MouseButton::Middle,
307 MouseButton::Navigate(NavigationDirection::Back),
308 MouseButton::Navigate(NavigationDirection::Forward),
309 ]
310 }
311}
312
313impl Default for MouseButton {
314 fn default() -> Self {
315 Self::Left
316 }
317}
318
319#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
320pub enum NavigationDirection {
321 Back,
322 Forward,
323}
324
325impl Default for NavigationDirection {
326 fn default() -> Self {
327 Self::Back
328 }
329}
330
331#[derive(Clone, Debug, Default)]
332pub struct MouseMoveEvent {
333 pub position: Point<Pixels>,
334 pub pressed_button: Option<MouseButton>,
335 pub modifiers: Modifiers,
336}
337
338#[derive(Clone, Debug)]
339pub struct ScrollWheelEvent {
340 pub position: Point<Pixels>,
341 pub delta: ScrollDelta,
342 pub modifiers: Modifiers,
343 pub touch_phase: TouchPhase,
344}
345
346impl Deref for ScrollWheelEvent {
347 type Target = Modifiers;
348
349 fn deref(&self) -> &Self::Target {
350 &self.modifiers
351 }
352}
353
354#[derive(Clone, Copy, Debug)]
355pub enum ScrollDelta {
356 Pixels(Point<Pixels>),
357 Lines(Point<f32>),
358}
359
360impl Default for ScrollDelta {
361 fn default() -> Self {
362 Self::Lines(Default::default())
363 }
364}
365
366impl ScrollDelta {
367 pub fn precise(&self) -> bool {
368 match self {
369 ScrollDelta::Pixels(_) => true,
370 ScrollDelta::Lines(_) => false,
371 }
372 }
373
374 pub fn pixel_delta(&self, line_height: Pixels) -> Point<Pixels> {
375 match self {
376 ScrollDelta::Pixels(delta) => *delta,
377 ScrollDelta::Lines(delta) => point(line_height * delta.x, line_height * delta.y),
378 }
379 }
380}
381
382#[derive(Clone, Debug, Default)]
383pub struct MouseExitEvent {
384 pub position: Point<Pixels>,
385 pub pressed_button: Option<MouseButton>,
386 pub modifiers: Modifiers,
387}
388
389impl Deref for MouseExitEvent {
390 type Target = Modifiers;
391
392 fn deref(&self) -> &Self::Target {
393 &self.modifiers
394 }
395}
396
397#[derive(Clone, Debug)]
398pub enum InputEvent {
399 KeyDown(KeyDownEvent),
400 KeyUp(KeyUpEvent),
401 ModifiersChanged(ModifiersChangedEvent),
402 MouseDown(MouseDownEvent),
403 MouseUp(MouseUpEvent),
404 MouseMoved(MouseMoveEvent),
405 MouseExited(MouseExitEvent),
406 ScrollWheel(ScrollWheelEvent),
407}
408
409impl InputEvent {
410 pub fn position(&self) -> Option<Point<Pixels>> {
411 match self {
412 InputEvent::KeyDown { .. } => None,
413 InputEvent::KeyUp { .. } => None,
414 InputEvent::ModifiersChanged { .. } => None,
415 InputEvent::MouseDown(event) => Some(event.position),
416 InputEvent::MouseUp(event) => Some(event.position),
417 InputEvent::MouseMoved(event) => Some(event.position),
418 InputEvent::MouseExited(event) => Some(event.position),
419 InputEvent::ScrollWheel(event) => Some(event.position),
420 }
421 }
422
423 pub fn mouse_event<'a>(&'a self) -> Option<&'a dyn Any> {
424 match self {
425 InputEvent::KeyDown { .. } => None,
426 InputEvent::KeyUp { .. } => None,
427 InputEvent::ModifiersChanged { .. } => None,
428 InputEvent::MouseDown(event) => Some(event),
429 InputEvent::MouseUp(event) => Some(event),
430 InputEvent::MouseMoved(event) => Some(event),
431 InputEvent::MouseExited(event) => Some(event),
432 InputEvent::ScrollWheel(event) => Some(event),
433 }
434 }
435
436 pub fn keyboard_event<'a>(&'a self) -> Option<&'a dyn Any> {
437 match self {
438 InputEvent::KeyDown(event) => Some(event),
439 InputEvent::KeyUp(event) => Some(event),
440 InputEvent::ModifiersChanged(event) => Some(event),
441 InputEvent::MouseDown(_) => None,
442 InputEvent::MouseUp(_) => None,
443 InputEvent::MouseMoved(_) => None,
444 InputEvent::MouseExited(_) => None,
445 InputEvent::ScrollWheel(_) => None,
446 }
447 }
448}
449
450pub struct FocusEvent {
451 pub blurred: Option<FocusHandle>,
452 pub focused: Option<FocusHandle>,
453}
454
455pub type MouseDownListener<V> = Arc<
456 dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
457 + Send
458 + Sync
459 + 'static,
460>;
461pub type MouseUpListener<V> = Arc<
462 dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
463 + Send
464 + Sync
465 + 'static,
466>;
467pub type MouseClickListener<V> =
468 Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
469
470pub type MouseMoveListener<V> = Arc<
471 dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
472 + Send
473 + Sync
474 + 'static,
475>;
476
477pub type ScrollWheelListener<V> = Arc<
478 dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
479 + Send
480 + Sync
481 + 'static,
482>;
483
484pub type KeyListener<V> = Arc<
485 dyn Fn(
486 &mut V,
487 &dyn Any,
488 &[&DispatchContext],
489 DispatchPhase,
490 &mut ViewContext<V>,
491 ) -> Option<Box<dyn Action>>
492 + Send
493 + Sync
494 + 'static,
495>;