Tizen 2.1 base
[framework/osp/uifw.git] / src / ui / FUi_TouchTapGestureDetector.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Flora License, Version 1.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://floralicense.org/license/
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an AS IS BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 /**
18  * @file                FUi_TouchTapGestureDetector.cpp
19  * @brief               This is the implementation file for %_TouchTapGestureDetector class
20  * @version             2.0
21  *
22  * This file contains the implementation of %_TouchTapGestureDetector class.
23  *
24  */
25 #include <FBaseUtilMath.h>
26 #include <FBaseColIEnumeratorT.h>
27 #include <FBaseColIListT.h>
28 #include <FUiITouchTapGestureEventListener.h>
29 #include "FUi_TouchTapGestureDetector.h"
30 #include "FUi_TouchManager.h"
31 #include "FUi_ITouchTapGestureEventListener.h"
32 #include "FUi_TouchTapGestureDetectorImpl.h"
33 #include "FUi_FingerInfo.h"
34 #include "FUi_TouchGestureTimerManager.h"
35
36 using namespace Tizen::Graphics;
37 using namespace Tizen::Base::Utility;
38 using namespace Tizen::Base::Collection;
39
40 namespace
41 {
42 const int DEFAULT_INTERNAL = 330;
43 const int DEFAULT_TAP_COUNT = 2;
44 const int DEFAULT_MOVE_ALLOWANCE = 10;
45 const int DEFAULT_TOUCH_COUNT = 1;
46 const int MAX_TOUCH_COUNT = 10;
47 const int INIT_TAP_COUNT = 1;
48 const int INVALID_POINT_ID = 9999;
49 }
50
51 namespace Tizen { namespace Ui
52 {
53
54 class _TouchTapGestureDetector::_TapInfo
55 {
56 public:
57         bool __isPressed;
58         int __tappedCount;
59 };
60
61 _TouchTapGestureDetector::_TouchTapGestureDetector(void)
62         : __tapCount(DEFAULT_TAP_COUNT)
63         , __interval(DEFAULT_INTERNAL)
64         , __touchCount(DEFAULT_TOUCH_COUNT)
65         , __oneTapMoveAllowance(DEFAULT_MOVE_ALLOWANCE)
66         , __oneTapIsInBounds(true)
67         , __maxPointId(DEFAULT_TOUCH_COUNT-1)
68         , __oneTapStartPoint(0, 0)
69         , __pGestureTimerManager(null)
70         , __pTapInfoList(null)
71 {
72         result r = GetLastResult();
73         SysTryReturnVoidResult(NID_UI, r == E_SUCCESS, r, GetErrorMessage(r));
74
75         __pGestureTimerManager = new (std::nothrow) _TouchGestureTimerManager(*this);
76         SysTryReturnVoidResult(NID_UI, __pGestureTimerManager, E_SYSTEM, "[E_SYSTEM] System error occurred..");
77
78         __pTapInfoList = new (std::nothrow) ArrayListT<_TapInfo*>;
79         SysTryReturnVoidResult(NID_UI, __pTapInfoList, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
80
81         for(int i=0; i < MAX_TOUCH_COUNT; i++)
82         {
83                 _TapInfo* pTapInfo = new (std::nothrow) _TapInfo;
84                 SysTryCatch(NID_UI, pTapInfo, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
85
86                 pTapInfo->__isPressed = false;
87                 pTapInfo->__tappedCount = 0;
88
89                 __pTapInfoList->Add(pTapInfo);
90         }
91
92         SetDetectorType(_TOUCH_GESTURE_DETECTOR_TYPE_TAP);
93         return;
94
95 CATCH:
96         if (__pGestureTimerManager)
97         {
98                 delete __pGestureTimerManager;
99                 __pGestureTimerManager = null;
100         }
101
102         if (__pTapInfoList)
103         {
104                 RemoveTapInfoList();
105                 delete __pTapInfoList;
106                 __pTapInfoList = null;
107         }
108 }
109
110 _TouchTapGestureDetector::~_TouchTapGestureDetector(void)
111 {
112         RemoveTapInfoList();
113         __pTapInfoList->RemoveAll();
114
115         delete __pTapInfoList;
116         __pTapInfoList = null;
117
118         delete __pGestureTimerManager;
119         __pGestureTimerManager = null;
120 }
121
122 void
123 _TouchTapGestureDetector::RemoveTapInfoList(void)
124 {
125         IEnumeratorT<_TapInfo*>* pEnumerator = __pTapInfoList->GetEnumeratorN();
126         if (pEnumerator)
127         {
128                 while(pEnumerator->MoveNext() == E_SUCCESS)
129                 {
130                         _TapInfo* pTapInfo = null;
131                         pEnumerator->GetCurrent(pTapInfo);
132                         if (!pTapInfo)
133                         {
134                                 continue;
135                         }
136                         delete pTapInfo;
137                 }
138                 delete pEnumerator;
139         }
140 }
141
142 result
143 _TouchTapGestureDetector::SetTapCount(int count)
144 {
145         SysTryReturnResult(NID_UI, count > 0, E_INVALID_ARG, "[E_INVALID_ARG] Argument is less than 0");
146
147         __tapCount = count;
148         return E_SUCCESS;
149 }
150
151 int
152 _TouchTapGestureDetector::GetTapCount(void) const
153 {
154         return __tapCount;
155 }
156
157 result
158 _TouchTapGestureDetector::SetTapInterval(long intarval)
159 {
160         SysTryReturnResult(NID_UI, intarval > 0, E_INVALID_ARG, "[E_INVALID_ARG] Argument is less than 0");
161
162         __interval = intarval;
163         return E_SUCCESS;
164 }
165
166 long
167 _TouchTapGestureDetector::GetTapInterval(void) const
168 {
169         return __interval;
170 }
171
172 result
173 _TouchTapGestureDetector::SetTouchCount(int count)
174 {
175         SysTryReturnResult(NID_UI, count > 0, E_INVALID_ARG, "[E_INVALID_ARG] Argument is less than 0");
176
177         __touchCount = count;
178         __maxPointId = __touchCount - 1;
179
180         if (__touchCount > DEFAULT_TOUCH_COUNT)
181         {
182                 _Control* pControl = GetControl();
183                 if (pControl && !pControl->IsMultiTouchEnabled())
184                 {
185                         pControl->SetMultiTouchEnabled(true);
186                 }
187         }
188         return E_SUCCESS;
189 }
190
191 int
192 _TouchTapGestureDetector::GetTouchCount(void) const
193 {
194         return __touchCount;
195 }
196
197 result
198 _TouchTapGestureDetector::SetMoveAllowance(int allowance)
199 {
200         SysTryReturnResult(NID_UI, allowance >= 0, E_INVALID_ARG, "[E_INVALID_ARG] Argument is less than 0");
201         SysTryReturnResult(NID_UI, __touchCount == DEFAULT_TOUCH_COUNT, E_INVALID_CONDITION, "[E_INVALID_CONDITION] move allowance applies only for default(1) touch count.");
202
203         __oneTapMoveAllowance = allowance;
204
205         return E_SUCCESS;
206 }
207
208 int
209 _TouchTapGestureDetector::GetMoveAllowance(void) const
210 {
211         return __oneTapMoveAllowance;
212 }
213
214 bool
215 _TouchTapGestureDetector::IsInBounds(void)
216 {
217         return __oneTapIsInBounds;
218 }
219
220 bool
221 _TouchTapGestureDetector::IsAllTapped(void)
222 {
223         bool allTapped = true;
224
225         for(int i=0; i<__touchCount; i++)
226         {
227                 _TapInfo* pTapInfo = null;
228                 __pTapInfoList->GetAt(i, pTapInfo);
229                 if (!pTapInfo)
230                 {
231                         continue;
232                 }
233
234                 if (pTapInfo->__isPressed && pTapInfo->__tappedCount >= __tapCount)
235                 {
236                         allTapped = true;
237                 }
238                 else
239                 {
240                         allTapped = false;
241                 }
242         }
243
244         return allTapped;
245 }
246
247 bool
248 _TouchTapGestureDetector::OnTouchPressed(const _Control& source, const _TouchInfo& touchinfo)
249 {
250         if (touchinfo.GetPointId() > __maxPointId || GetDetectorState() != _TOUCH_GESTURE_DETECTOR_STATE_READY)
251         {
252                 return false;
253         }
254
255         _TapInfo* pTapInfo = null;
256         __pTapInfoList->GetAt(touchinfo.GetPointId(), pTapInfo);
257         SysTryReturn(NID_UI, pTapInfo, false, E_SYSTEM, "[E_SYSTEM] System error occurred. ");
258
259         if (__touchCount == DEFAULT_TOUCH_COUNT)
260         {
261                 if (pTapInfo->__tappedCount == 0)
262                 {
263                         __oneTapStartPoint.x = touchinfo.GetCurrentPosition().x;
264                         __oneTapStartPoint.y = touchinfo.GetCurrentPosition().y;
265                 }
266
267                 if (Math::Abs(touchinfo.GetCurrentPosition().x - __oneTapStartPoint.x) > __oneTapMoveAllowance
268                         || Math::Abs(touchinfo.GetCurrentPosition().y - __oneTapStartPoint.y) > __oneTapMoveAllowance)
269                 {
270                         __oneTapIsInBounds = false;
271                 }
272                 else
273                 {
274                         __oneTapIsInBounds = true;
275                 }
276         }
277         else
278         {
279                 __oneTapIsInBounds = true;
280         }
281
282         pTapInfo->__isPressed = true;
283
284         SysTryReturn(NID_UI, __pTapInfoList->SetAt(pTapInfo, touchinfo.GetPointId()) == E_SUCCESS,
285                                 false, E_SYSTEM, "[E_SYSTEM] System error occurred.");
286
287         bool allTouched = false;
288
289         for(int i=0; i<__touchCount; i++)
290         {
291                 _TapInfo* pAllTapInfo = null;
292                 __pTapInfoList->GetAt(i, pAllTapInfo);
293                 if (pAllTapInfo)
294                 {
295                         if (pAllTapInfo->__isPressed)
296                         {
297                                 allTouched = true;
298                         }
299                         else
300                         {
301                                 allTouched = false;
302                         }
303                 }
304         }
305
306         if (allTouched && !IsGestureStarted())
307         {
308                 SetDetectorState(_TOUCH_GESTURE_DETECTOR_STATE_READY);
309                 SetGestureStart(true);
310
311                 if (__pGestureTimerManager->IsTimerStarted() == false)
312                 {
313                         _Control* pControl = GetControl();
314                         if (!pControl)
315                         {
316                                 SetControl(source);
317                         }
318
319                         if (__pGestureTimerManager->StartTimer(__interval) != E_SUCCESS)
320                         {
321                                 SysLogException(NID_UI, E_SYSTEM, "[E_SYSTEM] Tapping timer is not started.");
322                         }
323                 }
324         }
325
326         return false;
327 }
328
329 bool
330 _TouchTapGestureDetector::OnTouchMoved(const _Control& source, const _TouchInfo& touchinfo)
331 {
332         if ((touchinfo.GetPointId() > __maxPointId) || (GetDetectorState() != _TOUCH_GESTURE_DETECTOR_STATE_READY))
333         {
334                 return false;
335         }
336
337         if (__touchCount == DEFAULT_TOUCH_COUNT)
338         {
339                 if (Math::Abs(touchinfo.GetCurrentPosition().x - __oneTapStartPoint.x) > __oneTapMoveAllowance
340                         || Math::Abs(touchinfo.GetCurrentPosition().y - __oneTapStartPoint.y) > __oneTapMoveAllowance)
341                 {
342                         __oneTapIsInBounds = false;
343                         __pGestureTimerManager->CancelTimer();
344                         SetDetectorState(_TOUCH_GESTURE_DETECTOR_STATE_FAILED);
345                         ClearTapInfoList();
346                 }
347         }
348
349         return false;
350 }
351
352 bool
353 _TouchTapGestureDetector::OnTouchReleased(const _Control& source, const _TouchInfo& touchinfo)
354 {
355         if ((touchinfo.GetPointId() > __maxPointId) || (GetDetectorState() != _TOUCH_GESTURE_DETECTOR_STATE_READY))
356         {
357                 return false;
358         }
359
360         _TapInfo* pTapInfo = null;
361         __pTapInfoList->GetAt(touchinfo.GetPointId(), pTapInfo);
362         SysTryReturn(NID_UI, pTapInfo, false, E_SYSTEM, "[E_SYSTEM] System error occurred. ");
363
364         if (pTapInfo->__isPressed)
365         {
366                 pTapInfo->__tappedCount++;
367                 SysTryReturn(NID_UI, __pTapInfoList->SetAt(pTapInfo, touchinfo.GetPointId()) == E_SUCCESS,
368                                         false, E_SYSTEM, "[E_SYSTEM] System error occurred.");
369
370                 if (__touchCount == DEFAULT_TOUCH_COUNT)
371                 {
372                         if (Math::Abs(touchinfo.GetCurrentPosition().x - __oneTapStartPoint.x) > __oneTapMoveAllowance
373                                 || Math::Abs(touchinfo.GetCurrentPosition().y - __oneTapStartPoint.y) > __oneTapMoveAllowance)
374                         {
375                                 __oneTapIsInBounds = false;
376                         }
377                 }
378         }
379
380         if (IsGestureStarted() && !__pGestureTimerManager->IsTimerExpired())
381         {
382                 if (IsAllTapped() && IsInBounds())
383                 {
384                         __pGestureTimerManager->CancelTimer();
385                         SetDetectorState(_TOUCH_GESTURE_DETECTOR_STATE_SUCCESS);
386                         ClearTapInfoList();
387                 }
388         }
389         else
390         {
391                 if (!IsAllTapped() && !IsGestureStarted())
392                 {
393                         if (!__pGestureTimerManager->IsTimerExpired())
394                         {
395                                 __pGestureTimerManager->CancelTimer();
396                         }
397                         SetDetectorState(_TOUCH_GESTURE_DETECTOR_STATE_FAILED);
398                         ClearTapInfoList();
399                 }
400         }
401
402         return false;
403 }
404
405 bool
406 _TouchTapGestureDetector::OnTouchCanceled(const _Control& source, const _TouchInfo& touchinfo)
407 {
408         ClearTapInfoList();
409
410         if (__pGestureTimerManager->IsTimerExpired() == false)
411         {
412                 __pGestureTimerManager->CancelTimer();
413         }
414
415         return false;
416 }
417
418 void
419 _TouchTapGestureDetector::ClearTapInfoList(void)
420 {
421         for(int i=0; i < MAX_TOUCH_COUNT; i++)
422         {
423                 _TapInfo* pTapInfo = null;
424                 __pTapInfoList->GetAt(i, pTapInfo);
425                 if (!pTapInfo)
426                 {
427                         continue;
428                 }
429
430                 pTapInfo->__isPressed = false;
431                 pTapInfo->__tappedCount = 0;
432
433                 __pTapInfoList->SetAt(pTapInfo, i);
434         }
435 }
436
437 }} //Tizen::Ui