Added hover event in Dali 14/27814/11
authorRichard Huang <r.huang@samsung.com>
Fri, 19 Sep 2014 10:41:01 +0000 (11:41 +0100)
committerRichard Huang <r.huang@samsung.com>
Fri, 3 Oct 2014 11:59:27 +0000 (04:59 -0700)
Hover events are a collection of touch points at a specific moment in time.
When a multi-touch event occurs, each touch point represents the points that
are currently being hovered or the points where a hover has stopped.

Hover event processor processes hover events and emits the Hovered signal
on the hit actor (and its parents).

Change-Id: Ife8e7c1561158e8f98061eb5037ad3b6944846dd

47 files changed:
automated-tests/src/dali-unmanaged/utc-Dali-CustomActor.cpp
automated-tests/src/dali-unmanaged/utc-Dali-TypeRegistry.cpp
automated-tests/src/dali/CMakeLists.txt
automated-tests/src/dali/utc-Dali-Actor.cpp
automated-tests/src/dali/utc-Dali-CustomActor.cpp
automated-tests/src/dali/utc-Dali-HoverProcessing.cpp [new file with mode: 0644]
automated-tests/src/dali/utc-Dali-Layer.cpp
automated-tests/src/dali/utc-Dali-TouchEventCombiner.cpp
dali/integration-api/events/event.h
dali/integration-api/events/hover-event-integ.cpp [new file with mode: 0644]
dali/integration-api/events/hover-event-integ.h [new file with mode: 0644]
dali/integration-api/events/multi-point-event-integ.cpp [new file with mode: 0644]
dali/integration-api/events/multi-point-event-integ.h [new file with mode: 0644]
dali/integration-api/events/touch-event-combiner.cpp
dali/integration-api/events/touch-event-combiner.h
dali/integration-api/events/touch-event-integ.cpp
dali/integration-api/events/touch-event-integ.h
dali/integration-api/file.list
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/actors/actor-impl.h
dali/internal/event/actors/custom-actor-internal.cpp
dali/internal/event/actors/custom-actor-internal.h
dali/internal/event/actors/layer-impl.cpp
dali/internal/event/actors/layer-impl.h
dali/internal/event/events/actor-observer.cpp [new file with mode: 0644]
dali/internal/event/events/actor-observer.h [new file with mode: 0644]
dali/internal/event/events/event-processor.cpp
dali/internal/event/events/event-processor.h
dali/internal/event/events/hover-event-processor.cpp [new file with mode: 0644]
dali/internal/event/events/hover-event-processor.h [new file with mode: 0644]
dali/internal/event/events/multi-point-event-util.cpp [new file with mode: 0644]
dali/internal/event/events/multi-point-event-util.h [new file with mode: 0644]
dali/internal/event/events/touch-event-processor.cpp
dali/internal/event/events/touch-event-processor.h
dali/internal/file.list
dali/public-api/actors/actor.cpp
dali/public-api/actors/actor.h
dali/public-api/actors/custom-actor-impl.cpp
dali/public-api/actors/custom-actor-impl.h
dali/public-api/actors/layer.cpp
dali/public-api/actors/layer.h
dali/public-api/dali-core.h
dali/public-api/events/hover-event.cpp [new file with mode: 0644]
dali/public-api/events/hover-event.h [new file with mode: 0644]
dali/public-api/events/touch-event.h
dali/public-api/events/touch-point.h
dali/public-api/file.list

index 8bb6ede..c7e8d64 100644 (file)
@@ -21,6 +21,7 @@
 #include <dali/public-api/dali-core.h>
 
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
 #include <dali/integration-api/events/mouse-wheel-event-integ.h>
 #include <dali/integration-api/events/key-event-integ.h>
 
@@ -132,6 +133,11 @@ struct TestCustomActor : public CustomActorImpl
     AddToCallStacks("OnTouchEvent");
     return true;
   }
