2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/event/events/gesture-processor.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/internal/event/actors/actor-impl.h>
24 #include <dali/internal/event/render-tasks/render-task-impl.h>
25 #include <dali/internal/event/events/hit-test-algorithm-impl.h>
37 * Functor to check whether an actor requires a particular gesture or not
39 struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
41 GestureHitTestCheck( Gesture::Type type )
46 virtual bool IsActorHittable( Actor* actor )
48 return actor->IsGestureRequred( mType ) && // Does the Application or derived actor type require the gesture?
49 actor->IsHittable(); // Is actor sensitive, visible and on the scene?
52 virtual bool DescendActorHierarchy( Actor* actor )
54 return actor->IsVisible() && // Actor is visible, if not visible then none of its children are visible.
55 actor->IsSensitive(); // Actor is sensitive, if insensitive none of its children should be hittable either.
61 } // unnamed namespace
64 GestureProcessor::GestureProcessor( Gesture::Type type )
66 mCurrentGesturedActor( NULL ),
67 mGesturedActorDisconnected( false )
71 GestureProcessor::~GestureProcessor()
76 void GestureProcessor::GetGesturedActor( Dali::Actor& actor, const GestureDetectorContainer& connectedDetectors, std::vector<GestureDetector*>& gestureDetectors, Functor& functor )
80 Actor* actorImpl( &GetImplementation(actor) );
82 // Check if our hit actor or any of its parents are attached to any registered detector.
83 // Find all detectors that have the actor attached.
84 for ( GestureDetectorContainer::const_iterator iter = connectedDetectors.begin(), endIter = connectedDetectors.end(); iter != endIter; ++iter )
86 GestureDetector* current(*iter);
88 // Check whether the actor is attached to the gesture detector and then call the functor to
89 // check whether the gesture detector satisfies the current gesture's parameters.
90 if ( current->IsAttached( *actorImpl ) && functor( current, actorImpl ) )
92 gestureDetectors.push_back(current);
96 // The hit actor or one of the parents is a gestured actor, break out.
97 if ( !gestureDetectors.empty() )
102 // No match, we should now check the hit actor's parent.
103 actor = actor.GetParent();
107 void GestureProcessor::ProcessAndEmit( const HitTestAlgorithm::Results& hitTestResults, const GestureDetectorContainer& connectedDetectors, Functor& functor )
109 Dali::Actor actor( hitTestResults.actor );
113 std::vector<GestureDetector*> gestureDetectors;
115 GetGesturedActor( actor, connectedDetectors, gestureDetectors, functor );
117 if ( actor && !gestureDetectors.empty() )
119 // We have a match but check if the hit point is within the gestured actor's bounds.
120 // If it is not then continue up the actor hierarchy.
122 if ( actor == hitTestResults.actor )
124 // Our gesture detector's attached actor WAS the hit actor so we can call the emitting functor.
125 functor( actor, gestureDetectors, hitTestResults.actorCoordinates );
126 break; // We have found AND emitted a signal on the gestured actor, break out.
130 if ( GetImplementation(actor).IsHittable() )
132 const Vector3 size( actor.GetCurrentSize() );
134 if ( ( size.x > 0.0f ) && ( size.y > 0.0f ) )
136 // Ensure tap is within the actor's area
137 Actor& actorImpl = GetImplementation(actor);
138 if ( actorImpl.RaySphereTest( hitTestResults.rayOrigin, hitTestResults.rayDirection ) ) // Quick check
140 Vector4 hitPointLocal;
141 float distance( 0.0f );
142 if( actorImpl.RayActorTest( hitTestResults.rayOrigin, hitTestResults.rayDirection, hitPointLocal, distance ) )
144 // One of the hit actor's parents was the gestured actor so call the emitting functor.
145 functor( actor, gestureDetectors, Vector2( hitPointLocal.x, hitPointLocal.y ) );
146 break; // We have found AND emitted a signal on the gestured actor, break out.
154 // Continue up hierarchy to see if any of the parents require this gesture.
157 actor = actor.GetParent();
162 bool GestureProcessor::HitTest(
164 Vector2 screenCoordinates,
165 HitTestAlgorithm::Results& hitTestResults)
167 GestureHitTestCheck hitCheck( mType );
168 HitTestAlgorithm::HitTest( stage, screenCoordinates, hitTestResults, hitCheck );
169 return hitTestResults.renderTask && hitTestResults.actor;
172 void GestureProcessor::SetActor( Dali::Actor actor )
174 if ( actor && actor != mCurrentGesturedActor )
178 mCurrentGesturedActor = &GetImplementation( actor );
179 mCurrentGesturedActor->AddObserver( *this );
181 mGesturedActorDisconnected = false;
184 void GestureProcessor::ResetActor()
186 if ( mCurrentGesturedActor )
188 mCurrentGesturedActor->RemoveObserver( *this );
189 mCurrentGesturedActor = NULL;
190 mGesturedActorDisconnected = false;
194 Actor* GestureProcessor::GetCurrentGesturedActor()
196 return mGesturedActorDisconnected ? NULL : mCurrentGesturedActor;
199 void GestureProcessor::SceneObjectRemoved(ProxyObject& proxy)
201 if ( mCurrentGesturedActor == &proxy &&
202 !mGesturedActorDisconnected )
204 // Inform deriving classes.
205 OnGesturedActorStageDisconnection();
207 // do not call proxy.RemoveObserver here, proxy is currently iterating through observers... you wouldnt want to upset proxy now would you?
208 mGesturedActorDisconnected = true;
212 void GestureProcessor::ProxyDestroyed(ProxyObject& proxy)
214 if ( mCurrentGesturedActor == &proxy )
216 // Inform deriving classes.
217 OnGesturedActorStageDisconnection();
219 mCurrentGesturedActor = NULL;
223 } // namespace Internal