Renaming of enum values for coding standards compliance.
[platform/core/uifw/dali-core.git] / dali / integration-api / events / touch-event-combiner.cpp
index 0a3d35d..d73291b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 // EXTERNAL INCLUDES
 #include <algorithm>
+#include <cmath> // abs<float>
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
 #include <dali/public-api/common/dali-common.h>
 
 namespace Dali
@@ -46,7 +48,7 @@ struct TouchEventCombiner::PointInfo
    * @param[in]  touchPoint  The point to add.
    * @param[in]  pointTime   The time of the point event.
    */
-  PointInfo( const TouchPoint& touchPoint, unsigned long pointTime )
+  PointInfo( const Point& touchPoint, uint32_t pointTime )
   : point( touchPoint ),
     time( pointTime )
   {
@@ -54,8 +56,8 @@ struct TouchEventCombiner::PointInfo
 
   // Data
 
-  TouchPoint point;   ///< The point.
-  unsigned long time; ///< The time the point event took place.
+  Point point;        ///< The point.
+  uint32_t time; ///< The time the point event took place.
 };
 
 TouchEventCombiner::TouchEventCombiner()
@@ -64,14 +66,14 @@ TouchEventCombiner::TouchEventCombiner()
 {
 }
 
-TouchEventCombiner::TouchEventCombiner( unsigned long minMotionTime, float minMotionXDistance, float minMotionYDistance )
+TouchEventCombiner::TouchEventCombiner( uint32_t minMotionTime, float minMotionXDistance, float minMotionYDistance )
 : mMinMotionTime( minMotionTime ),
   mMinMotionDistance( minMotionXDistance, minMotionYDistance )
 {
   DALI_ASSERT_ALWAYS( minMotionXDistance >= 0.0f && minMotionYDistance >= 0.0f && "Negative values not allowed\n" );
 }
 
