(Touch) Emit Up to down consumer (if different from current consumer) 91/24091/1
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 27 Jun 2014 12:24:19 +0000 (21:24 +0900)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Tue, 8 Jul 2014 13:19:39 +0000 (14:19 +0100)
[problem]     Actor receiving touch-down may never receive touch-up and it cannot rely on leave.
[cause]       Can be moved away and another actor may be hit.
[solution]    Emit an Interrupted event to the touch-down actor if it's not the current one
              consumed.

Change-Id: Icb59c3434eac12cffebf4d58dff9a2310764099b
Signed-off-by: Adeel Kazmi <adeel.kazmi@samsung.com>
dali/internal/event/events/touch-event-processor.cpp
dali/internal/event/events/touch-event-processor.h

index 4873551..bc4e061 100644 (file)
@@ -136,7 +136,7 @@ void PrintHierarchy()
 /**
  *  Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached.
  */
-Dali::Actor EmitTouchSignals( Dali::Actor actor, RenderTask& renderTask, const TouchEvent& event )
+Dali::Actor EmitTouchSignals( Dali::Actor actor, const TouchEvent& event )
 {
   Dali::Actor consumedActor;
 
@@ -168,7 +168,7 @@ Dali::Actor EmitTouchSignals( Dali::Actor actor, RenderTask& renderTask, const T
            (parent == oldParent) )
       {
         // One of the actor's parents may consumed the event and they should be set as the consumed actor.
-        consumedActor = EmitTouchSignals( parent, renderTask, event );
+        consumedActor = EmitTouchSignals( parent, event );
       }
     }
   }
