2 * Copyright (c) 2023 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/rotation-gesture/rotation-gesture-processor.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/integration-api/trace.h>
27 #include <dali/internal/event/common/scene-impl.h>
28 #include <dali/internal/event/events/gesture-requests.h>
29 #include <dali/internal/event/events/rotation-gesture/rotation-gesture-event.h>
30 #include <dali/internal/event/events/rotation-gesture/rotation-gesture-impl.h>
31 #include <dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.h>
32 #include <dali/internal/event/render-tasks/render-task-impl.h>
33 #include <dali/public-api/actors/actor.h>
34 #include <dali/public-api/events/rotation-gesture.h>
35 #include <dali/public-api/math/vector2.h>
43 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
44 const uint32_t MINIMUM_TOUCH_EVENTS_REQUIRED = 4u;
45 const uint32_t MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START = 4u;
48 * Creates a RotationGesture and asks the specified detector to emit its detected signal.
49 * @param[in] actor The actor that has been rotationed.
50 * @param[in] gestureDetectors The gesture detector container that should emit the signal.
51 * @param[in] rotationEvent The rotationEvent received from the adaptor.
52 * @param[in] localCenter Relative to the actor attached to the detector.
54 void EmitRotationSignal(
56 const GestureDetectorContainer& gestureDetectors,
57 const RotationGestureEvent& rotationEvent,
60 Internal::RotationGesturePtr rotation(new Internal::RotationGesture(rotationEvent.state));
61 rotation->SetTime(rotationEvent.time);
62 rotation->SetRotation(rotationEvent.rotation);
63 rotation->SetScreenCenterPoint(rotationEvent.centerPoint);
64 rotation->SetLocalCenterPoint(localCenter);
65 rotation->SetSourceType(rotationEvent.sourceType);
66 rotation->SetSourceData(rotationEvent.sourceData);
68 Dali::Actor actorHandle(actor);
69 const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
70 for(GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter)
72 static_cast<RotationGestureDetector*>(*iter)->EmitRotationGestureSignal(actorHandle, Dali::RotationGesture(rotation.Get()));
77 * Functor which checks whether the specified actor is attached to the gesture detector.
78 * It returns true if it is no longer attached. This can be used in remove_if functions.
80 struct IsNotAttachedFunctor
84 * @param[in] actor The actor to check whether it is attached.
86 IsNotAttachedFunctor(Actor* actor)
92 * Returns true if not attached, false if it is still attached.
93 * @param[in] detector The detector to check.
94 * @return true, if not attached, false otherwise.
96 bool operator()(const GestureDetector* detector) const
98 return !detector->IsAttached(*actorToCheck);
101 Actor* actorToCheck; ///< The actor to check whether it is attached or not.
104 } // unnamed namespace
106 RotationGestureProcessor::RotationGestureProcessor()
107 : GestureProcessor(GestureType::ROTATION),
108 mRotationGestureDetectors(),
109 mCurrentRotationEmitters(),
110 mCurrentRotationEvent(nullptr),
111 mMinimumTouchEvents(MINIMUM_TOUCH_EVENTS_REQUIRED),
112 mMinimumTouchEventsAfterStart(MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START)
116 void RotationGestureProcessor::Process(Scene& scene, const RotationGestureEvent& rotationEvent)
118 DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_ROTATION_GESTURE");
119 switch(rotationEvent.state)
121 case GestureState::STARTED:
123 // The rotation gesture should only be sent to the gesture detector which first received it so that
124 // it can be told when the gesture ends as well.
126 mCurrentRotationEmitters.clear();
129 HitTestAlgorithm::Results hitTestResults;
130 if(HitTest(scene, rotationEvent.centerPoint, hitTestResults))
132 // Record the current render-task for Screen->Actor coordinate conversions
133 mCurrentRenderTask = hitTestResults.renderTask;
135 // Set mCurrentRotationEvent to use inside overridden methods called from ProcessAndEmit()
136 mCurrentRotationEvent = &rotationEvent;
137 ProcessAndEmit(hitTestResults);
138 mCurrentRotationEvent = nullptr;
143 case GestureState::CONTINUING:
144 case GestureState::FINISHED:
145 case GestureState::CANCELLED:
147 // Only send subsequent rotation gesture signals if we processed the rotation gesture when it started.
148 // Check if actor is still touchable.
150 Actor* currentGesturedActor = GetCurrentGesturedActor();
151 if(currentGesturedActor)
153 if(currentGesturedActor->IsHittable() && !mCurrentRotationEmitters.empty() && mCurrentRenderTask)
155 // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
156 GestureDetectorContainer::iterator endIter = std::remove_if(mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), IsNotAttachedFunctor(currentGesturedActor));
157 mCurrentRotationEmitters.erase(endIter, mCurrentRotationEmitters.end());
159 if(!mCurrentRotationEmitters.empty())
162 RenderTask& renderTaskImpl(*mCurrentRenderTask.Get());
163 currentGesturedActor->ScreenToLocal(renderTaskImpl, actorCoords.x, actorCoords.y, rotationEvent.centerPoint.x, rotationEvent.centerPoint.y);
165 EmitRotationSignal(currentGesturedActor, mCurrentRotationEmitters, rotationEvent, actorCoords);
169 // If we have no current emitters then clear rotated actor as well.
173 // Clear current emitters if rotation gesture has ended or been cancelled.
174 if(rotationEvent.state == GestureState::FINISHED || rotationEvent.state == GestureState::CANCELLED)
176 mCurrentRotationEmitters.clear();
182 mCurrentRotationEmitters.clear();
189 case GestureState::CLEAR:
190 case GestureState::POSSIBLE:
198 void RotationGestureProcessor::AddGestureDetector(RotationGestureDetector* gestureDetector, Scene& /* scene */)
200 bool createRecognizer(mRotationGestureDetectors.empty());
202 mRotationGestureDetectors.push_back(gestureDetector);
206 mGestureRecognizer = new RotationGestureRecognizer(*this, mMinimumTouchEvents, mMinimumTouchEventsAfterStart);
210 void RotationGestureProcessor::RemoveGestureDetector(RotationGestureDetector* gestureDetector)
212 if(!mCurrentRotationEmitters.empty())
214 // Check if the removed detector was one that is currently being rotated and remove it from emitters.
215 GestureDetectorContainer::iterator endIter = std::remove(mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), gestureDetector);
216 mCurrentRotationEmitters.erase(endIter, mCurrentRotationEmitters.end());
218 // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
219 if(mCurrentRotationEmitters.empty())
225 // Find the detector...
226 RotationGestureDetectorContainer::iterator endIter = std::remove(mRotationGestureDetectors.begin(), mRotationGestureDetectors.end(), gestureDetector);
227 DALI_ASSERT_DEBUG(endIter != mRotationGestureDetectors.end());
230 mRotationGestureDetectors.erase(endIter, mRotationGestureDetectors.end());
232 if(mRotationGestureDetectors.empty())
234 mGestureRecognizer = nullptr;
238 void RotationGestureProcessor::SetMinimumTouchEvents(uint32_t value)
240 if(value > 1u && mMinimumTouchEvents != value)
242 mMinimumTouchEvents = value;
244 if(mGestureRecognizer)
246 RotationGestureRecognizer* rotationRecognizer = dynamic_cast<RotationGestureRecognizer*>(mGestureRecognizer.Get());
247 if(rotationRecognizer)
249 rotationRecognizer->SetMinimumTouchEvents(value);
255 void RotationGestureProcessor::SetMinimumTouchEventsAfterStart(uint32_t value)
257 if(value > 1u && mMinimumTouchEventsAfterStart != value)
259 mMinimumTouchEventsAfterStart = value;
261 if(mGestureRecognizer)
263 RotationGestureRecognizer* rotationRecognizer = dynamic_cast<RotationGestureRecognizer*>(mGestureRecognizer.Get());
264 if(rotationRecognizer)
266 rotationRecognizer->SetMinimumTouchEventsAfterStart(value);
272 void RotationGestureProcessor::OnGesturedActorStageDisconnection()
274 mCurrentRotationEmitters.clear();
277 bool RotationGestureProcessor::CheckGestureDetector(GestureDetector* detector, Actor* actor)
279 // No special case required for rotation.
283 void RotationGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates)
285 DALI_ASSERT_DEBUG(mCurrentRotationEvent);
287 EmitRotationSignal(actor, gestureDetectors, *mCurrentRotationEvent, actorCoordinates);
291 mCurrentRotationEmitters = gestureDetectors;
296 } // namespace Internal