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