Moved RotationGesture to the Public API
[platform/core/uifw/dali-core.git] / dali / internal / event / events / rotation-gesture / rotation-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/rotation-gesture/rotation-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/rotation-gesture.h>
27 #include <dali/public-api/math/vector2.h>
28 #include <dali/internal/event/events/rotation-gesture/rotation-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/rotation-gesture/rotation-gesture-recognizer.h>
33 #include <dali/internal/event/events/gesture-requests.h>
34
35 namespace Dali
36 {
37
38 namespace Internal
39 {
40
41 namespace
42 {
43 const uint32_t MINIMUM_TOUCH_EVENTS_REQUIRED = 4u;
44 const uint32_t MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START = 4u;
45
46 /**
47  * Creates a RotationGesture and asks the specified detector to emit its detected signal.
48  * @param[in]  actor             The actor that has been rotationed.
49  * @param[in]  gestureDetectors  The gesture detector container that should emit the signal.
50  * @param[in]  rotationEvent        The rotationEvent received from the adaptor.
51  * @param[in]  localCenter       Relative to the actor attached to the detector.
52  */
53 void EmitRotationSignal(
54     Actor* actor,
55     const GestureDetectorContainer& gestureDetectors,
56     const RotationGestureEvent& rotationEvent,
57     Vector2 localCenter)
58 {
59   RotationGesture rotation(rotationEvent.state);
60   rotation.time = rotationEvent.time;
61   rotation.rotation = rotationEvent.rotation;
62   rotation.screenCenterPoint = rotationEvent.centerPoint;
63   rotation.localCenterPoint = localCenter;
64
65   Dali::Actor actorHandle( actor );
66   const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
67   for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
68   {
69     static_cast< RotationGestureDetector* >( *iter )->EmitRotationGestureSignal( actorHandle, rotation );
70   }
71 }
72
73 /**
74  * Functor which checks whether the specified actor is attached to the gesture detector.
75  * It returns true if it is no longer attached.  This can be used in remove_if functions.
76  */
77 struct IsNotAttachedFunctor
78 {
79   /**
80    * Constructor
81    * @param[in]  actor  The actor to check whether it is attached.
82    */
83   IsNotAttachedFunctor(Actor* actor)
84   : actorToCheck(actor)
85   {
86   }
87
88   /**
89    * Returns true if not attached, false if it is still attached.
90    * @param[in]  detector  The detector to check.
91    * @return true, if not attached, false otherwise.
92    */
93   bool operator()(const GestureDetector* detector) const
94   {
95     return !detector->IsAttached(*actorToCheck);
96   }
97
98   Actor* actorToCheck; ///< The actor to check whether it is attached or not.
99 };
100
101 } // unnamed namespace
102
103 RotationGestureProcessor::RotationGestureProcessor()
104 : GestureProcessor( Gesture::Rotation ),
105   mRotationGestureDetectors(),
106   mCurrentRotationEmitters(),
107   mCurrentRotationEvent( nullptr ),
108   mMinimumTouchEvents( MINIMUM_TOUCH_EVENTS_REQUIRED ),
109   mMinimumTouchEventsAfterStart( MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START )
110 {
111 }
112
113 void RotationGestureProcessor::Process( Scene& scene, const RotationGestureEvent& rotationEvent )
114 {
115   switch ( rotationEvent.state )
116   {
117     case Gesture::Started:
118     {
119       // The rotation gesture should only be sent to the gesture detector which first received it so that
120       // it can be told when the gesture ends as well.
121
122       mCurrentRotationEmitters.clear();
123       ResetActor();
124
125       HitTestAlgorithm::Results hitTestResults;
126       if( HitTest( scene, rotationEvent.centerPoint, hitTestResults ) )
127       {
128         // Record the current render-task for Screen->Actor coordinate conversions
129         mCurrentRenderTask = hitTestResults.renderTask;
130
131         // Set mCurrentRotationEvent to use inside overridden methods called from ProcessAndEmit()
132         mCurrentRotationEvent = &rotationEvent;
133         ProcessAndEmit( hitTestResults );
134         mCurrentRotationEvent = NULL;
135       }
136       break;
137     }
138
139     case Gesture::Continuing:
140     case Gesture::Finished:
141     case Gesture::Cancelled:
142     {
143       // Only send subsequent rotation gesture signals if we processed the rotation gesture when it started.
144       // Check if actor is still touchable.
145
146       Actor* currentGesturedActor = GetCurrentGesturedActor();
147       if ( currentGesturedActor )
148       {
149         if ( currentGesturedActor->IsHittable() && !mCurrentRotationEmitters.empty() && mCurrentRenderTask )
150         {
151           // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
152           GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
153           mCurrentRotationEmitters.erase( endIter, mCurrentRotationEmitters.end() );
154
155           if ( !mCurrentRotationEmitters.empty() )
156           {
157             Vector2 actorCoords;
158             RenderTask& renderTaskImpl( *mCurrentRenderTask.Get() );
159             currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, rotationEvent.centerPoint.x, rotationEvent.centerPoint.y );
160
161             EmitRotationSignal( currentGesturedActor, mCurrentRotationEmitters, rotationEvent, actorCoords );
162           }
163           else
164           {
165             // If we have no current emitters then clear rotated actor as well.
166             ResetActor();
167           }
168
169           // Clear current emitters if rotation gesture has ended or been cancelled.
170           if ( rotationEvent.state == Gesture::Finished || rotationEvent.state == Gesture::Cancelled )
171           {
172             mCurrentRotationEmitters.clear();
173             ResetActor();
174           }
175         }
176         else
177         {
178           mCurrentRotationEmitters.clear();
179           ResetActor();
180         }
181       }
182       break;
183     }
184
185     case Gesture::Clear:
186     case Gesture::Possible:
187     {
188       // Nothing to do
189       break;
190     }
191   }
192 }
193
194 void RotationGestureProcessor::AddGestureDetector( RotationGestureDetector* gestureDetector, Scene& /* scene */ )
195 {
196   bool createRecognizer(mRotationGestureDetectors.empty());
197
198   mRotationGestureDetectors.push_back(gestureDetector);
199
200   if (createRecognizer)
201   {
202     mGestureRecognizer = new RotationGestureRecognizer( *this, mMinimumTouchEvents, mMinimumTouchEventsAfterStart );
203   }
204 }
205
206 void RotationGestureProcessor::RemoveGestureDetector( RotationGestureDetector* gestureDetector )
207 {
208   if ( !mCurrentRotationEmitters.empty() )
209   {
210     // Check if the removed detector was one that is currently being rotated and remove it from emitters.
211     GestureDetectorContainer::iterator endIter = std::remove( mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), gestureDetector );
212     mCurrentRotationEmitters.erase( endIter, mCurrentRotationEmitters.end() );
213
214     // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
215     if ( mCurrentRotationEmitters.empty() )
216     {
217       ResetActor();
218     }
219   }
220
221   // Find the detector...
222   RotationGestureDetectorContainer::iterator endIter = std::remove( mRotationGestureDetectors.begin(), mRotationGestureDetectors.end(), gestureDetector );
223   DALI_ASSERT_DEBUG( endIter != mRotationGestureDetectors.end() );
224
225   // ...and remove it
226   mRotationGestureDetectors.erase(endIter, mRotationGestureDetectors.end());
227
228   if (mRotationGestureDetectors.empty())
229   {
230     mGestureRecognizer = nullptr;
231   }
232 }
233
234 void RotationGestureProcessor::SetMinimumTouchEvents( uint32_t value )
235 {
236   if( value > 1u && mMinimumTouchEvents != value )
237   {
238     mMinimumTouchEvents = value;
239
240     if( mGestureRecognizer )
241     {
242       RotationGestureRecognizer* rotationRecognizer = dynamic_cast<RotationGestureRecognizer*>( mGestureRecognizer.Get() );
243       if( rotationRecognizer )
244       {
245         rotationRecognizer->SetMinimumTouchEvents( value );
246       }
247     }
248   }
249 }
250
251 void RotationGestureProcessor::SetMinimumTouchEventsAfterStart( uint32_t value )
252 {
253   if( value > 1u && mMinimumTouchEventsAfterStart != value )
254   {
255     mMinimumTouchEventsAfterStart = value;
256
257     if( mGestureRecognizer )
258     {
259       RotationGestureRecognizer* rotationRecognizer = dynamic_cast<RotationGestureRecognizer*>( mGestureRecognizer.Get() );
260       if( rotationRecognizer )
261       {
262         rotationRecognizer->SetMinimumTouchEventsAfterStart( value );
263       }
264     }
265   }
266 }
267
268 void RotationGestureProcessor::OnGesturedActorStageDisconnection()
269 {
270   mCurrentRotationEmitters.clear();
271 }
272
273 bool RotationGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
274 {
275   // No special case required for rotation.
276   return true;
277 }
278
279 void RotationGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
280 {
281   DALI_ASSERT_DEBUG( mCurrentRotationEvent );
282
283   EmitRotationSignal( actor, gestureDetectors, *mCurrentRotationEvent, actorCoordinates );
284
285   if ( actor->OnScene() )
286   {
287     mCurrentRotationEmitters = gestureDetectors;
288     SetActor( actor );
289   }
290 }
291
292 } // namespace Internal
293
294 } // namespace Dali