Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-core.git] / dali / internal / event / events / gesture-processor.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/events/gesture-processor.h>
20
21 // INTERNAL INCLUDES
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>
29
30 namespace Dali
31 {
32
33 namespace Internal
34 {
35
36 namespace
37 {
38
39 /**
40  * Functor to check whether an actor requires a particular gesture or not
41  */
42 struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
43 {
44   GestureHitTestCheck( DevelGesture::Type type )
45   : mType( type )
46   {
47   }
48
49   GestureHitTestCheck( Gesture::Type type )
50   : GestureHitTestCheck( static_cast< DevelGesture::Type >( type ) )
51   {
52   }
53
54   virtual bool IsActorHittable( Actor* actor )
55   {
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?
58   }
59
60   virtual bool DescendActorHierarchy( Actor* actor )
61   {
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.
64   }
65
66   virtual bool DoesLayerConsumeHit( Layer* layer )
67   {
68     return layer->IsTouchConsumed();
69   }
70
71   DevelGesture::Type mType;
72 };
73
74 } // unnamed namespace
75
76
77 GestureProcessor::GestureProcessor( DevelGesture::Type type )
78 : mGestureRecognizer(),
79   mNeedsUpdate( false ),
80   mType( type ),
81   mCurrentGesturedActor( nullptr ),
82   mGesturedActorDisconnected( false )
83 {
84 }
85
86 GestureProcessor::GestureProcessor( Gesture::Type type )
87 : GestureProcessor( static_cast< DevelGesture::Type >( type ) )
88 {
89 }
90
91
92 GestureProcessor::~GestureProcessor()
93 {
94   ResetActor();
95 }
96
97 void GestureProcessor::ProcessTouch( Scene& scene, const Integration::TouchEvent& event )
98 {
99   if( mGestureRecognizer )
100   {
101     mGestureRecognizer->SendEvent(scene, event);
102   }
103 }
104
105 void GestureProcessor::GetGesturedActor( Actor*& actor, GestureDetectorContainer& gestureDetectors )
106 {
107   while ( actor )
108   {
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 ) )
111     {
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 )
116       {
117         GestureDetector* current(*iter);
118
119         // Check deriving class for whether the current gesture satisfies the gesture detector's parameters.
120         if ( CheckGestureDetector( current, actor ) )
121         {
122           gestureDetectors.push_back(current);
123         }
124       }
125
126       // The hit actor or one of the parents is a gestured actor, break out.
127       if ( !gestureDetectors.empty() )
128       {
129         break;
130       }
131     }
132
133     // No match, we should now check the hit actor's parent.
134     actor = actor->GetParent();
135   }
136 }
137
138 void GestureProcessor::ProcessAndEmit( HitTestAlgorithm::Results& hitTestResults )
139 {
140   if ( hitTestResults.actor )
141   {
142     Actor* hitTestActor( &GetImplementation( hitTestResults.actor ) );
143     Actor* actor( hitTestActor );
144
145     while ( actor )
146     {
147       GestureDetectorContainer gestureDetectors;
148       GetGesturedActor( actor, gestureDetectors );
149
150       if ( actor && !gestureDetectors.empty() )
151       {
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.
154
155         if ( actor == hitTestActor )
156         {
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.
160         }
161         else
162         {
163           if ( actor->IsHittable() )
164           {
165             const Vector3 size( actor->GetCurrentSize() );
166
167             if ( ( size.x > 0.0f ) && ( size.y > 0.0f ) )
168             {
169               // Ensure tap is within the actor's area
170               if ( actor->RaySphereTest( hitTestResults.rayOrigin, hitTestResults.rayDirection ) ) // Quick check
171               {
172                 Vector2 hitPointLocal;
173                 float distance( 0.0f );
174                 if( actor->RayActorTest( hitTestResults.rayOrigin, hitTestResults.rayDirection, hitPointLocal, distance ) )
175                 {
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.
179                 }
180               }
181             }
182           }
183         }
184       }
185
186       // Continue up hierarchy to see if any of the parents require this gesture.
187       if ( actor )
188       {
189         actor = actor->GetParent();
190       }
191     }
192   }
193 }
194
195 bool GestureProcessor::HitTest( Scene& scene, Vector2 screenCoordinates, HitTestAlgorithm::Results& hitTestResults )
196 {
197   GestureHitTestCheck hitCheck( mType );
198   HitTestAlgorithm::HitTest( scene.GetSize(), scene.GetRenderTaskList(), scene.GetLayerList(), screenCoordinates, hitTestResults, hitCheck );
199   return hitTestResults.renderTask && hitTestResults.actor;
200 }
201
202 void GestureProcessor::SetActor( Actor* actor )
203 {
204   if ( actor && actor != mCurrentGesturedActor )
205   {
206     ResetActor();
207
208     mCurrentGesturedActor = actor;
209     mCurrentGesturedActor->AddObserver( *this );
210   }
211   mGesturedActorDisconnected = false;
212 }
213
214 void GestureProcessor::ResetActor()
215 {
216   if ( mCurrentGesturedActor )
217   {
218     mCurrentGesturedActor->RemoveObserver( *this );
219     mCurrentGesturedActor = nullptr;
220     mGesturedActorDisconnected = false;
221   }
222 }
223
224 Actor* GestureProcessor::GetCurrentGesturedActor()
225 {
226   return mGesturedActorDisconnected ? nullptr : mCurrentGesturedActor;
227 }
228
229 void GestureProcessor::SceneObjectRemoved(Object& object)
230 {
231   if ( mCurrentGesturedActor == &object &&
232       !mGesturedActorDisconnected )
233   {
234     // Inform deriving classes.
235     OnGesturedActorStageDisconnection();
236
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;
239   }
240 }
241
242 void GestureProcessor::ObjectDestroyed(Object& object)
243 {
244   if ( mCurrentGesturedActor == &object )
245   {
246     // Inform deriving classes.
247     OnGesturedActorStageDisconnection();
248
249     mCurrentGesturedActor = nullptr;
250   }
251 }
252
253 } // namespace Internal
254
255 } // namespace Dali