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