зеркало из https://github.com/mozilla/gecko-dev.git
212 строки
7.2 KiB
C++
212 строки
7.2 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Initial Developer of the Original Code is Nokia Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Miika Jarvinen <mjarvin@gmail.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
#include "mozSwipeGesture.h"
|
|
#include <QTouchEvent>
|
|
#include <QGraphicsWidget>
|
|
#include <prtypes.h>
|
|
#include <nsIDOMSimpleGestureEvent.h>
|
|
#include <math.h>
|
|
|
|
// Percent of screen size
|
|
static const float TRIGGER_DISTANCE = 0.3;
|
|
|
|
// It would be nice to get platform defines for these values
|
|
// Maximum finger distance in pixels
|
|
const int MAX_FINGER_DISTANCE = 250;
|
|
// We could define it as 2*QT_GUI_DOUBLE_CLICK_RADIUS, but it's not available
|
|
// due to QTBUG-9630
|
|
const int FINGER_DISTANCE_MISTAKE = 50;
|
|
|
|
QGesture*
|
|
MozSwipeGestureRecognizer::create(QObject* target)
|
|
{
|
|
return new MozSwipeGesture();
|
|
}
|
|
|
|
QGestureRecognizer::Result
|
|
MozSwipeGestureRecognizer::recognize(QGesture* aState,
|
|
QObject* aWatched,
|
|
QEvent* aEvent)
|
|
{
|
|
const QTouchEvent* ev = static_cast<const QTouchEvent *>(aEvent);
|
|
MozSwipeGesture* swipe = static_cast<MozSwipeGesture *>(aState);
|
|
|
|
QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
|
|
|
|
QGraphicsWidget* widget = qobject_cast<QGraphicsWidget*>(aWatched);
|
|
if (!widget) {
|
|
return result;
|
|
}
|
|
|
|
switch (aEvent->type()) {
|
|
case QEvent::TouchBegin:
|
|
swipe->mSwipeState = MozSwipeGesture::NOT_STARTED;
|
|
result = QGestureRecognizer::MayBeGesture;
|
|
break;
|
|
|
|
case QEvent::TouchEnd:
|
|
if (swipe->state() != Qt::NoGesture &&
|
|
swipe->mSwipeState == MozSwipeGesture::TRIGGERED) {
|
|
result = QGestureRecognizer::FinishGesture;
|
|
}
|
|
else {
|
|
result = QGestureRecognizer::CancelGesture;
|
|
}
|
|
break;
|
|
|
|
case QEvent::TouchUpdate:
|
|
// We have already handled this swipe
|
|
if (swipe->mSwipeState > MozSwipeGesture::STARTED) {
|
|
break;
|
|
}
|
|
|
|
if (ev->touchPoints().count() > 2) {
|
|
swipe->mSwipeState = MozSwipeGesture::CANCELLED;
|
|
result = QGestureRecognizer::CancelGesture;
|
|
break;
|
|
}
|
|
|
|
|
|
if (ev->touchPoints().count() == 2) {
|
|
swipe->mSwipeState = MozSwipeGesture::STARTED;
|
|
QList <QTouchEvent::TouchPoint> touchPoints = ev->touchPoints();
|
|
if (!swipe->Update(touchPoints[0], touchPoints[1], widget->size())) {
|
|
result = QGestureRecognizer::CancelGesture;
|
|
swipe->mSwipeState = MozSwipeGesture::CANCELLED;
|
|
}
|
|
if (swipe->mSwipeState == MozSwipeGesture::TRIGGERED) {
|
|
result = QGestureRecognizer::TriggerGesture;
|
|
}
|
|
else {
|
|
result = QGestureRecognizer::MayBeGesture;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
result = QGestureRecognizer::Ignore;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void
|
|
MozSwipeGestureRecognizer::reset(QGesture* aState)
|
|
{
|
|
MozSwipeGesture* swipe = static_cast<MozSwipeGesture *>(aState);
|
|
swipe->mHorizontalDirection = 0;
|
|
swipe->mVerticalDirection = 0;
|
|
QGestureRecognizer::reset(aState);
|
|
}
|
|
|
|
MozSwipeGesture::MozSwipeGesture()
|
|
: mHorizontalDirection(0)
|
|
, mVerticalDirection(0)
|
|
, mSwipeState(MozSwipeGesture::NOT_STARTED)
|
|
{
|
|
}
|
|
|
|
int MozSwipeGesture::Direction()
|
|
{
|
|
return mHorizontalDirection | mVerticalDirection;
|
|
}
|
|
|
|
bool
|
|
MozSwipeGesture::Update(const QTouchEvent::TouchPoint& aFirstPoint,
|
|
const QTouchEvent::TouchPoint& aSecondPoint,
|
|
const QSizeF& aSize)
|
|
{
|
|
// Check that fingers are not too far away
|
|
QPointF fingerDistance = aFirstPoint.pos() - aSecondPoint.pos();
|
|
if (fingerDistance.manhattanLength() > MAX_FINGER_DISTANCE) {
|
|
return false;
|
|
}
|
|
|
|
// Check that fingers doesn't move too much from the original distance
|
|
QPointF startFingerDistance = aFirstPoint.startPos() - aSecondPoint.startPos();
|
|
if ((startFingerDistance - fingerDistance).manhattanLength()
|
|
> FINGER_DISTANCE_MISTAKE) {
|
|
return false;
|
|
}
|
|
|
|
QPointF startPosition = aFirstPoint.startNormalizedPos();
|
|
QPointF currentPosition = aFirstPoint.normalizedPos();
|
|
|
|
float xDistance = fabs(currentPosition.x() - startPosition.x());
|
|
float yDistance = fabs(currentPosition.y() - startPosition.y());
|
|
|
|
startPosition = aFirstPoint.startPos();
|
|
currentPosition = aFirstPoint.pos();
|
|
|
|
if (!aSize.isEmpty()) {
|
|
xDistance = fabs(currentPosition.x() - startPosition.x())
|
|
/ aSize.width();
|
|
yDistance = fabs(currentPosition.y() - startPosition.y())
|
|
/ aSize.height();
|
|
}
|
|
|
|
mVerticalDirection = nsIDOMSimpleGestureEvent::DIRECTION_UP;
|
|
if (currentPosition.y() > startPosition.y()) {
|
|
mVerticalDirection = nsIDOMSimpleGestureEvent::DIRECTION_DOWN;
|
|
}
|
|
|
|
mHorizontalDirection = nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
|
|
if (currentPosition.x() > startPosition.x()) {
|
|
mHorizontalDirection = nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
|
|
}
|
|
|
|
if (xDistance > TRIGGER_DISTANCE) {
|
|
if (yDistance < TRIGGER_DISTANCE/2) {
|
|
mVerticalDirection = 0;
|
|
}
|
|
mSwipeState = TRIGGERED;
|
|
}
|
|
|
|
if (yDistance > TRIGGER_DISTANCE) {
|
|
if (xDistance < TRIGGER_DISTANCE/2) {
|
|
mHorizontalDirection = 0;
|
|
}
|
|
mSwipeState = TRIGGERED;
|
|
}
|
|
|
|
// Use center of touchpoints as hotspot
|
|
QPointF hotspot = aFirstPoint.pos() + aSecondPoint.pos();
|
|
hotspot /= 2;
|
|
setHotSpot(hotspot);
|
|
return true;
|
|
}
|