+  virtual bool OnHoverEvent(const HoverEvent& event)
+  {
+    AddToCallStacks("OnHoverEvent");
+    return true;
+  }
   virtual bool OnMouseWheelEvent(const MouseWheelEvent& event)
   {
     AddToCallStacks("OnMouseWheelEvent");
index 53eb88c..ebc7c0c 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/integration-api/events/pinch-gesture-event.h>
 #include <dali/integration-api/events/tap-gesture-event.h>
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
 
 using namespace Dali;
 
@@ -223,6 +224,10 @@ struct MyTestCustomActor : public CustomActorImpl
   {
     return true;
   }
+  virtual bool OnHoverEvent(const HoverEvent& event)
+  {
+    return true;
+  }
   virtual bool OnMouseWheelEvent(const MouseWheelEvent& event)
   {
     return true;
index 647ce4a..7c5f402 100644 (file)
@@ -26,6 +26,7 @@ SET(TC_SOURCES
         utc-Dali-Gesture.cpp
         utc-Dali-GestureDetector.cpp
         utc-Dali-Handle.cpp
+        utc-Dali-HoverProcessing.cpp
         utc-Dali-Image.cpp
         utc-Dali-ImageActor.cpp
         utc-Dali-ImageAttributes.cpp
index 95dc2e6..60a772a 100644 (file)
@@ -19,6 +19,7 @@
 #include <dali/public-api/dali-core.h>
 #include <string>
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
 #include <dali-test-suite-utils.h>
 
 //& set: DaliActor
@@ -42,6 +43,7 @@ namespace
 
 bool gTouchCallBackCalled=false;
 bool gTouchCallBack2Called=false;
+bool gHoverCallBackCalled=false;
 
 /**
  * Simulates a Down Touch at 25.0, 25.0.
@@ -138,6 +140,13 @@ static bool TestCallback2(Actor actor, const TouchEvent& event)
   END_TEST;
 }
 
+static bool TestCallback3(Actor actor, const HoverEvent& event)
+{
+  gHoverCallBackCalled = true;
+  return false;
+  END_TEST;
+}
+
 static Vector3 gSetSize;
 static bool gSetSizeCallBackCalled;
 void SetSizeCallback( Actor actor, const Vector3& size )
@@ -2254,6 +2263,32 @@ int UtcDaliActorTouchedSignal(void)
   END_TEST;
 }
 
+int UtcDaliActorHoveredSignal(void)
+{
+  TestApplication application;
+
+  gHoverCallBackCalled = false;
+
+  // get the root layer
+  Actor actor = Stage::GetCurrent().GetRootLayer();
+  DALI_TEST_CHECK( gHoverCallBackCalled == false );
+
+  application.SendNotification();
+  application.Render();
+
+  // connect to its hover signal
+  actor.HoveredSignal().Connect( TestCallback3 );
+
+  // simulate a hover event in the middle of the screen
+  Vector2 touchPoint( Stage::GetCurrent().GetSize() * 0.5 );
+  Dali::TouchPoint point( 1, TouchPoint::Motion, touchPoint.x, touchPoint.y );
+  Dali::Integration::HoverEvent event;
+  event.AddPoint( point );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( gHoverCallBackCalled == true );
+  END_TEST;
+}
 
 int UtcDaliActorSetSizeSignal(void)
 {
index 2e54d07..aa10dd3 100644 (file)
@@ -20,6 +20,7 @@
 #include <dali/public-api/dali-core.h>
 
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
 #include <dali/integration-api/events/mouse-wheel-event-integ.h>
 #include <dali/integration-api/events/key-event-integ.h>
 
@@ -61,6 +62,7 @@ struct TestCustomActor : public CustomActorImpl
     mTargetSize( Vector3::ZERO )
   {
     SetRequiresMouseWheelEvents(true);
+    SetRequiresHoverEvents(true);
   }
 
   /**
@@ -144,6 +146,11 @@ struct TestCustomActor : public CustomActorImpl
     AddToCallStacks("OnTouchEvent");
     return true;
   }
+  virtual bool OnHoverEvent(const HoverEvent& event)
+  {
+    AddToCallStacks("OnHoverEvent");
+    return true;
+  }
   virtual bool OnMouseWheelEvent(const MouseWheelEvent& event)
   {
     AddToCallStacks("OnMouseWheelEvent");
@@ -456,6 +463,10 @@ public:
   {
     return true;
   }
+  virtual bool OnHoverEvent(const HoverEvent& event)
+  {
+    return true;
+  }
   virtual bool OnMouseWheelEvent(const MouseWheelEvent& event)
   {
     return true;
@@ -1512,6 +1523,37 @@ int UtcDaliCustomActorOnTouchEvent(void)
   END_TEST;
 }
 
+int UtcDaliCustomActorOnHoverEvent(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::CustomActor::OnHoverEvent()");
+
+  TestCustomActor custom = TestCustomActor::New();
+  DALI_TEST_EQUALS( 0, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION );
+
+  // set size for custom actor
+  custom.SetSize( 100, 100 );
+  // add the custom actor to stage
+  Stage::GetCurrent().Add( custom );
+  custom.ResetCallStack();
+
+  // Render and notify a couple of times
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+  application.Render();
+
+  // simulate a hover event
+  Dali::TouchPoint point( 0, TouchPoint::Motion, 1, 1 );
+  Dali::Integration::HoverEvent event;
+  event.AddPoint( point );
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( 1, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION );
+  DALI_TEST_EQUALS( "OnHoverEvent", custom.GetMethodsCalled()[ 0 ], TEST_LOCATION );
+  END_TEST;
+}
+
 int UtcDaliCustomActorOnMouseWheelEvent(void)
 {
   TestApplication application;
diff --git a/automated-tests/src/dali/utc-Dali-HoverProcessing.cpp b/automated-tests/src/dali/utc-Dali-HoverProcessing.cpp
new file mode 100644 (file)
index 0000000..686fe95
--- /dev/null
@@ -0,0 +1,1452 @@
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+
+#include <stdlib.h>
+#include <dali/public-api/dali-core.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/integration-api/system-overlay.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_hover_processing_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_hover_processing_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+
+// Stores data that is populated in the callback and will be read by the TET cases
+struct SignalData
+{
+  SignalData()
+  : functorCalled( false ),
+    hoverEvent(),
+    hoveredActor()
+  {
+  }
+
+  void Reset()
+  {
+    functorCalled = false;
+
+    hoverEvent.time = 0u;
+    hoverEvent.points.clear();
+
+    hoveredActor = NULL;
+  }
+
+  bool functorCalled;
+  HoverEvent hoverEvent;
+  Actor hoveredActor;
+};
+
+// Functor that sets the data when called
+struct HoverEventFunctor
+{
+  /**
+   * Constructor.
+   * @param[in]  data         Reference to the data to store callback information.
+   * @param[in]  returnValue  What the functor should return.
+   */
+  HoverEventFunctor( SignalData& data, bool returnValue = true )
+  : signalData( data ),
+    returnValue( returnValue )
+  {
+  }
+
+  bool operator()( Actor actor, const HoverEvent& hoverEvent )
+  {
+    signalData.functorCalled = true;
+    signalData.hoveredActor = actor;
+    signalData.hoverEvent = hoverEvent;
+
+    return returnValue;
+  }
+
+  SignalData& signalData;
+  bool returnValue;
+};
+
+// Functor that removes the actor when called.
+struct RemoveActorFunctor : public HoverEventFunctor
+{
+  /**
+   * Constructor.
+   * @param[in]  data         Reference to the data to store callback information.
+   * @param[in]  returnValue  What the functor should return.
+   */
+  RemoveActorFunctor( SignalData& data, bool returnValue = true )
+  : HoverEventFunctor( data, returnValue )
+  {
+  }
+
+  bool operator()( Actor actor, const HoverEvent& hoverEvent )
+  {
+    Actor parent( actor.GetParent() );
+    if ( parent )
+    {
+      parent.Remove( actor );
+    }
+
+    return HoverEventFunctor::operator()( actor, hoverEvent );
+  }
+};
+
+Integration::HoverEvent GenerateSingleHover( TouchPoint::State state, Vector2 screenPosition )
+{
+  Integration::HoverEvent hoverEvent;
+  hoverEvent.points.push_back( TouchPoint ( 0, state, screenPosition.x, screenPosition.y ) );
+  return hoverEvent;
+}
+
+} // anon namespace
+
+///////////////////////////////////////////////////////////////////////////////
+
+int UtcDaliHoverNormalProcessing(void)
+{
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  Vector2 screenCoordinates( 10.0f, 10.0f );
+  Vector2 localCoordinates;
+  actor.ScreenToLocal( localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, screenCoordinates ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( 1u, data.hoverEvent.GetPointCount(), TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( screenCoordinates, data.hoverEvent.points[0].screen, TEST_LOCATION );
+  DALI_TEST_EQUALS( localCoordinates, data.hoverEvent.points[0].local, 0.1f, TEST_LOCATION );
+  data.Reset();
+
+  // Emit a motion signal
+  screenCoordinates.x = screenCoordinates.y = 11.0f;
+  actor.ScreenToLocal( localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, screenCoordinates ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( 1u, data.hoverEvent.GetPointCount(), TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Motion, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( screenCoordinates, data.hoverEvent.points[0].screen, TEST_LOCATION );
+  DALI_TEST_EQUALS( localCoordinates, data.hoverEvent.points[0].local, 0.1f, TEST_LOCATION );
+  data.Reset();
+
+  // Emit a finished signal
+  screenCoordinates.x = screenCoordinates.y = 12.0f;
+  actor.ScreenToLocal( localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Finished, screenCoordinates ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( 1u, data.hoverEvent.GetPointCount(), TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Finished, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( screenCoordinates, data.hoverEvent.points[0].screen, TEST_LOCATION );
+  DALI_TEST_EQUALS( localCoordinates, data.hoverEvent.points[0].local, 0.1f, TEST_LOCATION );
+  data.Reset();
+
+  // Emit a started signal where the actor is not present
+  screenCoordinates.x = screenCoordinates.y = 200.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, screenCoordinates ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliHoverOutsideCameraNearFarPlanes(void)
+{
+  TestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+  Vector2 stageSize = stage.GetSize();
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::CENTER);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  stage.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Get the camera's near and far planes
+  RenderTaskList taskList = stage.GetRenderTaskList();
+  Dali::RenderTask task = taskList.GetTask(0);
+  CameraActor camera = task.GetCameraActor();
+  float nearPlane = camera.GetNearClippingPlane();
+  float farPlane = camera.GetFarClippingPlane();
+
+  // Calculate the current distance of the actor from the camera
+  float tanHalfFov = tanf(camera.GetFieldOfView() * 0.5f);
+  float distance = (stageSize.y * 0.5f) / tanHalfFov;
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  Vector2 screenCoordinates( stageSize.x * 0.5f, stageSize.y * 0.5f );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, screenCoordinates ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Emit a started signal where actor is just at the camera's near plane
+  actor.SetZ(distance - nearPlane);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, screenCoordinates ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Emit a started signal where actor is closer than the camera's near plane
+  actor.SetZ((distance - nearPlane) + 1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, screenCoordinates ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Emit a started signal where actor is just at the camera's far plane
+  actor.SetZ(distance - farPlane);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, screenCoordinates ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Emit a started signal where actor is further than the camera's far plane
+  actor.SetZ((distance - farPlane) - 1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, screenCoordinates ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliHoverEmitEmpty(void)
+{
+  TestApplication application;
+
+  try
+  {
+    // Emit an empty HoverEvent
+    Integration::HoverEvent event;
+    application.ProcessEvent( event );
+    tet_result( TET_FAIL );
+  }
+  catch ( Dali::DaliException& e )
+  {
+    DALI_TEST_ASSERT( e, "!event.points.empty()", TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliHoverInterrupted(void)
+{
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, data.hoverEvent.points[0].state, TEST_LOCATION );
+  data.Reset();
+
+  // Emit an interrupted signal, we should be signalled regardless of whether there is a hit or not.
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Interrupted, Vector2( 200.0f, 200.0f /* Outside actor */ ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Interrupted, data.hoverEvent.points[0].state, TEST_LOCATION );
+  data.Reset();
+
+  // Emit another interrupted signal, our signal handler should not be called.
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Interrupted, Vector2( 200.0f, 200.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliHoverParentConsumer(void)
+{
+  TestApplication application;
+  Actor rootActor( Stage::GetCurrent().GetRootLayer() );
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data, false );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Connect to root actor's hovered signal
+  SignalData rootData;
+  HoverEventFunctor rootFunctor( rootData ); // Consumes signal
+  rootActor.HoveredSignal().Connect( &application, rootFunctor );
+
+  Vector2 screenCoordinates( 10.0f, 10.0f );
+  Vector2 actorCoordinates, rootCoordinates;
+  actor.ScreenToLocal( actorCoordinates.x, actorCoordinates.y, screenCoordinates.x, screenCoordinates.y );
+  rootActor.ScreenToLocal( rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, screenCoordinates ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( 1u, data.hoverEvent.GetPointCount(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 1u, rootData.hoverEvent.GetPointCount(), TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( screenCoordinates, data.hoverEvent.points[0].screen, TEST_LOCATION );
+  DALI_TEST_EQUALS( screenCoordinates, rootData.hoverEvent.points[0].screen, TEST_LOCATION );
+  DALI_TEST_EQUALS( actorCoordinates, data.hoverEvent.points[0].local, 0.1f, TEST_LOCATION );
+  DALI_TEST_EQUALS( rootCoordinates, rootData.hoverEvent.points[0].local, 0.1f, TEST_LOCATION );
+  DALI_TEST_CHECK( actor == data.hoverEvent.points[0].hitActor );
+  DALI_TEST_CHECK( actor == rootData.hoverEvent.points[0].hitActor );
+  data.Reset();
+  rootData.Reset();
+
+  // Emit a motion signal
+  screenCoordinates.x = screenCoordinates.y = 11.0f;
+  actor.ScreenToLocal( actorCoordinates.x, actorCoordinates.y, screenCoordinates.x, screenCoordinates.y );
+  rootActor.ScreenToLocal( rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, screenCoordinates ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( 1u, data.hoverEvent.GetPointCount(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 1u, rootData.hoverEvent.GetPointCount(), TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Motion, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Motion, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( screenCoordinates, data.hoverEvent.points[0].screen, TEST_LOCATION );
+  DALI_TEST_EQUALS( screenCoordinates, rootData.hoverEvent.points[0].screen, TEST_LOCATION );
+  DALI_TEST_EQUALS( actorCoordinates, data.hoverEvent.points[0].local, 0.1f, TEST_LOCATION );
+  DALI_TEST_EQUALS( rootCoordinates, rootData.hoverEvent.points[0].local, 0.1f, TEST_LOCATION );
+  DALI_TEST_CHECK( actor == data.hoverEvent.points[0].hitActor );
+  DALI_TEST_CHECK( actor == rootData.hoverEvent.points[0].hitActor );
+  data.Reset();
+  rootData.Reset();
+
+  // Emit a finished signal
+  screenCoordinates.x = screenCoordinates.y = 12.0f;
+  actor.ScreenToLocal( actorCoordinates.x, actorCoordinates.y, screenCoordinates.x, screenCoordinates.y );
+  rootActor.ScreenToLocal( rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Finished, screenCoordinates ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( 1u, data.hoverEvent.GetPointCount(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 1u, rootData.hoverEvent.GetPointCount(), TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Finished, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Finished, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( screenCoordinates, data.hoverEvent.points[0].screen, TEST_LOCATION );
+  DALI_TEST_EQUALS( screenCoordinates, rootData.hoverEvent.points[0].screen, TEST_LOCATION );
+  DALI_TEST_EQUALS( actorCoordinates, data.hoverEvent.points[0].local, 0.1f, TEST_LOCATION );
+  DALI_TEST_EQUALS( rootCoordinates, rootData.hoverEvent.points[0].local, 0.1f, TEST_LOCATION );
+  DALI_TEST_CHECK( actor == data.hoverEvent.points[0].hitActor );
+  DALI_TEST_CHECK( actor == rootData.hoverEvent.points[0].hitActor );
+  data.Reset();
+  rootData.Reset();
+
+  // Emit a started signal where the actor is not present, will hit the root actor though
+  screenCoordinates.x = screenCoordinates.y = 200.0f;
+  rootActor.ScreenToLocal( rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, screenCoordinates ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( 1u, rootData.hoverEvent.GetPointCount(), TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( screenCoordinates, rootData.hoverEvent.points[0].screen, TEST_LOCATION );
+  DALI_TEST_EQUALS( rootCoordinates, rootData.hoverEvent.points[0].local, 0.1f, TEST_LOCATION );
+  DALI_TEST_CHECK( rootActor == rootData.hoverEvent.points[0].hitActor );
+  END_TEST;
+}
+
+int UtcDaliHoverInterruptedParentConsumer(void)
+{
+  TestApplication application;
+  Actor rootActor( Stage::GetCurrent().GetRootLayer() );
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data, false );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Connect to root actor's hovered signal
+  SignalData rootData;
+  HoverEventFunctor rootFunctor( rootData ); // Consumes signal
+  rootActor.HoveredSignal().Connect( &application, rootFunctor );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_CHECK( actor == data.hoverEvent.points[0].hitActor );
+  DALI_TEST_CHECK( actor == rootData.hoverEvent.points[0].hitActor );
+  data.Reset();
+  rootData.Reset();
+
+  // Emit an interrupted signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Interrupted, Vector2( 200.0f, 200.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Interrupted, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Interrupted, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_CHECK( actor == data.hoverEvent.points[0].hitActor );
+  DALI_TEST_CHECK( actor == rootData.hoverEvent.points[0].hitActor );
+  data.Reset();
+  rootData.Reset();
+
+  // Emit another started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  data.Reset();
+  rootData.Reset();
+
+  // Remove actor from Stage
+  Stage::GetCurrent().Remove( actor );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit an interrupted signal, only root actor's signal should be called.
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Interrupted, Vector2( 200.0f, 200.0f /* Outside actor */ ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Interrupted, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_CHECK( rootActor == rootData.hoverEvent.points[0].hitActor );
+  data.Reset();
+  rootData.Reset();
+
+  // Emit another interrupted state, none of the signal's should be called.
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Interrupted, Vector2( 200.0f, 200.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( false, rootData.functorCalled, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliHoverLeave(void)
+{
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Set actor to require leave events
+  actor.SetLeaveRequired( true );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, data.hoverEvent.points[0].state, TEST_LOCATION );
+  data.Reset();
+
+  // Emit a motion signal outside of actor, should be signalled with a Leave
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2 ( 200.0f, 200.0f )) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Leave, data.hoverEvent.points[0].state, TEST_LOCATION );
+  data.Reset();
+
+  // Another motion outside of actor, no signalling
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2 ( 201.0f, 201.0f )) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Another motion event inside actor, signalled with motion
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2 ( 10.0f, 10.0f )) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Motion, data.hoverEvent.points[0].state, TEST_LOCATION );
+  data.Reset();
+
+  // We do not want to listen to leave events anymore
+  actor.SetLeaveRequired( false );
+
+  // Another motion event outside of actor, no signalling
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2 ( 200.0f, 200.0f )) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliHoverLeaveParentConsumer(void)
+{
+  TestApplication application;
+  Actor rootActor( Stage::GetCurrent().GetRootLayer() );
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data, false );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Connect to root actor's hovered signal
+  SignalData rootData;
+  HoverEventFunctor rootFunctor( rootData ); // Consumes signal
+  rootActor.HoveredSignal().Connect( &application, rootFunctor );
+
+  // Set actor to require leave events
+  actor.SetLeaveRequired( true );
+  rootActor.SetLeaveRequired( true );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_CHECK( actor == data.hoverEvent.points[0].hitActor );
+  DALI_TEST_CHECK( actor == rootData.hoverEvent.points[0].hitActor );
+  data.Reset();
+  rootData.Reset();
+
+  // Emit a motion signal outside of actor, should be signalled with a Leave
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2 ( 200.0f, 200.0f )) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Leave, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Leave, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_CHECK( actor == data.hoverEvent.points[0].hitActor );
+  DALI_TEST_CHECK( actor == rootData.hoverEvent.points[0].hitActor );
+  data.Reset();
+  rootData.Reset();
+
+  // Another motion outside of actor, only rootActor signalled
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2 ( 201.0f, 201.0f )) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Motion, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_CHECK( rootActor == rootData.hoverEvent.points[0].hitActor );
+  data.Reset();
+  rootData.Reset();
+
+  // Another motion event inside actor, signalled with motion
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2 ( 10.0f, 10.0f )) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Motion, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Motion, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_CHECK( actor == data.hoverEvent.points[0].hitActor );
+  DALI_TEST_CHECK( actor == rootData.hoverEvent.points[0].hitActor );
+  data.Reset();
+  rootData.Reset();
+
+  // We do not want to listen to leave events of actor anymore
+  actor.SetLeaveRequired( false );
+
+  // Another motion event outside of root actor, only root signalled
+  Vector2 stageSize( Stage::GetCurrent().GetSize() );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2 ( stageSize.width + 10.0f, stageSize.height + 10.0f )) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Leave, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliHoverActorBecomesInsensitive(void)
+{
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, data.hoverEvent.points[0].state, TEST_LOCATION );
+  data.Reset();
+
+  // Change actor to insensitive
+  actor.SetSensitive( false );
+
+  // Emit a motion signal, signalled with an interrupted
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2 ( 200.0f, 200.0f )) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Interrupted, data.hoverEvent.points[0].state, TEST_LOCATION );
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliHoverActorBecomesInsensitiveParentConsumer(void)
+{
+  TestApplication application;
+  Actor rootActor( Stage::GetCurrent().GetRootLayer() );
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data, false );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Connect to root actor's hovered signal
+  SignalData rootData;
+  HoverEventFunctor rootFunctor( rootData ); // Consumes signal
+  rootActor.HoveredSignal().Connect( &application, rootFunctor );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, data.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Started, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  DALI_TEST_CHECK( actor == data.hoverEvent.points[0].hitActor );
+  DALI_TEST_CHECK( actor == rootData.hoverEvent.points[0].hitActor );
+  data.Reset();
+  rootData.Reset();
+
+  // Remove actor from Stage
+  Stage::GetCurrent().Remove( actor );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Make root actor insensitive
+  rootActor.SetSensitive( false );
+
+  // Emit a motion signal, signalled with an interrupted (should get interrupted even if within root actor)
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2 ( 200.0f, 200.0f )) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, rootData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Interrupted, rootData.hoverEvent.points[0].state, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliHoverMultipleLayers(void)
+{
+  TestApplication application;
+  Actor rootActor( Stage::GetCurrent().GetRootLayer() );
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+
+  Layer layer1 ( Layer::New() );
+  layer1.SetSize(100.0f, 100.0f);
+  layer1.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add( layer1 );
+
+  Actor actor1 ( Actor::New() );
+  actor1.SetSize( 100.0f, 100.0f );
+  actor1.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  actor1.SetZ( 1.0f ); // Should hit actor1 in this layer
+  layer1.Add( actor1 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer1 and actor1
+  layer1.HoveredSignal().Connect( &application, functor );
+  actor1.HoveredSignal().Connect( &application, functor );
+
+  // Hit in hittable area, actor1 should be hit
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_CHECK( data.hoveredActor == actor1 );
+  data.Reset();
+
+  // Make layer1 insensitive, nothing should be hit
+  layer1.SetSensitive( false );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Make layer1 sensitive again, again actor1 will be hit
+  layer1.SetSensitive( true );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_CHECK( data.hoveredActor == actor1 );
+  data.Reset();
+
+  // Make rootActor insensitive, nothing should be hit
+  rootActor.SetSensitive( false );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Make rootActor sensitive
+  rootActor.SetSensitive( true );
+
+  // Add another layer
+  Layer layer2 ( Layer::New() );
+  layer2.SetSize(100.0f, 100.0f );
+  layer2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  layer2.SetZ( 10.0f ); // Should hit layer2 in this layer rather than actor2
+  Stage::GetCurrent().Add( layer2 );
+
+  Actor actor2 ( Actor::New() );
+  actor2.SetSize(100.0f, 100.0f);
+  actor2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  layer2.Add( actor2 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer2 and actor2
+  layer2.HoveredSignal().Connect( &application, functor );
+  actor2.HoveredSignal().Connect( &application, functor );
+
+  // Emit an event, should hit layer2
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  //DALI_TEST_CHECK( data.hoveredActor == layer2 ); // TODO: Uncomment this after removing renderable hack!
+  data.Reset();
+
+  // Make layer2 insensitive, should hit actor1
+  layer2.SetSensitive( false );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_CHECK( data.hoveredActor == actor1 );
+  data.Reset();
+
+  // Make layer2 sensitive again, should hit layer2
+  layer2.SetSensitive( true );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  //DALI_TEST_CHECK( data.hoveredActor == layer2 ); // TODO: Uncomment this after removing renderable hack!
+  data.Reset();
+
+  // Make layer2 invisible, render and notify
+  layer2.SetVisible( false );
+  application.SendNotification();
+  application.Render();
+
+  // Should hit actor1
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_CHECK( data.hoveredActor == actor1 );
+  data.Reset();
+
+  // Make rootActor invisible, render and notify
+  rootActor.SetVisible( false );
+  application.SendNotification();
+  application.Render();
+
+  // Should not hit anything
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliHoverMultipleRenderTasks(void)
+{
+  TestApplication application;
+  Stage stage ( Stage::GetCurrent() );
+  Vector2 stageSize ( stage.GetSize() );
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  // Create render task
+  Viewport viewport( stageSize.width * 0.5f, stageSize.height * 0.5f, stageSize.width * 0.5f, stageSize.height * 0.5f );
+  RenderTask renderTask ( Stage::GetCurrent().GetRenderTaskList().CreateTask() );
+  renderTask.SetViewport( viewport );
+  renderTask.SetInputEnabled( true );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Ensure renderTask actor can be hit too.
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( viewport.x + 5.0f, viewport.y + 5.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Disable input on renderTask, should not be hittable
+  renderTask.SetInputEnabled( false );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( viewport.x + 5.0f, viewport.y + 5.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliHoverMultipleRenderTasksWithChildLayer(void)
+{
+  TestApplication application;
+  Stage stage ( Stage::GetCurrent() );
+  Vector2 stageSize ( stage.GetSize() );
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  Layer layer = Layer::New();
+  layer.SetSize(100.0f, 100.0f);
+  layer.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  actor.Add(layer);
+
+  // Create render task
+  Viewport viewport( stageSize.width * 0.5f, stageSize.height * 0.5f, stageSize.width * 0.5f, stageSize.height * 0.5f );
+  RenderTask renderTask ( Stage::GetCurrent().GetRenderTaskList().CreateTask() );
+  renderTask.SetViewport( viewport );
+  renderTask.SetInputEnabled( true );
+  renderTask.SetSourceActor( actor );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+  layer.HoveredSignal().Connect( &application, functor );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Ensure renderTask actor can be hit too.
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( viewport.x + 5.0f, viewport.y + 5.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Disable input on renderTask, should not be hittable
+  renderTask.SetInputEnabled( false );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( viewport.x + 5.0f, viewport.y + 5.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliHoverOffscreenRenderTasks(void)
+{
+  TestApplication application;
+  Stage stage ( Stage::GetCurrent() );
+  Vector2 stageSize ( stage.GetSize() );
+
+  // FrameBufferImage for offscreen RenderTask
+  FrameBufferImage frameBufferImage( FrameBufferImage::New( stageSize.width, stageSize.height, Pixel::RGBA8888 ) );
+
+  // Create an image actor to display the FrameBufferImage
+  ImageActor imageActor ( ImageActor::New( frameBufferImage ) );
+  imageActor.SetParentOrigin(ParentOrigin::CENTER);
+  imageActor.SetSize( stageSize.x, stageSize.y );
+  imageActor.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
+  stage.Add( imageActor );
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stage.Add( actor );
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE ); // Ensure framebuffer connects
+
+  stage.GetRenderTaskList().GetTask( 0u ).SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
+
+  // Create a RenderTask
+  RenderTask renderTask = stage.GetRenderTaskList().CreateTask();
+  renderTask.SetSourceActor( actor );
+  renderTask.SetTargetFrameBuffer( frameBufferImage );
+  renderTask.SetInputEnabled( true );
+
+  // Create another RenderTask
+  RenderTask renderTask2( stage.GetRenderTaskList().CreateTask() );
+  renderTask2.SetInputEnabled( true );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliHoverMultipleRenderableActors(void)
+{
+  TestApplication application;
+  Stage stage ( Stage::GetCurrent() );
+  Vector2 stageSize ( stage.GetSize() );
+
+  Actor parent = ImageActor::New();
+  parent.SetSize(100.0f, 100.0f);
+  parent.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stage.Add(parent);
+
+  Actor actor = ImageActor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  parent.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  parent.HoveredSignal().Connect( &application, functor );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_CHECK( actor == data.hoveredActor );
+  END_TEST;
+}
+
+int UtcDaliHoverActorRemovedInSignal(void)
+{
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  RemoveActorFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Register for leave events
+  actor.SetLeaveRequired( true );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Re-add, render and notify
+  Stage::GetCurrent().Add(actor);
+  application.SendNotification();
+  application.Render();
+
+  // Emit another signal outside of actor's area, should not get anything as the scene has changed.
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 210.0f, 210.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit another signal outside of actor's area, should not get anything as the scene has changed.
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 210.0f, 210.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Re-add actor back to stage, render and notify
+  Stage::GetCurrent().Add(actor);
+  application.SendNotification();
+  application.Render();
+
+  // Emit another started event
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Completely delete the actor
+  actor = NULL;
+
+  // Emit event, should not crash and should not receive an event.
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 210.0f, 210.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliHoverActorSignalNotConsumed(void)
+{
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data, false );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliHoverActorUnStaged(void)
+{
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Emit a started signal
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Remove actor from stage
+  Stage::GetCurrent().Remove( actor );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a move at the same point, we should not be signalled.
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliHoverSystemOverlayActor(void)
+{
+  TestApplication application;
+  Dali::Integration::Core& core( application.GetCore() );
+  Dali::Integration::SystemOverlay& systemOverlay( core.GetSystemOverlay() );
+  systemOverlay.GetOverlayRenderTasks().CreateTask();
+
+  // Create an actor and add it to the system overlay.
+  Actor systemActor = Actor::New();
+  systemActor.SetSize(100.0f, 100.0f);
+  systemActor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  systemOverlay.Add( systemActor );
+
+  // Create an actor and add it to the stage as per normal, same position and size as systemActor
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Connect to the hover signals.
+  SignalData data;
+  HoverEventFunctor functor( data );
+  systemActor.HoveredSignal().Connect( &application, functor );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a started signal, the system overlay is drawn last so is at the top, should hit the systemActor.
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_CHECK( systemActor == data.hoveredActor );
+  END_TEST;
+}
+
+int UtcDaliHoverLeaveActorReadded(void)
+{
+  TestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  // Set actor to receive hover-events
+  actor.SetLeaveRequired( true );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Emit a started and motion
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 11.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Remove actor from stage and add again
+  stage.Remove( actor );
+  stage.Add( actor );
+
+  // Emit a motion within the actor's bounds
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 12.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Emit a motion outside the actor's bounds
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 200.0f, 200.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( TouchPoint::Leave, data.hoverEvent.points[0].state, TEST_LOCATION );
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliHoverStencil(void)
+{
+  TestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  TextActor actor = TextActor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  Actor stencil = Actor::New();
+  stencil.SetSize(50.0f, 50.0f);
+  stencil.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stencil.SetDrawMode( DrawMode::STENCIL );
+  stage.Add(stencil);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Emit an event within stencil area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Emit an event outside the stencil area but within the actor area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 60.0f, 60.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliHoverStencilInActorHierarchy(void)
+{
+  TestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  TextActor parent = TextActor::New();
+  parent.SetSize(100.0f, 100.0f);
+  parent.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stage.Add(parent);
+
+  TextActor child = TextActor::New();
+  child.SetSize(25.0f, 25.0f);
+  child.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  parent.Add(child);
+
+  Actor stencil = Actor::New();
+  stencil.SetSize(50.0f, 50.0f);
+  stencil.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stencil.SetDrawMode( DrawMode::STENCIL );
+  stage.Add(stencil);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to hover signals
+  SignalData parentData;
+  parent.HoveredSignal().Connect( &application, HoverEventFunctor(parentData) );
+  SignalData childData;
+  child.HoveredSignal().Connect( &application, HoverEventFunctor(childData) );
+
+  // Emit an event within stencil area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( false, parentData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, childData.functorCalled, TEST_LOCATION );
+  parentData.Reset();
+  childData.Reset();
+
+  // Emit an event outside child area and within stencil area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 40.0f, 40.0f ) ) );
+  DALI_TEST_EQUALS( true, parentData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( false, childData.functorCalled, TEST_LOCATION );
+  parentData.Reset();
+  childData.Reset();
+
+  // Emit an event outside stencil are but within parent area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 60.0f, 60.0f ) ) );
+  DALI_TEST_EQUALS( false, parentData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( false, childData.functorCalled, TEST_LOCATION );
+  parentData.Reset();
+  childData.Reset();
+
+  // Readd actor (so that stencil is the first child)
+  stage.Remove(parent);
+  application.SendNotification();
+  application.Render();
+  stage.Add(parent);
+  application.SendNotification();
+  application.Render();
+
+  // Redo hit in same area...
+
+  // Emit an event within stencil area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( false, parentData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( true, childData.functorCalled, TEST_LOCATION );
+  parentData.Reset();
+  childData.Reset();
+
+  // Emit an event outside child area and within stencil area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 40.0f, 40.0f ) ) );
+  DALI_TEST_EQUALS( true, parentData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( false, childData.functorCalled, TEST_LOCATION );
+  parentData.Reset();
+  childData.Reset();
+
+  // Emit an event outside stencil are but within parent area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, Vector2( 60.0f, 60.0f ) ) );
+  DALI_TEST_EQUALS( false, parentData.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( false, childData.functorCalled, TEST_LOCATION );
+  parentData.Reset();
+  childData.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliHoverMultipleStencils(void)
+{
+  TestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  TextActor actor = TextActor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  Actor stencil = Actor::New();
+  stencil.SetSize(50.0f, 50.0f);
+  stencil.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stencil.SetDrawMode( DrawMode::STENCIL );
+  stage.Add(stencil);
+
+  Actor stencil2 = Actor::New();
+  stencil2.SetSize(50.0f, 50.0f);
+  stencil2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stencil2.SetDrawMode( DrawMode::STENCIL );
+  stencil2.SetPosition(50.0f, 50.0f);
+  stage.Add(stencil2);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Emit an event within stencil area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Emit an event inside the second stencil area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 60.0f, 60.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Emit an event outside both stencil areas but within the actor area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 60.0f ) ) );
+  DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliHoverStencilNonRenderableActor(void)
+{
+  TestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  Actor stencil = Actor::New();
+  stencil.SetSize(50.0f, 50.0f);
+  stencil.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  stencil.SetDrawMode( DrawMode::STENCIL );
+  stage.Add(stencil);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData data;
+  HoverEventFunctor functor( data );
+  actor.HoveredSignal().Connect( &application, functor );
+
+  // Emit an event within stencil area
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 10.0f, 10.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  // Emit an event outside the stencil area but within the actor area, we should have a hit!
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, Vector2( 60.0f, 60.0f ) ) );
+  DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+  data.Reset();
+
+  END_TEST;
+}
index 5ec2a06..82ca140 100644 (file)
@@ -524,6 +524,17 @@ int UtcDaliLayerTouchConsumed(void)
   END_TEST;
 }
 
+int UtcDaliLayerHoverConsumed(void)
+{
+  TestApplication application;
+  Layer layer = Layer::New();
+
+  DALI_TEST_EQUALS( layer.IsHoverConsumed(), false, TEST_LOCATION );
+  layer.SetHoverConsumed( true );
+  DALI_TEST_EQUALS( layer.IsHoverConsumed(), true, TEST_LOCATION );
+  END_TEST;
+}
+
 int UtcDaliLayerClippingGLCalls(void)
 {
   TestApplication application;
@@ -547,6 +558,5 @@ int UtcDaliLayerClippingGLCalls(void)
   DALI_TEST_EQUALS( testBox.y, stage.GetSize().height - glScissorParams.y - testBox.height, TEST_LOCATION ); // GL Coordinates are from bottom left
   DALI_TEST_EQUALS( testBox.width, glScissorParams.width, TEST_LOCATION );
   DALI_TEST_EQUALS( testBox.height, glScissorParams.height, TEST_LOCATION );
-
   END_TEST;
 }
index 80eb3da..fb1eafa 100644 (file)
@@ -21,6 +21,7 @@
 #include <dali/public-api/dali-core.h>
 #include <dali/integration-api/events/touch-event-combiner.h>
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
 #include <dali-test-suite-utils.h>
 
 using namespace Dali;
@@ -216,9 +217,10 @@ int UtcDaliTouchEventCombinerSingleTouchNormal(void)
   // Down event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Down, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -230,9 +232,10 @@ int UtcDaliTouchEventCombinerSingleTouchNormal(void)
   // Motion in X direction
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Motion, 101.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -244,9 +247,10 @@ int UtcDaliTouchEventCombinerSingleTouchNormal(void)
   // Motion in Y direction
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Motion, 101.0f, 101.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -256,9 +260,10 @@ int UtcDaliTouchEventCombinerSingleTouchNormal(void)
   // Motion event, but same time
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Motion, 102.0f, 102.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
 
   time++;
@@ -266,9 +271,10 @@ int UtcDaliTouchEventCombinerSingleTouchNormal(void)
   // Motion event, both X and Y movement
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Motion, 102.0f, 102.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -280,17 +286,19 @@ int UtcDaliTouchEventCombinerSingleTouchNormal(void)
   // Motion event, no movement
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Motion, 102.0f, 102.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
 
   // Up event, no time diff, no movement
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Up, 102.0f, 102.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -307,9 +315,14 @@ int UtcDaliTouchEventCombinerSingleTouchMotionWithoutDown(void)
   // Motion event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Motion, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchHover, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.GetPointCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].state, TouchPoint::Started, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].screen, point.screen, TEST_LOCATION );
   }
 
   time++;
@@ -317,9 +330,83 @@ int UtcDaliTouchEventCombinerSingleTouchMotionWithoutDown(void)
   // Motion event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Motion, 102.0f, 102.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchHover, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.GetPointCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].state, point.state, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].screen, point.screen, TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliTouchEventCombinerSingleTouchMotionFollowedByDown(void)
+{
+  TouchEventCombiner combiner;
+  unsigned long time( 0u );
+
+  // Motion event
+  {
+    Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
+    TouchPoint point( 1, TouchPoint::Motion, 100.0f, 100.0f );
+
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchHover, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.GetPointCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].state, TouchPoint::Started, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].screen, point.screen, TEST_LOCATION );
+  }
+
+  time++;
+
+  // Motion event
+  {
+    Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
+    TouchPoint point( 1, TouchPoint::Motion, 102.0f, 102.0f );
+
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchHover, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.GetPointCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].state, point.state, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].screen, point.screen, TEST_LOCATION );
+  }
+
+  time++;
+
+  // Motion event
+  {
+    Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
+    TouchPoint point( 1, TouchPoint::Motion, 103.0f, 103.0f );
+
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchHover, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.GetPointCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].state, point.state, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].screen, point.screen, TEST_LOCATION );
+  }
+
+  time++;
+
+  // Down event
+  {
+    Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
+    TouchPoint point( 1, TouchPoint::Down, 103.0f, 103.0f );
+
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchBoth, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
+    DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
+    DALI_TEST_EQUALS( touchEvent.points[0].screen, point.screen, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.GetPointCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].state, TouchPoint::Finished, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].screen, point.screen, TEST_LOCATION );
   }
   END_TEST;
 }
@@ -332,9 +419,10 @@ int UtcDaliTouchEventCombinerSingleTouchTwoDowns(void)
   // Down event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Down, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -346,9 +434,10 @@ int UtcDaliTouchEventCombinerSingleTouchTwoDowns(void)
   // Another down with the same ID
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Down, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
   END_TEST;
 }
@@ -361,9 +450,10 @@ int UtcDaliTouchEventCombinerSingleTouchUpWithoutDown(void)
   // Up event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Up, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
 
   time++;
@@ -371,9 +461,10 @@ int UtcDaliTouchEventCombinerSingleTouchUpWithoutDown(void)
   // Up event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Up, 102.0f, 102.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
   END_TEST;
 }
@@ -386,9 +477,10 @@ int UtcDaliTouchEventCombinerSingleTouchTwoUps(void)
   // Down event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Down, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -400,9 +492,10 @@ int UtcDaliTouchEventCombinerSingleTouchTwoUps(void)
   // Up event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Up, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -414,9 +507,10 @@ int UtcDaliTouchEventCombinerSingleTouchTwoUps(void)
   // Another up event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Up, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
   END_TEST;
 }
@@ -429,9 +523,10 @@ int UtcDaliTouchEventCombinerSingleTouchUpWithDifferentId(void)
   // Down event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Down, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -443,9 +538,10 @@ int UtcDaliTouchEventCombinerSingleTouchUpWithDifferentId(void)
   // Up event with different ID
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 2, TouchPoint::Up, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
 
   time++;
@@ -453,9 +549,10 @@ int UtcDaliTouchEventCombinerSingleTouchUpWithDifferentId(void)
   // Up event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Up, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -472,9 +569,10 @@ int UtcDaliTouchEventCombinerSingleTouchMotionWithDifferentId(void)
   // Down event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Down, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -486,9 +584,14 @@ int UtcDaliTouchEventCombinerSingleTouchMotionWithDifferentId(void)
   // Motion event with different ID
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 2, TouchPoint::Motion, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchHover, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.GetPointCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].state, TouchPoint::Started, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].screen, point.screen, TEST_LOCATION );
   }
 
   time++;
@@ -496,9 +599,10 @@ int UtcDaliTouchEventCombinerSingleTouchMotionWithDifferentId(void)
   // Motion event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Motion, 102.0f, 102.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -515,9 +619,10 @@ int UtcDaliTouchEventCombinerMultiTouchNormal(void)
   // 1st point down
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Down, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -529,9 +634,10 @@ int UtcDaliTouchEventCombinerMultiTouchNormal(void)
   // 2nd point down
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 2, TouchPoint::Down, 200.0f, 200.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 2u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[1].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, TouchPoint::Stationary, TEST_LOCATION );
@@ -544,9 +650,10 @@ int UtcDaliTouchEventCombinerMultiTouchNormal(void)
   // 1st point motion
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Motion, 101.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 2u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -557,9 +664,10 @@ int UtcDaliTouchEventCombinerMultiTouchNormal(void)
   // 2nd point motion, no time diff
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 2, TouchPoint::Motion, 200.0f, 200.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
 
   time++;
@@ -567,9 +675,10 @@ int UtcDaliTouchEventCombinerMultiTouchNormal(void)
   // 2nd point motion
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 2, TouchPoint::Motion, 201.0f, 201.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 2u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[1].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, TouchPoint::Stationary, TEST_LOCATION );
@@ -582,9 +691,10 @@ int UtcDaliTouchEventCombinerMultiTouchNormal(void)
   // 1st point up
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Up, 101.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 2u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -597,9 +707,10 @@ int UtcDaliTouchEventCombinerMultiTouchNormal(void)
   // 2nd point motion
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 2, TouchPoint::Motion, 202.0f, 202.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -611,9 +722,10 @@ int UtcDaliTouchEventCombinerMultiTouchNormal(void)
   // 2nd point up
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 2, TouchPoint::Up, 202.0f, 202.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -632,9 +744,10 @@ int UtcDaliTouchEventCombinerSeveralPoints(void)
   for ( unsigned int pointCount = 1u; pointCount < maximum; ++pointCount )
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( pointCount, TouchPoint::Down, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time++, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time++, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), pointCount, TEST_LOCATION );
   }
 
@@ -642,9 +755,10 @@ int UtcDaliTouchEventCombinerSeveralPoints(void)
   for ( unsigned int pointCount = maximum - 1; pointCount > 0; --pointCount )
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( pointCount, TouchPoint::Up, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time++, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time++, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), pointCount, TEST_LOCATION );
   }
   END_TEST;
@@ -658,9 +772,10 @@ int UtcDaliTouchEventCombinerReset(void)
   // Down event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Down, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -675,9 +790,10 @@ int UtcDaliTouchEventCombinerReset(void)
   // Up event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Up, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
   END_TEST;
 }
@@ -690,9 +806,10 @@ int UtcDaliTouchEventCombinerSingleTouchInterrupted(void)
   // Down event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Down, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].deviceId, point.deviceId, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
@@ -704,20 +821,24 @@ int UtcDaliTouchEventCombinerSingleTouchInterrupted(void)
   // Interrupted event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Interrupted, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchBoth, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.GetPointCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].state, point.state, TEST_LOCATION );
   }
 
   // Send up, should not be able to send as combiner has been reset.
   // Up event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Up, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
   END_TEST;
 }
