(Gestures) Each actor is now aware of what gestures it requires which is used when...
[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 Flora License, Version 1.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://floralicense.org/license/
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 // CLASS HEADER
18 #include <dali/internal/event/events/gesture-processor.h>
19
20 // INTERNAL INCLUDES
21 #include <dali/integration-api/debug.h>
22 #include <dali/internal/event/actors/actor-impl.h>
23 #include <dali/internal/event/render-tasks/render-task-impl.h>
24 #include <dali/internal/event/events/hit-test-algorithm-impl.h>
25
26 namespace Dali
27 {
28
29 namespace Internal
30 {
31
32 namespace
33 {
34
35 /**
36  * Functor to check whether an actor requires a particular gesture or not
37  */
38 struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
39 {
40   GestureHitTestCheck( Gesture::Type type )
41   : mType( type )
42   {
43   }
44
45   virtual bool IsActorHittable( Actor* actor )
46   {
47     return actor->IsGestureRequred( mType ) && // Does the Application or derived actor type require the gesture?
48            actor->IsHittable();                // Is actor sensitive, visible and on the scene?
49   }
50
51   virtual bool DescendActorHierarchy( Actor* actor )
52   {
53     return actor->IsVisible() && // Actor is visible, if not visible then none of its children are visible.
54            actor->IsSensitive(); // Actor is sensitive, if insensitive none of its children should be hittable either.
55   }
56
57   Gesture::Type mType;
58 };
59
60 } // unnamed namespace
61
62
63 GestureProcessor::GestureProcessor( Gesture::Type type )
64 : mType( type ),
65   mCurrentGesturedActor( NULL ),
66   mGesturedActorDisconnected( false )
67 {
68 }
69
70 GestureProcessor::~GestureProcessor()
71 {
72   ResetActor();
73 }
74
75 void GestureProcessor::GetGesturedActor( Dali::Actor& actor, const GestureDetectorContainer& connectedDetectors, std::vector<GestureDetector*>& gestureDetectors, Functor& functor )
76 {
77   while ( actor )
78   {
79     Actor* actorImpl( &GetImplementation(actor) );
80
81     // Check if our hit actor or any of its parents are attached to any registered detector.
82     // Find all detectors that have the actor attached.
83     for ( GestureDetectorContainer::const_iterator iter = connectedDetectors.begin(), endIter = connectedDetectors.end(); iter != endIter; ++iter )
84     {
85       GestureDetector* current(*iter);
86
87       // Check whether the actor is attached to the gesture detector and then call the functor to
88       // check whether the gesture detector satisfies the current gesture's parameters.
89       if ( current->IsAttached( *actorImpl ) && functor( current, actorImpl ) )
90       {
91         gestureDetectors.push_back(current);
92       }
93     }
94
95     // The hit actor or one of the parents is a gestured actor, break out.
96     if ( !gestureDetectors.empty() )
97     {
98       break;
99     }
100
101     // No match, we should now check the hit actor's parent.
102     actor = actor.GetParent();
103   }
104 }
105
106 void GestureProcessor::ProcessAndEmit( const HitTestAlgorithm::Results& hitTestResults, const GestureDetectorContainer& connectedDetectors, Functor& functor )
107 {
108   Dali::Actor actor( hitTestResults.actor );
109
110   while ( actor )
111   {
112     std::vector<GestureDetector*> gestureDetectors;
113
114     GetGesturedActor( actor, connectedDetectors, gestureDetectors, functor );
115
116     if ( actor && !gestureDetectors.empty() )
117     {
118       // We have a match but check if the hit point is within the gestured actor's bounds.
119       // If it is not then continue up the actor hierarchy.
120
121       if ( actor == hitTestResults.actor )
122       {
123         // Our gesture detector's attached actor WAS the hit actor so we can call the emitting functor.
124         functor( actor, gestureDetectors, hitTestResults.actorCoordinates );
125         break; // We have found AND emitted a signal on the gestured actor, break out.
126       }
127       else
128       {
129         if ( GetImplementation(actor).IsHittable() )
130         {
131           const Vector3 size( actor.GetCurrentSize() );
132
133           if ( ( size.x > 0.0f ) && ( size.y > 0.0f ) )
134           {
135             // Ensure tap is within the actor's area
136             Actor& actorImpl = GetImplementation(actor);
137             if ( actorImpl.RaySphereTest( hitTestResults.rayOrigin, hitTestResults.rayDirection ) ) // Quick check
138             {
139               Vector4 hitPointLocal;
140               float distance( 0.0f );
141               if( actorImpl.RayActorTest( hitTestResults.rayOrigin, hitTestResults.rayDirection, hitPointLocal, distance ) )
142               {
143                 // One of the hit actor's parents was the gestured actor so call the emitting functor.
144                 functor( actor, gestureDetectors, Vector2( hitPointLocal.x, hitPointLocal.y ) );
145                 break; // We have found AND emitted a signal on the gestured actor, break out.
146               }
147             }
148           }
149         }
150       }
151     }
152
153     // Continue up hierarchy to see if any of the parents require this gesture.
154     if ( actor )
155     {
156       actor = actor.GetParent();
157     }
158   }
159 }
160
161 bool GestureProcessor::HitTest(
162   Stage&                     stage,
163   Vector2                    screenCoordinates,
164   HitTestAlgorithm::Results& hitTestResults)
165 {
166   GestureHitTestCheck hitCheck( mType );
167   HitTestAlgorithm::HitTest( stage, screenCoordinates, hitTestResults, hitCheck );
168   return hitTestResults.renderTask && hitTestResults.actor;
169 }
170
171 void GestureProcessor::SetActor( Dali::Actor actor )
172 {
173   if ( actor && actor != mCurrentGesturedActor )
174   {
175     ResetActor();
176
177     mCurrentGesturedActor = &GetImplementation( actor );
178     mCurrentGesturedActor->AddObserver( *this );
179   }
180   mGesturedActorDisconnected = false;
181 }
182
183 void GestureProcessor::ResetActor()
184 {
185   if ( mCurrentGesturedActor )
186   {
187     mCurrentGesturedActor->RemoveObserver( *this );
188     mCurrentGesturedActor = NULL;
189     mGesturedActorDisconnected = false;
190   }
191 }
192
193 Actor* GestureProcessor::GetCurrentGesturedActor()
194 {
195   return mGesturedActorDisconnected ? NULL : mCurrentGesturedActor;
196 }
197
198 void GestureProcessor::SceneObjectRemoved(ProxyObject& proxy)
199 {
200   if ( mCurrentGesturedActor == &proxy &&
201       !mGesturedActorDisconnected )
202   {
203     // Inform deriving classes.
204     OnGesturedActorStageDisconnection();
205
206     // do not call proxy.RemoveObserver here, proxy is currently iterating through observers... you wouldnt want to upset proxy now would you?
207     mGesturedActorDisconnected = true;
208   }
209 }
210
211 void GestureProcessor::ProxyDestroyed(ProxyObject& proxy)
212 {
213   if ( mCurrentGesturedActor == &proxy )
214   {
215     // Inform deriving classes.
216     OnGesturedActorStageDisconnection();
217
218     mCurrentGesturedActor = NULL;
219   }
220 }
221
222 } // namespace Internal
223
224 } // namespace Dali