324f9ffbe01c4163c2fa83577b9c7cccee3375b0
[platform/core/uifw/dali-core.git] / dali / internal / event / events / pinch-gesture / pinch-gesture-processor.cpp
1 /*
2  * Copyright (c) 2020 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/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/internal/event/events/pinch-gesture/pinch-gesture-event.h>
29 #include <dali/integration-api/debug.h>
30 #include <dali/internal/event/common/scene-impl.h>
31 #include <dali/internal/event/render-tasks/render-task-impl.h>
32 #include <dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.h>
33 #include <dali/internal/event/events/pinch-gesture/pinch-gesture-impl.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 const uint32_t MINIMUM_TOUCH_EVENTS_REQUIRED = 4u;
45 const uint32_t MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START = 4u;
46
47 /**
48  * Creates a PinchGesture and asks the specified detector to emit its detected signal.
49  * @param[in]  actor             The actor that has been pinched.
50  * @param[in]  gestureDetectors  The gesture detector container that should emit the signal.
51  * @param[in]  pinchEvent        The pinchEvent received from the adaptor.
52  * @param[in]  localCenter       Relative to the actor attached to the detector.
53  */
54 void EmitPinchSignal(
55     Actor* actor,
56     const GestureDetectorContainer& gestureDetectors,
57     const PinchGestureEvent& pinchEvent,
58     Vector2 localCenter)
59 {
60   Internal::PinchGesturePtr pinch( new Internal::PinchGesture(pinchEvent.state ) );
61   pinch->SetTime( pinchEvent.time );
62
63   pinch->SetScale( pinchEvent.scale );
64   pinch->SetSpeed( pinchEvent.speed );
65   pinch->SetScreenCenterPoint( pinchEvent.centerPoint );
66
67   pinch->SetLocalCenterPoint( localCenter );
68
69   Dali::Actor actorHandle( actor );
70   const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
71   for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
72   {
73     static_cast< PinchGestureDetector* >( *iter )->EmitPinchGestureSignal( actorHandle, Dali::PinchGesture( pinch.Get() ) );
74   }
75 }
76
77 /**
78  * Functor which checks whether the specified actor is attached to the gesture detector.
79  * It returns true if it is no longer attached.  This can be used in remove_if functions.
80  */
81 struct IsNotAttachedFunctor
82 {
83   /**
84    * Constructor
85    * @param[in]  actor  The actor to check whether it is attached.
86    */
87   IsNotAttachedFunctor(Actor* actor)
88   : actorToCheck(actor)
89   {
90   }
91
92   /**
93    * Returns true if not attached, false if it is still attached.
94    * @param[in]  detector  The detector to check.
95    * @return true, if not attached, false otherwise.
96    */
97   bool operator()(const GestureDetector* detector) const
98   {
99     return !detector->IsAttached(*actorToCheck);
100   }
101
102   Actor* actorToCheck; ///< The actor to check whether it is attached or not.
103 };
104
105 } // unnamed namespace
106
107 PinchGestureProcessor::PinchGestureProcessor()
108 : GestureProcessor( Dali::Gesture::Pinch ),
109   mPinchGestureDetectors(),
110   mCurrentPinchEmitters(),
111   mCurrentPinchEvent(NULL),
112   mMinimumPinchDistance(-1.0f),
113   mMinimumTouchEvents( MINIMUM_TOUCH_EVENTS_REQUIRED ),
114   mMinimumTouchEventsAfterStart( MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START )
115 {
116 }
117
118 PinchGestureProcessor::~PinchGestureProcessor()
119 {
120 }
121
122 void PinchGestureProcessor::SetMinimumPinchDistance( float value )
123 {
124   mMinimumPinchDistance = value;
125
126   if( mGestureRecognizer )
127   {
128     PinchGestureRecognizer* pinchRecognizer = dynamic_cast<PinchGestureRecognizer*>(mGestureRecognizer.Get());
129     if( pinchRecognizer )
130     {
131       pinchRecognizer->SetMinimumPinchDistance(value);
132     }
133   }
134 }
135
136 void PinchGestureProcessor::SetMinimumTouchEvents( uint32_t value )
137 {
138   if( value > 1u && mMinimumTouchEvents != value )
139   {
140     mMinimumTouchEvents = value;
141
142     if( mGestureRecognizer )
143     {
144       PinchGestureRecognizer* pinchRecognizer = dynamic_cast<PinchGestureRecognizer*>( mGestureRecognizer.Get() );
145       if( pinchRecognizer )
146       {
147         pinchRecognizer->SetMinimumTouchEvents( value );
148       }
149     }
150   }
151 }
152
153 void PinchGestureProcessor::SetMinimumTouchEventsAfterStart( uint32_t value )
154 {
155   if( value > 1u && mMinimumTouchEventsAfterStart != value )
156   {
157     mMinimumTouchEventsAfterStart = value;
158
159     if( mGestureRecognizer )
160     {
161       PinchGestureRecognizer* pinchRecognizer = dynamic_cast<PinchGestureRecognizer*>( mGestureRecognizer.Get() );
162       if( pinchRecognizer )
163       {
164         pinchRecognizer->SetMinimumTouchEventsAfterStart( value );
165       }
166     }
167   }
168 }
169
170 void PinchGestureProcessor::Process( Scene& scene, const PinchGestureEvent& pinchEvent )
171 {
172   switch ( pinchEvent.state )
173   {
174     case Dali::Gesture::Started:
175     {
176       // The pinch gesture should only be sent to the gesture detector which first received it so that
177       // it can be told when the gesture ends as well.
178
179       mCurrentPinchEmitters.clear();
180       ResetActor();
181
182       HitTestAlgorithm::Results hitTestResults;
183       if( HitTest( scene, pinchEvent.centerPoint, hitTestResults ) )
184       {
185         // Record the current render-task for Screen->Actor coordinate conversions
186         mCurrentRenderTask = hitTestResults.renderTask;
187
188         // Set mCurrentPinchEvent to use inside overridden methods called from ProcessAndEmit()
189         mCurrentPinchEvent = &pinchEvent;
190         ProcessAndEmit( hitTestResults );
191         mCurrentPinchEvent = NULL;
192       }
193       break;
194     }
195
196     case Dali::Gesture::Continuing:
197     case Dali::Gesture::Finished:
198     case Dali::Gesture::Cancelled:
199     {
200       // Only send subsequent pinch gesture signals if we processed the pinch gesture when it started.
201       // Check if actor is still touchable.
202
203       Actor* currentGesturedActor = GetCurrentGesturedActor();
204       if ( currentGesturedActor )
205       {
206         if ( currentGesturedActor->IsHittable() && !mCurrentPinchEmitters.empty() && mCurrentRenderTask )
207         {
208           // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
209           GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
210           mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
211
212           if ( !mCurrentPinchEmitters.empty() )
213           {
214             Vector2 actorCoords;
215             RenderTask& renderTaskImpl( *mCurrentRenderTask.Get() );
216             currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, pinchEvent.centerPoint.x, pinchEvent.centerPoint.y );
217
218             EmitPinchSignal( currentGesturedActor, mCurrentPinchEmitters, pinchEvent, actorCoords );
219           }
220           else
221           {
222             // If we have no current emitters then clear pinched actor as well.
223             ResetActor();
224           }
225
226           // Clear current emitters if pinch gesture has ended or been cancelled.
227           if ( pinchEvent.state == Dali::Gesture::Finished || pinchEvent.state == Dali::Gesture::Cancelled )
228           {
229             mCurrentPinchEmitters.clear();
230             ResetActor();
231           }
232         }
233         else
234         {
235           mCurrentPinchEmitters.clear();
236           ResetActor();
237         }
238       }
239       break;
240     }
241
242     case Dali::Gesture::Clear:
243     {
244       DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
245       break;
246     }
247     case Dali::Gesture::Possible:
248     {
249       DALI_ABORT( "Incorrect state received from Integration layer: Possible\n" );
250       break;
251     }
252   }
253 }
254
255 void PinchGestureProcessor::AddGestureDetector( PinchGestureDetector* gestureDetector, Scene& scene )
256 {
257   bool createRecognizer(mPinchGestureDetectors.empty());
258
259   mPinchGestureDetectors.push_back(gestureDetector);
260
261   if (createRecognizer)
262   {
263     Size size = scene.GetSize();
264     mGestureRecognizer = new PinchGestureRecognizer( *this, Vector2(size.width, size.height), scene.GetDpi(), mMinimumPinchDistance, mMinimumTouchEventsAfterStart, mMinimumTouchEventsAfterStart );
265   }
266 }
267
268 void PinchGestureProcessor::RemoveGestureDetector( PinchGestureDetector* gestureDetector )
269 {
270   if ( !mCurrentPinchEmitters.empty() )
271   {
272     // Check if the removed detector was one that is currently being pinched and remove it from emitters.
273     GestureDetectorContainer::iterator endIter = std::remove( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), gestureDetector );
274     mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
275
276     // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
277     if ( mCurrentPinchEmitters.empty() )
278     {
279       ResetActor();
280     }
281   }
282
283   // Find the detector...
284   PinchGestureDetectorContainer::iterator endIter = std::remove( mPinchGestureDetectors.begin(), mPinchGestureDetectors.end(), gestureDetector );
285   DALI_ASSERT_DEBUG( endIter != mPinchGestureDetectors.end() );
286
287   // ...and remove it
288   mPinchGestureDetectors.erase(endIter, mPinchGestureDetectors.end());
289
290   if (mPinchGestureDetectors.empty())
291   {
292     mGestureRecognizer = nullptr;
293   }
294 }
295
296 void PinchGestureProcessor::GestureDetectorUpdated( PinchGestureDetector* gestureDetector )
297 {
298   // Nothing to do as PinchGestureDetector does not have any specific parameters.
299 }
300
301 void PinchGestureProcessor::OnGesturedActorStageDisconnection()
302 {
303   mCurrentPinchEmitters.clear();
304 }
305
306 bool PinchGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
307 {
308   // No special case required for pinch.
309   return true;
310 }
311
312 void PinchGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
313 {
314   DALI_ASSERT_DEBUG( mCurrentPinchEvent );
315
316   EmitPinchSignal( actor, gestureDetectors, *mCurrentPinchEvent, actorCoordinates );
317
318   if ( actor->OnScene() )
319   {
320     mCurrentPinchEmitters = gestureDetectors;
321     SetActor( actor );
322   }
323 }
324
325 } // namespace Internal
326
327 } // namespace Dali