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