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-recognizer.h>
25 #include <dali/public-api/events/touch-point.h>
26 #include <dali/public-api/math/vector2.h>
27 #include <dali/devel-api/events/gesture-devel.h>
28 #include <dali/integration-api/events/touch-event-integ.h>
29 #include <dali/internal/event/events/rotation-gesture/rotation-gesture-event.h>
30 #include <dali/internal/event/common/scene-impl.h>
44 inline float GetAngle( const Integration::Point& point1, const Integration::Point& point2 )
46 const Vector2& point1ScreenPosition = point1.GetScreenPosition();
47 const Vector2& point2ScreenPosition = point2.GetScreenPosition();
48 return atan2( point2ScreenPosition.y - point1ScreenPosition.y, point2ScreenPosition.x - point1ScreenPosition.x );
51 inline Vector2 GetCenterPoint( const Integration::Point& point1, const Integration::Point& point2 )
53 return Vector2( point1.GetScreenPosition() + point2.GetScreenPosition() ) * 0.5f;
56 } // unnamed namespace
58 RotationGestureRecognizer::RotationGestureRecognizer( Observer& observer, uint32_t minimumTouchEvents, uint32_t minimumTouchEventsAfterStart )
59 : GestureRecognizer( DevelGesture::Rotation ),
60 mObserver( observer ),
63 mStartingAngle( 0.0f ),
64 mMinimumTouchEvents( minimumTouchEvents ),
65 mMinimumTouchEventsAfterStart( minimumTouchEventsAfterStart )
69 void RotationGestureRecognizer::SendEvent( const Integration::TouchEvent& event )
71 int pointCount = event.GetPointCount();
72 GestureRecognizerPtr ptr(this); // To keep us from being destroyed during the life-time of this method
80 // Change state to possible as we have two touch points.
82 mTouchEvents.push_back( event );
89 if ( pointCount != 2 )
91 // We no longer have two touch points so change state back to Clear.
97 const Integration::Point& currentPoint1 = event.points[0];
98 const Integration::Point& currentPoint2 = event.points[1];
100 if( currentPoint1.GetState() == PointState::UP || currentPoint2.GetState() == PointState::UP || currentPoint1.GetState() == PointState::INTERRUPTED )
102 // One of our touch points has an Up event so change our state back to Clear.
104 mTouchEvents.clear();
108 mTouchEvents.push_back( event );
110 // We can only determine a rotation after a certain number of touch points have been collected.
111 if( mTouchEvents.size() >= mMinimumTouchEvents )
113 // Remove the first few events from the vector otherwise values are exaggerated
114 mTouchEvents.erase( mTouchEvents.begin(), mTouchEvents.end() - mMinimumTouchEvents );
116 if( !mTouchEvents.empty() )
118 mStartingAngle = GetAngle( mTouchEvents.begin()->points[0], mTouchEvents.begin()->points[1] );
120 // Send rotation started
121 SendRotation( Gesture::Started, event );
126 mTouchEvents.clear();
128 if( mState == Possible )
130 // No rotation, so restart detection
132 mTouchEvents.clear();
142 if(event.points[0].GetState() == PointState::INTERRUPTED)
144 // System interruption occurred, rotation should be cancelled
145 mTouchEvents.clear();
146 SendRotation(Gesture::Cancelled, event);
148 mTouchEvents.clear();
150 else if( pointCount != 2 )
152 // Send rotation finished event
153 SendRotation( Gesture::Finished, event );
156 mTouchEvents.clear();
160 const Integration::Point& currentPoint1 = event.points[0];
161 const Integration::Point& currentPoint2 = event.points[1];
163 if( ( currentPoint1.GetState() == PointState::UP ) ||
164 ( currentPoint2.GetState() == PointState::UP ) )
166 mTouchEvents.push_back( event );
167 // Send rotation finished event
168 SendRotation( Gesture::Finished, event );
171 mTouchEvents.clear();
175 mTouchEvents.push_back( event );
177 if( mTouchEvents.size() >= mMinimumTouchEventsAfterStart )
179 // Send rotation continuing
180 SendRotation( Gesture::Continuing, event );
182 mTouchEvents.clear();
191 void RotationGestureRecognizer::SetMinimumTouchEvents( uint32_t value )
193 mMinimumTouchEvents = value;
196 void RotationGestureRecognizer::SetMinimumTouchEventsAfterStart( uint32_t value )
198 mMinimumTouchEventsAfterStart = value;
201 void RotationGestureRecognizer::SendRotation( Gesture::State state, const Integration::TouchEvent& currentEvent )
203 RotationGestureEvent gesture( state );
205 if( !mTouchEvents.empty() )
207 // Assert if we have been holding TouchEvents that do not have 2 points
208 DALI_ASSERT_DEBUG( mTouchEvents[0].GetPointCount() == 2 );
210 // We should use the current event in our calculations unless it does not have two points.
211 // If it does not have two points, then we should use the last point in mTouchEvents.
212 Integration::TouchEvent event( currentEvent );
213 if( event.GetPointCount() != 2 )
215 event = *mTouchEvents.rbegin();
218 const Integration::Point& currentPoint1( event.points[0] );
219 const Integration::Point& currentPoint2( event.points[1] );
221 gesture.rotation = GetAngle( currentPoint1, currentPoint2 ) - mStartingAngle;
222 gesture.centerPoint = GetCenterPoint( currentPoint1, currentPoint2 );
226 // Something has gone wrong, just cancel the gesture.
227 gesture.state = Gesture::Cancelled;
230 gesture.time = currentEvent.time;
234 // Create another handle so the recognizer cannot be destroyed during process function
235 GestureRecognizerPtr recognizerHandle = this;
237 mObserver.Process( *mScene, gesture );
241 } // namespace Internal