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