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