rui/views/
drag.rs

1use crate::*;
2use std::any::Any;
3
4#[derive(Clone, Copy, Eq, PartialEq)]
5pub enum GestureState {
6    Began,
7    Changed,
8    Ended,
9}
10
11/// Struct for the `drag` gesture.
12pub 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
129/// Struct for the `drag` gesture.
130pub 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> {}