2 * Copyright (c) 2014 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 "long-press-gesture-detector.h"
24 #include <dali/public-api/events/touch-point.h>
25 #include <dali/public-api/math/vector2.h>
27 #include <dali/integration-api/events/gesture-requests.h>
28 #include <dali/integration-api/events/long-press-gesture-event.h>
29 #include <dali/integration-api/events/touch-event-integ.h>
31 #include <system-settings.h>
34 #include <base/core-event-interface.h>
47 // TODO: Set these according to DPI
48 const float MAXIMUM_MOTION_ALLOWED = 60.0f;
49 // TODO: Set this time according to system setting (vconf)
50 const unsigned long LONG_PRESS_TIME = 500u;
51 } // unnamed namespace
53 LongPressGestureDetector::LongPressGestureDetector(CoreEventInterface& coreEventInterface, Vector2 screenSize, const Integration::LongPressGestureRequest& request)
54 : GestureDetector(screenSize, Gesture::LongPress),
55 mCoreEventInterface(coreEventInterface),
57 mMinimumTouchesRequired(request.minTouches),
58 mMaximumTouchesRequired(request.maxTouches),
62 mTimer = Dali::Timer::New(GetSystemValue());
63 mTimer.TickSignal().Connect( mTimerSlot, &LongPressGestureDetector::TimerCallback );
66 LongPressGestureDetector::~LongPressGestureDetector()
70 void LongPressGestureDetector::SendEvent(const Integration::TouchEvent& event)
72 unsigned int pointCount( event.GetPointCount() );
76 // Clear: Wait till one point touches the screen before starting timer.
79 const Integration::Point& point = event.points[0];
81 if ( point.GetState() == PointState::DOWN )
83 mTouchPositions.clear();
84 mTouchPositions[point.GetDeviceId()] = point.GetScreenPosition();
86 mTouchTime = event.time;
88 mTimer.SetInterval(GetSystemValue());
91 // A long press gesture may be possible, tell Core about this and change state to Touched.
93 EmitGesture( Gesture::Possible );
99 // Touched: Monitor movement and addition/removal of points.
102 if (pointCount > mMaximumTouchesRequired)
104 // A long press did not occur, tell Core that it was cancelled and change state to Failed.
105 EmitGesture( Gesture::Cancelled );
106 mTouchPositions.clear();
114 for ( Integration::PointContainerConstIterator iter = event.points.begin(), endIter = event.points.end();
115 iter != endIter && !endLoop; ++iter)
117 switch( iter->GetState() )
120 case PointState::DOWN:
122 mTouchPositions[iter->GetDeviceId()] = iter->GetScreenPosition();
128 case PointState::INTERRUPTED:
130 // System has interrupted us, long press is not possible, inform Core
131 EmitGesture( Gesture::Cancelled );
132 mTouchPositions.clear();
134 mState = ( pointCount == 1 ) ? Clear : Failed; // Change state to Clear if only one point, Failed otherwise.
139 case PointState::MOTION:
141 const Vector2 touchPosition( mTouchPositions[iter->GetDeviceId()] - iter->GetScreenPosition() );
142 float distanceSquared = touchPosition.LengthSquared();
144 if (distanceSquared > ( MAXIMUM_MOTION_ALLOWED * MAXIMUM_MOTION_ALLOWED ) )
146 // We have moved more than the allowable motion for a long press gesture. Inform Core and change state to Failed.
147 EmitGesture( Gesture::Cancelled );
155 case PointState::STATIONARY:
156 case PointState::LEAVE:
165 // Failed/Finished: Monitor the touches, waiting for all touches to be released.
169 // eventually the final touch point will be removed, marking the end of this gesture.
170 if ( pointCount == 1 )
172 PointState::Type primaryPointState = event.points[0].GetState();
174 if ( (primaryPointState == PointState::UP) || (primaryPointState == PointState::INTERRUPTED) )
176 if(mState == Finished)
178 // When the last touch point is lifted, we should inform the Core that the Long press has finished.
179 EmitGesture(Gesture::Finished);
181 mTouchPositions.clear();
182 mState = Clear; // Reset state to clear when last touch point is lifted.
190 void LongPressGestureDetector::Update(const Integration::GestureRequest& request)
192 const Integration::LongPressGestureRequest& longPress = static_cast<const Integration::LongPressGestureRequest&>(request);
194 mMinimumTouchesRequired = longPress.minTouches;
195 mMaximumTouchesRequired = longPress.maxTouches;
198 bool LongPressGestureDetector::TimerCallback()
200 EmitGesture(Gesture::Started);
204 // There is no touch event at this time, so ProcessEvents must be called directly
205 mCoreEventInterface.ProcessCoreEvents();
210 void LongPressGestureDetector::EmitGesture(Gesture::State state)
212 unsigned int touchPoints ( mTouchPositions.size() );
214 // We should tell Core about the Possible and Cancelled states regardless of whether we have satisfied long press requirements.
215 if ( (state == Gesture::Possible) ||
216 (state == Gesture::Cancelled) ||
217 (touchPoints >= mMinimumTouchesRequired) )
219 Integration::LongPressGestureEvent longPress( state );
220 longPress.numberOfTouches = touchPoints;
222 for (std::map<int, Vector2>::iterator iter = mTouchPositions.begin(), endIter = mTouchPositions.end();
223 iter != endIter; ++iter)
225 longPress.point += iter->second;
227 longPress.point /= touchPoints;
229 longPress.time = mTouchTime;
230 if ( state != Gesture::Possible )
232 longPress.time += GetSystemValue();
235 mCoreEventInterface.QueueCoreEvent(longPress);
239 int LongPressGestureDetector::GetSystemValue()
241 return GetLongPressTime( LONG_PRESS_TIME );
244 } // namespace Adaptor
246 } // namespace Internal