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