@@ -732,29 +853,34 @@ int UtcDaliTouchEventCombinerMultiTouchInterrupted(void)
   for ( unsigned int pointCount = 1u; pointCount < maximum; ++pointCount )
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( pointCount, TouchPoint::Down, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time++, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchTouch, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), pointCount, TEST_LOCATION );
   }
 
   // Interrupted event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Interrupted, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( true, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchBoth, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.GetPointCount(), 1u, TEST_LOCATION );
     DALI_TEST_EQUALS( touchEvent.points[0].state, point.state, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.GetPointCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( hoverEvent.points[0].state, point.state, TEST_LOCATION );
   }
 
   // Send up, should not be able to send as combiner has been reset.
   // Up event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Up, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
   END_TEST;
 }
@@ -767,9 +893,10 @@ int UtcDaliTouchEventCombinerInvalidState(void)
   // Stationary event
   {
     Integration::TouchEvent touchEvent;
+    Integration::HoverEvent hoverEvent;
     TouchPoint point( 1, TouchPoint::Stationary, 100.0f, 100.0f );
 
-    DALI_TEST_EQUALS( false, combiner.GetNextTouchEvent( point, time, touchEvent ), TEST_LOCATION );
+    DALI_TEST_EQUALS( Integration::TouchEventCombiner::DispatchNone, combiner.GetNextTouchEvent( point, time, touchEvent, hoverEvent ), TEST_LOCATION );
   }
   END_TEST;
 }
index 6883981..474dec0 100644 (file)
@@ -47,7 +47,8 @@ struct Event
     Touch,         ///< A touch event, when the user interacts with the screen.
     Key,           ///< A key pressed event, from the virtual or external keyboard.
     Gesture,       ///< A Gesture event has been detected.
-    MouseWheel     ///< A mouse wheel event, when the mouse wheel is being rolled from an external mouse.
+    MouseWheel,    ///< A mouse wheel event, when the mouse wheel is being rolled from an external mouse.
+    Hover          ///< A hover event, when the user hovers above the screen.
   };
 
   // Data
diff --git a/dali/integration-api/events/hover-event-integ.cpp b/dali/integration-api/events/hover-event-integ.cpp
new file mode 100644 (file)
index 0000000..4b846a8
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/integration-api/events/hover-event-integ.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+
+HoverEvent::HoverEvent()
+: MultiPointEvent( Hover )
+{
+}
+
+HoverEvent::HoverEvent( unsigned long time )
+: MultiPointEvent( Hover, time )
+{
+}
+
+HoverEvent::~HoverEvent()
+{
+}
+
+} // namespace Integration
+
+} // namespace Dali
diff --git a/dali/integration-api/events/hover-event-integ.h b/dali/integration-api/events/hover-event-integ.h
new file mode 100644 (file)
index 0000000..7d7bffd
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __DALI_INTEGRATION_HOVER_EVENT_H__
+#define __DALI_INTEGRATION_HOVER_EVENT_H__
+
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/events/hover-event.h>
+#include <dali/integration-api/events/multi-point-event-integ.h>
+
+namespace Dali DALI_IMPORT_API
+{
+
+namespace Integration
+{
+
+/**
+ * An instance of this structure should be used by the adaptor to send a hover event to Dali core.
+ *
+ * This class can contain one or many touch points. It also contains the time at which the
+ * event occurred.
+ */
+struct HoverEvent : public MultiPointEvent
+{
+  // Construction & Destruction
+
+  /**
+   * Default Constructor
+   */
+  HoverEvent();
+
+  /**
+   * Constructor
+   * @param[in]  time  The time the event occurred.
+   */
+  HoverEvent(unsigned long time);
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~HoverEvent();
+};
+
+} // namespace Integration
+
+} // namespace Dali
+
+#endif // __DALI_INTEGRATION_HOVER_EVENT_H__
diff --git a/dali/integration-api/events/multi-point-event-integ.cpp b/dali/integration-api/events/multi-point-event-integ.cpp
new file mode 100644 (file)
index 0000000..9320a45
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/integration-api/events/multi-point-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+
+MultiPointEvent::MultiPointEvent( Type eventType )
+: Event( eventType ),
+  time( 0 )
+{
+}
+
+MultiPointEvent::MultiPointEvent( Type eventType, unsigned long time )
+: Event( eventType ),
+  time( time )
+{
+}
+
+MultiPointEvent::~MultiPointEvent()
+{
+}
+
+void MultiPointEvent::AddPoint(const TouchPoint& point)
+{
+  points.push_back(point);
+}
+
+TouchPoint& MultiPointEvent::GetPoint(unsigned int point)
+{
+  DALI_ASSERT_ALWAYS(point < points.size() && "MultiPointEvent: Point index out of bounds");
+  return points[point];
+}
+
+const TouchPoint& MultiPointEvent::GetPoint(unsigned int point) const
+{
+  DALI_ASSERT_ALWAYS(point < points.size() && "MultiPointEvent: Point index out of bounds");
+  return points[point];
+}
+
+unsigned int MultiPointEvent::GetPointCount() const
+{
+  return points.size();
+}
+
+} // namespace Integration
+
+} // namespace Dali
diff --git a/dali/integration-api/events/multi-point-event-integ.h b/dali/integration-api/events/multi-point-event-integ.h
new file mode 100644 (file)
index 0000000..b5dd601
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef __DALI_INTEGRATION_MULTI_POINT_EVENT_H__
+#define __DALI_INTEGRATION_MULTI_POINT_EVENT_H__
+
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/integration-api/events/event.h>
+#include <dali/public-api/events/touch-point.h>
+
+namespace Dali DALI_IMPORT_API
+{
+
+namespace Integration
+{
+
+/**
+ * An instance of this structure should be used by the adaptor to send a multi-point event to Dali core.
+ *
+ * This class can contain one or multiple touch points. It also contains the time at which the
+ * event occurred.
+ */
+struct MultiPointEvent : public Event
+{
+  // Construction & Destruction
+
+public:
+  /**
+   * Virtual destructor
+   */
+  virtual ~MultiPointEvent();
+
+protected:
+  /**
+   * Default Constructor
+   */
+  MultiPointEvent(Type eventType);
+
+  /**
+   * Constructor
+   * @param[in]  time  The time the event occurred.
+   */
+  MultiPointEvent(Type eventType, unsigned long time);
+
+public:
+  // Data
+
+  /**
+   * @copydoc Dali::MultiPointEvent::points
+   */
+  std::vector<TouchPoint> points;
+
+  /**
+   * @copydoc Dali::MultiPointEvent::time
+   */
+  unsigned long time;
+
+  // Convenience Methods
+
+  /**
+   * Adds a point to the MultiPointEvent.
+   * @param[in]  point  The point to add.
+   */
+  void AddPoint(const TouchPoint& point);
+
+  /**
+   * @copydoc Dali::MultiPointEvent::GetPoint()
+   */
+  TouchPoint& GetPoint(unsigned int point);
+
+  /**
+   * @copydoc Dali::MultiPointEvent::GetPoint()
+   */
+  const TouchPoint& GetPoint(unsigned int point) const;
+
+  /**
+   * @copydoc Dali::MultiPointEvent::GetPointCount() const
+   */
+  unsigned int GetPointCount() const;
+};
+
+} // namespace Integration
+
+} // namespace Dali
+
+#endif // __DALI_INTEGRATION_MULTI_POINT_EVENT_H__
index 0a3d35d..7a3ddad 100644 (file)
@@ -23,6 +23,7 @@
 
 // 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
