ginebra2/Gestures/GestureRecognizer.cpp
changeset 9 b39122337a00
child 16 3c88a81ff781
equal deleted inserted replaced
7:a1f515018ac1 9:b39122337a00
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 *
       
     5 * This program is free software: you can redistribute it and/or modify
       
     6 * it under the terms of the GNU Lesser General Public License as published by
       
     7 * the Free Software Foundation, version 2.1 of the License.
       
     8 *
       
     9 * This program is distributed in the hope that it will be useful,
       
    10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12 * GNU Lesser General Public License for more details.
       
    13 *
       
    14 * You should have received a copy of the GNU Lesser General Public License
       
    15 * along with this program.  If not,
       
    16 * see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
       
    17 *
       
    18 * Description:
       
    19 *
       
    20 */
       
    21 
       
    22 /*
       
    23  W A R N I N G
       
    24  -------------
       
    25   THIS IS A TEMPORARY GESTURE CODE. WOULD BE REPLACED WHEN BROWSER HAS ITS OWN GESTURE FRAMEWORK
       
    26  */
       
    27 
       
    28 #include "GestureRecognizer.h"
       
    29 
       
    30 #include "GestureListener.h"
       
    31 #include "GestureRecognizer_p.h"
       
    32 
       
    33 #include <QtGui>
       
    34 
       
    35 static const int DoubleClickFilterDuration = 300;
       
    36 static const int LongClickFilterDuration = 1000;
       
    37 static const int MinTimeHoldForClick = 50;
       
    38 static const int ThresholdForMove = 30;
       
    39 
       
    40 namespace GVA {
       
    41 
       
    42 GestureRecognizer::GestureRecognizer(GestureListener* gestureListener)
       
    43     : d_ptr(new GestureRecognizerPrivate(gestureListener))
       
    44 {
       
    45     Q_D(GestureRecognizer);
       
    46     d->q_ptr = this;
       
    47 }
       
    48 
       
    49 GestureRecognizer::~GestureRecognizer()
       
    50 { }
       
    51 
       
    52 bool GestureRecognizer::mouseEventFilter(QGraphicsSceneMouseEvent* event)
       
    53 {
       
    54     Q_D(GestureRecognizer);
       
    55     bool handled = false;
       
    56 
       
    57     switch(event->type()) {
       
    58     case QEvent::GraphicsSceneMouseDoubleClick:
       
    59         handled = d->mouseDoubleClickEvent(event);
       
    60         break;
       
    61     case QEvent::GraphicsSceneMouseMove:
       
    62         handled = d->mouseMoveEvent(event);
       
    63         break;
       
    64     case QEvent::GraphicsSceneMousePress:
       
    65         handled = d->mousePressEvent(event);
       
    66         break;
       
    67     case QEvent::GraphicsSceneMouseRelease:
       
    68         handled = d->mouseReleaseEvent(event);
       
    69         break;
       
    70     case QEvent::GraphicsSceneContextMenu:
       
    71         //Swallow context menu event.
       
    72         //Since we have own way of handling it
       
    73         handled = true;
       
    74     default:
       
    75         break;
       
    76     }
       
    77     return handled;
       
    78 }
       
    79 
       
    80 qreal GestureRecognizer::dragInertia() const
       
    81 {
       
    82     Q_D(const GestureRecognizer);
       
    83     return d->m_dragInertia;
       
    84 }
       
    85 
       
    86 void GestureRecognizer::setDragInertia(qreal inertia)
       
    87 {
       
    88     Q_D(GestureRecognizer);
       
    89     d->m_dragInertia = inertia;
       
    90 }
       
    91 
       
    92 int GestureRecognizer::directionErrorMargin() const
       
    93 {
       
    94     Q_D(const GestureRecognizer);
       
    95     return d->m_directionErrorMargin;
       
    96 }
       
    97 
       
    98 void GestureRecognizer::setDirectionErrorMargin(int errorMargin)
       
    99 {
       
   100     Q_D(GestureRecognizer);
       
   101     d->m_directionErrorMargin = errorMargin;
       
   102 }
       
   103 
       
   104 qreal GestureRecognizer::axisLockThreshold() const
       
   105 {
       
   106     Q_D(const GestureRecognizer);
       
   107     return d->m_axisLockThreshold;
       
   108 }
       
   109 
       
   110 void GestureRecognizer::setAxisLockThreshold(qreal threshold)
       
   111 {
       
   112     Q_D(GestureRecognizer);
       
   113     d->m_axisLockThreshold = threshold;
       
   114 }
       
   115 
       
   116 qreal GestureRecognizer::maximumVelocity() const
       
   117 {
       
   118     Q_D(const GestureRecognizer);
       
   119     return d->m_maxVelocity;
       
   120 }
       
   121 
       
   122 void GestureRecognizer::setMaximumVelocity(qreal v)
       
   123 {
       
   124     Q_D(GestureRecognizer);
       
   125     d->m_maxVelocity = v;
       
   126 }
       
   127 
       
   128 qreal GestureRecognizer::minimumVelocity() const
       
   129 {
       
   130     Q_D(const GestureRecognizer);
       
   131     return d->m_minVelocity;
       
   132 }
       
   133 
       
   134 void GestureRecognizer::setMinimumVelocity(qreal v)
       
   135 {
       
   136     Q_D(GestureRecognizer);
       
   137     d->m_minVelocity = v;
       
   138 }
       
   139 
       
   140 int GestureRecognizer::panningThreshold() const
       
   141 {
       
   142     Q_D(const GestureRecognizer);
       
   143     return d->m_panningThreshold;
       
   144 }
       
   145 
       
   146 void GestureRecognizer::setPanningThreshold(int threshold)
       
   147 {
       
   148     Q_D(GestureRecognizer);
       
   149     d->m_panningThreshold = threshold;
       
   150 }
       
   151 
       
   152 qreal GestureRecognizer::fastVelocityFactor() const
       
   153 {
       
   154     Q_D(const GestureRecognizer);
       
   155     return d->m_fastVelocityFactor;
       
   156 }
       
   157 
       
   158 void GestureRecognizer::setFastVelocityFactor(qreal v)
       
   159 {
       
   160     Q_D(GestureRecognizer);
       
   161     d->m_fastVelocityFactor = v;
       
   162 }
       
   163 
       
   164 int GestureRecognizer::scrollsPerSecond() const
       
   165 {
       
   166     Q_D(const GestureRecognizer);
       
   167     return d->m_fastVelocityFactor;
       
   168 }
       
   169 
       
   170 void GestureRecognizer::setScrollsPerSecond(int sps)
       
   171 {
       
   172     Q_D(GestureRecognizer);
       
   173     d->m_scrollsPerSecond = sps;
       
   174 }
       
   175 
       
   176 //
       
   177 //GestureRecognizerPrivate DIFINITION
       
   178 //
       
   179 GestureRecognizerPrivate::GestureRecognizerPrivate(GestureListener* gestureListener)
       
   180     : m_gestureListener(gestureListener)
       
   181     , m_state(GestureRecognizerPrivate::Inactive)
       
   182     , m_dragInertia(0.85)
       
   183     , m_directionErrorMargin(10)
       
   184     , m_axisLockThreshold(0)
       
   185     , m_maxVelocity(3500)
       
   186     , m_minVelocity(10)
       
   187     , m_panningThreshold(25)
       
   188     , m_fastVelocityFactor(0.01)
       
   189     , m_scrollsPerSecond(20)
       
   190     , m_velocity(QPointF(0, 0))
       
   191     , m_position(QPointF(-1, -1))
       
   192     , m_initialPos(QPointF(-1, -1))
       
   193 
       
   194 { }
       
   195 
       
   196 GestureRecognizerPrivate::~GestureRecognizerPrivate()
       
   197 { }
       
   198 
       
   199 bool GestureRecognizerPrivate::mousePressEvent(QGraphicsSceneMouseEvent* event)
       
   200 {
       
   201     if (event->button() != Qt::LeftButton)
       
   202         return false;
       
   203 
       
   204     if (m_state == GestureRecognizerPrivate::Inactive) {
       
   205         //First mouse press.
       
   206         m_position = event->scenePos();
       
   207         m_initialPos = m_position;
       
   208 
       
   209         changeState(GestureRecognizerPrivate::Press);
       
   210 
       
   211         GestureEvent gesture = gestureEvent(m_initialPos, GestureEvent::Touch);
       
   212         m_gestureListener->handleGesture(&gesture);
       
   213 
       
   214         m_lastTime.start();
       
   215         m_delayedPressMoment.start();
       
   216         m_timer.start(LongClickFilterDuration, this);
       
   217     } else if(m_state == GestureRecognizerPrivate::Release) {
       
   218         //This press is for double tap.
       
   219         changeState(GestureRecognizerPrivate::DoublePress);
       
   220     }
       
   221     event->setAccepted(true);
       
   222     return true;
       
   223 }
       
   224 
       
   225 bool GestureRecognizerPrivate::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
       
   226 {
       
   227     if (event->button() != Qt::LeftButton)
       
   228         return true;
       
   229 
       
   230     if (m_state == GestureRecognizerPrivate::Inactive) {
       
   231         //Release event cannot be generated in gesture recognizer is in active!
       
   232         event->setAccepted(true);
       
   233         resetTouchPositions();
       
   234         return true;
       
   235     }
       
   236 
       
   237     if (m_state == GestureRecognizerPrivate::Press) {
       
   238         if (m_delayedPressMoment.elapsed() > MinTimeHoldForClick) {
       
   239             //Waiting for MinTimeHoldForClick to make sure use has actually pressed.
       
   240             //Removes accidentall press
       
   241             changeState(GestureRecognizerPrivate::Release);
       
   242             m_timer.start(DoubleClickFilterDuration, this);
       
   243         } else
       
   244             resetTouchPositions();
       
   245     } else if (m_state == GestureRecognizerPrivate::Move) {
       
   246         if (qAbs(m_velocity.x()) > m_minVelocity
       
   247             || qAbs(m_velocity.y()) > m_minVelocity) {
       
   248             GestureEvent gesture = gestureEvent(m_position, GestureEvent::Flick);
       
   249             gesture.setVelocity(m_velocity);
       
   250             m_gestureListener->handleGesture(&gesture);
       
   251         }
       
   252         m_velocity = QPointF(0,0);
       
   253         resetTouchPositions();
       
   254     } else if (m_state == GestureRecognizerPrivate::DoublePress) {
       
   255         //Stop double tap timer
       
   256         m_timer.stop();
       
   257         GestureEvent gesture = gestureEvent(m_initialPos, GestureEvent::DoubleTap);
       
   258         m_gestureListener->handleGesture(&gesture);
       
   259         resetTouchPositions();
       
   260     }
       
   261     event->setAccepted(true);
       
   262     return true;
       
   263 }
       
   264 
       
   265 bool GestureRecognizerPrivate::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
       
   266 {
       
   267     QPoint delta;
       
   268     if (m_state == GestureRecognizerPrivate::Press) {
       
   269         delta = (event->scenePos() - m_initialPos).toPoint();
       
   270         QPoint absDelta;
       
   271         absDelta.setX(qAbs(delta.x()));
       
   272         absDelta.setY(qAbs(delta.y()));
       
   273 
       
   274         if ((absDelta.x() > ThresholdForMove) || (absDelta.y() > ThresholdForMove)) {
       
   275             //Stop long tap timer
       
   276             m_timer.stop();
       
   277 
       
   278             changeState(GestureRecognizerPrivate::Move);
       
   279             m_position = event->scenePos();
       
   280         } else {
       
   281             //Ignore until user has actually moved
       
   282             return true;
       
   283         }
       
   284     } else if (m_state == GestureRecognizerPrivate::Move) {
       
   285         delta = (event->scenePos() - m_position).toPoint();
       
   286         m_position = event->scenePos();
       
   287     } else {
       
   288         resetTouchPositions();
       
   289         return true;
       
   290     }
       
   291 
       
   292     //Aplly if axis stickiness is specified.
       
   293     if (m_axisLockThreshold) {
       
   294         int dx = qAbs(delta.x());
       
   295         int dy = qAbs(delta.y());
       
   296 
       
   297         if (dx || dy) {
       
   298             bool vertical = (dy > dx);
       
   299             qreal alpha = qreal(vertical ? dx : dy) / qreal(vertical ? dy : dx);
       
   300             if (alpha <= m_axisLockThreshold) {
       
   301                 if (vertical)
       
   302                     delta.setX(0);
       
   303                 else
       
   304                     delta.setY(0);
       
   305             }
       
   306         }
       
   307     }
       
   308 
       
   309     m_velocity = calculateVelocity(delta, m_lastTime.elapsed());
       
   310 
       
   311     //Send pan gesture
       
   312     GestureEvent gesture = gestureEvent(m_position, GestureEvent::Pan);
       
   313     gesture.setDelta(delta);
       
   314     m_gestureListener->handleGesture(&gesture);
       
   315     m_lastTime.restart();
       
   316 
       
   317     event->setAccepted(true);
       
   318     return true;
       
   319 }
       
   320 
       
   321 bool GestureRecognizerPrivate::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
       
   322 {
       
   323     if (m_state == GestureRecognizerPrivate::Release) {
       
   324         m_timer.stop();
       
   325         GestureEvent gesture = gestureEvent(m_initialPos, GestureEvent::DoubleTap);
       
   326         m_gestureListener->handleGesture(&gesture);
       
   327     }
       
   328     resetTouchPositions();
       
   329     event->setAccepted(true);
       
   330     return true;
       
   331 }
       
   332 
       
   333 void GestureRecognizerPrivate::changeState(GestureRecognizerPrivate::State state)
       
   334 {
       
   335     m_state = state;
       
   336 }
       
   337 
       
   338 GestureEvent GestureRecognizerPrivate::gestureEvent(const QPointF& pos, GestureEvent::Type type)
       
   339 {
       
   340     GestureEvent gestureEvent;
       
   341     gestureEvent.setType(type);
       
   342     gestureEvent.setPosition(pos);
       
   343     return gestureEvent;
       
   344 }
       
   345 
       
   346 void GestureRecognizerPrivate::timerEvent(QTimerEvent* event)
       
   347 {
       
   348     if (event->timerId() != m_timer.timerId())
       
   349         return;
       
   350 
       
   351     m_timer.stop();
       
   352 
       
   353     QPointF position;
       
   354     GestureEvent::Type gestureType;
       
   355 
       
   356     if (m_state == GestureRecognizerPrivate::Press) {
       
   357         //Long press
       
   358         position = m_position;
       
   359         gestureType = GestureEvent::LongTap;
       
   360     } else if (m_state == GestureRecognizerPrivate::Release) {
       
   361         //Actual release event
       
   362         position = m_initialPos;
       
   363         gestureType = GestureEvent::Release;
       
   364     } else {
       
   365         resetTouchPositions();
       
   366         changeState(GestureRecognizerPrivate::Inactive);
       
   367         return;
       
   368     }
       
   369 
       
   370     resetTouchPositions();
       
   371     GestureEvent gesture = gestureEvent(position, gestureType);
       
   372     m_gestureListener->handleGesture(&gesture);
       
   373     return;
       
   374 }
       
   375 
       
   376 void GestureRecognizerPrivate::resetTouchPositions()
       
   377 {
       
   378     m_position = QPointF(-1, -1);
       
   379     m_initialPos = m_position;
       
   380     changeState(GestureRecognizerPrivate::Inactive);
       
   381 }
       
   382 
       
   383 QPointF GestureRecognizerPrivate::calculateVelocity(const QPointF& delta, int time)
       
   384 {
       
   385     QPointF newVelocity = m_velocity;
       
   386 
       
   387     if ((delta / qreal(time)).manhattanLength() < 25) {
       
   388         QPointF rawVelocity = delta / qreal(time) * qreal(1000) / qreal(m_scrollsPerSecond);
       
   389         newVelocity = newVelocity * (qreal(1) - m_dragInertia) + rawVelocity * m_dragInertia;
       
   390     }
       
   391 
       
   392     newVelocity.setX(delta.x() ? qBound(-m_maxVelocity, newVelocity.x(), m_maxVelocity) : m_velocity.x());
       
   393     newVelocity.setY(delta.y() ? qBound(-m_maxVelocity, newVelocity.y(), m_maxVelocity) : m_velocity.y());
       
   394     return newVelocity;
       
   395 }
       
   396 
       
   397 } // namespace GVA
       
   398