2 * Copyright (c) 2024 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/gesture-detector-impl.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/internal/event/common/stage-impl.h>
27 #include <dali/internal/event/common/thread-local-storage.h>
28 #include <dali/internal/event/events/actor-gesture-data.h>
29 #include <dali/internal/event/events/gesture-event-processor.h>
30 #include <dali/internal/event/events/touch-event-impl.h>
31 #include <dali/internal/event/render-tasks/render-task-impl.h>
37 GestureDetector::GestureDetector(GestureType::Value type, const SceneGraph::PropertyOwner* sceneObject)
38 : Object(sceneObject),
40 mGestureEventProcessor(ThreadLocalStorage::Get().GetGestureEventProcessor()),
48 GestureDetector::~GestureDetector()
50 if(DALI_UNLIKELY(!Dali::Stage::IsCoreThread()))
52 DALI_LOG_ERROR("~GestureDetector[%p] called from non-UI thread! something unknown issue will be happened!\n", this);
55 if(!mPendingAttachActors.empty())
57 for(GestureDetectorActorContainer::iterator iter = mPendingAttachActors.begin(), endIter = mPendingAttachActors.end(); iter != endIter; ++iter)
60 actor->RemoveObserver(*this);
61 actor->GetGestureData().RemoveGestureDetector(*this);
64 mPendingAttachActors.clear();
67 if(!mAttachedActors.empty())
69 for(GestureDetectorActorContainer::iterator iter = mAttachedActors.begin(), endIter = mAttachedActors.end(); iter != endIter; ++iter)
72 actor->RemoveObserver(*this);
73 actor->GetGestureData().RemoveGestureDetector(*this);
76 mAttachedActors.clear();
78 // Guard to allow handle destruction after Core has been destroyed
79 if(Stage::IsInstalled())
81 mGestureEventProcessor.RemoveGestureDetector(this);
86 void GestureDetector::Attach(Actor& actor)
88 if(!IsAttached(actor))
92 // Register with EventProcessor if first actor being added
93 if(mAttachedActors.empty())
95 mGestureEventProcessor.AddGestureDetector(this, actor.GetScene());
97 mAttachedActors.push_back(&actor);
98 // We need to observe the actor's destruction
99 actor.AddObserver(*this);
100 // Add the detector to the actor (so the actor knows it requires this gesture when going through hit-test algorithm)
101 actor.GetGestureData().AddGestureDetector(*this);
102 // Notification for derived classes
103 OnActorAttach(actor);
107 actor.AddObserver(*this);
108 // Add the detector to the actor (so the actor knows it requires this gesture when going through hit-test algorithm)
109 actor.GetGestureData().AddGestureDetector(*this);
111 mPendingAttachActors.push_back(&actor);
116 void GestureDetector::SceneObjectAdded(Object& object)
118 Actor& actor = dynamic_cast<Actor&>(object);
120 // Make sure the actor has not already been attached. Can't use IsAttached() as that checks the pending list as well
121 if(find(mAttachedActors.begin(), mAttachedActors.end(), &actor) == mAttachedActors.end())
123 GestureDetectorActorContainer::iterator match = find(mPendingAttachActors.begin(), mPendingAttachActors.end(), &actor);
125 if(match != mPendingAttachActors.end())
127 mPendingAttachActors.erase(match);
129 // Register with EventProcessor if first actor being added
130 if(mAttachedActors.empty())
132 mGestureEventProcessor.AddGestureDetector(this, actor.GetScene());
134 mAttachedActors.push_back(&actor);
136 // Notification for derived classes
137 OnActorAttach(actor);
141 // Actor was not in the pending list
142 DALI_ASSERT_DEBUG(false);
147 // Check if actor has been attached and is still in the pending list - this would not be correct
148 DALI_ASSERT_DEBUG(find(mPendingAttachActors.begin(), mPendingAttachActors.end(), &actor) == mPendingAttachActors.end());
152 void GestureDetector::Detach(Actor& actor)
154 if(!mPendingAttachActors.empty())
156 GestureDetectorActorContainer::iterator match = find(mPendingAttachActors.begin(), mPendingAttachActors.end(), &actor);
158 if(match != mPendingAttachActors.end())
160 // We no longer need to observe the actor's destruction
161 actor.RemoveObserver(*this);
163 // Remove detector from actor-gesture-data
164 actor.GetGestureData().RemoveGestureDetector(*this);
166 mPendingAttachActors.erase(match);
170 if(!mAttachedActors.empty())
172 GestureDetectorActorContainer::iterator match = find(mAttachedActors.begin(), mAttachedActors.end(), &actor);
174 if(match != mAttachedActors.end())
176 // We no longer need to observe the actor's destruction
177 actor.RemoveObserver(*this);
179 // Remove detector from actor-gesture-data
180 actor.GetGestureData().RemoveGestureDetector(*this);
182 mAttachedActors.erase(match);
184 // Notification for derived classes
185 OnActorDetach(actor);
187 // Unregister from gesture event processor if we do not have any actors
188 if(mAttachedActors.empty())
190 // Guard to allow handle destruction after Core has been destroyed
191 if(Stage::IsInstalled())
193 mGestureEventProcessor.RemoveGestureDetector(this);
200 void GestureDetector::DetachAll()
202 if(!mPendingAttachActors.empty())
204 GestureDetectorActorContainer pendingActors(mPendingAttachActors);
206 mPendingAttachActors.clear();
208 for(GestureDetectorActorContainer::iterator iter = pendingActors.begin(), endIter = pendingActors.end(); iter != endIter; ++iter)
212 // We no longer need to observe the actor's destruction
213 actor->RemoveObserver(*this);
215 // Remove detector from actor-gesture-data
216 actor->GetGestureData().RemoveGestureDetector(*this);
220 if(!mAttachedActors.empty())
222 GestureDetectorActorContainer attachedActors(mAttachedActors);
224 // Clear mAttachedActors before we call OnActorDetach in case derived classes call a method which manipulates mAttachedActors.
225 mAttachedActors.clear();
227 for(GestureDetectorActorContainer::iterator iter = attachedActors.begin(), endIter = attachedActors.end(); iter != endIter; ++iter)
231 // We no longer need to observe the actor's destruction
232 actor->RemoveObserver(*this);
234 // Remove detector from actor-gesture-data
235 actor->GetGestureData().RemoveGestureDetector(*this);
237 // Notification for derived classes
238 OnActorDetach(*actor);
241 // Guard to allow handle destruction after Core has been destroyed
242 if(Stage::IsInstalled())
244 // Unregister from gesture event processor
245 mGestureEventProcessor.RemoveGestureDetector(this);
250 size_t GestureDetector::GetAttachedActorCount() const
252 return mPendingAttachActors.size() + mAttachedActors.size();
255 Dali::Actor GestureDetector::GetAttachedActor(size_t index) const
259 if(index < mPendingAttachActors.size())
261 actor = Dali::Actor(mPendingAttachActors[index]);
263 else if(index < mPendingAttachActors.size() + mAttachedActors.size())
265 actor = Dali::Actor(mAttachedActors[index - mPendingAttachActors.size()]);
271 bool GestureDetector::HandleEvent(Dali::Actor& actor, Dali::TouchEvent& touch)
274 Dali::Internal::Actor& actorImpl(GetImplementation(actor));
275 if(touch.GetPointCount() > 0 && actorImpl.OnScene())
277 const PointState::Type state = touch.GetState(0);
278 if(state == PointState::DOWN)
282 actorImpl.SetNeedGesturePropagation(false);
283 mGestureEventProcessor.RegisterGestureDetector(this);
286 Integration::TouchEvent touchEvent(touch.GetTime());
287 for(std::size_t i = 0; i < touch.GetPointCount(); i++)
289 Integration::Point point;
290 point.SetState(touch.GetState(i));
291 point.SetDeviceId(touch.GetDeviceId(i));
292 point.SetScreenPosition(touch.GetScreenPosition(i));
293 point.SetRadius(touch.GetRadius(i));
294 point.SetPressure(touch.GetPressure(i));
295 point.SetAngle(touch.GetAngle(i));
296 point.SetDeviceClass(touch.GetDeviceClass(i));
297 point.SetDeviceSubclass(touch.GetDeviceSubclass(i));
298 point.SetMouseButton(touch.GetMouseButton(i));
299 point.SetHitActor(touch.GetHitActor(i));
300 point.SetLocalPosition(touch.GetLocalPosition(i));
301 touchEvent.points.push_back(point);
304 Dali::Internal::TouchEvent& touchEventImpl(GetImplementation(touch));
305 mFeededActor.SetActor(&actorImpl);
306 mRenderTask = &GetImplementation(touchEventImpl.GetRenderTaskPtr());
308 if(!actorImpl.NeedGesturePropagation())
310 ProcessTouchEvent(actorImpl.GetScene(), touchEvent);
313 ret = IsDetected() && !actorImpl.NeedGesturePropagation();
314 actorImpl.SetNeedGesturePropagation(false);
316 if(state == PointState::FINISHED || state == PointState::INTERRUPTED)
324 void GestureDetector::CancelAllOtherGestureDetectors()
326 mGestureEventProcessor.CancelAllOtherGestureDetectors(this);
329 bool GestureDetector::IsDetected() const
334 void GestureDetector::SetDetected(bool detected)
336 mIsDetected = detected;
339 void GestureDetector::Clear()
341 mGestureRecognizer = nullptr;
342 mGestureEventProcessor.UnregisterGestureDetector(this);
346 bool GestureDetector::IsAttached(Actor& actor) const
348 return (find(mPendingAttachActors.begin(), mPendingAttachActors.end(), &actor) != mPendingAttachActors.end()) ||
349 (find(mAttachedActors.begin(), mAttachedActors.end(), &actor) != mAttachedActors.end());
352 void GestureDetector::ObjectDestroyed(Object& object)
354 if(!mPendingAttachActors.empty())
356 GestureDetectorActorContainer::iterator match = find(mPendingAttachActors.begin(), mPendingAttachActors.end(), &object);
358 if(match != mPendingAttachActors.end())
360 mPendingAttachActors.erase(match);
364 if(!mAttachedActors.empty())
366 GestureDetectorActorContainer::iterator match = find(mAttachedActors.begin(), mAttachedActors.end(), &object);
368 if(match != mAttachedActors.end())
370 mAttachedActors.erase(match);
372 // Notification for derived classes
373 OnActorDestroyed(object);
375 // Unregister from gesture event processor if we do not have any actors
376 if(mAttachedActors.empty())
378 // Guard to allow handle destruction after Core has been destroyed
379 if(Stage::IsInstalled())
381 mGestureEventProcessor.RemoveGestureDetector(this);
388 } // namespace Internal