2 * Copyright (c) 2019 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/common/scene-impl.h>
26 #include <dali/internal/event/events/hit-test-algorithm-impl.h>
27 #include <dali/internal/event/events/actor-gesture-data.h>
28 #include <dali/internal/event/render-tasks/render-task-impl.h>
40 * Functor to check whether an actor requires a particular gesture or not
42 struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
44 GestureHitTestCheck( DevelGesture::Type type )
49 GestureHitTestCheck( Gesture::Type type )
50 : GestureHitTestCheck( static_cast< DevelGesture::Type >( type ) )
54 virtual bool IsActorHittable( Actor* actor )
56 return actor->IsGestureRequred( mType ) && // Does the Application or derived actor type require the gesture?
57 actor->IsHittable(); // Is actor sensitive, visible and on the scene?
60 virtual bool DescendActorHierarchy( Actor* actor )
62 return actor->IsVisible() && // Actor is visible, if not visible then none of its children are visible.
63 actor->IsSensitive(); // Actor is sensitive, if insensitive none of its children should be hittable either.
66 virtual bool DoesLayerConsumeHit( Layer* layer )
68 return layer->IsTouchConsumed();
71 DevelGesture::Type mType;
74 } // unnamed namespace
77 GestureProcessor::GestureProcessor( DevelGesture::Type type )
78 : mGestureRecognizer(),
79 mNeedsUpdate( false ),
81 mCurrentGesturedActor( nullptr ),
82 mGesturedActorDisconnected( false )
86 GestureProcessor::GestureProcessor( Gesture::Type type )
87 : GestureProcessor( static_cast< DevelGesture::Type >( type ) )
92 GestureProcessor::~GestureProcessor()
97 void GestureProcessor::ProcessTouch( Scene& scene, const Integration::TouchEvent& event )
99 if( mGestureRecognizer )
101 mGestureRecognizer->SendEvent(scene, event);
105 void GestureProcessor::GetGesturedActor( Actor*& actor, GestureDetectorContainer& gestureDetectors )
109 // We may be checking a parent so ensure the parent requires this gesture (and do not unintentionally create the gesture data for the parent)
110 if ( actor->IsGestureRequred( mType ) )
112 // Retrieve the actor's detectors and check if they satisfy current gesture
113 const GestureDetectorContainer& connectedDetectors( actor->GetGestureData().GetGestureDetectorContainer( mType ) );
114 const GestureDetectorContainer::const_iterator endIter( connectedDetectors.end() );
115 for ( GestureDetectorContainer::const_iterator iter = connectedDetectors.begin(); iter != endIter; ++iter )
117 GestureDetector* current(*iter);
119 // Check deriving class for whether the current gesture satisfies the gesture detector's parameters.
120 if ( CheckGestureDetector( current, actor ) )
122 gestureDetectors.push_back(current);
126 // The hit actor or one of the parents is a gestured actor, break out.
127 if ( !gestureDetectors.empty() )
133 // No match, we should now check the hit actor's parent.
134 actor = actor->GetParent();
138 void GestureProcessor::ProcessAndEmit( HitTestAlgorithm::Results& hitTestResults )
140 if ( hitTestResults.actor )
142 Actor* hitTestActor( &GetImplementation( hitTestResults.actor ) );
143 Actor* actor( hitTestActor );
147 GestureDetectorContainer gestureDetectors;
148 GetGesturedActor( actor, gestureDetectors );
150 if ( actor && !gestureDetectors.empty() )
152 // We have a match but check if the hit point is within the gestured actor's bounds.
153 // If it is not then continue up the actor hierarchy.
155 if ( actor == hitTestActor )
157 // Our gesture detector's attached actor WAS the hit actor so we can can emit the signal.
158 EmitGestureSignal( actor, gestureDetectors, hitTestResults.actorCoordinates );
159 break; // We have found AND emitted a signal on the gestured actor, break out.
163 if ( actor->IsHittable() )
165 const Vector3 size( actor->GetCurrentSize() );
167 if ( ( size.x > 0.0f ) && ( size.y > 0.0f ) )
169 // Ensure tap is within the actor's area
170 if ( actor->RaySphereTest( hitTestResults.rayOrigin, hitTestResults.rayDirection ) ) // Quick check
172 Vector2 hitPointLocal;
173 float distance( 0.0f );
174 if( actor->RayActorTest( hitTestResults.rayOrigin, hitTestResults.rayDirection, hitPointLocal, distance ) )
176 // One of the parents was the gestured actor so we can emit the signal for that actor.
177 EmitGestureSignal( actor, gestureDetectors, hitPointLocal );
178 break; // We have found AND emitted a signal on the gestured actor, break out.
186 // Continue up hierarchy to see if any of the parents require this gesture.
189 actor = actor->GetParent();
195 bool GestureProcessor::HitTest( Scene& scene, Vector2 screenCoordinates, HitTestAlgorithm::Results& hitTestResults )
197 GestureHitTestCheck hitCheck( mType );
198 HitTestAlgorithm::HitTest( scene.GetSize(), scene.GetRenderTaskList(), scene.GetLayerList(), screenCoordinates, hitTestResults, hitCheck );
199 return hitTestResults.renderTask && hitTestResults.actor;
202 void GestureProcessor::SetActor( Actor* actor )
204 if ( actor && actor != mCurrentGesturedActor )
208 mCurrentGesturedActor = actor;
209 mCurrentGesturedActor->AddObserver( *this );
211 mGesturedActorDisconnected = false;
214 void GestureProcessor::ResetActor()
216 if ( mCurrentGesturedActor )
218 mCurrentGesturedActor->RemoveObserver( *this );
219 mCurrentGesturedActor = nullptr;
220 mGesturedActorDisconnected = false;
224 Actor* GestureProcessor::GetCurrentGesturedActor()
226 return mGesturedActorDisconnected ? nullptr : mCurrentGesturedActor;
229 void GestureProcessor::SceneObjectRemoved(Object& object)
231 if ( mCurrentGesturedActor == &object &&
232 !mGesturedActorDisconnected )
234 // Inform deriving classes.
235 OnGesturedActorStageDisconnection();
237 // do not call object.RemoveObserver here, object is currently iterating through observers... you wouldnt want to upset object now would you?
238 mGesturedActorDisconnected = true;
242 void GestureProcessor::ObjectDestroyed(Object& object)
244 if ( mCurrentGesturedActor == &object )
246 // Inform deriving classes.
247 OnGesturedActorStageDisconnection();
249 mCurrentGesturedActor = nullptr;
253 } // namespace Internal