cf74b6f28fa2bad0904720ebd6dbefbef20c95f1
[platform/core/uifw/dali-core.git] / dali / internal / event / events / tap-gesture / tap-gesture-processor.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/events/tap-gesture/tap-gesture-processor.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23
24 // INTERNAL INCLUDES
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/tap-gesture-recognizer.h>
34 #include <dali/internal/event/events/gesture-requests.h>
35 #include <dali/internal/event/events/tap-gesture/tap-gesture-event.h>
36
37 namespace Dali
38 {
39
40 namespace Internal
41 {
42
43 namespace
44 {
45
46 /**
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.
52  */
53 void EmitTapSignal(
54   Actor* actor,
55   const GestureDetectorContainer& gestureDetectors,
56   const TapGestureEvent& tapEvent,
57   Vector2 localPoint)
58 {
59   TapGesture tap;
60   tap.time = tapEvent.time;
61   tap.numberOfTaps = tapEvent.numberOfTaps;
62   tap.numberOfTouches = tapEvent.numberOfTouches;
63   tap.screenPoint = tapEvent.point;
64   tap.localPoint = localPoint;
65
66   Dali::Actor actorHandle( actor );
67   const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
68   for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
69   {
70     static_cast< TapGestureDetector* >( *iter )->EmitTapGestureSignal( actorHandle, tap );
71   }
72 }
73
74 } // unnamed namespace
75
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 )
85 {
86 }
87
88 TapGestureProcessor::~TapGestureProcessor()
89 {
90 }
91
92 void TapGestureProcessor::Process( Scene& scene, const TapGestureEvent& tapEvent )
93 {
94   switch ( tapEvent.state )
95   {
96     case Gesture::Possible:
97     {
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 ) )
101       {
102         SetActor( &GetImplementation( hitTestResults.actor ) );
103         mCurrentTapActor.SetActor( GetCurrentGesturedActor() );
104
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;
107       }
108       else
109       {
110         ResetActor();
111       }
112       break;
113     }
114
115     case Gesture::Started:
116     {
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 )
120       {
121         // Check that this actor is still the one that was used for the last touch down ?
122         if ( mCurrentTapActor.GetActor() == &GetImplementation( hitTestResults.actor ) )
123         {
124           mCurrentTapEvent = &tapEvent;
125           ProcessAndEmit( hitTestResults );
126         }
127         mCurrentTapEvent = NULL;
128         mPossibleProcessed = false;
129       }
130       break;
131     }
132
133     case Gesture::Cancelled:
134     {
135       mPossibleProcessed = false;
136       ResetActor();
137       break;
138     }
139
140     case Gesture::Continuing:
141     {
142       DALI_ABORT( "Incorrect state received from Integration layer: Continuing\n" );
143       break;
144     }
145     case Gesture::Finished:
146     {
147       DALI_ABORT( "Incorrect state received from Integration layer: Finished\n" );
148       break;
149     }
150     case Gesture::Clear:
151     {
152       DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
153       break;
154     }
155   }
156 }
157
158 void TapGestureProcessor::AddGestureDetector( TapGestureDetector* gestureDetector, Scene& scene )
159 {
160   bool firstRegistration(mTapGestureDetectors.empty());
161
162   mTapGestureDetectors.push_back(gestureDetector);
163
164   const unsigned int minTapsRequired = gestureDetector->GetMinimumTapsRequired();
165   const unsigned int maxTapsRequired = gestureDetector->GetMaximumTapsRequired();
166   const unsigned int touchesRequired = gestureDetector->GetTouchesRequired();
167
168   DALI_ASSERT_ALWAYS( minTapsRequired <= maxTapsRequired && "Minimum taps requested is greater than the maximum requested" );
169
170   if (firstRegistration)
171   {
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.
174
175     mMinTapsRequired = minTapsRequired;
176     mMaxTapsRequired = maxTapsRequired;
177     mMinTouchesRequired = mMaxTouchesRequired = touchesRequired;
178
179     TapGestureRequest request;
180     request.minTaps = mMinTapsRequired;
181     request.maxTaps = mMaxTapsRequired;
182     request.minTouches = mMinTouchesRequired;
183     request.maxTouches = mMaxTouchesRequired;
184
185     Size size = scene.GetSize();
186     mGestureRecognizer = new TapGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const TapGestureRequest&>(request));
187   }
188   else
189   {
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.
193
194     // This is quicker than calling UpdateDetection as there is no need to iterate through the container
195
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;
200
201     if ( (minTaps != mMinTapsRequired)||(maxTaps != mMaxTapsRequired) ||
202          (minTouches != mMinTouchesRequired)||(maxTouches != mMaxTouchesRequired) )
203     {
204       TapGestureRequest request;
205       request.minTaps = mMinTapsRequired = minTaps;
206       request.maxTaps = mMaxTapsRequired = maxTaps;
207       request.minTouches = mMinTouchesRequired = minTouches;
208       request.maxTouches = mMaxTouchesRequired = maxTouches;
209
210       mGestureRecognizer->Update(request);
211     }
212   }
213 }
214
215 void TapGestureProcessor::RemoveGestureDetector( TapGestureDetector* gestureDetector )
216 {
217   // Find detector ...
218   TapGestureDetectorContainer::iterator endIter = std::remove( mTapGestureDetectors.begin(), mTapGestureDetectors.end(), gestureDetector );
219   DALI_ASSERT_DEBUG( endIter != mTapGestureDetectors.end() );
220
221   // ... and remove it
222   mTapGestureDetectors.erase( endIter, mTapGestureDetectors.end() );
223
224   if ( mTapGestureDetectors.empty() )
225   {
226     mGestureRecognizer = nullptr;
227
228     ResetActor();
229   }
230   else
231   {
232     UpdateDetection();
233   }
234 }
235
236 void TapGestureProcessor::GestureDetectorUpdated( TapGestureDetector* gestureDetector )
237 {
238   DALI_ASSERT_DEBUG(find(mTapGestureDetectors.begin(), mTapGestureDetectors.end(), gestureDetector) != mTapGestureDetectors.end());
239
240   const unsigned int minTapsRequired = gestureDetector->GetMinimumTapsRequired();
241   const unsigned int maxTapsRequired = gestureDetector->GetMaximumTapsRequired();
242
243   DALI_ASSERT_ALWAYS( minTapsRequired <= maxTapsRequired && "Minimum taps requested is greater than the maximum requested" );
244
245   UpdateDetection();
246 }
247
248 void TapGestureProcessor::UpdateDetection()
249 {
250   DALI_ASSERT_DEBUG(!mTapGestureDetectors.empty());
251
252   unsigned int minTaps = UINT_MAX;
253   unsigned int maxTaps = 0;
254   unsigned int minTouches = UINT_MAX;
255   unsigned int maxTouches = 0;
256
257   for ( TapGestureDetectorContainer::iterator iter = mTapGestureDetectors.begin(), endIter = mTapGestureDetectors.end(); iter != endIter; ++iter )
258   {
259     TapGestureDetector* detector(*iter);
260
261     if( detector )
262     {
263       const unsigned int minTapsRequired = detector->GetMinimumTapsRequired();
264       const unsigned int maxTapsRequired = detector->GetMaximumTapsRequired();
265       const unsigned int touchesRequired = detector->GetTouchesRequired();
266
267       minTaps = minTapsRequired < minTaps ? minTapsRequired : minTaps;
268       maxTaps = maxTapsRequired > maxTaps ? maxTapsRequired : maxTaps;
269       minTouches = touchesRequired < minTouches ? touchesRequired : minTouches;
270       maxTouches = touchesRequired > maxTouches ? touchesRequired : maxTouches;
271     }
272   }
273
274   if ( (minTaps != mMinTapsRequired)||(maxTaps != mMaxTapsRequired) ||
275        (minTouches != mMinTouchesRequired)||(maxTouches != mMaxTouchesRequired) )
276   {
277     TapGestureRequest request;
278     request.minTaps = mMinTapsRequired = minTaps;
279     request.maxTaps = mMaxTapsRequired = maxTaps;
280     request.minTouches = mMinTouchesRequired = minTouches;
281     request.maxTouches = mMaxTouchesRequired = maxTouches;
282
283     mGestureRecognizer->Update(request);
284   }
285 }
286
287 bool TapGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
288 {
289   DALI_ASSERT_DEBUG( mCurrentTapEvent );
290
291   TapGestureDetector* tapDetector ( static_cast< TapGestureDetector* >( detector ) );
292
293   return ( ( tapDetector->GetMinimumTapsRequired() <= mCurrentTapEvent->numberOfTaps ) && ( tapDetector->GetMaximumTapsRequired() >= mCurrentTapEvent->numberOfTaps ) ) &&
294          ( tapDetector->GetTouchesRequired() == mCurrentTapEvent->numberOfTouches );
295 }
296
297 void TapGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
298 {
299   DALI_ASSERT_DEBUG( mCurrentTapEvent );
300
301   EmitTapSignal( actor, gestureDetectors, *mCurrentTapEvent, actorCoordinates );
302 }
303
304 } // namespace Internal
305
306 } // namespace Dali