From: Richard Huang Date: Fri, 19 Sep 2014 10:41:01 +0000 (+0100) Subject: Added hover event in Dali X-Git-Tag: dali_1.0.12~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=28335fec38b67d9eb534f0bcc959d697f7cfc888;p=platform%2Fcore%2Fuifw%2Fdali-core.git Added hover event in Dali 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 --- diff --git a/automated-tests/src/dali-unmanaged/utc-Dali-CustomActor.cpp b/automated-tests/src/dali-unmanaged/utc-Dali-CustomActor.cpp index 8bb6ede..c7e8d64 100644 --- a/automated-tests/src/dali-unmanaged/utc-Dali-CustomActor.cpp +++ b/automated-tests/src/dali-unmanaged/utc-Dali-CustomActor.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -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"); diff --git a/automated-tests/src/dali-unmanaged/utc-Dali-TypeRegistry.cpp b/automated-tests/src/dali-unmanaged/utc-Dali-TypeRegistry.cpp index 53eb88c..ebc7c0c 100644 --- a/automated-tests/src/dali-unmanaged/utc-Dali-TypeRegistry.cpp +++ b/automated-tests/src/dali-unmanaged/utc-Dali-TypeRegistry.cpp @@ -24,6 +24,7 @@ #include #include #include +#include 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; diff --git a/automated-tests/src/dali/CMakeLists.txt b/automated-tests/src/dali/CMakeLists.txt index 647ce4a..7c5f402 100644 --- a/automated-tests/src/dali/CMakeLists.txt +++ b/automated-tests/src/dali/CMakeLists.txt @@ -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 diff --git a/automated-tests/src/dali/utc-Dali-Actor.cpp b/automated-tests/src/dali/utc-Dali-Actor.cpp index 95dc2e6..60a772a 100644 --- a/automated-tests/src/dali/utc-Dali-Actor.cpp +++ b/automated-tests/src/dali/utc-Dali-Actor.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include //& 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) { diff --git a/automated-tests/src/dali/utc-Dali-CustomActor.cpp b/automated-tests/src/dali/utc-Dali-CustomActor.cpp index 2e54d07..aa10dd3 100644 --- a/automated-tests/src/dali/utc-Dali-CustomActor.cpp +++ b/automated-tests/src/dali/utc-Dali-CustomActor.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -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 index 0000000..686fe95 --- /dev/null +++ b/automated-tests/src/dali/utc-Dali-HoverProcessing.cpp @@ -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 + +#include +#include +#include +#include +#include + +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; +} diff --git a/automated-tests/src/dali/utc-Dali-Layer.cpp b/automated-tests/src/dali/utc-Dali-Layer.cpp index 5ec2a06..82ca140 100644 --- a/automated-tests/src/dali/utc-Dali-Layer.cpp +++ b/automated-tests/src/dali/utc-Dali-Layer.cpp @@ -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; } diff --git a/automated-tests/src/dali/utc-Dali-TouchEventCombiner.cpp b/automated-tests/src/dali/utc-Dali-TouchEventCombiner.cpp index 80eb3da..fb1eafa 100644 --- a/automated-tests/src/dali/utc-Dali-TouchEventCombiner.cpp +++ b/automated-tests/src/dali/utc-Dali-TouchEventCombiner.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include 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; } diff --git a/dali/integration-api/events/event.h b/dali/integration-api/events/event.h index 6883981..474dec0 100644 --- a/dali/integration-api/events/event.h +++ b/dali/integration-api/events/event.h @@ -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 index 0000000..4b846a8 --- /dev/null +++ b/dali/integration-api/events/hover-event-integ.cpp @@ -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 + +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 index 0000000..7d7bffd --- /dev/null +++ b/dali/integration-api/events/hover-event-integ.h @@ -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 +#include + +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 index 0000000..9320a45 --- /dev/null +++ b/dali/integration-api/events/multi-point-event-integ.cpp @@ -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 + +// INTERNAL INCLUDES +#include + +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 index 0000000..b5dd601 --- /dev/null +++ b/dali/integration-api/events/multi-point-event-integ.h @@ -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 +#include +#include + +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 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__ diff --git a/dali/integration-api/events/touch-event-combiner.cpp b/dali/integration-api/events/touch-event-combiner.cpp index 0a3d35d..7a3ddad 100644 --- a/dali/integration-api/events/touch-event-combiner.cpp +++ b/dali/integration-api/events/touch-event-combiner.cpp @@ -23,6 +23,7 @@ // INTERNAL INCLUDES #include +#include #include 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 diff --git a/dali/integration-api/events/touch-event-combiner.h b/dali/integration-api/events/touch-event-combiner.h index 27627bc..1c3b351 100644 --- a/dali/integration-api/events/touch-event-combiner.h +++ b/dali/integration-api/events/touch-event-combiner.h @@ -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. diff --git a/dali/integration-api/events/touch-event-integ.cpp b/dali/integration-api/events/touch-event-integ.cpp index 438530f..ac44731 100644 --- a/dali/integration-api/events/touch-event-integ.cpp +++ b/dali/integration-api/events/touch-event-integ.cpp @@ -18,9 +18,6 @@ // CLASS HEADER #include -// INTERNAL INCLUDES -#include - 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 diff --git a/dali/integration-api/events/touch-event-integ.h b/dali/integration-api/events/touch-event-integ.h index 86cfe5e..86752aa 100644 --- a/dali/integration-api/events/touch-event-integ.h +++ b/dali/integration-api/events/touch-event-integ.h @@ -19,10 +19,8 @@ */ // INTERNAL INCLUDES -#include -#include #include -#include +#include 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 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 diff --git a/dali/integration-api/file.list b/dali/integration-api/file.list index 5620edd..c820882 100644 --- a/dali/integration-api/file.list +++ b/dali/integration-api/file.list @@ -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 \ diff --git a/dali/internal/event/actors/actor-impl.cpp b/dali/internal/event/actors/actor-impl.cpp index fcb0680..0968ac9 100644 --- a/dali/internal/event/actors/actor-impl.cpp +++ b/dali/internal/event/actors/actor-impl.cpp @@ -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 ), diff --git a/dali/internal/event/actors/actor-impl.h b/dali/internal/event/actors/actor-impl.h index 7a16a3a..e23cbd6 100644 --- a/dali/internal/event/actors/actor-impl.h +++ b/dali/internal/event/actors/actor-impl.h @@ -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. diff --git a/dali/internal/event/actors/custom-actor-internal.cpp b/dali/internal/event/actors/custom-actor-internal.cpp index 6ade4ed..273b6ac 100644 --- a/dali/internal/event/actors/custom-actor-internal.cpp +++ b/dali/internal/event/actors/custom-actor-internal.cpp @@ -40,6 +40,7 @@ CustomActor::CustomActor(CustomActorImpl& extension) mImpl( &extension ) { mDerivedRequiresTouch = extension.RequiresTouchEvents(); + mDerivedRequiresHover = extension.RequiresHoverEvents(); mDerivedRequiresMouseWheelEvent = extension.RequiresMouseWheelEvents(); } diff --git a/dali/internal/event/actors/custom-actor-internal.h b/dali/internal/event/actors/custom-actor-internal.h index 44b3418..d4ed7f7 100644 --- a/dali/internal/event/actors/custom-actor-internal.h +++ b/dali/internal/event/actors/custom-actor-internal.h @@ -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) diff --git a/dali/internal/event/actors/layer-impl.cpp b/dali/internal/event/actors/layer-impl.cpp index a91c052..ad5080c 100644 --- a/dali/internal/event/actors/layer-impl.cpp +++ b/dali/internal/event/actors/layer-impl.cpp @@ -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(); diff --git a/dali/internal/event/actors/layer-impl.h b/dali/internal/event/actors/layer-impl.h index affc8cd..ccea127 100644 --- a/dali/internal/event/actors/layer-impl.h +++ b/dali/internal/event/actors/layer-impl.h @@ -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 index 0000000..51c33a0 --- /dev/null +++ b/dali/internal/event/events/actor-observer.cpp @@ -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 +#include +#include + +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 index 0000000..1beb297 --- /dev/null +++ b/dali/internal/event/events/actor-observer.h @@ -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 + +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__ + diff --git a/dali/internal/event/events/event-processor.cpp b/dali/internal/event/events/event-processor.cpp index 3f62462..9d63a3c 100644 --- a/dali/internal/event/events/event-processor.cpp +++ b/dali/internal/event/events/event-processor.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -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(event) ); + + break; + } + case Event::Key: { typedef Integration::KeyEvent DerivedType; @@ -211,6 +226,12 @@ void EventProcessor::ProcessEvents() break; } + case Event::Hover: + { + mHoverEventProcessor.ProcessHoverEvent( static_cast(*event) ); + break; + } + case Event::Key: { mKeyEventProcessor.ProcessKeyEvent( static_cast(*event) ); diff --git a/dali/internal/event/events/event-processor.h b/dali/internal/event/events/event-processor.h index e8b4226..45ea643 100644 --- a/dali/internal/event/events/event-processor.h +++ b/dali/internal/event/events/event-processor.h @@ -20,6 +20,7 @@ // INTERNAL INCLUDES #include +#include #include #include #include @@ -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 index 0000000..3ab14d4 --- /dev/null +++ b/dali/internal/event/events/hover-event-processor.cpp @@ -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 + +#if defined(DEBUG_ENABLED) +#include +#endif + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 index 0000000..2457551 --- /dev/null +++ b/dali/internal/event/events/hover-event-processor.h @@ -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 +#include + +namespace Dali +{ + +class Actor; +struct Vector2; +struct Vector4; + +namespace Integration +{ +struct HoverEvent; +} + +namespace Internal +{ + +class ActorObserver; +class Stage; + +/** + *

