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