6981f88fc00713fe638c0d47d0495a7e0f91ddfb
[platform/core/uifw/dali-adaptor.git] / adaptors / common / events / tap-gesture-detector.cpp
1 /*
2  * Copyright (c) 2014 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 "tap-gesture-detector.h"
20
21 // EXTERNAL INCLUDES
22 #include <cmath>
23
24 #include <dali/public-api/math/vector2.h>
25
26 #include <dali/integration-api/events/gesture-requests.h>
27 #include <dali/integration-api/events/touch-event-integ.h>
28 #include <base/core-event-interface.h>
29
30 // INTERNAL INCLUDES
31
32 namespace Dali
33 {
34
35 namespace Internal
36 {
37
38 namespace Adaptor
39 {
40
41 namespace
42 {
43 // TODO: Set these according to DPI
44 const float MAXIMUM_MOTION_ALLOWED = 20.0f;
45 const unsigned long MAXIMUM_TIME_ALLOWED = 500u;
46 } // unnamed namespace
47
48 TapGestureDetector::TapGestureDetector(CoreEventInterface& coreEventInterface, Vector2 screenSize, const Integration::TapGestureRequest& request)
49 : GestureDetector(screenSize, Gesture::Tap),
50   mCoreEventInterface(coreEventInterface),
51   mState(Clear),
52   mMinimumTapsRequired(request.minTaps),
53   mMaximumTapsRequired(request.maxTaps),
54   mTapsRegistered(0),
55   mTouchPosition(),
56   mTouchTime(0u),
57   mLastTapTime(0u)
58 {
59 }
60
61 TapGestureDetector::~TapGestureDetector()
62 {
63 }
64
65 void TapGestureDetector::SendEvent(const Integration::TouchEvent& event)
66 {
67   if (event.GetPointCount() == 1)
68   {
69     const TouchPoint& point = event.points[0];
70     TouchPoint::State pointState = point.state;
71
72     switch (mState)
73     {
74       case Clear:
75       {
76         if (pointState == TouchPoint::Down)
77         {
78           SetupForTouchDown( event, point );
79         }
80         break;
81       }
82
83       case Touched:
84       {
85         if ( pointState == TouchPoint::Up )
86         {
87           mLastTapTime = mTouchTime;
88           EmitSingleTap( event.time, point );
89           mState = Registered;
90         }
91         else if (pointState == TouchPoint::Interrupted)
92         {
93           mState = Clear;
94         }
95         break;
96       }
97
98       case Registered:
99       {
100         if ( pointState == TouchPoint::Up )
101         {
102           // This is a possible multiple tap, so has it been quick enough ?
103           unsigned long timeDelta = abs( event.time - mLastTapTime );
104           if ( timeDelta > MAXIMUM_TIME_ALLOWED )
105           {
106             mLastTapTime = event.time;
107             EmitSingleTap( event.time, point );
108             mState = Clear;
109             break;
110           }
111           else
112           {
113             ++mTapsRegistered;
114             EmitGesture( Gesture::Started, event.time );
115             mState = Clear;
116           }
117           break;
118         }
119         if (pointState == TouchPoint::Down)
120         {
121           Vector2 distanceDelta(abs(mTouchPosition.x - point.screen.x),
122                                 abs(mTouchPosition.y - point.screen.y));
123
124           unsigned long timeDelta = abs( mTouchTime - mLastTapTime );
125
126           if (distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
127               distanceDelta.y > MAXIMUM_MOTION_ALLOWED ||
128               timeDelta > MAXIMUM_TIME_ALLOWED )
129           {
130             SetupForTouchDown( event, point );
131           }
132           else
133           {
134             EmitPossibleState( event );
135           }
136         }
137         break;
138       }
139
140       case Failed:
141       default:
142       {
143         mState = Clear;
144         break;
145       }
146     }
147   }
148   else
149   {
150     mState = Failed;
151
152     // We have entered a multi-touch event so emit registered gestures if required.
153     EmitGesture(Gesture::Started, event.time);
154   }
155 }
156
157 void TapGestureDetector::SetupForTouchDown( const Integration::TouchEvent& event, const TouchPoint& point )
158 {
159   mTouchPosition.x = point.screen.x;
160   mTouchPosition.y = point.screen.y;
161   mTouchTime = event.time;
162   mLastTapTime = 0u;
163   mTapsRegistered = 0;
164   mState = Touched;
165   EmitPossibleState( event );
166 }
167
168 void TapGestureDetector::EmitPossibleState( const Integration::TouchEvent& event )
169 {
170   Integration::TapGestureEvent tapEvent( Gesture::Possible );
171   tapEvent.point = mTouchPosition;
172   tapEvent.time = event.time;
173   mCoreEventInterface.QueueCoreEvent(tapEvent);
174 }
175
176
177 void TapGestureDetector::Update(const Integration::GestureRequest& request)
178 {
179   const Integration::TapGestureRequest& tap = static_cast<const Integration::TapGestureRequest&>(request);
180
181   mMinimumTapsRequired = tap.minTaps;
182   mMaximumTapsRequired = tap.maxTaps;
183 }
184
185 void TapGestureDetector::EmitGesture( Gesture::State state, unsigned int time )
186 {
187   if ( (state == Gesture::Cancelled) ||
188        (mTapsRegistered >= mMinimumTapsRequired && mTapsRegistered <= mMaximumTapsRequired) )
189
190   {
191     Integration::TapGestureEvent event( state );
192     EmitTap( time, event );
193   }
194 }
195
196 void TapGestureDetector::EmitSingleTap( unsigned int time, const TouchPoint& point )
197 {
198   Integration::TapGestureEvent event( Gesture::Started );
199   Vector2 distanceDelta(abs(mTouchPosition.x - point.screen.x),
200                         abs(mTouchPosition.y - point.screen.y));
201
202   if (distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
203       distanceDelta.y > MAXIMUM_MOTION_ALLOWED )
204   {
205     event.state = Gesture::Cancelled;
206   }
207   mTapsRegistered = 1u;
208   EmitTap( time, event );
209 }
210
211 void TapGestureDetector::EmitTap( unsigned int time, Integration::TapGestureEvent& event )
212 {
213   event.numberOfTaps = mTapsRegistered;
214   event.point = mTouchPosition;
215   event.time = time;
216   mCoreEventInterface.QueueCoreEvent(event);
217 }
218
219 } // namespace Adaptor
220
221 } // namespace Internal
222
223 } // namespace Dali