Multi-Hover Event Processing:

+ * + * 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 index 0000000..d762508 --- /dev/null +++ b/dali/internal/event/events/multi-point-event-util.cpp @@ -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 +#endif + +// CLASS HEADER +#include +#include + +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; iIsEnabledFor( 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 index 0000000..780c174 --- /dev/null +++ b/dali/internal/event/events/multi-point-event-util.h @@ -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 +#include + +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__ + diff --git a/dali/internal/event/events/touch-event-processor.cpp b/dali/internal/event/events/touch-event-processor.cpp index 758d5ab..393114c 100644 --- a/dali/internal/event/events/touch-event-processor.cpp +++ b/dali/internal/event/events/touch-event-processor.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include 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; iIsEnabledFor( 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 diff --git a/dali/internal/event/events/touch-event-processor.h b/dali/internal/event/events/touch-event-processor.h index 5eee7c7..c07a131 100644 --- a/dali/internal/event/events/touch-event-processor.h +++ b/dali/internal/event/events/touch-event-processor.h @@ -20,7 +20,7 @@ // INTERNAL INCLUDES #include -#include +#include namespace Dali { @@ -39,6 +39,7 @@ namespace Internal class Actor; class Stage; +class ActorObserver; /** *

Multi-Touch Event Processing:

@@ -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 diff --git a/dali/internal/file.list b/dali/internal/file.list index 28acf87..45a25a9 100644 --- a/dali/internal/file.list +++ b/dali/internal/file.list @@ -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 \ diff --git a/dali/public-api/actors/actor.cpp b/dali/public-api/actors/actor.cpp index 2ffa4ab..88fc0d6 100644 --- a/dali/public-api/actors/actor.cpp +++ b/dali/public-api/actors/actor.cpp @@ -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(); diff --git a/dali/public-api/actors/actor.h b/dali/public-api/actors/actor.h index 438735a..b007ce4 100644 --- a/dali/public-api/actors/actor.h +++ b/dali/public-api/actors/actor.h @@ -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 * *

