1use gpui::{
2 geometry::rect::RectF,
3 platform::{MouseButton, MouseButtonEvent},
4 EventContext,
5};
6use smallvec::SmallVec;
7use std::{cell::Cell, rc::Rc};
8
9use crate::element::PaintContext;
10
11pub trait Interactive<V: 'static> {
12 fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V>;
13
14 fn on_mouse_down(
15 mut self,
16 button: MouseButton,
17 handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
18 ) -> Self
19 where
20 Self: Sized,
21 {
22 self.interaction_handlers()
23 .mouse_down
24 .push(Rc::new(handler));
25 self
26 }
27
28 fn on_mouse_up(
29 mut self,
30 button: MouseButton,
31 handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
32 ) -> Self
33 where
34 Self: Sized,
35 {
36 self.interaction_handlers().mouse_up.push(Rc::new(handler));
37 self
38 }
39
40 fn on_mouse_down_out(
41 mut self,
42 button: MouseButton,
43 handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
44 ) -> Self
45 where
46 Self: Sized,
47 {
48 self.interaction_handlers()
49 .mouse_down_out
50 .push(Rc::new(handler));
51 self
52 }
53
54 fn on_mouse_up_out(
55 mut self,
56 button: MouseButton,
57 handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
58 ) -> Self
59 where
60 Self: Sized,
61 {
62 self.interaction_handlers()
63 .mouse_up_out
64 .push(Rc::new(handler));
65 self
66 }
67
68 fn on_click(
69 self,
70 button: MouseButton,
71 handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
72 ) -> Self
73 where
74 Self: Sized,
75 {
76 let pressed = Rc::new(Cell::new(false));
77 self.on_mouse_down(button, {
78 let pressed = pressed.clone();
79 move |_, _, _| {
80 pressed.set(true);
81 }
82 })
83 .on_mouse_up_out(button, {
84 let pressed = pressed.clone();
85 move |_, _, _| {
86 pressed.set(false);
87 }
88 })
89 .on_mouse_up(button, move |view, event, cx| {
90 if pressed.get() {
91 pressed.set(false);
92 handler(view, event, cx);
93 }
94 })
95 }
96}
97
98pub struct InteractionHandlers<V: 'static> {
99 mouse_down: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
100 mouse_down_out: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
101 mouse_up: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
102 mouse_up_out: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
103}
104
105impl<V: 'static> InteractionHandlers<V> {
106 pub fn paint(&self, order: u32, bounds: RectF, cx: &mut PaintContext<V>) {
107 for handler in self.mouse_down.iter().cloned() {
108 cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
109 if event.is_down && bounds.contains_point(event.position) {
110 handler(view, event, cx);
111 }
112 })
113 }
114 for handler in self.mouse_up.iter().cloned() {
115 cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
116 if !event.is_down && bounds.contains_point(event.position) {
117 handler(view, event, cx);
118 }
119 })
120 }
121 for handler in self.mouse_down_out.iter().cloned() {
122 cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
123 if event.is_down && !bounds.contains_point(event.position) {
124 handler(view, event, cx);
125 }
126 })
127 }
128 for handler in self.mouse_up_out.iter().cloned() {
129 cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
130 if !event.is_down && !bounds.contains_point(event.position) {
131 handler(view, event, cx);
132 }
133 })
134 }
135 }
136}
137
138impl<V> Default for InteractionHandlers<V> {
139 fn default() -> Self {
140 Self {
141 mouse_down: Default::default(),
142 mouse_up: Default::default(),
143 mouse_down_out: Default::default(),
144 mouse_up_out: Default::default(),
145 }
146 }
147}