@@ -82,13 +83,13 @@ TouchEventCombiner::~TouchEventCombiner()
 {
 }
 
-bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned long time, TouchEvent& touchEvent )
+TouchEventCombiner::EventDispatchType TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned long time, TouchEvent& touchEvent, HoverEvent& hoverEvent )
 {
-  bool dispatchEvent( false );
+  TouchEventCombiner::EventDispatchType dispatchEvent( TouchEventCombiner::DispatchNone );
 
   switch ( point.state )
   {
-    case TouchPoint::Down:
+    case TouchPoint::Started:
     {
       touchEvent.time = time;
       bool addToContainer( true );
@@ -117,13 +118,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::DispatchTouch; // 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 ( point.deviceId == iter->point.deviceId )
+            {
+              match = iter;
+              // Add new point to the HoverEvent
+              iter->point.state = TouchPoint::Finished;
+              hoverEvent.AddPoint( iter->point );
+            }
+            else
+            {
+              iter->point.state = TouchPoint::Stationary;
+              hoverEvent.AddPoint( iter->point );
+            }
+          }
+
+          if ( match != mHoveredPoints.end() )
+          {
+            mHoveredPoints.erase( match );
+            dispatchEvent = TouchEventCombiner::DispatchBoth; // We should only dispatch hover events if the point was actually hovered in this window
+          }
+        }
       }
 
       break;
     }
 
-    case TouchPoint::Up:
+    case TouchPoint::Finished:
     {
       touchEvent.time = time;
 
@@ -148,17 +178,29 @@ 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::DispatchTouch; // 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.deviceId == point.deviceId )
+          {
+            mHoveredPoints.erase( iter );
+          }
+        }
       }
       break;
     }
 
     case TouchPoint::Motion:
     {
+      bool fromNewDeviceId = false;
+
       if ( !mPressedPoints.empty() )
       {
         touchEvent.time = time;
 
+        bool ignore = false;
         PointInfoContainer::iterator match = mPressedPoints.end();
         for ( PointInfoContainer::iterator iter = mPressedPoints.begin(), endIter = mPressedPoints.end(); iter != endIter; ++iter )
         {
@@ -169,6 +211,7 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
             if ( timeDiff < mMinMotionTime )
             {
               // Motion event sent too soon after previous event so ignore
+              ignore = true;
               break;
             }
 
@@ -176,6 +219,7 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
                  ( abs( point.screen.y - iter->point.screen.y ) < mMinMotionDistance.y ) )
             {
               // Not enough positional change from last event so ignore
+              ignore = true;
               break;
             }
 
@@ -196,7 +240,79 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
           PointInfo matchedPoint( point, time );
           std::swap( *match, matchedPoint );
 
-          dispatchEvent = true;
+          dispatchEvent = TouchEventCombiner::DispatchTouch; // 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();
+        for ( PointInfoContainer::iterator iter = mHoveredPoints.begin(), endIter = mHoveredPoints.end(); iter != endIter; ++iter )
+        {
+          if ( iter->point.deviceId == point.deviceId )
+          {
+            unsigned long 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 ) )
+            {
+              // 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.state = TouchPoint::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() )
+          {
+            TouchPoint hoverPoint(point);
+            hoverPoint.state = TouchPoint::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::DispatchTouch)
+          {
+            dispatchEvent = TouchEventCombiner::DispatchBoth;
+          }
+          else
+          {
+            dispatchEvent = TouchEventCombiner::DispatchHover;
+          }
         }
       }
       break;
@@ -208,7 +324,8 @@ bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned lo
 
       // We should still tell core about the interruption.
       touchEvent.AddPoint( point );
-      dispatchEvent = true;
+      hoverEvent.AddPoint( point );
+      dispatchEvent = TouchEventCombiner::DispatchBoth;
       break;
     }
 
@@ -259,6 +376,7 @@ Vector2 TouchEventCombiner::GetMinimumMotionDistanceThreshold() const
 void TouchEventCombiner::Reset()
 {
   mPressedPoints.clear();
+  mHoveredPoints.clear();
 }
 
 } // namespace Integration
index 27627bc..1c3b351 100644 (file)
@@ -30,13 +30,14 @@ namespace Integration
 {
 
 struct TouchEvent;
+struct HoverEvent;
 
 /**
  * Dali::Integration::TouchEventCombiner is a utility class, an instance of which, should be created
  * upon initialisation.  It accepts single Point(s) containing information about a touch area and
- * creates a TouchEvent combining the latest event's information with previous TouchPoint(s).
+ * creates a TouchEvent and/or HoverEvent combining the latest event's information with previous TouchPoint(s).
  *
- * The created TouchEvent can then be sent to the Dali Core as indicated by the GetNextTouchEvent()
+ * The created TouchEvent and/or HoverEvent can then be sent to the Dali Core as indicated by the GetNextTouchEvent()
  * method.
  *
  * The TouchEventCombiner ensures that the following rules are also adhered to:
@@ -49,6 +50,16 @@ class TouchEventCombiner
 {
 public:
 
+  // Enumerations
+
+  enum EventDispatchType
+  {
+    DispatchTouch,      ///< The touch event should be dispatched.
+    DispatchHover,      ///< The hover event should be dispatched.
+    DispatchBoth,       ///< Both touch event and hover event should be dispatched.
+    DispatchNone        ///< Neither touch event nor hover event should be dispatched.
+  };
+
   /**
    * Default Constructor.
    * @note The default minimum motion time is 1 ms between motion events and the default behaviour
@@ -81,19 +92,20 @@ public:
 public:
 
   /**
-   * Allows the caller to pass in a point which is processed and the TouchEvent is appropriately filled with the new,
+   * Allows the caller to pass in a point which is processed and the TouchEvent and/or HoverEvent is appropriately filled with the new,
    * and previously stored Point information.
    *
-   * @note If the thresholds set have not been passed, then false is returned and the TouchEvent should not be sent
+   * @note If the thresholds set have not been passed, then false is returned and the TouchEvent and/or HoverEvent should not be sent
    * to Dali Core.
    *
    * @param[in]   point         The new Point.
    * @param[in]   time          The time the event occurred.
    * @param[out]  touchEvent    This is populated with the correct Point(s) and time information.
+   * @param[out]  hoverEvent    This is populated with the correct Point(s) and time information.
    *
    * @return true if the point is beyond the different thresholds set thus, should be sent to core, false otherwise.
    */
-  bool GetNextTouchEvent( const TouchPoint& point, unsigned long time, TouchEvent& touchEvent );
+  EventDispatchType GetNextTouchEvent( const TouchPoint& point, unsigned long time, TouchEvent& touchEvent, HoverEvent& hoverEvent );
 
   /**
    * Sets the minimum time (in ms) that should occur between motion events.
@@ -148,7 +160,8 @@ private:
 
   struct PointInfo;
   typedef std::vector< PointInfo > PointInfoContainer;
-  PointInfoContainer mPressedPoints; ///< A container of point and time.
+  PointInfoContainer mPressedPoints; ///< A container of touched point and time.
+  PointInfoContainer mHoveredPoints; ///< A container of hovered point and time.
 
   unsigned long mMinMotionTime; ///< The minimum time that should elapse before considering a new motion event.
   Vector2 mMinMotionDistance; ///< The minimum distance in the X and Y direction before considering a new motion event.
index 438530f..ac44731 100644 (file)
@@ -18,9 +18,6 @@
 // CLASS HEADER
 #include <dali/integration-api/events/touch-event-integ.h>
 
-// INTERNAL INCLUDES
-#include <dali/public-api/common/dali-common.h>
-
 namespace Dali
 {
 
@@ -28,14 +25,12 @@ namespace Integration
 {
 
 TouchEvent::TouchEvent()
-: Event(Touch),
-  time(0)
+: MultiPointEvent( Touch )
 {
 }
 
-TouchEvent::TouchEvent(unsigned long time)
-: Event(Touch),
-  time(time)
+TouchEvent::TouchEvent( unsigned long time )
+: MultiPointEvent( Touch, time )
 {
 }
 
@@ -43,28 +38,6 @@ TouchEvent::~TouchEvent()
 {
 }
 
-void TouchEvent::AddPoint(const TouchPoint& point)
-{
-  points.push_back(point);
-}
-
-TouchPoint& TouchEvent::GetPoint(unsigned int point)
-{
-  DALI_ASSERT_ALWAYS(point < points.size() && "TouchEvent: Point index out of bounds");
-  return points[point];
-}
-
-const TouchPoint& TouchEvent::GetPoint(unsigned int point) const
-{
-  DALI_ASSERT_ALWAYS(point < points.size() && "TouchEvent: Point index out of bounds");
-  return points[point];
-}
-
-unsigned int TouchEvent::GetPointCount() const
-{
-  return points.size();
-}
-
 } // namespace Integration
 
 } // namespace Dali
index 86cfe5e..86752aa 100644 (file)
  */
 
 // INTERNAL INCLUDES
-#include <dali/public-api/common/vector-wrapper.h>
-#include <dali/integration-api/events/event.h>
 #include <dali/public-api/events/touch-event.h>
-#include <dali/public-api/events/touch-point.h>
+#include <dali/integration-api/events/multi-point-event-integ.h>
 
 namespace Dali DALI_IMPORT_API
 {
@@ -36,7 +34,7 @@ namespace Integration
  * This class can contain one or many touch points. It also contains the time at which the
  * event occurred.
  */
-struct TouchEvent : public Event
+struct TouchEvent : public MultiPointEvent
 {
   // Construction & Destruction
 
@@ -55,41 +53,6 @@ struct TouchEvent : public Event
    * Virtual destructor
    */
   virtual ~TouchEvent();
-
-  // Data
-
-  /**
-   * @copydoc Dali::TouchEvent::points
-   */
-  std::vector<TouchPoint> points;
-
-  /**
-   * @copydoc Dali::TouchEvent::time
-   */
-  unsigned long time;
-
-  // Convenience Methods
-
-  /**
-   * Adds a point to the TouchEvent.
-   * @param[in]  point  The point to add.
-   */
-  void AddPoint(const TouchPoint& point);
-
-  /**
-   * @copydoc Dali::TouchEvent::GetPoint()
-   */
-  TouchPoint& GetPoint(unsigned int point);
-
-  /**
-   * @copydoc Dali::TouchEvent::GetPoint()
-   */
-  const TouchPoint& GetPoint(unsigned int point) const;
-
-  /**
-   * @copydoc Dali::TouchEvent::GetPointCount() const
-   */
-  unsigned int GetPointCount() const;
 };
 
 } // namespace Integration
index 5620edd..c820882 100644 (file)
@@ -13,9 +13,11 @@ platform_abstraction_src_files = \
    $(platform_abstraction_src_dir)/common/lockless-buffer.cpp \
    $(platform_abstraction_src_dir)/events/event.cpp \
    $(platform_abstraction_src_dir)/events/gesture-event.cpp \
+   $(platform_abstraction_src_dir)/events/hover-event-integ.cpp \
    $(platform_abstraction_src_dir)/events/key-event-integ.cpp \
    $(platform_abstraction_src_dir)/events/long-press-gesture-event.cpp \
    $(platform_abstraction_src_dir)/events/mouse-wheel-event-integ.cpp \
+   $(platform_abstraction_src_dir)/events/multi-point-event-integ.cpp \
    $(platform_abstraction_src_dir)/events/pan-gesture-event.cpp \
    $(platform_abstraction_src_dir)/events/pinch-gesture-event.cpp \
    $(platform_abstraction_src_dir)/events/tap-gesture-event.cpp \
@@ -60,9 +62,11 @@ platform_abstraction_events_header_files = \
    $(platform_abstraction_src_dir)/events/event.h \
    $(platform_abstraction_src_dir)/events/gesture-event.h \
    $(platform_abstraction_src_dir)/events/gesture-requests.h \
+   $(platform_abstraction_src_dir)/events/hover-event-integ.h \
    $(platform_abstraction_src_dir)/events/key-event-integ.h \
    $(platform_abstraction_src_dir)/events/long-press-gesture-event.h \
    $(platform_abstraction_src_dir)/events/mouse-wheel-event-integ.h \
+   $(platform_abstraction_src_dir)/events/multi-point-event-integ.h \
    $(platform_abstraction_src_dir)/events/pan-gesture-event.h \
    $(platform_abstraction_src_dir)/events/pinch-gesture-event.h \
    $(platform_abstraction_src_dir)/events/tap-gesture-event.h \
index fcb0680..0968ac9 100644 (file)
@@ -209,9 +209,10 @@ BaseHandle CreateActor()
 TypeRegistration mType( typeid(Dali::Actor), typeid(Dali::Handle), CreateActor );
 
 SignalConnectorType signalConnector1(mType, Dali::Actor::SIGNAL_TOUCHED,    &Actor::DoConnectSignal);
-SignalConnectorType signalConnector2(mType, Dali::Actor::SIGNAL_SET_SIZE,   &Actor::DoConnectSignal);
-SignalConnectorType signalConnector3(mType, Dali::Actor::SIGNAL_ON_STAGE,   &Actor::DoConnectSignal);
-SignalConnectorType signalConnector4(mType, Dali::Actor::SIGNAL_OFF_STAGE,  &Actor::DoConnectSignal);
+SignalConnectorType signalConnector2(mType, Dali::Actor::SIGNAL_HOVERED,    &Actor::DoConnectSignal);
+SignalConnectorType signalConnector3(mType, Dali::Actor::SIGNAL_SET_SIZE,   &Actor::DoConnectSignal);
+SignalConnectorType signalConnector4(mType, Dali::Actor::SIGNAL_ON_STAGE,   &Actor::DoConnectSignal);
+SignalConnectorType signalConnector5(mType, Dali::Actor::SIGNAL_OFF_STAGE,  &Actor::DoConnectSignal);
 
 TypeAction a1(mType, Dali::Actor::ACTION_SHOW, &Actor::DoAction);
 TypeAction a2(mType, Dali::Actor::ACTION_HIDE, &Actor::DoAction);
@@ -1863,6 +1864,11 @@ bool Actor::GetTouchRequired() const
   return !mTouchedSignalV2.Empty() || mDerivedRequiresTouch;
 }
 
+bool Actor::GetHoverRequired() const
+{
+  return !mHoveredSignalV2.Empty() || mDerivedRequiresHover;
+}
+
 bool Actor::GetMouseWheelEventRequired() const
 {
   return !mMouseWheelEventSignalV2.Empty() || mDerivedRequiresMouseWheelEvent;
@@ -1911,6 +1917,25 @@ bool Actor::EmitTouchEventSignal(const TouchEvent& event)
   return consumed;
 }
 
+bool Actor::EmitHoverEventSignal(const HoverEvent& event)
+{
+  bool consumed = false;
+
+  if ( !mHoveredSignalV2.Empty() )
+  {
+    Dali::Actor handle( this );
+    consumed = mHoveredSignalV2.Emit( handle, event );
+  }
+
+  if (!consumed)
+  {
+    // Notification for derived classes
+    consumed = OnHoverEvent( event );
+  }
+
+  return consumed;
+}
+
 bool Actor::EmitMouseWheelEventSignal(const MouseWheelEvent& event)
 {
   bool consumed = false;
@@ -1935,6 +1960,11 @@ Dali::Actor::TouchSignalV2& Actor::TouchedSignal()
   return mTouchedSignalV2;
 }
 
