Merge "LookAt API for actor" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / events / long-press-gesture / long-press-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/long-press-gesture/long-press-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/actors/actor-impl.h>
28 #include <dali/internal/event/common/scene-impl.h>
29 #include <dali/internal/event/events/gesture-requests.h>
30 #include <dali/internal/event/events/long-press-gesture/long-press-gesture-event.h>
31 #include <dali/internal/event/events/long-press-gesture/long-press-gesture-impl.h>
32 #include <dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.h>
33 #include <dali/internal/event/render-tasks/render-task-impl.h>
34 #include <dali/public-api/actors/actor.h>
35 #include <dali/public-api/common/dali-common.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 unsigned long DEFAULT_MINIMUM_HOLDING_TIME = 500u;
45
46 /**
47  * Creates a LongPressGesture and asks the specified detector to emit its detected signal.
48  * @param[in]  actor             The actor on which the long press gesture has occurred.
49  * @param[in]  gestureDetectors  A reference to gesture detectors that should emit the signal.
50  * @param[in]  longPressEvent    The longPressEvent received from the adaptor.
51  * @param[in]  localPoint        Relative to the actor attached to the detector.
52  */
53 void EmitLongPressSignal(
54   Actor*                          actor,
55   const GestureDetectorContainer& gestureDetectors,
56   const LongPressGestureEvent&    longPressEvent,
57   Vector2                         localPoint)
58 {
59   Internal::LongPressGesturePtr longPress(new Internal::LongPressGesture(longPressEvent.state));
60   longPress->SetTime(longPressEvent.time);
61   longPress->SetNumberOfTouches(longPressEvent.numberOfTouches);
62   longPress->SetScreenPoint(longPressEvent.point);
63   longPress->SetLocalPoint(localPoint);
64   longPress->SetSourceType(longPressEvent.sourceType);
65   longPress->SetSourceData(longPressEvent.sourceData);
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<LongPressGestureDetector*>(*iter)->EmitLongPressGestureSignal(actorHandle, Dali::LongPressGesture(longPress.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 LongPressGestureProcessor::LongPressGestureProcessor()
106 : GestureProcessor(GestureType::LONG_PRESS),
107   mLongPressGestureDetectors(),
108   mCurrentEmitters(),
109   mCurrentRenderTask(),
110   mMinTouchesRequired(1),
111   mMaxTouchesRequired(1),
112   mCurrentLongPressEvent(nullptr),
113   mMinimumHoldingTime(DEFAULT_MINIMUM_HOLDING_TIME)
114 {
115 }
116
117 LongPressGestureProcessor::~LongPressGestureProcessor() = default;
118
119 void LongPressGestureProcessor::Process(Scene& scene, const LongPressGestureEvent& longPressEvent)
120 {
121   DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_LONG_PRESS_GESTURE");
122   switch(longPressEvent.state)
123   {
124     case GestureState::POSSIBLE:
125     {
126       mCurrentEmitters.clear();
127       ResetActor();
128
129       HitTestAlgorithm::Results hitTestResults;
130       if(HitTest(scene, longPressEvent.point, hitTestResults))
131       {
132         SetActor(&GetImplementation(hitTestResults.actor));
133       }
134       break;
135     }
136
137     case GestureState::STARTED:
138     {
139       Actor* currentGesturedActor = GetCurrentGesturedActor();
140       if(currentGesturedActor)
141       {
142         HitTestAlgorithm::Results hitTestResults;
143         HitTest(scene, longPressEvent.point, hitTestResults);
144
145         if(hitTestResults.actor && (currentGesturedActor == &GetImplementation(hitTestResults.actor)))
146         {
147           // Record the current render-task for Screen->Actor coordinate conversions
148           mCurrentRenderTask = hitTestResults.renderTask;
149
150           // Set mCurrentLongPressEvent to use inside overridden methods called from ProcessAndEmit()
151           mCurrentLongPressEvent = &longPressEvent;
152           ProcessAndEmit(hitTestResults);
153           mCurrentLongPressEvent = nullptr;
154         }
155         else
156         {
157           mCurrentEmitters.clear();
158           ResetActor();
159         }
160       }
161       break;
162     }
163
164     case GestureState::FINISHED:
165     {
166       // The gesture should only be sent to the gesture detector which first received it so that it
167       // can be told when the gesture ends as well.
168
169       // Only send subsequent long press gesture signals if we processed the gesture when it started.
170       // Check if actor is still touchable.
171
172       Actor* currentGesturedActor = GetCurrentGesturedActor();
173       if(currentGesturedActor)
174       {
175         if(currentGesturedActor->IsHittable() && !mCurrentEmitters.empty() && mCurrentRenderTask)
176         {
177           // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
178           GestureDetectorContainer::iterator endIter = std::remove_if(mCurrentEmitters.begin(), mCurrentEmitters.end(), IsNotAttachedFunctor(currentGesturedActor));
179           mCurrentEmitters.erase(endIter, mCurrentEmitters.end());
180
181           if(!mCurrentEmitters.empty())
182           {
183             Vector2     actorCoords;
184             RenderTask& renderTaskImpl = *mCurrentRenderTask.Get();
185             currentGesturedActor->ScreenToLocal(renderTaskImpl, actorCoords.x, actorCoords.y, longPressEvent.point.x, longPressEvent.point.y);
186
187             EmitLongPressSignal(currentGesturedActor, mCurrentEmitters, longPressEvent, actorCoords);
188           }
189         }
190
191         // Clear current emitters and emitted actor
192         mCurrentEmitters.clear();
193         ResetActor();
194       }
195       break;
196     }
197
198     case GestureState::CANCELLED:
199     {
200       mCurrentEmitters.clear();
201       ResetActor();
202       break;
203     }
204
205     case GestureState::CONTINUING:
206     {
207       DALI_ABORT("Incorrect state received from Integration layer: CONTINUING\n");
208       break;
209     }
210
211     case GestureState::CLEAR:
212     {
213       DALI_ABORT("Incorrect state received from Integration layer: CLEAR\n");
214       break;
215     }
216   }
217 }
218
219 void LongPressGestureProcessor::AddGestureDetector(LongPressGestureDetector* gestureDetector, Scene& scene)
220 {
221   bool firstRegistration(mLongPressGestureDetectors.empty());
222
223   mLongPressGestureDetectors.push_back(gestureDetector);
224
225   if(firstRegistration)
226   {
227     mMinTouchesRequired = gestureDetector->GetMinimumTouchesRequired();
228     mMaxTouchesRequired = gestureDetector->GetMaximumTouchesRequired();
229
230     LongPressGestureRequest request;
231     request.minTouches = mMinTouchesRequired;
232     request.maxTouches = mMaxTouchesRequired;
233
234     Size size = scene.GetSize();
235
236     mGestureRecognizer = new LongPressGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const LongPressGestureRequest&>(request), mMinimumHoldingTime);
237   }
238   else
239   {
240     UpdateDetection();
241   }
242 }
243
244 void LongPressGestureProcessor::RemoveGestureDetector(LongPressGestureDetector* gestureDetector)
245 {
246   // Find detector ...
247   LongPressGestureDetectorContainer::iterator endIter = std::remove(mLongPressGestureDetectors.begin(), mLongPressGestureDetectors.end(), gestureDetector);
248   DALI_ASSERT_DEBUG(endIter != mLongPressGestureDetectors.end());
249
250   // ... and remove it
251   mLongPressGestureDetectors.erase(endIter, mLongPressGestureDetectors.end());
252
253   if(mLongPressGestureDetectors.empty())
254   {
255     mGestureRecognizer = nullptr;
256   }
257   else
258   {
259     UpdateDetection();
260   }
261 }
262
263 void LongPressGestureProcessor::GestureDetectorUpdated(LongPressGestureDetector* gestureDetector)
264 {
265   DALI_ASSERT_DEBUG(find(mLongPressGestureDetectors.begin(), mLongPressGestureDetectors.end(), gestureDetector) != mLongPressGestureDetectors.end());
266
267   UpdateDetection();
268 }
269
270 void LongPressGestureProcessor::SetMinimumHoldingTime(uint32_t time)
271 {
272   if(time > 0u && mMinimumHoldingTime != time)
273   {
274     mMinimumHoldingTime = time;
275
276     if(mGestureRecognizer)
277     {
278       LongPressGestureRecognizer* longPressRecognizer = dynamic_cast<LongPressGestureRecognizer*>(mGestureRecognizer.Get());
279       if(longPressRecognizer)
280       {
281         longPressRecognizer->SetMinimumHoldingTime(time);
282       }
283     }
284   }
285 }
286
287 uint32_t LongPressGestureProcessor::GetMinimumHoldingTime() const
288 {
289   return mMinimumHoldingTime;
290 }
291
292 void LongPressGestureProcessor::UpdateDetection()
293 {
294   DALI_ASSERT_DEBUG(!mLongPressGestureDetectors.empty());
295
296   unsigned int minimumRequired = UINT_MAX;
297   unsigned int maximumRequired = 0;
298
299   for(LongPressGestureDetectorContainer::iterator iter = mLongPressGestureDetectors.begin(), endIter = mLongPressGestureDetectors.end(); iter != endIter; ++iter)
300   {
301     LongPressGestureDetector* current(*iter);
302
303     if(current)
304     {
305       unsigned int minimum = current->GetMinimumTouchesRequired();
306       if(minimum < minimumRequired)
307       {
308         minimumRequired = minimum;
309       }
310
311       unsigned int maximum = current->GetMaximumTouchesRequired();
312       if(maximum > maximumRequired)
313       {
314         maximumRequired = maximum;
315       }
316     }
317   }
318
319   if((minimumRequired != mMinTouchesRequired) || (maximumRequired != mMaxTouchesRequired))
320   {
321     mMinTouchesRequired = minimumRequired;
322     mMaxTouchesRequired = maximumRequired;
323
324     LongPressGestureRequest request;
325     request.minTouches = mMinTouchesRequired;
326     request.maxTouches = mMaxTouchesRequired;
327     mGestureRecognizer->Update(request);
328   }
329 }
330
331 void LongPressGestureProcessor::OnGesturedActorStageDisconnection()
332 {
333   mCurrentEmitters.clear();
334 }
335
336 bool LongPressGestureProcessor::CheckGestureDetector(GestureDetector* detector, Actor* actor)
337 {
338   DALI_ASSERT_DEBUG(mCurrentLongPressEvent);
339
340   LongPressGestureDetector* longPressDetector(static_cast<LongPressGestureDetector*>(detector));
341
342   return (longPressDetector->GetMinimumTouchesRequired() <= mCurrentLongPressEvent->numberOfTouches) &&
343          (longPressDetector->GetMaximumTouchesRequired() >= mCurrentLongPressEvent->numberOfTouches);
344 }
345
346 void LongPressGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates)
347 {
348   DALI_ASSERT_DEBUG(mCurrentLongPressEvent);
349
350   mCurrentEmitters.clear();
351   ResetActor();
352
353   EmitLongPressSignal(actor, gestureDetectors, *mCurrentLongPressEvent, actorCoordinates);
354
355   if(actor->OnScene())
356   {
357     mCurrentEmitters = gestureDetectors;
358     SetActor(actor);
359   }
360 }
361
362 } // namespace Internal
363
364 } // namespace Dali