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