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