@@ -189,7 +189,7 @@ Dali::Actor EmitTouchSignals( Actor* actor, RenderTask& renderTask, const TouchE
   primaryPoint.hitActor = actor;
   primaryPoint.state = state;
 
-  return EmitTouchSignals( Dali::Actor(actor), renderTask, touchEvent );
+  return EmitTouchSignals( Dali::Actor(actor), touchEvent );
 }
 
 /**
@@ -216,6 +216,7 @@ TouchEventProcessor::TouchEventProcessor( Stage& stage )
 : mStage( stage ),
   mLastPrimaryHitActor(),
   mLastConsumedActor(),
+  mTouchDownConsumedActor(),
   mLastRenderTask()
 {
   DALI_LOG_TRACE_METHOD( gLogFilter );
@@ -247,32 +248,40 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even
     Dali::Actor consumingActor;
     touchEvent.points.push_back(event.points[0]);
 
-    if ( mLastRenderTask )
+    Actor* lastPrimaryHitActor( mLastPrimaryHitActor.GetActor() );
+    if ( lastPrimaryHitActor )
     {
-      RenderTask& lastRenderTaskImpl( GetImplementation( mLastRenderTask ) );
+      Dali::Actor lastPrimaryHitActorHandle( lastPrimaryHitActor );
+      touchEvent.points[0].hitActor = lastPrimaryHitActorHandle;
+      consumingActor = EmitTouchSignals( lastPrimaryHitActorHandle, touchEvent );
+    }
 
-      Actor* lastPrimaryHitActor( mLastPrimaryHitActor.GetActor() );
-      if ( lastPrimaryHitActor )
-      {
-        Dali::Actor lastPrimaryHitActorHandle( lastPrimaryHitActor );
-        touchEvent.points[0].hitActor = lastPrimaryHitActorHandle;
-        consumingActor = EmitTouchSignals( lastPrimaryHitActorHandle, lastRenderTaskImpl, touchEvent );
-      }
+    // If the last consumed actor was different to the primary hit actor then inform it as well (if it has not already been informed).
+    Actor* lastConsumedActor( mLastConsumedActor.GetActor() );
+    if ( lastConsumedActor &&
+         lastConsumedActor != lastPrimaryHitActor &&
+         lastConsumedActor != consumingActor )
+    {
+      Dali::Actor lastConsumedActorHandle( lastConsumedActor );
+      touchEvent.points[0].hitActor = lastConsumedActorHandle;
+      EmitTouchSignals( lastConsumedActorHandle, touchEvent );
+    }
 
-      // If the last consumed actor was different to the primary hit actor then inform it as well (if it has not already been informed).
-      Actor* lastConsumedActor( mLastConsumedActor.GetActor() );
-      if ( lastConsumedActor &&
-           lastConsumedActor != lastPrimaryHitActor &&
-           lastConsumedActor != consumingActor )
-      {
-        Dali::Actor lastConsumedActorHandle( lastConsumedActor );
-        touchEvent.points[0].hitActor = lastConsumedActorHandle;
-        EmitTouchSignals( lastConsumedActorHandle, lastRenderTaskImpl, touchEvent );
-      }
+    // Tell the touch-down consuming actor as well, if required
+    Actor* touchDownConsumedActor( mTouchDownConsumedActor.GetActor() );
+    if ( touchDownConsumedActor &&
+         touchDownConsumedActor != lastPrimaryHitActor &&
+         touchDownConsumedActor != lastConsumedActor &&
+         touchDownConsumedActor != consumingActor )
+    {
+      Dali::Actor touchDownConsumedActorHandle( touchDownConsumedActor );
+      touchEvent.points[0].hitActor = touchDownConsumedActorHandle;
+      EmitTouchSignals( touchDownConsumedActorHandle, touchEvent );
     }
 
     mLastPrimaryHitActor.SetActor( NULL );
     mLastConsumedActor.SetActor( NULL );
+    mTouchDownConsumedActor.SetActor( NULL );
     mLastRenderTask.Reset();
 
     touchEvent.points[0].hitActor = NULL;
@@ -318,7 +327,7 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even
   Dali::Actor consumedActor;
   if ( currentRenderTask )
   {
-    consumedActor = EmitTouchSignals( touchEvent.points[0].hitActor, GetImplementation( currentRenderTask ), touchEvent );
+    consumedActor = EmitTouchSignals( touchEvent.points[0].hitActor, touchEvent );
   }
 
   TouchPoint& primaryPoint = touchEvent.points[0];
@@ -328,9 +337,18 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even
   DALI_LOG_INFO( gLogFilter, Debug::Concise, "PrimaryHitActor:     (%p) %s\n", primaryPoint.hitActor ? (void*)&primaryPoint.hitActor.GetBaseObject() : NULL, primaryPoint.hitActor ? primaryPoint.hitActor.GetName().c_str() : "" );
   DALI_LOG_INFO( gLogFilter, Debug::Concise, "ConsumedActor:       (%p) %s\n", consumedActor ? (void*)&consumedActor.GetBaseObject() : NULL, consumedActor ? consumedActor.GetName().c_str() : "" );
 
+  if ( ( primaryPointState == TouchPoint::Down ) &&
+       ( touchEvent.GetPointCount() == 1 ) &&
+       ( consumedActor && consumedActor.OnStage() ) )
+  {
+    mTouchDownConsumedActor.SetActor( &GetImplementation( consumedActor ) );
+  }
+
   // 4) Check if the last primary hit actor requires a leave event and if it was different to the current primary
   //    hit actor.  Also process the last consumed actor in the same manner.
 
+  Actor* lastPrimaryHitActor( mLastPrimaryHitActor.GetActor() );
+  Actor* lastConsumedActor( mLastConsumedActor.GetActor() );
   if( (primaryPointState == TouchPoint::Motion) || (primaryPointState == TouchPoint::Up) || (primaryPointState == TouchPoint::Stationary) )
   {
     if ( mLastRenderTask )
@@ -338,7 +356,6 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even
       Dali::Actor leaveEventConsumer;
       RenderTask& lastRenderTaskImpl( GetImplementation( mLastRenderTask ) );
 
-      Actor* lastPrimaryHitActor( mLastPrimaryHitActor.GetActor() );
       if( lastPrimaryHitActor &&
           lastPrimaryHitActor != primaryHitActor &&
           lastPrimaryHitActor != consumedActor )
@@ -363,7 +380,6 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even
       // Check if the motion event has been consumed by another actor's listener.  In this case, the previously
       // consumed actor's listeners may need to be informed (through a leave event).
       // Further checks here to ensure we do not signal the same actor twice for the same event.
-      Actor* lastConsumedActor( mLastConsumedActor.GetActor() );
       if ( lastConsumedActor &&
            lastConsumedActor != consumedActor &&
            lastConsumedActor != lastPrimaryHitActor &&
@@ -425,14 +441,33 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even
     }
   }
 
-  // 6) Emit the stage touched event if required.
+  // 6) Emit an interrupted event to the touch-down actor if it hasn't consumed the up and
+  //    emit the stage touched event if required.
+
   if ( touchEvent.GetPointCount() == 1 ) // Only want the first touch and the last release
   {
     switch ( primaryPointState )
     {
-      case TouchPoint::Down:
       case TouchPoint::Up:
       {
+        Actor* touchDownConsumedActor( mTouchDownConsumedActor.GetActor() );
+        if ( touchDownConsumedActor &&
+             touchDownConsumedActor != consumedActor &&
+             touchDownConsumedActor != lastPrimaryHitActor &&
+             touchDownConsumedActor != lastConsumedActor )
+        {
+          Dali::Actor touchDownConsumedActorHandle( touchDownConsumedActor );
+          touchEvent.points[0].hitActor = touchDownConsumedActorHandle;
+          touchEvent.points[0].state = TouchPoint::Interrupted;
+          EmitTouchSignals( touchDownConsumedActorHandle, touchEvent );
+        }
+
+        mTouchDownConsumedActor.SetActor( NULL );
+      }
+      // No break, Fallthrough
+
+      case TouchPoint::Down:
+      {
         mStage.EmitTouchedSignal( touchEvent );
         break;
       }
index 4022045..5eee7c7 100644 (file)
@@ -156,6 +156,7 @@ private:
   Stage& mStage; ///< Used to deliver touch events
   ActorObserver mLastPrimaryHitActor; ///< Stores the last primary point hit actor
   ActorObserver mLastConsumedActor; ///< Stores the last consumed actor
+  ActorObserver mTouchDownConsumedActor; ///< Stores the touch-down consumed actor
   Dali::RenderTask mLastRenderTask; ///< The RenderTask used for the last hit actor
 };