[dali_2.3.27] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / event / events / pan-gesture / pan-gesture-detector-impl.cpp
1 /*
2  * Copyright (c) 2022 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/pan-gesture/pan-gesture-detector-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/debug.h>
26 #include <dali/internal/event/actors/actor-impl.h>
27 #include <dali/internal/event/common/property-helper.h>
28 #include <dali/internal/event/common/thread-local-storage.h>
29 #include <dali/internal/event/events/gesture-event-processor.h>
30 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
31 #include <dali/public-api/events/pan-gesture.h>
32 #include <dali/public-api/math/degree.h>
33 #include <dali/public-api/math/radian.h>
34 #include <dali/public-api/object/type-registry.h>
35
36 namespace Dali
37 {
38 namespace Internal
39 {
40 namespace
41 {
42 // Properties
43
44 //              Name                  Type   writable animatable constraint-input  enum for index-checking
45 DALI_PROPERTY_TABLE_BEGIN
46 DALI_PROPERTY("screenPosition", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::SCREEN_POSITION)
47 DALI_PROPERTY("screenDisplacement", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::SCREEN_DISPLACEMENT)
48 DALI_PROPERTY("screenVelocity", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::SCREEN_VELOCITY)
49 DALI_PROPERTY("localPosition", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::LOCAL_POSITION)
50 DALI_PROPERTY("localDisplacement", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::LOCAL_DISPLACEMENT)
51 DALI_PROPERTY("localVelocity", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::LOCAL_VELOCITY)
52 DALI_PROPERTY("panning", BOOLEAN, false, false, true, Dali::PanGestureDetector::Property::PANNING)
53 DALI_PROPERTY_TABLE_END(DEFAULT_GESTURE_DETECTOR_PROPERTY_START_INDEX, PanGestureDetectorDefaultProperties)
54
55 // Signals
56
57 const char* const SIGNAL_PAN_DETECTED = "panDetected";
58
59 BaseHandle Create()
60 {
61   return Dali::PanGestureDetector::New();
62 }
63
64 TypeRegistration mType(typeid(Dali::PanGestureDetector), typeid(Dali::GestureDetector), Create, PanGestureDetectorDefaultProperties);
65
66 SignalConnectorType signalConnector1(mType, SIGNAL_PAN_DETECTED, &PanGestureDetector::DoConnectSignal);
67
68 #if defined(DEBUG_ENABLED)
69 Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_PAN_GESTURE_DETECTOR");
70 #endif
71
72 /**
73  * Returns the angle going in the opposite direction to that specified by angle.
74  */
75 float GetOppositeAngle(float angle)
76 {
77   // Calculate the opposite angle so that we cover both directions.
78   if(angle <= 0.0f)
79   {
80     angle += Math::PI;
81   }
82   else
83   {
84     angle -= Math::PI;
85   }
86
87   return angle;
88 }
89
90 } // unnamed namespace
91
92 PanGestureDetectorPtr PanGestureDetector::New()
93 {
94   const SceneGraph::PanGesture& sceneObject = ThreadLocalStorage::Get().GetGestureEventProcessor().GetPanGestureProcessor().GetSceneObject();
95   return new PanGestureDetector(sceneObject);
96 }
97
98 void PanGestureDetector::SetMinimumTouchesRequired(uint32_t minimum)
99 {
100   DALI_ASSERT_ALWAYS(minimum > 0 && "Can only set a positive number of required touches");
101
102   if(mMinimumTouches != minimum)
103   {
104     DALI_LOG_INFO(gLogFilter, Debug::Concise, "Minimum Touches Set: %u\n", minimum);
105
106     mMinimumTouches = minimum;
107
108     if(!mAttachedActors.empty())
109     {
110       DALI_LOG_INFO(gLogFilter, Debug::General, "Updating Gesture Detector\n");
111
112       mGestureEventProcessor.GestureDetectorUpdated(this);
113     }
114   }
115 }
116
117 void PanGestureDetector::SetMaximumTouchesRequired(uint32_t maximum)
118 {
119   DALI_ASSERT_ALWAYS(maximum > 0 && "Can only set a positive number of maximum touches");
120
121   if(mMaximumTouches != maximum)
122   {
123     DALI_LOG_INFO(gLogFilter, Debug::Concise, "Maximum Touches Set: %u\n", maximum);
124
125     mMaximumTouches = maximum;
126
127     if(!mAttachedActors.empty())
128     {
129       DALI_LOG_INFO(gLogFilter, Debug::General, "Updating Gesture Detector\n");
130
131       mGestureEventProcessor.GestureDetectorUpdated(this);
132     }
133   }
134 }
135
136 void PanGestureDetector::SetMaximumMotionEventAge(uint32_t maximumAge)
137 {
138   if(mMaximumMotionEventAge != maximumAge)
139   {
140     DALI_LOG_INFO(gLogFilter, Debug::Concise, "Maximum Motion Age Set: %u ms\n", maximumAge);
141
142     mMaximumMotionEventAge = maximumAge;
143
144     if(!mAttachedActors.empty())
145     {
146       DALI_LOG_INFO(gLogFilter, Debug::General, "Updating Gesture Detector\n");
147
148       mGestureEventProcessor.GestureDetectorUpdated(this);
149     }
150   }
151 }
152
153 uint32_t PanGestureDetector::GetMinimumTouchesRequired() const
154 {
155   return mMinimumTouches;
156 }
157
158 uint32_t PanGestureDetector::GetMaximumTouchesRequired() const
159 {
160   return mMaximumTouches;
161 }
162
163 uint32_t PanGestureDetector::GetMaximumMotionEventAge() const
164 {
165   return mMaximumMotionEventAge;
166 }
167
168 void PanGestureDetector::AddAngle(Radian angle, Radian threshold)
169 {
170   threshold = fabsf(threshold); // Ensure the threshold is positive.
171
172   // If the threshold is greater than PI, then just use PI
173   // This means that any panned angle will invoke the pan gesture. We should still add this angle as
174   // an angle may have been added previously with a small threshold.
175   if(threshold > Math::PI)
176   {
177     threshold = Math::PI;
178   }
179
180   angle = WrapInDomain(angle, -Math::PI, Math::PI);
181
182   DALI_LOG_INFO(gLogFilter, Debug::Concise, "Angle Added: %.2f, Threshold: %.2f\n", Degree(angle), Degree(threshold));
183
184   AngleThresholdPair pair(angle, threshold);
185   mAngleContainer.push_back(pair);
186 }
187
188 void PanGestureDetector::AddDirection(Radian direction, Radian threshold)
189 {
190   AddAngle(direction, threshold);
191
192   // Calculate the opposite angle so that we cover the entire direction.
193   direction = GetOppositeAngle(direction);
194
195   AddAngle(direction, threshold);
196 }
197
198 uint32_t PanGestureDetector::GetAngleCount() const
199 {
200   return static_cast<uint32_t>(mAngleContainer.size());
201 }
202
203 PanGestureDetector::AngleThresholdPair PanGestureDetector::GetAngle(uint32_t index) const
204 {
205   PanGestureDetector::AngleThresholdPair ret(Radian(0), Radian(0));
206
207   if(index < mAngleContainer.size())
208   {
209     ret = mAngleContainer[index];
210   }
211
212   return ret;
213 }
214
215 void PanGestureDetector::ClearAngles()
216 {
217   mAngleContainer.clear();
218 }
219
220 void PanGestureDetector::RemoveAngle(Radian angle)
221 {
222   angle = WrapInDomain(angle, -Math::PI, Math::PI);
223
224   for(AngleContainer::iterator iter = mAngleContainer.begin(), endIter = mAngleContainer.end(); iter != endIter; ++iter)
225   {
226     if(iter->first == angle)
227     {
228       mAngleContainer.erase(iter);
229       break;
230     }
231   }
232 }
233
234 void PanGestureDetector::RemoveDirection(Radian direction)
235 {
236   RemoveAngle(direction);
237
238   // Calculate the opposite angle so that we cover the entire direction.
239   direction = GetOppositeAngle(direction);
240
241   RemoveAngle(direction);
242 }
243
244 bool PanGestureDetector::RequiresDirectionalPan() const
245 {
246   // If no directional angles have been added to the container then we do not require directional panning
247   return !mAngleContainer.empty();
248 }
249
250 bool PanGestureDetector::CheckAngleAllowed(Radian angle) const
251 {
252   bool allowed(false);
253   if(mAngleContainer.empty())
254   {
255     allowed = true;
256   }
257   else
258   {
259     for(AngleContainer::const_iterator iter = mAngleContainer.begin(), endIter = mAngleContainer.end(); iter != endIter; ++iter)
260     {
261       float angleAllowed(iter->first);
262       float threshold(iter->second);
263
264       DALI_LOG_INFO(gLogFilter, Debug::General, "AngleToCheck: %.2f, CompareWith: %.2f, Threshold: %.2f\n", Degree(angle), Degree(angleAllowed), Degree(threshold));
265
266       float relativeAngle(fabsf(WrapInDomain(angle - angleAllowed, -Math::PI, Math::PI)));
267       if(relativeAngle <= threshold)
268       {
269         allowed = true;
270         break;
271       }
272     }
273   }
274
275   return allowed;
276 }
277
278 void PanGestureDetector::EmitPanGestureSignal(Dali::Actor actor, const Dali::PanGesture& pan)
279 {
280   if(!mDetectedSignal.Empty())
281   {
282     // Guard against destruction during signal emission
283     Dali::PanGestureDetector handle(this);
284
285     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Emitting Signal (%p)\n", this);
286     if(pan.GetState() !=  GestureState::CONTINUING)
287     {
288       DALI_LOG_DEBUG_INFO("emitting pan gesture actor id(%d) state(%d)\n", actor.GetProperty<int32_t>(Dali::Actor::Property::ID), pan.GetState());
289     }
290     mDetectedSignal.Emit(actor, pan);
291   }
292 }
293
294 bool PanGestureDetector::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
295 {
296   bool                connected(true);
297   PanGestureDetector* gesture = static_cast<PanGestureDetector*>(object); // TypeRegistry guarantees that this is the correct type.
298
299   if(0 == strcmp(signalName.c_str(), SIGNAL_PAN_DETECTED))
300   {
301     gesture->DetectedSignal().Connect(tracker, functor);
302   }
303   else
304   {
305     // signalName does not match any signal
306     connected = false;
307   }
308
309   return connected;
310 }
311
312 void PanGestureDetector::SetPanGestureProperties(const Dali::PanGesture& pan)
313 {
314   ThreadLocalStorage::Get().GetGestureEventProcessor().SetGestureProperties(pan);
315 }
316
317 PanGestureDetector::PanGestureDetector(const SceneGraph::PanGesture& sceneObject)
318 : GestureDetector(GestureType::PAN, &sceneObject),
319   mMinimumTouches(1),
320   mMaximumTouches(1),
321   mMaximumMotionEventAge(std::numeric_limits<uint32_t>::max())
322 {
323 }
324
325 PanGestureDetector::~PanGestureDetector() = default;
326
327 const SceneGraph::PanGesture& PanGestureDetector::GetPanGestureSceneObject() const
328 {
329   return static_cast<const SceneGraph::PanGesture&>(GetSceneObject());
330 }
331
332 void PanGestureDetector::OnActorAttach(Actor& actor)
333 {
334   DALI_LOG_INFO(gLogFilter, Debug::General, "PanGestureDetector attach actor(%d)\n", actor.GetId());
335 }
336
337 void PanGestureDetector::OnActorDetach(Actor& actor)
338 {
339   DALI_LOG_INFO(gLogFilter, Debug::General, "PanGestureDetector detach actor(%d)\n", actor.GetId());
340 }
341
342 void PanGestureDetector::OnActorDestroyed(Object& object)
343 {
344   // Do nothing
345 }
346
347 void PanGestureDetector::SetDefaultProperty(Property::Index index, const Property::Value& property)
348 {
349   // None of our properties should be settable from Public API
350 }
351
352 Property::Value PanGestureDetector::GetDefaultProperty(Property::Index index) const
353 {
354   return GetDefaultPropertyCurrentValue(index); // Scene-graph only properties
355 }
356
357 Property::Value PanGestureDetector::GetDefaultPropertyCurrentValue(Property::Index index) const
358 {
359   Property::Value value;
360
361   switch(index)
362   {
363     case Dali::PanGestureDetector::Property::SCREEN_POSITION:
364     {
365       value = GetPanGestureSceneObject().GetScreenPositionProperty().Get();
366       break;
367     }
368
369     case Dali::PanGestureDetector::Property::SCREEN_DISPLACEMENT:
370     {
371       value = GetPanGestureSceneObject().GetScreenDisplacementProperty().Get();
372       break;
373     }
374
375     case Dali::PanGestureDetector::Property::SCREEN_VELOCITY:
376     {
377       value = GetPanGestureSceneObject().GetScreenVelocityProperty().Get();
378       break;
379     }
380
381     case Dali::PanGestureDetector::Property::LOCAL_POSITION:
382     {
383       value = GetPanGestureSceneObject().GetLocalPositionProperty().Get();
384       break;
385     }
386
387     case Dali::PanGestureDetector::Property::LOCAL_DISPLACEMENT:
388     {
389       value = GetPanGestureSceneObject().GetLocalDisplacementProperty().Get();
390       break;
391     }
392
393     case Dali::PanGestureDetector::Property::LOCAL_VELOCITY:
394     {
395       value = GetPanGestureSceneObject().GetLocalVelocityProperty().Get();
396       break;
397     }
398
399     case Dali::PanGestureDetector::Property::PANNING:
400     {
401       value = GetPanGestureSceneObject().GetPanningProperty().Get();
402       break;
403     }
404
405     default:
406     {
407       DALI_ASSERT_ALWAYS(false && "PanGestureDetector Property index invalid"); // should not come here
408       break;
409     }
410   }
411
412   return value;
413 }
414
415 const PropertyInputImpl* PanGestureDetector::GetSceneObjectInputProperty(Property::Index index) const
416 {
417   const PropertyInputImpl* property = nullptr;
418
419   switch(index)
420   {
421     case Dali::PanGestureDetector::Property::SCREEN_POSITION:
422     {
423       property = &GetPanGestureSceneObject().GetScreenPositionProperty();
424       break;
425     }
426
427     case Dali::PanGestureDetector::Property::SCREEN_DISPLACEMENT:
428     {
429       property = &GetPanGestureSceneObject().GetScreenDisplacementProperty();
430       break;
431     }
432
433     case Dali::PanGestureDetector::Property::SCREEN_VELOCITY:
434     {
435       property = &GetPanGestureSceneObject().GetScreenVelocityProperty();
436       break;
437     }
438
439     case Dali::PanGestureDetector::Property::LOCAL_POSITION:
440     {
441       property = &GetPanGestureSceneObject().GetLocalPositionProperty();
442       break;
443     }
444
445     case Dali::PanGestureDetector::Property::LOCAL_DISPLACEMENT:
446     {
447       property = &GetPanGestureSceneObject().GetLocalDisplacementProperty();
448       break;
449     }
450
451     case Dali::PanGestureDetector::Property::LOCAL_VELOCITY:
452     {
453       property = &GetPanGestureSceneObject().GetLocalVelocityProperty();
454       break;
455     }
456
457     case Dali::PanGestureDetector::Property::PANNING:
458     {
459       property = &GetPanGestureSceneObject().GetPanningProperty();
460       break;
461     }
462
463     default:
464       break;
465   }
466   if(!property)
467   {
468     // not our property, ask base
469     property = Object::GetSceneObjectInputProperty(index);
470   }
471
472   return property;
473 }
474
475 } // namespace Internal
476
477 } // namespace Dali