From 6c49daaab5caa3213e7f943c3a47988b615105f3 Mon Sep 17 00:00:00 2001 From: Akos Polster Date: Sun, 17 Oct 2010 02:01:17 +0200 Subject: [PATCH] Fix kinetic scrolling on Symbian. Fix timer handling. --- bookview.cpp | 14 +- bookview.h | 6 +- dorian.pro | 7 +- mainwindow.cpp | 1 + pkg/changelog | 1 + widgets/flickable.cpp | 284 ---------------------------------- widgets/flickable.h | 80 ---------- widgets/flickcharm.cpp | 402 ++++++++++++++++++++++++++++++++++++++++++++++++ widgets/flickcharm.h | 67 ++++++++ widgets/progress.cpp | 1 + 10 files changed, 488 insertions(+), 375 deletions(-) delete mode 100755 widgets/flickable.cpp delete mode 100755 widgets/flickable.h create mode 100755 widgets/flickcharm.cpp create mode 100755 widgets/flickcharm.h diff --git a/bookview.cpp b/bookview.cpp index 121fa50..2eda697 100644 --- a/bookview.cpp +++ b/bookview.cpp @@ -5,8 +5,10 @@ #include #include -#ifdef Q_WS_MAEMO_5 +#if defined(Q_WS_MAEMO_5) # include +#elif defined(Q_OS_SYMBIAN) +# include "flickcharm.h" #endif #include "book.h" @@ -72,9 +74,12 @@ BookView::BookView(QWidget *parent): s->setValue("scheme", s->value("scheme", "default")); setBook(0); -#ifdef Q_WS_MAEMO_5 +#if defined(Q_WS_MAEMO_5) scrollerMonitor = 0; scroller = property("kineticScroller").value(); +#elif defined(Q_OS_SYMBIAN) + FlickCharm *charm = new FlickCharm(this); + charm->activateOn(this); #endif } @@ -400,9 +405,8 @@ void BookView::timerEvent(QTimerEvent *e) killTimer(scrollerMonitor); } } -#else - Q_UNUSED(e); -#endif // Q_WS_MAEMO_5 +#endif + QWebView::timerEvent(e); } void BookView::keyPressEvent(QKeyEvent* event) diff --git a/bookview.h b/bookview.h index 994fe5d..f96d599 100644 --- a/bookview.h +++ b/bookview.h @@ -16,9 +16,6 @@ class QAbstractKineticScroller; /** Visual representation of a book. */ class BookView: public QWebView -#ifdef Q_OS_SYMBIAN - , public Flickable -#endif { Q_OBJECT @@ -99,9 +96,10 @@ private: bool mousePressed; int contentsHeight; /**< Last know height of the frame. */ -#if def(Q_WS_MAEMO_5) +#if defined(Q_WS_MAEMO_5) int scrollerMonitor; QAbstractKineticScroller *scroller; +#endif }; #endif // BOOKVIEW_H diff --git a/dorian.pro b/dorian.pro index fe08054..cac489f 100644 --- a/dorian.pro +++ b/dorian.pro @@ -114,20 +114,23 @@ unix { LIBS += -lz } } + win32 { DEFINES += ZLIB_WINAPI INCLUDEPATH += $$PWD/model/zlib LIBS += pkg/win32/zlibstat.lib } + symbian { ICON = $$PWD/pkg/symbian/book.svgt TARGET.UID3 = 0xEA633557 # FIXME: TARGET.CAPABILITY = ... # FIXME: Include path to OpenC ZLIB? INCLUDEPATH += c:/Qt/4.7.0/src/3rdparty/zlib - SOURCES += widgets/flickable.cpp - HEADERS += widgets/flickable.h + HEADERS += widgets/flickcharm.h + SOURCES += widgets/flickcharm.cpp } + maemo5 { QT += maemo5 dbus isEmpty(PREFIX) { diff --git a/mainwindow.cpp b/mainwindow.cpp index 5d2389f..3350754 100755 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -403,6 +403,7 @@ void MainWindow::timerEvent(QTimerEvent *event) #endif // Q_WS_MAEMO_5 qDebug() << "MainWindow::timerEvent: Prevent display blanking"; } + AdopterWindow::timerEvent(event); } void MainWindow::resizeEvent(QResizeEvent *e) diff --git a/pkg/changelog b/pkg/changelog index 4311462..d535473 100644 --- a/pkg/changelog +++ b/pkg/changelog @@ -1,6 +1,7 @@ dorian (0.3.1-1) unstable; urgency=low * Fix sorting of library + * Fix book view kinetic scrolling on Symbian -- Akos Polster Sat, 10 Oct 2010 02:00:00 +0200 diff --git a/widgets/flickable.cpp b/widgets/flickable.cpp deleted file mode 100755 index 7841d7d..0000000 --- a/widgets/flickable.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 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$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** 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(); - } -} diff --git a/widgets/flickable.h b/widgets/flickable.h deleted file mode 100755 index 4211a2f..0000000 --- a/widgets/flickable.h +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 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$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef FLICKABLE_H -#define FLICKABLE_H - -class QMouseEvent; -class QPoint; -class QWidget; - -class FlickableTicker; -class FlickablePrivate; - -class Flickable -{ -public: - - Flickable(); - virtual ~Flickable(); - - void setThreshold(int threshold); - int threshold() const; - - void setAcceptMouseClick(QWidget *target); - - void handleMousePress(QMouseEvent *event); - void handleMouseMove(QMouseEvent *event); - void handleMouseRelease(QMouseEvent *event); - -protected: - virtual QPoint scrollOffset() const = 0; - virtual void setScrollOffset(const QPoint &offset) = 0; - -private: - void tick(); - -private: - FlickablePrivate *d; - friend class FlickableTicker; -}; - -#endif // FLICKABLE_H diff --git a/widgets/flickcharm.cpp b/widgets/flickcharm.cpp new file mode 100755 index 0000000..062a6f4 --- /dev/null +++ b/widgets/flickcharm.cpp @@ -0,0 +1,402 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demos of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "flickcharm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +const int fingerAccuracyThreshold = 3; + +struct FlickData { + typedef enum { + Steady, // Interaction without scrolling + ManualScroll, // Scrolling manually with the finger on the screen + AutoScroll, // Scrolling automatically + AutoScrollAcceleration // Scrolling automatically but a finger is on the screen + } State; + State state; + QWidget *widget; + QPoint pressPos; + QPoint lastPos; + QPoint speed; + QTime speedTimer; + QList ignored; + QTime accelerationTimer; + bool lastPosValid:1; + bool waitingAcceleration:1; + + FlickData() + : lastPosValid(false) + , waitingAcceleration(false) + {} + + void resetSpeed() + { + speed = QPoint(); + lastPosValid = false; + } + void updateSpeed(const QPoint &newPosition) + { + if (lastPosValid) { + const int timeElapsed = speedTimer.elapsed(); + if (timeElapsed) { + const QPoint newPixelDiff = (newPosition - lastPos); + const QPoint pixelsPerSecond = newPixelDiff * (1000 / timeElapsed); + // fingers are inacurates, we ignore small changes to avoid stopping the autoscroll because + // of a small horizontal offset when scrolling vertically + const int newSpeedY = (qAbs(pixelsPerSecond.y()) > fingerAccuracyThreshold) ? pixelsPerSecond.y() : 0; + const int newSpeedX = (qAbs(pixelsPerSecond.x()) > fingerAccuracyThreshold) ? pixelsPerSecond.x() : 0; + if (state == AutoScrollAcceleration) { + const int max = 4000; // px by seconds + const int oldSpeedY = speed.y(); + const int oldSpeedX = speed.x(); + if ((oldSpeedY <= 0 && newSpeedY <= 0) || (oldSpeedY >= 0 && newSpeedY >= 0) + && (oldSpeedX <= 0 && newSpeedX <= 0) || (oldSpeedX >= 0 && newSpeedX >= 0)) { + speed.setY(qBound(-max, (oldSpeedY + (newSpeedY / 4)), max)); + speed.setX(qBound(-max, (oldSpeedX + (newSpeedX / 4)), max)); + } else { + speed = QPoint(); + } + } else { + const int max = 2500; // px by seconds + // we average the speed to avoid strange effects with the last delta + if (!speed.isNull()) { + speed.setX(qBound(-max, (speed.x() / 4) + (newSpeedX * 3 / 4), max)); + speed.setY(qBound(-max, (speed.y() / 4) + (newSpeedY * 3 / 4), max)); + } else { + speed = QPoint(newSpeedX, newSpeedY); + } + } + } + } else { + lastPosValid = true; + } + speedTimer.start(); + lastPos = newPosition; + } + + // scroll by dx, dy + // return true if the widget was scrolled + bool scrollWidget(const int dx, const int dy) + { + QAbstractScrollArea *scrollArea = qobject_cast(widget); + if (scrollArea) { + const int x = scrollArea->horizontalScrollBar()->value(); + const int y = scrollArea->verticalScrollBar()->value(); + scrollArea->horizontalScrollBar()->setValue(x - dx); + scrollArea->verticalScrollBar()->setValue(y - dy); + return (scrollArea->horizontalScrollBar()->value() != x + || scrollArea->verticalScrollBar()->value() != y); + } + + QWebView *webView = qobject_cast(widget); + if (webView) { + QWebFrame *frame = webView->page()->mainFrame(); + const QPoint position = frame->scrollPosition(); + frame->setScrollPosition(position - QPoint(dx, dy)); + return frame->scrollPosition() != position; + } + return false; + } + + bool scrollTo(const QPoint &newPosition) + { + const QPoint delta = newPosition - lastPos; + updateSpeed(newPosition); + return scrollWidget(delta.x(), delta.y()); + } +}; + +class FlickCharmPrivate +{ +public: + QHash flickData; + QBasicTimer ticker; + QTime timeCounter; + void startTicker(QObject *object) + { + if (!ticker.isActive()) + ticker.start(15, object); + timeCounter.start(); + } +}; + +FlickCharm::FlickCharm(QObject *parent): QObject(parent) +{ + d = new FlickCharmPrivate; +} + +FlickCharm::~FlickCharm() +{ + delete d; +} + +void FlickCharm::activateOn(QWidget *widget) +{ + QAbstractScrollArea *scrollArea = qobject_cast(widget); + if (scrollArea) { + scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + QWidget *viewport = scrollArea->viewport(); + + viewport->installEventFilter(this); + scrollArea->installEventFilter(this); + + d->flickData.remove(viewport); + d->flickData[viewport] = new FlickData; + d->flickData[viewport]->widget = widget; + d->flickData[viewport]->state = FlickData::Steady; + + return; + } + + QWebView *webView = qobject_cast(widget); + if (webView) { + QWebFrame *frame = webView->page()->mainFrame(); + frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); + frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff); + + webView->installEventFilter(this); + + d->flickData.remove(webView); + d->flickData[webView] = new FlickData; + d->flickData[webView]->widget = webView; + d->flickData[webView]->state = FlickData::Steady; + + return; + } + + qWarning() << "FlickCharm only works on QAbstractScrollArea (and derived classes)"; + qWarning() << "or QWebView (and derived classes)"; +} + +void FlickCharm::deactivateFrom(QWidget *widget) +{ + QAbstractScrollArea *scrollArea = qobject_cast(widget); + if (scrollArea) { + QWidget *viewport = scrollArea->viewport(); + + viewport->removeEventFilter(this); + scrollArea->removeEventFilter(this); + + delete d->flickData[viewport]; + d->flickData.remove(viewport); + + return; + } + + QWebView *webView = qobject_cast(widget); + if (webView) { + webView->removeEventFilter(this); + + delete d->flickData[webView]; + d->flickData.remove(webView); + + return; + } +} + +static QPoint deaccelerate(const QPoint &speed, const int deltatime) +{ + const int deltaSpeed = deltatime; + + int x = speed.x(); + int y = speed.y(); + x = (x == 0) ? x : (x > 0) ? qMax(0, x - deltaSpeed) : qMin(0, x + deltaSpeed); + y = (y == 0) ? y : (y > 0) ? qMax(0, y - deltaSpeed) : qMin(0, y + deltaSpeed); + return QPoint(x, y); +} + +bool FlickCharm::eventFilter(QObject *object, QEvent *event) +{ + if (!object->isWidgetType()) + return false; + + const QEvent::Type type = event->type(); + + switch (type) { + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + break; + case QEvent::MouseButtonDblClick: // skip double click + return true; + default: + return false; + } + + QMouseEvent *mouseEvent = static_cast(event); + if (type == QEvent::MouseMove && mouseEvent->buttons() != Qt::LeftButton) + return false; + + if (mouseEvent->modifiers() != Qt::NoModifier) + return false; + + QWidget *viewport = qobject_cast(object); + FlickData *data = d->flickData.value(viewport); + if (!viewport || !data || data->ignored.removeAll(event)) + return false; + + const QPoint mousePos = mouseEvent->pos(); + bool consumed = false; + switch (data->state) { + + case FlickData::Steady: + if (type == QEvent::MouseButtonPress) { + consumed = true; + data->pressPos = mousePos; + } else if (type == QEvent::MouseButtonRelease) { + consumed = true; + QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonPress, + data->pressPos, Qt::LeftButton, + Qt::LeftButton, Qt::NoModifier); + QMouseEvent *event2 = new QMouseEvent(QEvent::MouseButtonRelease, + data->pressPos, Qt::LeftButton, + Qt::LeftButton, Qt::NoModifier); + + data->ignored << event1; + data->ignored << event2; + QApplication::postEvent(object, event1); + QApplication::postEvent(object, event2); + } else if (type == QEvent::MouseMove) { + consumed = true; + data->scrollTo(mousePos); + + const QPoint delta = mousePos - data->pressPos; + if (delta.x() > fingerAccuracyThreshold || delta.y() > fingerAccuracyThreshold) + data->state = FlickData::ManualScroll; + } + break; + + case FlickData::ManualScroll: + if (type == QEvent::MouseMove) { + consumed = true; + data->scrollTo(mousePos); + } else if (type == QEvent::MouseButtonRelease) { + consumed = true; + data->state = FlickData::AutoScroll; + data->lastPosValid = false; + d->startTicker(this); + } + break; + + case FlickData::AutoScroll: + if (type == QEvent::MouseButtonPress) { + consumed = true; + data->state = FlickData::AutoScrollAcceleration; + data->waitingAcceleration = true; + data->accelerationTimer.start(); + data->updateSpeed(mousePos); + data->pressPos = mousePos; + } else if (type == QEvent::MouseButtonRelease) { + consumed = true; + data->state = FlickData::Steady; + data->resetSpeed(); + } + break; + + case FlickData::AutoScrollAcceleration: + if (type == QEvent::MouseMove) { + consumed = true; + data->updateSpeed(mousePos); + data->accelerationTimer.start(); + if (data->speed.isNull()) + data->state = FlickData::ManualScroll; + } else if (type == QEvent::MouseButtonRelease) { + consumed = true; + data->state = FlickData::AutoScroll; + data->waitingAcceleration = false; + data->lastPosValid = false; + } + break; + default: + break; + } + data->lastPos = mousePos; + return true; +} + +void FlickCharm::timerEvent(QTimerEvent *event) +{ + int count = 0; + QHashIterator item(d->flickData); + while (item.hasNext()) { + item.next(); + FlickData *data = item.value(); + if (data->state == FlickData::AutoScrollAcceleration + && data->waitingAcceleration + && data->accelerationTimer.elapsed() > 40) { + data->state = FlickData::ManualScroll; + data->resetSpeed(); + } + if (data->state == FlickData::AutoScroll || data->state == FlickData::AutoScrollAcceleration) { + const int timeElapsed = d->timeCounter.elapsed(); + const QPoint delta = (data->speed) * timeElapsed / 1000; + bool hasScrolled = data->scrollWidget(delta.x(), delta.y()); + + if (data->speed.isNull() || !hasScrolled) + data->state = FlickData::Steady; + else + count++; + data->speed = deaccelerate(data->speed, timeElapsed); + } + } + + if (!count) + d->ticker.stop(); + else + d->timeCounter.start(); + + QObject::timerEvent(event); +} diff --git a/widgets/flickcharm.h b/widgets/flickcharm.h new file mode 100755 index 0000000..83d7ac9 --- /dev/null +++ b/widgets/flickcharm.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demos of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FLICKCHARM_H +#define FLICKCHARM_H + +#include + +class FlickCharmPrivate; +class QWidget; + +class FlickCharm: public QObject +{ + Q_OBJECT +public: + FlickCharm(QObject *parent = 0); + ~FlickCharm(); + void activateOn(QWidget *widget); + void deactivateFrom(QWidget *widget); + bool eventFilter(QObject *object, QEvent *event); + +protected: + void timerEvent(QTimerEvent *event); + +private: + FlickCharmPrivate *d; +}; + +#endif // FLICKCHARM_H diff --git a/widgets/progress.cpp b/widgets/progress.cpp index d0a1409..e3eb3b8 100644 --- a/widgets/progress.cpp +++ b/widgets/progress.cpp @@ -45,4 +45,5 @@ void Progress::timerEvent(QTimerEvent *e) killTimer(timer); hide(); } + QLabel::timerEvent(e); } -- 1.7.9.5