145746708d2cf63b07f2026e0ab213ba9dc3f74f
[platform/core/uifw/dali-core.git] / dali / internal / event / events / gesture-processor.cpp
1 /*
2  * Copyright (c) 2014 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/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>
28
29 namespace Dali
30 {
31
32 namespace Internal
33 {
34
35 namespace
36 {
37
38 /**
39  * Functor to check whether an actor requires a particular gesture or not
40  */
41 struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
42 {
43   GestureHitTestCheck( Gesture::Type type )
44   : mType( type )
45   {
46   }
47
48   virtual bool IsActorHittable( Actor* actor )
49   {
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?
52   }
53
54   virtual bool DescendActorHierarchy( Actor* actor )
55   {
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.
58   }
59
60   virtual bool DoesLayerConsumeHit( Layer* layer )
61   {
62     return layer->IsTouchConsumed();
63   }
64
65   Gesture::Type mType;
66 };
67
68 } // unnamed namespace
69
70
71 GestureProcessor::GestureProcessor( Gesture::Type type )
72 : mType( type ),
73   mCurrentGesturedActor( NULL ),
74   mGesturedActorDisconnected( false )
75 {
76 }
77
78 GestureProcessor::~GestureProcessor()
79 {
80   ResetActor();
81 }
82
83 void GestureProcessor::GetGesturedActor( Actor*& actor, GestureDetectorContainer& gestureDetectors )
84 {
85   while ( actor )
86   {
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 ) )
89     {
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 )
94       {
95         GestureDetector* current(*iter);
96
97         // Check deriving class for whether the current gesture satisfies the gesture detector's parameters.
98         if ( CheckGestureDetector( current, actor ) )
99         {
100           gestureDetectors.push_back(current);
101         }
102       }
103
104       // The hit actor or one of the parents is a gestured actor, break out.
105       if ( !gestureDetectors.empty() )
106       {
107         break;
108       }
109     }
110
111     // No match, we should now check the hit actor's parent.
112     actor = actor->GetParent();
113   }
114 }
115
116 void GestureProcessor::ProcessAndEmit( HitTestAlgorithm::Results& hitTestResults )
117 {
118   if ( hitTestResults.actor )
119   {
120     Actor* hitTestActor( &GetImplementation( hitTestResults.actor ) );
121     Actor* actor( hitTestActor );
122
123     while ( actor )
124     {
125       GestureDetectorContainer gestureDetectors;
126       GetGesturedActor( actor, gestureDetectors );
127
128       if ( actor && !gestureDetectors.empty() )
129       {
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.
132
133         if ( actor == hitTestActor )
134         {
135           // Our gesture detector's attached actor WAS the hit actor so we can can emit the signal.
136           EmitGestureSignal( actor, gestureDetectors, hitTestResults.actorCoordinates );
137           break; // We have found AND emitted a signal on the gestured actor, break out.
138         }
139         else
140         {
141           if ( actor->IsHittable() )
142           {
143             const Vector3 size( actor->GetCurrentSize() );
144
145             if ( ( size.x > 0.0f ) && ( size.y > 0.0f ) )
146             {
147               // Ensure tap is within the actor's area
148               if ( actor->RaySphereTest( hitTestResults.rayOrigin, hitTestResults.rayDirection ) ) // Quick check
149               {
150                 Vector4 hitPointLocal;
151                 float distance( 0.0f );
152                 if( actor->RayActorTest( hitTestResults.rayOrigin, hitTestResults.rayDirection, hitPointLocal, distance ) )
153                 {
154                   // One of the parents was the gestured actor so we can emit the signal for that actor.
155                   EmitGestureSignal( actor, gestureDetectors, Vector2( hitPointLocal.x, hitPointLocal.y ) );
156                   break; // We have found AND emitted a signal on the gestured actor, break out.
157                 }
158               }
159             }
160           }
161         }
162       }
163
164       // Continue up hierarchy to see if any of the parents require this gesture.
165       if ( actor )
166       {
167         actor = actor->GetParent();
168       }
169     }
170   }
171 }
172
173 bool GestureProcessor::HitTest(
174   Stage&                     stage,
175   Vector2                    screenCoordinates,
176   HitTestAlgorithm::Results& hitTestResults)
177 {
178   GestureHitTestCheck hitCheck( mType );
179   HitTestAlgorithm::HitTest( stage, screenCoordinates, hitTestResults, hitCheck );
180   return hitTestResults.renderTask && hitTestResults.actor;
181 }
182
183 void GestureProcessor::SetActor( Actor* actor )
184 {
185   if ( actor && actor != mCurrentGesturedActor )
186   {
187     ResetActor();
188
189     mCurrentGesturedActor = actor;
190     mCurrentGesturedActor->AddObserver( *this );
191   }
192   mGesturedActorDisconnected = false;
193 }
194
195 void GestureProcessor::ResetActor()
196 {
197   if ( mCurrentGesturedActor )
198   {
199     mCurrentGesturedActor->RemoveObserver( *this );
200     mCurrentGesturedActor = NULL;
201     mGesturedActorDisconnected = false;
202   }
203 }
204
205 Actor* GestureProcessor::GetCurrentGesturedActor()
206 {
207   return mGesturedActorDisconnected ? NULL : mCurrentGesturedActor;
208 }
209
210 void GestureProcessor::SceneObjectRemoved(ProxyObject& proxy)
211 {
212   if ( mCurrentGesturedActor == &proxy &&
213       !mGesturedActorDisconnected )
214   {
215     // Inform deriving classes.
216     OnGesturedActorStageDisconnection();
217
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;
220   }
221 }
222
223 void GestureProcessor::ProxyDestroyed(ProxyObject& proxy)
224 {
225   if ( mCurrentGesturedActor == &proxy )
226   {
227     // Inform deriving classes.
228     OnGesturedActorStageDisconnection();
229
230     mCurrentGesturedActor = NULL;
231   }
232 }
233
234 } // namespace Internal
235
236 } // namespace Dali