Merge "Include the algorithm header file" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / events / gesture-processor.cpp
1 /*
2  * Copyright (c) 2020 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/events/ray-test.h>
29 #include <dali/internal/event/render-tasks/render-task-impl.h>
30
31 namespace Dali
32 {
33
34 namespace Internal
35 {
36
37 namespace
38 {
39
40 /**
41  * Functor to check whether an actor requires a particular gesture or not
42  */
43 struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
44 {
45   GestureHitTestCheck( GestureType::Value type )
46   : mType( type )
47   {
48   }
49
50   bool IsActorHittable( Actor* actor ) override
51   {
52     return actor->IsGestureRequired( mType ) && // Does the Application or derived actor type require the gesture?
53            actor->IsHittable();                 // Is actor sensitive, visible and on the scene?
54   }
55
56   bool DescendActorHierarchy( Actor* actor ) override
57   {
58     return actor->IsVisible() && // Actor is visible, if not visible then none of its children are visible.
59            actor->IsSensitive(); // Actor is sensitive, if insensitive none of its children should be hittable either.
60   }
61
62   bool DoesLayerConsumeHit( Layer* layer ) override
63   {
64     return layer->IsTouchConsumed();
65   }
66
67   GestureType::Value mType;
68 };
69
70 } // unnamed namespace
71
72
73 GestureProcessor::GestureProcessor( GestureType::Value type )
74 : mGestureRecognizer(),
75   mNeedsUpdate( false ),
76   mType( type ),
77   mCurrentGesturedActor( nullptr ),
78   mGesturedActorDisconnected( false )
79 {
80 }
81
82 GestureProcessor::~GestureProcessor()
83 {
84   ResetActor();
85 }
86
87 void GestureProcessor::ProcessTouch( Scene& scene, const Integration::TouchEvent& event )
88 {
89   if( mGestureRecognizer )
90   {
91     mGestureRecognizer->SendEvent(scene, event);
92   }
93 }
94
95 void GestureProcessor::GetGesturedActor( Actor*& actor, GestureDetectorContainer& gestureDetectors )
96 {
97   while ( actor )
98   {
99     // We may be checking a parent so ensure the parent requires this gesture (and do not unintentionally create the gesture data for the parent)
100     if ( actor->IsGestureRequired( mType ) )
101     {
102       // Retrieve the actor's detectors and check if they satisfy current gesture
103       const GestureDetectorContainer& connectedDetectors( actor->GetGestureData().GetGestureDetectorContainer( mType ) );
104       const GestureDetectorContainer::const_iterator endIter( connectedDetectors.end() );
105       for ( GestureDetectorContainer::const_iterator iter = connectedDetectors.begin(); iter != endIter; ++iter )
106       {
107         GestureDetector* current(*iter);
108
109         // Check deriving class for whether the current gesture satisfies the gesture detector's parameters.
110         if ( CheckGestureDetector( current, actor ) )
111         {
112           gestureDetectors.push_back(current);
113         }
114       }
115
116       // The hit actor or one of the parents is a gestured actor, break out.
117       if ( !gestureDetectors.empty() )
118       {
119         break;
120       }
121     }
122
123     // No match, we should now check the hit actor's parent.
124     actor = actor->GetParent();
125   }
126 }
127
128 void GestureProcessor::ProcessAndEmit( HitTestAlgorithm::Results& hitTestResults )
129 {
130   if ( hitTestResults.actor )
131   {
132     Actor* hitTestActor( &GetImplementation( hitTestResults.actor ) );
133     Actor* actor( hitTestActor );
134     RayTest rayTest;
135
136     while ( actor )
137     {
138       GestureDetectorContainer gestureDetectors;
139       GetGesturedActor( actor, gestureDetectors );
140
141       if ( actor && !gestureDetectors.empty() )
142       {
143         // We have a match but check if the hit point is within the gestured actor's bounds.
144         // If it is not then continue up the actor hierarchy.
145
146         if ( actor == hitTestActor )
147         {
148           // Our gesture detector's attached actor WAS the hit actor so we can can emit the signal.
149           EmitGestureSignal( actor, gestureDetectors, hitTestResults.actorCoordinates );
150           break; // We have found AND emitted a signal on the gestured actor, break out.
151         }
152         else
153         {
154           if ( actor->IsHittable() )
155           {
156             const Vector3 size( actor->GetCurrentSize() );
157
158             if ( ( size.x > 0.0f ) && ( size.y > 0.0f ) )
159             {
160               // Ensure tap is within the actor's area
161               if ( rayTest.SphereTest( *actor, hitTestResults.rayOrigin, hitTestResults.rayDirection ) ) // Quick check
162               {
163                 Vector2 hitPointLocal;
164                 float distance( 0.0f );
165                 if( rayTest.ActorTest( *actor, hitTestResults.rayOrigin, hitTestResults.rayDirection, hitPointLocal, distance ) )
166                 {
167                   // One of the parents was the gestured actor so we can emit the signal for that actor.
168                   EmitGestureSignal( actor, gestureDetectors, hitPointLocal );
169                   break; // We have found AND emitted a signal on the gestured actor, break out.
170                 }
171               }
172             }
173           }
174         }
175       }
176
177       // Continue up hierarchy to see if any of the parents require this gesture.
178       if ( actor )
179       {
180         actor = actor->GetParent();
181       }
182     }
183   }
184 }
185
186 bool GestureProcessor::HitTest( Scene& scene, Vector2 screenCoordinates, HitTestAlgorithm::Results& hitTestResults )
187 {
188   GestureHitTestCheck hitCheck( mType );
189   HitTestAlgorithm::HitTest( scene.GetSize(), scene.GetRenderTaskList(), scene.GetLayerList(), screenCoordinates, hitTestResults, hitCheck );
190   return hitTestResults.renderTask && hitTestResults.actor;
191 }
192
193 void GestureProcessor::SetActor( Actor* actor )
194 {
195   if ( actor && actor != mCurrentGesturedActor )
196   {
197     ResetActor();
198
199     mCurrentGesturedActor = actor;
200     mCurrentGesturedActor->AddObserver( *this );
201   }
202   mGesturedActorDisconnected = false;
203 }
204
205 void GestureProcessor::ResetActor()
206 {
207   if ( mCurrentGesturedActor )
208   {
209     mCurrentGesturedActor->RemoveObserver( *this );
210     mCurrentGesturedActor = nullptr;
211     mGesturedActorDisconnected = false;
212   }
213 }
214
215 Actor* GestureProcessor::GetCurrentGesturedActor()
216 {
217   return mGesturedActorDisconnected ? nullptr : mCurrentGesturedActor;
218 }
219
220 void GestureProcessor::SceneObjectRemoved(Object& object)
221 {
222   if ( mCurrentGesturedActor == &object &&
223       !mGesturedActorDisconnected )
224   {
225     // Inform deriving classes.
226     OnGesturedActorStageDisconnection();
227
228     // do not call object.RemoveObserver here, object is currently iterating through observers... you wouldnt want to upset object now would you?
229     mGesturedActorDisconnected = true;
230   }
231 }
232
233 void GestureProcessor::ObjectDestroyed(Object& object)
234 {
235   if ( mCurrentGesturedActor == &object )
236   {
237     // Inform deriving classes.
238     OnGesturedActorStageDisconnection();
239
240     mCurrentGesturedActor = nullptr;
241   }
242 }
243
244 } // namespace Internal
245
246 } // namespace Dali