From 556c629fd8b6ae64b43d500ae566b4a450e4406d Mon Sep 17 00:00:00 2001 From: Joogab Yun Date: Thu, 3 Jun 2021 15:43:05 +0900 Subject: [PATCH] [Tizen] Add TOUCH_FOCUSABLE property This is a property that allows you to have focus even when touched. It works only when KEYBOARD_FOCUSABLE is set to true. KEYBOARD_FOCUSABLE : whether the view can have focus or not TOUCH_FOCUSABLE : Whether the user can focus by touch Change-Id: Id991d7a0bd734718164b874f013e24235476e789 --- automated-tests/src/dali/utc-Dali-Actor.cpp | 24 ++ dali/devel-api/actors/actor-devel.h | 11 + dali/internal/event/actors/actor-impl.cpp | 2 + dali/internal/event/actors/actor-impl.h | 19 + .../event/actors/actor-property-handler.cpp | 16 + .../event/events/hit-test-algorithm-impl.cpp | 428 ++++++++++----------- 6 files changed, 284 insertions(+), 216 deletions(-) diff --git a/automated-tests/src/dali/utc-Dali-Actor.cpp b/automated-tests/src/dali/utc-Dali-Actor.cpp index 217be4a..605c267 100755 --- a/automated-tests/src/dali/utc-Dali-Actor.cpp +++ b/automated-tests/src/dali/utc-Dali-Actor.cpp @@ -2522,6 +2522,30 @@ int UtcDaliActorIsKeyboardFocusable(void) END_TEST; } +int UtcDaliActorSetTouchFocusable(void) +{ + TestApplication application; + + Actor actor = Actor::New(); + + actor.SetProperty(DevelActor::Property::TOUCH_FOCUSABLE, true); + DALI_TEST_CHECK(actor.GetProperty(DevelActor::Property::TOUCH_FOCUSABLE) == true); + + actor.SetProperty(DevelActor::Property::TOUCH_FOCUSABLE, false); + DALI_TEST_CHECK(actor.GetProperty(DevelActor::Property::TOUCH_FOCUSABLE) == false); + END_TEST; +} + +int UtcDaliActorIsTouchFocusable(void) +{ + TestApplication application; + + Actor actor = Actor::New(); + + DALI_TEST_CHECK(actor.GetProperty(DevelActor::Property::TOUCH_FOCUSABLE) == false); + END_TEST; +} + int UtcDaliActorRemoveConstraints(void) { tet_infoline(" UtcDaliActorRemoveConstraints"); diff --git a/dali/devel-api/actors/actor-devel.h b/dali/devel-api/actors/actor-devel.h index 88fc86b..2bf110d 100755 --- a/dali/devel-api/actors/actor-devel.h +++ b/dali/devel-api/actors/actor-devel.h @@ -150,6 +150,17 @@ enum Type * The actual touched size is actor.width + touchAreaOffset.right - touchAreaOffset.left and actor.height + touchAreaOffset.bottom - touchAreaOffset.top */ TOUCH_AREA_OFFSET, + + /** + * @brief Sets whether this view can focus by touch. If user sets this to true, the actor will be focused when user touch it. + * @code + * Actor actor = Actor::New(); + * actor.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true); // whether the view can have focus or not with keyboard navigation. + * actor.SetProperty(DevelActor::Property::TOUCH_FOCUSABLE, true); // Whether the user can focus by touch, user can set focus by touching the actor. + * @endcode + * @details Name "touchFocusable", type Property::BOOLEAN. + */ + TOUCH_FOCUSABLE }; } // namespace Property diff --git a/dali/internal/event/actors/actor-impl.cpp b/dali/internal/event/actors/actor-impl.cpp index 5fb9d4f..fb4ff42 100644 --- a/dali/internal/event/actors/actor-impl.cpp +++ b/dali/internal/event/actors/actor-impl.cpp @@ -141,6 +141,7 @@ DALI_PROPERTY("siblingOrder", INTEGER, true, false, false, Dali::DevelActor::Pro DALI_PROPERTY("updateSizeHint", VECTOR2, true, false, false, Dali::DevelActor::Property::UPDATE_SIZE_HINT) DALI_PROPERTY("captureAllTouchAfterStart", BOOLEAN, true, false, false, Dali::DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START) DALI_PROPERTY("touchAreaOffset", RECTANGLE, true, false, false, Dali::DevelActor::Property::TOUCH_AREA_OFFSET) +DALI_PROPERTY("touchFocusable", BOOLEAN, true, false, false, Dali::DevelActor::Property::TOUCH_FOCUSABLE) DALI_PROPERTY_TABLE_END(DEFAULT_ACTOR_PROPERTY_START_INDEX, ActorDefaultProperties) // Signals @@ -1448,6 +1449,7 @@ Actor::Actor(DerivedType derivedType, const SceneGraph::Node& node) mSensitive(true), mLeaveRequired(false), mKeyboardFocusable(false), + mTouchFocusable(false), mOnSceneSignalled(false), mInsideOnSizeSet(false), mInheritPosition(true), diff --git a/dali/internal/event/actors/actor-impl.h b/dali/internal/event/actors/actor-impl.h index bf89164..b88c166 100644 --- a/dali/internal/event/actors/actor-impl.h +++ b/dali/internal/event/actors/actor-impl.h @@ -1326,6 +1326,24 @@ public: } /** + * Set whether this view can focus by touch. + * @param[in] focusable focuable by touch. + */ + void SetTouchFocusable(bool focusable) + { + mTouchFocusable = focusable; + } + + /** + * This returns whether this actor can focus by touch. + * @return true if this actor can focus by touch. + */ + bool IsTouchFocusable() const + { + return mTouchFocusable; + } + + /** * Query whether the application or derived actor type requires intercept touch events. * @return True if intercept touch events are required. */ @@ -2051,6 +2069,7 @@ protected: bool mSensitive : 1; ///< Whether the actor emits touch event signals 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 mTouchFocusable : 1; ///< Whether the actor should be focusable by touch bool mOnSceneSignalled : 1; ///< Set to true before OnSceneConnection signal is emitted, and false before OnSceneDisconnection bool mInsideOnSizeSet : 1; ///< Whether we are inside OnSizeSet bool mInheritPosition : 1; ///< Cached: Whether the parent's position should be inherited. diff --git a/dali/internal/event/actors/actor-property-handler.cpp b/dali/internal/event/actors/actor-property-handler.cpp index ca44caf..ce4cc93 100644 --- a/dali/internal/event/actors/actor-property-handler.cpp +++ b/dali/internal/event/actors/actor-property-handler.cpp @@ -581,6 +581,16 @@ void Actor::PropertyHandler::SetDefaultProperty(Internal::Actor& actor, Property break; } + case Dali::DevelActor::Property::TOUCH_FOCUSABLE: + { + bool value = false; + if(property.Get(value)) + { + actor.SetTouchFocusable(value); + } + break; + } + default: { // this can happen in the case of a non-animatable default property so just do nothing @@ -1616,6 +1626,12 @@ bool Actor::PropertyHandler::GetCachedPropertyValue(const Internal::Actor& actor break; } + case Dali::DevelActor::Property::TOUCH_FOCUSABLE: + { + value = actor.IsTouchFocusable(); + break; + } + default: { // Must be a scene-graph only property diff --git a/dali/internal/event/events/hit-test-algorithm-impl.cpp b/dali/internal/event/events/hit-test-algorithm-impl.cpp index d47f35d..3f53fa4 100644 --- a/dali/internal/event/events/hit-test-algorithm-impl.cpp +++ b/dali/internal/event/events/hit-test-algorithm-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2021 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. @@ -19,9 +19,6 @@ #include // INTERNAL INCLUDES -#include -#include -#include #include #include #include @@ -31,31 +28,30 @@ #include #include #include +#include +#include +#include namespace Dali { - namespace Internal { - namespace HitTestAlgorithm { - namespace { - struct HitActor { HitActor() - : actor( nullptr ), - distance( std::numeric_limits::max() ), - depth( std::numeric_limits::min() ) + : actor(nullptr), + distance(std::numeric_limits::max()), + depth(std::numeric_limits::min()) { } - Actor *actor; ///< The actor hit (if actor is hit, then this is initialised). + Actor* actor; ///< The actor hit (if actor is hit, then this is initialised). Vector2 hitPosition; ///< Position of hit (only valid if actor valid). - float distance; ///< Distance from ray origin to hit actor. + float distance; ///< Distance from ray origin to hit actor. int32_t depth; ///< Depth index of this actor. }; @@ -69,22 +65,22 @@ struct HitTestFunctionWrapper : public HitTestInterface * * @param[in] func HitTestFunction to call with an Actor handle. */ - HitTestFunctionWrapper( Dali::HitTestAlgorithm::HitTestFunction func ) - : mFunc( func ) + HitTestFunctionWrapper(Dali::HitTestAlgorithm::HitTestFunction func) + : mFunc(func) { } - bool IsActorHittable( Actor* actor ) override + bool IsActorHittable(Actor* actor) override { - return mFunc( Dali::Actor( actor ), Dali::HitTestAlgorithm::CHECK_ACTOR ); + return mFunc(Dali::Actor(actor), Dali::HitTestAlgorithm::CHECK_ACTOR); } - bool DescendActorHierarchy( Actor* actor ) override + bool DescendActorHierarchy(Actor* actor) override { - return mFunc( Dali::Actor( actor ), Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE ); + return mFunc(Dali::Actor(actor), Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE); } - bool DoesLayerConsumeHit( Layer* layer ) override + bool DoesLayerConsumeHit(Layer* layer) override { // Layer::IsTouchConsumed() focuses on touch only. Here we are a wrapper for the public-api // where the caller may want to check for something completely different. @@ -101,19 +97,19 @@ struct HitTestFunctionWrapper : public HitTestInterface */ struct ActorTouchableCheck : public HitTestInterface { - bool IsActorHittable( Actor* actor ) override + bool IsActorHittable(Actor* actor) override { - return actor->GetTouchRequired() && // Does the Application or derived actor type require a touch event? - actor->IsHittable(); // Is actor sensitive, visible and on the scene? + return (actor->GetTouchRequired() || actor->IsTouchFocusable()) && // Does the Application or derived actor type require a touch event? or focusable by touch? + actor->IsHittable(); // Is actor sensitive, visible and on the scene? } - bool DescendActorHierarchy( Actor* actor ) override + bool DescendActorHierarchy(Actor* actor) override { 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 ) override + bool DoesLayerConsumeHit(Layer* layer) override { return layer->IsTouchConsumed(); } @@ -122,16 +118,16 @@ struct ActorTouchableCheck : public HitTestInterface /** * Check to see if the actor we're about to hit test is exclusively owned by another rendertask? */ -bool IsActorExclusiveToAnotherRenderTask( const Actor& actor, - const RenderTask& renderTask, - const RenderTaskList::ExclusivesContainer& exclusives ) +bool IsActorExclusiveToAnotherRenderTask(const Actor& actor, + const RenderTask& renderTask, + const RenderTaskList::ExclusivesContainer& exclusives) { - if( exclusives.size() ) + if(exclusives.size()) { - for( const auto& exclusive : exclusives ) + for(const auto& exclusive : exclusives) { - if( ( exclusive.renderTaskPtr != &renderTask ) && ( exclusive.actor.GetActor() == &actor ) ) + if((exclusive.renderTaskPtr != &renderTask) && (exclusive.actor.GetActor() == &actor)) { return true; } @@ -149,23 +145,23 @@ bool IsActorExclusiveToAnotherRenderTask( const Actor& actor, * - When comparing against renderable parents, if Actor is the same distance * or closer than it's renderable parent, then it takes priority. */ -HitActor HitTestWithinLayer( Actor& actor, - const RenderTask& renderTask, - const RenderTaskList::ExclusivesContainer& exclusives, - const Vector4& rayOrigin, - const Vector4& rayDir, - float& nearClippingPlane, - float& farClippingPlane, - HitTestInterface& hitCheck, - bool& overlayHit, - bool layerIs3d, - uint32_t clippingDepth, - uint32_t clippingBitPlaneMask, - const RayTest& rayTest ) +HitActor HitTestWithinLayer(Actor& actor, + const RenderTask& renderTask, + const RenderTaskList::ExclusivesContainer& exclusives, + const Vector4& rayOrigin, + const Vector4& rayDir, + float& nearClippingPlane, + float& farClippingPlane, + HitTestInterface& hitCheck, + bool& overlayHit, + bool layerIs3d, + uint32_t clippingDepth, + uint32_t clippingBitPlaneMask, + const RayTest& rayTest) { HitActor hit; - if( IsActorExclusiveToAnotherRenderTask( actor, renderTask, exclusives ) ) + if(IsActorExclusiveToAnotherRenderTask(actor, renderTask, exclusives)) { return hit; } @@ -175,43 +171,43 @@ HitActor HitTestWithinLayer( Actor& actor, // This is used later to ensure all nested clipped children have hit // all clipping actors also for them to be counted as hit. uint32_t newClippingDepth = clippingDepth; - bool clippingActor = actor.GetClippingMode() != ClippingMode::DISABLED; - if( clippingActor ) + bool clippingActor = actor.GetClippingMode() != ClippingMode::DISABLED; + if(clippingActor) { ++newClippingDepth; } // If we are a clipping actor or hittable... - if( clippingActor || hitCheck.IsActorHittable( &actor ) ) + if(clippingActor || hitCheck.IsActorHittable(&actor)) { - Vector3 size( actor.GetCurrentSize() ); + Vector3 size(actor.GetCurrentSize()); // Ensure the actor has a valid size. // If so, perform a quick ray sphere test to see if our ray is close to the actor. - if( size.x > 0.0f && size.y > 0.0f && rayTest.SphereTest( actor, rayOrigin, rayDir ) ) + if(size.x > 0.0f && size.y > 0.0f && rayTest.SphereTest(actor, rayOrigin, rayDir)) { Vector2 hitPointLocal; - float distance; + float distance; // Finally, perform a more accurate ray test to see if our ray actually hits the actor. - if( rayTest.ActorTest( actor, rayOrigin, rayDir, hitPointLocal, distance ) ) + if(rayTest.ActorTest(actor, rayOrigin, rayDir, hitPointLocal, distance)) { - if( distance >= nearClippingPlane && distance <= farClippingPlane ) + if(distance >= nearClippingPlane && distance <= farClippingPlane) { // If the hit has happened on a clipping actor, then add this clipping depth to the mask of hit clipping depths. // This mask shows all the actors that have been hit at different clipping depths. - if( clippingActor ) + if(clippingActor) { clippingBitPlaneMask |= 1u << clippingDepth; } - if( overlayHit && !actor.IsOverlay() ) + if(overlayHit && !actor.IsOverlay()) { // If we have already hit an overlay and current actor is not an overlay ignore current actor. } else { - if( actor.IsOverlay() ) + if(actor.IsOverlay()) { overlayHit = true; } @@ -223,7 +219,7 @@ HitActor HitTestWithinLayer( Actor& actor, // Check if we are performing clipping. IE. if any actors so far have clipping enabled - not necessarily this one. // We can do this by checking the clipping depth has a value 1 or above. - if( newClippingDepth >= 1u ) + if(newClippingDepth >= 1u) { // Now for us to count this actor as hit, we must have also hit // all CLIPPING actors up to this point in the hierarchy as well. @@ -232,31 +228,31 @@ HitActor HitTestWithinLayer( Actor& actor, // EG. a depth of 4 (10000 binary) = a mask of 1111 binary. // This allows us a fast way of comparing all bits are set up to this depth. // Note: If the current Actor has clipping, that is included in the depth mask too. - uint32_t clippingDepthMask = ( 1u << newClippingDepth ) - 1u; + uint32_t clippingDepthMask = (1u << newClippingDepth) - 1u; // The two masks must be equal to be a hit, as we are already assuming a hit // (for non-clipping mode) then they must be not-equal to disqualify the hit. - if( clippingBitPlaneMask != clippingDepthMask ) + if(clippingBitPlaneMask != clippingDepthMask) { haveHitActor = false; } } - if( haveHitActor ) + if(haveHitActor) { - hit.actor = &actor; + hit.actor = &actor; hit.hitPosition = hitPointLocal; - hit.distance = distance; - hit.depth = actor.GetSortingDepth() ; + hit.distance = distance; + hit.depth = actor.GetSortingDepth(); - if( actor.GetRendererCount() > 0 ) + if(actor.GetRendererCount() > 0) { //Get renderer with maximum depth - int rendererMaxDepth(actor.GetRendererAt( 0 ).Get()->GetDepthIndex()); - for( uint32_t i(1); i < actor.GetRendererCount(); ++i ) + int rendererMaxDepth(actor.GetRendererAt(0).Get()->GetDepthIndex()); + for(uint32_t i(1); i < actor.GetRendererCount(); ++i) { - int depth = actor.GetRendererAt( i ).Get()->GetDepthIndex(); - if( depth > rendererMaxDepth ) + int depth = actor.GetRendererAt(i).Get()->GetDepthIndex(); + if(depth > rendererMaxDepth) { rendererMaxDepth = depth; } @@ -272,34 +268,34 @@ HitActor HitTestWithinLayer( Actor& actor, // Find a child hit, until we run out of actors in the current layer. HitActor childHit; - if( actor.GetChildCount() > 0 ) + if(actor.GetChildCount() > 0) { - childHit.distance = std::numeric_limits::max(); - childHit.depth = std::numeric_limits::min(); + childHit.distance = std::numeric_limits::max(); + childHit.depth = std::numeric_limits::min(); ActorContainer& children = actor.GetChildrenInternal(); // Hit test ALL children and calculate their distance. bool parentIsRenderable = actor.IsRenderable(); - for( ActorIter iter = children.begin(), endIter = children.end(); iter != endIter; ++iter ) + for(ActorIter iter = children.begin(), endIter = children.end(); iter != endIter; ++iter) { // Descend tree only if... - if ( !( *iter )->IsLayer() && // Child is NOT a layer, hit testing current layer only - ( hitCheck.DescendActorHierarchy( ( *iter ).Get() ) ) ) // We can descend into child hierarchy + if(!(*iter)->IsLayer() && // Child is NOT a layer, hit testing current layer only + (hitCheck.DescendActorHierarchy((*iter).Get()))) // We can descend into child hierarchy { - HitActor currentHit( HitTestWithinLayer( ( *iter->Get() ), - renderTask, - exclusives, - rayOrigin, - rayDir, - nearClippingPlane, - farClippingPlane, - hitCheck, - overlayHit, - layerIs3d, - newClippingDepth, - clippingBitPlaneMask, - rayTest ) ); + HitActor currentHit(HitTestWithinLayer((*iter->Get()), + renderTask, + exclusives, + rayOrigin, + rayDir, + nearClippingPlane, + farClippingPlane, + hitCheck, + overlayHit, + layerIs3d, + newClippingDepth, + clippingBitPlaneMask, + rayTest)); // Make sure the set hit actor is actually hittable. This is usually required when we have some // clipping as we need to hit-test all actors as we descend the tree regardless of whether they @@ -310,12 +306,12 @@ HitActor HitTestWithinLayer( Actor& actor, } bool updateChildHit = false; - if( currentHit.distance >= 0.0f ) + if(currentHit.distance >= 0.0f) { - if( layerIs3d ) + if(layerIs3d) { - updateChildHit = ( ( currentHit.depth > childHit.depth ) || - ( ( currentHit.depth == childHit.depth ) && ( currentHit.distance < childHit.distance ) ) ); + updateChildHit = ((currentHit.depth > childHit.depth) || + ((currentHit.depth == childHit.depth) && (currentHit.distance < childHit.distance))); } else { @@ -323,10 +319,10 @@ HitActor HitTestWithinLayer( Actor& actor, } } - if( updateChildHit ) + if(updateChildHit) { - if( !parentIsRenderable || currentHit.depth > hit.depth || - ( layerIs3d && ( currentHit.depth == hit.depth && currentHit.distance < hit.distance )) ) + if(!parentIsRenderable || currentHit.depth > hit.depth || + (layerIs3d && (currentHit.depth == hit.depth && currentHit.distance < hit.distance))) { childHit = currentHit; } @@ -335,23 +331,23 @@ HitActor HitTestWithinLayer( Actor& actor, } } - return ( childHit.actor ) ? childHit : hit; + return (childHit.actor) ? childHit : hit; } /** * Return true if actor is sourceActor or a descendent of sourceActor */ -bool IsWithinSourceActors( const Actor& sourceActor, const Actor& actor ) +bool IsWithinSourceActors(const Actor& sourceActor, const Actor& actor) { - if ( &sourceActor == &actor ) + if(&sourceActor == &actor) { return true; } Actor* parent = actor.GetParent(); - if ( parent ) + if(parent) { - return IsWithinSourceActors( sourceActor, *parent ); + return IsWithinSourceActors(sourceActor, *parent); } // Not within source actors @@ -361,32 +357,32 @@ bool IsWithinSourceActors( const Actor& sourceActor, const Actor& actor ) /** * Returns true if the layer and all of the layer's parents are visible and sensitive. */ -inline bool IsActuallyHittable( Layer& layer, const Vector2& screenCoordinates, const Vector2& stageSize, HitTestInterface& hitCheck ) +inline bool IsActuallyHittable(Layer& layer, const Vector2& screenCoordinates, const Vector2& stageSize, HitTestInterface& hitCheck) { - bool hittable( true ); + bool hittable(true); - if( layer.IsClipping() ) + if(layer.IsClipping()) { ClippingBox box = layer.GetClippingBox(); - if( screenCoordinates.x < static_cast( box.x )|| - screenCoordinates.x > static_cast( box.x + box.width )|| - screenCoordinates.y < stageSize.y - static_cast( box.y + box.height ) || - screenCoordinates.y > stageSize.y - static_cast( box.y ) ) + if(screenCoordinates.x < static_cast(box.x) || + screenCoordinates.x > static_cast(box.x + box.width) || + screenCoordinates.y < stageSize.y - static_cast(box.y + box.height) || + screenCoordinates.y > stageSize.y - static_cast(box.y)) { // Not touchable if clipping is enabled in the layer and the screen coordinate is outside the clip region. hittable = false; } } - if( hittable ) + if(hittable) { - Actor* actor( &layer ); + Actor* actor(&layer); // Ensure that we can descend into the layer's (or any of its parent's) hierarchy. - while( actor && hittable ) + while(actor && hittable) { - if( ! hitCheck.DescendActorHierarchy( actor ) ) + if(!hitCheck.DescendActorHierarchy(actor)) { hittable = false; break; @@ -401,112 +397,112 @@ inline bool IsActuallyHittable( Layer& layer, const Vector2& screenCoordinates, /** * Gets the near and far clipping planes of the camera from which the scene is viewed in the render task. */ -void GetCameraClippingPlane( RenderTask& renderTask, float& nearClippingPlane, float& farClippingPlane ) +void GetCameraClippingPlane(RenderTask& renderTask, float& nearClippingPlane, float& farClippingPlane) { CameraActor* cameraActor = renderTask.GetCameraActor(); - nearClippingPlane = cameraActor->GetNearClippingPlane(); - farClippingPlane = cameraActor->GetFarClippingPlane(); + nearClippingPlane = cameraActor->GetNearClippingPlane(); + farClippingPlane = cameraActor->GetFarClippingPlane(); } /** * Hit test a RenderTask */ -bool HitTestRenderTask( const RenderTaskList::ExclusivesContainer& exclusives, - const Vector2& sceneSize, - LayerList& layers, - RenderTask& renderTask, - Vector2 screenCoordinates, - Results& results, - HitTestInterface& hitCheck, - const RayTest& rayTest ) +bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives, + const Vector2& sceneSize, + LayerList& layers, + RenderTask& renderTask, + Vector2 screenCoordinates, + Results& results, + HitTestInterface& hitCheck, + const RayTest& rayTest) { - if ( renderTask.IsHittable( screenCoordinates ) ) + if(renderTask.IsHittable(screenCoordinates)) { Viewport viewport; - renderTask.GetViewport( viewport ); - if( screenCoordinates.x < static_cast( viewport.x ) || - screenCoordinates.x > static_cast( viewport.x + viewport.width ) || - screenCoordinates.y < static_cast( viewport.y ) || - screenCoordinates.y > static_cast( viewport.y + viewport.height ) ) + renderTask.GetViewport(viewport); + if(screenCoordinates.x < static_cast(viewport.x) || + screenCoordinates.x > static_cast(viewport.x + viewport.width) || + screenCoordinates.y < static_cast(viewport.y) || + screenCoordinates.y > static_cast(viewport.y + viewport.height)) { // The screen coordinate is outside the viewport of render task. The viewport clips all layers. return false; } float nearClippingPlane, farClippingPlane; - GetCameraClippingPlane( renderTask, nearClippingPlane, farClippingPlane ); + GetCameraClippingPlane(renderTask, nearClippingPlane, farClippingPlane); // Determine the layer depth of the source actor - Actor* sourceActor( renderTask.GetSourceActor() ); - if( sourceActor ) + Actor* sourceActor(renderTask.GetSourceActor()); + if(sourceActor) { - Dali::Layer layer( sourceActor->GetLayer() ); - if( layer ) + Dali::Layer layer(sourceActor->GetLayer()); + if(layer) { - const uint32_t sourceActorDepth( layer.GetProperty< bool >( Dali::Layer::Property::DEPTH ) ); - - CameraActor* cameraActor = renderTask.GetCameraActor(); - bool pickingPossible = cameraActor->BuildPickingRay( - screenCoordinates, - viewport, - results.rayOrigin, - results.rayDirection ); - if( !pickingPossible ) + const uint32_t sourceActorDepth(layer.GetProperty(Dali::Layer::Property::DEPTH)); + + CameraActor* cameraActor = renderTask.GetCameraActor(); + bool pickingPossible = cameraActor->BuildPickingRay( + screenCoordinates, + viewport, + results.rayOrigin, + results.rayDirection); + if(!pickingPossible) { return false; } // Hit test starting with the top layer, working towards the bottom layer. HitActor hit; - bool overlayHit = false; - bool layerConsumesHit = false; + bool overlayHit = false; + bool layerConsumesHit = false; - for( int32_t i = layers.GetLayerCount() - 1; i >= 0 && !( hit.actor ); --i ) + for(int32_t i = layers.GetLayerCount() - 1; i >= 0 && !(hit.actor); --i) { - Layer* layer( layers.GetLayer( i ) ); + Layer* layer(layers.GetLayer(i)); overlayHit = false; // Ensure layer is touchable (also checks whether ancestors are also touchable) - if( IsActuallyHittable( *layer, screenCoordinates, sceneSize, hitCheck ) ) + if(IsActuallyHittable(*layer, screenCoordinates, sceneSize, hitCheck)) { // Always hit-test the source actor; otherwise test whether the layer is below the source actor in the hierarchy - if( sourceActorDepth == static_cast( i ) ) + if(sourceActorDepth == static_cast(i)) { // Recursively hit test the source actor & children, without crossing into other layers. - hit = HitTestWithinLayer( *sourceActor, - renderTask, - exclusives, - results.rayOrigin, - results.rayDirection, - nearClippingPlane, - farClippingPlane, - hitCheck, - overlayHit, - layer->GetBehavior() == Dali::Layer::LAYER_3D, - 0u, - 0u, - rayTest ); + hit = HitTestWithinLayer(*sourceActor, + renderTask, + exclusives, + results.rayOrigin, + results.rayDirection, + nearClippingPlane, + farClippingPlane, + hitCheck, + overlayHit, + layer->GetBehavior() == Dali::Layer::LAYER_3D, + 0u, + 0u, + rayTest); } - else if( IsWithinSourceActors( *sourceActor, *layer ) ) + else if(IsWithinSourceActors(*sourceActor, *layer)) { // Recursively hit test all the actors, without crossing into other layers. - hit = HitTestWithinLayer( *layer, - renderTask, - exclusives, - results.rayOrigin, - results.rayDirection, - nearClippingPlane, - farClippingPlane, - hitCheck, - overlayHit, - layer->GetBehavior() == Dali::Layer::LAYER_3D, - 0u, - 0u, - rayTest ); + hit = HitTestWithinLayer(*layer, + renderTask, + exclusives, + results.rayOrigin, + results.rayDirection, + nearClippingPlane, + farClippingPlane, + hitCheck, + overlayHit, + layer->GetBehavior() == Dali::Layer::LAYER_3D, + 0u, + 0u, + rayTest); } // If this layer is set to consume the hit, then do not check any layers behind it - if( hitCheck.DoesLayerConsumeHit( layer ) ) + if(hitCheck.DoesLayerConsumeHit(layer)) { layerConsumesHit = true; break; @@ -514,16 +510,16 @@ bool HitTestRenderTask( const RenderTaskList::ExclusivesContainer& exclusives, } } - if( hit.actor ) + if(hit.actor) { - results.renderTask = RenderTaskPtr( &renderTask ); - results.actor = Dali::Actor( hit.actor ); + results.renderTask = RenderTaskPtr(&renderTask); + results.actor = Dali::Actor(hit.actor); results.actorCoordinates = hit.hitPosition; return true; // Success } - if( layerConsumesHit ) + if(layerConsumesHit) { return true; // Also success if layer is consuming the hit } @@ -544,30 +540,30 @@ bool HitTestRenderTask( const RenderTaskList::ExclusivesContainer& exclusives, * @param[in] onScreen True to test on-screen, false to test off-screen * @return True if we have a hit, false otherwise */ -bool HitTestRenderTaskList( const Vector2& sceneSize, - LayerList& layers, - RenderTaskList& taskList, - const Vector2& screenCoordinates, - Results& results, - HitTestInterface& hitCheck, - bool onScreen ) +bool HitTestRenderTaskList(const Vector2& sceneSize, + LayerList& layers, + RenderTaskList& taskList, + const Vector2& screenCoordinates, + Results& results, + HitTestInterface& hitCheck, + bool onScreen) { - RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks(); - RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend(); - const auto& exclusives = taskList.GetExclusivesList(); - RayTest rayTest; + RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks(); + RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend(); + const auto& exclusives = taskList.GetExclusivesList(); + RayTest rayTest; - for( RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter ) + for(RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter) { - RenderTask& renderTask = *iter->Get(); - const bool isOffscreenRenderTask = renderTask.GetFrameBuffer(); - if( (onScreen && isOffscreenRenderTask) || (!onScreen && !isOffscreenRenderTask) ) + RenderTask& renderTask = *iter->Get(); + const bool isOffscreenRenderTask = renderTask.GetFrameBuffer(); + if((onScreen && isOffscreenRenderTask) || (!onScreen && !isOffscreenRenderTask)) { // Skip to next task continue; } - if( HitTestRenderTask( exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck, rayTest ) ) + if(HitTestRenderTask(exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck, rayTest)) { // Return true when an actor is hit (or layer in our render-task consumes the hit) return true; // don't bother checking off screen tasks @@ -588,19 +584,19 @@ bool HitTestRenderTaskList( const Vector2& sceneSize, * @param[in] onScreen True to test on-screen, false to test off-screen * @return True if we have a hit, false otherwise */ -bool HitTestForEachRenderTask( const Vector2& sceneSize, - LayerList& layers, - RenderTaskList& taskList, - const Vector2& screenCoordinates, - Results& results, - HitTestInterface& hitCheck ) +bool HitTestForEachRenderTask(const Vector2& sceneSize, + LayerList& layers, + RenderTaskList& taskList, + const Vector2& screenCoordinates, + Results& results, + HitTestInterface& hitCheck) { bool result = false; // Check on-screen tasks before off-screen ones. // Hit test order should be reverse of draw order (see ProcessRenderTasks() where off-screen tasks are drawn first). - if( HitTestRenderTaskList( sceneSize, layers, taskList, screenCoordinates, results, hitCheck, true ) || - HitTestRenderTaskList( sceneSize, layers, taskList, screenCoordinates, results, hitCheck, false ) ) + if(HitTestRenderTaskList(sceneSize, layers, taskList, screenCoordinates, results, hitCheck, true) || + HitTestRenderTaskList(sceneSize, layers, taskList, screenCoordinates, results, hitCheck, false)) { // Found hit. result = true; @@ -613,37 +609,37 @@ bool HitTestForEachRenderTask( const Vector2& sceneSize, HitTestInterface::~HitTestInterface() = default; -bool HitTest( const Vector2& sceneSize, RenderTaskList& taskList, LayerList& layerList, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func ) +bool HitTest(const Vector2& sceneSize, RenderTaskList& taskList, LayerList& layerList, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func) { - bool wasHit( false ); + bool wasHit(false); // Hit-test the regular on-scene actors - Results hitTestResults; - HitTestFunctionWrapper hitTestFunctionWrapper( func ); - if( HitTestForEachRenderTask( sceneSize, layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) ) + Results hitTestResults; + HitTestFunctionWrapper hitTestFunctionWrapper(func); + if(HitTestForEachRenderTask(sceneSize, layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper)) { - results.actor = hitTestResults.actor; + results.actor = hitTestResults.actor; results.actorCoordinates = hitTestResults.actorCoordinates; - wasHit = true; + wasHit = true; } return wasHit; } -bool HitTest( const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface ) +bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface) { - bool wasHit( false ); + bool wasHit(false); // Hit-test the regular on-scene actors - if( !wasHit ) + if(!wasHit) { - wasHit = HitTestForEachRenderTask( sceneSize, layerList, renderTaskList, screenCoordinates, results, hitTestInterface ); + wasHit = HitTestForEachRenderTask(sceneSize, layerList, renderTaskList, screenCoordinates, results, hitTestInterface); } return wasHit; } -bool HitTest( const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results ) +bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results) { ActorTouchableCheck actorTouchableCheck; - return HitTest( sceneSize, renderTaskList, layerList, screenCoordinates, results, actorTouchableCheck ); + return HitTest(sceneSize, renderTaskList, layerList, screenCoordinates, results, actorTouchableCheck); } } // namespace HitTestAlgorithm -- 2.7.4