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/tap-gesture-processor.h>
25 #include <dali/public-api/actors/actor.h>
26 #include <dali/public-api/common/dali-common.h>
27 #include <dali/public-api/events/tap-gesture.h>
28 #include <dali/public-api/math/vector2.h>
29 #include <dali/integration-api/debug.h>
30 #include <dali/internal/event/actors/actor-impl.h>
31 #include <dali/internal/event/render-tasks/render-task-impl.h>
32 #include <dali/internal/event/common/scene-impl.h>
33 #include <dali/internal/event/events/tap-gesture-recognizer.h>
34 #include <dali/internal/event/events/gesture-requests.h>
35 #include <dali/internal/event/events/tap-gesture-event.h>
47 * Creates a TapGesture and asks the specified detector to emit its detected signal.
48 * @param[in] actor The actor on which a tap has occurred.
49 * @param[in] gestureDetectors A reference to gesture detectors that should emit the signal.
50 * @param[in] tapEvent The tapEvent received from the adaptor.
51 * @param[in] localPoint Relative to the actor attached to the detector.
55 const GestureDetectorContainer& gestureDetectors,
56 const TapGestureEvent& tapEvent,
60 tap.time = tapEvent.time;
61 tap.numberOfTaps = tapEvent.numberOfTaps;
62 tap.numberOfTouches = tapEvent.numberOfTouches;
63 tap.screenPoint = tapEvent.point;
64 tap.localPoint = localPoint;
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< TapGestureDetector* >( *iter )->EmitTapGestureSignal( actorHandle, tap );
74 } // unnamed namespace
76 TapGestureProcessor::TapGestureProcessor()
77 : GestureProcessor( Gesture::Tap ),
78 mTapGestureDetectors(),
79 mMinTapsRequired( 1 ),
80 mMaxTapsRequired( 1 ),
81 mMinTouchesRequired( 1 ),
82 mMaxTouchesRequired( 1 ),
83 mCurrentTapEvent( NULL ),
84 mPossibleProcessed( false )
88 TapGestureProcessor::~TapGestureProcessor()
92 void TapGestureProcessor::Process( Scene& scene, const TapGestureEvent& tapEvent )
94 switch ( tapEvent.state )
96 case Gesture::Possible:
98 // Do a hit test and if an actor has been hit then save to see if tap event is still valid on a tap( same actor being hit )
99 HitTestAlgorithm::Results hitTestResults;
100 if ( HitTest( scene, tapEvent.point, hitTestResults ) )
102 SetActor( &GetImplementation( hitTestResults.actor ) );
103 mCurrentTapActor.SetActor( GetCurrentGesturedActor() );
105 // Indicate that we've processed a touch down. Bool should be sufficient as a change in actor will result in a cancellation
106 mPossibleProcessed = true;
115 case Gesture::Started:
117 // Ensure that we're processing a hit on the current actor and that we've already processed a touch down
118 HitTestAlgorithm::Results hitTestResults;
119 if ( GetCurrentGesturedActor() && HitTest( scene, tapEvent.point, hitTestResults ) && mPossibleProcessed )
121 // Check that this actor is still the one that was used for the last touch down ?
122 if ( mCurrentTapActor.GetActor() == &GetImplementation( hitTestResults.actor ) )
124 mCurrentTapEvent = &tapEvent;
125 ProcessAndEmit( hitTestResults );
127 mCurrentTapEvent = NULL;
128 mPossibleProcessed = false;
133 case Gesture::Cancelled:
135 mPossibleProcessed = false;
140 case Gesture::Continuing:
142 DALI_ABORT( "Incorrect state received from Integration layer: Continuing\n" );
145 case Gesture::Finished:
147 DALI_ABORT( "Incorrect state received from Integration layer: Finished\n" );
152 DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
158 void TapGestureProcessor::AddGestureDetector( TapGestureDetector* gestureDetector, Scene& scene )
160 bool firstRegistration(mTapGestureDetectors.empty());
162 mTapGestureDetectors.push_back(gestureDetector);
164 const unsigned int minTapsRequired = gestureDetector->GetMinimumTapsRequired();
165 const unsigned int maxTapsRequired = gestureDetector->GetMaximumTapsRequired();
166 const unsigned int touchesRequired = gestureDetector->GetTouchesRequired();
168 DALI_ASSERT_ALWAYS( minTapsRequired <= maxTapsRequired && "Minimum taps requested is greater than the maximum requested" );
170 if (firstRegistration)
172 // If this is the first tap gesture detector that has been added, then our minimum and maximum
173 // requirements are the same as each other.
175 mMinTapsRequired = minTapsRequired;
176 mMaxTapsRequired = maxTapsRequired;
177 mMinTouchesRequired = mMaxTouchesRequired = touchesRequired;
179 TapGestureRequest request;
180 request.minTaps = mMinTapsRequired;
181 request.maxTaps = mMaxTapsRequired;
182 request.minTouches = mMinTouchesRequired;
183 request.maxTouches = mMaxTouchesRequired;
185 Size size = scene.GetSize();
186 mGestureRecognizer = new TapGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const TapGestureRequest&>(request));
190 // If we have already registered for tap gesture detection before then we need to check our
191 // minimum and maximums and see if our gesture detection requirements have changed, if they
192 // have, then we should ask the adaptor to update its detection policy.
194 // This is quicker than calling UpdateDetection as there is no need to iterate through the container
196 unsigned int minTaps = mMinTapsRequired < minTapsRequired ? mMinTapsRequired : minTapsRequired;
197 unsigned int maxTaps = mMaxTapsRequired > maxTapsRequired ? mMaxTapsRequired : maxTapsRequired;
198 unsigned int minTouches = mMinTouchesRequired < touchesRequired ? mMinTouchesRequired : touchesRequired;
199 unsigned int maxTouches = mMaxTouchesRequired > touchesRequired ? mMaxTouchesRequired : touchesRequired;
201 if ( (minTaps != mMinTapsRequired)||(maxTaps != mMaxTapsRequired) ||
202 (minTouches != mMinTouchesRequired)||(maxTouches != mMaxTouchesRequired) )
204 TapGestureRequest request;
205 request.minTaps = mMinTapsRequired = minTaps;
206 request.maxTaps = mMaxTapsRequired = maxTaps;
207 request.minTouches = mMinTouchesRequired = minTouches;
208 request.maxTouches = mMaxTouchesRequired = maxTouches;
210 mGestureRecognizer->Update(request);
215 void TapGestureProcessor::RemoveGestureDetector( TapGestureDetector* gestureDetector )
218 TapGestureDetectorContainer::iterator endIter = std::remove( mTapGestureDetectors.begin(), mTapGestureDetectors.end(), gestureDetector );
219 DALI_ASSERT_DEBUG( endIter != mTapGestureDetectors.end() );
222 mTapGestureDetectors.erase( endIter, mTapGestureDetectors.end() );
224 if ( mTapGestureDetectors.empty() )
226 mGestureRecognizer.Detach();
236 void TapGestureProcessor::GestureDetectorUpdated( TapGestureDetector* gestureDetector )
238 DALI_ASSERT_DEBUG(find(mTapGestureDetectors.begin(), mTapGestureDetectors.end(), gestureDetector) != mTapGestureDetectors.end());
240 const unsigned int minTapsRequired = gestureDetector->GetMinimumTapsRequired();
241 const unsigned int maxTapsRequired = gestureDetector->GetMaximumTapsRequired();
243 DALI_ASSERT_ALWAYS( minTapsRequired <= maxTapsRequired && "Minimum taps requested is greater than the maximum requested" );
248 void TapGestureProcessor::UpdateDetection()
250 DALI_ASSERT_DEBUG(!mTapGestureDetectors.empty());
252 unsigned int minTaps = UINT_MAX;
253 unsigned int maxTaps = 0;
254 unsigned int minTouches = UINT_MAX;
255 unsigned int maxTouches = 0;
257 for ( TapGestureDetectorContainer::iterator iter = mTapGestureDetectors.begin(), endIter = mTapGestureDetectors.end(); iter != endIter; ++iter )
259 TapGestureDetector* detector(*iter);
263 const unsigned int minTapsRequired = detector->GetMinimumTapsRequired();
264 const unsigned int maxTapsRequired = detector->GetMaximumTapsRequired();
265 const unsigned int touchesRequired = detector->GetTouchesRequired();
267 minTaps = minTapsRequired < minTaps ? minTapsRequired : minTaps;
268 maxTaps = maxTapsRequired > maxTaps ? maxTapsRequired : maxTaps;
269 minTouches = touchesRequired < minTouches ? touchesRequired : minTouches;
270 maxTouches = touchesRequired > maxTouches ? touchesRequired : maxTouches;
274 if ( (minTaps != mMinTapsRequired)||(maxTaps != mMaxTapsRequired) ||
275 (minTouches != mMinTouchesRequired)||(maxTouches != mMaxTouchesRequired) )
277 TapGestureRequest request;
278 request.minTaps = mMinTapsRequired = minTaps;
279 request.maxTaps = mMaxTapsRequired = maxTaps;
280 request.minTouches = mMinTouchesRequired = minTouches;
281 request.maxTouches = mMaxTouchesRequired = maxTouches;
283 mGestureRecognizer->Update(request);
287 bool TapGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
289 DALI_ASSERT_DEBUG( mCurrentTapEvent );
291 TapGestureDetector* tapDetector ( static_cast< TapGestureDetector* >( detector ) );
293 return ( ( tapDetector->GetMinimumTapsRequired() <= mCurrentTapEvent->numberOfTaps ) && ( tapDetector->GetMaximumTapsRequired() >= mCurrentTapEvent->numberOfTaps ) ) &&
294 ( tapDetector->GetTouchesRequired() == mCurrentTapEvent->numberOfTouches );
297 void TapGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
299 DALI_ASSERT_DEBUG( mCurrentTapEvent );
301 EmitTapSignal( actor, gestureDetectors, *mCurrentTapEvent, actorCoordinates );
304 } // namespace Internal