-TouchEventCombiner::TouchEventCombiner( unsigned long minMotionTime, Vector2 minMotionDistance )
+TouchEventCombiner::TouchEventCombiner( uint32_t minMotionTime, Vector2 minMotionDistance )
 : mMinMotionTime( minMotionTime ),
   mMinMotionDistance( minMotionDistance )
 {
@@ -82,13 +84,15 @@ TouchEventCombiner::~TouchEventCombiner()
 {
 }
 
-bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned long time, TouchEvent& touchEvent )
+TouchEventCombiner::EventDispatchType TouchEventCombiner::GetNextTouchEvent( const Point& point, uint32_t time, TouchEvent& touchEvent, HoverEvent& hoverEvent )
 {
-  bool dispatchEvent( false );
+  TouchEventCombiner::EventDispatchType dispatchEvent( TouchEventCombiner::DISPATCH_NONE );
+  const PointState::Type state = point.GetState();
+  const int deviceId = point.GetDeviceId();
 
-  switch ( point.state )
+  switch ( state )
   {
-    case TouchPoint::Down:
+    case PointState::STARTED:
     {
       touchEvent.time = time;
       bool addToContainer( true );
@@ -96,9 +100,9 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
       // Iterate through already stored touch points and add to TouchEvent
       for ( PointInfoContainer::iterator iter = mPressedPoints.begin(), endIter = mPressedPoints.end(); iter != endIter; ++iter )
       {
-        if ( iter->point.deviceId != point.deviceId )
+        if ( iter->point.GetDeviceId() != deviceId )
         {
-          iter->point.state = TouchPoint::Stationary;
+          iter->point.SetState( PointState::STATIONARY );
         }
         else
         {
@@ -117,13 +121,42 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
       {
         mPressedPoints.push_back( PointInfo( point, time ) );
         touchEvent.AddPoint( point );
-        dispatchEvent = true; // Only dispatch event if just added to container
+        dispatchEvent = TouchEventCombiner::DISPATCH_TOUCH; // Only dispatch touch event if just added to container
+
+        // Check whether hover event was dispatched previously
+        if ( !mHoveredPoints.empty() )
+        {
+          hoverEvent.time = time;
+
+          PointInfoContainer::iterator match( mHoveredPoints.end() );
+          for ( PointInfoContainer::iterator iter = mHoveredPoints.begin(), endIter = mHoveredPoints.end(); iter != endIter; ++iter )
+          {
+            if ( deviceId == iter->point.GetDeviceId() )
+            {
+              match = iter;
+              // Add new point to the HoverEvent
+              iter->point.SetState( PointState::FINISHED );
+              hoverEvent.AddPoint( iter->point );
+            }
+            else
+            {
+              iter->point.SetState( PointState::STATIONARY );
+              hoverEvent.AddPoint( iter->point );
+            }
+          }
+
+          if ( match != mHoveredPoints.end() )
+          {
+            mHoveredPoints.erase( match );
+            dispatchEvent = TouchEventCombiner::DISPATCH_BOTH; // We should only dispatch hover events if the point was actually hovered in this window
+          }
+        }
       }
 
       break;
     }
 
-    case TouchPoint::Up:
+    case PointState::FINISHED:
     {
       touchEvent.time = time;
 
@@ -131,7 +164,7 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
       PointInfoContainer::iterator match( mPressedPoints.end() );
       for ( PointInfoContainer::iterator iter = mPressedPoints.begin(), endIter = mPressedPoints.end(); iter != endIter; ++iter )
       {
-        if ( point.deviceId == iter->point.deviceId )
+        if ( deviceId == iter->point.GetDeviceId() )
         {
           match = iter;
 
@@ -140,7 +173,7 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
         }
         else
         {
-          iter->point.state = TouchPoint::Stationary;
+          iter->point.SetState( PointState::STATIONARY );
           touchEvent.AddPoint( iter->point );
         }
       }
@@ -148,34 +181,50 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
       if ( match != mPressedPoints.end() )
       {
         mPressedPoints.erase( match );
-        dispatchEvent = true; // We should only dispatch events if the point was actually pressed in this window
+        dispatchEvent = TouchEventCombiner::DISPATCH_TOUCH; // We should only dispatch touch events if the point was actually pressed in this window
+
+        // Iterate through already stored touch points for HoverEvent and delete them
+        for ( PointInfoContainer::iterator iter = mHoveredPoints.begin(), endIter = mHoveredPoints.end(); iter != endIter; ++iter )
+        {
+          if ( iter->point.GetDeviceId() == deviceId )
+          {
+            iter = mHoveredPoints.erase( iter );
+          }
+        }
       }
       break;
     }
 
-    case TouchPoint::Motion:
+    case PointState::MOTION:
     {
+      bool fromNewDeviceId = false;
+
       if ( !mPressedPoints.empty() )
       {
         touchEvent.time = time;
 
+        bool ignore = false;
         PointInfoContainer::iterator match = mPressedPoints.end();
+        const Vector2& pointScreenPosition = point.GetScreenPosition();
         for ( PointInfoContainer::iterator iter = mPressedPoints.begin(), endIter = mPressedPoints.end(); iter != endIter; ++iter )
         {
-          if ( point.deviceId == iter->point.deviceId )
+          if ( deviceId == iter->point.GetDeviceId() )
           {
-            unsigned long timeDiff( time - iter->time );
+            uint32_t timeDiff( time - iter->time );
 
             if ( timeDiff < mMinMotionTime )
             {
               // Motion event sent too soon after previous event so ignore
+              ignore = true;
               break;
             }
 
-            if ( ( abs( point.screen.x - iter->point.screen.x ) < mMinMotionDistance.x ) &&
-                 ( abs( point.screen.y - iter->point.screen.y ) < mMinMotionDistance.y ) )
+            const Vector2& currentScreenPosition = iter->point.GetScreenPosition();
+            if ( ( std::abs( pointScreenPosition.x - currentScreenPosition.x ) < mMinMotionDistance.x ) &&
+                 ( std::abs( pointScreenPosition.y - currentScreenPosition.y ) < mMinMotionDistance.y ) )
             {
               // Not enough positional change from last event so ignore
+              ignore = true;
               break;
             }
 
@@ -186,7 +235,7 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
           }
           else
           {
-            iter->point.state = TouchPoint::Stationary;
+            iter->point.SetState( PointState::STATIONARY );
             touchEvent.AddPoint( iter->point );
           }
         }
@@ -196,19 +245,94 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
           PointInfo matchedPoint( point, time );
           std::swap( *match, matchedPoint );
 
-          dispatchEvent = true;
+          dispatchEvent = TouchEventCombiner::DISPATCH_TOUCH; // Dispatch touch event
+        }
+        else if(!ignore)
+        {
+          fromNewDeviceId = true;
+        }
+      }
+
+      // Dispatch hover event if no previous down event received or the motion event comes from a new device ID
+      if(mPressedPoints.empty() || fromNewDeviceId)
+      {
+        hoverEvent.time = time;
+
+        // Iterate through already stored touch points and add to HoverEvent
+        bool ignore = false;
+        PointInfoContainer::iterator match = mHoveredPoints.end();
+        const Vector2& pointScreenPosition = point.GetScreenPosition();
+        for ( PointInfoContainer::iterator iter = mHoveredPoints.begin(), endIter = mHoveredPoints.end(); iter != endIter; ++iter )
+        {
+          if ( iter->point.GetDeviceId() == deviceId )
+          {
+            uint32_t timeDiff( time - iter->time );
+
+            if ( timeDiff < mMinMotionTime )
+            {
+              // Motion event sent too soon after previous event so ignore
+              ignore = true;
+              break;
+            }
+
+            const Vector2& currentScreenPosition = iter->point.GetScreenPosition();
+            if ( ( std::abs( pointScreenPosition.x - currentScreenPosition.x ) < mMinMotionDistance.x ) &&
+                 ( std::abs( pointScreenPosition.y - currentScreenPosition.y ) < mMinMotionDistance.y ) )
+            {
+              // Not enough positional change from last event so ignore
+              ignore = true;
+              break;
+            }
+
+            match = iter;
+
+            // Add new touch point to the HoverEvent
+            hoverEvent.AddPoint( point );
+          }
+          else
+          {
+            iter->point.SetState( PointState::STATIONARY );
+            hoverEvent.AddPoint( iter->point );
+          }
+        }
+
+        // Add new hover point to the list and to the HoverEvent
+        if ( !ignore ) // Only dispatch hover event when it should not be ignored
+        {
+          if( match == mHoveredPoints.end() )
+          {
+            Point hoverPoint(point);
+            hoverPoint.SetState( PointState::STARTED ); // The first hover event received
+            mHoveredPoints.push_back( PointInfo( hoverPoint, time ) );
+            hoverEvent.AddPoint( hoverPoint );
+          }
+          else
+          {
+            PointInfo matchedPoint( point, time );
+            std::swap( *match, matchedPoint );
+          }
+
+          if(dispatchEvent == TouchEventCombiner::DISPATCH_TOUCH)
+          {
+            dispatchEvent = TouchEventCombiner::DISPATCH_BOTH;
+          }
+          else
+          {
+            dispatchEvent = TouchEventCombiner::DISPATCH_HOVER;
+          }
         }
       }
       break;
     }
 
-    case TouchPoint::Interrupted:
+    case PointState::INTERRUPTED:
     {
       Reset();
 
       // We should still tell core about the interruption.
       touchEvent.AddPoint( point );
-      dispatchEvent = true;
+      hoverEvent.AddPoint( point );
+      dispatchEvent = TouchEventCombiner::DISPATCH_BOTH;
       break;
     }
 
@@ -219,7 +343,7 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
   return dispatchEvent;
 }
 
-void TouchEventCombiner::SetMinimumMotionTimeThreshold( unsigned long minTime )
+void TouchEventCombiner::SetMinimumMotionTimeThreshold( uint32_t minTime )
 {
   mMinMotionTime = minTime;
 }
@@ -259,6 +383,7 @@ Vector2 TouchEventCombiner::GetMinimumMotionDistanceThreshold() const
 void TouchEventCombiner::Reset()
 {
   mPressedPoints.clear();
+  mHoveredPoints.clear();
 }
 
 } // namespace Integration