1use crate::*;
2use std::any::Any;
3
4#[derive(Clone, Copy, Eq, PartialEq)]
5pub enum GestureState {
6 Began,
7 Changed,
8 Ended,
9}
10
11pub struct Drag<V, F> {
13 child: V,
14 func: F,
15 grab: bool,
16}
17
18impl<V, F, A> Drag<V, F>
19where
20 V: View,
21 F: Fn(&mut Context, LocalOffset, GestureState, Option<MouseButton>) -> A + 'static,
22{
23 pub fn new(v: V, f: F) -> Self {
24 Self {
25 child: v,
26 func: f,
27 grab: false,
28 }
29 }
30
31 pub fn grab_cursor(self) -> Self {
32 Self {
33 child: self.child,
34 func: self.func,
35 grab: true,
36 }
37 }
38}
39
40impl<V, F, A> View for Drag<V, F>
41where
42 V: View,
43 F: Fn(&mut Context, LocalOffset, GestureState, Option<MouseButton>) -> A + 'static,
44 A: 'static,
45{
46 fn process(
47 &self,
48 event: &Event,
49 vid: ViewId,
50 cx: &mut Context,
51 actions: &mut Vec<Box<dyn Any>>,
52 ) {
53 match &event {
54 Event::TouchBegin { id, position } => {
55 if self.hittest(vid, *position, cx).is_some() {
56 cx.touches[*id] = vid;
57 cx.starts[*id] = *position;
58 cx.previous_position[*id] = *position;
59 cx.grab_cursor = self.grab;
60 }
61 }
62 Event::TouchMove {
63 id,
64 position,
65 delta,
66 } => {
67 if cx.touches[*id] == vid {
68 actions.push(Box::new((self.func)(
69 cx,
70 *delta,
71 GestureState::Changed,
72 cx.mouse_button,
73 )));
74 cx.previous_position[*id] = *position;
75 }
76 }
77 Event::TouchEnd { id, .. } => {
78 if cx.touches[*id] == vid {
79 cx.touches[*id] = ViewId::default();
80 cx.grab_cursor = false;
81 actions.push(Box::new((self.func)(
82 cx,
83 LocalOffset::zero(),
84 GestureState::Ended,
85 cx.mouse_button,
86 )));
87 }
88 }
89 _ => (),
90 }
91 }
92
93 fn draw(&self, id: ViewId, args: &mut DrawArgs) {
94 self.child.draw(id.child(&0), args)
95 }
96
97 fn layout(&self, id: ViewId, args: &mut LayoutArgs) -> LocalSize {
98 self.child.layout(id.child(&0), args)
99 }
100
101 fn dirty(&self, id: ViewId, xform: LocalToWorld, cx: &mut Context) {
102 self.child.dirty(id.child(&0), xform, cx);
103 }
104
105 fn hittest(&self, id: ViewId, pt: LocalPoint, cx: &mut Context) -> Option<ViewId> {
106 self.child.hittest(id.child(&0), pt, cx)
107 }
108
109 fn commands(&self, id: ViewId, cx: &mut Context, cmds: &mut Vec<CommandInfo>) {
110 self.child.commands(id.child(&0), cx, cmds)
111 }
112
113 fn gc(&self, id: ViewId, cx: &mut Context, map: &mut Vec<ViewId>) {
114 self.child.gc(id.child(&0), cx, map)
115 }
116
117 fn access(
118 &self,
119 id: ViewId,
120 cx: &mut Context,
121 nodes: &mut Vec<(accesskit::NodeId, accesskit::Node)>,
122 ) -> Option<accesskit::NodeId> {
123 self.child.access(id.child(&0), cx, nodes)
124 }
125}
126
127impl<V, F> private::Sealed for Drag<V, F> {}
128
129pub struct DragS<V, F, B, T> {
131 child: V,
132 func: F,
133 binding: B,
134 phantom: std::marker::PhantomData<T>,
135 grab: bool,
136}
137
138impl<V, F, A, B, T> DragS<V, F, B, T>
139where
140 V: View,
141 F: Fn(&mut T, LocalOffset, GestureState, Option<MouseButton>) -> A + 'static,
142 B: Binding<T>,
143 A: 'static,
144 T: 'static,
145{
146 pub fn new(v: V, b: B, f: F) -> Self {
147 Self {
148 child: v,
149 func: f,
150 binding: b,
151 phantom: std::marker::PhantomData::default(),
152 grab: false,
153 }
154 }
155
156 pub fn grab_cursor(self) -> Self {
157 Self {
158 child: self.child,
159 func: self.func,
160 binding: self.binding,
161 phantom: std::marker::PhantomData::default(),
162 grab: true,
163 }
164 }
165}
166
167impl<V, F, A, B, T> View for DragS<V, F, B, T>
168where
169 V: View,
170 F: Fn(&mut T, LocalOffset, GestureState, Option<MouseButton>) -> A + 'static,
171 B: Binding<T>,
172 A: 'static,
173 T: 'static,
174{
175 fn process(
176 &self,
177 event: &Event,
178 vid: ViewId,
179 cx: &mut Context,
180 actions: &mut Vec<Box<dyn Any>>,
181 ) {
182 match &event {
183 Event::TouchBegin { id, position } => {
184 if self.hittest(vid, *position, cx).is_some() {
185 cx.touches[*id] = vid;
186 cx.starts[*id] = *position;
187 cx.previous_position[*id] = *position;
188 cx.grab_cursor = self.grab;
189 }
190 }
191 Event::TouchMove {
192 id,
193 position,
194 delta,
195 } => {
196 if cx.touches[*id] == vid {
197 let button = cx.mouse_button;
198 actions.push(Box::new((self.func)(
199 self.binding.get_mut(cx),
200 *delta,
201 GestureState::Changed,
202 button,
203 )));
204 cx.previous_position[*id] = *position;
205 }
206 }
207 Event::TouchEnd { id, .. } => {
208 if cx.touches[*id] == vid {
209 cx.touches[*id] = ViewId::default();
210 cx.grab_cursor = false;
211 let button = cx.mouse_button;
212 actions.push(Box::new((self.func)(
213 self.binding.get_mut(cx),
214 LocalOffset::zero(),
215 GestureState::Ended,
216 button,
217 )));
218 }
219 }
220 _ => self.child.process(event, vid.child(&0), cx, actions),
221 }
222 }
223
224 fn draw(&self, id: ViewId, args: &mut DrawArgs) {
225 self.child.draw(id.child(&0), args)
226 }
227
228 fn layout(&self, id: ViewId, args: &mut LayoutArgs) -> LocalSize {
229 self.child.layout(id.child(&0), args)
230 }
231
232 fn dirty(&self, id: ViewId, xform: LocalToWorld, cx: &mut Context) {
233 self.child.dirty(id.child(&0), xform, cx);
234 }
235
236 fn hittest(&self, id: ViewId, pt: LocalPoint, cx: &mut Context) -> Option<ViewId> {
237 self.child.hittest(id.child(&0), pt, cx)
238 }
239
240 fn commands(&self, id: ViewId, cx: &mut Context, cmds: &mut Vec<CommandInfo>) {
241 self.child.commands(id.child(&0), cx, cmds)
242 }
243
244 fn gc(&self, id: ViewId, cx: &mut Context, map: &mut Vec<ViewId>) {
245 self.child.gc(id.child(&0), cx, map)
246 }
247
248 fn access(
249 &self,
250 id: ViewId,
251 cx: &mut Context,
252 nodes: &mut Vec<(accesskit::NodeId, accesskit::Node)>,
253 ) -> Option<accesskit::NodeId> {
254 self.child.access(id.child(&0), cx, nodes)
255 }
256}
257
258impl<V, F, B, T> private::Sealed for DragS<V, F, B, T> {}