Fixed an issue the triple tap did not work.
[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 {
54 }
55
56 TapGestureRecognizer::~TapGestureRecognizer() = default;
57
58 void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
59 {
60   GestureRecognizerPtr ptr(this); // To keep us from being destroyed during the life-time of this method
61
62   if(event.GetPointCount() == 1)
63   {
64     const Integration::Point& point      = event.points[0];
65     PointState::Type          pointState = point.GetState();
66
67     switch(mState)
68     {
69       case CLEAR:
70       {
71         if(pointState == PointState::DOWN)
72         {
73           SetupForTouchDown(event, point);
74         }
75         break;
76       }
77
78       case TOUCHED:
79       {
80         uint32_t deltaBetweenTouchDownTouchUp = event.time - mTouchTime;
81
82         if(pointState == PointState::UP)
83         {
84           if(deltaBetweenTouchDownTouchUp < MAXIMUM_TIME_ALLOWED)
85           {
86             mLastTapTime = mTouchTime;
87             EmitSingleTap(event.time, point);
88             mState = REGISTERED;
89           }
90           else
91           {
92             mState = CLEAR;
93           }
94         }
95         else if(pointState == PointState::INTERRUPTED)
96         {
97           mState = CLEAR;
98         }
99         break;
100       }
101
102       case REGISTERED:
103       {
104         if(pointState == PointState::UP)
105         {
106           // This is a possible multiple tap, so has it been quick enough?
107           uint32_t timeDelta                    = event.time - mLastTapTime;
108           uint32_t deltaBetweenTouchDownTouchUp = event.time - mTouchTime;
109           if(timeDelta > MAXIMUM_TIME_ALLOWED) // If exceeded time between taps then just a single tap
110           {
111             mLastTapTime = event.time;
112             EmitSingleTap(event.time, point);
113           }
114           else if(deltaBetweenTouchDownTouchUp < MAXIMUM_TIME_ALLOWED)
115           {
116             ++mTapsRegistered;
117             EmitGesture(GestureState::STARTED, event.time);
118           }
119           else // Delta between touch down and touch up too long to be considered a TAP event
120           {
121             mState = CLEAR;
122           }
123         }
124         else if(pointState == PointState::DOWN)
125         {
126           const Vector2& screen(point.GetScreenPosition());
127           Vector2        distanceDelta(std::abs(mTouchPosition.x - screen.x),
128                                 std::abs(mTouchPosition.y - screen.y));
129
130           uint32_t timeDelta = event.time - mLastTapTime;
131
132           if(distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
133              distanceDelta.y > MAXIMUM_MOTION_ALLOWED ||
134              timeDelta > MAXIMUM_TIME_ALLOWED)
135           {
136             SetupForTouchDown(event, point);
137           }
138           else
139           {
140             EmitPossibleState(event);
141           }
142         }
143         break;
144       }
145
146       case FAILED:
147       default:
148       {
149         mState = CLEAR;
150         break;
151       }
152     }
153   }
154   else
155   {
156     mState = FAILED;
157
158     // We have entered a multi-touch event so emit registered gestures if required.
159     EmitGesture(GestureState::STARTED, event.time);
160   }
161 }
162
163 void TapGestureRecognizer::SetupForTouchDown(const Integration::TouchEvent& event, const Integration::Point& point)
164 {
165   mTouchPosition  = point.GetScreenPosition();
166   mTouchTime      = event.time;
167   mLastTapTime    = 0u;
168   mTapsRegistered = 0;
169   mState          = TOUCHED;
170   EmitPossibleState(event);
171 }
172
173 void TapGestureRecognizer::EmitPossibleState(const Integration::TouchEvent& event)
174 {
175   TapGestureEvent tapEvent(GestureState::POSSIBLE);
176   tapEvent.point = mTouchPosition;
177   tapEvent.time  = event.time;
178
179   ProcessEvent(tapEvent);
180 }
181
182 void TapGestureRecognizer::Update(const GestureRequest& request)
183 {
184   const TapGestureRequest& tap = static_cast<const TapGestureRequest&>(request);
185
186   mMinimumTapsRequired = tap.minTaps;
187   mMaximumTapsRequired = tap.maxTaps;
188 }
189
190 void TapGestureRecognizer::EmitGesture(GestureState state, uint32_t time)
191 {
192   if((state == GestureState::CANCELLED) ||
193      (mTapsRegistered >= mMinimumTapsRequired && mTapsRegistered <= mMaximumTapsRequired))
194
195   {
196     TapGestureEvent event(state);
197     EmitTap(time, event);
198   }
199 }
200
201 void TapGestureRecognizer::EmitSingleTap(uint32_t time, const Integration::Point& point)
202 {
203   TapGestureEvent event(GestureState::STARTED);
204   const Vector2&  screen(point.GetScreenPosition());
205   Vector2         distanceDelta(std::abs(mTouchPosition.x - screen.x),
206                         std::abs(mTouchPosition.y - screen.y));
207
208   if(distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
209      distanceDelta.y > MAXIMUM_MOTION_ALLOWED)
210   {
211     event.state = GestureState::CANCELLED;
212   }
213   mTapsRegistered = 1u;
214   EmitTap(time, event);
215 }
216
217 void TapGestureRecognizer::EmitTap(uint32_t time, TapGestureEvent& event)
218 {
219   event.numberOfTaps = mTapsRegistered;
220   event.point        = mTouchPosition;
221   event.time         = time;
222
223   ProcessEvent(event);
224 }
225
226 void TapGestureRecognizer::ProcessEvent(TapGestureEvent& event)
227 {
228   if(mScene)
229   {
230     // Create another handle so the recognizer cannot be destroyed during process function
231     GestureRecognizerPtr recognizerHandle = this;
232     mObserver.Process(*mScene, event);
233   }
234 }
235
236 } // namespace Internal
237
238 } // namespace Dali