+Dali::Actor::HoverSignalV2& Actor::HoveredSignal()
+{
+  return mHoveredSignalV2;
+}
+
 Dali::Actor::MouseWheelEventSignalV2& Actor::MouseWheelEventSignal()
 {
   return mMouseWheelEventSignalV2;
@@ -1964,6 +1994,10 @@ bool Actor::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tra
   {
     actor->TouchedSignal().Connect( tracker, functor );
   }
+  else if(Dali::Actor::SIGNAL_HOVERED == signalName)
+  {
+    actor->HoveredSignal().Connect( tracker, functor );
+  }
   else if(Dali::Actor::SIGNAL_MOUSE_WHEEL_EVENT == signalName)
   {
     actor->MouseWheelEventSignal().Connect( tracker, functor );
@@ -2013,6 +2047,7 @@ Actor::Actor( DerivedType derivedType )
   mLeaveRequired( false ),
   mKeyboardFocusable( false ),
   mDerivedRequiresTouch( false ),
+  mDerivedRequiresHover( false ),
   mDerivedRequiresMouseWheelEvent( false ),
   mOnStageSignalled( false ),
   mInheritRotation( true ),
index 7a16a3a..e23cbd6 100644 (file)
@@ -44,6 +44,7 @@ namespace Dali
 
 struct KeyEvent;
 struct TouchEvent;
+struct HoverEvent;
 struct MouseWheelEvent;
 
 namespace Internal
@@ -607,23 +608,24 @@ public:
   float GetCurrentOpacity() const;
 
   /**
-   * Sets whether an actor should emit touch signals; see SignalTouch().
+   * Sets whether an actor should emit touch or hover signals; see SignalTouch() and SignalHover().
    * An actor is sensitive by default, which means that as soon as an application connects to the SignalTouch(),
-   * the touch event signal will be emitted.
+   * the touch event signal will be emitted, and as soon as an application connects to the SignalHover(), the
+   * hover event signal will be emitted.
    *
-   * If the application wishes to temporarily disable the touch event signal emission, then they can do so by calling:
+   * If the application wishes to temporarily disable the touch or hover event signal emission, then they can do so by calling:
    * @code
    * actor.SetSensitive(false);
    * @endcode
    *
-   * Then, to re-enable the touch event signal emission, the application should call:
+   * Then, to re-enable the touch or hover event signal emission, the application should call:
    * @code
    * actor.SetSensitive(true);
    * @endcode
    *
-   * @see SignalTouch().
-   * @note If an actor's sensitivity is set to false, then it's children will not emit a touch event signal either.
-   * @param[in]  sensitive  true to enable emission of the touch event signals, false otherwise.
+   * @see SignalTouch() and SignalHover().
+   * @note If an actor's sensitivity is set to false, then it's children will not emit a touch or hover event signal either.
+   * @param[in]  sensitive  true to enable emission of the touch or hover event signals, false otherwise.
    */
   void SetSensitive(bool sensitive)
   {
@@ -631,9 +633,9 @@ public:
   }
 
   /**
-   * Query whether an actor emits touch event signals.
+   * Query whether an actor emits touch or hover event signals.
    * @see SetSensitive(bool)
-   * @return true, if emission of touch event signals is enabled, false otherwise.
+   * @return true, if emission of touch or hover event signals is enabled, false otherwise.
    */
   bool IsSensitive() const
   {
@@ -888,18 +890,18 @@ public:
   bool RayActorTest( const Vector4& rayOrigin, const Vector4& rayDir, Vector4& hitPointLocal, float& distance ) const;
 
   /**
-   * Sets whether the actor should receive a notification when touch motion events leave
+   * Sets whether the actor should receive a notification when touch or hover motion events leave
    * the boundary of the actor.
    *
    * @note By default, this is set to false as most actors do not require this.
-   * @note Need to connect to the SignalTouch to actually receive this event.
+   * @note Need to connect to the SignalTouch or SignalHover to actually receive this event.
    *
    * @param[in]  required  Should be set to true if a Leave event is required
    */
   void SetLeaveRequired(bool required);
 
   /**
-   * This returns whether the actor requires touch events whenever touch motion events leave
+   * This returns whether the actor requires touch or hover events whenever touch or hover motion events leave
    * the boundary of the actor.
    * @return true if a Leave event is required, false otherwise.
    */
@@ -922,6 +924,12 @@ public:
   bool GetTouchRequired() const;
 
   /**
+   * Query whether the application or derived actor type requires hover events.
+   * @return True if hover events are required.
+   */
+  bool GetHoverRequired() const;
+
+  /**
    * Query whether the application or derived actor type requires mouse wheel events.
    * @return True if mouse wheel events are required.
    */
@@ -962,6 +970,13 @@ public:
   bool EmitTouchEventSignal(const TouchEvent& event);
 
   /**
+   * Used by the EventProcessor to emit hover event signals.
+   * @param[in] event The hover event.
+   * @return True if the event was consumed.
+   */
+  bool EmitHoverEventSignal(const HoverEvent& event);
+
+  /**
    * Used by the EventProcessor to emit mouse wheel event signals.
    * @param[in] event The mouse wheel event.
    * @return True if the event was consumed.
@@ -974,6 +989,11 @@ public:
   Dali::Actor::TouchSignalV2& TouchedSignal();
 
   /**
+   * @copydoc Dali::Actor::HoveredSignal()
+   */
+  Dali::Actor::HoverSignalV2& HoveredSignal();
+
+  /**
    * @copydoc Dali::Actor::MouseWheelEventSignal()
    */
   Dali::Actor::MouseWheelEventSignalV2& MouseWheelEventSignal();
@@ -1291,7 +1311,7 @@ private:
 
   /**
    * For use in derived classes.
-   * This is only called if mTouchRequired is true, and the touch-signal was not consumed.
+   * This is only called if mDerivedRequiresTouch is true, and the touch-signal was not consumed.
    * @param[in] event The touch event.
    * @return True if the event should be consumed.
    */
@@ -1299,6 +1319,14 @@ private:
 
   /**
    * For use in derived classes.
+   * This is only called if mDerivedRequiresHover is true, and the hover-signal was not consumed.
+   * @param[in] event The hover event.
+   * @return True if the event should be consumed.
+   */
+  virtual bool OnHoverEvent(const HoverEvent& event) { return false; }
+
+  /**
+   * For use in derived classes.
    * This is only called if the mouse wheel signal was not consumed.
    * @param[in] event The mouse event.
    * @return True if the event should be consumed.
@@ -1342,6 +1370,7 @@ protected:
 
   // Signals
   Dali::Actor::TouchSignalV2             mTouchedSignalV2;
+  Dali::Actor::HoverSignalV2             mHoveredSignalV2;
   Dali::Actor::MouseWheelEventSignalV2   mMouseWheelEventSignalV2;
   Dali::Actor::SetSizeSignalV2           mSetSizeSignalV2;
   Dali::Actor::OnStageSignalV2           mOnStageSignalV2;
@@ -1361,6 +1390,7 @@ protected:
   bool mLeaveRequired                              : 1; ///< Whether a touch event signal is emitted when the a touch leaves the actor's bounds
   bool mKeyboardFocusable                          : 1; ///< Whether the actor should be focusable by keyboard navigation
   bool mDerivedRequiresTouch                       : 1; ///< Whether the derived actor type requires touch event signals
+  bool mDerivedRequiresHover                       : 1; ///< Whether the derived actor type requires hover event signals
   bool mDerivedRequiresMouseWheelEvent             : 1; ///< Whether the derived actor type requires mouse wheel event signals
   bool mOnStageSignalled                           : 1; ///< Set to true before OnStageConnection signal is emitted, and false before OnStageDisconnection
   bool mInheritRotation                            : 1; ///< Cached: Whether the parent's rotation should be inherited.
index 6ade4ed..273b6ac 100644 (file)
@@ -40,6 +40,7 @@ CustomActor::CustomActor(CustomActorImpl& extension)
   mImpl( &extension )
 {
   mDerivedRequiresTouch = extension.RequiresTouchEvents();
+  mDerivedRequiresHover = extension.RequiresHoverEvents();
   mDerivedRequiresMouseWheelEvent = extension.RequiresMouseWheelEvents();
 }
 
index 44b3418..d4ed7f7 100644 (file)
@@ -134,6 +134,14 @@ private:
   }
 
   /**
+   * @copydoc Internal::Actor::OnHoverEvent
+   */
+  virtual bool OnHoverEvent(const HoverEvent& event)
+  {
+    return mImpl->OnHoverEvent(event);
+  }
+
+  /**
    * @copydoc Internal::Actor::OnKeyEvent
    */
   virtual bool OnKeyEvent(const KeyEvent& event)
index a91c052..ad5080c 100644 (file)
@@ -112,7 +112,8 @@ Layer::Layer( Actor::DerivedType type )
   mSortFunction(Dali::Layer::ZValue),
   mIsClipping(false),
   mDepthTestDisabled(false),
-  mTouchConsumed(false)
+  mTouchConsumed(false),
+  mHoverConsumed(false)
 {
 }
 
@@ -285,6 +286,16 @@ bool Layer::IsTouchConsumed() const
   return mTouchConsumed;
 }
 
+void Layer::SetHoverConsumed( bool consume )
+{
+  mHoverConsumed = consume;
+}
+
+bool Layer::IsHoverConsumed() const
+{
+  return mHoverConsumed;
+}
+
 SceneGraph::Node* Layer::CreateNode() const
 {
   return SceneGraph::Layer::New();
index affc8cd..ccea127 100644 (file)
@@ -170,6 +170,16 @@ public:
   bool IsTouchConsumed() const;
 
   /**
+   * @copydoc Dali::Layer::SetHoverConsumed()
+   */
+  void SetHoverConsumed( bool consume );
+
+  /**
+   * @copydoc Dali::Layer::IsHoverConsumed()
+   */
+  bool IsHoverConsumed() const;
+
+  /**
    * Helper function to get the scene object.
    * This should only be called by Stage
    * @return the scene object for the layer.
@@ -274,6 +284,7 @@ private:
   bool mIsClipping:1;                           ///< True when clipping is enabled
   bool mDepthTestDisabled:1;                    ///< Whether depth test is disabled.
   bool mTouchConsumed:1;                        ///< Whether we should consume touch (including gesture).
+  bool mHoverConsumed:1;                        ///< Whether we should consume hover.
 
   static bool mFirstInstance;
   static DefaultPropertyLookup* mDefaultLayerPropertyLookup; ///< Default properties
diff --git a/dali/internal/event/events/actor-observer.cpp b/dali/internal/event/events/actor-observer.cpp
new file mode 100644 (file)
index 0000000..51c33a0
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/integration-api/debug.h>
+#include <dali/internal/event/actors/actor-impl.h>
+#include <dali/internal/event/events/actor-observer.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ACTOR_OBSERVER" );
+#endif // defined(DEBUG_ENABLED)
+}
+
+ActorObserver::ActorObserver::ActorObserver()
+: mActor ( NULL ),
+  mActorDisconnected(false)
+{
+  DALI_LOG_TRACE_METHOD( gLogFilter );
+}
+
+ActorObserver::ActorObserver::~ActorObserver()
+{
+  DALI_LOG_TRACE_METHOD( gLogFilter );
+  SetActor( NULL );
+}
+
+Actor* ActorObserver::ActorObserver::GetActor()
+{
+  return mActorDisconnected ? NULL : mActor;
+}
+
+void ActorObserver::ActorObserver::SetActor( Actor* actor )
+{
+  DALI_LOG_TRACE_METHOD( gLogFilter );
+
+  if ( mActor != actor )
+  {
+    ResetActor();
+
+    mActor = actor;
+
+    if ( mActor )
+    {
+      mActor->AddObserver( *this );
+      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Start Observing:            %p\n", mActor);
+    }
+  }
+
+  // Make sure this flag is unset (as we may have been disconnected if it's the same actor)
+  mActorDisconnected = false;
+}
+
+void ActorObserver::ActorObserver::ResetActor()
+{
+  if ( mActor )
+  {
+    DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Stop Observing:             %p\n", mActor);
+    mActor->RemoveObserver( *this );
+    mActor = NULL;
+    mActorDisconnected = false;
+  }
+}
+
+void ActorObserver::ActorObserver::SceneObjectRemoved( ProxyObject& proxy )
+{
+  DALI_LOG_TRACE_METHOD( gLogFilter );
+
+  if ( mActor == &proxy )
+  {
+    // do not call proxy.RemoveObserver here, proxy is currently iterating through observers... you wouldnt want to upset proxy now would you?
+    mActorDisconnected = true;
+  }
+}
+
+void ActorObserver::ActorObserver::ProxyDestroyed(ProxyObject& proxy)
+{
+  DALI_LOG_TRACE_METHOD( gLogFilter );
+
+  if ( mActor == &proxy )
+  {
+    DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Stop Observing:             %p\n", mActor);
+    mActor = NULL;
+  }
+}
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/dali/internal/event/events/actor-observer.h b/dali/internal/event/events/actor-observer.h
new file mode 100644 (file)
index 0000000..1beb297
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef __DALI_INTERNAL_ACTOR_OBSERVER_H__
+#define __DALI_INTERNAL_ACTOR_OBSERVER_H__
+
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/common/proxy-object.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+class Actor;
+
+/**
+ * Stores an actor pointer and connects/disconnects to any required signals appropriately when set/unset.
+ */
+struct ActorObserver : public ProxyObject::Observer
+{
+public:
+
+  // Construction & Destruction
+
+  /**
+   * Constructor.
+   */
+  ActorObserver();
+
+  /**
+   * Non virtual destructor
+   */
+  ~ActorObserver();
+
+  // Methods
+
+  /**
+   * Return the stored Actor pointer.
+   * @return The Actor pointer.
+   */
+  Actor* GetActor();
+
+  /**
+   * Assignment operator.
+   * This disconnects the required signals from the currently set actor and connects to the required
+   * signals for the the actor specified (if set).
+   */
+  void SetActor( Actor* actor );
+
+  /**
+   * Resets the set actor and disconnects any connected signals.
+   */
+  void ResetActor();
+
+private:
+
+  // Undefined
+  ActorObserver( const ActorObserver& );
+  ActorObserver& operator=( const ActorObserver& );
+
+private:
+
+  /**
+   * This will never get called as we do not observe objects that have not been added to the scene.
+   * @param[in] proxy The proxy object.
+   * @see ProxyObject::Observer::SceneObjectAdded()
+   */
+  virtual void SceneObjectAdded(ProxyObject& proxy) { }
+
+  /**
+   * This will be called when the actor is removed from the stage, we should clear and stop
+   * observing it.
+   * @param[in] proxy The proxy object.
+   * @see ProxyObject::Observer::SceneObjectRemoved()
+   */
+  virtual void SceneObjectRemoved(ProxyObject& proxy);
+
+  /**
+   * This will be called when the actor is destroyed. We should clear the actor.
+   * No need to stop observing as the object is being destroyed anyway.
+   * @see ProxyObject::Observer::ProxyDestroyed()
+   */
+  virtual void ProxyDestroyed(ProxyObject& proxy);
+
+private:
+  Actor* mActor;              ///< Raw pointer to an Actor.
+  bool  mActorDisconnected;   ///< Indicates whether the actor has been disconnected from the scene
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ACTOR_OBSERVER_H__
+
index 3f62462..9d63a3c 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali/integration-api/events/key-event-integ.h>
 #include <dali/integration-api/events/mouse-wheel-event-integ.h>
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
 #include <dali/integration-api/events/pinch-gesture-event.h>
 #include <dali/integration-api/events/pan-gesture-event.h>
 #include <dali/integration-api/events/tap-gesture-event.h>
@@ -56,6 +57,7 @@ static const std::size_t INITIAL_BUFFER_SIZE = MAX_MESSAGE_SIZE * INITIAL_MIN_CA
 
 EventProcessor::EventProcessor(Stage& stage, NotificationManager& /* notificationManager */, GestureEventProcessor& gestureEventProcessor)
 : mTouchEventProcessor(stage),
+  mHoverEventProcessor(stage),
   mGestureEventProcessor(gestureEventProcessor),
   mKeyEventProcessor(stage),
   mMouseWheelEventProcessor(stage),
@@ -99,6 +101,19 @@ void EventProcessor::QueueEvent( const Event& event )
       break;
     }
 
+    case Event::Hover:
+    {
+      typedef Integration::HoverEvent DerivedType;
+
+      // Reserve some memory inside the message queue
+      unsigned int* slot = mCurrentEventQueue->ReserveMessageSlot( sizeof( DerivedType ) );
+
+      // Construct message in the message queue memory; note that delete should not be called on the return value
+      new (slot) DerivedType( static_cast<const DerivedType&>(event) );
+
+      break;
+    }
+
     case Event::Key:
     {
       typedef Integration::KeyEvent DerivedType;
@@ -211,6 +226,12 @@ void EventProcessor::ProcessEvents()
         break;
       }
 
+      case Event::Hover:
+      {
+        mHoverEventProcessor.ProcessHoverEvent( static_cast<const Integration::HoverEvent&>(*event) );
+        break;
+      }
+
       case Event::Key:
       {
         mKeyEventProcessor.ProcessKeyEvent( static_cast<const Integration::KeyEvent&>(*event) );
index e8b4226..45ea643 100644 (file)
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/internal/event/events/touch-event-processor.h>
+#include <dali/internal/event/events/hover-event-processor.h>
 #include <dali/internal/event/events/key-event-processor.h>
 #include <dali/internal/event/events/mouse-wheel-event-processor.h>
 #include <dali/internal/common/message-buffer.h>
@@ -87,6 +88,7 @@ private:
 private:
 
   TouchEventProcessor      mTouchEventProcessor;        ///< Processes touch events.
+  HoverEventProcessor      mHoverEventProcessor;        ///< Processes hover events.
   GestureEventProcessor&   mGestureEventProcessor;      ///< Processes gesture events.
   KeyEventProcessor        mKeyEventProcessor;          ///< Processes key events.
   MouseWheelEventProcessor mMouseWheelEventProcessor;   ///< Processes mouse wheel events.
diff --git a/dali/internal/event/events/hover-event-processor.cpp b/dali/internal/event/events/hover-event-processor.cpp
new file mode 100644 (file)
index 0000000..3ab14d4
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/hover-event-processor.h>
+
+#if defined(DEBUG_ENABLED)
+#include <sstream>
+#endif
+
+// INTERNAL INCLUDES
+#include <dali/public-api/actors/renderable-actor.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/internal/event/actors/actor-impl.h>
+#include <dali/internal/event/actors/layer-impl.h>
+#include <dali/internal/event/common/stage-impl.h>
+#include <dali/internal/event/events/hit-test-algorithm-impl.h>
+#include <dali/internal/event/events/multi-point-event-util.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_HOVER_PROCESSOR" );
+
+const char * TOUCH_POINT_STATE[TouchPoint::Last] =
+{
+  "Started",
+  "Finished",
+  "Motion",
+  "Leave",
+  "Stationary",
+  "Interrupted",
+};
+
+#endif // defined(DEBUG_ENABLED)
+
+/**
+ *  Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached.
+ */
+Dali::Actor EmitHoverSignals( Dali::Actor actor, const HoverEvent& event )
+{
+  Dali::Actor consumedActor;
+
+  if ( actor )
+  {
+    Dali::Actor oldParent( actor.GetParent() );
+
+    Actor& actorImpl( GetImplementation(actor) );
+
+    bool consumed( false );
+
+    // Only emit the signal if the actor's hover signal has connections (or derived actor implementation requires hover).
+    if ( actorImpl.GetHoverRequired() )
+    {
+      consumed = actorImpl.EmitHoverEventSignal( event );
+    }
+
+    if ( consumed )
+    {
+      // One of this actor's listeners has consumed the event so set this actor as the consumed actor.
+      consumedActor = Dali::Actor( &actorImpl );
+    }
+    else
+    {
+      // The actor may have been removed/reparented during the signal callbacks.
+      Dali::Actor parent = actor.GetParent();
+
+      if ( parent &&
+           (parent == oldParent) )
+      {
+        // One of the actor's parents may consumed the event and they should be set as the consumed actor.
+        consumedActor = EmitHoverSignals( parent, event );
+      }
+    }
+  }
+
+  return consumedActor;
+}
+
+/**
+ * Changes the state of the primary point to leave and emits the hover signals
+ */
+Dali::Actor EmitHoverSignals( Actor* actor, RenderTask& renderTask, const HoverEvent& originalEvent, TouchPoint::State state )
+{
+  HoverEvent hoverEvent( originalEvent );
+
+  DALI_ASSERT_DEBUG( NULL != actor && "NULL actor pointer" );
+  if( actor )
+  {
+    TouchPoint& primaryPoint = hoverEvent.points[0];
+
+    actor->ScreenToLocal( renderTask, primaryPoint.local.x, primaryPoint.local.y, primaryPoint.screen.x, primaryPoint.screen.y );
+
+    primaryPoint.hitActor = Dali::Actor(actor);
+    primaryPoint.state = state;
+  }
+
+  return EmitHoverSignals( Dali::Actor(actor), hoverEvent );
+}
+
+/**
+ * Used in the hit-test algorithm to check whether the actor is hoverable.
+ */
+struct ActorHoverableCheck : public HitTestAlgorithm::HitTestInterface
+{
+  bool IsActorHittable( Actor* actor )
+  {
+    return actor->GetHoverRequired() && // Does the Application or derived actor type require a hover event?
+           actor->IsHittable();         // Is actor sensitive, visible and on the scene?
+  }
+
+  bool DescendActorHierarchy( Actor* actor )
+  {
+    return actor->IsVisible() && // Actor is visible, if not visible then none of its children are visible.
+           actor->IsSensitive(); // Actor is sensitive, if insensitive none of its children should be hittable either.
+  }
+
+  bool DoesLayerConsumeHit( Layer* layer )
+  {
+    return layer->IsHoverConsumed();
+  }
+};
+
+} // unnamed namespace
+
+HoverEventProcessor::HoverEventProcessor( Stage& stage )
+: mStage( stage ),
+  mLastPrimaryHitActor(),
+  mLastConsumedActor(),
+  mHoverStartConsumedActor(),
+  mLastRenderTask()
+{
+  DALI_LOG_TRACE_METHOD( gLogFilter );
+}
+
+HoverEventProcessor::~HoverEventProcessor()
+{
+  DALI_LOG_TRACE_METHOD( gLogFilter );
+}
+
+void HoverEventProcessor::ProcessHoverEvent( const Integration::HoverEvent& event )
+{
+  DALI_LOG_TRACE_METHOD( gLogFilter );
+
+  DALI_ASSERT_ALWAYS( !event.points.empty() && "Empty HoverEvent sent from Integration\n" );
+
+  Stage& stage = mStage;
+
+  PRINT_HIERARCHY(gLogFilter);
+
+  // Copy so we can add the results of a hit-test.
+  HoverEvent hoverEvent( event.time );
+
+  // 1) Check if it is an interrupted event - we should inform our last primary hit actor about this
+  //    and emit the stage signal as well.
+
+  if ( event.points[0].state == TouchPoint::Interrupted )
+  {
+    Dali::Actor consumingActor;
+    hoverEvent.points.push_back(event.points[0]);
+
+    Actor* lastPrimaryHitActor( mLastPrimaryHitActor.GetActor() );
+    if ( lastPrimaryHitActor )
+    {
+      Dali::Actor lastPrimaryHitActorHandle( lastPrimaryHitActor );
+      hoverEvent.points[0].hitActor = lastPrimaryHitActorHandle;
+      consumingActor = EmitHoverSignals( lastPrimaryHitActorHandle, hoverEvent );
+    }
+
+    // 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 );
+      hoverEvent.points[0].hitActor = lastConsumedActorHandle;
+      EmitHoverSignals( lastConsumedActorHandle, hoverEvent );
+    }
+
+    // Tell the hover-start consuming actor as well, if required
+    Actor* hoverStartConsumedActor( mHoverStartConsumedActor.GetActor() );
+    if ( hoverStartConsumedActor &&
+         hoverStartConsumedActor != lastPrimaryHitActor &&
+         hoverStartConsumedActor != lastConsumedActor &&
+         hoverStartConsumedActor != consumingActor )
+    {
+      Dali::Actor hoverStartConsumedActorHandle( hoverStartConsumedActor );
+      hoverEvent.points[0].hitActor = hoverStartConsumedActorHandle;
+      EmitHoverSignals( hoverStartConsumedActorHandle, hoverEvent );
+    }
+
+    mLastPrimaryHitActor.SetActor( NULL );
+    mLastConsumedActor.SetActor( NULL );
+    mHoverStartConsumedActor.SetActor( NULL );
+    mLastRenderTask.Reset();
+
+    hoverEvent.points[0].hitActor = NULL;
+
+    return; // No need for hit testing
+  }
+
+  // 2) Hit Testing.
+
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Point(s): %d\n", event.GetPointCount() );
+
+  Dali::RenderTask currentRenderTask;
+
+  for ( TouchPointContainerConstIterator iter = event.points.begin(), beginIter = event.points.begin(), endIter = event.points.end(); iter != endIter; ++iter )
+  {
+    HitTestAlgorithm::Results hitTestResults;
+    ActorHoverableCheck actorHoverableCheck;
+    HitTestAlgorithm::HitTest( stage, iter->screen, hitTestResults, actorHoverableCheck );
+
+    TouchPoint newPoint( iter->deviceId, iter->state, iter->screen.x, iter->screen.y );
+    newPoint.hitActor = hitTestResults.actor;
+    newPoint.local = hitTestResults.actorCoordinates;
+
+    hoverEvent.points.push_back( newPoint );
+
+    DALI_LOG_INFO( gLogFilter, Debug::General, "  State(%s), Screen(%.0f, %.0f), HitActor(%p, %s), Local(%.2f, %.2f)\n",
+                   TOUCH_POINT_STATE[iter->state], iter->screen.x, iter->screen.y,
+                   ( hitTestResults.actor ? (void*)&hitTestResults.actor.GetBaseObject() : NULL ),
+                   ( hitTestResults.actor ? hitTestResults.actor.GetName().c_str() : "" ),
+                   hitTestResults.actorCoordinates.x, hitTestResults.actorCoordinates.y );
+
+    // Only set the currentRenderTask for the primary hit actor.
+    if ( iter == beginIter && hitTestResults.renderTask )
+    {
+      currentRenderTask = hitTestResults.renderTask;
+    }
+  }
+
+  // 3) Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached.
+
+  // Emit the touch signal
+  Dali::Actor consumedActor;
+  if ( currentRenderTask )
+  {
+    consumedActor = EmitHoverSignals( hoverEvent.points[0].hitActor, hoverEvent );
+  }
+
+  TouchPoint& primaryPoint = hoverEvent.points[0];
+  Dali::Actor primaryHitActor = primaryPoint.hitActor;
+  TouchPoint::State primaryPointState = primaryPoint.state;
+
+  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::Started ) &&
+       ( hoverEvent.GetPointCount() == 1 ) &&
+       ( consumedActor && consumedActor.OnStage() ) )
+  {
+    mHoverStartConsumedActor.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::Finished) || (primaryPointState == TouchPoint::Stationary) )
+  {
+    if ( mLastRenderTask )
+    {
+      Dali::Actor leaveEventConsumer;
+      RenderTask& lastRenderTaskImpl( GetImplementation( mLastRenderTask ) );
+
+      if( lastPrimaryHitActor &&
+          lastPrimaryHitActor != primaryHitActor &&
+          lastPrimaryHitActor != consumedActor )
+      {
+        if( lastPrimaryHitActor->IsHittable() && IsActuallySensitive( lastPrimaryHitActor ) )
+        {
+          if ( lastPrimaryHitActor->GetLeaveRequired() )
+          {
+            DALI_LOG_INFO( gLogFilter, Debug::Concise, "LeaveActor(Hit):     (%p) %s\n", (void*)lastPrimaryHitActor, lastPrimaryHitActor->GetName().c_str() );
+            leaveEventConsumer = EmitHoverSignals( mLastPrimaryHitActor.GetActor(), lastRenderTaskImpl, hoverEvent, TouchPoint::Leave );
+          }
+        }
+        else
+        {
+          // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one.
+          // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
+          DALI_LOG_INFO( gLogFilter, Debug::Concise, "InterruptedActor(Hit):     (%p) %s\n", (void*)lastPrimaryHitActor, lastPrimaryHitActor->GetName().c_str() );
+          leaveEventConsumer = EmitHoverSignals( mLastPrimaryHitActor.GetActor(), lastRenderTaskImpl, hoverEvent, TouchPoint::Interrupted );
+        }
+      }
+
+      // 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.
+      if ( lastConsumedActor &&
+           lastConsumedActor != consumedActor &&
+           lastConsumedActor != lastPrimaryHitActor &&
+           lastConsumedActor != primaryHitActor &&
+           lastConsumedActor != leaveEventConsumer )
+      {
+        if( lastConsumedActor->IsHittable() && IsActuallySensitive( lastConsumedActor ) )
+        {
+          if( lastConsumedActor->GetLeaveRequired() )
+          {
+            DALI_LOG_INFO( gLogFilter, Debug::Concise, "LeaveActor(Consume): (%p) %s\n", (void*)lastConsumedActor, lastConsumedActor->GetName().c_str() );
+            EmitHoverSignals( lastConsumedActor, lastRenderTaskImpl, hoverEvent, TouchPoint::Leave );
+          }
+        }
+        else
+        {
+          // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one.
+          // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
+          DALI_LOG_INFO( gLogFilter, Debug::Concise, "InterruptedActor(Consume):     (%p) %s\n", (void*)lastConsumedActor, lastConsumedActor->GetName().c_str() );
+          EmitHoverSignals( mLastConsumedActor.GetActor(), lastRenderTaskImpl, hoverEvent, TouchPoint::Interrupted );
+        }
+      }
+    }
+  }
+
+  // 5) If our primary point is an Finished event, then the primary point (in multi-touch) will change next
+  //    time so set our last primary actor to NULL.  Do the same to the last consumed actor as well.
+
+  if ( primaryPointState == TouchPoint::Finished )
+  {
+    mLastPrimaryHitActor.SetActor( NULL );
+    mLastConsumedActor.SetActor( NULL );
+    mLastRenderTask.Reset();
+  }
+  else
+  {
+    // The primaryHitActor may have been removed from the stage so ensure it is still on the stage before setting members.
+    if ( primaryHitActor && primaryHitActor.OnStage() )
+    {
+      mLastPrimaryHitActor.SetActor( &GetImplementation( primaryHitActor ) );
+
+      // Only observe the consumed actor if we have a primaryHitActor (check if it is still on stage).
+      if ( consumedActor && consumedActor.OnStage() )
+      {
+        mLastConsumedActor.SetActor( &GetImplementation( consumedActor ) );
+      }
+      else
+      {
+        mLastConsumedActor.SetActor( NULL );
+      }
+
+      mLastRenderTask = currentRenderTask;
+    }
+    else
+    {
+      mLastPrimaryHitActor.SetActor( NULL );
+      mLastConsumedActor.SetActor( NULL );
+      mLastRenderTask.Reset();
+    }
+  }
+
+  // 6) Emit an interrupted event to the hover-started actor if it hasn't consumed the Finished.
+
+  if ( hoverEvent.GetPointCount() == 1 ) // Only want the first hover started
+  {
+    switch ( primaryPointState )
+    {
+      case TouchPoint::Finished:
+      {
+        Actor* hoverStartConsumedActor( mHoverStartConsumedActor.GetActor() );
+        if ( hoverStartConsumedActor &&
+             hoverStartConsumedActor != consumedActor &&
+             hoverStartConsumedActor != lastPrimaryHitActor &&
+             hoverStartConsumedActor != lastConsumedActor )
+        {
+          Dali::Actor hoverStartConsumedActorHandle( hoverStartConsumedActor );
+          hoverEvent.points[0].hitActor = hoverStartConsumedActorHandle;
+          hoverEvent.points[0].state = TouchPoint::Interrupted;
+          EmitHoverSignals( hoverStartConsumedActorHandle, hoverEvent );
+
+          // Restore hover-event to original state
+          hoverEvent.points[0].hitActor = primaryHitActor;
+          hoverEvent.points[0].state = primaryPointState;
+        }
+
+        mHoverStartConsumedActor.SetActor( NULL );
+      }
+      // No break, Fallthrough
+
+      case TouchPoint::Started:
+      case TouchPoint::Motion:
+      case TouchPoint::Leave:
+      case TouchPoint::Stationary:
+      case TouchPoint::Interrupted:
+      case TouchPoint::Last:
+      {
+        // Ignore
+        break;
+      }
+    }
+  }
+}
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/event/events/hover-event-processor.h b/dali/internal/event/events/hover-event-processor.h
new file mode 100644 (file)
index 0000000..2457551
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef __DALI_INTERNAL_HOVER_EVENT_PROCESSOR_H__
+#define __DALI_INTERNAL_HOVER_EVENT_PROCESSOR_H__
+
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/internal/event/events/actor-observer.h>
+
+namespace Dali
+{
+
+class Actor;
+struct Vector2;
+struct Vector4;
+
+namespace Integration
+{
+struct HoverEvent;
+}
+
+namespace Internal
+{
+
+class ActorObserver;
+class Stage;
+
+/**
+ * <h3>Multi-Hover Event Processing:</h3>
+ *
+ * The HoverEventProcessor processes hover events and emits the Hovered signal on the hit actor (and
+ * its parents).
+ *
+ * - Hit Testing & Hover Event Delivery are described in Dali::Actor.
+ */
+class HoverEventProcessor
+{
+public:
+
+  /**
+   * Create an event processor.
+   * @param[in] stage The stage.
+   */
+  HoverEventProcessor( Stage& stage );
+
+  /**
+   * Non-virtual destructor; HoverEventProcessor is not a base class
+   */
+  ~HoverEventProcessor();
+
+  /**
+   * This function is called by the event processor whenever a hover event occurs.
+   * @param[in] event The hover event that has occurred.
+   */
+  void ProcessHoverEvent( const Integration::HoverEvent& event );
+
+private:
+
+  // Undefined
+  HoverEventProcessor(const HoverEventProcessor&);
+
+  // Undefined
+  HoverEventProcessor& operator=(const HoverEventProcessor& rhs);
+
+  Stage& mStage; ///< Used to deliver touch events
+  ActorObserver mLastPrimaryHitActor; ///< Stores the last primary point hit actor
+  ActorObserver mLastConsumedActor; ///< Stores the last consumed actor
+  ActorObserver mHoverStartConsumedActor; ///< Stores the hover-start consumed actor
+  Dali::RenderTask mLastRenderTask; ///< The RenderTask used for the last hit actor
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_HOVER_EVENT_PROCESSOR_H__
diff --git a/dali/internal/event/events/multi-point-event-util.cpp b/dali/internal/event/events/multi-point-event-util.cpp
new file mode 100644 (file)
index 0000000..d762508
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#if defined(DEBUG_ENABLED)
+#include <sstream>
+#endif
+
+// CLASS HEADER
+#include <dali/internal/event/common/stage-impl.h>
+#include <dali/internal/event/events/multi-point-event-util.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+#if defined(DEBUG_ENABLED)
+
+static bool HIERARCHY_GEOMETRY(false);
+static bool HIERARCHY_SENSITIVITY(false);
+static bool HIERARCHY_TOUCH_REQUIRED(false);
+static bool HIERARCHY_HOVER_REQUIRED(false);
+static bool HIERARCHY_HITTABLE(false);
+
+static const Debug::LogLevel HIERARCHY_DEBUG_LOG_LEVEL( Debug::Verbose );
+
+void PrintChildren( Debug::Filter* logFilter, Dali::Actor actor, int level )
+{
+  std::ostringstream output;
+
+  for ( int t = 0; t < level; ++t )
+  {
+    output << " | ";
+  }
+
+  output << actor.GetName() << "(" << actor.GetTypeName() << ", " << actor.GetObjectPtr() << ")";
+
+  if ( HIERARCHY_GEOMETRY )
+  {
+    output << " Pos: " << actor.GetCurrentWorldPosition() << " Size: " << actor.GetCurrentSize() << " Scale: " << actor.GetCurrentWorldScale();
+  }
+
+  if ( HIERARCHY_SENSITIVITY )
+  {
+    output << " Sensitivity: " << ( IsActuallySensitive( &GetImplementation( actor ) ) ? "True " : "False " );
+  }
+
+  if ( HIERARCHY_TOUCH_REQUIRED )
+  {
+    output << " TouchRequired: " << ( GetImplementation(actor).GetTouchRequired() ? "True " : "False " );
+  }
+
+  if ( HIERARCHY_HOVER_REQUIRED )
+  {
+    output << " HoverRequired: " << ( GetImplementation(actor).GetHoverRequired() ? "True " : "False " );
+  }
+
+  if ( HIERARCHY_HITTABLE )
+  {
+    output << " Hittable: " << ( GetImplementation(actor).IsHittable() ? "True " : "False " );
+  }
+
+  output << std::endl;
+
+  if( logFilter )
+  {
+    DALI_LOG_INFO( logFilter, HIERARCHY_DEBUG_LOG_LEVEL, output.str().c_str() );
+  }
+
+  ++level;
+  unsigned int numChildren=actor.GetChildCount();
+  for ( unsigned int i=0; i<numChildren; ++i )
+  {
+    PrintChildren( logFilter, actor.GetChildAt(i), level );
+  }
+  --level;
+}
+
+void PrintHierarchy( Debug::Filter* logFilter )
+{
+  if ( logFilter && logFilter->IsEnabledFor( HIERARCHY_DEBUG_LOG_LEVEL ) )
+  {
+    PrintChildren( logFilter, Dali::Stage().GetCurrent().GetRootLayer(), 0 );
+  }
+}
+
+#endif // defined(DEBUG_ENABLED)
+
+bool IsActuallySensitive( Actor* actor )
+{
+  bool sensitive = true;
+
+  while ( actor && sensitive )
+  {
+    sensitive = actor->IsSensitive();
+    actor = actor->GetParent();
+  }
+
+  return sensitive;
+}
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/dali/internal/event/events/multi-point-event-util.h b/dali/internal/event/events/multi-point-event-util.h
new file mode 100644 (file)
index 0000000..780c174
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef __DALI_INTERNAL_MULTI_POINT_EVENT_UTIL_H__
+#define __DALI_INTERNAL_MULTI_POINT_EVENT_UTIL_H__
+
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/internal/event/actors/actor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+#if defined(DEBUG_ENABLED)
+
+/**
+ * Prints out all the children of the given actor when debug is enabled.
+ *
+ * @param[in]  actor  The actor whose children to print.
+ * @param[in]  level  The number of " | " to put in front of the children.
+ */
+void PrintChildren( Debug::Filter* logFilter, Dali::Actor actor, int level );
+
+/**
+ * Prints the entire hierarchy of the scene.
+ */
+void PrintHierarchy( Debug::Filter* logFilter );
+
+#define PRINT_HIERARCHY(f) PrintHierarchy(f)
+
+#else // defined(DEBUG_ENABLED)
+
+#define PRINT_HIERARCHY(f)
+
+#endif // defined(DEBUG_ENABLED)
+
+/**
+ * In the hit test algorithm above we do not descend actor tree if it is insensitive, so here, we
+ * should also check if any of the actor's parents has become insensitive since we last processed
+ * it.
+ */
+bool IsActuallySensitive( Actor* actor );
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_MULTI_POINT_EVENT_UTIL_H__
+
index 758d5ab..393114c 100644 (file)
@@ -31,6 +31,7 @@
 #include <dali/internal/event/actors/layer-impl.h>
 #include <dali/internal/event/common/stage-impl.h>
 #include <dali/internal/event/events/hit-test-algorithm-impl.h>
+#include <dali/internal/event/events/multi-point-event-util.h>
 #include <dali/internal/event/render-tasks/render-task-impl.h>
 
 namespace Dali
@@ -42,8 +43,6 @@ namespace Internal
 namespace
 {
 
-bool IsActuallySensitive( Actor* actor );
-
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_TOUCH_PROCESSOR" );
 
@@ -57,80 +56,6 @@ const char * TOUCH_POINT_STATE[TouchPoint::Last] =
   "Interrupted",
 };
 
-static const Debug::LogLevel HIERARCHY_DEBUG_LOG_LEVEL( Debug::Verbose );
-
-static bool HIERARCHY_GEOMETRY( false );
-static bool HIERARCHY_SENSITIVITY( false );
-static bool HIERARCHY_TOUCH_REQUIRED( false );
-static bool HIERARCHY_HITTABLE( false );
-
-/**
- * Prints out all the children of the given actor when debug is enabled.
- *
- * @param[in]  actor  The actor whose children to print.
- * @param[in]  level  The number of " | " to put in front of the children.
- */
-void PrintChildren( Dali::Actor actor, int level )
-{
-  std::ostringstream output;
-
-  for ( int t = 0; t < level; ++t )
-  {
-    output << " | ";
-  }
-
-  output << actor.GetName() << "(" << actor.GetTypeName() << ", " << actor.GetObjectPtr() << ")";
-
-  if ( HIERARCHY_GEOMETRY )
-  {
-    output << " Pos: " << actor.GetCurrentWorldPosition() << " Size: " << actor.GetCurrentSize() << " Scale: " << actor.GetCurrentWorldScale();
-  }
-
-  if ( HIERARCHY_SENSITIVITY )
-  {
-    output << " Sensitivity: " << ( IsActuallySensitive( &GetImplementation( actor ) ) ? "True " : "False " );
-  }
-
-  if ( HIERARCHY_TOUCH_REQUIRED )
-  {
-    output << " TouchRequired: " << ( GetImplementation(actor).GetTouchRequired() ? "True " : "False " );
-  }
-
-  if ( HIERARCHY_HITTABLE )
-  {
-    output << " Hittable: " << ( GetImplementation(actor).IsHittable() ? "True " : "False " );
-  }
-
-  output << std::endl;
-
-  DALI_LOG_INFO( gLogFilter, HIERARCHY_DEBUG_LOG_LEVEL, output.str().c_str() );
-
-  ++level;
-  unsigned int numChildren=actor.GetChildCount();
-  for ( unsigned int i=0; i<numChildren; ++i )
-  {
-    PrintChildren( actor.GetChildAt(i), level );
-  }
-  --level;
-}
-
-/**
- * Prints the entire hierarchy of the scene.
- */
-void PrintHierarchy()
-{
-  if ( gLogFilter->IsEnabledFor( HIERARCHY_DEBUG_LOG_LEVEL ) )
-  {
-    PrintChildren( Dali::Stage().GetCurrent().GetRootLayer(), 0 );
-  }
-}
-
-#define PRINT_HIERARCHY PrintHierarchy()
-
-#else // defined(DEBUG_ENABLED)
-
-#define PRINT_HIERARCHY
-
 #endif // defined(DEBUG_ENABLED)
 
 /**
@@ -197,24 +122,6 @@ Dali::Actor EmitTouchSignals( Actor* actor, RenderTask& renderTask, const TouchE
   return EmitTouchSignals( Dali::Actor(actor), touchEvent );
 }
 
-/**
- * In the hit test algorithm above we do not descend actor tree if it is insensitive, so here, we
- * should also check if any of the actor's parents has become insensitive since we last processed
- * it.
- */
-bool IsActuallySensitive( Actor* actor )
-{
-  bool sensitive = true;
-
-  while ( actor && sensitive )
-  {
-    sensitive = actor->IsSensitive();
-    actor = actor->GetParent();
-  }
-
-  return sensitive;
-}
-
 } // unnamed namespace
 
 TouchEventProcessor::TouchEventProcessor( Stage& stage )
@@ -240,7 +147,7 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even
 
   Stage& stage = mStage;
 
-  PRINT_HIERARCHY;
+  PRINT_HIERARCHY(gLogFilter);
 
   // Copy so we can add the results of a hit-test.
   TouchEvent touchEvent( event.time );
@@ -494,78 +401,6 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even
   }
 }
 
