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