2 * Copyright (c) 2020 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/public-api/actors/actor.h>
26 #include <dali/public-api/events/rotation-gesture.h>
27 #include <dali/public-api/math/vector2.h>
28 #include <dali/internal/event/events/rotation-gesture/rotation-gesture-event.h>
29 #include <dali/integration-api/debug.h>
30 #include <dali/internal/event/common/scene-impl.h>
31 #include <dali/internal/event/render-tasks/render-task-impl.h>
32 #include <dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.h>
33 #include <dali/internal/event/events/gesture-requests.h>
43 const uint32_t MINIMUM_TOUCH_EVENTS_REQUIRED = 4u;
44 const uint32_t MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START = 4u;
47 * Creates a RotationGesture and asks the specified detector to emit its detected signal.
48 * @param[in] actor The actor that has been rotationed.
49 * @param[in] gestureDetectors The gesture detector container that should emit the signal.
50 * @param[in] rotationEvent The rotationEvent received from the adaptor.
51 * @param[in] localCenter Relative to the actor attached to the detector.
53 void EmitRotationSignal(
55 const GestureDetectorContainer& gestureDetectors,
56 const RotationGestureEvent& rotationEvent,
59 RotationGesture rotation(rotationEvent.state);
60 rotation.time = rotationEvent.time;
61 rotation.rotation = rotationEvent.rotation;
62 rotation.screenCenterPoint = rotationEvent.centerPoint;
63 rotation.localCenterPoint = localCenter;
65 Dali::Actor actorHandle( actor );
66 const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
67 for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
69 static_cast< RotationGestureDetector* >( *iter )->EmitRotationGestureSignal( actorHandle, rotation );
74 * Functor which checks whether the specified actor is attached to the gesture detector.
75 * It returns true if it is no longer attached. This can be used in remove_if functions.
77 struct IsNotAttachedFunctor
81 * @param[in] actor The actor to check whether it is attached.
83 IsNotAttachedFunctor(Actor* actor)
89 * Returns true if not attached, false if it is still attached.
90 * @param[in] detector The detector to check.
91 * @return true, if not attached, false otherwise.
93 bool operator()(const GestureDetector* detector) const
95 return !detector->IsAttached(*actorToCheck);
98 Actor* actorToCheck; ///< The actor to check whether it is attached or not.
101 } // unnamed namespace
103 RotationGestureProcessor::RotationGestureProcessor()
104 : GestureProcessor( Gesture::Rotation ),
105 mRotationGestureDetectors(),
106 mCurrentRotationEmitters(),
107 mCurrentRotationEvent( nullptr ),
108 mMinimumTouchEvents( MINIMUM_TOUCH_EVENTS_REQUIRED ),
109 mMinimumTouchEventsAfterStart( MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START )
113 void RotationGestureProcessor::Process( Scene& scene, const RotationGestureEvent& rotationEvent )
115 switch ( rotationEvent.state )
117 case Gesture::Started:
119 // The rotation gesture should only be sent to the gesture detector which first received it so that
120 // it can be told when the gesture ends as well.
122 mCurrentRotationEmitters.clear();
125 HitTestAlgorithm::Results hitTestResults;
126 if( HitTest( scene, rotationEvent.centerPoint, hitTestResults ) )
128 // Record the current render-task for Screen->Actor coordinate conversions
129 mCurrentRenderTask = hitTestResults.renderTask;
131 // Set mCurrentRotationEvent to use inside overridden methods called from ProcessAndEmit()
132 mCurrentRotationEvent = &rotationEvent;
133 ProcessAndEmit( hitTestResults );
134 mCurrentRotationEvent = NULL;
139 case Gesture::Continuing:
140 case Gesture::Finished:
141 case Gesture::Cancelled:
143 // Only send subsequent rotation gesture signals if we processed the rotation gesture when it started.
144 // Check if actor is still touchable.
146 Actor* currentGesturedActor = GetCurrentGesturedActor();
147 if ( currentGesturedActor )
149 if ( currentGesturedActor->IsHittable() && !mCurrentRotationEmitters.empty() && mCurrentRenderTask )
151 // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
152 GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
153 mCurrentRotationEmitters.erase( endIter, mCurrentRotationEmitters.end() );
155 if ( !mCurrentRotationEmitters.empty() )
158 RenderTask& renderTaskImpl( *mCurrentRenderTask.Get() );
159 currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, rotationEvent.centerPoint.x, rotationEvent.centerPoint.y );
161 EmitRotationSignal( currentGesturedActor, mCurrentRotationEmitters, rotationEvent, actorCoords );
165 // If we have no current emitters then clear rotated actor as well.
169 // Clear current emitters if rotation gesture has ended or been cancelled.
170 if ( rotationEvent.state == Gesture::Finished || rotationEvent.state == Gesture::Cancelled )
172 mCurrentRotationEmitters.clear();
178 mCurrentRotationEmitters.clear();
186 case Gesture::Possible:
194 void RotationGestureProcessor::AddGestureDetector( RotationGestureDetector* gestureDetector, Scene& /* scene */ )
196 bool createRecognizer(mRotationGestureDetectors.empty());
198 mRotationGestureDetectors.push_back(gestureDetector);
200 if (createRecognizer)
202 mGestureRecognizer = new RotationGestureRecognizer( *this, mMinimumTouchEvents, mMinimumTouchEventsAfterStart );
206 void RotationGestureProcessor::RemoveGestureDetector( RotationGestureDetector* gestureDetector )
208 if ( !mCurrentRotationEmitters.empty() )
210 // Check if the removed detector was one that is currently being rotated and remove it from emitters.
211 GestureDetectorContainer::iterator endIter = std::remove( mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), gestureDetector );
212 mCurrentRotationEmitters.erase( endIter, mCurrentRotationEmitters.end() );
214 // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
215 if ( mCurrentRotationEmitters.empty() )
221 // Find the detector...
222 RotationGestureDetectorContainer::iterator endIter = std::remove( mRotationGestureDetectors.begin(), mRotationGestureDetectors.end(), gestureDetector );
223 DALI_ASSERT_DEBUG( endIter != mRotationGestureDetectors.end() );
226 mRotationGestureDetectors.erase(endIter, mRotationGestureDetectors.end());
228 if (mRotationGestureDetectors.empty())
230 mGestureRecognizer = nullptr;
234 void RotationGestureProcessor::SetMinimumTouchEvents( uint32_t value )
236 if( value > 1u && mMinimumTouchEvents != value )
238 mMinimumTouchEvents = value;
240 if( mGestureRecognizer )
242 RotationGestureRecognizer* rotationRecognizer = dynamic_cast<RotationGestureRecognizer*>( mGestureRecognizer.Get() );
243 if( rotationRecognizer )
245 rotationRecognizer->SetMinimumTouchEvents( value );
251 void RotationGestureProcessor::SetMinimumTouchEventsAfterStart( uint32_t value )
253 if( value > 1u && mMinimumTouchEventsAfterStart != value )
255 mMinimumTouchEventsAfterStart = value;
257 if( mGestureRecognizer )
259 RotationGestureRecognizer* rotationRecognizer = dynamic_cast<RotationGestureRecognizer*>( mGestureRecognizer.Get() );
260 if( rotationRecognizer )
262 rotationRecognizer->SetMinimumTouchEventsAfterStart( value );
268 void RotationGestureProcessor::OnGesturedActorStageDisconnection()
270 mCurrentRotationEmitters.clear();
273 bool RotationGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
275 // No special case required for rotation.
279 void RotationGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
281 DALI_ASSERT_DEBUG( mCurrentRotationEvent );
283 EmitRotationSignal( actor, gestureDetectors, *mCurrentRotationEvent, actorCoordinates );
285 if ( actor->OnScene() )
287 mCurrentRotationEmitters = gestureDetectors;
292 } // namespace Internal