-TouchEventProcessor::ActorObserver::ActorObserver()
-: mActor ( NULL ),
-  mActorDisconnected(false)
-{
-  DALI_LOG_TRACE_METHOD( gLogFilter );
-}
-
-TouchEventProcessor::ActorObserver::~ActorObserver()
-{
-  DALI_LOG_TRACE_METHOD( gLogFilter );
-  SetActor( NULL );
-}
-
-Actor* TouchEventProcessor::ActorObserver::GetActor()
-{
-  return mActorDisconnected ? NULL : mActor;
-}
-
-void TouchEventProcessor::ActorObserver::SetActor( Actor* actor )
-{
-  DALI_LOG_TRACE_METHOD( gLogFilter );
-
-  if ( mActor != actor )
-  {
-    ResetActor();
-
-    mActor = actor;
-
-    if ( mActor )
-    {
-      mActor->AddObserver( *this );
-      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Start Observing:            %p\n", mActor);
-    }
-  }
-
-  // Make sure this flag is unset (as we may have been disconnected if it's the same actor)
-  mActorDisconnected = false;
-}
-
-void TouchEventProcessor::ActorObserver::ResetActor()
-{
-  if ( mActor )
-  {
-    DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Stop Observing:             %p\n", mActor);
-    mActor->RemoveObserver( *this );
-    mActor = NULL;
-    mActorDisconnected = false;
-  }
-}
-
-void TouchEventProcessor::ActorObserver::SceneObjectRemoved( ProxyObject& proxy )
-{
-  DALI_LOG_TRACE_METHOD( gLogFilter );
-
-  if ( mActor == &proxy )
-  {
-    // do not call proxy.RemoveObserver here, proxy is currently iterating through observers... you wouldnt want to upset proxy now would you?
-    mActorDisconnected = true;
-  }
-}
-
-void TouchEventProcessor::ActorObserver::ProxyDestroyed(ProxyObject& proxy)
-{
-  DALI_LOG_TRACE_METHOD( gLogFilter );
-
-  if ( mActor == &proxy )
-  {
-    DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Stop Observing:             %p\n", mActor);
-    mActor = NULL;
-  }
-}
-
 } // namespace Internal
 
 } // namespace Dali
