(Gestures) Use the actor-gesture-data containers and use raw Actor pointers.
[platform/core/uifw/dali-core.git] / dali / internal / event / events / pan-gesture-processor.cpp
1 /*
2  * Copyright (c) 2014 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-processor.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/actors/actor.h>
26 #include <dali/public-api/common/dali-common.h>
27 #include <dali/public-api/events/pan-gesture.h>
28 #include <dali/public-api/math/vector2.h>
29 #include <dali/integration-api/events/pan-gesture-event.h>
30 #include <dali/integration-api/gesture-manager.h>
31 #include <dali/integration-api/debug.h>
32 #include <dali/internal/event/common/stage-impl.h>
33 #include <dali/internal/event/render-tasks/render-task-impl.h>
34 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
35
36 namespace Dali
37 {
38
39 namespace Internal
40 {
41
42 namespace // unnamed namespace
43 {
44
45 const unsigned long MAXIMUM_TIME_WITH_VALID_LAST_VELOCITY( 50u );
46
47 /**
48  * Functor which checks whether the specified actor is attached to the gesture detector.
49  * If the actor is attached, it also checks whether the number of touches of the current pan event
50  * are within the range of that expected by the detector.
51  * It returns true if it is no longer attached or the touches are out of range.
52  * This can be used in remove_if functions.
53  */
54 struct IsNotAttachedAndOutsideTouchesRangeFunctor
55 {
56   /**
57    * Constructor
58    * @param[in]  actor                 The actor to check whether it is attached.
59    * @param[in]  touches               The number of touches in the current pan event.
60    * @param[in]  outsideRangeEmitters  Reference to container where emitters outside of the touches range should be added.
61    */
62   IsNotAttachedAndOutsideTouchesRangeFunctor(Actor* actor, unsigned int touches, GestureDetectorContainer& outsideRangeEmitters)
63   : actorToCheck(actor),
64     numberOfTouches(touches),
65     outsideTouchesRangeEmitters(outsideRangeEmitters)
66   {
67   }
68
69   /**
70    * Returns true if not attached, false if it is still attached.
71    * Additionally, checks if the number of touches has changed and stops sending the pan to a particular
72    * detector if it exceeds the range of that detector.
73    * @param[in]  detector  The detector to check.
74    * @return true, if not attached, false otherwise.
75    */
76   bool operator()(GestureDetector* detector) const
77   {
78     bool remove(!detector->IsAttached(*actorToCheck));
79
80     if (!remove)
81     {
82       PanGestureDetector* panDetector( static_cast< PanGestureDetector* >( detector ) );
83
84       // Ensure number of touch points is within the range of our emitter. If it isn't then remove
85       // this emitter and add it to the outsideTouchesRangeEmitters container
86       if ( (numberOfTouches < panDetector->GetMinimumTouchesRequired()) ||
87            (numberOfTouches > panDetector->GetMaximumTouchesRequired()) )
88       {
89         remove = true;
90         outsideTouchesRangeEmitters.push_back(detector);
91       }
92     }
93
94     return remove;
95   }
96
97   Actor* actorToCheck; ///< The actor to check whether it is attached or not.
98   unsigned int numberOfTouches; ///< The number of touches in the pan event.
99   GestureDetectorContainer& outsideTouchesRangeEmitters; ///< Emitters that are outside of the range of current pan.
100 };
101
102 } // unnamed namespace
103
104 struct PanGestureProcessor::PanEventFunctor : public GestureProcessor::Functor
105 {
106   /**
107    * Constructor
108    * @param[in]  panEvent   The current gesture event.
109    * @param[in]  processor  Reference to the processor.
110    */
111   PanEventFunctor( const Integration::PanGestureEvent& panEvent, PanGestureProcessor& processor )
112   : panEvent( panEvent ),
113     processor( processor )
114   {
115   }
116
117   /**
118    * Check if the detector meets the current gesture event parameters.
119    */
120   virtual bool operator() ( GestureDetector* detector, Actor* actor )
121   {
122     bool retVal( false );
123
124     PanGestureDetector* panDetector( static_cast< PanGestureDetector* >( detector ) );
125
126     if ( ( panEvent.numberOfTouches >= panDetector->GetMinimumTouchesRequired() ) &&
127          ( panEvent.numberOfTouches <= panDetector->GetMaximumTouchesRequired() ) )
128     {
129       // Check if the detector requires directional panning.
130       if ( panDetector->RequiresDirectionalPan() && processor.mCurrentRenderTask )
131       {
132         // It does, calculate the angle of the pan in local actor coordinates and ensures it fits
133         // the detector's criteria.
134         RenderTask& renderTaskImpl( GetImplementation( processor.mCurrentRenderTask ) );
135
136         Vector2 startPosition, currentPosition;
137         actor->ScreenToLocal( renderTaskImpl, startPosition.x,   startPosition.y,   processor.mPossiblePanPosition.x, processor.mPossiblePanPosition.y );
138         actor->ScreenToLocal( renderTaskImpl, currentPosition.x, currentPosition.y, panEvent.currentPosition.x,       panEvent.currentPosition.y );
139         Vector2 displacement( currentPosition - startPosition );
140
141         Radian angle( atan( displacement.y / displacement.x ) );
142
143         /////////////////////////////
144         //            |            //
145         //            |            //
146         //   Q3 (-,-) | Q4 (+,-)   //
147         //            |            //
148         //    ----------------- +x //
149         //            |            //
150         //   Q2 (-,+) | Q1 (+,+)   //
151         //            |            //
152         //            |            //
153         //           +y            //
154         /////////////////////////////
155         // Quadrant 1: As is
156         // Quadrant 2: 180 degrees + angle
157         // Quadrant 3: angle - 180 degrees
158         // Quadrant 4: As is
159         /////////////////////////////
160
161         if ( displacement.x < 0.0f )
162         {
163           if ( displacement.y >= 0.0f )
164           {
165             // Quadrant 2
166             angle += Math::PI;
167           }
168           else
169           {
170             // Quadrant 3
171             angle -= Math::PI;
172           }
173         }
174
175         if ( panDetector->CheckAngleAllowed( angle ) )
176         {
177           retVal = true;
178         }
179       }
180       else
181       {
182         // Directional panning not required so we can use this actor and gesture detector.
183         retVal = true;
184       }
185     }
186
187     return retVal;
188   }
189
190   /**
191    * Gestured actor and gesture detectors that meet the gesture's parameters found, emit and save required information.
192    */
193   virtual void operator() ( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
194   {
195     processor.mCurrentPanEmitters.clear();
196     processor.ResetActor();
197
198     actor->ScreenToLocal( GetImplementation(processor.mCurrentRenderTask), actorCoordinates.x, actorCoordinates.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
199
200     processor.EmitPanSignal( actor, gestureDetectors, panEvent, actorCoordinates, panEvent.state, processor.mCurrentRenderTask );
201
202     if ( actor->OnStage() )
203     {
204       processor.mCurrentPanEmitters = gestureDetectors;
205       processor.SetActor( actor );
206     }
207   }
208
209   const Integration::PanGestureEvent& panEvent;
210   PanGestureProcessor& processor;
211 };
212
213 PanGestureProcessor::PanGestureProcessor( Stage& stage, Integration::GestureManager& gestureManager )
214 : GestureProcessor( Gesture::Pan ),
215   mStage( stage ),
216   mGestureManager( gestureManager ),
217   mGestureDetectors(),
218   mCurrentPanEmitters(),
219   mCurrentRenderTask(),
220   mPossiblePanPosition(),
221   mMinTouchesRequired( 1 ),
222   mMaxTouchesRequired( 1 ),
223   mSceneObject( SceneGraph::PanGesture::New() ) // Create scene object to store pan information.
224 {
225   // Pass ownership to scene-graph
226   AddGestureMessage( mStage.GetUpdateManager(), mSceneObject );
227 }
228
229 PanGestureProcessor::~PanGestureProcessor()
230 {
231   if( Stage::IsInstalled() && ( mSceneObject != NULL ) )
232   {
233     RemoveGestureMessage( mStage.GetUpdateManager(), mSceneObject );
234     mSceneObject = NULL; // mSceneObject is about to be destroyed
235   }
236 }
237
238 void PanGestureProcessor::Process( const Integration::PanGestureEvent& panEvent )
239 {
240   switch( panEvent.state )
241   {
242     case Gesture::Possible:
243     {
244       mCurrentPanEmitters.clear();
245       ResetActor();
246
247       HitTestAlgorithm::Results hitTestResults;
248       if( HitTest( mStage, panEvent.currentPosition, hitTestResults ) )
249       {
250         SetActor( &GetImplementation( hitTestResults.actor ) );
251         mPossiblePanPosition = panEvent.currentPosition;
252       }
253
254       break;
255     }
256
257     case Gesture::Started:
258     {
259       if ( GetCurrentGesturedActor() )
260       {
261         // The pan gesture should only be sent to the gesture detector which first received it so that
262         // it can be told when the gesture ends as well.
263
264         HitTestAlgorithm::Results hitTestResults;
265         HitTest( mStage, mPossiblePanPosition, hitTestResults ); // Hit test original possible position...
266
267         if ( hitTestResults.actor && ( GetCurrentGesturedActor() == &GetImplementation( hitTestResults.actor ) ) )
268         {
269           // Record the current render-task for Screen->Actor coordinate conversions
270           mCurrentRenderTask = hitTestResults.renderTask;
271
272           PanEventFunctor functor( panEvent, *this );
273           ProcessAndEmit( hitTestResults, functor );
274         }
275         else
276         {
277           ResetActor();
278           mCurrentPanEmitters.clear();
279         }
280       }
281       break;
282     }
283
284     case Gesture::Continuing:
285     case Gesture::Finished:
286     case Gesture::Cancelled:
287     {
288       // Only send subsequent pan gesture signals if we processed the pan gesture when it started.
289       // Check if actor is still touchable.
290
291       Actor* currentGesturedActor = GetCurrentGesturedActor();
292       if ( currentGesturedActor )
293       {
294         if ( currentGesturedActor->IsHittable() && !mCurrentPanEmitters.empty() && mCurrentRenderTask )
295         {
296           GestureDetectorContainer outsideTouchesRangeEmitters;
297
298           // Removes emitters that no longer have the actor attached
299           // Also remove emitters whose touches are outside the range of the current pan event and add them to outsideTouchesRangeEmitters
300           GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentPanEmitters.begin(), mCurrentPanEmitters.end(),
301                                                                        IsNotAttachedAndOutsideTouchesRangeFunctor(currentGesturedActor, panEvent.numberOfTouches, outsideTouchesRangeEmitters) );
302           mCurrentPanEmitters.erase( endIter, mCurrentPanEmitters.end() );
303
304           Vector2 actorCoords;
305
306           if ( !outsideTouchesRangeEmitters.empty() || !mCurrentPanEmitters.empty() )
307           {
308             currentGesturedActor->ScreenToLocal( GetImplementation( mCurrentRenderTask ), actorCoords.x, actorCoords.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
309
310             // EmitPanSignal checks whether we have a valid actor and whether the container we are passing in has emitters before it emits the pan.
311             EmitPanSignal( currentGesturedActor, outsideTouchesRangeEmitters, panEvent, actorCoords, Gesture::Finished, mCurrentRenderTask);
312             EmitPanSignal( currentGesturedActor, mCurrentPanEmitters, panEvent, actorCoords, panEvent.state, mCurrentRenderTask);
313           }
314
315           if ( mCurrentPanEmitters.empty() )
316           {
317             // If we have no emitters attached then clear pan actor as well.
318             ResetActor();
319           }
320
321           // Clear current gesture detectors if pan gesture has ended or been cancelled.
322           if ( ( panEvent.state == Gesture::Finished ) || ( panEvent.state == Gesture::Cancelled ) )
323           {
324             mCurrentPanEmitters.clear();
325             ResetActor();
326           }
327         }
328         else
329         {
330           mCurrentPanEmitters.clear();
331           ResetActor();
332         }
333       }
334       break;
335     }
336
337     case Gesture::Clear:
338       DALI_ASSERT_ALWAYS( false && "Incorrect state received from Integration layer: Clear\n" );
339       break;
340   }
341 }
342
343 void PanGestureProcessor::AddGestureDetector( PanGestureDetector* gestureDetector )
344 {
345   bool firstRegistration(mGestureDetectors.empty());
346
347   mGestureDetectors.push_back(gestureDetector);
348
349   // Set the pan scene object on the gesture detector
350   gestureDetector->SetSceneObject( mSceneObject );
351
352   if (firstRegistration)
353   {
354     mMinTouchesRequired = gestureDetector->GetMinimumTouchesRequired();
355     mMaxTouchesRequired = gestureDetector->GetMaximumTouchesRequired();
356
357     Integration::PanGestureRequest request;
358     request.minTouches = mMinTouchesRequired;
359     request.maxTouches = mMaxTouchesRequired;
360     mGestureManager.Register(request);
361   }
362   else
363   {
364     UpdateDetection();
365   }
366 }
367
368 void PanGestureProcessor::RemoveGestureDetector( PanGestureDetector* gestureDetector )
369 {
370   if (!mCurrentPanEmitters.empty())
371   {
372     // Check if the removed detector was one that is currently being panned and remove it from emitters.
373     GestureDetectorContainer::iterator endIter = std::remove( mCurrentPanEmitters.begin(), mCurrentPanEmitters.end(), gestureDetector );
374     mCurrentPanEmitters.erase( endIter, mCurrentPanEmitters.end() );
375
376     // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
377     if ( mCurrentPanEmitters.empty() )
378     {
379       ResetActor();
380     }
381   }
382
383   // Find the detector...
384   PanGestureDetectorContainer::iterator endIter = std::remove( mGestureDetectors.begin(), mGestureDetectors.end(), gestureDetector );
385   DALI_ASSERT_DEBUG( endIter != mGestureDetectors.end() );
386
387   // ...and remove it
388   mGestureDetectors.erase(endIter, mGestureDetectors.end());
389
390   if (mGestureDetectors.empty())
391   {
392     Integration::GestureRequest request(Gesture::Pan);
393     mGestureManager.Unregister(request);
394   }
395   else
396   {
397     UpdateDetection();
398   }
399 }
400
401 void PanGestureProcessor::GestureDetectorUpdated( PanGestureDetector* gestureDetector )
402 {
403   DALI_ASSERT_DEBUG(find(mGestureDetectors.begin(), mGestureDetectors.end(), gestureDetector) != mGestureDetectors.end());
404
405   UpdateDetection();
406 }
407
408 void PanGestureProcessor::SetPanGestureProperties( const PanGesture& pan )
409 {
410   // If we are currently processing a pan gesture then just ignore
411   if ( mCurrentPanEmitters.empty() && mSceneObject )
412   {
413     // We update the scene object directly rather than sending a message.
414     // Sending a message could cause unnecessary delays, the scene object ensure thread safe behaviour.
415     mSceneObject->AddGesture( pan );
416   }
417 }
418
419 void PanGestureProcessor::EnableProfiling()
420 {
421   mSceneObject->EnableProfiling();
422 }
423
424 void PanGestureProcessor::SetPredictionMode(int mode)
425 {
426   if( (mode < 0)
427       || (mode >= SceneGraph::PanGesture::NUM_PREDICTION_MODES) )
428   {
429     mode = SceneGraph::PanGesture::DEFAULT_PREDICTION_MODE;
430   }
431   SceneGraph::PanGesture::PredictionMode modeEnum = static_cast<SceneGraph::PanGesture::PredictionMode>(mode);
432   mSceneObject->SetPredictionMode(modeEnum);
433 }
434
435 void PanGestureProcessor::SetPredictionAmount(unsigned int amount)
436 {
437   mSceneObject->SetPredictionAmount(amount);
438 }
439
440 void PanGestureProcessor::UpdateDetection()
441 {
442   DALI_ASSERT_DEBUG(!mGestureDetectors.empty());
443
444   unsigned int minimumRequired = UINT_MAX;
445   unsigned int maximumRequired = 0;
446
447   for ( PanGestureDetectorContainer::iterator iter = mGestureDetectors.begin(), endIter = mGestureDetectors.end(); iter != endIter; ++iter )
448   {
449     PanGestureDetector* detector(*iter);
450
451     unsigned int minimum = detector->GetMinimumTouchesRequired();
452     if (minimum < minimumRequired)
453     {
454       minimumRequired = minimum;
455     }
456
457     unsigned int maximum = detector->GetMaximumTouchesRequired();
458     if (maximum > maximumRequired)
459     {
460       maximumRequired = maximum;
461     }
462   }
463
464   if ( (minimumRequired != mMinTouchesRequired)||(maximumRequired != mMaxTouchesRequired) )
465   {
466     mMinTouchesRequired = minimumRequired;
467     mMaxTouchesRequired = maximumRequired;
468
469     Integration::PanGestureRequest request;
470     request.minTouches = mMinTouchesRequired;
471     request.maxTouches = mMaxTouchesRequired;
472     mGestureManager.Update(request);
473   }
474 }
475
476 void PanGestureProcessor::EmitPanSignal( Actor* actor,
477                                          const GestureDetectorContainer& gestureDetectors,
478                                          const Integration::PanGestureEvent& panEvent,
479                                          Vector2 localCurrent,
480                                          Gesture::State state,
481                                          Dali::RenderTask renderTask )
482 {
483   if ( actor && !gestureDetectors.empty() )
484   {
485     PanGesture pan(state);
486     pan.time = panEvent.time;
487
488     pan.numberOfTouches = panEvent.numberOfTouches;
489     pan.screenPosition = panEvent.currentPosition;
490     pan.position = localCurrent;
491
492     RenderTask& renderTaskImpl( GetImplementation( renderTask ) );
493
494     Vector2 localPrevious;
495     actor->ScreenToLocal( renderTaskImpl, localPrevious.x, localPrevious.y, panEvent.previousPosition.x, panEvent.previousPosition.y );
496
497     pan.displacement = localCurrent - localPrevious;
498     Vector2 previousPos( panEvent.previousPosition );
499     if ( state == Gesture::Started )
500     {
501       previousPos = mPossiblePanPosition;
502     }
503
504     pan.screenDisplacement = panEvent.currentPosition - previousPos;
505
506     pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
507     pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
508
509     pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
510     pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
511
512     // When the gesture ends, we may incorrectly get a ZERO velocity (as we have lifted our finger without any movement)
513     // so we should use the last recorded velocity instead in this scenario.
514     if ( ( state == Gesture::Finished ) && ( pan.screenVelocity == Vector2::ZERO ) &&
515          ( panEvent.timeDelta < MAXIMUM_TIME_WITH_VALID_LAST_VELOCITY ) )
516     {
517       pan.velocity = mLastVelocity;
518       pan.screenVelocity = mLastScreenVelocity;
519     }
520     else
521     {
522       // Store the current velocity for future iterations.
523       mLastVelocity = pan.velocity;
524       mLastScreenVelocity = pan.screenVelocity;
525     }
526
527     if ( mSceneObject )
528     {
529       // We update the scene object directly rather than sending a message.
530       // Sending a message could cause unnecessary delays, the scene object ensure thread safe behaviour.
531       mSceneObject->AddGesture( pan );
532     }
533
534     Dali::Actor actorHandle( actor );
535     const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
536     for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
537     {
538       static_cast< PanGestureDetector* >( *iter )->EmitPanGestureSignal( actorHandle, pan );
539     }
540   }
541 }
542
543 void PanGestureProcessor::OnGesturedActorStageDisconnection()
544 {
545   mCurrentPanEmitters.clear();
546 }
547
548 } // namespace Internal
549
550 } // namespace Dali