#include <QDir>
#include <QTimer>
-#ifdef Q_WS_MAEMO_5
+#if defined(Q_WS_MAEMO_5)
# include <QAbstractKineticScroller>
+#elif defined(Q_OS_SYMBIAN)
+# include "flickcharm.h"
#endif
#include "book.h"
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<QAbstractKineticScroller *>();
+#elif defined(Q_OS_SYMBIAN)
+ FlickCharm *charm = new FlickCharm(this);
+ charm->activateOn(this);
#endif
}
killTimer(scrollerMonitor);
}
}
-#else
- Q_UNUSED(e);
-#endif // Q_WS_MAEMO_5
+#endif
+ QWebView::timerEvent(e);
}
void BookView::keyPressEvent(QKeyEvent* event)
/** Visual representation of a book. */
class BookView: public QWebView
-#ifdef Q_OS_SYMBIAN
- , public Flickable
-#endif
{
Q_OBJECT
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
LIBS += -lz\r
}\r
}\r
+\r
win32 {\r
DEFINES += ZLIB_WINAPI\r
INCLUDEPATH += $$PWD/model/zlib\r
LIBS += pkg/win32/zlibstat.lib\r
}\r
+\r
symbian {\r
ICON = $$PWD/pkg/symbian/book.svgt\r
TARGET.UID3 = 0xEA633557\r
# FIXME: TARGET.CAPABILITY = ...\r
# FIXME: Include path to OpenC ZLIB?\r
INCLUDEPATH += c:/Qt/4.7.0/src/3rdparty/zlib\r
- SOURCES += widgets/flickable.cpp\r
- HEADERS += widgets/flickable.h\r
+ HEADERS += widgets/flickcharm.h\r
+ SOURCES += widgets/flickcharm.cpp\r
}\r
+\r
maemo5 {\r
QT += maemo5 dbus\r
isEmpty(PREFIX) {\r
#endif // Q_WS_MAEMO_5
qDebug() << "MainWindow::timerEvent: Prevent display blanking";
}
+ AdopterWindow::timerEvent(event);
}
void MainWindow::resizeEvent(QResizeEvent *e)
dorian (0.3.1-1) unstable; urgency=low
* Fix sorting of library
+ * Fix book view kinetic scrolling on Symbian
-- Akos Polster <akos@pipacs.com> Sat, 10 Oct 2010 02:00:00 +0200
+++ /dev/null
-/****************************************************************************\r
-**\r
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).\r
-** All rights reserved.\r
-** Contact: Nokia Corporation (qt-info@nokia.com)\r
-**\r
-** This file is part of the demonstration applications of the Qt Toolkit.\r
-**\r
-** $QT_BEGIN_LICENSE:LGPL$\r
-** Commercial Usage\r
-** Licensees holding valid Qt Commercial licenses may use this file in\r
-** accordance with the Qt Commercial License Agreement provided with the\r
-** Software or, alternatively, in accordance with the terms contained in\r
-** a written agreement between you and Nokia.\r
-**\r
-** GNU Lesser General Public License Usage\r
-** Alternatively, this file may be used under the terms of the GNU Lesser\r
-** General Public License version 2.1 as published by the Free Software\r
-** Foundation and appearing in the file LICENSE.LGPL included in the\r
-** packaging of this file. Please review the following information to\r
-** ensure the GNU Lesser General Public License version 2.1 requirements\r
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\r
-**\r
-** In addition, as a special exception, Nokia gives you certain additional\r
-** rights. These rights are described in the Nokia Qt LGPL Exception\r
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.\r
-**\r
-** GNU General Public License Usage\r
-** Alternatively, this file may be used under the terms of the GNU\r
-** General Public License version 3.0 as published by the Free Software\r
-** Foundation and appearing in the file LICENSE.GPL included in the\r
-** packaging of this file. Please review the following information to\r
-** ensure the GNU General Public License version 3.0 requirements will be\r
-** met: http://www.gnu.org/copyleft/gpl.html.\r
-**\r
-** If you have questions regarding the use of this file, please contact\r
-** Nokia at qt-info@nokia.com.\r
-** $QT_END_LICENSE$\r
-**\r
-****************************************************************************/\r
-\r
-#include "flickable.h"\r
-\r
-#include <QtCore>\r
-#include <QtGui>\r
-\r
-class FlickableTicker: QObject\r
-{\r
-public:\r
- FlickableTicker(Flickable *scroller) {\r
- m_scroller = scroller;\r
- }\r
-\r
- void start(int interval) {\r
- if (!m_timer.isActive())\r
- m_timer.start(interval, this);\r
- }\r
-\r
- void stop() {\r
- m_timer.stop();\r
- }\r
-\r
-protected:\r
- void timerEvent(QTimerEvent *event) {\r
- Q_UNUSED(event);\r
- m_scroller->tick();\r
- }\r
-\r
-private:\r
- Flickable *m_scroller;\r
- QBasicTimer m_timer;\r
-};\r
-\r
-class FlickablePrivate\r
-{\r
-public:\r
- typedef enum {\r
- Steady,\r
- Pressed,\r
- ManualScroll,\r
- AutoScroll,\r
- Stop\r
- } State;\r
-\r
- State state;\r
- int threshold;\r
- QPoint pressPos;\r
- QPoint offset;\r
- QPoint delta;\r
- QPoint speed;\r
- FlickableTicker *ticker;\r
- QTime timeStamp;\r
- QWidget *target;\r
- QList<QEvent*> ignoreList;\r
-};\r
-\r
-Flickable::Flickable()\r
-{\r
- d = new FlickablePrivate;\r
- d->state = FlickablePrivate::Steady;\r
- d->threshold = 10;\r
- d->ticker = new FlickableTicker(this);\r
- d->timeStamp = QTime::currentTime();\r
- d->target = 0;\r
-}\r
-\r
-Flickable::~Flickable()\r
-{\r
- delete d;\r
-}\r
-\r
-void Flickable::setThreshold(int th)\r
-{\r
- if (th >= 0)\r
- d->threshold = th;\r
-}\r
-\r
-int Flickable::threshold() const\r
-{\r
- return d->threshold;\r
-}\r
-\r
-void Flickable::setAcceptMouseClick(QWidget *target)\r
-{\r
- d->target = target;\r
-}\r
-\r
-static QPoint deaccelerate(const QPoint &speed, int a = 1, int max = 64)\r
-{\r
- int x = qBound(-max, speed.x(), max);\r
- int y = qBound(-max, speed.y(), max);\r
- x = (x == 0) ? x : (x > 0) ? qMax(0, x - a) : qMin(0, x + a);\r
- y = (y == 0) ? y : (y > 0) ? qMax(0, y - a) : qMin(0, y + a);\r
- return QPoint(x, y);\r
-}\r
-\r
-void Flickable::handleMousePress(QMouseEvent *event)\r
-{\r
- event->ignore();\r
-\r
- if (event->button() != Qt::LeftButton)\r
- return;\r
-\r
- if (d->ignoreList.removeAll(event))\r
- return;\r
-\r
- switch (d->state) {\r
-\r
- case FlickablePrivate::Steady:\r
- event->accept();\r
- d->state = FlickablePrivate::Pressed;\r
- d->pressPos = event->pos();\r
- break;\r
-\r
- case FlickablePrivate::AutoScroll:\r
- event->accept();\r
- d->state = FlickablePrivate::Stop;\r
- d->speed = QPoint(0, 0);\r
- d->pressPos = event->pos();\r
- d->offset = scrollOffset();\r
- d->ticker->stop();\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
-}\r
-\r
-void Flickable::handleMouseRelease(QMouseEvent *event)\r
-{\r
- event->ignore();\r
-\r
- if (event->button() != Qt::LeftButton)\r
- return;\r
-\r
- if (d->ignoreList.removeAll(event))\r
- return;\r
-\r
- QPoint delta;\r
-\r
- switch (d->state) {\r
-\r
- case FlickablePrivate::Pressed:\r
- event->accept();\r
- d->state = FlickablePrivate::Steady;\r
- if (d->target) {\r
- QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonPress,\r
- d->pressPos, Qt::LeftButton,\r
- Qt::LeftButton, Qt::NoModifier);\r
- QMouseEvent *event2 = new QMouseEvent(*event);\r
- d->ignoreList << event1;\r
- d->ignoreList << event2;\r
- QApplication::postEvent(d->target, event1);\r
- QApplication::postEvent(d->target, event2);\r
- }\r
- break;\r
-\r
- case FlickablePrivate::ManualScroll:\r
- event->accept();\r
- delta = event->pos() - d->pressPos;\r
- if (d->timeStamp.elapsed() > 100) {\r
- d->timeStamp = QTime::currentTime();\r
- d->speed = delta - d->delta;\r
- d->delta = delta;\r
- }\r
- d->offset = scrollOffset();\r
- d->pressPos = event->pos();\r
- if (d->speed == QPoint(0, 0)) {\r
- d->state = FlickablePrivate::Steady;\r
- } else {\r
- d->speed /= 4;\r
- d->state = FlickablePrivate::AutoScroll;\r
- d->ticker->start(20);\r
- }\r
- break;\r
-\r
- case FlickablePrivate::Stop:\r
- event->accept();\r
- d->state = FlickablePrivate::Steady;\r
- d->offset = scrollOffset();\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
-}\r
-\r
-void Flickable::handleMouseMove(QMouseEvent *event)\r
-{\r
- event->ignore();\r
-\r
- if (!(event->buttons() & Qt::LeftButton))\r
- return;\r
-\r
- if (d->ignoreList.removeAll(event))\r
- return;\r
-\r
- QPoint delta;\r
-\r
- switch (d->state) {\r
-\r
- case FlickablePrivate::Pressed:\r
- case FlickablePrivate::Stop:\r
- delta = event->pos() - d->pressPos;\r
- if (delta.x() > d->threshold || delta.x() < -d->threshold ||\r
- delta.y() > d->threshold || delta.y() < -d->threshold) {\r
- d->timeStamp = QTime::currentTime();\r
- d->state = FlickablePrivate::ManualScroll;\r
- d->delta = QPoint(0, 0);\r
- d->pressPos = event->pos();\r
- event->accept();\r
- }\r
- break;\r
-\r
- case FlickablePrivate::ManualScroll:\r
- event->accept();\r
- delta = event->pos() - d->pressPos;\r
- setScrollOffset(d->offset - delta);\r
- if (d->timeStamp.elapsed() > 100) {\r
- d->timeStamp = QTime::currentTime();\r
- d->speed = delta - d->delta;\r
- d->delta = delta;\r
- }\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
-}\r
-\r
-void Flickable::tick()\r
-{\r
- if (d->state == FlickablePrivate:: AutoScroll) {\r
- d->speed = deaccelerate(d->speed);\r
- setScrollOffset(d->offset - d->speed);\r
- d->offset = scrollOffset();\r
- if (d->speed == QPoint(0, 0)) {\r
- d->state = FlickablePrivate::Steady;\r
- d->ticker->stop();\r
- }\r
- } else {\r
- d->ticker->stop();\r
- }\r
-}\r
+++ /dev/null
-/****************************************************************************\r
-**\r
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).\r
-** All rights reserved.\r
-** Contact: Nokia Corporation (qt-info@nokia.com)\r
-**\r
-** This file is part of the demonstration applications of the Qt Toolkit.\r
-**\r
-** $QT_BEGIN_LICENSE:LGPL$\r
-** Commercial Usage\r
-** Licensees holding valid Qt Commercial licenses may use this file in\r
-** accordance with the Qt Commercial License Agreement provided with the\r
-** Software or, alternatively, in accordance with the terms contained in\r
-** a written agreement between you and Nokia.\r
-**\r
-** GNU Lesser General Public License Usage\r
-** Alternatively, this file may be used under the terms of the GNU Lesser\r
-** General Public License version 2.1 as published by the Free Software\r
-** Foundation and appearing in the file LICENSE.LGPL included in the\r
-** packaging of this file. Please review the following information to\r
-** ensure the GNU Lesser General Public License version 2.1 requirements\r
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\r
-**\r
-** In addition, as a special exception, Nokia gives you certain additional\r
-** rights. These rights are described in the Nokia Qt LGPL Exception\r
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.\r
-**\r
-** GNU General Public License Usage\r
-** Alternatively, this file may be used under the terms of the GNU\r
-** General Public License version 3.0 as published by the Free Software\r
-** Foundation and appearing in the file LICENSE.GPL included in the\r
-** packaging of this file. Please review the following information to\r
-** ensure the GNU General Public License version 3.0 requirements will be\r
-** met: http://www.gnu.org/copyleft/gpl.html.\r
-**\r
-** If you have questions regarding the use of this file, please contact\r
-** Nokia at qt-info@nokia.com.\r
-** $QT_END_LICENSE$\r
-**\r
-****************************************************************************/\r
-\r
-#ifndef FLICKABLE_H\r
-#define FLICKABLE_H\r
-\r
-class QMouseEvent;\r
-class QPoint;\r
-class QWidget;\r
-\r
-class FlickableTicker;\r
-class FlickablePrivate;\r
-\r
-class Flickable\r
-{\r
-public:\r
-\r
- Flickable();\r
- virtual ~Flickable();\r
-\r
- void setThreshold(int threshold);\r
- int threshold() const;\r
-\r
- void setAcceptMouseClick(QWidget *target);\r
-\r
- void handleMousePress(QMouseEvent *event);\r
- void handleMouseMove(QMouseEvent *event);\r
- void handleMouseRelease(QMouseEvent *event);\r
-\r
-protected:\r
- virtual QPoint scrollOffset() const = 0;\r
- virtual void setScrollOffset(const QPoint &offset) = 0;\r
-\r
-private:\r
- void tick();\r
-\r
-private:\r
- FlickablePrivate *d;\r
- friend class FlickableTicker;\r
-};\r
-\r
-#endif // FLICKABLE_H\r
--- /dev/null
+/****************************************************************************\r
+**\r
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).\r
+** All rights reserved.\r
+** Contact: Nokia Corporation (qt-info@nokia.com)\r
+**\r
+** This file is part of the demos of the Qt Toolkit.\r
+**\r
+** $QT_BEGIN_LICENSE:LGPL$\r
+** Commercial Usage\r
+** Licensees holding valid Qt Commercial licenses may use this file in\r
+** accordance with the Qt Commercial License Agreement provided with the\r
+** Software or, alternatively, in accordance with the terms contained in\r
+** a written agreement between you and Nokia.\r
+**\r
+** GNU Lesser General Public License Usage\r
+** Alternatively, this file may be used under the terms of the GNU Lesser\r
+** General Public License version 2.1 as published by the Free Software\r
+** Foundation and appearing in the file LICENSE.LGPL included in the\r
+** packaging of this file. Please review the following information to\r
+** ensure the GNU Lesser General Public License version 2.1 requirements\r
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\r
+**\r
+** In addition, as a special exception, Nokia gives you certain additional\r
+** rights. These rights are described in the Nokia Qt LGPL Exception\r
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.\r
+**\r
+** GNU General Public License Usage\r
+** Alternatively, this file may be used under the terms of the GNU\r
+** General Public License version 3.0 as published by the Free Software\r
+** Foundation and appearing in the file LICENSE.GPL included in the\r
+** packaging of this file. Please review the following information to\r
+** ensure the GNU General Public License version 3.0 requirements will be\r
+** met: http://www.gnu.org/copyleft/gpl.html.\r
+**\r
+** If you have questions regarding the use of this file, please contact\r
+** Nokia at qt-info@nokia.com.\r
+** $QT_END_LICENSE$\r
+**\r
+****************************************************************************/\r
+\r
+#include "flickcharm.h"\r
+\r
+#include <QAbstractScrollArea>\r
+#include <QApplication>\r
+#include <QBasicTimer>\r
+#include <QEvent>\r
+#include <QHash>\r
+#include <QList>\r
+#include <QMouseEvent>\r
+#include <QScrollBar>\r
+#include <QTime>\r
+#include <QWebFrame>\r
+#include <QWebView>\r
+\r
+#include <QDebug>\r
+\r
+const int fingerAccuracyThreshold = 3;\r
+\r
+struct FlickData {\r
+ typedef enum {\r
+ Steady, // Interaction without scrolling\r
+ ManualScroll, // Scrolling manually with the finger on the screen\r
+ AutoScroll, // Scrolling automatically\r
+ AutoScrollAcceleration // Scrolling automatically but a finger is on the screen\r
+ } State;\r
+ State state;\r
+ QWidget *widget;\r
+ QPoint pressPos;\r
+ QPoint lastPos;\r
+ QPoint speed;\r
+ QTime speedTimer;\r
+ QList<QEvent*> ignored;\r
+ QTime accelerationTimer;\r
+ bool lastPosValid:1;\r
+ bool waitingAcceleration:1;\r
+\r
+ FlickData()\r
+ : lastPosValid(false)\r
+ , waitingAcceleration(false)\r
+ {}\r
+\r
+ void resetSpeed()\r
+ {\r
+ speed = QPoint();\r
+ lastPosValid = false;\r
+ }\r
+ void updateSpeed(const QPoint &newPosition)\r
+ {\r
+ if (lastPosValid) {\r
+ const int timeElapsed = speedTimer.elapsed();\r
+ if (timeElapsed) {\r
+ const QPoint newPixelDiff = (newPosition - lastPos);\r
+ const QPoint pixelsPerSecond = newPixelDiff * (1000 / timeElapsed);\r
+ // fingers are inacurates, we ignore small changes to avoid stopping the autoscroll because\r
+ // of a small horizontal offset when scrolling vertically\r
+ const int newSpeedY = (qAbs(pixelsPerSecond.y()) > fingerAccuracyThreshold) ? pixelsPerSecond.y() : 0;\r
+ const int newSpeedX = (qAbs(pixelsPerSecond.x()) > fingerAccuracyThreshold) ? pixelsPerSecond.x() : 0;\r
+ if (state == AutoScrollAcceleration) {\r
+ const int max = 4000; // px by seconds\r
+ const int oldSpeedY = speed.y();\r
+ const int oldSpeedX = speed.x();\r
+ if ((oldSpeedY <= 0 && newSpeedY <= 0) || (oldSpeedY >= 0 && newSpeedY >= 0)\r
+ && (oldSpeedX <= 0 && newSpeedX <= 0) || (oldSpeedX >= 0 && newSpeedX >= 0)) {\r
+ speed.setY(qBound(-max, (oldSpeedY + (newSpeedY / 4)), max));\r
+ speed.setX(qBound(-max, (oldSpeedX + (newSpeedX / 4)), max));\r
+ } else {\r
+ speed = QPoint();\r
+ }\r
+ } else {\r
+ const int max = 2500; // px by seconds\r
+ // we average the speed to avoid strange effects with the last delta\r
+ if (!speed.isNull()) {\r
+ speed.setX(qBound(-max, (speed.x() / 4) + (newSpeedX * 3 / 4), max));\r
+ speed.setY(qBound(-max, (speed.y() / 4) + (newSpeedY * 3 / 4), max));\r
+ } else {\r
+ speed = QPoint(newSpeedX, newSpeedY);\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ lastPosValid = true;\r
+ }\r
+ speedTimer.start();\r
+ lastPos = newPosition;\r
+ }\r
+\r
+ // scroll by dx, dy\r
+ // return true if the widget was scrolled\r
+ bool scrollWidget(const int dx, const int dy)\r
+ {\r
+ QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget);\r
+ if (scrollArea) {\r
+ const int x = scrollArea->horizontalScrollBar()->value();\r
+ const int y = scrollArea->verticalScrollBar()->value();\r
+ scrollArea->horizontalScrollBar()->setValue(x - dx);\r
+ scrollArea->verticalScrollBar()->setValue(y - dy);\r
+ return (scrollArea->horizontalScrollBar()->value() != x\r
+ || scrollArea->verticalScrollBar()->value() != y);\r
+ }\r
+\r
+ QWebView *webView = qobject_cast<QWebView*>(widget);\r
+ if (webView) {\r
+ QWebFrame *frame = webView->page()->mainFrame();\r
+ const QPoint position = frame->scrollPosition();\r
+ frame->setScrollPosition(position - QPoint(dx, dy));\r
+ return frame->scrollPosition() != position;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ bool scrollTo(const QPoint &newPosition)\r
+ {\r
+ const QPoint delta = newPosition - lastPos;\r
+ updateSpeed(newPosition);\r
+ return scrollWidget(delta.x(), delta.y());\r
+ }\r
+};\r
+\r
+class FlickCharmPrivate\r
+{\r
+public:\r
+ QHash<QWidget*, FlickData*> flickData;\r
+ QBasicTimer ticker;\r
+ QTime timeCounter;\r
+ void startTicker(QObject *object)\r
+ {\r
+ if (!ticker.isActive())\r
+ ticker.start(15, object);\r
+ timeCounter.start();\r
+ }\r
+};\r
+\r
+FlickCharm::FlickCharm(QObject *parent): QObject(parent)\r
+{\r
+ d = new FlickCharmPrivate;\r
+}\r
+\r
+FlickCharm::~FlickCharm()\r
+{\r
+ delete d;\r
+}\r
+\r
+void FlickCharm::activateOn(QWidget *widget)\r
+{\r
+ QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget);\r
+ if (scrollArea) {\r
+ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);\r
+ scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);\r
+\r
+ QWidget *viewport = scrollArea->viewport();\r
+\r
+ viewport->installEventFilter(this);\r
+ scrollArea->installEventFilter(this);\r
+\r
+ d->flickData.remove(viewport);\r
+ d->flickData[viewport] = new FlickData;\r
+ d->flickData[viewport]->widget = widget;\r
+ d->flickData[viewport]->state = FlickData::Steady;\r
+\r
+ return;\r
+ }\r
+\r
+ QWebView *webView = qobject_cast<QWebView*>(widget);\r
+ if (webView) {\r
+ QWebFrame *frame = webView->page()->mainFrame();\r
+ frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);\r
+ frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);\r
+\r
+ webView->installEventFilter(this);\r
+\r
+ d->flickData.remove(webView);\r
+ d->flickData[webView] = new FlickData;\r
+ d->flickData[webView]->widget = webView;\r
+ d->flickData[webView]->state = FlickData::Steady;\r
+\r
+ return;\r
+ }\r
+\r
+ qWarning() << "FlickCharm only works on QAbstractScrollArea (and derived classes)";\r
+ qWarning() << "or QWebView (and derived classes)";\r
+}\r
+\r
+void FlickCharm::deactivateFrom(QWidget *widget)\r
+{\r
+ QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget);\r
+ if (scrollArea) {\r
+ QWidget *viewport = scrollArea->viewport();\r
+\r
+ viewport->removeEventFilter(this);\r
+ scrollArea->removeEventFilter(this);\r
+\r
+ delete d->flickData[viewport];\r
+ d->flickData.remove(viewport);\r
+\r
+ return;\r
+ }\r
+\r
+ QWebView *webView = qobject_cast<QWebView*>(widget);\r
+ if (webView) {\r
+ webView->removeEventFilter(this);\r
+\r
+ delete d->flickData[webView];\r
+ d->flickData.remove(webView);\r
+\r
+ return;\r
+ }\r
+}\r
+\r
+static QPoint deaccelerate(const QPoint &speed, const int deltatime)\r
+{\r
+ const int deltaSpeed = deltatime;\r
+\r
+ int x = speed.x();\r
+ int y = speed.y();\r
+ x = (x == 0) ? x : (x > 0) ? qMax(0, x - deltaSpeed) : qMin(0, x + deltaSpeed);\r
+ y = (y == 0) ? y : (y > 0) ? qMax(0, y - deltaSpeed) : qMin(0, y + deltaSpeed);\r
+ return QPoint(x, y);\r
+}\r
+\r
+bool FlickCharm::eventFilter(QObject *object, QEvent *event)\r
+{\r
+ if (!object->isWidgetType())\r
+ return false;\r
+\r
+ const QEvent::Type type = event->type();\r
+\r
+ switch (type) {\r
+ case QEvent::MouseButtonPress:\r
+ case QEvent::MouseMove:\r
+ case QEvent::MouseButtonRelease:\r
+ break;\r
+ case QEvent::MouseButtonDblClick: // skip double click\r
+ return true;\r
+ default:\r
+ return false;\r
+ }\r
+\r
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);\r
+ if (type == QEvent::MouseMove && mouseEvent->buttons() != Qt::LeftButton)\r
+ return false;\r
+\r
+ if (mouseEvent->modifiers() != Qt::NoModifier)\r
+ return false;\r
+\r
+ QWidget *viewport = qobject_cast<QWidget*>(object);\r
+ FlickData *data = d->flickData.value(viewport);\r
+ if (!viewport || !data || data->ignored.removeAll(event))\r
+ return false;\r
+\r
+ const QPoint mousePos = mouseEvent->pos();\r
+ bool consumed = false;\r
+ switch (data->state) {\r
+\r
+ case FlickData::Steady:\r
+ if (type == QEvent::MouseButtonPress) {\r
+ consumed = true;\r
+ data->pressPos = mousePos;\r
+ } else if (type == QEvent::MouseButtonRelease) {\r
+ consumed = true;\r
+ QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonPress,\r
+ data->pressPos, Qt::LeftButton,\r
+ Qt::LeftButton, Qt::NoModifier);\r
+ QMouseEvent *event2 = new QMouseEvent(QEvent::MouseButtonRelease,\r
+ data->pressPos, Qt::LeftButton,\r
+ Qt::LeftButton, Qt::NoModifier);\r
+\r
+ data->ignored << event1;\r
+ data->ignored << event2;\r
+ QApplication::postEvent(object, event1);\r
+ QApplication::postEvent(object, event2);\r
+ } else if (type == QEvent::MouseMove) {\r
+ consumed = true;\r
+ data->scrollTo(mousePos);\r
+\r
+ const QPoint delta = mousePos - data->pressPos;\r
+ if (delta.x() > fingerAccuracyThreshold || delta.y() > fingerAccuracyThreshold)\r
+ data->state = FlickData::ManualScroll;\r
+ }\r
+ break;\r
+\r
+ case FlickData::ManualScroll:\r
+ if (type == QEvent::MouseMove) {\r
+ consumed = true;\r
+ data->scrollTo(mousePos);\r
+ } else if (type == QEvent::MouseButtonRelease) {\r
+ consumed = true;\r
+ data->state = FlickData::AutoScroll;\r
+ data->lastPosValid = false;\r
+ d->startTicker(this);\r
+ }\r
+ break;\r
+\r
+ case FlickData::AutoScroll:\r
+ if (type == QEvent::MouseButtonPress) {\r
+ consumed = true;\r
+ data->state = FlickData::AutoScrollAcceleration;\r
+ data->waitingAcceleration = true;\r
+ data->accelerationTimer.start();\r
+ data->updateSpeed(mousePos);\r
+ data->pressPos = mousePos;\r
+ } else if (type == QEvent::MouseButtonRelease) {\r
+ consumed = true;\r
+ data->state = FlickData::Steady;\r
+ data->resetSpeed();\r
+ }\r
+ break;\r
+\r
+ case FlickData::AutoScrollAcceleration:\r
+ if (type == QEvent::MouseMove) {\r
+ consumed = true;\r
+ data->updateSpeed(mousePos);\r
+ data->accelerationTimer.start();\r
+ if (data->speed.isNull())\r
+ data->state = FlickData::ManualScroll;\r
+ } else if (type == QEvent::MouseButtonRelease) {\r
+ consumed = true;\r
+ data->state = FlickData::AutoScroll;\r
+ data->waitingAcceleration = false;\r
+ data->lastPosValid = false;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ data->lastPos = mousePos;\r
+ return true;\r
+}\r
+\r
+void FlickCharm::timerEvent(QTimerEvent *event)\r
+{\r
+ int count = 0;\r
+ QHashIterator<QWidget*, FlickData*> item(d->flickData);\r
+ while (item.hasNext()) {\r
+ item.next();\r
+ FlickData *data = item.value();\r
+ if (data->state == FlickData::AutoScrollAcceleration\r
+ && data->waitingAcceleration\r
+ && data->accelerationTimer.elapsed() > 40) {\r
+ data->state = FlickData::ManualScroll;\r
+ data->resetSpeed();\r
+ }\r
+ if (data->state == FlickData::AutoScroll || data->state == FlickData::AutoScrollAcceleration) {\r
+ const int timeElapsed = d->timeCounter.elapsed();\r
+ const QPoint delta = (data->speed) * timeElapsed / 1000;\r
+ bool hasScrolled = data->scrollWidget(delta.x(), delta.y());\r
+\r
+ if (data->speed.isNull() || !hasScrolled)\r
+ data->state = FlickData::Steady;\r
+ else\r
+ count++;\r
+ data->speed = deaccelerate(data->speed, timeElapsed);\r
+ }\r
+ }\r
+\r
+ if (!count)\r
+ d->ticker.stop();\r
+ else\r
+ d->timeCounter.start();\r
+\r
+ QObject::timerEvent(event);\r
+}\r
--- /dev/null
+/****************************************************************************\r
+**\r
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).\r
+** All rights reserved.\r
+** Contact: Nokia Corporation (qt-info@nokia.com)\r
+**\r
+** This file is part of the demos of the Qt Toolkit.\r
+**\r
+** $QT_BEGIN_LICENSE:LGPL$\r
+** Commercial Usage\r
+** Licensees holding valid Qt Commercial licenses may use this file in\r
+** accordance with the Qt Commercial License Agreement provided with the\r
+** Software or, alternatively, in accordance with the terms contained in\r
+** a written agreement between you and Nokia.\r
+**\r
+** GNU Lesser General Public License Usage\r
+** Alternatively, this file may be used under the terms of the GNU Lesser\r
+** General Public License version 2.1 as published by the Free Software\r
+** Foundation and appearing in the file LICENSE.LGPL included in the\r
+** packaging of this file. Please review the following information to\r
+** ensure the GNU Lesser General Public License version 2.1 requirements\r
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\r
+**\r
+** In addition, as a special exception, Nokia gives you certain additional\r
+** rights. These rights are described in the Nokia Qt LGPL Exception\r
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.\r
+**\r
+** GNU General Public License Usage\r
+** Alternatively, this file may be used under the terms of the GNU\r
+** General Public License version 3.0 as published by the Free Software\r
+** Foundation and appearing in the file LICENSE.GPL included in the\r
+** packaging of this file. Please review the following information to\r
+** ensure the GNU General Public License version 3.0 requirements will be\r
+** met: http://www.gnu.org/copyleft/gpl.html.\r
+**\r
+** If you have questions regarding the use of this file, please contact\r
+** Nokia at qt-info@nokia.com.\r
+** $QT_END_LICENSE$\r
+**\r
+****************************************************************************/\r
+\r
+#ifndef FLICKCHARM_H\r
+#define FLICKCHARM_H\r
+\r
+#include <QObject>\r
+\r
+class FlickCharmPrivate;\r
+class QWidget;\r
+\r
+class FlickCharm: public QObject\r
+{\r
+ Q_OBJECT\r
+public:\r
+ FlickCharm(QObject *parent = 0);\r
+ ~FlickCharm();\r
+ void activateOn(QWidget *widget);\r
+ void deactivateFrom(QWidget *widget);\r
+ bool eventFilter(QObject *object, QEvent *event);\r
+\r
+protected:\r
+ void timerEvent(QTimerEvent *event);\r
+\r
+private:\r
+ FlickCharmPrivate *d;\r
+};\r
+\r
+#endif // FLICKCHARM_H\r
killTimer(timer);
hide();
}
+ QLabel::timerEvent(e);
}