Changed indicator bg color.
[platform/framework/native/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 Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0/
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 result
215 _TouchTapGestureDetector::SetMoveAllowance(float allowance)
216 {
217         SysTryReturnResult(NID_UI, allowance >= 0, E_INVALID_ARG, "[E_INVALID_ARG] Argument is less than 0");
218         SysTryReturnResult(NID_UI, __touchCount == DEFAULT_TOUCH_COUNT, E_INVALID_CONDITION, "[E_INVALID_CONDITION] move allowance applies only for default(1) touch count.");
219
220         __oneTapMoveAllowance = allowance;
221
222         return E_SUCCESS;
223 }
224
225 float
226 _TouchTapGestureDetector::GetMoveAllowanceF(void) const
227 {
228         return __oneTapMoveAllowance;
229 }
230
231 bool
232 _TouchTapGestureDetector::IsInBounds(void)
233 {
234         return __oneTapIsInBounds;
235 }
236
237 bool
238 _TouchTapGestureDetector::IsAllTapped(void)
239 {
240         bool allTapped = true;
241
242         for(int i=0; i<__touchCount; i++)
243         {
244                 _TapInfo* pTapInfo = null;
245                 __pTapInfoList->GetAt(i, pTapInfo);
246                 if (!pTapInfo)
247                 {
248                         continue;
249                 }
250
251                 if (pTapInfo->__isPressed && pTapInfo->__tappedCount >= __tapCount)
252                 {
253                         allTapped = true;
254                 }
255                 else
256                 {
257                         allTapped = false;
258                 }
259         }
260
261         return allTapped;
262 }
263
264 bool
265 _TouchTapGestureDetector::OnTouchPressed(const _Control& source, const _TouchInfo& touchinfo)
266 {
267         if (touchinfo.GetPointId() > __maxPointId || GetDetectorState() != _TOUCH_GESTURE_DETECTOR_STATE_READY)
268         {
269                 return false;
270         }
271
272         _TapInfo* pTapInfo = null;
273         __pTapInfoList->GetAt(touchinfo.GetPointId(), pTapInfo);
274         SysTryReturn(NID_UI, pTapInfo, false, E_SYSTEM, "[E_SYSTEM] System error occurred. ");
275
276         if (__touchCount == DEFAULT_TOUCH_COUNT)
277         {
278                 if (pTapInfo->__tappedCount == 0)
279                 {
280                         __oneTapStartPoint.x = touchinfo.GetCurrentPosition().x;
281                         __oneTapStartPoint.y = touchinfo.GetCurrentPosition().y;
282                 }
283
284                 if (Math::Abs(touchinfo.GetCurrentPosition().x - __oneTapStartPoint.x) > __oneTapMoveAllowance
285                         || Math::Abs(touchinfo.GetCurrentPosition().y - __oneTapStartPoint.y) > __oneTapMoveAllowance)
286                 {
287                         __oneTapIsInBounds = false;
288                 }
289                 else
290                 {
291                         __oneTapIsInBounds = true;
292                 }
293         }
294         else
295         {
296                 __oneTapIsInBounds = true;
297         }
298
299         pTapInfo->__isPressed = true;
300
301         SysTryReturn(NID_UI, __pTapInfoList->SetAt(pTapInfo, touchinfo.GetPointId()) == E_SUCCESS,
302                                 false, E_SYSTEM, "[E_SYSTEM] System error occurred.");
303
304         bool allTouched = false;
305
306         for(int i=0; i<__touchCount; i++)
307         {
308                 _TapInfo* pAllTapInfo = null;
309                 __pTapInfoList->GetAt(i, pAllTapInfo);
310                 if (pAllTapInfo)
311                 {
312                         if (pAllTapInfo->__isPressed)
313                         {
314                                 allTouched = true;
315                         }
316                         else
317                         {
318                                 allTouched = false;
319                         }
320                 }
321         }
322
323         if (allTouched && !IsGestureStarted())
324         {
325                 SetDetectorState(_TOUCH_GESTURE_DETECTOR_STATE_READY);
326                 SetGestureStart(true);
327
328                 if (__pGestureTimerManager->IsTimerStarted() == false)
329                 {
330                         _Control* pControl = GetControl();
331                         if (!pControl)
332                         {
333                                 SetControl(source);
334                         }
335
336                         if (__pGestureTimerManager->StartTimer(__interval) != E_SUCCESS)
337                         {
338                                 SysLogException(NID_UI, E_SYSTEM, "[E_SYSTEM] Tapping timer is not started.");
339                         }
340                 }
341         }
342
343         return false;
344 }
345
346 bool
347 _TouchTapGestureDetector::OnTouchMoved(const _Control& source, const _TouchInfo& touchinfo)
348 {
349         if ((touchinfo.GetPointId() > __maxPointId) || (GetDetectorState() != _TOUCH_GESTURE_DETECTOR_STATE_READY))
350         {
351                 return false;
352         }
353
354         if (__touchCount == DEFAULT_TOUCH_COUNT)
355         {
356                 if (Math::Abs(touchinfo.GetCurrentPosition().x - __oneTapStartPoint.x) > __oneTapMoveAllowance
357                         || Math::Abs(touchinfo.GetCurrentPosition().y - __oneTapStartPoint.y) > __oneTapMoveAllowance)
358                 {
359                         __oneTapIsInBounds = false;
360                         __pGestureTimerManager->CancelTimer();
361                         SetDetectorState(_TOUCH_GESTURE_DETECTOR_STATE_FAILED);
362                         ClearTapInfoList();
363                 }
364         }
365
366         return false;
367 }
368
369 bool
370 _TouchTapGestureDetector::OnTouchReleased(const _Control& source, const _TouchInfo& touchinfo)
371 {
372         if ((touchinfo.GetPointId() > __maxPointId) || (GetDetectorState() != _TOUCH_GESTURE_DETECTOR_STATE_READY))
373         {
374                 return false;
375         }
376
377         _TapInfo* pTapInfo = null;
378         __pTapInfoList->GetAt(touchinfo.GetPointId(), pTapInfo);
379         SysTryReturn(NID_UI, pTapInfo, false, E_SYSTEM, "[E_SYSTEM] System error occurred. ");
380
381         if (pTapInfo->__isPressed)
382         {
383                 pTapInfo->__tappedCount++;
384                 SysTryReturn(NID_UI, __pTapInfoList->SetAt(pTapInfo, touchinfo.GetPointId()) == E_SUCCESS,
385                                         false, E_SYSTEM, "[E_SYSTEM] System error occurred.");
386
387                 if (__touchCount == DEFAULT_TOUCH_COUNT)
388                 {
389                         if (Math::Abs(touchinfo.GetCurrentPosition().x - __oneTapStartPoint.x) > __oneTapMoveAllowance
390                                 || Math::Abs(touchinfo.GetCurrentPosition().y - __oneTapStartPoint.y) > __oneTapMoveAllowance)
391                         {
392                                 __oneTapIsInBounds = false;
393                         }
394                 }
395         }
396
397         if (IsGestureStarted() && !__pGestureTimerManager->IsTimerExpired())
398         {
399                 if (IsAllTapped() && IsInBounds())
400                 {
401                         __pGestureTimerManager->CancelTimer();
402                         SetDetectorState(_TOUCH_GESTURE_DETECTOR_STATE_SUCCESS);
403                         ClearTapInfoList();
404                 }
405         }
406         else
407         {
408                 if (!IsAllTapped() && !IsGestureStarted())
409                 {
410                         if (!__pGestureTimerManager->IsTimerExpired())
411                         {
412                                 __pGestureTimerManager->CancelTimer();
413                         }
414                         SetDetectorState(_TOUCH_GESTURE_DETECTOR_STATE_FAILED);
415                         ClearTapInfoList();
416                 }
417         }
418
419         return false;
420 }
421
422 bool
423 _TouchTapGestureDetector::OnTouchCanceled(const _Control& source, const _TouchInfo& touchinfo)
424 {
425         ClearTapInfoList();
426
427         if (__pGestureTimerManager->IsTimerExpired() == false)
428         {
429                 __pGestureTimerManager->CancelTimer();
430         }
431
432         return false;
433 }
434
435 void
436 _TouchTapGestureDetector::ClearTapInfoList(void)
437 {
438         for(int i=0; i < MAX_TOUCH_COUNT; i++)
439         {
440                 _TapInfo* pTapInfo = null;
441                 __pTapInfoList->GetAt(i, pTapInfo);
442                 if (!pTapInfo)
443                 {
444                         continue;
445                 }
446
447                 pTapInfo->__isPressed = false;
448                 pTapInfo->__tappedCount = 0;
449
450                 __pTapInfoList->SetAt(pTapInfo, i);
451         }
452 }
453
454 }} //Tizen::Ui