1. Revert "Sets the tap gesture timer to 330ms."
[platform/core/uifw/dali-core.git] / dali / internal / event / events / tap-gesture / tap-gesture-recognizer.cpp
1 /*
2  * Copyright (c) 2021 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 const float         MAXIMUM_MOTION_ALLOWED = 20.0f;
40 const unsigned long MAXIMUM_TIME_ALLOWED   = 500u;
41 } // unnamed namespace
42
43 TapGestureRecognizer::TapGestureRecognizer(Observer& observer, Vector2 screenSize, const TapGestureRequest& request)
44 : GestureRecognizer(screenSize, GestureType::TAP),
45   mObserver(observer),
46   mState(CLEAR),
47   mMinimumTapsRequired(request.minTaps),
48   mMaximumTapsRequired(request.maxTaps),
49   mTapsRegistered(0),
50   mTouchPosition(),
51   mTouchTime(0u),
52   mLastTapTime(0u),
53   mGestureSourceType(GestureSourceType::INVALID)
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 < MAXIMUM_TIME_ALLOWED)
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 > MAXIMUM_TIME_ALLOWED) // If exceeded time between taps then just a single tap
141           {
142             mLastTapTime = event.time;
143             EmitSingleTap(event.time, point);
144           }
145           else if(deltaBetweenTouchDownTouchUp < MAXIMUM_TIME_ALLOWED)
146           {
147             ++mTapsRegistered;
148             EmitGesture(GestureState::STARTED, event.time);
149           }
150           else // Delta between touch down and touch up too long to be considered a TAP event
151           {
152             mState = CLEAR;
153           }
154         }
155         else if(pointState == PointState::DOWN)
156         {
157           const Vector2& screen(point.GetScreenPosition());
158           Vector2        distanceDelta(std::abs(mTouchPosition.x - screen.x),
159                                 std::abs(mTouchPosition.y - screen.y));
160
161           uint32_t timeDelta = event.time - mLastTapTime;
162
163           if(distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
164              distanceDelta.y > MAXIMUM_MOTION_ALLOWED ||
165              timeDelta > MAXIMUM_TIME_ALLOWED)
166           {
167             SetupForTouchDown(event, point);
168           }
169           else
170           {
171             EmitPossibleState(event);
172           }
173         }
174         break;
175       }
176
177       case FAILED:
178       default:
179       {
180         mState = CLEAR;
181         break;
182       }
183     }
184   }
185   else
186   {
187     mState = FAILED;
188
189     // We have entered a multi-touch event so emit registered gestures if required.
190     EmitGesture(GestureState::STARTED, event.time);
191   }
192 }
193
194 void TapGestureRecognizer::SetupForTouchDown(const Integration::TouchEvent& event, const Integration::Point& point)
195 {
196   mTouchPosition  = point.GetScreenPosition();
197   mTouchTime      = event.time;
198   mLastTapTime    = 0u;
199   mTapsRegistered = 0;
200   mState          = TOUCHED;
201
202   EmitPossibleState(event);
203 }
204
205 void TapGestureRecognizer::EmitPossibleState(const Integration::TouchEvent& event)
206 {
207   TapGestureEvent tapEvent(GestureState::POSSIBLE);
208   tapEvent.point             = mTouchPosition;
209   tapEvent.time              = event.time;
210   tapEvent.gestureSourceType = mGestureSourceType;
211
212   ProcessEvent(tapEvent);
213 }
214
215 void TapGestureRecognizer::Update(const GestureRequest& request)
216 {
217   const TapGestureRequest& tap = static_cast<const TapGestureRequest&>(request);
218
219   mMinimumTapsRequired = tap.minTaps;
220   mMaximumTapsRequired = tap.maxTaps;
221 }
222
223 void TapGestureRecognizer::EmitGesture(GestureState state, uint32_t time)
224 {
225   if((state == GestureState::CANCELLED) ||
226      (mTapsRegistered >= mMinimumTapsRequired && mTapsRegistered <= mMaximumTapsRequired))
227
228   {
229     TapGestureEvent event(state);
230     EmitTap(time, event);
231   }
232 }
233
234 void TapGestureRecognizer::EmitSingleTap(uint32_t time, const Integration::Point& point)
235 {
236   TapGestureEvent event(GestureState::STARTED);
237   const Vector2&  screen(point.GetScreenPosition());
238   Vector2         distanceDelta(std::abs(mTouchPosition.x - screen.x),
239                         std::abs(mTouchPosition.y - screen.y));
240
241   if(distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
242      distanceDelta.y > MAXIMUM_MOTION_ALLOWED)
243   {
244     event.state = GestureState::CANCELLED;
245   }
246   mTapsRegistered = 1u;
247   EmitTap(time, event);
248 }
249
250 void TapGestureRecognizer::EmitTap(uint32_t time, TapGestureEvent& event)
251 {
252   event.numberOfTaps      = mTapsRegistered;
253   event.point             = mTouchPosition;
254   event.time              = time;
255   event.gestureSourceType = mGestureSourceType;
256
257   ProcessEvent(event);
258 }
259
260 void TapGestureRecognizer::ProcessEvent(TapGestureEvent& event)
261 {
262   if(mScene)
263   {
264     // Create another handle so the recognizer cannot be destroyed during process function
265     GestureRecognizerPtr recognizerHandle = this;
266     mObserver.Process(*mScene, event);
267   }
268 }
269
270 } // namespace Internal
271
272 } // namespace Dali