From: Adeel Kazmi Date: Wed, 16 Jul 2014 15:54:09 +0000 (+0100) Subject: (HitTest) Ensure non-renderable actors are hittable even if outside the stencil X-Git-Tag: dali_1.0.1~12^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e61d60833033fe14c46188cbde1005b3f52f7044;p=platform%2Fcore%2Fuifw%2Fdali-core.git (HitTest) Ensure non-renderable actors are hittable even if outside the stencil We do not expect to receive a hit outside the stencil area for a rendered actor. However, for non-renderable actors, we cannot see these anyway and so these should still be hittable even if we haven't hit the stencil area. This would allow controls like scroll-view to work with stencils where we only want the stencil to affect the children of scroll-view. Change-Id: Ic8e9d00a4125c94972ad2cfe298fae65313ad7dd Signed-off-by: Adeel Kazmi --- diff --git a/automated-tests/src/dali/utc-Dali-TouchProcessing.cpp b/automated-tests/src/dali/utc-Dali-TouchProcessing.cpp index b0c3709..6f11247 100644 --- a/automated-tests/src/dali/utc-Dali-TouchProcessing.cpp +++ b/automated-tests/src/dali/utc-Dali-TouchProcessing.cpp @@ -1289,3 +1289,215 @@ int UtcDaliTouchLeaveActorReadded(void) END_TEST; } + +int UtcDaliTouchStencil(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 touched signal + SignalData data; + TouchEventFunctor functor( data ); + actor.TouchedSignal().Connect( &application, functor ); + + // Emit an event within stencil area + application.ProcessEvent( GenerateSingleTouch( TouchPoint::Down, 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( GenerateSingleTouch( TouchPoint::Down, Vector2( 60.0f, 60.0f ) ) ); + DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION ); + data.Reset(); + + END_TEST; +} + +int UtcDaliTouchStencilInActorHierarchy(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 touch signals + SignalData parentData; + parent.TouchedSignal().Connect( &application, TouchEventFunctor(parentData) ); + SignalData childData; + child.TouchedSignal().Connect( &application, TouchEventFunctor(childData) ); + + // Emit an event within stencil area + application.ProcessEvent( GenerateSingleTouch( TouchPoint::Down, 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( GenerateSingleTouch( 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( GenerateSingleTouch( 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( GenerateSingleTouch( 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( GenerateSingleTouch( 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( GenerateSingleTouch( 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 UtcDaliTouchMultipleStencils(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 touched signal + SignalData data; + TouchEventFunctor functor( data ); + actor.TouchedSignal().Connect( &application, functor ); + + // Emit an event within stencil area + application.ProcessEvent( GenerateSingleTouch( TouchPoint::Down, 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( GenerateSingleTouch( TouchPoint::Down, 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( GenerateSingleTouch( TouchPoint::Down, Vector2( 10.0f, 60.0f ) ) ); + DALI_TEST_EQUALS( false, data.functorCalled, TEST_LOCATION ); + data.Reset(); + + END_TEST; +} + +int UtcDaliTouchStencilNonRenderableActor(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 touched signal + SignalData data; + TouchEventFunctor functor( data ); + actor.TouchedSignal().Connect( &application, functor ); + + // Emit an event within stencil area + application.ProcessEvent( GenerateSingleTouch( TouchPoint::Down, 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( GenerateSingleTouch( TouchPoint::Down, Vector2( 60.0f, 60.0f ) ) ); + DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION ); + data.Reset(); + + END_TEST; +} diff --git a/capi/dali/public-api/actors/actor.h b/capi/dali/public-api/actors/actor.h index 8649edd..a03259e 100644 --- a/capi/dali/public-api/actors/actor.h +++ b/capi/dali/public-api/actors/actor.h @@ -156,12 +156,13 @@ typedef ActorContainer::const_iterator ActorConstIter; ///< Const iterator for D * * Hit Priority of above Actor tree (all overlays): 1 - Lowest. 6 - Highest. * @endcode - * - Stencil Actors can be used to influence the result of hits within a layer. + * - Stencil Actors can be used to influence the result of hits on renderable actors within a layer. * If a Stencil Actor exists on a layer and that Actor is marked visible then a successful - * hit can only take place in the area that the stencil Actor marks as visible. + * hit on a renderable actor can only take place in the area that the stencil Actor marks as visible. * The hit can be in any Stencil Actor in that layer, but must be in the region of one of them. * Stencil Actor inheritance behaves as with rendering in that any child of a Stencil Actor will * 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: * diff --git a/dali/internal/event/events/hit-test-algorithm-impl.cpp b/dali/internal/event/events/hit-test-algorithm-impl.cpp index 22fe563..51eeeec 100644 --- a/dali/internal/event/events/hit-test-algorithm-impl.cpp +++ b/dali/internal/event/events/hit-test-algorithm-impl.cpp @@ -390,10 +390,11 @@ bool HitTestRenderTask( LayerList& layers, hit = HitTestWithinLayer( *layer, results.rayOrigin, results.rayDirection, false, nearClippingPlane, farClippingPlane, hitCheck, stencilOnLayer, stencilHit, false ); } - // If a stencil on this layer hasn't been hit, then discard hit results for this layer - if ( stencilOnLayer && !stencilHit ) + // If a stencil on this layer hasn't been hit, then discard hit results for this layer if our current hit actor is renderable + if ( stencilOnLayer && !stencilHit && + hit.actor && hit.actor->IsRenderable() ) { - hit = previousHit; + hit = previousHit; } // If this layer is set to consume the hit, then do not check any layers behind it