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/gesture-processor.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/internal/event/actors/actor-impl.h>
24 #include <dali/internal/event/actors/layer-impl.h>
25 #include <dali/internal/event/common/scene-impl.h>
26 #include <dali/internal/event/events/actor-gesture-data.h>
27 #include <dali/internal/event/events/hit-test-algorithm-impl.h>
28 #include <dali/internal/event/events/ray-test.h>
29 #include <dali/internal/event/render-tasks/render-task-impl.h>
38 * Functor to check whether an actor requires a particular gesture or not
40 struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
42 GestureHitTestCheck(GestureType::Value type)
47 bool IsActorHittable(Actor* actor) override
49 return actor->IsGestureRequired(mType) && // Does the Application or derived actor type require the gesture?
50 actor->IsHittable(); // Is actor sensitive, visible and on the scene?
53 bool DescendActorHierarchy(Actor* actor) override
55 return actor->IsVisible() && // Actor is visible, if not visible then none of its children are visible.
56 actor->IsSensitive(); // Actor is sensitive, if insensitive none of its children should be hittable either.
59 bool DoesLayerConsumeHit(Layer* layer) override
61 return layer->IsTouchConsumed();
64 bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp, bool isGeometry) override
66 return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
69 GestureType::Value mType;
72 } // unnamed namespace
74 GestureProcessor::GestureProcessor(GestureType::Value type)
75 : mGestureRecognizer(),
78 mCurrentGesturedActor(nullptr),
81 mGesturedActorDisconnected(false),
82 mFeededActor(nullptr),
84 mGestureDetector(nullptr)
88 GestureProcessor::~GestureProcessor()
93 void GestureProcessor::ProcessTouch(Scene& scene, const Integration::TouchEvent& event)
95 if(mGestureRecognizer)
97 if(!event.points.empty())
99 mPoint = event.points[0];
100 mEventTime = event.time;
102 mFeededActor = nullptr;
103 mGestureDetector = nullptr;
104 mGestureRecognizer->SendEvent(scene, event);
108 void GestureProcessor::ProcessTouch(GestureDetector* gestureDetector, Actor& actor, Dali::Internal::RenderTask& renderTask, Scene& scene, const Integration::TouchEvent& event)
110 if(mGestureRecognizer)
112 if(!event.points.empty())
114 mPoint = event.points[0];
115 mEventTime = event.time;
117 mGestureDetector = gestureDetector;
118 mFeededActor.SetActor(&actor);
119 mRenderTask = &renderTask;
120 mGestureRecognizer->SendEvent(scene, event);
124 Actor* GestureProcessor::GetFeededActor()
126 return mFeededActor.GetActor();
129 GestureDetector* GestureProcessor::GetFeededGestureDetector()
131 return mGestureDetector;
134 RenderTaskPtr GestureProcessor::GetFeededRenderTask()
139 void GestureProcessor::GetGesturedActor(Actor*& actor, GestureDetectorContainer& gestureDetectors)
143 // We may be checking a parent so ensure the parent requires this gesture (and do not unintentionally create the gesture data for the parent)
144 if(actor->IsGestureRequired(mType))
146 // Retrieve the actor's detectors and check if they satisfy current gesture
147 const GestureDetectorContainer& connectedDetectors(actor->GetGestureData().GetGestureDetectorContainer(mType));
148 const GestureDetectorContainer::const_iterator endIter(connectedDetectors.end());
149 for(GestureDetectorContainer::const_iterator iter = connectedDetectors.begin(); iter != endIter; ++iter)
151 GestureDetector* current(*iter);
153 // Check deriving class for whether the current gesture satisfies the gesture detector's parameters.
154 if(CheckGestureDetector(current, actor))
156 gestureDetectors.push_back(current);
160 // The hit actor or one of the parents is a gestured actor, break out.
161 if(!gestureDetectors.empty())
167 // No match, we should now check the hit actor's parent.
168 actor = actor->GetParent();
172 void GestureProcessor::ProcessAndEmit(HitTestAlgorithm::Results& hitTestResults)
174 if(hitTestResults.actor)
176 Actor* hitTestActor(&GetImplementation(hitTestResults.actor));
177 Actor* actor(hitTestActor);
182 GestureDetectorContainer gestureDetectors;
183 GetGesturedActor(actor, gestureDetectors);
185 if(actor && !gestureDetectors.empty())
187 // We have a match but check if the hit point is within the gestured actor's bounds.
188 // If it is not then continue up the actor hierarchy.
190 if(actor == hitTestActor)
192 // Our gesture detector's attached actor WAS the hit actor so we can can emit the signal.
193 EmitGestureSignal(actor, gestureDetectors, hitTestResults.actorCoordinates);
194 // If NeedGesturePropagation is true, it passes the gesture to the parent.
195 if(!actor->NeedGesturePropagation())
197 break; // We have found AND emitted a signal on the gestured actor, break out.
199 actor->SetNeedGesturePropagation(false);
203 if(actor->IsHittable())
205 const Vector3 size(actor->GetCurrentSize());
207 if((size.x > 0.0f) && (size.y > 0.0f))
209 // Ensure tap is within the actor's area
210 if(rayTest.SphereTest(*actor, hitTestResults.rayOrigin, hitTestResults.rayDirection)) // Quick check
212 Vector2 hitPointLocal;
213 float distance(0.0f);
214 if(rayTest.ActorTest(*actor, hitTestResults.rayOrigin, hitTestResults.rayDirection, hitPointLocal, distance))
216 // One of the parents was the gestured actor so we can emit the signal for that actor.
217 EmitGestureSignal(actor, gestureDetectors, hitPointLocal);
218 // If NeedGesturePropagation is true, it passes the gesture to the parent.
219 if(!actor->NeedGesturePropagation())
221 break; // We have found AND emitted a signal on the gestured actor, break out.
223 actor->SetNeedGesturePropagation(false);
231 // Continue up hierarchy to see if any of the parents require this gesture.
234 actor = actor->GetParent();
240 void GestureProcessor::ProcessAndEmitActor(HitTestAlgorithm::Results& hitTestResults, GestureDetector* gestureDetector)
242 if(hitTestResults.actor && gestureDetector)
244 Actor* actor(&GetImplementation(hitTestResults.actor));
245 GestureDetectorContainer gestureDetectors;
246 // Check deriving class for whether the current gesture satisfies the gesture detector's parameters.
247 if(actor && actor->IsVisible() && gestureDetector && CheckGestureDetector(gestureDetector, actor))
249 gestureDetectors.push_back(gestureDetector);
250 gestureDetector->SetDetected(true);
251 EmitGestureSignal(actor, gestureDetectors, hitTestResults.actorCoordinates);
256 bool GestureProcessor::HitTest(Scene& scene, Vector2 screenCoordinates, HitTestAlgorithm::Results& hitTestResults)
258 GestureHitTestCheck hitCheck(mType);
259 hitTestResults.point = mPoint;
260 hitTestResults.eventTime = mEventTime;
261 HitTestAlgorithm::HitTest(scene.GetSize(), scene.GetRenderTaskList(), scene.GetLayerList(), screenCoordinates, hitTestResults, hitCheck);
262 return hitTestResults.renderTask && hitTestResults.actor;
265 void GestureProcessor::SetActor(Actor* actor)
267 if(actor && actor != mCurrentGesturedActor)
271 mCurrentGesturedActor = actor;
272 mCurrentGesturedActor->AddObserver(*this);
274 mGesturedActorDisconnected = false;
277 void GestureProcessor::ResetActor()
279 if(mCurrentGesturedActor)
281 mCurrentGesturedActor->RemoveObserver(*this);
282 mCurrentGesturedActor = nullptr;
283 mGesturedActorDisconnected = false;
287 Actor* GestureProcessor::GetCurrentGesturedActor()
289 return mGesturedActorDisconnected ? nullptr : mCurrentGesturedActor;
292 void GestureProcessor::SceneObjectRemoved(Object& object)
294 if(mCurrentGesturedActor == &object &&
295 !mGesturedActorDisconnected)
297 // Inform deriving classes.
298 OnGesturedActorStageDisconnection();
300 // do not call object.RemoveObserver here, object is currently iterating through observers... you wouldnt want to upset object now would you?
301 mGesturedActorDisconnected = true;
305 void GestureProcessor::ObjectDestroyed(Object& object)
307 if(mCurrentGesturedActor == &object)
309 // Inform deriving classes.
310 OnGesturedActorStageDisconnection();
312 mCurrentGesturedActor = nullptr;
316 } // namespace Internal