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/pinch-gesture/pinch-gesture-processor.h>
25 #include <dali/public-api/actors/actor.h>
26 #include <dali/public-api/events/pinch-gesture.h>
27 #include <dali/public-api/math/vector2.h>
28 #include <dali/internal/event/events/pinch-gesture/pinch-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/pinch-gesture/pinch-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 PinchGesture and asks the specified detector to emit its detected signal.
48 * @param[in] actor The actor that has been pinched.
49 * @param[in] gestureDetectors The gesture detector container that should emit the signal.
50 * @param[in] pinchEvent The pinchEvent received from the adaptor.
51 * @param[in] localCenter Relative to the actor attached to the detector.
55 const GestureDetectorContainer& gestureDetectors,
56 const PinchGestureEvent& pinchEvent,
59 PinchGesture pinch(pinchEvent.state);
60 pinch.time = pinchEvent.time;
62 pinch.scale = pinchEvent.scale;
63 pinch.speed = pinchEvent.speed;
64 pinch.screenCenterPoint = pinchEvent.centerPoint;
66 pinch.localCenterPoint = localCenter;
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< PinchGestureDetector* >( *iter )->EmitPinchGestureSignal( actorHandle, pinch );
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 PinchGestureProcessor::PinchGestureProcessor()
107 : GestureProcessor( Gesture::Pinch ),
108 mPinchGestureDetectors(),
109 mCurrentPinchEmitters(),
110 mCurrentPinchEvent(NULL),
111 mMinimumPinchDistance(-1.0f),
112 mMinimumTouchEvents( MINIMUM_TOUCH_EVENTS_REQUIRED ),
113 mMinimumTouchEventsAfterStart( MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START )
117 PinchGestureProcessor::~PinchGestureProcessor()
121 void PinchGestureProcessor::SetMinimumPinchDistance( float value )
123 mMinimumPinchDistance = value;
125 if( mGestureRecognizer )
127 PinchGestureRecognizer* pinchRecognizer = dynamic_cast<PinchGestureRecognizer*>(mGestureRecognizer.Get());
128 if( pinchRecognizer )
130 pinchRecognizer->SetMinimumPinchDistance(value);
135 void PinchGestureProcessor::SetMinimumTouchEvents( uint32_t value )
137 if( value > 1u && mMinimumTouchEvents != value )
139 mMinimumTouchEvents = value;
141 if( mGestureRecognizer )
143 PinchGestureRecognizer* pinchRecognizer = dynamic_cast<PinchGestureRecognizer*>( mGestureRecognizer.Get() );
144 if( pinchRecognizer )
146 pinchRecognizer->SetMinimumTouchEvents( value );
152 void PinchGestureProcessor::SetMinimumTouchEventsAfterStart( uint32_t value )
154 if( value > 1u && mMinimumTouchEventsAfterStart != value )
156 mMinimumTouchEventsAfterStart = value;
158 if( mGestureRecognizer )
160 PinchGestureRecognizer* pinchRecognizer = dynamic_cast<PinchGestureRecognizer*>( mGestureRecognizer.Get() );
161 if( pinchRecognizer )
163 pinchRecognizer->SetMinimumTouchEventsAfterStart( value );
169 void PinchGestureProcessor::Process( Scene& scene, const PinchGestureEvent& pinchEvent )
171 switch ( pinchEvent.state )
173 case Gesture::Started:
175 // The pinch gesture should only be sent to the gesture detector which first received it so that
176 // it can be told when the gesture ends as well.
178 mCurrentPinchEmitters.clear();
181 HitTestAlgorithm::Results hitTestResults;
182 if( HitTest( scene, pinchEvent.centerPoint, hitTestResults ) )
184 // Record the current render-task for Screen->Actor coordinate conversions
185 mCurrentRenderTask = hitTestResults.renderTask;
187 // Set mCurrentPinchEvent to use inside overridden methods called from ProcessAndEmit()
188 mCurrentPinchEvent = &pinchEvent;
189 ProcessAndEmit( hitTestResults );
190 mCurrentPinchEvent = NULL;
195 case Gesture::Continuing:
196 case Gesture::Finished:
197 case Gesture::Cancelled:
199 // Only send subsequent pinch gesture signals if we processed the pinch gesture when it started.
200 // Check if actor is still touchable.
202 Actor* currentGesturedActor = GetCurrentGesturedActor();
203 if ( currentGesturedActor )
205 if ( currentGesturedActor->IsHittable() && !mCurrentPinchEmitters.empty() && mCurrentRenderTask )
207 // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
208 GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
209 mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
211 if ( !mCurrentPinchEmitters.empty() )
214 RenderTask& renderTaskImpl( *mCurrentRenderTask.Get() );
215 currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, pinchEvent.centerPoint.x, pinchEvent.centerPoint.y );
217 EmitPinchSignal( currentGesturedActor, mCurrentPinchEmitters, pinchEvent, actorCoords );
221 // If we have no current emitters then clear pinched actor as well.
225 // Clear current emitters if pinch gesture has ended or been cancelled.
226 if ( pinchEvent.state == Gesture::Finished || pinchEvent.state == Gesture::Cancelled )
228 mCurrentPinchEmitters.clear();
234 mCurrentPinchEmitters.clear();
243 DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
246 case Gesture::Possible:
248 DALI_ABORT( "Incorrect state received from Integration layer: Possible\n" );
254 void PinchGestureProcessor::AddGestureDetector( PinchGestureDetector* gestureDetector, Scene& scene )
256 bool createRecognizer(mPinchGestureDetectors.empty());
258 mPinchGestureDetectors.push_back(gestureDetector);
260 if (createRecognizer)
262 Size size = scene.GetSize();
263 mGestureRecognizer = new PinchGestureRecognizer( *this, Vector2(size.width, size.height), scene.GetDpi(), mMinimumPinchDistance, mMinimumTouchEventsAfterStart, mMinimumTouchEventsAfterStart );
267 void PinchGestureProcessor::RemoveGestureDetector( PinchGestureDetector* gestureDetector )
269 if ( !mCurrentPinchEmitters.empty() )
271 // Check if the removed detector was one that is currently being pinched and remove it from emitters.
272 GestureDetectorContainer::iterator endIter = std::remove( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), gestureDetector );
273 mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
275 // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
276 if ( mCurrentPinchEmitters.empty() )
282 // Find the detector...
283 PinchGestureDetectorContainer::iterator endIter = std::remove( mPinchGestureDetectors.begin(), mPinchGestureDetectors.end(), gestureDetector );
284 DALI_ASSERT_DEBUG( endIter != mPinchGestureDetectors.end() );
287 mPinchGestureDetectors.erase(endIter, mPinchGestureDetectors.end());
289 if (mPinchGestureDetectors.empty())
291 mGestureRecognizer.Detach();
295 void PinchGestureProcessor::GestureDetectorUpdated( PinchGestureDetector* gestureDetector )
297 // Nothing to do as PinchGestureDetector does not have any specific parameters.
300 void PinchGestureProcessor::OnGesturedActorStageDisconnection()
302 mCurrentPinchEmitters.clear();
305 bool PinchGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
307 // No special case required for pinch.
311 void PinchGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
313 DALI_ASSERT_DEBUG( mCurrentPinchEvent );
315 EmitPinchSignal( actor, gestureDetectors, *mCurrentPinchEvent, actorCoordinates );
317 if ( actor->OnStage() )
319 mCurrentPinchEmitters = gestureDetectors;
324 } // namespace Internal