6fc7c7c9af733ae5e4ec532a0f97afe70d8f1312
[platform/core/uifw/dali-core.git] / dali / internal / event / events / pinch-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/pinch-gesture-processor.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/actors/actor.h>
26 #include <dali/public-api/events/pinch-gesture.h>
27 #include <dali/public-api/math/vector2.h>
28 #include <dali/integration-api/events/pinch-gesture-event.h>
29 #include <dali/integration-api/gesture-manager.h>
30 #include <dali/integration-api/debug.h>
31 #include <dali/internal/event/common/stage-impl.h>
32 #include <dali/internal/event/render-tasks/render-task-impl.h>
33
34 namespace Dali
35 {
36
37 namespace Internal
38 {
39
40 namespace
41 {
42
43 /**
44  * Creates a PinchGesture and asks the specified detector to emit its detected signal.
45  * @param[in]  actor             The actor that has been pinched.
46  * @param[in]  gestureDetectors  The gesture detector container that should emit the signal.
47  * @param[in]  pinchEvent        The pinchEvent received from the adaptor.
48  * @param[in]  localCenter       Relative to the actor attached to the detector.
49  */
50 void EmitPinchSignal(
51     Actor* actor,
52     const GestureDetectorContainer& gestureDetectors,
53     const Integration::PinchGestureEvent& pinchEvent,
54     Vector2 localCenter)
55 {
56   PinchGesture pinch(pinchEvent.state);
57   pinch.time = pinchEvent.time;
58
59   pinch.scale = pinchEvent.scale;
60   pinch.speed = pinchEvent.speed;
61   pinch.screenCenterPoint = pinchEvent.centerPoint;
62
63   pinch.localCenterPoint = localCenter;
64
65   Dali::Actor actorHandle( actor );
66   const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
67   for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
68   {
69     static_cast< PinchGestureDetector* >( *iter )->EmitPinchGestureSignal( actorHandle, pinch );
70   }
71 }
72
73 /**
74  * Functor which checks whether the specified actor is attached to the gesture detector.
75  * It returns true if it is no longer attached.  This can be used in remove_if functions.
76  */
77 struct IsNotAttachedFunctor
78 {
79   /**
80    * Constructor
81    * @param[in]  actor  The actor to check whether it is attached.
82    */
83   IsNotAttachedFunctor(Actor* actor)
84   : actorToCheck(actor)
85   {
86   }
87
88   /**
89    * Returns true if not attached, false if it is still attached.
90    * @param[in]  detector  The detector to check.
91    * @return true, if not attached, false otherwise.
92    */
93   bool operator()(const GestureDetector* detector) const
94   {
95     return !detector->IsAttached(*actorToCheck);
96   }
97
98   Actor* actorToCheck; ///< The actor to check whether it is attached or not.
99 };
100
101 } // unnamed namespace
102
103 PinchGestureProcessor::PinchGestureProcessor( Stage& stage, Integration::GestureManager& gestureManager )
104 : GestureProcessor( Gesture::Pinch ),
105   mStage(stage),
106   mGestureManager(gestureManager),
107   mGestureDetectors(),
108   mCurrentPinchEmitters(),
109   mCurrentPinchEvent(NULL)
110 {
111 }
112
113 PinchGestureProcessor::~PinchGestureProcessor()
114 {
115 }
116
117 void PinchGestureProcessor::Process( const Integration::PinchGestureEvent& pinchEvent )
118 {
119   switch ( pinchEvent.state )
120   {
121     case Gesture::Started:
122     {
123       // The pinch gesture should only be sent to the gesture detector which first received it so that
124       // it can be told when the gesture ends as well.
125
126       mCurrentPinchEmitters.clear();
127       ResetActor();
128
129       HitTestAlgorithm::Results hitTestResults;
130       if( HitTest( mStage, pinchEvent.centerPoint, hitTestResults ) )
131       {
132         // Record the current render-task for Screen->Actor coordinate conversions
133         mCurrentRenderTask = hitTestResults.renderTask;
134
135         // Set mCurrentPinchEvent to use inside overridden methods called from ProcessAndEmit()
136         mCurrentPinchEvent = &pinchEvent;
137         ProcessAndEmit( hitTestResults );
138         mCurrentPinchEvent = NULL;
139       }
140       break;
141     }
142
143     case Gesture::Continuing:
144     case Gesture::Finished:
145     case Gesture::Cancelled:
146     {
147       // Only send subsequent pinch gesture signals if we processed the pinch gesture when it started.
148       // Check if actor is still touchable.
149
150       Actor* currentGesturedActor = GetCurrentGesturedActor();
151       if ( currentGesturedActor )
152       {
153         if ( currentGesturedActor->IsHittable() && !mCurrentPinchEmitters.empty() && mCurrentRenderTask )
154         {
155           // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
156           GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
157           mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
158
159           if ( !mCurrentPinchEmitters.empty() )
160           {
161             Vector2 actorCoords;
162             RenderTask& renderTaskImpl( GetImplementation(mCurrentRenderTask) );
163             currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, pinchEvent.centerPoint.x, pinchEvent.centerPoint.y );
164
165             EmitPinchSignal( currentGesturedActor, mCurrentPinchEmitters, pinchEvent, actorCoords );
166           }
167           else
168           {
169             // If we have no current emitters then clear pinched actor as well.
170             ResetActor();
171           }
172
173           // Clear current emitters if pinch gesture has ended or been cancelled.
174           if ( pinchEvent.state == Gesture::Finished || pinchEvent.state == Gesture::Cancelled )
175           {
176             mCurrentPinchEmitters.clear();
177             ResetActor();
178           }
179         }
180         else
181         {
182           mCurrentPinchEmitters.clear();
183           ResetActor();
184         }
185       }
186       break;
187     }
188
189     case Gesture::Clear:
190     {
191       DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
192       break;
193     }
194     case Gesture::Possible:
195     {
196       DALI_ABORT( "Incorrect state received from Integration layer: Possible\n" );
197       break;
198     }
199   }
200 }
201
202 void PinchGestureProcessor::AddGestureDetector( PinchGestureDetector* gestureDetector )
203 {
204   bool registerWithAdaptor(mGestureDetectors.empty());
205
206   mGestureDetectors.push_back(gestureDetector);
207
208   if (registerWithAdaptor)
209   {
210     Integration::GestureRequest request(Gesture::Pinch);
211     mGestureManager.Register(request);
212   }
213 }
214
215 void PinchGestureProcessor::RemoveGestureDetector( PinchGestureDetector* gestureDetector )
216 {
217   if ( !mCurrentPinchEmitters.empty() )
218   {
219     // Check if the removed detector was one that is currently being pinched and remove it from emitters.
220     GestureDetectorContainer::iterator endIter = std::remove( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), gestureDetector );
221     mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
222
223     // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
224     if ( mCurrentPinchEmitters.empty() )
225     {
226       ResetActor();
227     }
228   }
229
230   // Find the detector...
231   PinchGestureDetectorContainer::iterator endIter = std::remove( mGestureDetectors.begin(), mGestureDetectors.end(), gestureDetector );
232   DALI_ASSERT_DEBUG( endIter != mGestureDetectors.end() );
233
234   // ...and remove it
235   mGestureDetectors.erase(endIter, mGestureDetectors.end());
236
237   if (mGestureDetectors.empty())
238   {
239     Integration::GestureRequest request(Gesture::Pinch);
240     mGestureManager.Unregister(request);
241   }
242 }
243
244 void PinchGestureProcessor::GestureDetectorUpdated( PinchGestureDetector* gestureDetector )
245 {
246   // Nothing to do as PinchGestureDetector does not have any specific parameters.
247 }
248
249 void PinchGestureProcessor::OnGesturedActorStageDisconnection()
250 {
251   mCurrentPinchEmitters.clear();
252 }
253
254 bool PinchGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
255 {
256   // No special case required for pinch.
257   return true;
258 }
259
260 void PinchGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
261 {
262   DALI_ASSERT_DEBUG( mCurrentPinchEvent );
263
264   EmitPinchSignal( actor, gestureDetectors, *mCurrentPinchEvent, actorCoordinates );
265
266   if ( actor->OnStage() )
267   {
268     mCurrentPinchEmitters = gestureDetectors;
269     SetActor( actor );
270   }
271 }
272
273 } // namespace Internal
274
275 } // namespace Dali