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