[dali_2.3.24] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / event / events / tap-gesture / tap-gesture-recognizer.cpp
1 /*
2  * Copyright (c) 2023 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
37 TapGestureRecognizer::TapGestureRecognizer(Observer& observer, Vector2 screenSize, const TapGestureRequest& request, uint32_t maximumAllowedTime, uint32_t recognizerTime, float maximumMotionAllowedDistance)
38 : GestureRecognizer(screenSize, GestureType::TAP),
39   mObserver(observer),
40   mState(CLEAR),
41   mTouchPosition(),
42   mTapsRegistered(0u),
43   mTouchTime(0u),
44   mLastTapTime(0u),
45   mDeltaBetweenTouchDownTouchUp(0u),
46   mMaximumAllowedTime(maximumAllowedTime),
47   mRecognizerTime(recognizerTime),
48   mMaximumMotionAllowedDistance(maximumMotionAllowedDistance)
49 {
50 }
51
52 TapGestureRecognizer::~TapGestureRecognizer() = default;
53
54 void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
55 {
56   GestureRecognizerPtr ptr(this); // To keep us from being destroyed during the life-time of this method
57   if(event.GetPointCount() == 1)
58   {
59     const Integration::Point& point      = event.points[0];
60     PointState::Type          pointState = point.GetState();
61
62     switch(mState)
63     {
64       case CLEAR:
65       {
66         if(pointState == PointState::DOWN)
67         {
68           SetupForTouchDown(event, point);
69         }
70         break;
71       }
72
73       case TOUCHED:
74       {
75         if(pointState == PointState::UP)
76         {
77           mDeltaBetweenTouchDownTouchUp = event.time - mTouchTime;
78           if(mDeltaBetweenTouchDownTouchUp < mRecognizerTime)
79           {
80             EmitSingleTap(event.time, point);
81             mState = REGISTERED;
82           }
83           else // Clear if the time between touch down and touch up is long.
84           {
85             mState = CLEAR;
86             DALI_LOG_RELEASE_INFO("time between touch down and touch up is long. (%dms > %dms)\n", mDeltaBetweenTouchDownTouchUp, mRecognizerTime);
87           }
88         }
89         else if(pointState == PointState::INTERRUPTED)
90         {
91           mState = CLEAR;
92         }
93         break;
94       }
95
96       case REGISTERED:
97       {
98         if(pointState == PointState::UP)
99         {
100           mDeltaBetweenTouchDownTouchUp = event.time - mTouchTime;
101           if(mDeltaBetweenTouchDownTouchUp < mRecognizerTime)
102           {
103             const Vector2& screen(point.GetScreenPosition());
104             Vector2        distanceDelta(std::abs(mTouchPosition.x - screen.x),
105                                 std::abs(mTouchPosition.y - screen.y));
106             if(distanceDelta.x > mMaximumMotionAllowedDistance ||
107                distanceDelta.y > mMaximumMotionAllowedDistance)
108             {
109               mState = CLEAR;
110               DALI_LOG_RELEASE_INFO("There is a long distance between touch down and touch up. (%f or %f > %f)\n", distanceDelta.x, distanceDelta.y, mMaximumMotionAllowedDistance);
111             }
112             else
113             {
114               EmitGesture(GestureState::STARTED, event.time);
115             }
116           }
117           else // Clear if the time between touch down and touch up is long.
118           {
119             mState = CLEAR;
120             DALI_LOG_RELEASE_INFO("time between touch down and touch up is long. (%dms > %dms)\n", mDeltaBetweenTouchDownTouchUp, mRecognizerTime);
121           }
122         }
123         else if(pointState == PointState::DOWN)
124         {
125           const Vector2& screen(point.GetScreenPosition());
126           Vector2        distanceDelta(std::abs(mTouchPosition.x - screen.x),
127                                 std::abs(mTouchPosition.y - screen.y));
128
129           uint32_t timeDelta = event.time - mLastTapTime;
130           mTouchTime         = event.time;
131
132           if(distanceDelta.x > mMaximumMotionAllowedDistance ||
133              distanceDelta.y > mMaximumMotionAllowedDistance ||
134              timeDelta > mMaximumAllowedTime) // If the time between tabs is long, it starts over from SetupForTouchDown.
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 }
159
160 void TapGestureRecognizer::SetupForTouchDown(const Integration::TouchEvent& event, const Integration::Point& point)
161 {
162   mTouchPosition = point.GetScreenPosition();
163   mTouchTime     = event.time;
164   mLastTapTime   = 0u;
165   mState         = TOUCHED;
166   mTapsRegistered = 0u;
167
168   EmitPossibleState(event);
169 }
170
171 void TapGestureRecognizer::EmitPossibleState(const Integration::TouchEvent& event)
172 {
173   TapGestureEvent tapEvent(GestureState::POSSIBLE);
174   tapEvent.point = mTouchPosition;
175   tapEvent.time  = event.time;
176
177   ProcessEvent(tapEvent);
178 }
179
180 void TapGestureRecognizer::Update(const GestureRequest& request)
181 {
182   // Nothing to do.
183 }
184
185 void TapGestureRecognizer::SetMaximumAllowedTime(uint32_t time)
186 {
187   mMaximumAllowedTime = time;
188 }
189
190 void TapGestureRecognizer::SetRecognizerTime(uint32_t time)
191 {
192   mRecognizerTime = time;
193 }
194
195 void TapGestureRecognizer::SetMaximumMotionAllowedDistance(float distance)
196 {
197   mMaximumMotionAllowedDistance = distance;
198 }
199
200 void TapGestureRecognizer::EmitGesture(GestureState state, uint32_t time)
201 {
202   TapGestureEvent event(state);
203   EmitTap(time, event);
204 }
205
206 void TapGestureRecognizer::EmitSingleTap(uint32_t time, const Integration::Point& point)
207 {
208   TapGestureEvent event(GestureState::STARTED);
209   const Vector2&  screen(point.GetScreenPosition());
210   Vector2         distanceDelta(std::abs(mTouchPosition.x - screen.x),
211                         std::abs(mTouchPosition.y - screen.y));
212
213   if(distanceDelta.x > mMaximumMotionAllowedDistance ||
214      distanceDelta.y > mMaximumMotionAllowedDistance)
215   {
216     event.state = GestureState::CANCELLED;
217     DALI_LOG_RELEASE_INFO("There is a long distance between touch down and touch up. (%f or %f > %f)\n", distanceDelta.x, distanceDelta.y, mMaximumMotionAllowedDistance);
218   }
219   EmitTap(time, event);
220 }
221
222 void TapGestureRecognizer::EmitTap(uint32_t time, TapGestureEvent& event)
223 {
224   event.numberOfTaps = ++mTapsRegistered;
225   event.point  = mTouchPosition;
226   event.time   = time;
227   mLastTapTime = event.time;
228
229   ProcessEvent(event);
230 }
231
232 void TapGestureRecognizer::ProcessEvent(TapGestureEvent& event)
233 {
234   event.sourceType = mSourceType;
235   event.sourceData = mSourceData;
236   if(mScene)
237   {
238     // Create another handle so the recognizer cannot be destroyed during process function
239     GestureRecognizerPtr recognizerHandle = this;
240     mObserver.Process(*mScene, event);
241   }
242 }
243
244 } // namespace Internal
245
246 } // namespace Dali