Merge "Add stride to PixelData" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / events / tap-gesture / tap-gesture-recognizer.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/events/tap-gesture/tap-gesture-recognizer.h>
20
21 // EXTERNAL INCLUDES
22 #include <cmath>
23
24 #include <dali/public-api/math/vector2.h>
25
26 #include <dali/integration-api/events/touch-event-integ.h>
27
28 // INTERNAL INCLUDES
29 #include <dali/internal/event/common/scene-impl.h>
30 #include <dali/internal/event/events/gesture-requests.h>
31
32 namespace Dali
33 {
34 namespace Internal
35 {
36 namespace
37 {
38 // TODO: Set these according to DPI
39 constexpr float MAXIMUM_MOTION_ALLOWED = 20.0f;
40 } // unnamed namespace
41
42 TapGestureRecognizer::TapGestureRecognizer(Observer& observer, Vector2 screenSize, const TapGestureRequest& request, uint32_t maximumAllowedTime)
43 : GestureRecognizer(screenSize, GestureType::TAP),
44   mObserver(observer),
45   mState(CLEAR),
46   mMinimumTapsRequired(request.minTaps),
47   mMaximumTapsRequired(request.maxTaps),
48   mTapsRegistered(0),
49   mTouchPosition(),
50   mTouchTime(0u),
51   mLastTapTime(0u),
52   mGestureSourceType(GestureSourceType::INVALID),
53   mMaximumAllowedTime(maximumAllowedTime)
54 {
55 }
56
57 TapGestureRecognizer::~TapGestureRecognizer() = default;
58
59 void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
60 {
61   GestureRecognizerPtr ptr(this); // To keep us from being destroyed during the life-time of this method
62
63   if(event.GetPointCount() == 1)
64   {
65     const Integration::Point& point      = event.points[0];
66     PointState::Type          pointState = point.GetState();
67
68     MouseButton::Type mouseButton = point.GetMouseButton();
69     switch(mouseButton)
70     {
71       case MouseButton::INVALID:
72       {
73         mGestureSourceType = GestureSourceType::INVALID;
74         break;
75       }
76       case MouseButton::PRIMARY:
77       {
78         mGestureSourceType = GestureSourceType::PRIMARY;
79         break;
80       }
81       case MouseButton::SECONDARY:
82       {
83         mGestureSourceType = GestureSourceType::SECONDARY;
84         break;
85       }
86       case MouseButton::TERTIARY:
87       {
88         mGestureSourceType = GestureSourceType::TERTIARY;
89         break;
90       }
91       default:
92       {
93         mGestureSourceType = GestureSourceType::INVALID;
94         break;
95       }
96     }
97
98     switch(mState)
99     {
100       case CLEAR:
101       {
102         if(pointState == PointState::DOWN)
103         {
104           SetupForTouchDown(event, point);
105         }
106         break;
107       }
108
109       case TOUCHED:
110       {
111         uint32_t deltaBetweenTouchDownTouchUp = event.time - mTouchTime;
112
113         if(pointState == PointState::UP)
114         {
115           if(deltaBetweenTouchDownTouchUp < mMaximumAllowedTime)
116           {
117             mLastTapTime = mTouchTime;
118             EmitSingleTap(event.time, point);
119             mState = REGISTERED;
120           }
121           else
122           {
123             mState = CLEAR;
124           }
125         }
126         else if(pointState == PointState::INTERRUPTED)
127         {
128           mState = CLEAR;
129         }
130         break;
131       }
132
133       case REGISTERED:
134       {
135         if(pointState == PointState::UP)
136         {
137           // This is a possible multiple tap, so has it been quick enough?
138           uint32_t timeDelta                    = event.time - mLastTapTime;
139           uint32_t deltaBetweenTouchDownTouchUp = event.time - mTouchTime;
140           if(timeDelta > mMaximumAllowedTime || // If exceeded time between taps then just a single tap
141              mMaximumTapsRequired == 1u)        // If MaximumTapsRequired is 1, it is not waiting for a multi-tap, so a Tap gesture send a single tap.
142           {
143             mLastTapTime = event.time;
144             EmitSingleTap(event.time, point);
145           }
146           else if(deltaBetweenTouchDownTouchUp < mMaximumAllowedTime)
147           {
148             ++mTapsRegistered;
149             EmitGesture(GestureState::STARTED, event.time);
150           }
151           else // Delta between touch down and touch up too long to be considered a TAP event
152           {
153             mState = CLEAR;
154           }
155         }
156         else if(pointState == PointState::DOWN)
157         {
158           const Vector2& screen(point.GetScreenPosition());
159           Vector2        distanceDelta(std::abs(mTouchPosition.x - screen.x),
160                                 std::abs(mTouchPosition.y - screen.y));
161
162           uint32_t timeDelta = event.time - mLastTapTime;
163
164           if(distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
165              distanceDelta.y > MAXIMUM_MOTION_ALLOWED ||
166              timeDelta > mMaximumAllowedTime)
167           {
168             SetupForTouchDown(event, point);
169           }
170           else
171           {
172             EmitPossibleState(event);
173           }
174         }
175         break;
176       }
177
178       case FAILED:
179       default:
180       {
181         mState = CLEAR;
182         break;
183       }
184     }
185   }
186   else
187   {
188     mState = FAILED;
189
190     // We have entered a multi-touch event so emit registered gestures if required.
191     EmitGesture(GestureState::STARTED, event.time);
192   }
193 }
194
195 void TapGestureRecognizer::SetupForTouchDown(const Integration::TouchEvent& event, const Integration::Point& point)
196 {
197   mTouchPosition  = point.GetScreenPosition();
198   mTouchTime      = event.time;
199   mLastTapTime    = 0u;
200   mTapsRegistered = 0;
201   mState          = TOUCHED;
202
203   EmitPossibleState(event);
204 }
205
206 void TapGestureRecognizer::EmitPossibleState(const Integration::TouchEvent& event)
207 {
208   TapGestureEvent tapEvent(GestureState::POSSIBLE);
209   tapEvent.point             = mTouchPosition;
210   tapEvent.time              = event.time;
211   tapEvent.gestureSourceType = mGestureSourceType;
212
213   ProcessEvent(tapEvent);
214 }
215
216 void TapGestureRecognizer::Update(const GestureRequest& request)
217 {
218   const TapGestureRequest& tap = static_cast<const TapGestureRequest&>(request);
219
220   mMinimumTapsRequired = tap.minTaps;
221   mMaximumTapsRequired = tap.maxTaps;
222 }
223
224 void TapGestureRecognizer::SetMaximumAllowedTime(uint32_t time)
225 {
226   mMaximumAllowedTime = time;
227 }
228
229 void TapGestureRecognizer::EmitGesture(GestureState state, uint32_t time)
230 {
231   if((state == GestureState::CANCELLED) ||
232      (mTapsRegistered >= mMinimumTapsRequired && mTapsRegistered <= mMaximumTapsRequired))
233
234   {
235     TapGestureEvent event(state);
236     EmitTap(time, event);
237   }
238 }
239
240 void TapGestureRecognizer::EmitSingleTap(uint32_t time, const Integration::Point& point)
241 {
242   TapGestureEvent event(GestureState::STARTED);
243   const Vector2&  screen(point.GetScreenPosition());
244   Vector2         distanceDelta(std::abs(mTouchPosition.x - screen.x),
245                         std::abs(mTouchPosition.y - screen.y));
246
247   if(distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
248      distanceDelta.y > MAXIMUM_MOTION_ALLOWED)
249   {
250     event.state = GestureState::CANCELLED;
251   }
252   mTapsRegistered = 1u;
253   EmitTap(time, event);
254 }
255
256 void TapGestureRecognizer::EmitTap(uint32_t time, TapGestureEvent& event)
257 {
258   event.numberOfTaps      = mTapsRegistered;
259   event.point             = mTouchPosition;
260   event.time              = time;
261   event.gestureSourceType = mGestureSourceType;
262
263   ProcessEvent(event);
264 }
265
266 void TapGestureRecognizer::ProcessEvent(TapGestureEvent& event)
267 {
268   if(mScene)
269   {
270     // Create another handle so the recognizer cannot be destroyed during process function
271     GestureRecognizerPtr recognizerHandle = this;
272     mObserver.Process(*mScene, event);
273   }
274 }
275
276 } // namespace Internal
277
278 } // namespace Dali