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