-//
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Flora License, Version 1.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://floralicense.org/license/
-//
-// 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.
-//
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
// CLASS HEADER
#include <dali/internal/event/events/gesture-processor.h>
// INTERNAL INCLUDES
#include <dali/integration-api/debug.h>
#include <dali/internal/event/actors/actor-impl.h>
-#include <dali/internal/event/render-tasks/render-task-impl.h>
+#include <dali/internal/event/actors/layer-impl.h>
+#include <dali/internal/event/common/scene-impl.h>
#include <dali/internal/event/events/hit-test-algorithm-impl.h>
+#include <dali/internal/event/events/actor-gesture-data.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
namespace Dali
{
namespace Internal
{
-GestureProcessor::GestureProcessor()
-: mCurrentGesturedActor( NULL )
+namespace
+{
+
+/**
+ * Functor to check whether an actor requires a particular gesture or not
+ */
+struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
+{
+ GestureHitTestCheck( DevelGesture::Type type )
+ : mType( type )
+ {
+ }
+
+ GestureHitTestCheck( Gesture::Type type )
+ : GestureHitTestCheck( static_cast< DevelGesture::Type >( type ) )
+ {
+ }
+
+ virtual bool IsActorHittable( Actor* actor )
+ {
+ return actor->IsGestureRequred( mType ) && // Does the Application or derived actor type require the gesture?
+ actor->IsHittable(); // Is actor sensitive, visible and on the scene?
+ }
+
+ virtual 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.
+ }
+
+ virtual bool DoesLayerConsumeHit( Layer* layer )
+ {
+ return layer->IsTouchConsumed();
+ }
+
+ DevelGesture::Type mType;
+};
+
+} // unnamed namespace
+
+
+GestureProcessor::GestureProcessor( DevelGesture::Type type )
+: mGestureRecognizer(),
+ mNeedsUpdate( false ),
+ mType( type ),
+ mCurrentGesturedActor( nullptr ),
+ mGesturedActorDisconnected( false )
+{
+}
+
+GestureProcessor::GestureProcessor( Gesture::Type type )
+: GestureProcessor( static_cast< DevelGesture::Type >( type ) )
{
}
+
GestureProcessor::~GestureProcessor()
{
ResetActor();
}
-void GestureProcessor::GetGesturedActor( Dali::Actor& actor, const GestureDetectorContainer& connectedDetectors, std::vector<GestureDetector*>& gestureDetectors, Functor& functor )
+void GestureProcessor::ProcessTouch( Scene& scene, const Integration::TouchEvent& event )
{
- while ( actor )
+ if( mGestureRecognizer )
{
- Actor* actorImpl( &GetImplementation(actor) );
+ mGestureRecognizer->SendEvent(scene, event);
+ }
+}
- // Check if our hit actor or any of its parents are attached to any registered detector.
- // Find all detectors that have the actor attached.
- for ( GestureDetectorContainer::const_iterator iter = connectedDetectors.begin(), endIter = connectedDetectors.end(); iter != endIter; ++iter )
+void GestureProcessor::GetGesturedActor( Actor*& actor, GestureDetectorContainer& gestureDetectors )
+{
+ while ( actor )
+ {
+ // We may be checking a parent so ensure the parent requires this gesture (and do not unintentionally create the gesture data for the parent)
+ if ( actor->IsGestureRequred( mType ) )
{
- GestureDetector* current(*iter);
-
- // Check whether the actor is attached to the gesture detector and then call the functor to
- // check whether the gesture detector satisfies the current gesture's parameters.
- if ( current->IsAttached( *actorImpl ) && functor( current, actorImpl ) )
+ // Retrieve the actor's detectors and check if they satisfy current gesture
+ const GestureDetectorContainer& connectedDetectors( actor->GetGestureData().GetGestureDetectorContainer( mType ) );
+ const GestureDetectorContainer::const_iterator endIter( connectedDetectors.end() );
+ for ( GestureDetectorContainer::const_iterator iter = connectedDetectors.begin(); iter != endIter; ++iter )
{
- gestureDetectors.push_back(current);
+ GestureDetector* current(*iter);
+
+ // Check deriving class for whether the current gesture satisfies the gesture detector's parameters.
+ if ( CheckGestureDetector( current, actor ) )
+ {
+ gestureDetectors.push_back(current);
+ }
}
- }
- // The hit actor or one of the parents is a gestured actor, break out.
- if ( !gestureDetectors.empty() )
- {
- break;
+ // The hit actor or one of the parents is a gestured actor, break out.
+ if ( !gestureDetectors.empty() )
+ {
+ break;
+ }
}
// No match, we should now check the hit actor's parent.
- actor = actor.GetParent();
+ actor = actor->GetParent();
}
}
-void GestureProcessor::ProcessAndEmit( const HitTestAlgorithm::Results& hitTestResults, const GestureDetectorContainer& connectedDetectors, Functor& functor )
+void GestureProcessor::ProcessAndEmit( HitTestAlgorithm::Results& hitTestResults )
{
- Dali::Actor actor( hitTestResults.actor );
-
- while ( actor )
+ if ( hitTestResults.actor )
{
- std::vector<GestureDetector*> gestureDetectors;
+ Actor* hitTestActor( &GetImplementation( hitTestResults.actor ) );
+ Actor* actor( hitTestActor );
- GetGesturedActor( actor, connectedDetectors, gestureDetectors, functor );
-
- if ( actor && !gestureDetectors.empty() )
+ while ( actor )
{
- // We have a match but check if the hit point is within the gestured actor's bounds.
- // If it is not then continue up the actor hierarchy.
+ GestureDetectorContainer gestureDetectors;
+ GetGesturedActor( actor, gestureDetectors );
- if ( actor == hitTestResults.actor )
- {
- // Our gesture detector's attached actor WAS the hit actor so we can call the emitting functor.
- functor( actor, gestureDetectors, hitTestResults.actorCoordinates );
- break; // We have found AND emitted a signal on the gestured actor, break out.
- }
- else
+ if ( actor && !gestureDetectors.empty() )
{
- if ( GetImplementation(actor).IsHittable() )
- {
- const Vector3 size( actor.GetCurrentSize() );
+ // We have a match but check if the hit point is within the gestured actor's bounds.
+ // If it is not then continue up the actor hierarchy.
- if ( ( size.x > 0.0f ) && ( size.y > 0.0f ) )
+ if ( actor == hitTestActor )
+ {
+ // Our gesture detector's attached actor WAS the hit actor so we can can emit the signal.
+ EmitGestureSignal( actor, gestureDetectors, hitTestResults.actorCoordinates );
+ break; // We have found AND emitted a signal on the gestured actor, break out.
+ }
+ else
+ {
+ if ( actor->IsHittable() )
{
- // Ensure tap is within the actor's area
- Actor& actorImpl = GetImplementation(actor);
- if ( actorImpl.RaySphereTest( hitTestResults.rayOrigin, hitTestResults.rayDirection ) ) // Quick check
+ const Vector3 size( actor->GetCurrentSize() );
+
+ if ( ( size.x > 0.0f ) && ( size.y > 0.0f ) )
{
- Vector4 hitPointLocal;
- float distance( 0.0f );
- if( actorImpl.RayActorTest( hitTestResults.rayOrigin, hitTestResults.rayDirection, hitPointLocal, distance ) )
+ // Ensure tap is within the actor's area
+ if ( actor->RaySphereTest( hitTestResults.rayOrigin, hitTestResults.rayDirection ) ) // Quick check
{
- // One of the hit actor's parents was the gestured actor so call the emitting functor.
- functor( actor, gestureDetectors, Vector2( hitPointLocal.x, hitPointLocal.y ) );
- break; // We have found AND emitted a signal on the gestured actor, break out.
+ Vector2 hitPointLocal;
+ float distance( 0.0f );
+ if( actor->RayActorTest( hitTestResults.rayOrigin, hitTestResults.rayDirection, hitPointLocal, distance ) )
+ {
+ // One of the parents was the gestured actor so we can emit the signal for that actor.
+ EmitGestureSignal( actor, gestureDetectors, hitPointLocal );
+ break; // We have found AND emitted a signal on the gestured actor, break out.
+ }
}
}
}
}
}
- }
- // Continue up hierarchy to see if any of the parents require this gesture.
- if ( actor )
- {
- actor = actor.GetParent();
+ // Continue up hierarchy to see if any of the parents require this gesture.
+ if ( actor )
+ {
+ actor = actor->GetParent();
+ }
}
}
}
-bool GestureProcessor::HitTest(
- Stage& stage,
- Vector2 screenCoordinates,
- HitTestAlgorithm::Results& hitTestResults)
+bool GestureProcessor::HitTest( Scene& scene, Vector2 screenCoordinates, HitTestAlgorithm::Results& hitTestResults )
{
- bool hit = false;
-
- HitTestAlgorithm::HitTest( stage, screenCoordinates, hitTestResults );
- if( hitTestResults.renderTask && hitTestResults.actor )
- {
- if( ! GetImplementation( hitTestResults.renderTask ).IsSystemLevel() )
- {
- hit = true;
- }
- else
- {
- DALI_LOG_ERROR( "Gesture not possible in SystemOverlay" );
- }
- }
- return hit;
+ GestureHitTestCheck hitCheck( mType );
+ HitTestAlgorithm::HitTest( scene.GetSize(), scene.GetRenderTaskList(), scene.GetLayerList(), screenCoordinates, hitTestResults, hitCheck );
+ return hitTestResults.renderTask && hitTestResults.actor;
}
-void GestureProcessor::SetActor( Dali::Actor actor )
+void GestureProcessor::SetActor( Actor* actor )
{
if ( actor && actor != mCurrentGesturedActor )
{
ResetActor();
- mCurrentGesturedActor = &GetImplementation( actor );
+ mCurrentGesturedActor = actor;
mCurrentGesturedActor->AddObserver( *this );
}
+ mGesturedActorDisconnected = false;
}
void GestureProcessor::ResetActor()
if ( mCurrentGesturedActor )
{
mCurrentGesturedActor->RemoveObserver( *this );
- mCurrentGesturedActor = NULL;
+ mCurrentGesturedActor = nullptr;
+ mGesturedActorDisconnected = false;
}
}
-void GestureProcessor::SceneObjectRemoved(ProxyObject& proxy)
+Actor* GestureProcessor::GetCurrentGesturedActor()
+{
+ return mGesturedActorDisconnected ? nullptr : mCurrentGesturedActor;
+}
+
+void GestureProcessor::SceneObjectRemoved(Object& object)
{
- if ( mCurrentGesturedActor == &proxy )
+ if ( mCurrentGesturedActor == &object &&
+ !mGesturedActorDisconnected )
{
// Inform deriving classes.
OnGesturedActorStageDisconnection();
- proxy.RemoveObserver( *this );
- mCurrentGesturedActor = NULL;
+ // do not call object.RemoveObserver here, object is currently iterating through observers... you wouldnt want to upset object now would you?
+ mGesturedActorDisconnected = true;
}
}
-void GestureProcessor::ProxyDestroyed(ProxyObject& proxy)
+void GestureProcessor::ObjectDestroyed(Object& object)
{
- if ( mCurrentGesturedActor == &proxy )
+ if ( mCurrentGesturedActor == &object )
{
// Inform deriving classes.
OnGesturedActorStageDisconnection();
- mCurrentGesturedActor = NULL;
+ mCurrentGesturedActor = nullptr;
}
}