Add SetTapRecognizerTime
[platform/core/uifw/dali-core.git] / dali / internal / event / events / tap-gesture / tap-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/tap-gesture/tap-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/tap-gesture/tap-gesture-event.h>
31 #include <dali/internal/event/events/tap-gesture/tap-gesture-impl.h>
32 #include <dali/internal/event/events/tap-gesture/tap-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 #include <dali/public-api/events/tap-gesture.h>
37 #include <dali/public-api/math/vector2.h>
38
39 namespace Dali
40 {
41 namespace Internal
42 {
43 namespace
44 {
45 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
46 constexpr uint32_t DEFAULT_MAXIMUM_ALLOWED_TIME = 500u;
47 constexpr uint32_t DEFAULT_RECOGNIZER_TIME      = 500u;
48
49 /**
50  * Creates a TapGesture and asks the specified detector to emit its detected signal.
51  * @param[in]  actor             The actor on which a tap has occurred.
52  * @param[in]  gestureDetectors  A reference to gesture detectors that should emit the signal.
53  * @param[in]  tapEvent          The tapEvent received from the adaptor.
54  * @param[in]  localPoint        Relative to the actor attached to the detector.
55  */
56 void EmitTapSignal(
57   Actor*                          actor,
58   const GestureDetectorContainer& gestureDetectors,
59   const TapGestureEvent&          tapEvent,
60   Vector2                         localPoint)
61 {
62   Internal::TapGesturePtr tap(new Internal::TapGesture(tapEvent.state));
63   tap->SetTime(tapEvent.time);
64   tap->SetNumberOfTaps(tapEvent.numberOfTaps);
65   tap->SetNumberOfTouches(tapEvent.numberOfTouches);
66   tap->SetScreenPoint(tapEvent.point);
67   tap->SetLocalPoint(localPoint);
68   tap->SetSourceType(tapEvent.sourceType);
69   tap->SetSourceData(tapEvent.sourceData);
70
71   DALI_TRACE_SCOPE(gTraceFilter, "DALI_EMIT_TAP_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<TapGestureDetector*>(*iter)->EmitTapGestureSignal(actorHandle, Dali::TapGesture(tap.Get()));
78   }
79 }
80
81 } // unnamed namespace
82
83 TapGestureProcessor::TapGestureProcessor()
84 : GestureProcessor(GestureType::TAP),
85   mTapGestureDetectors(),
86   mMinTapsRequired(1),
87   mMaxTapsRequired(1),
88   mMinTouchesRequired(1),
89   mMaxTouchesRequired(1),
90   mCurrentTapEvent(nullptr),
91   mPossibleProcessed(false),
92   mMaximumAllowedTime(DEFAULT_MAXIMUM_ALLOWED_TIME),
93   mRecognizerTime(DEFAULT_RECOGNIZER_TIME)
94 {
95 }
96
97 TapGestureProcessor::~TapGestureProcessor() = default;
98
99 void TapGestureProcessor::Process(Scene& scene, const TapGestureEvent& tapEvent)
100 {
101   DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_TAP_GESTURE");
102   switch(tapEvent.state)
103   {
104     case GestureState::POSSIBLE:
105     {
106       // Do a hit test and if an actor has been hit then save to see if tap event is still valid on a tap( same actor being hit )
107       HitTestAlgorithm::Results hitTestResults;
108       if(HitTest(scene, tapEvent.point, hitTestResults))
109       {
110         SetActor(&GetImplementation(hitTestResults.actor));
111         mCurrentTapActor.SetActor(GetCurrentGesturedActor());
112
113         // Indicate that we've processed a touch down. Bool should be sufficient as a change in actor will result in a cancellation
114         mPossibleProcessed = true;
115       }
116       else
117       {
118         ResetActor();
119       }
120       break;
121     }
122
123     case GestureState::STARTED:
124     {
125       // Ensure that we're processing a hit on the current actor and that we've already processed a touch down
126       HitTestAlgorithm::Results hitTestResults;
127       if(GetCurrentGesturedActor() && HitTest(scene, tapEvent.point, hitTestResults) && mPossibleProcessed)
128       {
129         // Check that this actor is still the one that was used for the last touch down ?
130         if(mCurrentTapActor.GetActor() == &GetImplementation(hitTestResults.actor))
131         {
132           mCurrentTapEvent = &tapEvent;
133           ProcessAndEmit(hitTestResults);
134         }
135         mCurrentTapEvent   = nullptr;
136         mPossibleProcessed = false;
137       }
138       break;
139     }
140
141     case GestureState::CANCELLED:
142     {
143       mPossibleProcessed = false;
144       ResetActor();
145       break;
146     }
147
148     case GestureState::CONTINUING:
149     {
150       DALI_ABORT("Incorrect state received from Integration layer: CONTINUING\n");
151       break;
152     }
153     case GestureState::FINISHED:
154     {
155       DALI_ABORT("Incorrect state received from Integration layer: FINISHED\n");
156       break;
157     }
158     case GestureState::CLEAR:
159     {
160       DALI_ABORT("Incorrect state received from Integration layer: CLEAR\n");
161       break;
162     }
163   }
164 }
165
166 void TapGestureProcessor::AddGestureDetector(TapGestureDetector* gestureDetector, Scene& scene)
167 {
168   bool firstRegistration(mTapGestureDetectors.empty());
169
170   mTapGestureDetectors.push_back(gestureDetector);
171
172   const unsigned int minTapsRequired = gestureDetector->GetMinimumTapsRequired();
173   const unsigned int maxTapsRequired = gestureDetector->GetMaximumTapsRequired();
174   const unsigned int touchesRequired = gestureDetector->GetTouchesRequired();
175
176   DALI_ASSERT_ALWAYS(minTapsRequired <= maxTapsRequired && "Minimum taps requested is greater than the maximum requested");
177
178   if(firstRegistration)
179   {
180     // If this is the first tap gesture detector that has been added, then our minimum and maximum
181     // requirements are the same as each other.
182
183     mMinTapsRequired    = minTapsRequired;
184     mMaxTapsRequired    = maxTapsRequired;
185     mMinTouchesRequired = mMaxTouchesRequired = touchesRequired;
186
187     TapGestureRequest request;
188     request.minTaps    = mMinTapsRequired;
189     request.maxTaps    = mMaxTapsRequired;
190     request.minTouches = mMinTouchesRequired;
191     request.maxTouches = mMaxTouchesRequired;
192
193     Size size          = scene.GetSize();
194     mGestureRecognizer = new TapGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const TapGestureRequest&>(request), mMaximumAllowedTime, mRecognizerTime);
195   }
196   else
197   {
198     // If we have already registered for tap gesture detection before then we need to check our
199     // minimum and maximums and see if our gesture detection requirements have changed, if they
200     // have, then we should ask the adaptor to update its detection policy.
201
202     // This is quicker than calling UpdateDetection as there is no need to iterate through the container
203
204     unsigned int minTaps    = mMinTapsRequired < minTapsRequired ? mMinTapsRequired : minTapsRequired;
205     unsigned int maxTaps    = mMaxTapsRequired > maxTapsRequired ? mMaxTapsRequired : maxTapsRequired;
206     unsigned int minTouches = mMinTouchesRequired < touchesRequired ? mMinTouchesRequired : touchesRequired;
207     unsigned int maxTouches = mMaxTouchesRequired > touchesRequired ? mMaxTouchesRequired : touchesRequired;
208
209     if((minTaps != mMinTapsRequired) || (maxTaps != mMaxTapsRequired) ||
210        (minTouches != mMinTouchesRequired) || (maxTouches != mMaxTouchesRequired))
211     {
212       TapGestureRequest request;
213       request.minTaps = mMinTapsRequired = minTaps;
214       request.maxTaps = mMaxTapsRequired = maxTaps;
215       request.minTouches = mMinTouchesRequired = minTouches;
216       request.maxTouches = mMaxTouchesRequired = maxTouches;
217
218       mGestureRecognizer->Update(request);
219     }
220   }
221 }
222
223 void TapGestureProcessor::RemoveGestureDetector(TapGestureDetector* gestureDetector)
224 {
225   // Find detector ...
226   TapGestureDetectorContainer::iterator endIter = std::remove(mTapGestureDetectors.begin(), mTapGestureDetectors.end(), gestureDetector);
227   DALI_ASSERT_DEBUG(endIter != mTapGestureDetectors.end());
228
229   // ... and remove it
230   mTapGestureDetectors.erase(endIter, mTapGestureDetectors.end());
231
232   if(mTapGestureDetectors.empty())
233   {
234     mGestureRecognizer = nullptr;
235
236     ResetActor();
237   }
238   else
239   {
240     UpdateDetection();
241   }
242 }
243
244 void TapGestureProcessor::GestureDetectorUpdated(TapGestureDetector* gestureDetector)
245 {
246   DALI_ASSERT_DEBUG(find(mTapGestureDetectors.begin(), mTapGestureDetectors.end(), gestureDetector) != mTapGestureDetectors.end());
247
248   const unsigned int minTapsRequired = gestureDetector->GetMinimumTapsRequired();
249   const unsigned int maxTapsRequired = gestureDetector->GetMaximumTapsRequired();
250
251   DALI_ASSERT_ALWAYS(minTapsRequired <= maxTapsRequired && "Minimum taps requested is greater than the maximum requested");
252
253   UpdateDetection();
254 }
255
256 void TapGestureProcessor::SetMaximumAllowedTime(uint32_t time)
257 {
258   if(time == 0u)
259   {
260     DALI_LOG_WARNING("MaximumAllowedTime must be greater than zero.");
261     return;
262   }
263   if(mMaximumAllowedTime != time)
264   {
265     mMaximumAllowedTime = time;
266
267     if(mGestureRecognizer)
268     {
269       TapGestureRecognizer* tapRecognizer = dynamic_cast<TapGestureRecognizer*>(mGestureRecognizer.Get());
270       if(tapRecognizer)
271       {
272         tapRecognizer->SetMaximumAllowedTime(time);
273       }
274     }
275   }
276 }
277
278 void TapGestureProcessor::SetRecognizerTime(uint32_t time)
279 {
280   if(time == 0u)
281   {
282     DALI_LOG_WARNING("RecognizerTime must be greater than zero.");
283     return;
284   }
285   if(mRecognizerTime != time)
286   {
287     mRecognizerTime = time;
288
289     if(mGestureRecognizer)
290     {
291       TapGestureRecognizer* tapRecognizer = dynamic_cast<TapGestureRecognizer*>(mGestureRecognizer.Get());
292       if(tapRecognizer)
293       {
294         tapRecognizer->SetRecognizerTime(time);
295       }
296     }
297   }
298 }
299
300 void TapGestureProcessor::UpdateDetection()
301 {
302   DALI_ASSERT_DEBUG(!mTapGestureDetectors.empty());
303
304   unsigned int minTaps    = UINT_MAX;
305   unsigned int maxTaps    = 0;
306   unsigned int minTouches = UINT_MAX;
307   unsigned int maxTouches = 0;
308
309   for(TapGestureDetectorContainer::iterator iter = mTapGestureDetectors.begin(), endIter = mTapGestureDetectors.end(); iter != endIter; ++iter)
310   {
311     TapGestureDetector* detector(*iter);
312
313     if(detector)
314     {
315       const unsigned int minTapsRequired = detector->GetMinimumTapsRequired();
316       const unsigned int maxTapsRequired = detector->GetMaximumTapsRequired();
317       const unsigned int touchesRequired = detector->GetTouchesRequired();
318
319       minTaps    = minTapsRequired < minTaps ? minTapsRequired : minTaps;
320       maxTaps    = maxTapsRequired > maxTaps ? maxTapsRequired : maxTaps;
321       minTouches = touchesRequired < minTouches ? touchesRequired : minTouches;
322       maxTouches = touchesRequired > maxTouches ? touchesRequired : maxTouches;
323     }
324   }
325
326   if((minTaps != mMinTapsRequired) || (maxTaps != mMaxTapsRequired) ||
327      (minTouches != mMinTouchesRequired) || (maxTouches != mMaxTouchesRequired))
328   {
329     TapGestureRequest request;
330     request.minTaps = mMinTapsRequired = minTaps;
331     request.maxTaps = mMaxTapsRequired = maxTaps;
332     request.minTouches = mMinTouchesRequired = minTouches;
333     request.maxTouches = mMaxTouchesRequired = maxTouches;
334
335     mGestureRecognizer->Update(request);
336   }
337 }
338
339 bool TapGestureProcessor::CheckGestureDetector(GestureDetector* detector, Actor* actor)
340 {
341   DALI_ASSERT_DEBUG(mCurrentTapEvent);
342
343   TapGestureDetector* tapDetector(static_cast<TapGestureDetector*>(detector));
344
345   return (tapDetector->GetMinimumTapsRequired() <= mCurrentTapEvent->numberOfTaps) && (tapDetector->GetTouchesRequired() == mCurrentTapEvent->numberOfTouches);
346 }
347
348 void TapGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates)
349 {
350   DALI_ASSERT_DEBUG(mCurrentTapEvent);
351
352   EmitTapSignal(actor, gestureDetectors, *mCurrentTapEvent, actorCoordinates);
353 }
354
355 } // namespace Internal
356
357 } // namespace Dali