2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.h>
22 #include <cstring> // for strcmp
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>
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)
57 const char* const SIGNAL_PAN_DETECTED = "panDetected";
61 return Dali::PanGestureDetector::New();
64 TypeRegistration mType(typeid(Dali::PanGestureDetector), typeid(Dali::GestureDetector), Create, PanGestureDetectorDefaultProperties);
66 SignalConnectorType signalConnector1(mType, SIGNAL_PAN_DETECTED, &PanGestureDetector::DoConnectSignal);
68 #if defined(DEBUG_ENABLED)
69 Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_PAN_GESTURE_DETECTOR");
73 * Returns the angle going in the opposite direction to that specified by angle.
75 float GetOppositeAngle(float angle)
77 // Calculate the opposite angle so that we cover both directions.
90 } // unnamed namespace
92 PanGestureDetectorPtr PanGestureDetector::New()
94 const SceneGraph::PanGesture& sceneObject = ThreadLocalStorage::Get().GetGestureEventProcessor().GetPanGestureProcessor().GetSceneObject();
95 return new PanGestureDetector(sceneObject);
98 void PanGestureDetector::SetMinimumTouchesRequired(uint32_t minimum)
100 DALI_ASSERT_ALWAYS(minimum > 0 && "Can only set a positive number of required touches");
102 if(mMinimumTouches != minimum)
104 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Minimum Touches Set: %u\n", minimum);
106 mMinimumTouches = minimum;
108 if(!mAttachedActors.empty())
110 DALI_LOG_INFO(gLogFilter, Debug::General, "Updating Gesture Detector\n");
112 mGestureEventProcessor.GestureDetectorUpdated(this);
117 void PanGestureDetector::SetMaximumTouchesRequired(uint32_t maximum)
119 DALI_ASSERT_ALWAYS(maximum > 0 && "Can only set a positive number of maximum touches");
121 if(mMaximumTouches != maximum)
123 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Maximum Touches Set: %u\n", maximum);
125 mMaximumTouches = maximum;
127 if(!mAttachedActors.empty())
129 DALI_LOG_INFO(gLogFilter, Debug::General, "Updating Gesture Detector\n");
131 mGestureEventProcessor.GestureDetectorUpdated(this);
136 void PanGestureDetector::SetMaximumMotionEventAge(uint32_t maximumAge)
138 if(mMaximumMotionEventAge != maximumAge)
140 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Maximum Motion Age Set: %u ms\n", maximumAge);
142 mMaximumMotionEventAge = maximumAge;
144 if(!mAttachedActors.empty())
146 DALI_LOG_INFO(gLogFilter, Debug::General, "Updating Gesture Detector\n");
148 mGestureEventProcessor.GestureDetectorUpdated(this);
153 uint32_t PanGestureDetector::GetMinimumTouchesRequired() const
155 return mMinimumTouches;
158 uint32_t PanGestureDetector::GetMaximumTouchesRequired() const
160 return mMaximumTouches;
163 uint32_t PanGestureDetector::GetMaximumMotionEventAge() const
165 return mMaximumMotionEventAge;
168 void PanGestureDetector::AddAngle(Radian angle, Radian threshold)
170 threshold = fabsf(threshold); // Ensure the threshold is positive.
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)
177 threshold = Math::PI;
180 angle = WrapInDomain(angle, -Math::PI, Math::PI);
182 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Angle Added: %.2f, Threshold: %.2f\n", Degree(angle), Degree(threshold));
184 AngleThresholdPair pair(angle, threshold);
185 mAngleContainer.push_back(pair);
188 void PanGestureDetector::AddDirection(Radian direction, Radian threshold)
190 AddAngle(direction, threshold);
192 // Calculate the opposite angle so that we cover the entire direction.
193 direction = GetOppositeAngle(direction);
195 AddAngle(direction, threshold);
198 uint32_t PanGestureDetector::GetAngleCount() const
200 return static_cast<uint32_t>(mAngleContainer.size());
203 PanGestureDetector::AngleThresholdPair PanGestureDetector::GetAngle(uint32_t index) const
205 PanGestureDetector::AngleThresholdPair ret(Radian(0), Radian(0));
207 if(index < mAngleContainer.size())
209 ret = mAngleContainer[index];
215 void PanGestureDetector::ClearAngles()
217 mAngleContainer.clear();
220 void PanGestureDetector::RemoveAngle(Radian angle)
222 angle = WrapInDomain(angle, -Math::PI, Math::PI);
224 for(AngleContainer::iterator iter = mAngleContainer.begin(), endIter = mAngleContainer.end(); iter != endIter; ++iter)
226 if(iter->first == angle)
228 mAngleContainer.erase(iter);
234 void PanGestureDetector::RemoveDirection(Radian direction)
236 RemoveAngle(direction);
238 // Calculate the opposite angle so that we cover the entire direction.
239 direction = GetOppositeAngle(direction);
241 RemoveAngle(direction);
244 bool PanGestureDetector::RequiresDirectionalPan() const
246 // If no directional angles have been added to the container then we do not require directional panning
247 return !mAngleContainer.empty();
250 bool PanGestureDetector::CheckAngleAllowed(Radian angle) const
253 if(mAngleContainer.empty())
259 for(AngleContainer::const_iterator iter = mAngleContainer.begin(), endIter = mAngleContainer.end(); iter != endIter; ++iter)
261 float angleAllowed(iter->first);
262 float threshold(iter->second);
264 DALI_LOG_INFO(gLogFilter, Debug::General, "AngleToCheck: %.2f, CompareWith: %.2f, Threshold: %.2f\n", Degree(angle), Degree(angleAllowed), Degree(threshold));
266 float relativeAngle(fabsf(WrapInDomain(angle - angleAllowed, -Math::PI, Math::PI)));
267 if(relativeAngle <= threshold)
278 void PanGestureDetector::EmitPanGestureSignal(Dali::Actor actor, const Dali::PanGesture& pan)
280 if(!mDetectedSignal.Empty())
282 // Guard against destruction during signal emission
283 Dali::PanGestureDetector handle(this);
285 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Emitting Signal (%p)\n", this);
287 mDetectedSignal.Emit(actor, pan);
291 bool PanGestureDetector::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
293 bool connected(true);
294 PanGestureDetector* gesture = static_cast<PanGestureDetector*>(object); // TypeRegistry guarantees that this is the correct type.
296 if(0 == strcmp(signalName.c_str(), SIGNAL_PAN_DETECTED))
298 gesture->DetectedSignal().Connect(tracker, functor);
302 // signalName does not match any signal
309 void PanGestureDetector::SetPanGestureProperties(const Dali::PanGesture& pan)
311 ThreadLocalStorage::Get().GetGestureEventProcessor().SetGestureProperties(pan);
314 PanGestureDetector::PanGestureDetector(const SceneGraph::PanGesture& sceneObject)
315 : GestureDetector(GestureType::PAN, &sceneObject),
318 mMaximumMotionEventAge(std::numeric_limits<uint32_t>::max())
322 PanGestureDetector::~PanGestureDetector() = default;
324 const SceneGraph::PanGesture& PanGestureDetector::GetPanGestureSceneObject() const
326 return static_cast<const SceneGraph::PanGesture&>(GetSceneObject());
329 void PanGestureDetector::OnActorAttach(Actor& actor)
334 void PanGestureDetector::OnActorDetach(Actor& actor)
339 void PanGestureDetector::OnActorDestroyed(Object& object)
344 void PanGestureDetector::SetDefaultProperty(Property::Index index, const Property::Value& property)
346 // None of our properties should be settable from Public API
349 Property::Value PanGestureDetector::GetDefaultProperty(Property::Index index) const
351 return GetDefaultPropertyCurrentValue(index); // Scene-graph only properties
354 Property::Value PanGestureDetector::GetDefaultPropertyCurrentValue(Property::Index index) const
356 Property::Value value;
360 case Dali::PanGestureDetector::Property::SCREEN_POSITION:
362 value = GetPanGestureSceneObject().GetScreenPositionProperty().Get();
366 case Dali::PanGestureDetector::Property::SCREEN_DISPLACEMENT:
368 value = GetPanGestureSceneObject().GetScreenDisplacementProperty().Get();
372 case Dali::PanGestureDetector::Property::SCREEN_VELOCITY:
374 value = GetPanGestureSceneObject().GetScreenVelocityProperty().Get();
378 case Dali::PanGestureDetector::Property::LOCAL_POSITION:
380 value = GetPanGestureSceneObject().GetLocalPositionProperty().Get();
384 case Dali::PanGestureDetector::Property::LOCAL_DISPLACEMENT:
386 value = GetPanGestureSceneObject().GetLocalDisplacementProperty().Get();
390 case Dali::PanGestureDetector::Property::LOCAL_VELOCITY:
392 value = GetPanGestureSceneObject().GetLocalVelocityProperty().Get();
396 case Dali::PanGestureDetector::Property::PANNING:
398 value = GetPanGestureSceneObject().GetPanningProperty().Get();
404 DALI_ASSERT_ALWAYS(false && "PanGestureDetector Property index invalid"); // should not come here
412 const PropertyInputImpl* PanGestureDetector::GetSceneObjectInputProperty(Property::Index index) const
414 const PropertyInputImpl* property = nullptr;
418 case Dali::PanGestureDetector::Property::SCREEN_POSITION:
420 property = &GetPanGestureSceneObject().GetScreenPositionProperty();
424 case Dali::PanGestureDetector::Property::SCREEN_DISPLACEMENT:
426 property = &GetPanGestureSceneObject().GetScreenDisplacementProperty();
430 case Dali::PanGestureDetector::Property::SCREEN_VELOCITY:
432 property = &GetPanGestureSceneObject().GetScreenVelocityProperty();
436 case Dali::PanGestureDetector::Property::LOCAL_POSITION:
438 property = &GetPanGestureSceneObject().GetLocalPositionProperty();
442 case Dali::PanGestureDetector::Property::LOCAL_DISPLACEMENT:
444 property = &GetPanGestureSceneObject().GetLocalDisplacementProperty();
448 case Dali::PanGestureDetector::Property::LOCAL_VELOCITY:
450 property = &GetPanGestureSceneObject().GetLocalVelocityProperty();
454 case Dali::PanGestureDetector::Property::PANNING:
456 property = &GetPanGestureSceneObject().GetPanningProperty();
465 // not our property, ask base
466 property = Object::GetSceneObjectInputProperty(index);
472 } // namespace Internal