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