index 5eee7c7..c07a131 100644 (file)
@@ -20,7 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/public-api/render-tasks/render-task.h>
-#include <dali/internal/event/common/proxy-object.h>
+#include <dali/internal/event/events/actor-observer.h>
 
 namespace Dali
 {
@@ -39,6 +39,7 @@ namespace Internal
 
 class Actor;
 class Stage;
+class ActorObserver;
 
 /**
  * <h3>Multi-Touch Event Processing:</h3>
@@ -79,80 +80,6 @@ private:
 
 private:
 
-  /**
-   * Stores an actor pointer and connects/disconnects to any required signals appropriately when set/unset.
-   */
-  struct ActorObserver : public ProxyObject::Observer
-  {
-  public:
-
-    // Construction & Destruction
-
-    /**
-     * Constructor.
-     */
-    ActorObserver();
-
-    /**
-     * Non virtual destructor
-     */
-    ~ActorObserver();
-
-    // Methods
-
-    /**
-     * Return the stored Actor pointer.
-     * @return The Actor pointer.
-     */
-    Actor* GetActor();
-
-    /**
-     * Assignment operator.
-     * This disconnects the required signals from the currently set actor and connects to the required
-     * signals for the the actor specified (if set).
-     */
-    void SetActor( Actor* actor );
-
-    /**
-     * Resets the set actor and disconnects any connected signals.
-     */
-    void ResetActor();
-
-  private:
-
-    // Undefined
-    ActorObserver( const ActorObserver& );
-    ActorObserver& operator=( const ActorObserver& );
-
-  private:
-
-    /**
-     * This will never get called as we do not observe objects that have not been added to the scene.
-     * @param[in] proxy The proxy object.
-     * @see ProxyObject::Observer::SceneObjectAdded()
-     */
-    virtual void SceneObjectAdded(ProxyObject& proxy) { }
-
-    /**
-     * This will be called when the actor is removed from the stage, we should clear and stop
-     * observing it.
-     * @param[in] proxy The proxy object.
-     * @see ProxyObject::Observer::SceneObjectRemoved()
-     */
-    virtual void SceneObjectRemoved(ProxyObject& proxy);
-
-    /**
-     * This will be called when the actor is destroyed. We should clear the actor.
-     * No need to stop observing as the object is being destroyed anyway.
-     * @see ProxyObject::Observer::ProxyDestroyed()
-     */
-    virtual void ProxyDestroyed(ProxyObject& proxy);
-
-  private:
-    Actor* mActor;              ///< Raw pointer to an Actor.
-    bool   mActorDisconnected;  ///< Indicates whether the actor has been disconnected from the scene
-  };
-
   Stage& mStage; ///< Used to deliver touch events
   ActorObserver mLastPrimaryHitActor; ///< Stores the last primary point hit actor
   ActorObserver mLastConsumedActor; ///< Stores the last consumed actor
index 28acf87..45a25a9 100644 (file)
@@ -48,15 +48,18 @@ internal_src_files = \
   $(internal_src_dir)/event/effects/shader-effect-impl.cpp \
   $(internal_src_dir)/event/effects/shader-factory.cpp \
   $(internal_src_dir)/event/events/actor-gesture-data.cpp \
+  $(internal_src_dir)/event/events/actor-observer.cpp \
   $(internal_src_dir)/event/events/event-processor.cpp \
   $(internal_src_dir)/event/events/key-event-processor.cpp \
   $(internal_src_dir)/event/events/gesture-detector-impl.cpp \
   $(internal_src_dir)/event/events/gesture-event-processor.cpp \
   $(internal_src_dir)/event/events/gesture-processor.cpp \
   $(internal_src_dir)/event/events/hit-test-algorithm-impl.cpp \
+  $(internal_src_dir)/event/events/hover-event-processor.cpp \
   $(internal_src_dir)/event/events/long-press-gesture-detector-impl.cpp \
   $(internal_src_dir)/event/events/long-press-gesture-processor.cpp \
   $(internal_src_dir)/event/events/mouse-wheel-event-processor.cpp \
+  $(internal_src_dir)/event/events/multi-point-event-util.cpp \
   $(internal_src_dir)/event/events/pan-gesture-detector-impl.cpp \
   $(internal_src_dir)/event/events/pan-gesture-processor.cpp \
   $(internal_src_dir)/event/events/pinch-gesture-detector-impl.cpp \
index 2ffa4ab..88fc0d6 100644 (file)
@@ -49,6 +49,7 @@ namespace Dali
 {
 
 const char* const Actor::SIGNAL_TOUCHED = "touched";
+const char* const Actor::SIGNAL_HOVERED = "hovered";
 const char* const Actor::SIGNAL_MOUSE_WHEEL_EVENT = "mouse-wheel-event";
 const char* const Actor::SIGNAL_SET_SIZE = "set-size";
 const char* const Actor::SIGNAL_ON_STAGE = "on-stage";
@@ -495,6 +496,11 @@ Actor::TouchSignalV2& Actor::TouchedSignal()
   return GetImplementation(*this).TouchedSignal();
 }
 
+Actor::HoverSignalV2& Actor::HoveredSignal()
+{
+  return GetImplementation(*this).HoveredSignal();
+}
+
 Actor::MouseWheelEventSignalV2& Actor::MouseWheelEventSignal()
 {
   return GetImplementation(*this).MouseWheelEventSignal();
index 438735a..b007ce4 100644 (file)
@@ -50,6 +50,7 @@ class Layer;
 struct Radian;
 struct KeyEvent;
 struct TouchEvent;
+struct HoverEvent;
 struct MouseWheelEvent;
 struct Vector2;
 struct Vector3;
@@ -71,11 +72,11 @@ typedef ActorContainer::const_iterator ActorConstIter; ///< Const iterator for D
  *
  * <h3>Multi-Touch Events:</h3>
  *
- * Touch events are received via signals; see Actor::TouchedSignal() for more details.
+ * Touch or hover events are received via signals; see Actor::TouchedSignal() and Actor::HoveredSignal() for more details.
  *
  * <i>Hit Testing Rules Summary:</i>
  *
- * - An actor is only hittable if the actor's touch signal has a connection.
+ * - An actor is only hittable if the actor's touch or hover signal has a connection.
  * - An actor is only hittable when it is between the camera's near and far planes.
  * - If an actor is made insensitive, then the actor and its children are not hittable; see IsSensitive()
  * - If an actor's visibility flag is unset, then none of its children are hittable either; see IsVisible()
@@ -108,7 +109,7 @@ typedef ActorContainer::const_iterator ActorConstIter; ///< Const iterator for D
  *         // Depth-first traversal within current layer, visiting parent first
  *
  *         // Check whether current actor should be hit-tested
- *         IF ( TOUCH-SIGNAL-NOT-EMPTY &&
+ *         IF ( ( TOUCH-SIGNAL-NOT-EMPTY || HOVER-SIGNAL-NOT-EMPTY ) &&
  *              ACTOR-HAS-NON-ZERO-SIZE &&
  *              ACTOR-WORLD-COLOR-IS-NOT-TRANSPARENT )
  *         {
@@ -158,11 +159,11 @@ typedef ActorContainer::const_iterator ActorConstIter; ///< Const iterator for D
  *     also be considered a Stencil Actor.
  *     Non-renderable actors can be hit regardless of whether a stencil actor is hit or not.
  *
- * <i>Touch Event Delivery:</i>
+ * <i>Touch or hover Event Delivery:</i>
  *
  * - Delivery
- *   - The hit actor's touch signal is emitted first; if it is not consumed by any of the listeners,
- *     the parent's touch signal is emitted, and so on.
+ *   - The hit actor's touch or hover signal is emitted first; if it is not consumed by any of the listeners,
+ *     the parent's touch or hover signal is emitted, and so on.
  *   - The following pseudocode shows the delivery mechanism:
  *     @code
  *     EMIT-TOUCH-SIGNAL( ACTOR )
@@ -182,25 +183,45 @@ typedef ActorContainer::const_iterator ActorConstIter; ///< Const iterator for D
  *         }
  *       }
  *     }
+ *
+ *     EMIT-HOVER-SIGNAL( ACTOR )
+ *     {
+ *       IF ( HOVER-SIGNAL-NOT-EMPTY )
+ *       {
+ *         // Only do the emission if hover signal of actor has connections.
+ *         CONSUMED = HOVERED-SIGNAL( HOVER-EVENT )
+ *       }
+ *
+ *       IF ( NOT-CONSUMED )
+ *       {
+ *         // If event is not consumed then deliver it to the parent unless we reach the root actor
+ *         IF ( ACTOR-PARENT )
+ *         {
+ *           EMIT-HOVER-SIGNAL( ACTOR-PARENT )
+ *         }
+ *       }
+ *     }
  *     @endcode
  *   - If there are several touch points, then the delivery is only to the first touch point's hit
- *     actor (and its parents).  There will be NO touch signal delivery for the hit actors of the
+ *     actor (and its parents).  There will be NO touch or hover signal delivery for the hit actors of the
  *     other touch points.
  *   - The local coordinates are from the top-left (0.0f, 0.0f, 0.5f) of the hit actor.
  *
  * - Leave State
  *   - A "Leave" state is set when the first point exits the bounds of the previous first point's
  *     hit actor (primary hit actor).
- *   - When this happens, the last primary hit actor's touch signal is emitted with a "Leave" state
+ *   - When this happens, the last primary hit actor's touch or hover signal is emitted with a "Leave" state
  *     (only if it requires leave signals); see SetLeaveRequired().
  *
  * - Interrupted State
- *   - If a system event occurs which interrupts the touch processing, then the last primary hit
- *     actor's touch signals are emitted with an "Interrupted" state.
- *   - If the last primary hit actor, or one of its parents, is no longer touchable, then its
- *     touch signals are also emitted with an "Interrupted" state.
+ *   - If a system event occurs which interrupts the touch or hover processing, then the last primary hit
+ *     actor's touch or hover signals are emitted with an "Interrupted" state.
+ *   - If the last primary hit actor, or one of its parents, is no longer touchable or hoverable, then its
+ *     touch or hover signals are also emitted with an "Interrupted" state.
  *   - If the consumed actor on touch-down is not the same as the consumed actor on touch-up, then
  *     touch signals are also emitted from the touch-down actor with an "Interrupted" state.
+ *   - If the consumed actor on hover-start is not the same as the consumed actor on hover-finished, then
+ *     hover signals are also emitted from the hover-started actor with an "Interrupted" state.
  * <h3>Key Events:</h3>
  *
  * Key events are received by an actor once set to grab key events, only one actor can be set as focused.
@@ -214,6 +235,7 @@ public:
   // Typedefs
 
   typedef SignalV2< bool (Actor, const TouchEvent&)> TouchSignalV2;                ///< Touch signal type
+  typedef SignalV2< bool (Actor, const HoverEvent&)> HoverSignalV2;                ///< Hover signal type
   typedef SignalV2< bool (Actor, const MouseWheelEvent&) > MouseWheelEventSignalV2;///< Mousewheel signal type
   typedef SignalV2< void (Actor, const Vector3&) > SetSizeSignalV2; ///< SetSize signal type
   typedef SignalV2< void (Actor) > OnStageSignalV2;  ///< Stage connection signal type
@@ -269,6 +291,7 @@ public:
   /// @name Signals
   /** @{ */
   static const char* const SIGNAL_TOUCHED;            ///< name "touched",           @see TouchedSignal()
+  static const char* const SIGNAL_HOVERED;            ///< name "hovered",           @see HoveredSignal()
   static const char* const SIGNAL_MOUSE_WHEEL_EVENT;  ///< name "mouse-wheel-event", @see MouseWheelEventSignal()
   static const char* const SIGNAL_SET_SIZE;           ///< name "set-size",          @see SetSizeSignal()
   static const char* const SIGNAL_ON_STAGE;           ///< name "on-stage",          @see OnStageSignal()
@@ -1055,38 +1078,39 @@ public:
   // Input Handling
 
   /**
-   * @brief Sets whether an actor should emit touch event signals; @see SignalTouched().
+   * @brief Sets whether an actor should emit touch or hover signals; see SignalTouch() and SignalHover().
    *
-   * An actor is sensitive by default, which means that as soon as an application connects to the SignalTouched(),
-   * the touch event signal will be emitted.
+   * An actor is sensitive by default, which means that as soon as an application connects to the SignalTouch(),
+   * the touch event signal will be emitted, and as soon as an application connects to the SignalHover(), the
+   * hover event signal will be emitted.
    *
-   * If the application wishes to temporarily disable the touch event signal emission, then they can do so by calling:
+   * If the application wishes to temporarily disable the touch or hover event signal emission, then they can do so by calling:
    * @code
    * actor.SetSensitive(false);
    * @endcode
    *
-   * Then, to re-enable the touch event signal emission, the application should call:
+   * Then, to re-enable the touch or hover event signal emission, the application should call:
    * @code
    * actor.SetSensitive(true);
    * @endcode
    *
-   * @see SignalTouched().
+   * @see @see SignalTouch() and SignalHover().
    * @note If an actor's sensitivity is set to false, then it's children will not be hittable either.
    *       This is regardless of the individual sensitivity values of the children i.e. an actor will only be
    *       hittable if all of its parents have sensitivity set to true.
    * @pre The Actor has been initialized.
-   * @param[in]  sensitive  true to enable emission of the touch event signals, false otherwise.
+   * @param[in]  sensitive  true to enable emission of the touch or hover event signals, false otherwise.
    */
   void SetSensitive(bool sensitive);
 
   /**
-   * @brief Query whether an actor emits touch event signals.
+   * @brief Query whether an actor emits touch or hover event signals.
    *
    * @note If an actor is not sensitive, then it's children will not be hittable either.
    *       This is regardless of the individual sensitivity values of the children i.e. an actor will only be
    *       hittable if all of its parents have sensitivity set to true.
    * @pre The Actor has been initialized.
-   * @return true, if emission of touch event signals is enabled, false otherwise.
+   * @return true, if emission of touch or hover event signals is enabled, false otherwise.
    */
   bool IsSensitive() const;
 
@@ -1104,11 +1128,11 @@ public:
   bool ScreenToLocal(float& localX, float& localY, float screenX, float screenY) const;
 
   /**
-   * @brief Sets whether the actor should receive a notification when touch motion events leave
+   * @brief Sets whether the actor should receive a notification when touch or hover motion events leave
    * the boundary of the actor.
    *
    * @note By default, this is set to false as most actors do not require this.
-   * @note Need to connect to the SignalTouch to actually receive this event.
+   * @note Need to connect to the SignalTouch or SignalHover to actually receive this event.
    *
    * @pre The Actor has been initialized.
    * @param[in]  required  Should be set to true if a Leave event is required
@@ -1116,7 +1140,7 @@ public:
   void SetLeaveRequired(bool required);
 
   /**
-   * @brief This returns whether the actor requires touch events whenever touch motion events leave
+   * @brief This returns whether the actor requires touch or hover events whenever touch or hover motion events leave
    * the boundary of the actor.
    *
    * @pre The Actor has been initialized.
@@ -1159,6 +1183,20 @@ public: // Signals
   TouchSignalV2& TouchedSignal();
 
   /**
+   * @brief This signal is emitted when hover input is received.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName(Actor actor, const HoverEvent& event);
+   * @endcode
+   * The return value of True, indicates that the hover event should be consumed.
+   * Otherwise the signal will be emitted on the next sensitive parent of the actor.
+   * @pre The Actor has been initialized.
+   * @return The signal to connect to.
+   */
+  HoverSignalV2& HoveredSignal();
+
+  /**
    * @brief This signal is emitted when mouse wheel event is received.
    *
    * A callback of the following type may be connected:
index 28e5b79..c393604 100644 (file)
@@ -43,6 +43,7 @@ void CustomActorImpl::OnPropertySet( Property::Index index, Property::Value prop
 CustomActorImpl::CustomActorImpl(bool requiresTouchEvents)
 : mOwner(NULL),
   mRequiresTouchEvents(requiresTouchEvents),
+  mRequiresHoverEvents(false),
   mRequiresMouseWheelEvents(false)
 {
 }
@@ -64,6 +65,16 @@ bool CustomActorImpl::RequiresTouchEvents() const
   return mRequiresTouchEvents;
 }
 
+bool CustomActorImpl::RequiresHoverEvents() const
+{
+  return mRequiresHoverEvents;
+}
+
+void CustomActorImpl::SetRequiresHoverEvents(bool requiresHoverEvents)
+{
+  mRequiresHoverEvents = requiresHoverEvents;
+}
+
 bool CustomActorImpl::RequiresMouseWheelEvents() const
 {
   return mRequiresMouseWheelEvents;
index 071cb8f..3792e51 100644 (file)
@@ -37,6 +37,7 @@ class CustomActor;
 class CustomActorImpl;
 struct KeyEvent;
 struct TouchEvent;
+struct HoverEvent;
 struct MouseWheelEvent;
 struct Vector3;
 
@@ -151,6 +152,15 @@ public:
   virtual bool OnTouchEvent(const TouchEvent& event) = 0;
 
   /**
+   * @brief Called after a hover-event is received by the owning actor.
+   *
+   * @note This must be enabled during construction; see CustomActorImpl::SetRequiresHoverEvents(bool)
+   * @param[in] event The hover event.
+   * @return True if the event should be consumed.
+   */
+  virtual bool OnHoverEvent(const HoverEvent& event) = 0;
+
+  /**
    * @brief Called after a key-event is received by the actor that has had its focus set.
    *
    * @param[in] event the Key Event
@@ -205,6 +215,12 @@ protected: // For derived classes
   CustomActorImpl(bool requiresTouchEvents);
 
   /**
+   * @brief Set whether the custom actor requires hover events.
+   * @param[in] requiresHoverEvents True if the OnHoverEvent() callback is required.
+   */
+  void SetRequiresHoverEvents(bool requiresHoverEvents);
+
+  /**
    * @brief Set whether the custom actor requires mouse wheel events.
    * @param[in] requiresMouseWheelEvents True if the OnMouseWheelEvent() callback is required.
    */
@@ -237,6 +253,12 @@ public: // Not intended for application developers
 
   /**
    * @brief Called when ownership of the CustomActorImpl is passed to a CustomActor.
+   * @return True if the OnHoverEvent() callback is required.
+   */
+  bool RequiresHoverEvents() const;
+
+  /**
+   * @brief Called when ownership of the CustomActorImpl is passed to a CustomActor.
    * @return True if the OnMouseWheelEvent() callback is required.
    */
   bool RequiresMouseWheelEvents() const;
@@ -245,6 +267,7 @@ private:
 
   Internal::CustomActor* mOwner;  ///< Internal owner of this custom actor implementation
   bool mRequiresTouchEvents;      ///< Whether the OnTouchEvent() callback is required
+  bool mRequiresHoverEvents;      ///< Whether the OnHoverEvent() callback is required
   bool mRequiresMouseWheelEvents; ///< Whether the OnMouseWheelEvent() callback is required
 };
 
