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::ViewContext;
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(move |view, event, cx| {
25 if event.button == button {
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 V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
36 ) -> Self
37 where
38 Self: Sized,
39 {
40 self.interaction_handlers()
41 .mouse_up
42 .push(Rc::new(move |view, event, cx| {
43 if event.button == button {
44 handler(view, event, cx)
45 }
46 }));
47 self
48 }
49
50 fn on_mouse_down_out(
51 mut self,
52 button: MouseButton,
53 handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
54 ) -> Self
55 where
56 Self: Sized,
57 {
58 self.interaction_handlers()
59 .mouse_down_out
60 .push(Rc::new(move |view, event, cx| {
61 if event.button == button {
62 handler(view, event, cx)
63 }
64 }));
65 self
66 }
67
68 fn on_mouse_up_out(
69 mut self,
70 button: MouseButton,
71 handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
72 ) -> Self
73 where
74 Self: Sized,
75 {
76 self.interaction_handlers()
77 .mouse_up_out
78 .push(Rc::new(move |view, event, cx| {
79 if event.button == button {
80 handler(view, event, cx)
81 }
82 }));
83 self
84 }
85
86 fn on_click(
87 self,
88 button: MouseButton,
89 handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
90 ) -> Self
91 where
92 Self: Sized,
93 {
94 let pressed = Rc::new(Cell::new(false));
95 self.on_mouse_down(button, {
96 let pressed = pressed.clone();
97 move |_, _, _| {
98 pressed.set(true);
99 }
100 })
101 .on_mouse_up_out(button, {
102 let pressed = pressed.clone();
103 move |_, _, _| {
104 pressed.set(false);
105 }
106 })
107 .on_mouse_up(button, move |view, event, cx| {
108 if pressed.get() {
109 pressed.set(false);
110 handler(view, event, cx);
111 }
112 })
113 }
114}
115
116pub struct InteractionHandlers<V: 'static> {
117 mouse_down: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
118 mouse_down_out: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
119 mouse_up: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
120 mouse_up_out: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
121}
122
123impl<V: 'static> InteractionHandlers<V> {
124 pub fn paint(&self, order: u32, bounds: RectF, cx: &mut ViewContext<V>) {
125 for handler in self.mouse_down.iter().cloned() {
126 cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
127 if event.is_down && bounds.contains_point(event.position) {
128 handler(view, event, cx);
129 }
130 })
131 }
132 for handler in self.mouse_up.iter().cloned() {
133 cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
134 if !event.is_down && bounds.contains_point(event.position) {
135 handler(view, event, cx);
136 }
137 })
138 }
139 for handler in self.mouse_down_out.iter().cloned() {
140 cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
141 if event.is_down && !bounds.contains_point(event.position) {
142 handler(view, event, cx);
143 }
144 })
145 }
146 for handler in self.mouse_up_out.iter().cloned() {
147 cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
148 if !event.is_down && !bounds.contains_point(event.position) {
149 handler(view, event, cx);
150 }
151 })
152 }
153 }
154}
155
156impl<V> Default for InteractionHandlers<V> {
157 fn default() -> Self {
158 Self {
159 mouse_down: Default::default(),
160 mouse_up: Default::default(),
161 mouse_down_out: Default::default(),
162 mouse_up_out: Default::default(),
163 }
164 }
165}