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/actors/layer-impl.h>
25 #include <dali/internal/event/events/hit-test-algorithm-impl.h>
26 #include <dali/internal/event/events/actor-gesture-data.h>
27 #include <dali/internal/event/render-tasks/render-task-impl.h>
39 * Functor to check whether an actor requires a particular gesture or not
41 struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
43 GestureHitTestCheck( Gesture::Type type )
48 virtual bool IsActorHittable( Actor* actor )
50 return actor->IsGestureRequred( mType ) && // Does the Application or derived actor type require the gesture?
51 actor->IsHittable(); // Is actor sensitive, visible and on the scene?
54 virtual bool DescendActorHierarchy( Actor* actor )
56 return actor->IsVisible() && // Actor is visible, if not visible then none of its children are visible.
57 actor->IsSensitive(); // Actor is sensitive, if insensitive none of its children should be hittable either.
60 virtual bool DoesLayerConsumeHit( Layer* layer )
62 return layer->IsTouchConsumed();
68 } // unnamed namespace
71 GestureProcessor::GestureProcessor( Gesture::Type type )
73 mCurrentGesturedActor( NULL ),
74 mGesturedActorDisconnected( false )
78 GestureProcessor::~GestureProcessor()
83 void GestureProcessor::GetGesturedActor( Actor*& actor, GestureDetectorContainer& gestureDetectors, Functor& functor )
87 // We may be checking a parent so ensure the parent requires this gesture (and do not unintentionally create the gesture data for the parent)
88 if ( actor->IsGestureRequred( mType ) )
90 // Retrieve the actor's detectors and check if they satisfy current gesture
91 const GestureDetectorContainer& connectedDetectors( actor->GetGestureData().GetGestureDetectorContainer( mType ) );
92 const GestureDetectorContainer::const_iterator endIter( connectedDetectors.end() );
93 for ( GestureDetectorContainer::const_iterator iter = connectedDetectors.begin(); iter != endIter; ++iter )
95 GestureDetector* current(*iter);
97 // Check whether the gesture detector satisfies the current gesture's parameters.
98 if ( functor( current, actor ) )
100 gestureDetectors.push_back(current);
104 // The hit actor or one of the parents is a gestured actor, break out.
105 if ( !gestureDetectors.empty() )
111 // No match, we should now check the hit actor's parent.
112 actor = actor->GetParent();
116 void GestureProcessor::ProcessAndEmit( HitTestAlgorithm::Results& hitTestResults, Functor& functor )
118 if ( hitTestResults.actor )
120 Actor* hitTestActor( &GetImplementation( hitTestResults.actor ) );
121 Actor* actor( hitTestActor );
125 GestureDetectorContainer gestureDetectors;
126 GetGesturedActor( actor, gestureDetectors, functor );
128 if ( actor && !gestureDetectors.empty() )
130 // We have a match but check if the hit point is within the gestured actor's bounds.
131 // If it is not then continue up the actor hierarchy.
133 if ( actor == hitTestActor )
135 // Our gesture detector's attached actor WAS the hit actor so we can call the emitting functor.
136 functor( actor, gestureDetectors, hitTestResults.actorCoordinates );
137 break; // We have found AND emitted a signal on the gestured actor, break out.
141 if ( actor->IsHittable() )
143 const Vector3 size( actor->GetCurrentSize() );
145 if ( ( size.x > 0.0f ) && ( size.y > 0.0f ) )
147 // Ensure tap is within the actor's area
148 if ( actor->RaySphereTest( hitTestResults.rayOrigin, hitTestResults.rayDirection ) ) // Quick check
150 Vector4 hitPointLocal;
151 float distance( 0.0f );
152 if( actor->RayActorTest( hitTestResults.rayOrigin, hitTestResults.rayDirection, hitPointLocal, distance ) )
154 // One of the hit actor's parents was the gestured actor so call the emitting functor.
155 functor( actor, gestureDetectors, Vector2( hitPointLocal.x, hitPointLocal.y ) );
156 break; // We have found AND emitted a signal on the gestured actor, break out.
164 // Continue up hierarchy to see if any of the parents require this gesture.
167 actor = actor->GetParent();
173 bool GestureProcessor::HitTest(
175 Vector2 screenCoordinates,
176 HitTestAlgorithm::Results& hitTestResults)
178 GestureHitTestCheck hitCheck( mType );
179 HitTestAlgorithm::HitTest( stage, screenCoordinates, hitTestResults, hitCheck );
180 return hitTestResults.renderTask && hitTestResults.actor;
183 void GestureProcessor::SetActor( Actor* actor )
185 if ( actor && actor != mCurrentGesturedActor )
189 mCurrentGesturedActor = actor;
190 mCurrentGesturedActor->AddObserver( *this );
192 mGesturedActorDisconnected = false;
195 void GestureProcessor::ResetActor()
197 if ( mCurrentGesturedActor )
199 mCurrentGesturedActor->RemoveObserver( *this );
200 mCurrentGesturedActor = NULL;
201 mGesturedActorDisconnected = false;
205 Actor* GestureProcessor::GetCurrentGesturedActor()
207 return mGesturedActorDisconnected ? NULL : mCurrentGesturedActor;
210 void GestureProcessor::SceneObjectRemoved(ProxyObject& proxy)
212 if ( mCurrentGesturedActor == &proxy &&
213 !mGesturedActorDisconnected )
215 // Inform deriving classes.
216 OnGesturedActorStageDisconnection();
218 // do not call proxy.RemoveObserver here, proxy is currently iterating through observers... you wouldnt want to upset proxy now would you?
219 mGesturedActorDisconnected = true;
223 void GestureProcessor::ProxyDestroyed(ProxyObject& proxy)
225 if ( mCurrentGesturedActor == &proxy )
227 // Inform deriving classes.
228 OnGesturedActorStageDisconnection();
230 mCurrentGesturedActor = NULL;
234 } // namespace Internal