Multi-Touch Events:

* - * 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. * * Hit Testing Rules Summary: * - * - 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. * - * Touch Event Delivery: + * Touch or hover Event Delivery: * * - 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. *

Key Events:

* * 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: diff --git a/dali/public-api/actors/custom-actor-impl.cpp b/dali/public-api/actors/custom-actor-impl.cpp index 28e5b79..c393604 100644 --- a/dali/public-api/actors/custom-actor-impl.cpp +++ b/dali/public-api/actors/custom-actor-impl.cpp @@ -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; diff --git a/dali/public-api/actors/custom-actor-impl.h b/dali/public-api/actors/custom-actor-impl.h index 071cb8f..3792e51 100644 --- a/dali/public-api/actors/custom-actor-impl.h +++ b/dali/public-api/actors/custom-actor-impl.h @@ -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 }; diff --git a/dali/public-api/actors/layer.cpp b/dali/public-api/actors/layer.cpp index 20b1fe0..76fa041 100644 --- a/dali/public-api/actors/layer.cpp +++ b/dali/public-api/actors/layer.cpp @@ -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) { diff --git a/dali/public-api/actors/layer.h b/dali/public-api/actors/layer.h index 5ca44ee..8a1199e 100644 --- a/dali/public-api/actors/layer.h +++ b/dali/public-api/actors/layer.h @@ -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 /** diff --git a/dali/public-api/dali-core.h b/dali/public-api/dali-core.h index 35c64fb..d9ddbb7 100644 --- a/dali/public-api/dali-core.h +++ b/dali/public-api/dali-core.h @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include diff --git a/dali/public-api/events/hover-event.cpp b/dali/public-api/events/hover-event.cpp new file mode 100644 index 0000000..860b364 --- /dev/null +++ b/dali/public-api/events/hover-event.cpp @@ -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 + +// INTERNAL INCLUDES +#include + +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 index 0000000..bc5d8f7 --- /dev/null +++ b/dali/public-api/events/hover-event.h @@ -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 +#include +#include + +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__ diff --git a/dali/public-api/events/touch-event.h b/dali/public-api/events/touch-event.h index e068726..d1eebc5 100644 --- a/dali/public-api/events/touch-event.h +++ b/dali/public-api/events/touch-event.h @@ -25,10 +25,6 @@ namespace Dali DALI_IMPORT_API { -typedef std::vector 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. * diff --git a/dali/public-api/events/touch-point.h b/dali/public-api/events/touch-point.h index d5038ef..12cafb8 100644 --- a/dali/public-api/events/touch-point.h +++ b/dali/public-api/events/touch-point.h @@ -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 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__ diff --git a/dali/public-api/file.list b/dali/public-api/file.list index c6166f9..45d0040 100644 --- a/dali/public-api/file.list +++ b/dali/public-api/file.list @@ -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 \