Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-core.git] / dali / internal / event / events / pan-gesture / pan-gesture-processor.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/events/pan-gesture/pan-gesture-processor.h>
20
21 #if defined(DEBUG_ENABLED)
22 #include <sstream>
23 #endif
24
25 // EXTERNAL INCLUDES
26 #include <algorithm>
27
28 // INTERNAL INCLUDES
29 #include <dali/integration-api/debug.h>
30 #include <dali/integration-api/trace.h>
31 #include <dali/internal/event/common/scene-impl.h>
32 #include <dali/internal/event/events/gesture-requests.h>
33 #include <dali/internal/event/events/multi-point-event-util.h>
34 #include <dali/internal/event/events/pan-gesture/pan-gesture-event.h>
35 #include <dali/internal/event/events/pan-gesture/pan-gesture-impl.h>
36 #include <dali/internal/event/events/pan-gesture/pan-gesture-recognizer.h>
37 #include <dali/internal/event/render-tasks/render-task-impl.h>
38 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
39 #include <dali/internal/update/manager/update-manager.h>
40 #include <dali/public-api/actors/actor.h>
41 #include <dali/public-api/common/dali-common.h>
42 #include <dali/public-api/events/pan-gesture.h>
43 #include <dali/public-api/math/vector2.h>
44
45 namespace Dali
46 {
47 namespace Internal
48 {
49 namespace // unnamed namespace
50 {
51 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
52 #if defined(DEBUG_ENABLED)
53 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_PAN_PROCESSOR");
54
55 const char* GESTURE_STATES[6] =
56   {
57     "CLEAR",
58     "STARTED",
59     "CONTINUING",
60     "FINISHED",
61     "CANCELLED",
62     "POSSIBLE"};
63
64 #endif // defined(DEBUG_ENABLED)
65
66 const unsigned long MAXIMUM_TIME_WITH_VALID_LAST_VELOCITY(50u);
67
68 /**
69  * Functor which checks whether the specified actor is attached to the gesture detector.
70  * If the actor is attached, it also checks whether the number of touches of the current pan event
71  * are within the range of that expected by the detector.
72  * It returns true if it is no longer attached or the touches are out of range.
73  * This can be used in remove_if functions.
74  */
75 struct IsNotAttachedAndOutsideTouchesRangeFunctor
76 {
77   /**
78    * Constructor
79    * @param[in]  actor                 The actor to check whether it is attached.
80    * @param[in]  touches               The number of touches in the current pan event.
81    * @param[in]  outsideRangeEmitters  Reference to container where emitters outside of the touches range should be added.
82    */
83   IsNotAttachedAndOutsideTouchesRangeFunctor(Actor* actor, unsigned int touches, GestureDetectorContainer& outsideRangeEmitters)
84   : actorToCheck(actor),
85     numberOfTouches(touches),
86     outsideTouchesRangeEmitters(outsideRangeEmitters)
87   {
88   }
89
90   /**
91    * Returns true if not attached, false if it is still attached.
92    * Additionally, checks if the number of touches has changed and stops sending the pan to a particular
93    * detector if it exceeds the range of that detector.
94    * @param[in]  detector  The detector to check.
95    * @return true, if not attached, false otherwise.
96    */
97   bool operator()(GestureDetector* detector) const
98   {
99     bool remove(!detector->IsAttached(*actorToCheck));
100
101     if(!remove)
102     {
103       PanGestureDetector* panDetector(static_cast<PanGestureDetector*>(detector));
104
105       // Ensure number of touch points is within the range of our emitter. If it isn't then remove
106       // this emitter and add it to the outsideTouchesRangeEmitters container
107       if((numberOfTouches < panDetector->GetMinimumTouchesRequired()) ||
108          (numberOfTouches > panDetector->GetMaximumTouchesRequired()))
109       {
110         remove = true;
111         outsideTouchesRangeEmitters.push_back(detector);
112       }
113     }
114
115     return remove;
116   }
117
118   Actor*                    actorToCheck;                ///< The actor to check whether it is attached or not.
119   unsigned int              numberOfTouches;             ///< The number of touches in the pan event.
120   GestureDetectorContainer& outsideTouchesRangeEmitters; ///< Emitters that are outside of the range of current pan.
121 };
122
123 } // unnamed namespace
124
125 PanGestureProcessor::PanGestureProcessor(SceneGraph::UpdateManager& updateManager)
126 : GestureProcessor(GestureType::PAN),
127   mPanGestureDetectors(),
128   mCurrentPanEmitters(),
129   mCurrentRenderTask(),
130   mPossiblePanPosition(),
131   mMinTouchesRequired(1),
132   mMaxTouchesRequired(1),
133   mMaxMotionEventAge(std::numeric_limits<uint32_t>::max()),
134   mCurrentPanEvent(nullptr),
135   mSceneObject(SceneGraph::PanGesture::New()) // Create scene object to store pan information.
136 {
137   // Pass ownership to scene-graph; scene object lives for the lifecycle of UpdateManager
138   updateManager.SetPanGestureProcessor(mSceneObject);
139 }
140
141 PanGestureProcessor::~PanGestureProcessor()
142 {
143   mSceneObject = nullptr; // mSceneObject is owned and destroyed by update manager (there is only one of these for now)
144 }
145
146 void PanGestureProcessor::Process(Scene& scene, const PanGestureEvent& panEvent)
147 {
148 #if defined(DEBUG_ENABLED)
149   DALI_LOG_TRACE_METHOD(gLogFilter);
150
151   DALI_LOG_INFO(gLogFilter, Debug::General, "    Pan Event\n");
152   DALI_LOG_INFO(gLogFilter, Debug::General, "      State: %s  Touches: %d  Time: %d  TimeDelta: %d\n", GESTURE_STATES[static_cast<uint8_t>(panEvent.state)], panEvent.numberOfTouches, panEvent.time, panEvent.timeDelta);
153   DALI_LOG_INFO(gLogFilter, Debug::General, "      Positions: Current: (%.0f, %.0f), Previous: (%.0f, %.0f)\n", panEvent.currentPosition.x, panEvent.currentPosition.y, panEvent.previousPosition.x, panEvent.previousPosition.y);
154 #endif
155
156   DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_PAN_GESTURE");
157
158   switch(panEvent.state)
159   {
160     case GestureState::POSSIBLE:
161     {
162       mCurrentPanEmitters.clear();
163       ResetActor();
164
165       HitTestAlgorithm::Results hitTestResults;
166       if(HitTest(scene, panEvent.currentPosition, hitTestResults))
167       {
168         SetActor(&GetImplementation(hitTestResults.actor));
169         mPossiblePanPosition = panEvent.currentPosition;
170       }
171       break;
172     }
173
174     case GestureState::STARTED:
175     {
176       // Requires a core update
177       mNeedsUpdate = true;
178
179       // The pan gesture should only be sent to the gesture detector which first received it so that
180       // it can be told when the gesture ends as well.
181
182       HitTestAlgorithm::Results hitTestResults;
183       HitTest(scene, panEvent.previousPosition, hitTestResults); // Hit Test previous position
184
185       if(hitTestResults.actor)
186       {
187         // If the current hit actor is different from the one we touched down on then set accordingly & update initial pan position
188         if(&GetImplementation(hitTestResults.actor) != GetCurrentGesturedActor())
189         {
190           mPossiblePanPosition = panEvent.previousPosition;
191           SetActor(&GetImplementation(hitTestResults.actor));
192         }
193
194         // Record the current render-task for Screen->Actor coordinate conversions
195         mCurrentRenderTask = hitTestResults.renderTask;
196
197         // Set mCurrentPanEvent to use inside overridden methods called in ProcessAndEmit()
198         mCurrentPanEvent = &panEvent;
199         ProcessAndEmit(hitTestResults);
200         mCurrentPanEvent = nullptr;
201       }
202       else
203       {
204         ResetActor();
205         mCurrentPanEmitters.clear();
206       }
207       break;
208     }
209
210     case GestureState::CONTINUING:
211     {
212       // Requires a core update
213       mNeedsUpdate = true;
214
215       DALI_FALLTHROUGH;
216     }
217
218     case GestureState::FINISHED:
219     case GestureState::CANCELLED:
220     {
221       // Only send subsequent pan gesture signals if we processed the pan gesture when it started.
222       // Check if actor is still touchable.
223
224       Actor* currentGesturedActor = GetCurrentGesturedActor();
225       if(currentGesturedActor)
226       {
227         if(currentGesturedActor->IsHittable() && !mCurrentPanEmitters.empty() && mCurrentRenderTask)
228         {
229           GestureDetectorContainer outsideTouchesRangeEmitters;
230
231           // Removes emitters that no longer have the actor attached
232           // Also remove emitters whose touches are outside the range of the current pan event and add them to outsideTouchesRangeEmitters
233           GestureDetectorContainer::iterator endIter = std::remove_if(mCurrentPanEmitters.begin(), mCurrentPanEmitters.end(), IsNotAttachedAndOutsideTouchesRangeFunctor(currentGesturedActor, panEvent.numberOfTouches, outsideTouchesRangeEmitters));
234           mCurrentPanEmitters.erase(endIter, mCurrentPanEmitters.end());
235
236           Vector2 actorCoords;
237
238           if(!outsideTouchesRangeEmitters.empty() || !mCurrentPanEmitters.empty())
239           {
240             currentGesturedActor->ScreenToLocal(*mCurrentRenderTask.Get(), actorCoords.x, actorCoords.y, panEvent.currentPosition.x, panEvent.currentPosition.y);
241
242             // EmitPanSignal checks whether we have a valid actor and whether the container we are passing in has emitters before it emits the pan.
243             EmitPanSignal(currentGesturedActor, outsideTouchesRangeEmitters, panEvent, actorCoords, GestureState::FINISHED, mCurrentRenderTask);
244             EmitPanSignal(currentGesturedActor, mCurrentPanEmitters, panEvent, actorCoords, panEvent.state, mCurrentRenderTask);
245           }
246
247           if(mCurrentPanEmitters.empty())
248           {
249             // If we have no emitters attached then clear pan actor as well.
250             ResetActor();
251           }
252
253           // Clear current gesture detectors if pan gesture has ended or been cancelled.
254           if((panEvent.state == GestureState::FINISHED) || (panEvent.state == GestureState::CANCELLED))
255           {
256             mCurrentPanEmitters.clear();
257             ResetActor();
258           }
259         }
260         else
261         {
262           mCurrentPanEmitters.clear();
263           ResetActor();
264         }
265       }
266       break;
267     }
268
269     case GestureState::CLEAR:
270     {
271       DALI_ABORT("Incorrect state received from Integration layer: CLEAR\n");
272       break;
273     }
274   }
275 }
276
277 void PanGestureProcessor::AddGestureDetector(PanGestureDetector* gestureDetector, Scene& scene, int32_t minDistance, int32_t minPanEvents)
278 {
279   bool firstRegistration(mPanGestureDetectors.empty());
280
281   mPanGestureDetectors.push_back(gestureDetector);
282
283   if(firstRegistration)
284   {
285     mMinTouchesRequired = gestureDetector->GetMinimumTouchesRequired();
286     mMaxTouchesRequired = gestureDetector->GetMaximumTouchesRequired();
287     mMaxMotionEventAge  = gestureDetector->GetMaximumMotionEventAge();
288
289     PanGestureRequest request;
290     request.minTouches        = mMinTouchesRequired;
291     request.maxTouches        = mMaxTouchesRequired;
292     request.maxMotionEventAge = mMaxMotionEventAge;
293
294     Size size          = scene.GetSize();
295     mGestureRecognizer = new PanGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const PanGestureRequest&>(request), minDistance, minPanEvents);
296   }
297   else
298   {
299     UpdateDetection();
300   }
301 }
302
303 void PanGestureProcessor::RemoveGestureDetector(PanGestureDetector* gestureDetector)
304 {
305   if(!mCurrentPanEmitters.empty())
306   {
307     // Check if the removed detector was one that is currently being panned and remove it from emitters.
308     GestureDetectorContainer::iterator endIter = std::remove(mCurrentPanEmitters.begin(), mCurrentPanEmitters.end(), gestureDetector);
309     mCurrentPanEmitters.erase(endIter, mCurrentPanEmitters.end());
310
311     // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
312     if(mCurrentPanEmitters.empty())
313     {
314       ResetActor();
315     }
316   }
317
318   // Find the detector...
319   PanGestureDetectorContainer::iterator endIter = std::remove(mPanGestureDetectors.begin(), mPanGestureDetectors.end(), gestureDetector);
320   DALI_ASSERT_DEBUG(endIter != mPanGestureDetectors.end());
321
322   // ...and remove it
323   mPanGestureDetectors.erase(endIter, mPanGestureDetectors.end());
324
325   if(mPanGestureDetectors.empty())
326   {
327     mGestureRecognizer = nullptr;
328   }
329   else
330   {
331     UpdateDetection();
332   }
333 }
334
335 void PanGestureProcessor::GestureDetectorUpdated(PanGestureDetector* gestureDetector)
336 {
337   DALI_ASSERT_DEBUG(find(mPanGestureDetectors.begin(), mPanGestureDetectors.end(), gestureDetector) != mPanGestureDetectors.end());
338
339   UpdateDetection();
340 }
341
342 bool PanGestureProcessor::SetPanGestureProperties(const Dali::PanGesture& pan)
343 {
344   // If we are currently processing a pan gesture then just ignore
345   if(mCurrentPanEmitters.empty() && mSceneObject)
346   {
347     const PanGesture& panImpl(GetImplementation(pan));
348
349     // We update the scene object directly rather than sending a message.
350     // Sending a message could cause unnecessary delays, the scene object ensure thread safe behaviour.
351     mSceneObject->AddGesture(panImpl);
352
353     if(GestureState::STARTED == panImpl.GetState() || GestureState::CONTINUING == panImpl.GetState())
354     {
355       mNeedsUpdate = true;
356     }
357   }
358
359   return mNeedsUpdate;
360 }
361
362 void PanGestureProcessor::EnableProfiling()
363 {
364   mSceneObject->EnableProfiling();
365 }
366
367 void PanGestureProcessor::SetPredictionMode(int mode)
368 {
369   if((mode < 0) || (mode >= SceneGraph::PanGesture::NUM_PREDICTION_MODES))
370   {
371     mode = SceneGraph::PanGesture::DEFAULT_PREDICTION_MODE;
372   }
373   SceneGraph::PanGesture::PredictionMode modeEnum = static_cast<SceneGraph::PanGesture::PredictionMode>(mode);
374   mSceneObject->SetPredictionMode(modeEnum);
375 }
376
377 void PanGestureProcessor::SetPredictionAmount(unsigned int amount)
378 {
379   mSceneObject->SetPredictionAmount(amount);
380 }
381
382 void PanGestureProcessor::SetMaximumPredictionAmount(unsigned int amount)
383 {
384   mSceneObject->SetMaximumPredictionAmount(amount);
385 }
386
387 void PanGestureProcessor::SetMinimumPredictionAmount(unsigned int amount)
388 {
389   mSceneObject->SetMinimumPredictionAmount(amount);
390 }
391
392 void PanGestureProcessor::SetPredictionAmountAdjustment(unsigned int amount)
393 {
394   mSceneObject->SetPredictionAmountAdjustment(amount);
395 }
396
397 void PanGestureProcessor::SetSmoothingMode(int mode)
398 {
399   if((mode < 0) || (mode >= SceneGraph::PanGesture::NUM_SMOOTHING_MODES))
400   {
401     mode = SceneGraph::PanGesture::DEFAULT_SMOOTHING_MODE;
402   }
403   SceneGraph::PanGesture::SmoothingMode modeEnum = static_cast<SceneGraph::PanGesture::SmoothingMode>(mode);
404   mSceneObject->SetSmoothingMode(modeEnum);
405 }
406
407 void PanGestureProcessor::SetSmoothingAmount(float amount)
408 {
409   mSceneObject->SetSmoothingAmount(amount);
410 }
411
412 void PanGestureProcessor::SetUseActualTimes(bool value)
413 {
414   mSceneObject->SetUseActualTimes(value);
415 }
416
417 void PanGestureProcessor::SetInterpolationTimeRange(int value)
418 {
419   mSceneObject->SetInterpolationTimeRange(value);
420 }
421
422 void PanGestureProcessor::SetScalarOnlyPredictionEnabled(bool value)
423 {
424   mSceneObject->SetScalarOnlyPredictionEnabled(value);
425 }
426
427 void PanGestureProcessor::SetTwoPointPredictionEnabled(bool value)
428 {
429   mSceneObject->SetTwoPointPredictionEnabled(value);
430 }
431
432 void PanGestureProcessor::SetTwoPointInterpolatePastTime(int value)
433 {
434   mSceneObject->SetTwoPointInterpolatePastTime(value);
435 }
436
437 void PanGestureProcessor::SetTwoPointVelocityBias(float value)
438 {
439   mSceneObject->SetTwoPointVelocityBias(value);
440 }
441
442 void PanGestureProcessor::SetTwoPointAccelerationBias(float value)
443 {
444   mSceneObject->SetTwoPointAccelerationBias(value);
445 }
446
447 void PanGestureProcessor::SetMultitapSmoothingRange(int value)
448 {
449   mSceneObject->SetMultitapSmoothingRange(value);
450 }
451
452 const SceneGraph::PanGesture& PanGestureProcessor::GetSceneObject() const
453 {
454   return *mSceneObject;
455 }
456
457 void PanGestureProcessor::UpdateDetection()
458 {
459   DALI_ASSERT_DEBUG(!mPanGestureDetectors.empty());
460
461   uint32_t minimumRequired       = std::numeric_limits<uint32_t>::max();
462   uint32_t maximumRequired       = 0;
463   uint32_t maximumMotionEventAge = std::numeric_limits<uint32_t>::max();
464
465   for(PanGestureDetectorContainer::iterator iter = mPanGestureDetectors.begin(), endIter = mPanGestureDetectors.end(); iter != endIter; ++iter)
466   {
467     PanGestureDetector* detector(*iter);
468
469     if(detector)
470     {
471       uint32_t minimum = detector->GetMinimumTouchesRequired();
472       if(minimum < minimumRequired)
473       {
474         minimumRequired = minimum;
475       }
476
477       uint32_t maximum = detector->GetMaximumTouchesRequired();
478       if(maximum > maximumRequired)
479       {
480         maximumRequired = maximum;
481       }
482
483       uint32_t maximumAge = detector->GetMaximumMotionEventAge();
484       if(maximumAge < maximumMotionEventAge)
485       {
486         maximumMotionEventAge = maximumAge;
487       }
488     }
489   }
490
491   if((minimumRequired != mMinTouchesRequired) || (maximumRequired != mMaxTouchesRequired) || (maximumMotionEventAge != mMaxMotionEventAge))
492   {
493     mMinTouchesRequired = minimumRequired;
494     mMaxTouchesRequired = maximumRequired;
495     mMaxMotionEventAge  = maximumMotionEventAge;
496
497     PanGestureRequest request;
498     request.minTouches        = mMinTouchesRequired;
499     request.maxTouches        = mMaxTouchesRequired;
500     request.maxMotionEventAge = mMaxMotionEventAge;
501     mGestureRecognizer->Update(request);
502   }
503 }
504
505 void PanGestureProcessor::EmitPanSignal(Actor*                          actor,
506                                         const GestureDetectorContainer& gestureDetectors,
507                                         const PanGestureEvent&          panEvent,
508                                         Vector2                         localCurrent,
509                                         GestureState                    state,
510                                         RenderTaskPtr                   renderTask)
511 {
512   if(actor && !gestureDetectors.empty())
513   {
514     Internal::PanGesturePtr pan(new Internal::PanGesture(state));
515
516     pan->SetTime(panEvent.time);
517
518     pan->SetNumberOfTouches(panEvent.numberOfTouches);
519     pan->SetScreenPosition(panEvent.currentPosition);
520     pan->SetPosition(localCurrent);
521     pan->SetSourceType(panEvent.sourceType);
522     pan->SetSourceData(panEvent.sourceData);
523
524     RenderTask& renderTaskImpl(*renderTask.Get());
525
526     Vector2 localPrevious;
527     actor->ScreenToLocal(renderTaskImpl, localPrevious.x, localPrevious.y, panEvent.previousPosition.x, panEvent.previousPosition.y);
528
529     pan->SetDisplacement(localCurrent - localPrevious);
530     Vector2 previousPos(panEvent.previousPosition);
531     if(state == GestureState::STARTED)
532     {
533       previousPos = mPossiblePanPosition;
534     }
535
536     pan->SetScreenDisplacement(panEvent.currentPosition - previousPos);
537
538     // Avoid dividing by 0
539     if(panEvent.timeDelta > 0)
540     {
541       Vector2 velocity;
542       velocity.x = pan->GetDisplacement().x / static_cast<float>(panEvent.timeDelta);
543       velocity.y = pan->GetDisplacement().y / static_cast<float>(panEvent.timeDelta);
544       pan->SetVelocity(velocity);
545
546       Vector2 screenVelocity;
547       screenVelocity.x = pan->GetScreenDisplacement().x / static_cast<float>(panEvent.timeDelta);
548       screenVelocity.y = pan->GetScreenDisplacement().y / static_cast<float>(panEvent.timeDelta);
549       pan->SetScreenVelocity(screenVelocity);
550     }
551
552     // When the gesture ends, we may incorrectly get a ZERO velocity (as we have lifted our finger without any movement)
553     // so we should use the last recorded velocity instead in this scenario.
554     if((state == GestureState::FINISHED) && (pan->GetScreenVelocity() == Vector2::ZERO) &&
555        (panEvent.timeDelta < MAXIMUM_TIME_WITH_VALID_LAST_VELOCITY))
556     {
557       pan->SetVelocity(mLastVelocity);
558       pan->SetScreenVelocity(mLastScreenVelocity);
559     }
560     else
561     {
562       // Store the current velocity for future iterations.
563       mLastVelocity       = pan->GetVelocity();
564       mLastScreenVelocity = pan->GetScreenVelocity();
565     }
566
567     if(mSceneObject)
568     {
569       // We update the scene object directly rather than sending a message.
570       // Sending a message could cause unnecessary delays, the scene object ensure thread safe behaviour.
571       mSceneObject->AddGesture(*pan.Get());
572     }
573
574     DALI_TRACE_SCOPE(gTraceFilter, "DALI_EMIT_PAN_GESTURE_SIGNAL");
575
576     Dali::Actor actorHandle(actor);
577
578     const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
579     for(GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter)
580     {
581       static_cast<PanGestureDetector*>(*iter)->EmitPanGestureSignal(actorHandle, Dali::PanGesture(pan.Get()));
582     }
583   }
584 }
585
586 void PanGestureProcessor::OnGesturedActorStageDisconnection()
587 {
588   mCurrentPanEmitters.clear();
589 }
590
591 bool PanGestureProcessor::CheckGestureDetector(GestureDetector* detector, Actor* actor)
592 {
593   DALI_ASSERT_DEBUG(mCurrentPanEvent);
594
595   bool                retVal(false);
596   PanGestureDetector* panDetector(static_cast<PanGestureDetector*>(detector));
597
598   if((mCurrentPanEvent->numberOfTouches >= panDetector->GetMinimumTouchesRequired()) &&
599      (mCurrentPanEvent->numberOfTouches <= panDetector->GetMaximumTouchesRequired()))
600   {
601     // Check if the detector requires directional panning.
602     if(panDetector->RequiresDirectionalPan() && mCurrentRenderTask)
603     {
604       // It does, calculate the angle of the pan in local actor coordinates and ensures it fits
605       // the detector's criteria.
606       RenderTask& renderTaskImpl = *mCurrentRenderTask.Get();
607
608       Vector2 startPosition, currentPosition;
609       actor->ScreenToLocal(renderTaskImpl, startPosition.x, startPosition.y, mPossiblePanPosition.x, mPossiblePanPosition.y);
610       actor->ScreenToLocal(renderTaskImpl, currentPosition.x, currentPosition.y, mCurrentPanEvent->currentPosition.x, mCurrentPanEvent->currentPosition.y);
611       Vector2 displacement(currentPosition - startPosition);
612
613       Radian angle(atanf(displacement.y / displacement.x));
614
615       /////////////////////////////
616       //            |            //
617       //            |            //
618       //   Q3 (-,-) | Q4 (+,-)   //
619       //            |            //
620       //    ----------------- +x //
621       //            |            //
622       //   Q2 (-,+) | Q1 (+,+)   //
623       //            |            //
624       //            |            //
625       //           +y            //
626       /////////////////////////////
627       // Quadrant 1: As is
628       // Quadrant 2: 180 degrees + angle
629       // Quadrant 3: angle - 180 degrees
630       // Quadrant 4: As is
631       /////////////////////////////
632
633       if(displacement.x < 0.0f)
634       {
635         if(displacement.y >= 0.0f)
636         {
637           // Quadrant 2
638           angle.radian += Math::PI;
639         }
640         else
641         {
642           // Quadrant 3
643           angle.radian -= Math::PI;
644         }
645       }
646
647       if(panDetector->CheckAngleAllowed(angle))
648       {
649         retVal = true;
650       }
651     }
652     else
653     {
654       // Directional panning not required so we can use this actor and gesture detector.
655       retVal = true;
656     }
657   }
658   return retVal;
659 }
660
661 void PanGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates)
662 {
663   DALI_ASSERT_DEBUG(mCurrentPanEvent);
664
665   mCurrentPanEmitters.clear();
666   ResetActor();
667
668   actor->ScreenToLocal(*mCurrentRenderTask.Get(), actorCoordinates.x, actorCoordinates.y, mCurrentPanEvent->currentPosition.x, mCurrentPanEvent->currentPosition.y);
669
670   EmitPanSignal(actor, gestureDetectors, *mCurrentPanEvent, actorCoordinates, mCurrentPanEvent->state, mCurrentRenderTask);
671
672   if(actor->OnScene())
673   {
674     mCurrentPanEmitters = gestureDetectors;
675     SetActor(actor);
676   }
677 }
678
679 } // namespace Internal
680
681 } // namespace Dali