fixed bug (TapGesture improvement)
[platform/framework/native/uifw.git] / src / ui / FUi_UiTouchEvent.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_UiTouchEvent.cpp
19  * @brief               This is the implementation file for the _UiTouchEvent class.
20  */
21
22 #include <FBaseResult.h>
23 #include <FBaseColIEnumeratorT.h>
24 #include <FBaseSysLog.h>
25 #include "FUi_UiTouchEvent.h"
26 #include "FUi_ITouchEventListener.h"
27 #include "FUi_ITouchEventPreviewer.h"
28 #include "FUi_Control.h"
29 #include "FUi_ControlManager.h"
30 #include "FUi_TouchGestureDetector.h"
31 #include "FUi_TouchManager.h"
32 #include "FUi_ITouchGestureDelegate.h"
33 #include "FUi_ControlImpl.h"
34 #include "FUi_TouchEventArg.h"
35 #include "FUi_ControlManager.h"
36 #include "FUi_CoordinateSystemUtils.h"
37
38 extern "C" {
39 extern void _UiPrintControl(const Tizen::Ui::_Control& control, bool printChildren);
40 }
41
42
43 using namespace std::tr1;
44 using namespace Tizen::Base::Collection;
45 using namespace Tizen::Graphics;
46
47 namespace Tizen { namespace Ui
48 {
49 _TouchInfo::_TouchInfo(void)
50         : __pointId(0)
51         , __touchStatus(_TOUCH_PRESSED)
52         , __currentPosition(0, 0)
53         , __isFlicked(false)
54         , __timeStamp(0)
55 {
56 }
57
58 _TouchInfo::_TouchInfo(unsigned long pointId, _TouchStatus status, const Tizen::Graphics::Point& current, const bool isFlick, long long timeStamp)
59         : __pointId(pointId)
60         , __touchStatus(status)
61         , __isFlicked(isFlick)
62         , __timeStamp(timeStamp)
63 {
64         __currentPosition = _CoordinateSystemUtils::ConvertToFloat(current);
65 }
66
67 _TouchInfo::_TouchInfo(unsigned long pointId, _TouchStatus status, const Tizen::Graphics::FloatPoint& current, const bool isFlick, long long timeStamp)
68         : __pointId(pointId)
69         , __touchStatus(status)
70         , __currentPosition(current)
71         , __isFlicked(isFlick)
72         , __timeStamp(timeStamp)
73 {
74 }
75
76 _TouchInfo::_TouchInfo(const _TouchInfo& rhs)
77         : __pointId(rhs.__pointId)
78         , __touchStatus(rhs.__touchStatus)
79         , __currentPosition(rhs.__currentPosition)
80         , __isFlicked(rhs.__isFlicked)
81         , __timeStamp(rhs.__timeStamp)
82 {
83 }
84
85 _TouchInfo&
86 _TouchInfo::operator =(const _TouchInfo& rhs)
87 {
88         if (this != &rhs)
89         {
90                 __pointId = rhs.__pointId;
91                 __touchStatus = rhs.__touchStatus;
92                 __currentPosition = rhs.__currentPosition;
93                 __isFlicked = rhs.__isFlicked;
94                 __timeStamp = rhs.__timeStamp;
95         }
96
97         return *this;
98 }
99
100 _TouchInfo::~_TouchInfo(void)
101 {
102 }
103
104 _TouchStatus
105 _TouchInfo::GetTouchStatus(void) const
106 {
107         return __touchStatus;
108 }
109
110 Tizen::Graphics::FloatPoint
111 _TouchInfo::GetCurrentPosition(void) const
112 {
113         return __currentPosition;
114 }
115
116 unsigned long
117 _TouchInfo::GetPointId(void) const
118 {
119         return __pointId;
120 }
121
122 bool
123 _TouchInfo::IsFlicked(void) const
124 {
125         return __isFlicked;
126 }
127
128 long long
129 _TouchInfo::GetTimeStamp(void) const
130 {
131         return __timeStamp;
132 }
133
134 void
135 _TouchInfo::SetTouchInfo(unsigned long pointId, _TouchStatus status, Tizen::Graphics::Point& current, bool isFlick, long long timeStamp)
136 {
137         __pointId = pointId;
138         __touchStatus = status;
139         __currentPosition = _CoordinateSystemUtils::ConvertToFloat(current);
140         __isFlicked = isFlick;
141         __timeStamp = timeStamp;
142 }
143
144 void
145 _TouchInfo::SetTouchInfo(unsigned long pointId, _TouchStatus status, Tizen::Graphics::FloatPoint& current, bool isFlick, long long timeStamp)
146 {
147         __pointId = pointId;
148         __touchStatus = status;
149         __currentPosition = current;
150         __isFlicked = isFlick;
151         __timeStamp = timeStamp;
152 }
153
154 _UiTouchEvent::_UiTouchEvent(const _UiObjectHandle& destination, const _TouchInfo& touchInfo, _UiEventRouteType routeType, const _UiObjectHandle& source)
155         : _UiEvent(destination, source, routeType)
156         , __touchInfo(touchInfo)
157         , __pForcedControlList(new (std::nothrow) LinkedListT<_Control*>)
158 {
159 }
160
161 _UiTouchEvent::~_UiTouchEvent(void)
162 {
163 }
164
165 _UiTouchEvent::_UiTouchEvent(const _UiTouchEvent& rhs)
166         : _UiEvent(rhs)
167         , __touchInfo(rhs.__touchInfo)
168         , __pForcedControlList(rhs.__pForcedControlList)
169 {
170 }
171
172 _UiTouchEvent&
173 _UiTouchEvent::operator =(const _UiTouchEvent& rhs)
174 {
175         _UiEvent::operator =(rhs);
176
177         if (this != &rhs)
178         {
179                 __touchInfo = rhs.__touchInfo;
180                 __pForcedControlList = rhs.__pForcedControlList;
181         }
182
183         return *this;
184 }
185
186 const _TouchInfo*
187 _UiTouchEvent::GetTouchInfo(void) const
188 {
189         return &__touchInfo;
190 }
191
192 _UiTouchEvent*
193 _UiTouchEvent::CloneN(void) const
194 {
195         return new (std::nothrow) _UiTouchEvent(*this);
196 }
197
198 _UiEventType
199 _UiTouchEvent::GetEventType(void) const
200 {
201         return _UI_EVENT_TOUCH;
202 }
203
204 bool
205 _UiTouchEvent::IsEventEnabled(const _Control& control) const
206 {
207         if (!_UiEvent::IsEventEnabled(control))
208         {
209                 return false;
210         }
211
212         if (!control.IsInputEventEnabled())
213         {
214                 return false;
215         }
216
217         return true;
218 }
219
220 result
221 _UiTouchEvent::OnPreviewEventProcessing(const _Control& control, bool& isFiltered)
222 {
223         result r = E_SUCCESS;
224
225         const _TouchInfo* pTouchInfo = GetTouchInfo();
226         SysTryReturn(NID_UI, pTouchInfo, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
227
228         if ((!ExistGlobalGesture() || GetAccessibilityEvent()) && !isFiltered)
229         {
230                 _ITouchEventPreviewer* pTouchEventPreviewer = control.GetPropagatedTouchEventListener();
231                 SysTryReturn(NID_UI, pTouchEventPreviewer, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
232
233                 r = FirePreviewListener(pTouchEventPreviewer, &control, isFiltered);
234         }
235
236         return r;
237 }
238
239 result
240 _UiTouchEvent::OnEventProcessing(const _Control& control, bool& isFiltered)
241 {
242         result r = E_SUCCESS;
243
244         bool doesControlExist = false;
245
246         const _TouchInfo* pTouchInfo = GetTouchInfo();
247         SysTryReturn(NID_UI, pTouchInfo, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
248
249         if ((!ExistGlobalGesture() || GetAccessibilityEvent()) && !isFiltered)
250         {
251                 ProcessGesture(control, isFiltered);
252         }
253         else if (isFiltered)
254         {
255                 doesControlExist = __pForcedControlList->Contains(const_cast<_Control*>(&control));
256
257                 if (doesControlExist)
258                 {
259                         bool isForcedFiltered = false;
260                         ProcessGesture(control, isForcedFiltered);
261
262                         if (isForcedFiltered)
263                         {
264                                 isFiltered = true;
265                         }
266                 }
267         }
268
269         if (!ExistGlobalGesture() || GetAccessibilityEvent())
270         {
271                 if(!isFiltered || doesControlExist)
272                 {
273                         _ITouchEventListener* pTouchEventListener = control.GetPropagatedTouchEventListener();
274                         SysTryReturn(NID_UI, pTouchEventListener, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
275
276                         r = FireListener(pTouchEventListener, &control, true, isFiltered);
277                 }
278         }
279
280         return r;
281 }
282
283 result
284 _UiTouchEvent::OnListenerProcessing(const _IUiEventListener& listener, bool& isFiltered)
285 {
286         _ITouchEventListener* pTouchEventListener = dynamic_cast <_ITouchEventListener*>(const_cast <_IUiEventListener*>(&listener));
287         SysTryReturn(NID_UI, pTouchEventListener, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
288
289         return FireListener(pTouchEventListener, null, true, isFiltered);
290 }
291
292 result
293 _UiTouchEvent::OnEventHandled(const _Control& control)
294 {
295         _Control* pTarget = const_cast<_Control*>(GetControl(GetDestination()));
296         SysTryReturn(NID_UI, pTarget, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
297
298         const _TouchInfo* pTouchInfo = GetTouchInfo();
299         SysTryReturn(NID_UI, pTouchInfo, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
300
301         result r = E_SUCCESS;
302
303         switch (pTouchInfo->GetTouchStatus())
304         {
305         case _TOUCH_PRESSED:
306                 pTarget->GetPropagatedTouchEventListener()->OnTouchPressHandled(control);
307                 break;
308
309         case _TOUCH_MOVED:
310                 pTarget->GetPropagatedTouchEventListener()->OnTouchMoveHandled(control);
311                 break;
312
313         case _TOUCH_RELEASED:
314                 pTarget->GetPropagatedTouchEventListener()->OnTouchReleaseHandled(control);
315                 break;
316
317         case _TOUCH_CANCELED:
318                 pTarget->GetPropagatedTouchEventListener()->OnTouchCancelHandled(control);
319                 break;
320
321         default:
322                 r = E_SYSTEM;
323                 break;
324         }
325
326         return r;
327 }
328
329 result
330 _UiTouchEvent::FireListener(const _ITouchEventListener* pListener, const _Control* pControl,  bool isTouchEvent, bool& isFiltered)
331 {
332         _ITouchEventListener* pTouchEventListener = const_cast <_ITouchEventListener*>(pListener);
333         SysTryReturn(NID_UI, pTouchEventListener, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
334
335         result r = E_SUCCESS;
336
337         const _TouchInfo* pTouchInfo = GetTouchInfo();
338         SysTryReturn(NID_UI, pTouchInfo, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
339
340         const _Control* pTarget = GetControl(GetOriginalDestination());
341         if (pTarget == null)
342         {
343                 SysLog(NID_UI, "pTarget == null, Call ResetTouchInfo.");
344                 _TouchManager* pTouchManager = _TouchManager::GetInstance();
345                 pTouchManager->ResetTouchInfo();
346
347                 return E_SUCCESS;
348
349 }
350
351         if (ResetTouchInfo(pTarget, *pTouchInfo) == E_SUCCESS)
352         {
353                 isFiltered = true;
354                 return E_SYSTEM;
355         }
356
357         FloatPoint point(0, 0);
358
359         if (pControl)
360         {
361                 _TouchManager* pTouchManager = _TouchManager::GetInstance();
362                 SysAssert(pTouchManager != null)
363
364                 point = GetRelativePoint(*pControl, pTouchInfo->GetCurrentPosition());
365
366                 if (isTouchEvent && (pTouchInfo->GetTouchStatus() != _TOUCH_CANCELED))
367                 {
368                         if (!pTouchManager->IsTouchAllowed() || (pTouchManager->IsTouchAllowed() && pTouchManager->IsTouchCanceledOnGestureSuccess())
369                                 || (!pControl->IsMultiTouchEnabled() && pTouchInfo->GetPointId() > 0))
370                         {
371                                 isFiltered = true;
372                                 return E_SUCCESS;
373                         }
374                 }
375         }
376         else
377         {
378                 point = GetRelativePoint(*pTarget, pTouchInfo->GetCurrentPosition());
379         }
380
381         _TouchInfo touchInfo(pTouchInfo->GetPointId(), pTouchInfo->GetTouchStatus(), point, false, pTouchInfo->GetTimeStamp());
382
383         switch (touchInfo.GetTouchStatus())
384         {
385         case _TOUCH_PRESSED:
386                 isFiltered = pTouchEventListener->OnTouchPressed(*pTarget, touchInfo);
387                 break;
388
389         case _TOUCH_RELEASED:
390                 isFiltered = pTouchEventListener->OnTouchReleased(*pTarget, touchInfo);
391                 break;
392
393         case _TOUCH_MOVED:
394                 isFiltered = pTouchEventListener->OnTouchMoved(*pTarget, touchInfo);
395                 break;
396
397                 // 2.0 compatibility for touch simulate
398         case _TOUCH_LONG_PRESSED:
399                 // fall through
400         case _TOUCH_DOUBLE_PRESSED:
401                 {
402                         void* pData = pTarget->GetUserData();
403                         if (pData)
404                         {
405                                 _ControlImpl* pTargetImpl = static_cast<_ControlImpl*>(pData);
406                         if (pTargetImpl)
407                         {
408                                 pTargetImpl->GenerateTouchEvent(touchInfo);
409                         }
410                 }
411                 }
412                 break;
413
414         case _TOUCH_CANCELED:
415                 isFiltered = pTouchEventListener->OnTouchCanceled(*pTarget, touchInfo);
416                 break;
417
418         default:
419                 r = E_SYSTEM;
420         }
421
422         if (isFiltered)
423         {
424                 if (pControl)
425                 {
426                         SysLog(NID_UI, "Event Consumed : isFiltered is True : pControl %x", pControl);
427                         //_UiPrintControl(*pControl, false);
428                 }
429                 SysLog(NID_UI, "Event Consumed : isFiltered is True : pTarget %x", pTarget);
430         }
431
432         return r;
433 }
434
435 result
436 _UiTouchEvent::FirePreviewListener(const _ITouchEventPreviewer* pListener, const _Control* pControl, bool& isFiltered)
437 {
438         _ITouchEventPreviewer* pTouchEventPreviewer = const_cast <_ITouchEventPreviewer*>(pListener);
439         SysTryReturn(NID_UI, pTouchEventPreviewer, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
440
441         result r = E_SUCCESS;
442
443         const _TouchInfo* pTouchInfo = GetTouchInfo();
444         SysTryReturn(NID_UI, pTouchInfo, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
445
446         const _Control* pTarget = GetControl(GetDestination());
447
448         FloatPoint point = GetRelativePoint(*pControl, pTouchInfo->GetCurrentPosition());
449
450         if (!pControl->IsMultiTouchEnabled() && pTouchInfo->GetPointId() > 0)
451         {
452                 isFiltered = false;
453                 return E_SUCCESS;
454         }
455
456         _TouchInfo touchInfo(pTouchInfo->GetPointId(), pTouchInfo->GetTouchStatus(), point, false, pTouchInfo->GetTimeStamp());
457
458         _UiTouchEventDelivery eventDelivery = _UI_TOUCH_EVENT_DELIVERY_NO;
459
460         //condition 1) if target is not enabled multi touch, point id should be 0
461         //2) target is enabled multi touch
462         switch (touchInfo.GetTouchStatus())
463         {
464         case _TOUCH_PRESSED:
465                 eventDelivery = pTouchEventPreviewer->OnPreviewTouchPressed(*pTarget, touchInfo);
466
467                 break;
468
469         case _TOUCH_RELEASED:
470                 eventDelivery = pTouchEventPreviewer->OnPreviewTouchReleased(*pTarget, touchInfo);
471
472                 break;
473
474         case _TOUCH_MOVED:
475                 eventDelivery = pTouchEventPreviewer->OnPreviewTouchMoved(*pTarget, touchInfo);
476
477                 break;
478
479         case _TOUCH_CANCELED:
480                 eventDelivery = pTouchEventPreviewer->OnPreviewTouchCanceled(*pTarget, touchInfo);
481                 break;
482
483         default:
484                 r = E_SYSTEM;
485                 break;
486         }
487
488         if (eventDelivery != _UI_TOUCH_EVENT_DELIVERY_NO)
489         {
490                 // isFiltered = (eventDelivery == _UI_TOUCH_EVENT_DELIVERY_FORCED_YES);
491
492                 // if (isFiltered)
493                 if (eventDelivery == _UI_TOUCH_EVENT_DELIVERY_FORCED_YES)
494                 {
495                         __pForcedControlList->Add(const_cast<_Control*>(pControl));
496                 }
497         }
498         else
499         {
500                 isFiltered = true;
501         }
502
503         return r;
504 }
505
506 result
507 _UiTouchEvent::ProcessGesture(const _Control& control, bool& isFiltered)
508 {
509         if (control.IsSendingDelayedEvent())
510         {
511                 return E_SUCCESS;
512         }
513
514         IListT<_TouchGestureDetector*>* pGestureList = control.GetGestureDetectorList();
515         if (!pGestureList || (pGestureList && (pGestureList->GetCount() <= 0)))
516         {
517                 return E_SUCCESS;
518         }
519
520         IEnumeratorT<_TouchGestureDetector*>* pEnumerator = pGestureList->GetEnumeratorN();
521         SysTryReturn(NID_UI, pEnumerator, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
522
523         while (pEnumerator->MoveNext() == E_SUCCESS)
524         {
525                 _TouchGestureDetector* pGestureDetector = null;
526                 pEnumerator->GetCurrent(pGestureDetector);
527
528                 if (!pGestureDetector)
529                 {
530                         continue;
531                 }
532
533                 _ITouchGestureDelegate* pDelegator = pGestureDetector->GetDelegate();
534                 if (pDelegator)
535                 {
536                         FireListener(pDelegator, &control, false, isFiltered);
537                 }
538         }
539
540         delete pEnumerator;
541         return E_SUCCESS;
542 }
543
544 FloatPoint
545 _UiTouchEvent::GetRelativePoint(const _Control& control, const FloatPoint& point) const
546 {
547         FloatPoint relativePoint(point);
548         FloatRectangle absRect = control.GetAbsoluteBoundsF();
549
550         relativePoint.x -= absRect.x;
551         relativePoint.y -= absRect.y;
552
553         return relativePoint;
554 }
555
556 result
557 _UiTouchEvent::ResetTouchInfo(const _Control* pControl, const _TouchInfo& touchInfo)
558 {
559         _TouchManager* pTouchManager = _TouchManager::GetInstance();
560         SysTryReturnResult(NID_UI, pTouchManager, E_SYSTEM, "[E_SYSTEM] System error occurred. ");
561
562         if (pControl == null)
563         {
564                 if (touchInfo.GetTouchStatus() == _TOUCH_RELEASED)
565                 {
566                         pTouchManager->ResetTouchInfo();
567                 }
568
569                 return E_SUCCESS;
570         }
571
572         return E_INVALID_CONDITION;
573 }
574
575 bool
576 _UiTouchEvent::ExistGlobalGesture(void)
577 {
578         _ControlManager* pControlManager = _ControlManager::GetInstance();
579         SysTryReturn(NID_UI, pControlManager, false, E_SYSTEM, "[E_SYSTEM] System error occurred.");
580
581         bool exist = false;
582
583         IListT<_TouchGestureDetector*>* pGestureList = pControlManager->GetGestureDetectorList();
584         if (pGestureList && (pGestureList->GetCount() > 0))
585         {
586                 exist = true;
587         }
588
589         return exist;
590 }
591
592 }} // Tizen::Ui