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