--- /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
+\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
+#include <QtGui>\r
+\r
+#include "listview.h"\r
+#include "trace.h"\r
+\r
+ListView::ListView(QWidget *parent): QListView(parent)\r
+{\r
+#ifndef Q_OS_SYMBIAN\r
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);\r
+#endif\r
+#ifdef Q_OS_SYMBIAN_ONE_DAY\r
+ offset = 0;\r
+ Flickable::setAcceptMouseClick(this);\r
+#endif\r
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);\r
+ setUniformItemSizes(true);\r
+ setEditTriggers(QAbstractItemView::NoEditTriggers);\r
+}\r
+\r
+int ListView::contentsHeight() const\r
+{\r
+ return QListView::contentsSize().height() + 10;\r
+}\r
+\r
+#ifdef Q_OS_SYMBIAN_ONE_DAY\r
+\r
+QPoint ListView::scrollOffset() const\r
+{\r
+ Trace t("ListView::scrollOffset");\r
+ qDebug() << "0," << offset;\r
+ return QPoint(0, offset);\r
+}\r
+\r
+void ListView::setScrollOffset(const QPoint &o)\r
+{\r
+ Trace t("ListView::setScrollOffset");\r
+ qDebug() << o;\r
+ offset = o.y();\r
+ QListView::scrollContentsBy(0, offset)\r
+}\r
+\r
+void ListView::mousePressEvent(QMouseEvent *event)\r
+{\r
+ Flickable::handleMousePress(event);\r
+ if (!event->isAccepted()) {\r
+ QListView::mousePressEvent(event);\r
+ }\r
+}\r
+\r
+void ListView::mouseReleaseEvent(QMouseEvent *event)\r
+{\r
+ Flickable::handleMouseRelease(event);\r
+ if (!event->isAccepted()) {\r
+ QListView::mouseReleaseEvent(event);\r
+ }\r
+}\r
+\r
+void ListView::mouseMoveEvent(QMouseEvent *event)\r
+{\r
+ Flickable::handleMouseMove(event);\r
+ if (!event->isAccepted()) {\r
+ QListView::mouseMoveEvent(eveevent);\r
+ }\r
+}\r
+\r
+#endif // Q_OS_SYMBIAN_ONE_DAY\r