2 * Copyright (c) 2019 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/math/vector2.h>
27 #include <dali/devel-api/events/gesture-devel.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>
34 #include <dali/devel-api/events/rotation-gesture.h>
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 RotationGesture rotation(rotationEvent.state);
61 rotation.time = rotationEvent.time;
62 rotation.rotation = rotationEvent.rotation;
63 rotation.screenCenterPoint = rotationEvent.centerPoint;
64 rotation.localCenterPoint = localCenter;
66 Dali::Actor actorHandle( actor );
67 const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
68 for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
70 static_cast< RotationGestureDetector* >( *iter )->EmitRotationGestureSignal( actorHandle, rotation );
75 * Functor which checks whether the specified actor is attached to the gesture detector.
76 * It returns true if it is no longer attached. This can be used in remove_if functions.
78 struct IsNotAttachedFunctor
82 * @param[in] actor The actor to check whether it is attached.
84 IsNotAttachedFunctor(Actor* actor)
90 * Returns true if not attached, false if it is still attached.
91 * @param[in] detector The detector to check.
92 * @return true, if not attached, false otherwise.
94 bool operator()(const GestureDetector* detector) const
96 return !detector->IsAttached(*actorToCheck);
99 Actor* actorToCheck; ///< The actor to check whether it is attached or not.
102 } // unnamed namespace
104 RotationGestureProcessor::RotationGestureProcessor()
105 : GestureProcessor( DevelGesture::Rotation ),
106 mRotationGestureDetectors(),
107 mCurrentRotationEmitters(),
108 mCurrentRotationEvent( nullptr ),
109 mMinimumTouchEvents( MINIMUM_TOUCH_EVENTS_REQUIRED ),
110 mMinimumTouchEventsAfterStart( MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START )
114 void RotationGestureProcessor::Process( Scene& scene, const RotationGestureEvent& rotationEvent )
116 switch ( rotationEvent.state )
118 case Gesture::Started:
120 // The rotation gesture should only be sent to the gesture detector which first received it so that
121 // it can be told when the gesture ends as well.
123 mCurrentRotationEmitters.clear();
126 HitTestAlgorithm::Results hitTestResults;
127 if( HitTest( scene, rotationEvent.centerPoint, hitTestResults ) )
129 // Record the current render-task for Screen->Actor coordinate conversions
130 mCurrentRenderTask = hitTestResults.renderTask;
132 // Set mCurrentRotationEvent to use inside overridden methods called from ProcessAndEmit()
133 mCurrentRotationEvent = &rotationEvent;
134 ProcessAndEmit( hitTestResults );
135 mCurrentRotationEvent = NULL;
140 case Gesture::Continuing:
141 case Gesture::Finished:
142 case Gesture::Cancelled:
144 // Only send subsequent rotation gesture signals if we processed the rotation gesture when it started.
145 // Check if actor is still touchable.
147 Actor* currentGesturedActor = GetCurrentGesturedActor();
148 if ( currentGesturedActor )
150 if ( currentGesturedActor->IsHittable() && !mCurrentRotationEmitters.empty() && mCurrentRenderTask )
152 // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
153 GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
154 mCurrentRotationEmitters.erase( endIter, mCurrentRotationEmitters.end() );
156 if ( !mCurrentRotationEmitters.empty() )
159 RenderTask& renderTaskImpl( *mCurrentRenderTask.Get() );
160 currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, rotationEvent.centerPoint.x, rotationEvent.centerPoint.y );
162 EmitRotationSignal( currentGesturedActor, mCurrentRotationEmitters, rotationEvent, actorCoords );
166 // If we have no current emitters then clear rotated actor as well.
170 // Clear current emitters if rotation gesture has ended or been cancelled.
171 if ( rotationEvent.state == Gesture::Finished || rotationEvent.state == Gesture::Cancelled )
173 mCurrentRotationEmitters.clear();
179 mCurrentRotationEmitters.clear();
187 case Gesture::Possible:
195 void RotationGestureProcessor::AddGestureDetector( RotationGestureDetector* gestureDetector, Scene& /* scene */ )
197 bool createRecognizer(mRotationGestureDetectors.empty());
199 mRotationGestureDetectors.push_back(gestureDetector);
201 if (createRecognizer)
203 mGestureRecognizer = new RotationGestureRecognizer( *this, mMinimumTouchEvents, mMinimumTouchEventsAfterStart );
207 void RotationGestureProcessor::RemoveGestureDetector( RotationGestureDetector* gestureDetector )
209 if ( !mCurrentRotationEmitters.empty() )
211 // Check if the removed detector was one that is currently being rotated and remove it from emitters.
212 GestureDetectorContainer::iterator endIter = std::remove( mCurrentRotationEmitters.begin(), mCurrentRotationEmitters.end(), gestureDetector );
213 mCurrentRotationEmitters.erase( endIter, mCurrentRotationEmitters.end() );
215 // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
216 if ( mCurrentRotationEmitters.empty() )
222 // Find the detector...
223 RotationGestureDetectorContainer::iterator endIter = std::remove( mRotationGestureDetectors.begin(), mRotationGestureDetectors.end(), gestureDetector );
224 DALI_ASSERT_DEBUG( endIter != mRotationGestureDetectors.end() );
227 mRotationGestureDetectors.erase(endIter, mRotationGestureDetectors.end());
229 if (mRotationGestureDetectors.empty())
231 mGestureRecognizer.Detach();
235 void RotationGestureProcessor::SetMinimumTouchEvents( uint32_t value )
237 if( value > 1u && mMinimumTouchEvents != value )
239 mMinimumTouchEvents = value;
241 if( mGestureRecognizer )
243 RotationGestureRecognizer* rotationRecognizer = dynamic_cast<RotationGestureRecognizer*>( mGestureRecognizer.Get() );
244 if( rotationRecognizer )
246 rotationRecognizer->SetMinimumTouchEvents( value );
252 void RotationGestureProcessor::SetMinimumTouchEventsAfterStart( uint32_t value )
254 if( value > 1u && mMinimumTouchEventsAfterStart != value )
256 mMinimumTouchEventsAfterStart = value;
258 if( mGestureRecognizer )
260 RotationGestureRecognizer* rotationRecognizer = dynamic_cast<RotationGestureRecognizer*>( mGestureRecognizer.Get() );
261 if( rotationRecognizer )
263 rotationRecognizer->SetMinimumTouchEventsAfterStart( value );
269 void RotationGestureProcessor::OnGesturedActorStageDisconnection()
271 mCurrentRotationEmitters.clear();
274 bool RotationGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
276 // No special case required for rotation.
280 void RotationGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
282 DALI_ASSERT_DEBUG( mCurrentRotationEvent );
284 EmitRotationSignal( actor, gestureDetectors, *mCurrentRotationEvent, actorCoordinates );
286 if ( actor->OnStage() )
288 mCurrentRotationEmitters = gestureDetectors;
293 } // namespace Internal