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