/* -*- 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 #include #include #include #include // 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(aEvent); MozSwipeGesture* swipe = static_cast(aState); QGestureRecognizer::Result result = QGestureRecognizer::Ignore; QGraphicsWidget* widget = qobject_cast(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 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(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; }