mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 20:47:44 +00:00
181 lines
5.7 KiB
C++
181 lines
5.7 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
#include "mozSwipeGesture.h"
|
|
#include <QTouchEvent>
|
|
#include <QGraphicsWidget>
|
|
#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;
|
|
}
|