Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
gesture.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <functional>
6#include <memory>
7#include <unordered_map>
8#include <vector>
9
10namespace pulp::view {
11
12class View;
13
22
27
29public:
30 using Callback = std::function<void(GestureRecognizer&)>;
31
32 virtual ~GestureRecognizer() = default;
33
34 GestureState state() const { return state_; }
35 View* owner() const { return owner_; }
36
39
40 bool requires_failure_of(const GestureRecognizer& other) const;
42
47
48protected:
49 friend class View;
50 friend class GestureArbiter;
51
52 virtual void on_pointer_event(const MouseEvent& event,
53 const GestureContext& context) = 0;
54 virtual void on_time_advanced(const GestureContext& context) {
55 (void)context;
56 }
57 virtual void on_reset() {}
58 virtual bool keep_possible_after_release() const { return false; }
59 virtual bool wants_time_updates() const { return false; }
60
63 void fail();
64 void cancel();
65
66private:
67 void set_owner(View* owner) { owner_ = owner; }
68 bool has_pending_callbacks() const { return !pending_callbacks_.empty(); }
69 void clear_pending_callbacks() { pending_callbacks_.clear(); }
70 void remove_relationships_to(const GestureRecognizer& other) noexcept;
71 void dispatch_pending_callbacks();
72
73 View* owner_ = nullptr;
75 std::vector<GestureRecognizer*> require_failures_;
76 std::vector<GestureRecognizer*> simultaneous_;
77 std::vector<GestureState> pending_callbacks_;
78};
79
80class TapRecognizer final : public GestureRecognizer {
81public:
83
84 int required_tap_count() const { return required_tap_count_; }
85 Point position() const { return last_position_; }
86 void set_required_tap_count(int count);
87 void set_max_movement(float points) { max_movement_ = points; }
88 void set_max_press_duration(double seconds) { max_press_duration_ = seconds; }
89 void set_max_interval(double seconds) { max_interval_ = seconds; }
90
91protected:
92 void on_pointer_event(const MouseEvent& event,
93 const GestureContext& context) override;
94 void on_reset() override;
95 bool keep_possible_after_release() const override;
96
97private:
98 int required_tap_count_ = 1;
99 int tap_count_ = 0;
100 int pointer_id_ = 0;
101 bool pressed_ = false;
102 Point press_position_{};
103 Point last_position_{};
104 double press_time_ = 0.0;
105 double previous_release_time_ = -1.0;
106 float max_movement_ = 8.0f;
107 double max_press_duration_ = 0.35;
108 double max_interval_ = 0.30;
109};
110
112public:
113 Point position() const { return press_position_; }
114 void set_min_duration(double seconds) { min_duration_ = seconds; }
115 void set_max_movement(float points) { max_movement_ = points; }
116
117protected:
118 void on_pointer_event(const MouseEvent& event,
119 const GestureContext& context) override;
120 void on_time_advanced(const GestureContext& context) override;
121 void on_reset() override;
122 bool wants_time_updates() const override;
123
124private:
125 void maybe_begin(double timestamp_seconds);
126
127 int pointer_id_ = 0;
128 bool pressed_ = false;
129 Point press_position_{};
130 double press_time_ = 0.0;
131 float max_movement_ = 8.0f;
132 double min_duration_ = 0.50;
133};
134
135class PanRecognizer final : public GestureRecognizer {
136public:
137 void set_min_distance(float points) { min_distance_ = points; }
138
139 Point translation() const { return translation_; }
140 Point velocity() const { return velocity_; }
141
142protected:
143 void on_pointer_event(const MouseEvent& event,
144 const GestureContext& context) override;
145 void on_reset() override;
146
147private:
148 int pointer_id_ = 0;
149 bool pressed_ = false;
150 Point start_position_{};
151 Point last_position_{};
152 double last_time_ = 0.0;
153 Point translation_{};
154 Point velocity_{};
155 float min_distance_ = 5.0f;
156};
157
158class SwipeRecognizer final : public GestureRecognizer {
159public:
160 void set_min_distance(float points) { min_distance_ = points; }
161 void set_min_velocity(float points_per_second) { min_velocity_ = points_per_second; }
162
163 Point translation() const { return translation_; }
164 Point velocity() const { return velocity_; }
165
166protected:
167 void on_pointer_event(const MouseEvent& event,
168 const GestureContext& context) override;
169 void on_reset() override;
170
171private:
172 int pointer_id_ = 0;
173 bool pressed_ = false;
174 Point start_position_{};
175 Point last_position_{};
176 double start_time_ = 0.0;
177 double last_time_ = 0.0;
178 Point translation_{};
179 Point velocity_{};
180 float min_distance_ = 30.0f;
181 float min_velocity_ = 300.0f;
182};
183
184class FlingRecognizer final : public GestureRecognizer {
185public:
186 void set_min_velocity(float points_per_second) { min_velocity_ = points_per_second; }
187 void set_max_duration(double seconds) { max_duration_ = seconds; }
188
189 Point translation() const { return translation_; }
190 Point velocity() const { return velocity_; }
191
192protected:
193 void on_pointer_event(const MouseEvent& event,
194 const GestureContext& context) override;
195 void on_reset() override;
196
197private:
198 int pointer_id_ = 0;
199 bool pressed_ = false;
200 Point start_position_{};
201 Point last_position_{};
202 double start_time_ = 0.0;
203 double last_time_ = 0.0;
204 Point translation_{};
205 Point velocity_{};
206 float min_velocity_ = 800.0f;
207 double max_duration_ = 0.50;
208};
209
210class PinchRecognizer final : public GestureRecognizer {
211public:
212 void set_min_scale_delta(float delta) { min_scale_delta_ = delta; }
213
214 float scale() const { return scale_; }
215 float delta_scale() const { return delta_scale_; }
216 Point center() const { return center_; }
217
218protected:
219 void on_pointer_event(const MouseEvent& event,
220 const GestureContext& context) override;
221 void on_reset() override;
222
223private:
224 struct Touch {
225 Point start{};
226 Point current{};
227 };
228
229 bool pair_metrics(float* distance, Point* center) const;
230 void finish_or_cancel(bool cancelled);
231
232 std::unordered_map<int, Touch> touches_;
233 float initial_distance_ = 0.0f;
234 float last_scale_ = 1.0f;
235 float scale_ = 1.0f;
236 float delta_scale_ = 0.0f;
237 Point center_{};
238 float min_scale_delta_ = 0.025f;
239};
240
242public:
243 void set_min_rotation(float radians) { min_rotation_ = radians; }
244
245 float rotation() const { return rotation_; }
246 float delta_rotation() const { return delta_rotation_; }
247 Point center() const { return center_; }
248
249protected:
250 void on_pointer_event(const MouseEvent& event,
251 const GestureContext& context) override;
252 void on_reset() override;
253
254private:
255 struct Touch {
256 Point start{};
257 Point current{};
258 };
259
260 bool pair_metrics(float* angle, Point* center) const;
261 void finish_or_cancel(bool cancelled);
262
263 std::unordered_map<int, Touch> touches_;
264 float initial_angle_ = 0.0f;
265 float last_rotation_ = 0.0f;
266 float rotation_ = 0.0f;
267 float delta_rotation_ = 0.0f;
268 Point center_{};
269 float min_rotation_ = 0.035f;
270};
271
273public:
277 bool claimed_pointer() const { return claimed_pointer_; }
278
279 bool handle_pointer_event(View& root, const MouseEvent& root_event,
280 double timestamp_seconds = -1.0);
281 void advance_time(View& root, double timestamp_seconds = -1.0);
282 bool wants_time_updates() const;
283 void reset();
286 void abandon() noexcept;
287
288private:
289 bool claimed_pointer_ = false;
290
291 struct Candidate {
292 GestureRecognizer* recognizer = nullptr;
293 View* owner = nullptr;
294 bool active = false;
295 };
296
297 struct PointerSession {
298 int pointer_id = 0;
299 std::vector<Candidate> candidates;
300 };
301
302 // Sessions are held by shared_ptr, not by value. A recognizer callback can
303 // re-enter pointer dispatch and erase the very session the outer frame is
304 // still walking; owning the node keeps that frame's reference valid until
305 // it unwinds, and `pointer_id` lookups tell it the session has gone away.
306 using SessionMap = std::unordered_map<int, std::shared_ptr<PointerSession>>;
307
308 std::shared_ptr<PointerSession> start_session(View& root,
309 const MouseEvent& root_event);
310 bool session_is_live(const PointerSession& session) const;
311 void feed_session(View& root, PointerSession& session,
312 const MouseEvent& root_event,
313 const GestureContext& context);
314 void resolve_session(PointerSession& session, const MouseEvent& root_event);
315 void finish_session_if_needed(PointerSession& session,
316 const MouseEvent& root_event);
317 bool active_recognizers_allow(const PointerSession& session,
318 const Candidate& candidate) const;
319 void fail_conflicting_candidates(const Candidate& active_candidate);
320
321 SessionMap sessions_;
322};
323
324} // namespace pulp::view
Definition gesture.hpp:184
void set_max_duration(double seconds)
Definition gesture.hpp:187
void set_min_velocity(float points_per_second)
Definition gesture.hpp:186
void on_pointer_event(const MouseEvent &event, const GestureContext &context) override
Point translation() const
Definition gesture.hpp:189
Point velocity() const
Definition gesture.hpp:190
Definition gesture.hpp:272
bool claimed_pointer() const
True when a recognizer ACTIVELY claimed the last pointer event, as opposed to merely being a candidat...
Definition gesture.hpp:277
bool handle_pointer_event(View &root, const MouseEvent &root_event, double timestamp_seconds=-1.0)
void abandon() noexcept
Drop active recognition sessions without invoking user callbacks.
void advance_time(View &root, double timestamp_seconds=-1.0)
bool wants_time_updates() const
Definition gesture.hpp:28
friend class View
Definition gesture.hpp:49
Callback on_changed
Definition gesture.hpp:44
Callback on_cancelled
Definition gesture.hpp:46
friend class GestureArbiter
Definition gesture.hpp:50
virtual bool keep_possible_after_release() const
Definition gesture.hpp:58
bool requires_failure_of(const GestureRecognizer &other) const
void require_to_fail(GestureRecognizer &other)
GestureState state() const
Definition gesture.hpp:34
virtual void on_time_advanced(const GestureContext &context)
Definition gesture.hpp:54
Callback on_ended
Definition gesture.hpp:45
View * owner() const
Definition gesture.hpp:35
virtual void on_reset()
Definition gesture.hpp:57
void transition_to(GestureState state)
virtual void on_pointer_event(const MouseEvent &event, const GestureContext &context)=0
virtual bool wants_time_updates() const
Definition gesture.hpp:59
std::function< void(GestureRecognizer &)> Callback
Definition gesture.hpp:30
bool can_recognize_simultaneously_with(const GestureRecognizer &other) const
virtual ~GestureRecognizer()=default
Callback on_began
Definition gesture.hpp:43
void allow_simultaneous_with(GestureRecognizer &other)
Definition gesture.hpp:111
bool wants_time_updates() const override
void set_max_movement(float points)
Definition gesture.hpp:115
void on_pointer_event(const MouseEvent &event, const GestureContext &context) override
void on_time_advanced(const GestureContext &context) override
Point position() const
Definition gesture.hpp:113
void set_min_duration(double seconds)
Definition gesture.hpp:114
Definition gesture.hpp:135
void set_min_distance(float points)
Definition gesture.hpp:137
void on_pointer_event(const MouseEvent &event, const GestureContext &context) override
Point translation() const
Definition gesture.hpp:139
void on_reset() override
Point velocity() const
Definition gesture.hpp:140
Definition gesture.hpp:210
Point center() const
Definition gesture.hpp:216
void set_min_scale_delta(float delta)
Definition gesture.hpp:212
float scale() const
Definition gesture.hpp:214
float delta_scale() const
Definition gesture.hpp:215
void on_pointer_event(const MouseEvent &event, const GestureContext &context) override
Definition gesture.hpp:241
void set_min_rotation(float radians)
Definition gesture.hpp:243
void on_pointer_event(const MouseEvent &event, const GestureContext &context) override
float delta_rotation() const
Definition gesture.hpp:246
float rotation() const
Definition gesture.hpp:245
Point center() const
Definition gesture.hpp:247
Definition gesture.hpp:158
Point translation() const
Definition gesture.hpp:163
void set_min_distance(float points)
Definition gesture.hpp:160
void on_pointer_event(const MouseEvent &event, const GestureContext &context) override
void set_min_velocity(float points_per_second)
Definition gesture.hpp:161
Point velocity() const
Definition gesture.hpp:164
void set_required_tap_count(int count)
Point position() const
Definition gesture.hpp:85
void set_max_press_duration(double seconds)
Definition gesture.hpp:88
bool keep_possible_after_release() const override
int required_tap_count() const
Definition gesture.hpp:84
void set_max_movement(float points)
Definition gesture.hpp:87
TapRecognizer(int required_tap_count=1)
void on_reset() override
void set_max_interval(double seconds)
Definition gesture.hpp:89
void on_pointer_event(const MouseEvent &event, const GestureContext &context) override
Definition view.hpp:73
Input event types with modifier keys and pointer IDs.
Hover-cursor tracking for platform window hosts.
Definition fwd.hpp:27
@ candidate
Definition waveform_editor_primitives.hpp:193
GestureState
Definition gesture.hpp:14
@ failed
Definition gesture.hpp:20
@ cancelled
Definition gesture.hpp:19
@ possible
Definition gesture.hpp:15
@ began
Definition gesture.hpp:16
@ changed
Definition gesture.hpp:17
@ ended
Definition gesture.hpp:18
Definition gesture.hpp:23
double timestamp_seconds
Definition gesture.hpp:24
Point root_position
Definition gesture.hpp:25
Rich mouse/pointer event with position, modifiers, button state, pointer ID, and stylus properties.
Definition input_events.hpp:104
Definition geometry.hpp:20