index 20b1fe0..76fa041 100644 (file)
@@ -171,6 +171,16 @@ bool Layer::IsTouchConsumed() const
   return GetImplementation( *this ).IsTouchConsumed();
 }
 
+void Layer::SetHoverConsumed( bool consume )
+{
+  GetImplementation( *this ).SetHoverConsumed( consume );
+}
+
+bool Layer::IsHoverConsumed() const
+{
+  return GetImplementation( *this ).IsHoverConsumed();
+}
+
 Layer::Layer(Internal::Layer* internal)
 : Actor(internal)
 {
index 5ca44ee..8a1199e 100644 (file)
@@ -335,6 +335,22 @@ public:
    */
   bool IsTouchConsumed() const;
 
+  /**
+   * @brief This allows the user to specify whether this layer should consume hover.
+   *
+   * If set, any layers behind this layer will not be hit-test.
+   *
+   * @param[in]  consume  Whether the layer should consume hover.
+   */
+  void SetHoverConsumed( bool consume );
+
+  /**
+   * @brief Retrieves whether the layer consumes hover.
+   *
+   * @return true if consuming hover, false otherwise.
+   */
+  bool IsHoverConsumed() const;
+
 public: // Not intended for application developers
 
   /**
index 35c64fb..d9ddbb7 100644 (file)
@@ -70,6 +70,7 @@
 #include <dali/public-api/events/gesture-detector.h>
 #include <dali/public-api/events/gesture.h>
 #include <dali/public-api/events/hit-test-algorithm.h>
+#include <dali/public-api/events/hover-event.h>
 #include <dali/public-api/events/key-event.h>
 #include <dali/public-api/events/long-press-gesture-detector.h>
 #include <dali/public-api/events/long-press-gesture.h>
diff --git a/dali/public-api/events/hover-event.cpp b/dali/public-api/events/hover-event.cpp
new file mode 100644 (file)
index 0000000..860b364
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/public-api/events/hover-event.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+
+HoverEvent::HoverEvent()
+: time(0)
+{
+}
+
+HoverEvent::HoverEvent(unsigned long time)
+: time(time)
+{
+}
+
+HoverEvent::~HoverEvent()
+{
+}
+
+unsigned int HoverEvent::GetPointCount() const
+{
+  return points.size();
+}
+
+const TouchPoint& HoverEvent::GetPoint(unsigned int point) const
+{
+  DALI_ASSERT_ALWAYS( point < points.size() && "No point at index" );
+  return points[point];
+}
+
+} // namespace Dali
diff --git a/dali/public-api/events/hover-event.h b/dali/public-api/events/hover-event.h
new file mode 100644 (file)
index 0000000..bc5d8f7
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef __DALI_HOVER_EVENT_H__
+#define __DALI_HOVER_EVENT_H__
+
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/events/touch-point.h>
+
+namespace Dali DALI_IMPORT_API
+{
+
+/**
+ * @brief Hover events are a collection of touch points at a specific moment in time.
+ *
+ * When a multi-touch event occurs, each touch point represents the points that are currently being
+ * hovered or the points where a hover has stopped.
+ */
+struct DALI_IMPORT_API HoverEvent
+{
+  // Construction & Destruction
+
+  /**
+   * @brief Default constructor
+   */
+  HoverEvent();
+
+  /**
+   * @brief Constructor
+   * @param[in]  time  The time the event occurred
+   */
+  HoverEvent(unsigned long time);
+
+  /**
+   * @brief Destructor
+   */
+  ~HoverEvent();
+
+  // Data
+
+  /**
+   * @brief This is a container of points for this hover event.
+   *
+   * The first point in the set is always the
+   * primary touch point (i.e. the first point touched in a multi-touch event).
+   */
+  TouchPointContainer points;
+
+  /**
+   * @brief The time (in ms) that the hover event occurred.
+   */
+  unsigned long time;
+
+  // Convenience Methods
+
+  /**
+   * @brief Returns the total number of points in this HoverEvent.
+   *
+   * @return Total number of Points.
+   */
+  unsigned int GetPointCount() const;
+
+  /**
+   * @brief Returns a touch point at the index requested.
+   *
+   * The first point in the set is always the primary
+   * touch point (i.e. the first point touched in a multi-touch event).
+   * @note "point" should be less than the value returned by GetPointCount().
+   *       If out of range, then program asserts.
+   * @param[in] point The index of the required Point.
+   * @return Point requested
+   */
+  const TouchPoint& GetPoint(unsigned int point) const;
+};
+
+} // namespace Dali
+
+#endif // __DALI_HOVER_EVENT_H__
index e068726..d1eebc5 100644 (file)
 
 namespace Dali DALI_IMPORT_API
 {
-typedef std::vector<TouchPoint> TouchPointContainer; ///< Container of touch points.
-typedef TouchPointContainer::iterator TouchPointContainerIterator; ///< Iterator for Dali::TouchPointContainer
-typedef TouchPointContainer::const_iterator TouchPointContainerConstIterator; ///< Const iterator for Dali::TouchPointContainer
-
 /**
  * @brief Touch events are a collection of touch points at a specific moment in time.
  *
index d5038ef..12cafb8 100644 (file)
@@ -38,15 +38,17 @@ struct TouchPoint
    */
   enum State
   {
-    Down,        /**< Screen touched */
-    Up,          /**< Touch stopped */
-    Motion,      /**< Finger dragged */
-    Leave,       /**< Leave the boundary of an actor */
-    Stationary,  /**< No change from last event.  Useful when a multi-touch event occurs where
-                      all points are sent but indicates that this particular point has not changed
-                      since the last time */
-    Interrupted, /**< A system event has occurred which has interrupted the touch event sequence. */
-    Last         /**< Number of states. */
+    Started,        /**< Touch or hover started */
+    Finished,       /**< Touch or hover finished */
+    Down = Started, /**< Screen touched */
+    Up = Finished,  /**< Touch stopped */
+    Motion,         /**< Finger dragged or hovered */
+    Leave,          /**< Leave the boundary of an actor */
+    Stationary,     /**< No change from last event.  Useful when a multi-point event occurs where
+                         all points are sent but indicates that this particular point has not changed
+                         since the last time */
+    Interrupted,    /**< A system event has occurred which has interrupted the touch or hover event sequence. */
+    Last            /**< Number of states. */
   };
 
   // Construction & Destruction
@@ -112,6 +114,10 @@ struct TouchPoint
   Vector2 screen;
 };
 
+typedef std::vector<TouchPoint> TouchPointContainer; ///< Container of touch points.
+typedef TouchPointContainer::iterator TouchPointContainerIterator; ///< Iterator for Dali::TouchPointContainer
+typedef TouchPointContainer::const_iterator TouchPointContainerConstIterator; ///< Const iterator for Dali::TouchPointContainer
+
 } // namespace Dali
 
 #endif // __DALI_TOUCH_POINT_H__
index c6166f9..45d0040 100644 (file)
@@ -38,6 +38,7 @@ public_api_src_files = \
   $(public_api_src_dir)/events/gesture.cpp \
   $(public_api_src_dir)/events/gesture-detector.cpp \
   $(public_api_src_dir)/events/hit-test-algorithm.cpp \
+  $(public_api_src_dir)/events/hover-event.cpp \
   $(public_api_src_dir)/events/key-event.cpp \
   $(public_api_src_dir)/events/long-press-gesture.cpp \
   $(public_api_src_dir)/events/long-press-gesture-detector.cpp \
@@ -182,6 +183,7 @@ public_api_core_events_header_files = \
   $(public_api_src_dir)/events/gesture.h \
   $(public_api_src_dir)/events/gesture-detector.h \
   $(public_api_src_dir)/events/hit-test-algorithm.h \
+  $(public_api_src_dir)/events/hover-event.h \
   $(public_api_src_dir)/events/key-event.h \
   $(public_api_src_dir)/events/long-press-gesture.h \
   $(public_api_src_dir)/events/long-press-gesture-detector.h \