Merge "Clean up the code to build successfully on macOS" into devel/master
[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( GestureType::PINCH ),
109   mPinchGestureDetectors(),
110   mCurrentPinchEmitters(),
111   mCurrentPinchEvent(nullptr),
112   mMinimumPinchDistance(-1.0f),
113   mMinimumTouchEvents( MINIMUM_TOUCH_EVENTS_REQUIRED ),
114   mMinimumTouchEventsAfterStart( MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START )
115 {
116 }
117
118 PinchGestureProcessor::~PinchGestureProcessor() = default;
119
120 void PinchGestureProcessor::SetMinimumPinchDistance( float value )
121 {
122   mMinimumPinchDistance = value;
123
124   if( mGestureRecognizer )
125   {
126     PinchGestureRecognizer* pinchRecognizer = dynamic_cast<PinchGestureRecognizer*>(mGestureRecognizer.Get());
127     if( pinchRecognizer )
128     {
129       pinchRecognizer->SetMinimumPinchDistance(value);
130     }
131   }
132 }
133
134 void PinchGestureProcessor::SetMinimumTouchEvents( uint32_t value )
135 {
136   if( value > 1u && mMinimumTouchEvents != value )
137   {
138     mMinimumTouchEvents = value;
139
140     if( mGestureRecognizer )
141     {
142       PinchGestureRecognizer* pinchRecognizer = dynamic_cast<PinchGestureRecognizer*>( mGestureRecognizer.Get() );
143       if( pinchRecognizer )
144       {
145         pinchRecognizer->SetMinimumTouchEvents( value );
146       }
147     }
148   }
149 }
150
151 void PinchGestureProcessor::SetMinimumTouchEventsAfterStart( uint32_t value )
152 {
153   if( value > 1u && mMinimumTouchEventsAfterStart != value )
154   {
155     mMinimumTouchEventsAfterStart = value;
156
157     if( mGestureRecognizer )
158     {
159       PinchGestureRecognizer* pinchRecognizer = dynamic_cast<PinchGestureRecognizer*>( mGestureRecognizer.Get() );
160       if( pinchRecognizer )
161       {
162         pinchRecognizer->SetMinimumTouchEventsAfterStart( value );
163       }
164     }
165   }
166 }
167
168 void PinchGestureProcessor::Process( Scene& scene, const PinchGestureEvent& pinchEvent )
169 {
170   switch ( pinchEvent.state )
171   {
172     case GestureState::STARTED:
173     {
174       // The pinch gesture should only be sent to the gesture detector which first received it so that
175       // it can be told when the gesture ends as well.
176
177       mCurrentPinchEmitters.clear();
178       ResetActor();
179
180       HitTestAlgorithm::Results hitTestResults;
181       if( HitTest( scene, pinchEvent.centerPoint, hitTestResults ) )
182       {
183         // Record the current render-task for Screen->Actor coordinate conversions
184         mCurrentRenderTask = hitTestResults.renderTask;
185
186         // Set mCurrentPinchEvent to use inside overridden methods called from ProcessAndEmit()
187         mCurrentPinchEvent = &pinchEvent;
188         ProcessAndEmit( hitTestResults );
189         mCurrentPinchEvent = nullptr;
190       }
191       break;
192     }
193
194     case GestureState::CONTINUING:
195     case GestureState::FINISHED:
196     case GestureState::CANCELLED:
197     {
198       // Only send subsequent pinch gesture signals if we processed the pinch gesture when it started.
199       // Check if actor is still touchable.
200
201       Actor* currentGesturedActor = GetCurrentGesturedActor();
202       if ( currentGesturedActor )
203       {
204         if ( currentGesturedActor->IsHittable() && !mCurrentPinchEmitters.empty() && mCurrentRenderTask )
205         {
206           // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
207           GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
208           mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
209
210           if ( !mCurrentPinchEmitters.empty() )
211           {
212             Vector2 actorCoords;
213             RenderTask& renderTaskImpl( *mCurrentRenderTask.Get() );
214             currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, pinchEvent.centerPoint.x, pinchEvent.centerPoint.y );
215
216             EmitPinchSignal( currentGesturedActor, mCurrentPinchEmitters, pinchEvent, actorCoords );
217           }
218           else
219           {
220             // If we have no current emitters then clear pinched actor as well.
221             ResetActor();
222           }
223
224           // Clear current emitters if pinch gesture has ended or been cancelled.
225           if ( pinchEvent.state == GestureState::FINISHED || pinchEvent.state == GestureState::CANCELLED )
226           {
227             mCurrentPinchEmitters.clear();
228             ResetActor();
229           }
230         }
231         else
232         {
233           mCurrentPinchEmitters.clear();
234           ResetActor();
235         }
236       }
237       break;
238     }
239
240     case GestureState::CLEAR:
241     {
242       DALI_ABORT( "Incorrect state received from Integration layer: CLEAR\n" );
243       break;
244     }
245     case GestureState::POSSIBLE:
246     {
247       DALI_ABORT( "Incorrect state received from Integration layer: POSSIBLE\n" );
248       break;
249     }
250   }
251 }
252
253 void PinchGestureProcessor::AddGestureDetector( PinchGestureDetector* gestureDetector, Scene& scene )
254 {
255   bool createRecognizer(mPinchGestureDetectors.empty());
256
257   mPinchGestureDetectors.push_back(gestureDetector);
258
259   if (createRecognizer)
260   {
261     Size size = scene.GetSize();
262     mGestureRecognizer = new PinchGestureRecognizer( *this, Vector2(size.width, size.height), scene.GetDpi(), mMinimumPinchDistance, mMinimumTouchEventsAfterStart, mMinimumTouchEventsAfterStart );
263   }
264 }
265
266 void PinchGestureProcessor::RemoveGestureDetector( PinchGestureDetector* gestureDetector )
267 {
268   if ( !mCurrentPinchEmitters.empty() )
269   {
270     // Check if the removed detector was one that is currently being pinched and remove it from emitters.
271     GestureDetectorContainer::iterator endIter = std::remove( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), gestureDetector );
272     mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
273
274     // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
275     if ( mCurrentPinchEmitters.empty() )
276     {
277       ResetActor();
278     }
279   }
280
281   // Find the detector...
282   PinchGestureDetectorContainer::iterator endIter = std::remove( mPinchGestureDetectors.begin(), mPinchGestureDetectors.end(), gestureDetector );
283   DALI_ASSERT_DEBUG( endIter != mPinchGestureDetectors.end() );
284
285   // ...and remove it
286   mPinchGestureDetectors.erase(endIter, mPinchGestureDetectors.end());
287
288   if (mPinchGestureDetectors.empty())
289   {
290     mGestureRecognizer = nullptr;
291   }
292 }
293
294 void PinchGestureProcessor::GestureDetectorUpdated( PinchGestureDetector* gestureDetector )
295 {
296   // Nothing to do as PinchGestureDetector does not have any specific parameters.
297 }
298
299 void PinchGestureProcessor::OnGesturedActorStageDisconnection()
300 {
301   mCurrentPinchEmitters.clear();
302 }
303
304 bool PinchGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
305 {
306   // No special case required for pinch.
307   return true;
308 }
309
310 void PinchGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
311 {
312   DALI_ASSERT_DEBUG( mCurrentPinchEvent );
313
314   EmitPinchSignal( actor, gestureDetectors, *mCurrentPinchEvent, actorCoordinates );
315
316   if ( actor->OnScene() )
317   {
318     mCurrentPinchEmitters = gestureDetectors;
319     SetActor( actor );
320   }
321 }
322
323 } // namespace Internal
324
325 } // namespace Dali