Tizen 2.1 base
[framework/osp/uifw.git] / src / ui / FUi_TouchLongPressGestureDetector.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_TouchLongPressGestureDetector.cpp
19  * @brief               This is the implementation file for %_TouchLongPressGestureDetector class
20  * @version             2.0
21  *
22  * This file contains the implementation of %_TouchLongPressGestureDetector class.
23  *
24  */
25 #include <FBaseUtilMath.h>
26 #include <FBaseColIEnumeratorT.h>
27 #include <FUiITouchLongPressGestureEventListener.h>
28 #include "FUi_TouchLongPressGestureDetector.h"
29 #include "FUi_ITouchLongPressGestureEventListener.h"
30 #include "FUi_TouchManager.h"
31 #include "FUi_TouchLongPressGestureDetectorImpl.h"
32 #include "FUi_TouchGestureTimerManager.h"
33
34 using namespace Tizen::Base::Utility;
35 using namespace Tizen::Base::Collection;
36 using namespace Tizen::Graphics;
37
38 namespace Tizen { namespace Ui
39 {
40 const int DEFAULT_DURATION = 500;
41 const int DEFAULT_MOVE_ALLOWANCE = 10;
42 const int DEFAULT_TOUCH_COUNT = 1;
43 const int MAX_TOUCH_COUNT = 10;
44
45 class _TouchLongPressGestureDetector::_LongPressInfo
46 {
47 public:
48         bool __isPressed;
49         bool __isInBounds;
50         int __touchCount;
51 };
52
53 _TouchLongPressGestureDetector::_TouchLongPressGestureDetector(void)
54         : __duration(DEFAULT_DURATION)
55         , __moveAllowance(DEFAULT_MOVE_ALLOWANCE)
56         , __touchCount(DEFAULT_TOUCH_COUNT)
57         , __maxPointId(DEFAULT_TOUCH_COUNT-1)
58         , __pGestureTimerManager(null)
59         , __pLongPressInfoList(null)
60 {
61         result r = GetLastResult();
62         SysTryReturnVoidResult(NID_UI, r == E_SUCCESS, r, GetErrorMessage(r));
63
64         __pLongPressInfoList = new (std::nothrow) ArrayListT<_LongPressInfo*>;
65         SysTryReturnVoidResult(NID_UI, __pLongPressInfoList, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
66
67         for(int i=0; i < MAX_TOUCH_COUNT; i++)
68         {
69                 _LongPressInfo* pLongPressInfo = new (std::nothrow) _LongPressInfo;
70                 SysTryCatch(NID_UI, pLongPressInfo, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
71
72                 pLongPressInfo->__isPressed = false;
73                 pLongPressInfo->__isInBounds = false;
74                 pLongPressInfo->__touchCount = 0;
75
76                 __pLongPressInfoList->Add(pLongPressInfo);
77         }
78
79         SetDetectorType(_TOUCH_GESTURE_DETECTOR_TYPE_LONG_PRESS);
80         return;
81
82 CATCH:
83         if (__pLongPressInfoList)
84         {
85                 RemoveLongPressInfoList();
86                 delete __pLongPressInfoList;
87                 __pLongPressInfoList = null;
88         }
89 }
90
91 _TouchLongPressGestureDetector::~_TouchLongPressGestureDetector(void)
92 {
93         RemoveLongPressInfoList();
94         __pLongPressInfoList->RemoveAll();
95
96         delete __pLongPressInfoList;
97         __pLongPressInfoList = null;
98
99         if (__pGestureTimerManager != null)
100         {
101                 __pGestureTimerManager->CancelTimer();
102
103                 delete __pGestureTimerManager;
104                 __pGestureTimerManager = null;
105         }
106 }
107
108 void
109 _TouchLongPressGestureDetector::RemoveLongPressInfoList(void)
110 {
111         IEnumeratorT<_LongPressInfo*>* pEnumerator = __pLongPressInfoList->GetEnumeratorN();
112         if (pEnumerator)
113         {
114                 while(pEnumerator->MoveNext() == E_SUCCESS)
115                 {
116                         _LongPressInfo* pLongPressInfo = null;
117                         pEnumerator->GetCurrent(pLongPressInfo);
118                         if (!pLongPressInfo)
119                         {
120                                 continue;
121                         }
122                         delete pLongPressInfo;
123                 }
124                 delete pEnumerator;
125         }
126 }
127
128 result
129 _TouchLongPressGestureDetector::SetDuration(int duration)
130 {
131         SysTryReturnResult(NID_UI, duration > 0, E_INVALID_ARG, "[E_INVALID_ARG] Argument is less than 0");
132
133         __duration = duration;
134         return E_SUCCESS;
135 }
136
137 int
138 _TouchLongPressGestureDetector::GetDuration(void) const
139 {
140         return __duration;
141 }
142
143 result
144 _TouchLongPressGestureDetector::SetMoveAllowance(int allowance)
145 {
146         SysTryReturnResult(NID_UI, allowance > 0, E_INVALID_ARG, "[E_INVALID_ARG] Argument is less than 0");
147
148         __moveAllowance = allowance;
149         return E_SUCCESS;
150 }
151
152 int
153 _TouchLongPressGestureDetector::GetMoveAllowance(void) const
154 {
155         return __moveAllowance;
156 }
157
158 result
159 _TouchLongPressGestureDetector::SetTouchCount(int count)
160 {
161         SysTryReturnResult(NID_UI, count > 0, E_INVALID_ARG, "[E_INVALID_ARG] Argument is less than 0");
162
163         __touchCount = count;
164         __maxPointId = __touchCount-1;
165
166         if (__touchCount > DEFAULT_TOUCH_COUNT)
167         {
168                 _Control* pControl = GetControl();
169                 if (pControl && !pControl->IsMultiTouchEnabled())
170                 {
171                         pControl->SetMultiTouchEnabled(true);
172                 }
173         }
174
175         return E_SUCCESS;
176 }
177
178 int
179 _TouchLongPressGestureDetector::GetTouchCount(void) const
180 {
181         return __touchCount;
182 }
183
184 bool
185 _TouchLongPressGestureDetector::IsPressed(void)
186 {
187         bool allPressed = false;
188         for(int i=0; i<__touchCount; i++)
189         {
190                 _LongPressInfo* pLongPressInfo = null;
191                 __pLongPressInfoList->GetAt(i, pLongPressInfo);
192                 if (pLongPressInfo)
193                 {
194                         if (pLongPressInfo->__isPressed && pLongPressInfo->__isInBounds
195                                         && (pLongPressInfo->__touchCount == DEFAULT_TOUCH_COUNT))
196                         {
197                                 allPressed = true;
198                         }
199                         else
200                         {
201                                 allPressed = false;
202                         }
203                 }
204         }
205
206         return allPressed;
207 }
208
209 bool
210 _TouchLongPressGestureDetector::OnTouchPressed(const _Control& source, const _TouchInfo& touchinfo)
211 {
212         if (touchinfo.GetPointId() > __maxPointId || GetDetectorState() != _TOUCH_GESTURE_DETECTOR_STATE_READY )
213         {
214                 return false;
215         }
216
217         _LongPressInfo* pLongPressInfo = null;
218         __pLongPressInfoList->GetAt(touchinfo.GetPointId(), pLongPressInfo);
219         SysTryReturn(NID_UI, pLongPressInfo, false, E_SYSTEM, "[E_SYSTEM] System error occurred. ");
220
221         pLongPressInfo->__isPressed = true;
222         pLongPressInfo->__isInBounds = true;
223         pLongPressInfo->__touchCount++;
224         SysTryReturn(NID_UI, __pLongPressInfoList->SetAt(pLongPressInfo, touchinfo.GetPointId()) == E_SUCCESS,
225                                 false, E_SYSTEM, "[E_SYSTEM] System error occurred.");
226
227         bool allTouched = false;
228         for(int i=0; i<__touchCount; i++)
229         {
230                 _LongPressInfo* pLongPressInfo = null;
231                 __pLongPressInfoList->GetAt(i, pLongPressInfo);
232                 if (pLongPressInfo)
233                 {
234                         if (pLongPressInfo->__isPressed)
235                         {
236                                 allTouched = true;
237                         }
238                         else
239                         {
240                                 allTouched = false;
241                         }
242                 }
243         }
244
245         if (allTouched)
246         {
247                 SetGestureStart(true);
248
249                 __pGestureTimerManager = new (std::nothrow) _TouchGestureTimerManager(*this);
250                 SysTryReturn(NID_UI, __pGestureTimerManager, null, E_SYSTEM, "[E_SYSTEM] System error occurred.");
251
252                 if (__pGestureTimerManager->IsTimerStarted() == false)
253                 {
254                         _Control* pControl = GetControl();
255                         if (!pControl)
256                         {
257                                 SetControl(source);
258                         }
259
260                         if (__pGestureTimerManager->StartTimer(__duration) != E_SUCCESS)
261                         {
262                                 SysLogException(NID_UI, E_SYSTEM, "[E_SYSTEM] LongPress timer is not started.");
263                         }
264                 }
265         }
266
267         return false;
268 }
269
270 bool
271 _TouchLongPressGestureDetector::OnTouchMoved(const _Control& source, const _TouchInfo& touchinfo)
272 {
273         if (touchinfo.GetPointId() > __maxPointId || GetDetectorState() != _TOUCH_GESTURE_DETECTOR_STATE_READY )
274         {
275                 return false;
276         }
277
278         _LongPressInfo* pLongPressInfo = null;
279         __pLongPressInfoList->GetAt(touchinfo.GetPointId(), pLongPressInfo);
280         SysTryReturn(NID_UI, pLongPressInfo, false, E_SYSTEM, "[E_SYSTEM] System error occurred. ");
281
282         if (!pLongPressInfo->__isInBounds)
283         {
284                 return false;
285         }
286
287         _TouchManager* pTouchManager = _TouchManager::GetInstance();
288         SysTryReturn(NID_UI, pTouchManager, false, E_SYSTEM, "[E_SYSTEM] _TouchManager does not exist.");
289
290         Point startPoint(pTouchManager->GetStartPoint(touchinfo.GetPointId()).x, pTouchManager->GetStartPoint(touchinfo.GetPointId()).y);
291         _Control* pControl = GetControl();
292         if (pControl)
293         {
294                 startPoint.x -= pControl->GetAbsoluteBounds().x;
295                 startPoint.y -= pControl->GetAbsoluteBounds().y;
296         }
297
298         if (Math::Abs(startPoint.x- touchinfo.GetCurrentPosition().x) > __moveAllowance
299                 || Math::Abs(startPoint.y - touchinfo.GetCurrentPosition().y) > __moveAllowance)
300         {
301                 pLongPressInfo->__isInBounds = false;
302         }
303         else
304         {
305                 pLongPressInfo->__isInBounds = true;
306         }
307
308         SysTryReturn(NID_UI, __pLongPressInfoList->SetAt(pLongPressInfo, touchinfo.GetPointId()) == E_SUCCESS,
309                                 false, E_SYSTEM, "[E_SYSTEM] System error occurred.");
310
311         return false;
312 }
313
314 bool
315 _TouchLongPressGestureDetector::OnTouchReleased(const _Control& source, const _TouchInfo& touchinfo)
316 {
317         if (touchinfo.GetPointId() > __maxPointId || GetDetectorState() != _TOUCH_GESTURE_DETECTOR_STATE_READY )
318         {
319                 return false;
320         }
321
322         _LongPressInfo* pLongPressInfo = null;
323         __pLongPressInfoList->GetAt(touchinfo.GetPointId(), pLongPressInfo);
324         SysTryReturn(NID_UI, pLongPressInfo, false, E_SYSTEM, "[E_SYSTEM] System error occurred. ");
325
326         pLongPressInfo->__isPressed = false;
327         pLongPressInfo->__isInBounds = false;
328
329         SysTryReturn(NID_UI, __pLongPressInfoList->SetAt(pLongPressInfo, touchinfo.GetPointId()) == E_SUCCESS,
330                         false, E_SYSTEM, "[E_SYSTEM] System error occurred.");
331
332         //when touch is released not expired timer -> failed
333         if (IsGestureStarted() && __pGestureTimerManager != null && !__pGestureTimerManager->IsTimerExpired())
334         {
335                 __pGestureTimerManager->CancelTimer();
336
337                 delete __pGestureTimerManager;
338                 __pGestureTimerManager = null;
339
340                 SetDetectorState(_TOUCH_GESTURE_DETECTOR_STATE_FAILED);
341                 ClearLongPressInfoList();
342         }
343
344         return false;
345 }
346
347 bool
348 _TouchLongPressGestureDetector::OnTouchCanceled(const _Control& source, const _TouchInfo& touchinfo)
349 {
350         ClearLongPressInfoList();
351
352         if (__pGestureTimerManager != null && __pGestureTimerManager->IsTimerExpired() == false)
353         {
354                 __pGestureTimerManager->CancelTimer();
355
356                 delete __pGestureTimerManager;
357                 __pGestureTimerManager = null;
358         }
359
360         return false;
361 }
362
363 void
364 _TouchLongPressGestureDetector::ClearLongPressInfoList(void)
365 {
366         for(int i=0; i < MAX_TOUCH_COUNT; i++)
367         {
368                 _LongPressInfo* pLongPressInfo = null;
369                 __pLongPressInfoList->GetAt(i, pLongPressInfo);
370                 if (!pLongPressInfo)
371                 {
372                         continue;
373                 }
374
375                 pLongPressInfo->__isPressed = false;
376                 pLongPressInfo->__touchCount = 0;
377                 pLongPressInfo->__isInBounds = false;
378
379                 __pLongPressInfoList->SetAt(pLongPressInfo, i);
380         }
381 }
382
383 } } // Tizen::Ui
384