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