111e7c1bead674655883ce9bffa81d2f43a1c03a
[platform/core/uifw/dali-core.git] / dali / internal / event / events / rotation-gesture / rotation-gesture-processor.cpp
1 /*
2  * Copyright (c) 2023 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/integration-api/debug.h>
26 #include <dali/integration-api/trace.h>
27 #include <dali/internal/event/common/scene-impl.h>
28 #include <dali/internal/event/events/gesture-requests.h>
29 #include <dali/internal/event/events/rotation-gesture/rotation-gesture-event.h>
30 #include <dali/internal/event/events/rotation-gesture/rotation-gesture-impl.h>
31 #include <dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.h>
32 #include <dali/internal/event/render-tasks/render-task-impl.h>
33 #include <dali/public-api/actors/actor.h>
34 #include <dali/public-api/events/rotation-gesture.h>
35 #include <dali/public-api/math/vector2.h>
36
37 namespace Dali
38 {
39 namespace Internal
40 {
41 namespace
42 {
43 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
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   rotation->SetSourceType(rotationEvent.sourceType);
66   rotation->SetSourceData(rotationEvent.sourceData);
67
68   DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_EMIT_ROTATION_GESTURE_SIGNAL", [&](std::ostringstream& oss) {
69     oss << "[" << gestureDetectors.size() << "]";
70   });
71
72   Dali::Actor                                    actorHandle(actor);
73   const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
74   for(GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter)
75   {
76     static_cast<RotationGestureDetector*>(*iter)->EmitRotationGestureSignal(actorHandle, Dali::RotationGesture(rotation.Get()));
77   }
78
79   DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_EMIT_ROTATION_GESTURE_SIGNAL", [&](std::ostringstream& oss) {
80     oss << "[" << gestureDetectors.size() << "]";
81   });
82 }
83
84 /**
85  * Functor which checks whether the specified actor is attached to the gesture detector.
86  * It returns true if it is no longer attached.  This can be used in remove_if functions.
87  */
88 struct IsNotAttachedFunctor
89 {
90   /**
91    * Constructor
92    * @param[in]  actor  The actor to check whether it is attached.
93    */
94   IsNotAttachedFunctor(Actor* actor)
95   : actorToCheck(actor)
96   {
97   }
98
99   /**
100    * Returns true if not attached, false if it is still attached.
101    * @param[in]  detector  The detector to check.
102    * @return true, if not attached, false otherwise.
103    */
104   bool operator()(const GestureDetector* detector) const
105   {
106     return !detector->IsAttached(*actorToCheck);
107   }
108
109   Actor* actorToCheck; ///< The actor to check whether it is attached or not.
110 };
111
112 } // unnamed namespace
113
114 RotationGestureProcessor::RotationGestureProcessor()
115 : GestureProcessor(GestureType::ROTATION),
116   mRotationGestureDetectors(),
117   mCurrentRotationEmitters(),
118   mCurrentRotationEvent(nullptr),
119   mMinimumTouchEvents(MINIMUM_TOUCH_EVENTS_REQUIRED),
120   mMinimumTouchEventsAfterStart(MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START)
121 {
122 }
123
124 void RotationGestureProcessor::Process(Scene& scene, const RotationGestureEvent& rotationEvent, Actor* actor)
125 {
126   DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_ROTATION_GESTURE");
127   switch(rotationEvent.state)
128   {
129     case GestureState::STARTED:
130     {
131       // The rotation gesture should only be sent to the gesture detector which first received it so that
132       // it can be told when the gesture ends as well.
133
134       mCurrentRotationEmitters.clear();
135       ResetActor();
136
137       HitTestAlgorithm::Results hitTestResults;
138       if(actor)
139       {
140         hitTestResults.actor = Dali::Actor(actor);
141         hitTestResults.renderTask = rotationEvent.renderTask;
142
143         // Record the current render-task for Screen->Actor coordinate conversions
144         mCurrentRenderTask = hitTestResults.renderTask;
145
146         Vector2     actorCoords;
147         actor->ScreenToLocal(*mCurrentRenderTask.Get(), actorCoords.x, actorCoords.y, rotationEvent.centerPoint.x, rotationEvent.centerPoint.y);
148         hitTestResults.actorCoordinates = actorCoords;
149
150         // Set mCurrentRotationEvent to use inside overridden methods called from ProcessAndEmit()
151         mCurrentRotationEvent = &rotationEvent;
152         ProcessAndEmitActor(hitTestResults);
153         mCurrentRotationEvent = nullptr;
154
155       }
156       else if(HitTest(scene, rotationEvent.centerPoint, hitTestResults))
157       {
158         // Record the current render-task for Screen->Actor coordinate conversions
159         mCurrentRenderTask = hitTestResults.renderTask;
160
161         // Set mCurrentRotationEvent to use inside overridden methods called from ProcessAndEmit()
162         mCurrentRotationEvent = &rotationEvent;
163         ProcessAndEmit(hitTestResults);
164         mCurrentRotationEvent = nullptr;
165       }
166       break;
167     }
168
169     case GestureState::CONTINUING:
170     case GestureState::FINISHED:
171     case GestureState::CANCELLED:
172     {
173       // Only send subsequent rotation gesture signals if we processed the rotation gesture when it started.
174       // Check if actor is still touchable.
175
176       Actor* currentGesturedActor = GetCurrentGesturedActor();
177       if(currentGesturedActor)
178       {
179         if(currentGesturedActor->IsHittable() && !mCurrentRotationEmitters.empty() && mCurrentRenderTask)
180         {
181           // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
182           GestureDetectorContainer::iterator endIter = std::remove_if(mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), IsNotAttachedFunctor(currentGesturedActor));
183           mCurrentRotationEmitters.erase(endIter, mCurrentRotationEmitters.end());
184
185           if(!mCurrentRotationEmitters.empty())
186           {
187             Vector2     actorCoords;
188             RenderTask& renderTaskImpl(*mCurrentRenderTask.Get());
189             currentGesturedActor->ScreenToLocal(renderTaskImpl, actorCoords.x, actorCoords.y, rotationEvent.centerPoint.x, rotationEvent.centerPoint.y);
190
191             EmitRotationSignal(currentGesturedActor, mCurrentRotationEmitters, rotationEvent, actorCoords);
192           }
193           else
194           {
195             // If we have no current emitters then clear rotated actor as well.
196             ResetActor();
197           }
198
199           // Clear current emitters if rotation gesture has ended or been cancelled.
200           if(rotationEvent.state == GestureState::FINISHED || rotationEvent.state == GestureState::CANCELLED)
201           {
202             mCurrentRotationEmitters.clear();
203             ResetActor();
204           }
205         }
206         else
207         {
208           mCurrentRotationEmitters.clear();
209           ResetActor();
210         }
211       }
212       break;
213     }
214
215     case GestureState::CLEAR:
216     case GestureState::POSSIBLE:
217     {
218       // Nothing to do
219       break;
220     }
221   }
222 }
223
224 void RotationGestureProcessor::AddGestureDetector(RotationGestureDetector* gestureDetector, Scene& /* scene */)
225 {
226   bool createRecognizer(mRotationGestureDetectors.empty());
227
228   mRotationGestureDetectors.push_back(gestureDetector);
229
230   if(createRecognizer)
231   {
232     mGestureRecognizer = new RotationGestureRecognizer(*this, mMinimumTouchEvents, mMinimumTouchEventsAfterStart);
233   }
234 }
235
236 void RotationGestureProcessor::RemoveGestureDetector(RotationGestureDetector* gestureDetector)
237 {
238   if(!mCurrentRotationEmitters.empty())
239   {
240     // Check if the removed detector was one that is currently being rotated and remove it from emitters.
241     GestureDetectorContainer::iterator endIter = std::remove(mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), gestureDetector);
242     mCurrentRotationEmitters.erase(endIter, mCurrentRotationEmitters.end());
243
244     // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
245     if(mCurrentRotationEmitters.empty())
246     {
247       ResetActor();
248     }
249   }
250
251   // Find the detector...
252   RotationGestureDetectorContainer::iterator endIter = std::remove(mRotationGestureDetectors.begin(), mRotationGestureDetectors.end(), gestureDetector);
253   DALI_ASSERT_DEBUG(endIter != mRotationGestureDetectors.end());
254
255   // ...and remove it
256   mRotationGestureDetectors.erase(endIter, mRotationGestureDetectors.end());
257
258   if(mRotationGestureDetectors.empty())
259   {
260     mGestureRecognizer = nullptr;
261   }
262 }
263
264 void RotationGestureProcessor::SetMinimumTouchEvents(uint32_t value)
265 {
266   if(value > 1u && mMinimumTouchEvents != value)
267   {
268     mMinimumTouchEvents = value;
269
270     if(mGestureRecognizer)
271     {
272       RotationGestureRecognizer* rotationRecognizer = dynamic_cast<RotationGestureRecognizer*>(mGestureRecognizer.Get());
273       if(rotationRecognizer)
274       {
275         rotationRecognizer->SetMinimumTouchEvents(value);
276       }
277     }
278   }
279 }
280
281 void RotationGestureProcessor::SetMinimumTouchEventsAfterStart(uint32_t value)
282 {
283   if(value > 1u && mMinimumTouchEventsAfterStart != value)
284   {
285     mMinimumTouchEventsAfterStart = value;
286
287     if(mGestureRecognizer)
288     {
289       RotationGestureRecognizer* rotationRecognizer = dynamic_cast<RotationGestureRecognizer*>(mGestureRecognizer.Get());
290       if(rotationRecognizer)
291       {
292         rotationRecognizer->SetMinimumTouchEventsAfterStart(value);
293       }
294     }
295   }
296 }
297
298 void RotationGestureProcessor::OnGesturedActorStageDisconnection()
299 {
300   mCurrentRotationEmitters.clear();
301 }
302
303 bool RotationGestureProcessor::CheckGestureDetector(GestureDetector* detector, Actor* actor)
304 {
305   // No special case required for rotation.
306   return true;
307 }
308
309 void RotationGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates)
310 {
311   DALI_ASSERT_DEBUG(mCurrentRotationEvent);
312
313   EmitRotationSignal(actor, gestureDetectors, *mCurrentRotationEvent, actorCoordinates);
314
315   if(actor->OnScene())
316   {
317     mCurrentRotationEmitters = gestureDetectors;
318     SetActor(actor);
319   }
320 }
321
322 } // namespace Internal
323
324 } // namespace Dali