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