diff -r 000000000000 -r 1918ee327afb demos/embedded/flickable/flickable.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/demos/embedded/flickable/flickable.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "flickable.h" + +#include +#include + +class FlickableTicker: QObject +{ +public: + FlickableTicker(Flickable *scroller) { + m_scroller = scroller; + } + + void start(int interval) { + if (!m_timer.isActive()) + m_timer.start(interval, this); + } + + void stop() { + m_timer.stop(); + } + +protected: + void timerEvent(QTimerEvent *event) { + Q_UNUSED(event); + m_scroller->tick(); + } + +private: + Flickable *m_scroller; + QBasicTimer m_timer; +}; + +class FlickablePrivate +{ +public: + typedef enum { + Steady, + Pressed, + ManualScroll, + AutoScroll, + Stop + } State; + + State state; + int threshold; + QPoint pressPos; + QPoint offset; + QPoint delta; + QPoint speed; + FlickableTicker *ticker; + QTime timeStamp; + QWidget *target; + QList ignoreList; +}; + +Flickable::Flickable() +{ + d = new FlickablePrivate; + d->state = FlickablePrivate::Steady; + d->threshold = 10; + d->ticker = new FlickableTicker(this); + d->timeStamp = QTime::currentTime(); + d->target = 0; +} + +Flickable::~Flickable() +{ + delete d; +} + +void Flickable::setThreshold(int th) +{ + if (th >= 0) + d->threshold = th; +} + +int Flickable::threshold() const +{ + return d->threshold; +} + +void Flickable::setAcceptMouseClick(QWidget *target) +{ + d->target = target; +} + +static QPoint deaccelerate(const QPoint &speed, int a = 1, int max = 64) +{ + int x = qBound(-max, speed.x(), max); + int y = qBound(-max, speed.y(), max); + x = (x == 0) ? x : (x > 0) ? qMax(0, x - a) : qMin(0, x + a); + y = (y == 0) ? y : (y > 0) ? qMax(0, y - a) : qMin(0, y + a); + return QPoint(x, y); +} + +void Flickable::handleMousePress(QMouseEvent *event) +{ + event->ignore(); + + if (event->button() != Qt::LeftButton) + return; + + if (d->ignoreList.removeAll(event)) + return; + + switch (d->state) { + + case FlickablePrivate::Steady: + event->accept(); + d->state = FlickablePrivate::Pressed; + d->pressPos = event->pos(); + break; + + case FlickablePrivate::AutoScroll: + event->accept(); + d->state = FlickablePrivate::Stop; + d->speed = QPoint(0, 0); + d->pressPos = event->pos(); + d->offset = scrollOffset(); + d->ticker->stop(); + break; + + default: + break; + } +} + +void Flickable::handleMouseRelease(QMouseEvent *event) +{ + event->ignore(); + + if (event->button() != Qt::LeftButton) + return; + + if (d->ignoreList.removeAll(event)) + return; + + QPoint delta; + + switch (d->state) { + + case FlickablePrivate::Pressed: + event->accept(); + d->state = FlickablePrivate::Steady; + if (d->target) { + QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonPress, + d->pressPos, Qt::LeftButton, + Qt::LeftButton, Qt::NoModifier); + QMouseEvent *event2 = new QMouseEvent(*event); + d->ignoreList << event1; + d->ignoreList << event2; + QApplication::postEvent(d->target, event1); + QApplication::postEvent(d->target, event2); + } + break; + + case FlickablePrivate::ManualScroll: + event->accept(); + delta = event->pos() - d->pressPos; + if (d->timeStamp.elapsed() > 100) { + d->timeStamp = QTime::currentTime(); + d->speed = delta - d->delta; + d->delta = delta; + } + d->offset = scrollOffset(); + d->pressPos = event->pos(); + if (d->speed == QPoint(0, 0)) { + d->state = FlickablePrivate::Steady; + } else { + d->speed /= 4; + d->state = FlickablePrivate::AutoScroll; + d->ticker->start(20); + } + break; + + case FlickablePrivate::Stop: + event->accept(); + d->state = FlickablePrivate::Steady; + d->offset = scrollOffset(); + break; + + default: + break; + } +} + +void Flickable::handleMouseMove(QMouseEvent *event) +{ + event->ignore(); + + if (!(event->buttons() & Qt::LeftButton)) + return; + + if (d->ignoreList.removeAll(event)) + return; + + QPoint delta; + + switch (d->state) { + + case FlickablePrivate::Pressed: + case FlickablePrivate::Stop: + delta = event->pos() - d->pressPos; + if (delta.x() > d->threshold || delta.x() < -d->threshold || + delta.y() > d->threshold || delta.y() < -d->threshold) { + d->timeStamp = QTime::currentTime(); + d->state = FlickablePrivate::ManualScroll; + d->delta = QPoint(0, 0); + d->pressPos = event->pos(); + event->accept(); + } + break; + + case FlickablePrivate::ManualScroll: + event->accept(); + delta = event->pos() - d->pressPos; + setScrollOffset(d->offset - delta); + if (d->timeStamp.elapsed() > 100) { + d->timeStamp = QTime::currentTime(); + d->speed = delta - d->delta; + d->delta = delta; + } + break; + + default: + break; + } +} + +void Flickable::tick() +{ + if (d->state == FlickablePrivate:: AutoScroll) { + d->speed = deaccelerate(d->speed); + setScrollOffset(d->offset - d->speed); + d->offset = scrollOffset(); + if (d->speed == QPoint(0, 0)) { + d->state = FlickablePrivate::Steady; + d->ticker->stop(); + } + } else { + d->ticker->stop(); + } +}