Merge "fixed bug (TapGesture improvement)" into tizen_2.1
[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 (GetTouchInfo()->GetTouchStatus() != _TOUCH_CANCELED)
213         {
214                 if (!control.IsInputEventEnabled())
215                 {
216                         return false;
217                 }
218         }
219
220         return true;
221 }
222
223 result
224 _UiTouchEvent::OnPreviewEventProcessing(const _Control& control, bool& isFiltered)
225 {
226         result r = E_SUCCESS;
227
228         const _TouchInfo* pTouchInfo = GetTouchInfo();
229         SysTryReturn(NID_UI, pTouchInfo, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
230
231         if ((!ExistGlobalGesture() || GetAccessibilityEvent()) && !isFiltered)
232         {
233                 _ITouchEventPreviewer* pTouchEventPreviewer = control.GetPropagatedTouchEventListener();
234                 SysTryReturn(NID_UI, pTouchEventPreviewer, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
235
236                 r = FirePreviewListener(pTouchEventPreviewer, &control, isFiltered);
237         }
238
239         return r;
240 }
241
242 result
243 _UiTouchEvent::OnEventProcessing(const _Control& control, bool& isFiltered)
244 {
245         result r = E_SUCCESS;
246
247         bool doesControlExist = false;
248
249         const _TouchInfo* pTouchInfo = GetTouchInfo();
250         SysTryReturn(NID_UI, pTouchInfo, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
251
252         if ((!ExistGlobalGesture() || GetAccessibilityEvent()) && !isFiltered)
253         {
254                 ProcessGesture(control, isFiltered);
255         }
256         else if (isFiltered)
257         {
258                 doesControlExist = __pForcedControlList->Contains(const_cast<_Control*>(&control));
259
260                 if (doesControlExist)
261                 {
262                         bool isForcedFiltered = false;
263                         ProcessGesture(control, isForcedFiltered);
264
265                         if (isForcedFiltered)
266                         {
267                                 isFiltered = true;
268                         }
269                 }
270         }
271
272         if (!ExistGlobalGesture() || GetAccessibilityEvent())
273         {
274                 if(!isFiltered || doesControlExist)
275                 {
276                         _ITouchEventListener* pTouchEventListener = control.GetPropagatedTouchEventListener();
277                         SysTryReturn(NID_UI, pTouchEventListener, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
278
279                         r = FireListener(pTouchEventListener, &control, true, isFiltered);
280                 }
281         }
282
283         return r;
284 }
285
286 result
287 _UiTouchEvent::OnListenerProcessing(const _IUiEventListener& listener, bool& isFiltered)
288 {
289         _ITouchEventListener* pTouchEventListener = dynamic_cast <_ITouchEventListener*>(const_cast <_IUiEventListener*>(&listener));
290         SysTryReturn(NID_UI, pTouchEventListener, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
291
292         return FireListener(pTouchEventListener, null, true, isFiltered);
293 }
294
295 result
296 _UiTouchEvent::OnEventHandled(const _Control& control)
297 {
298         _Control* pTarget = const_cast<_Control*>(GetControl(GetDestination()));
299         SysTryReturn(NID_UI, pTarget, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
300
301         const _TouchInfo* pTouchInfo = GetTouchInfo();
302         SysTryReturn(NID_UI, pTouchInfo, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
303
304         result r = E_SUCCESS;
305
306         switch (pTouchInfo->GetTouchStatus())
307         {
308         case _TOUCH_PRESSED:
309                 pTarget->GetPropagatedTouchEventListener()->OnTouchPressHandled(control);
310                 break;
311
312         case _TOUCH_MOVED:
313                 pTarget->GetPropagatedTouchEventListener()->OnTouchMoveHandled(control);
314                 break;
315
316         case _TOUCH_RELEASED:
317                 pTarget->GetPropagatedTouchEventListener()->OnTouchReleaseHandled(control);
318                 break;
319
320         case _TOUCH_CANCELED:
321                 pTarget->GetPropagatedTouchEventListener()->OnTouchCancelHandled(control);
322                 break;
323
324         default:
325                 r = E_SYSTEM;
326                 break;
327         }
328
329         return r;
330 }
331
332 result
333 _UiTouchEvent::FireListener(const _ITouchEventListener* pListener, const _Control* pControl,  bool isTouchEvent, bool& isFiltered)
334 {
335         _ITouchEventListener* pTouchEventListener = const_cast <_ITouchEventListener*>(pListener);
336         SysTryReturn(NID_UI, pTouchEventListener, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
337
338         result r = E_SUCCESS;
339
340         const _TouchInfo* pTouchInfo = GetTouchInfo();
341         SysTryReturn(NID_UI, pTouchInfo, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
342
343         const _Control* pTarget = GetControl(GetOriginalDestination());
344         if (pTarget == null)
345         {
346                 SysLog(NID_UI, "pTarget == null, Call ResetTouchInfo.");
347                 _TouchManager* pTouchManager = _TouchManager::GetInstance();
348                 pTouchManager->ResetTouchInfo();
349
350                 return E_SUCCESS;
351
352 }
353
354         if (ResetTouchInfo(pTarget, *pTouchInfo) == E_SUCCESS)
355         {
356                 isFiltered = true;
357                 return E_SYSTEM;
358         }
359
360         FloatPoint point(0, 0);
361
362         if (pControl)
363         {
364                 _TouchManager* pTouchManager = _TouchManager::GetInstance();
365                 SysAssert(pTouchManager != null)
366
367                 point = GetRelativePoint(*pControl, pTouchInfo->GetCurrentPosition());
368
369                 if (isTouchEvent && (pTouchInfo->GetTouchStatus() != _TOUCH_CANCELED))
370                 {
371                         if (!pTouchManager->IsTouchAllowed() || (pTouchManager->IsTouchAllowed() && pTouchManager->IsTouchCanceledOnGestureSuccess())
372                                 || (!pControl->IsMultiTouchEnabled() && pTouchInfo->GetPointId() > 0))
373                         {
374                                 isFiltered = true;
375                                 return E_SUCCESS;
376                         }
377                 }
378         }
379         else
380         {
381                 point = GetRelativePoint(*pTarget, pTouchInfo->GetCurrentPosition());
382         }
383
384         _TouchInfo touchInfo(pTouchInfo->GetPointId(), pTouchInfo->GetTouchStatus(), point, false, pTouchInfo->GetTimeStamp());
385
386         switch (touchInfo.GetTouchStatus())
387         {
388         case _TOUCH_PRESSED:
389                 isFiltered = pTouchEventListener->OnTouchPressed(*pTarget, touchInfo);
390                 break;
391
392         case _TOUCH_RELEASED:
393                 isFiltered = pTouchEventListener->OnTouchReleased(*pTarget, touchInfo);
394                 break;
395
396         case _TOUCH_MOVED:
397                 isFiltered = pTouchEventListener->OnTouchMoved(*pTarget, touchInfo);
398                 break;
399
400                 // 2.0 compatibility for touch simulate
401         case _TOUCH_LONG_PRESSED:
402                 // fall through
403         case _TOUCH_DOUBLE_PRESSED:
404                 {
405                         void* pData = pTarget->GetUserData();
406                         if (pData)
407                         {
408                                 _ControlImpl* pTargetImpl = static_cast<_ControlImpl*>(pData);
409                         if (pTargetImpl)
410                         {
411                                 pTargetImpl->GenerateTouchEvent(touchInfo);
412                         }
413                 }
414                 }
415                 break;
416
417         case _TOUCH_CANCELED:
418                 isFiltered = pTouchEventListener->OnTouchCanceled(*pTarget, touchInfo);
419                 break;
420
421         default:
422                 r = E_SYSTEM;
423         }
424
425         if (isFiltered)
426         {
427                 if (pControl)
428                 {
429                         SysLog(NID_UI, "Event Consumed : isFiltered is True : pControl %x", pControl);
430                         //_UiPrintControl(*pControl, false);
431                 }
432                 SysLog(NID_UI, "Event Consumed : isFiltered is True : pTarget %x", pTarget);
433         }
434
435         return r;
436 }
437
438 result
439 _UiTouchEvent::FirePreviewListener(const _ITouchEventPreviewer* pListener, const _Control* pControl, bool& isFiltered)
440 {
441         _ITouchEventPreviewer* pTouchEventPreviewer = const_cast <_ITouchEventPreviewer*>(pListener);
442         SysTryReturn(NID_UI, pTouchEventPreviewer, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
443
444         result r = E_SUCCESS;
445
446         const _TouchInfo* pTouchInfo = GetTouchInfo();
447         SysTryReturn(NID_UI, pTouchInfo, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
448
449         const _Control* pTarget = GetControl(GetDestination());
450
451         FloatPoint point = GetRelativePoint(*pControl, pTouchInfo->GetCurrentPosition());
452
453         if (!pControl->IsMultiTouchEnabled() && pTouchInfo->GetPointId() > 0)
454         {
455                 isFiltered = false;
456                 return E_SUCCESS;
457         }
458
459         _TouchInfo touchInfo(pTouchInfo->GetPointId(), pTouchInfo->GetTouchStatus(), point, false, pTouchInfo->GetTimeStamp());
460
461         _UiTouchEventDelivery eventDelivery = _UI_TOUCH_EVENT_DELIVERY_NO;
462
463         //condition 1) if target is not enabled multi touch, point id should be 0
464         //2) target is enabled multi touch
465         switch (touchInfo.GetTouchStatus())
466         {
467         case _TOUCH_PRESSED:
468                 eventDelivery = pTouchEventPreviewer->OnPreviewTouchPressed(*pTarget, touchInfo);
469
470                 break;
471
472         case _TOUCH_RELEASED:
473                 eventDelivery = pTouchEventPreviewer->OnPreviewTouchReleased(*pTarget, touchInfo);
474
475                 break;
476
477         case _TOUCH_MOVED:
478                 eventDelivery = pTouchEventPreviewer->OnPreviewTouchMoved(*pTarget, touchInfo);
479
480                 break;
481
482         case _TOUCH_CANCELED:
483                 eventDelivery = pTouchEventPreviewer->OnPreviewTouchCanceled(*pTarget, touchInfo);
484                 break;
485
486         default:
487                 r = E_SYSTEM;
488                 break;
489         }
490
491         if (eventDelivery != _UI_TOUCH_EVENT_DELIVERY_NO)
492         {
493                 // isFiltered = (eventDelivery == _UI_TOUCH_EVENT_DELIVERY_FORCED_YES);
494
495                 // if (isFiltered)
496                 if (eventDelivery == _UI_TOUCH_EVENT_DELIVERY_FORCED_YES)
497                 {
498                         __pForcedControlList->Add(const_cast<_Control*>(pControl));
499                 }
500         }
501         else
502         {
503                 isFiltered = true;
504         }
505
506         return r;
507 }
508
509 result
510 _UiTouchEvent::ProcessGesture(const _Control& control, bool& isFiltered)
511 {
512         if (control.IsSendingDelayedEvent())
513         {
514                 return E_SUCCESS;
515         }
516
517         IListT<_TouchGestureDetector*>* pGestureList = control.GetGestureDetectorList();
518         if (!pGestureList || (pGestureList && (pGestureList->GetCount() <= 0)))
519         {
520                 return E_SUCCESS;
521         }
522
523         IEnumeratorT<_TouchGestureDetector*>* pEnumerator = pGestureList->GetEnumeratorN();
524         SysTryReturn(NID_UI, pEnumerator, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occurred.");
525
526         while (pEnumerator->MoveNext() == E_SUCCESS)
527         {
528                 _TouchGestureDetector* pGestureDetector = null;
529                 pEnumerator->GetCurrent(pGestureDetector);
530
531                 if (!pGestureDetector)
532                 {
533                         continue;
534                 }
535
536                 _ITouchGestureDelegate* pDelegator = pGestureDetector->GetDelegate();
537                 if (pDelegator)
538                 {
539                         FireListener(pDelegator, &control, false, isFiltered);
540                 }
541         }
542
543         delete pEnumerator;
544         return E_SUCCESS;
545 }
546
547 FloatPoint
548 _UiTouchEvent::GetRelativePoint(const _Control& control, const FloatPoint& point) const
549 {
550         FloatPoint relativePoint(point);
551         FloatRectangle absRect = control.GetAbsoluteBoundsF();
552
553         relativePoint.x -= absRect.x;
554         relativePoint.y -= absRect.y;
555
556         return relativePoint;
557 }
558
559 result
560 _UiTouchEvent::ResetTouchInfo(const _Control* pControl, const _TouchInfo& touchInfo)
561 {
562         _TouchManager* pTouchManager = _TouchManager::GetInstance();
563         SysTryReturnResult(NID_UI, pTouchManager, E_SYSTEM, "[E_SYSTEM] System error occurred. ");
564
565         if (pControl == null)
566         {
567                 if (touchInfo.GetTouchStatus() == _TOUCH_RELEASED)
568                 {
569                         pTouchManager->ResetTouchInfo();
570                 }
571
572                 return E_SUCCESS;
573         }
574
575         return E_INVALID_CONDITION;
576 }
577
578 bool
579 _UiTouchEvent::ExistGlobalGesture(void)
580 {
581         _ControlManager* pControlManager = _ControlManager::GetInstance();
582         SysTryReturn(NID_UI, pControlManager, false, E_SYSTEM, "[E_SYSTEM] System error occurred.");
583
584         bool exist = false;
585
586         IListT<_TouchGestureDetector*>* pGestureList = pControlManager->GetGestureDetectorList();
587         if (pGestureList && (pGestureList->GetCount() > 0))
588         {
589                 exist = true;
590         }
591
592         return exist;
593 }
594
595 }} // Tizen::Ui