blob: eea6385bb5bb0cfb9642d8e365f9590b98cc1019 [file] [log] [blame] [edit]
/*
* Copyright (C) 2011, 2012 Nokia Corporation and/or its subsidiary(-ies)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "QtTapGestureRecognizer.h"
#include "QtWebPageEventHandler.h"
#include <QLineF>
namespace WebKit {
// FIXME: These constants should possibly depend on DPI.
static const int panDistanceThreshold = 10;
static const int maxDoubleTapDistance = 120;
// FIXME: These constants should possibly be consistent across the platform.
static const int tapAndHoldTime = 1000;
static const int maxDoubleTapInterval = 500;
static const int highlightDelay = 100;
QtTapGestureRecognizer::QtTapGestureRecognizer(QtWebPageEventHandler* eventHandler)
: QtGestureRecognizer(eventHandler)
, m_candidate(SingleTapCandidate)
{
}
bool QtTapGestureRecognizer::withinDistance(const QTouchEvent::TouchPoint& touchPoint, int distance)
{
ASSERT(m_lastTouchPoint.id() != -1);
return QLineF(touchPoint.screenPos(), m_lastTouchPoint.screenPos()).length() < distance;
}
void QtTapGestureRecognizer::update(const QTouchEvent::TouchPoint& touchPoint)
{
switch (m_state) {
case NoGesture:
m_doubleTapTimer.stop(); // Cancel other pending single tap event.
m_state = GestureRecognitionStarted;
ASSERT(!m_tapAndHoldTimer.isActive());
m_tapAndHoldTimer.start(tapAndHoldTime, this);
// Early return if this is the second touch point of a potential double tap gesture.
if (m_candidate == DoubleTapCandidate && withinDistance(touchPoint, maxDoubleTapDistance))
return;
// The below in fact resets any previous single tap event.
m_candidate = SingleTapCandidate;
m_lastTouchPoint = touchPoint;
m_highlightTimer.start(highlightDelay, this);
m_doubleTapTimer.start(maxDoubleTapInterval, this);
break;
case GestureRecognitionStarted:
// If the touch point moves further than the threshold, we cancel the tap gesture.
if (!withinDistance(touchPoint, panDistanceThreshold))
reset();
break;
default:
ASSERT_NOT_REACHED();
break;
}
}
void QtTapGestureRecognizer::finish(const QTouchEvent::TouchPoint& touchPoint)
{
ASSERT(m_eventHandler);
m_tapAndHoldTimer.stop();
// Gesture has been cancelled, ignore.
if (m_state == NoGesture)
return;
m_state = NoGesture;
if (m_candidate == SingleTapCandidate) {
if (m_doubleTapTimer.isActive()) {
m_candidate = DoubleTapCandidate;
m_lastTouchPoint = touchPoint;
// Early return since this is a potential double tap gesture.
return;
}
// This happens when the finger is released (gesture finished) after the single
// tap timeout elapsed (500ms) but before the tap-and-hold timeout (1000ms) fired.
m_eventHandler->handleSingleTapEvent(touchPoint);
} else // DoubleTapCandidate
m_eventHandler->handleDoubleTapEvent(touchPoint);
reset();
}
void QtTapGestureRecognizer::cancel()
{
if (m_lastTouchPoint.id() == -1)
return;
reset();
}
void QtTapGestureRecognizer::highlightTimeout()
{
m_highlightTimer.stop();
// Gesture has been cancelled, ignore.
if (m_lastTouchPoint.id() == -1)
return;
m_eventHandler->activateTapHighlight(m_lastTouchPoint);
}
void QtTapGestureRecognizer::singleTapTimeout()
{
m_doubleTapTimer.stop();
// Finger is still pressed or gesture has been cancelled, ignore.
if (m_tapAndHoldTimer.isActive() || m_lastTouchPoint.id() == -1)
return;
m_eventHandler->handleSingleTapEvent(m_lastTouchPoint);
reset();
}
void QtTapGestureRecognizer::tapAndHoldTimeout()
{
m_tapAndHoldTimer.stop();
// Gesture has been cancelled, ignore.
if (m_lastTouchPoint.id() == -1)
return;
#if 0 // No support for synthetic context menus in WK2 yet.
m_eventHandler->handleTapAndHoldEvent(m_lastTouchPoint);
#endif
reset();
}
void QtTapGestureRecognizer::reset()
{
m_eventHandler->deactivateTapHighlight();
m_candidate = SingleTapCandidate;
m_lastTouchPoint.setId(-1);
m_highlightTimer.stop();
m_doubleTapTimer.stop();
m_tapAndHoldTimer.stop();
QtGestureRecognizer::reset();
}
void QtTapGestureRecognizer::timerEvent(QTimerEvent* ev)
{
int timerId = ev->timerId();
if (timerId == m_highlightTimer.timerId())
highlightTimeout();
else if (timerId == m_doubleTapTimer.timerId())
singleTapTimeout();
else if (timerId == m_tapAndHoldTimer.timerId())
tapAndHoldTimeout();
else
QObject::timerEvent(ev);
}
} // namespace WebKit