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