Tizen 2.4.0 rev3 SDK Public Release
[framework/graphics/dali.git] / dali / internal / event / events / long-press-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 "long-press-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/common/dali-common.h>
27 #include <dali/public-api/events/long-press-gesture.h>
28 #include <dali/integration-api/events/long-press-gesture-event.h>
29 #include <dali/integration-api/gesture-manager.h>
30 #include <dali/integration-api/debug.h>
31 #include <dali/internal/event/actors/actor-impl.h>
32 #include <dali/internal/event/common/stage-impl.h>
33 #include <dali/internal/event/render-tasks/render-task-impl.h>
34
35 namespace Dali
36 {
37
38 namespace Internal
39 {
40
41 namespace
42 {
43
44 /**
45  * Creates a LongPressGesture and asks the specified detector to emit its detected signal.
46  * @param[in]  actor             The actor on which the long press gesture has occurred.
47  * @param[in]  gestureDetectors  A reference to gesture detectors that should emit the signal.
48  * @param[in]  longPressEvent    The longPressEvent received from the adaptor.
49  * @param[in]  localPoint        Relative to the actor attached to the detector.
50  */
51 void EmitLongPressSignal(
52     Actor* actor,
53     const GestureDetectorContainer& gestureDetectors,
54     const Integration::LongPressGestureEvent& longPressEvent,
55     Vector2 localPoint)
56 {
57   LongPressGesture longPress(longPressEvent.state);
58   longPress.time = longPressEvent.time;
59   longPress.numberOfTouches = longPressEvent.numberOfTouches;
60   longPress.screenPoint = longPressEvent.point;
61   longPress.localPoint = localPoint;
62
63   Dali::Actor actorHandle( actor );
64   const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
65   for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
66   {
67     static_cast< LongPressGestureDetector* >( *iter )->EmitLongPressGestureSignal( actorHandle, longPress );
68   }
69 }
70
71 /**
72  * Functor which checks whether the specified actor is attached to the gesture detector.
73  * It returns true if it is no longer attached.  This can be used in remove_if functions.
74  */
75 struct IsNotAttachedFunctor
76 {
77   /**
78    * Constructor
79    * @param[in]  actor  The actor to check whether it is attached.
80    */
81   IsNotAttachedFunctor( Actor* actor )
82   : actorToCheck( actor )
83   {
84   }
85
86   /**
87    * Returns true if not attached, false if it is still attached.
88    * @param[in]  detector  The detector to check.
89    * @return true, if not attached, false otherwise.
90    */
91   bool operator()( const GestureDetector* detector ) const
92   {
93     return !detector->IsAttached( *actorToCheck );
94   }
95
96   Actor* actorToCheck; ///< The actor to check whether it is attached or not.
97 };
98
99 } // unnamed namespace
100
101 LongPressGestureProcessor::LongPressGestureProcessor( Stage& stage, Integration::GestureManager& gestureManager)
102 : GestureProcessor( Gesture::LongPress ),
103   mStage( stage ),
104   mGestureManager( gestureManager ),
105   mGestureDetectors(),
106   mCurrentEmitters(),
107   mCurrentRenderTask(),
108   mMinTouchesRequired( 1 ),
109   mMaxTouchesRequired( 1 ),
110   mCurrentLongPressEvent( NULL )
111 {
112 }
113
114 LongPressGestureProcessor::~LongPressGestureProcessor()
115 {
116 }
117
118 void LongPressGestureProcessor::Process( const Integration::LongPressGestureEvent& longPressEvent )
119 {
120   switch ( longPressEvent.state )
121   {
122     case Gesture::Possible:
123     {
124       mCurrentEmitters.clear();
125       ResetActor();
126
127       HitTestAlgorithm::Results hitTestResults;
128       if( HitTest( mStage, longPressEvent.point, hitTestResults ) )
129       {
130         SetActor( &GetImplementation( hitTestResults.actor ) );
131       }
132       break;
133     }
134
135     case Gesture::Started:
136     {
137       Actor* currentGesturedActor = GetCurrentGesturedActor();
138       if ( currentGesturedActor )
139       {
140         HitTestAlgorithm::Results hitTestResults;
141         HitTest( mStage, longPressEvent.point, hitTestResults );
142
143         if ( hitTestResults.actor && ( currentGesturedActor == &GetImplementation( hitTestResults.actor ) ) )
144         {
145           // Record the current render-task for Screen->Actor coordinate conversions
146           mCurrentRenderTask = hitTestResults.renderTask;
147
148           // Set mCurrentLongPressEvent to use inside overridden methods called from ProcessAndEmit()
149           mCurrentLongPressEvent = &longPressEvent;
150           ProcessAndEmit( hitTestResults );
151           mCurrentLongPressEvent = NULL;
152         }
153         else
154         {
155           mCurrentEmitters.clear();
156           ResetActor();
157         }
158       }
159       break;
160     }
161
162     case Gesture::Finished:
163     {
164       // The gesture should only be sent to the gesture detector which first received it so that it
165       // can be told when the gesture ends as well.
166
167       // Only send subsequent long press gesture signals if we processed the gesture when it started.
168       // Check if actor is still touchable.
169
170       Actor* currentGesturedActor = GetCurrentGesturedActor();
171       if ( currentGesturedActor )
172       {
173         if ( currentGesturedActor->IsHittable() && !mCurrentEmitters.empty() && mCurrentRenderTask )
174         {
175           // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
176           GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentEmitters.begin(), mCurrentEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
177           mCurrentEmitters.erase( endIter, mCurrentEmitters.end() );
178
179           if ( !mCurrentEmitters.empty() )
180           {
181             Vector2 actorCoords;
182             RenderTask& renderTaskImpl( GetImplementation( mCurrentRenderTask ) );
183             currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, longPressEvent.point.x, longPressEvent.point.y );
184
185             EmitLongPressSignal( currentGesturedActor, mCurrentEmitters, longPressEvent, actorCoords );
186           }
187         }
188
189         // Clear current emitters and emitted actor
190         mCurrentEmitters.clear();
191         ResetActor();
192       }
193       break;
194     }
195
196     case Gesture::Cancelled:
197     {
198       mCurrentEmitters.clear();
199       ResetActor();
200       break;
201     }
202
203     case Gesture::Continuing:
204       DALI_ASSERT_ALWAYS( false && "Incorrect state received from Integration layer: Continuing\n" );
205       break;
206
207     case Gesture::Clear:
208       DALI_ASSERT_ALWAYS( false && "Incorrect state received from Integration layer: Clear\n" );
209       break;
210   }
211 }
212
213 void LongPressGestureProcessor::AddGestureDetector( LongPressGestureDetector* gestureDetector )
214 {
215   bool firstRegistration(mGestureDetectors.empty());
216
217   mGestureDetectors.push_back(gestureDetector);
218
219   if (firstRegistration)
220   {
221     mMinTouchesRequired = gestureDetector->GetMinimumTouchesRequired();
222     mMaxTouchesRequired = gestureDetector->GetMaximumTouchesRequired();
223
224     Integration::LongPressGestureRequest request;
225     request.minTouches = mMinTouchesRequired;
226     request.maxTouches = mMaxTouchesRequired;
227     mGestureManager.Register( request );
228   }
229   else
230   {
231     UpdateDetection();
232   }
233 }
234
235 void LongPressGestureProcessor::RemoveGestureDetector( LongPressGestureDetector* gestureDetector )
236 {
237   // Find detector ...
238   LongPressGestureDetectorContainer::iterator endIter = std::remove( mGestureDetectors.begin(), mGestureDetectors.end(), gestureDetector );
239   DALI_ASSERT_DEBUG( endIter != mGestureDetectors.end() );
240
241   // ... and remove it
242   mGestureDetectors.erase( endIter, mGestureDetectors.end() );
243
244   if ( mGestureDetectors.empty() )
245   {
246     Integration::GestureRequest request( Gesture::LongPress );
247     mGestureManager.Unregister(request);
248   }
249   else
250   {
251     UpdateDetection();
252   }
253 }
254
255 void LongPressGestureProcessor::GestureDetectorUpdated( LongPressGestureDetector* gestureDetector )
256 {
257   DALI_ASSERT_DEBUG( find( mGestureDetectors.begin(), mGestureDetectors.end(), gestureDetector ) != mGestureDetectors.end() );
258
259   UpdateDetection();
260 }
261
262 void LongPressGestureProcessor::UpdateDetection()
263 {
264   DALI_ASSERT_DEBUG(!mGestureDetectors.empty());
265
266   unsigned int minimumRequired = UINT_MAX;
267   unsigned int maximumRequired = 0;
268
269   for ( LongPressGestureDetectorContainer::iterator iter = mGestureDetectors.begin(), endIter = mGestureDetectors.end(); iter != endIter; ++iter )
270   {
271     LongPressGestureDetector* current(*iter);
272
273     if( current )
274     {
275       unsigned int minimum = current->GetMinimumTouchesRequired();
276       if (minimum < minimumRequired)
277       {
278         minimumRequired = minimum;
279       }
280
281       unsigned int maximum = current->GetMaximumTouchesRequired();
282       if ( maximum > maximumRequired )
283       {
284         maximumRequired = maximum;
285       }
286     }
287   }
288
289   if ( (minimumRequired != mMinTouchesRequired) || (maximumRequired != mMaxTouchesRequired) )
290   {
291     mMinTouchesRequired = minimumRequired;
292     mMaxTouchesRequired = maximumRequired;
293
294     Integration::LongPressGestureRequest request;
295     request.minTouches = mMinTouchesRequired;
296     request.maxTouches = mMaxTouchesRequired;
297     mGestureManager.Update(request);
298   }
299 }
300
301 void LongPressGestureProcessor::OnGesturedActorStageDisconnection()
302 {
303   mCurrentEmitters.clear();
304 }
305
306 bool LongPressGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
307 {
308   DALI_ASSERT_DEBUG( mCurrentLongPressEvent );
309
310   LongPressGestureDetector* longPressDetector ( static_cast< LongPressGestureDetector* >( detector ) );
311
312   return ( longPressDetector->GetMinimumTouchesRequired() <= mCurrentLongPressEvent->numberOfTouches ) &&
313          ( longPressDetector->GetMaximumTouchesRequired() >= mCurrentLongPressEvent->numberOfTouches );
314 }
315
316 void LongPressGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
317 {
318   DALI_ASSERT_DEBUG( mCurrentLongPressEvent );
319
320   mCurrentEmitters.clear();
321   ResetActor();
322
323   EmitLongPressSignal( actor, gestureDetectors, *mCurrentLongPressEvent, actorCoordinates );
324
325   if ( actor->OnStage() )
326   {
327     mCurrentEmitters = gestureDetectors;
328     SetActor( actor );
329   }
330 }
331
332 } // namespace Internal
333
334 } // namespace Dali