summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@nokia.com>2010-11-30 21:44:52 (GMT)
committerRobert Griebl <robert.griebl@nokia.com>2010-12-02 00:04:34 (GMT)
commit0274e68767cce6440515a68d6af868725d5577a4 (patch)
tree7b219fb5cce3c9e76ae966f13401ae13bad9b28d /examples
parentf6f8ba94d5f82b8df723a217a3d0ecb50e570cbc (diff)
downloadQt-0274e68767cce6440515a68d6af868725d5577a4.zip
Qt-0274e68767cce6440515a68d6af868725d5577a4.tar.gz
Qt-0274e68767cce6440515a68d6af868725d5577a4.tar.bz2
QScroller merge, part 1
This merge consists of the actual kinetic scroller implementation, its autotests plus a few examples. QAbstractScrollArea and QAbstractItemView have been extended to support the new scroll events. The complete history is in http://scm.dev.nokia.troll.no/projects/qt/repos/rgriebls-qt-flickgesture/logs/4.7-flickgesture (part 2 is the QML Flickable replacement / part 3 is QWebView support) Task-number: QTBUG-9054 Reviewed-by: Ralf Engels
Diffstat (limited to 'examples')
-rw-r--r--examples/examples.pro1
-rw-r--r--examples/scroller/graphicsview/graphicsview.pro8
-rw-r--r--examples/scroller/graphicsview/main.cpp292
-rw-r--r--examples/scroller/plot/main.cpp183
-rw-r--r--examples/scroller/plot/plot.pro18
-rw-r--r--examples/scroller/plot/plotwidget.cpp205
-rw-r--r--examples/scroller/plot/plotwidget.h88
-rw-r--r--examples/scroller/plot/settingswidget.cpp690
-rw-r--r--examples/scroller/plot/settingswidget.h107
-rw-r--r--examples/scroller/scroller.pro11
-rw-r--r--examples/scroller/wheel/main.cpp119
-rw-r--r--examples/scroller/wheel/wheel.pro16
-rw-r--r--examples/scroller/wheel/wheelwidget.cpp276
-rw-r--r--examples/scroller/wheel/wheelwidget.h102
14 files changed, 2116 insertions, 0 deletions
diff --git a/examples/examples.pro b/examples/examples.pro
index f233aba..968740d 100644
--- a/examples/examples.pro
+++ b/examples/examples.pro
@@ -20,6 +20,7 @@ SUBDIRS = \
mainwindows \
painting \
richtext \
+ scroller \
sql \
tools \
tutorials \
diff --git a/examples/scroller/graphicsview/graphicsview.pro b/examples/scroller/graphicsview/graphicsview.pro
new file mode 100644
index 0000000..dcebe62
--- /dev/null
+++ b/examples/scroller/graphicsview/graphicsview.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+SOURCES = main.cpp
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/scroller/graphicsview
+sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS graphicsview.pro
+sources.path = $$[QT_INSTALL_EXAMPLES]/scroller/graphicsview
+INSTALLS += target sources
diff --git a/examples/scroller/graphicsview/main.cpp b/examples/scroller/graphicsview/main.cpp
new file mode 100644
index 0000000..e28978f
--- /dev/null
+++ b/examples/scroller/graphicsview/main.cpp
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** 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 examples 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 <QtCore>
+#include <QtGui>
+
+#define NUM_ITEMS 100
+#define NUM_LISTS 10
+
+/*!
+ \class RectObject
+ Note that it needs to be a QGraphicsObject or else the gestures will not work correctly.
+*/
+class RectObject : public QGraphicsObject
+{
+ Q_OBJECT
+
+public:
+
+ RectObject(const QString &text, qreal x, qreal y, qreal width, qreal height, QBrush brush, QGraphicsItem *parent = 0)
+ : QGraphicsObject(parent)
+ , m_text(text)
+ , m_rect(x, y, width, height)
+ , m_pen(brush.color().lighter(), 3.0)
+ , m_brush(brush)
+ {
+ setFlag(QGraphicsItem::ItemClipsToShape, true);
+ }
+
+ QRectF boundingRect() const
+ {
+ // here we only want the size of the children and not the size of the children of the children...
+ qreal halfpw = m_pen.widthF() / 2;
+ QRectF rect = m_rect;
+ if (halfpw > 0.0)
+ rect.adjust(-halfpw, -halfpw, halfpw, halfpw);
+
+ return rect;
+ }
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+ {
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+ painter->setPen(m_pen);
+ painter->setBrush(m_brush);
+ painter->drawRect(m_rect);
+
+ painter->setPen(Qt::black);
+ QFont f;
+ f.setPixelSize(m_rect.height());
+ painter->setFont(f);
+ painter->drawText(m_rect, Qt::AlignCenter, m_text);
+ }
+
+ QString m_text;
+ QRectF m_rect;
+ QPen m_pen;
+ QBrush m_brush;
+};
+
+class ViewObject : public QGraphicsObject
+{
+ Q_OBJECT
+public:
+ ViewObject(QGraphicsObject *parent)
+ : QGraphicsObject(parent)
+ { }
+
+ QRectF boundingRect() const
+ {
+ QRectF rect;
+ foreach (QGraphicsItem *item, childItems())
+ rect |= item->boundingRect().translated(item->pos());
+ return rect;
+ }
+
+ void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
+ { }
+};
+
+class ListObject : public QGraphicsObject
+{
+ Q_OBJECT
+
+public:
+ ListObject(const QSizeF &size, bool useTouch)
+ {
+ m_size = size;
+ setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
+ // grab gesture via Touch or Mouse events
+ QScroller::grabGesture(this, useTouch ? QScroller::TouchGesture : QScroller::LeftMouseButtonGesture);
+
+ // this needs to be QGraphicsOBJECT - otherwise gesture recognition
+ // will not work for the parent of the viewport (in this case the
+ // list)
+ m_viewport = new ViewObject(this);
+
+ }
+
+ QGraphicsObject *viewport() const
+ {
+ return m_viewport;
+ }
+
+ bool event(QEvent *e)
+ {
+ switch (e->type()) {
+// ![2]
+ case QEvent::ScrollPrepare: {
+ QScrollPrepareEvent *se = static_cast<QScrollPrepareEvent *>(e);
+ se->setViewportSize(m_size);
+ QRectF br = m_viewport->boundingRect();
+ se->setContentPosRange(QRectF(0, 0,
+ qMax(qreal(0), br.width() - m_size.width()),
+ qMax(qreal(0), br.height() - m_size.height())));
+ se->setContentPos(-m_viewport->pos());
+ se->accept();
+ return true;
+ }
+// ![1]
+// ![2]
+ case QEvent::Scroll: {
+ QScrollEvent *se = static_cast<QScrollEvent *>(e);
+ m_viewport->setPos(-se->contentPos() - se->overshootDistance());
+ return true;
+ }
+// ![2]
+ default:
+ break;
+ }
+ return QGraphicsObject::event(e);
+ }
+
+ bool sceneEvent(QEvent *e)
+ {
+ switch (e->type()) {
+ case QEvent::TouchBegin: {
+ // We need to return true for the TouchBegin here in the
+ // top-most graphics object - otherwise gestures in our parent
+ // objects will NOT work at all (the accept() flag is already
+ // set due to our setAcceptTouchEvents(true) call in the c'tor
+ return true;
+
+ }
+ case QEvent::GraphicsSceneMousePress: {
+ // We need to return true for the MousePress here in the
+ // top-most graphics object - otherwise gestures in our parent
+ // objects will NOT work at all (the accept() flag is already
+ // set to true by Qt)
+ return true;
+
+ }
+ default:
+ break;
+ }
+ return QGraphicsObject::sceneEvent(e);
+ }
+
+ QRectF boundingRect() const
+ {
+ return QRectF(0, 0, m_size.width() + 3, m_size.height());
+ }
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+ {
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+ painter->setPen(QPen(QColor(100, 100, 100), 3.0));
+ painter->drawRect(QRect(1.5, 1.5, m_size.width() - 3, m_size.height() - 3));
+ }
+
+ QSizeF m_size;
+ ViewObject *m_viewport;
+};
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(bool useTouch)
+ {
+ m_scene = new QGraphicsScene();
+
+ // -- make the main list
+ ListObject *mainList = new ListObject(QSizeF(780, 400), useTouch);
+ mainList->setObjectName(QLatin1String("MainList"));
+ m_scene->addItem(mainList);
+// ![3]
+ for (int i=0; i<NUM_LISTS; i++) {
+ ListObject *childList = new ListObject(QSizeF(mainList->m_size.width()/3, mainList->m_size.height()), useTouch);
+ childList->setObjectName(QString("ChildList %1").arg(i));
+ fillList(childList);
+ childList->setParentItem(mainList->viewport());
+ childList->setPos(i*mainList->m_size.width()/3, 0);
+ }
+ mainList->viewport()->setPos(0, 0);
+
+
+ /*
+ list1->setTransformOriginPoint(200, 200);
+ list1->setRotation(135);
+ list1->setPos(20 + 200 * .41, 20 + 200 * .41);
+ */
+// ![3]
+
+ m_view = new QGraphicsView(m_scene);
+ setCentralWidget(m_view);
+ setWindowTitle(tr("Gesture example"));
+ m_scene->setSceneRect(0, 0, m_view->viewport()->width(), m_view->viewport()->height());
+ }
+
+ /**
+ * Fills the list object \a list with RectObjects.
+ */
+ void fillList(ListObject *list)
+ {
+ qreal h = list->m_size.height() / 10;
+ for (int i=0; i<NUM_ITEMS; i++) {
+ QColor color = QColor(255*i/NUM_ITEMS, 255*(NUM_ITEMS-i)/NUM_ITEMS, 127*(i%2)+64*(i/2%2));
+ QString text = QLatin1String("Item #") + QString::number(i);
+ QGraphicsItem *rect = new RectObject(text, 0, 0, list->m_size.width() - 6, h - 3, QBrush(color), list->viewport());
+ rect->setPos(3, h*i+3);
+ }
+ list->viewport()->setPos(0, 0);
+ }
+
+
+protected:
+ void resizeEvent(QResizeEvent *e)
+ {
+ // resize the scene according to our own size to prevent scrolling
+ m_scene->setSceneRect(0, 0, m_view->viewport()->width(), m_view->viewport()->height());
+ QMainWindow::resizeEvent(e);
+ }
+
+ QGraphicsScene *m_scene;
+ QGraphicsView *m_view;
+};
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ bool useTouch = (app.arguments().contains(QLatin1String("--touch")));
+ MainWindow mw(useTouch);
+ mw.show();
+#ifdef Q_WS_MAC
+ mw.raise();
+#endif
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/examples/scroller/plot/main.cpp b/examples/scroller/plot/main.cpp
new file mode 100644
index 0000000..a4e2add
--- /dev/null
+++ b/examples/scroller/plot/main.cpp
@@ -0,0 +1,183 @@
+
+#include <QApplication>
+#include <QListWidget>
+#include <QListWidgetItem>
+#include <QSplitter>
+#include <QStackedWidget>
+#include <QSignalMapper>
+#include <QMainWindow>
+#include <QMenuBar>
+#include <QActionGroup>
+#include <QWebView>
+#include <QTimer>
+#include <QScroller>
+
+#include <QtDebug>
+
+#include <QGesture>
+
+#include "settingswidget.h"
+#include "plotwidget.h"
+
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ MainWindow(bool smallscreen, bool touch)
+ : QMainWindow(), m_touch(touch)
+ {
+ m_list = new QListWidget();
+ m_list->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+ m_list_scroller = installKineticScroller(m_list);
+
+ for (int i = 0; i < 1000; ++i)
+ new QListWidgetItem(QString("This is a test text %1 %2").arg(i).arg(QString("--------").left(i % 8)), m_list);
+
+ connect(m_list, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(listItemActivated(QListWidgetItem*)));
+ connect(m_list, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(listItemClicked(QListWidgetItem*)));
+ connect(m_list, SIGNAL(itemPressed(QListWidgetItem*)), this, SLOT(listItemPressed(QListWidgetItem*)));
+ connect(m_list, SIGNAL(itemSelectionChanged()), this, SLOT(listItemSelectionChanged()));
+ connect(m_list, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(listItemCurrentChanged(QListWidgetItem*)));
+
+ m_web = new QWebView();
+ m_web_scroller = installKineticScroller(m_web);
+
+ QTimer::singleShot(1000, this, SLOT(loadUrl()));
+
+ m_settings = new SettingsWidget(smallscreen);
+ installKineticScroller(m_settings);
+ m_plot = new PlotWidget(smallscreen);
+
+ QStackedWidget *stack = new QStackedWidget();
+ stack->addWidget(m_list);
+ stack->addWidget(m_web);
+
+ QActionGroup *pages = new QActionGroup(this);
+ pages->setExclusive(true);
+ QSignalMapper *mapper = new QSignalMapper(this);
+ connect(mapper, SIGNAL(mapped(int)), stack, SLOT(setCurrentIndex(int)));
+
+ createAction("List", pages, mapper, 0, true);
+ createAction("Web", pages, mapper, 1);
+
+ if (smallscreen) {
+ stack->addWidget(m_settings);
+ stack->addWidget(m_plot);
+
+ createAction("Settings", pages, mapper, 2);
+ createAction("Plot", pages, mapper, 3);
+
+ setCentralWidget(stack);
+ } else {
+ QSplitter *split = new QSplitter();
+ m_settings->setMinimumWidth(m_settings->sizeHint().width());
+ split->addWidget(stack);
+ split->addWidget(m_settings);
+ split->addWidget(m_plot);
+ setCentralWidget(split);
+ }
+ menuBar()->addMenu(QLatin1String("Pages"))->addActions(pages->actions());
+ connect(stack, SIGNAL(currentChanged(int)), this, SLOT(pageChanged(int)));
+ pageChanged(0);
+ }
+
+private slots:
+ void pageChanged(int page)
+ {
+ if (page < 0 || page > 1)
+ return;
+ switch (page) {
+ case 0:
+ m_settings->setScroller(m_list);
+ m_plot->setScroller(m_list);
+ break;
+ case 1:
+ m_settings->setScroller(m_web);
+ m_plot->setScroller(m_web);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void loadUrl()
+ {
+ m_web->load(QUrl("http://www.google.com"));
+ }
+
+ void listItemActivated(QListWidgetItem *lwi) { qWarning() << "Item ACTIVATED: " << lwi->text(); }
+ void listItemClicked(QListWidgetItem *lwi) { qWarning() << "Item CLICKED: " << lwi->text(); }
+ void listItemPressed(QListWidgetItem *lwi) { qWarning() << "Item PRESSED: " << lwi->text(); }
+ void listItemCurrentChanged(QListWidgetItem *lwi) { qWarning() << "Item CURRENT: " << (lwi ? lwi->text() : QString("(none)")); }
+ void listItemSelectionChanged()
+ {
+ int n = m_list->selectedItems().count();
+ qWarning("Item%s SELECTED: %d", n == 1 ? "" : "s", n);
+ foreach (QListWidgetItem *lwi, m_list->selectedItems())
+ qWarning() << " " << lwi->text();
+ }
+
+private:
+ QAction *createAction(const char *text, QActionGroup *group, QSignalMapper *mapper, int mapping, bool checked = false)
+ {
+ QAction *a = new QAction(QLatin1String(text), group);
+ a->setCheckable(true);
+ a->setChecked(checked);
+#if defined(Q_WS_MAC)
+ a->setMenuRole(QAction::NoRole);
+#endif
+ mapper->setMapping(a, mapping);
+ connect(a, SIGNAL(toggled(bool)), mapper, SLOT(map()));
+ return a;
+ }
+
+ QScroller *installKineticScroller(QWidget *w)
+ {
+ if (QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(w)) {
+ QScroller::grabGesture(area->viewport(), m_touch ? QScroller::TouchGesture : QScroller::LeftMouseButtonGesture);
+ return QScroller::scroller(area->viewport());
+ } else if (QWebView *web = qobject_cast<QWebView *>(w)) {
+ QScroller::grabGesture(web, m_touch ? QScroller::TouchGesture : QScroller::LeftMouseButtonGesture);
+ }
+ return QScroller::scroller(w);
+ }
+
+private:
+ QListWidget *m_list;
+ QWebView *m_web;
+ QScroller *m_list_scroller, *m_web_scroller;
+ SettingsWidget *m_settings;
+ PlotWidget *m_plot;
+ bool m_touch;
+};
+
+int main(int argc, char **argv)
+{
+ QApplication a(argc, argv);
+
+#if defined(Q_WS_MAEMO_5) || defined(Q_WS_S60) || defined(Q_WS_WINCE)
+ bool smallscreen = true;
+#else
+ bool smallscreen = false;
+#endif
+ bool touch = false;
+
+ if (a.arguments().contains(QLatin1String("--small")))
+ smallscreen = true;
+ if (a.arguments().contains(QLatin1String("--touch")))
+ touch = true;
+
+ MainWindow *mw = new MainWindow(smallscreen, touch);
+ if (smallscreen)
+ mw->showMaximized();
+ else
+ mw->show();
+#if defined(Q_WS_MAC)
+ mw->raise();
+#endif
+
+ return a.exec();
+}
+
+#include "main.moc"
diff --git a/examples/scroller/plot/plot.pro b/examples/scroller/plot/plot.pro
new file mode 100644
index 0000000..8c37b04
--- /dev/null
+++ b/examples/scroller/plot/plot.pro
@@ -0,0 +1,18 @@
+HEADERS = settingswidget.h \
+ plotwidget.h
+SOURCES = settingswidget.cpp \
+ plotwidget.cpp \
+ main.cpp
+
+QT += webkit
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/scroller/plot
+sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS plot.pro
+sources.path = $$[QT_INSTALL_EXAMPLES]/scroller/plot
+INSTALLS += target sources
+
+symbian {
+ TARGET.UID3 = 0xA000CF66
+ include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
+}
diff --git a/examples/scroller/plot/plotwidget.cpp b/examples/scroller/plot/plotwidget.cpp
new file mode 100644
index 0000000..5f0df67
--- /dev/null
+++ b/examples/scroller/plot/plotwidget.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** 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 QtGui module 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 <QPushButton>
+#include <QTextStream>
+#include <QColor>
+#include <QPainter>
+#include <QLabel>
+#include <QResizeEvent>
+#include <QPlastiqueStyle>
+#include <QAbstractScrollArea>
+
+#include "plotwidget.h"
+#include "qscroller.h"
+
+PlotWidget::PlotWidget(bool /*smallscreen*/)
+ : QWidget(), m_widget(0)
+{
+ setWindowTitle(QLatin1String("Plot"));
+ m_clear = new QPushButton(QLatin1String("Clear"), this);
+#if defined(Q_WS_MAEMO_5)
+ m_clear->setStyle(new QPlastiqueStyle());
+ m_clear->setFixedHeight(55);
+#endif
+ connect(m_clear, SIGNAL(clicked()), this, SLOT(reset()));
+ m_legend = new QLabel(this);
+ QString legend;
+ QTextStream ts(&legend);
+ // ok. this wouldn't pass the w3c html verification...
+ ts << "<table style=\"color:#000;\" border=\"0\">";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::red).light().name() << "\" /><td>Velocity X</td></tr>";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::red).dark().name() << "\" /><td>Velocity Y</td></tr>";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::green).light().name() << "\" /><td>Content Position X</td></tr>";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::green).dark().name() << "\" /><td>Content Position Y</td></tr>";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::blue).light().name() << "\" /><td>Overshoot Position X</td></tr>";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::blue).dark().name() << "\" /><td>Overshoot Position Y</td></tr>";
+ ts << "</table>";
+ m_legend->setText(legend);
+}
+
+void PlotWidget::setScroller(QWidget *widget)
+{
+ if (QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(widget))
+ widget = area->viewport();
+
+ if (m_widget)
+ m_widget->removeEventFilter(this);
+ m_widget = widget;
+ reset();
+ if (m_widget)
+ m_widget->installEventFilter(this);
+}
+
+bool PlotWidget::eventFilter(QObject *obj, QEvent *ev)
+{
+ if (ev->type() == QEvent::Scroll) {
+ QScrollEvent *se = static_cast<QScrollEvent *>(ev);
+ QScroller *scroller = QScroller::scroller(m_widget);
+
+ QPointF v = scroller->velocity();
+ //v.rx() *= scroller->pixelPerMeter().x();
+ //v.ry() *= scroller->pixelPerMeter().y();
+
+ PlotItem pi = { v, se->contentPos(), se->overshootDistance() };
+ addPlotItem(pi);
+ }
+
+ return QWidget::eventFilter(obj, ev);
+}
+
+static inline void doMaxMin(const QPointF &v, qreal &minmaxv)
+{
+ minmaxv = qMax(minmaxv, qMax(qAbs(v.x()), qAbs(v.y())));
+}
+
+void PlotWidget::addPlotItem(const PlotItem &pi)
+{
+ m_plotitems.append(pi);
+ minMaxVelocity = minMaxPosition = 0;
+
+ while (m_plotitems.size() > 500)
+ m_plotitems.removeFirst();
+
+ foreach (const PlotItem &pi, m_plotitems) {
+ doMaxMin(pi.velocity, minMaxVelocity);
+ doMaxMin(pi.contentPosition, minMaxPosition);
+ doMaxMin(pi.overshootPosition, minMaxPosition);
+ }
+ update();
+}
+
+void PlotWidget::reset()
+{
+ m_plotitems.clear();
+ minMaxVelocity = minMaxPosition = 0;
+ update();
+}
+
+void PlotWidget::resizeEvent(QResizeEvent *)
+{
+ QSize cs = m_clear->sizeHint();
+ QSize ls = m_legend->sizeHint();
+ m_clear->setGeometry(4, 4, cs.width(), cs.height());
+ m_legend->setGeometry(4, height() - ls.height() - 4, ls.width(), ls.height());
+}
+
+void PlotWidget::paintEvent(QPaintEvent *)
+{
+#define SCALE(v, mm) ((qreal(1) - (v / mm)) * qreal(0.5) * height())
+
+ QColor rvColor = Qt::red;
+ QColor cpColor = Qt::green;
+ QColor opColor = Qt::blue;
+
+
+ QPainter p(this);
+ //p.setRenderHints(QPainter::Antialiasing); //too slow for 60fps
+ p.fillRect(rect(), Qt::white);
+
+ p.setPen(Qt::black);
+ p.drawLine(0, SCALE(0, 1), width(), SCALE(0, 1));
+
+ if (m_plotitems.isEmpty())
+ return;
+
+ int x = 2;
+ int offset = m_plotitems.size() - width() / 2;
+ QList<PlotItem>::const_iterator it = m_plotitems.constBegin();
+ if (offset > 0)
+ it += (offset - 1);
+
+ const PlotItem *last = &(*it++);
+
+ while (it != m_plotitems.constEnd()) {
+ p.setPen(rvColor.light());
+ p.drawLine(qreal(x - 2), SCALE(last->velocity.x(), minMaxVelocity),
+ qreal(x), SCALE(it->velocity.x(), minMaxVelocity));
+ p.setPen(rvColor.dark());
+ p.drawLine(qreal(x - 2), SCALE(last->velocity.y(), minMaxVelocity),
+ qreal(x), SCALE(it->velocity.y(), minMaxVelocity));
+
+ p.setPen(cpColor.light());
+ p.drawLine(qreal(x - 2), SCALE(last->contentPosition.x(), minMaxPosition),
+ qreal(x), SCALE(it->contentPosition.x(), minMaxPosition));
+ p.setPen(cpColor.dark());
+ p.drawLine(qreal(x - 2), SCALE(last->contentPosition.y(), minMaxPosition),
+ qreal(x), SCALE(it->contentPosition.y(), minMaxPosition));
+
+ p.setPen(opColor.light());
+ p.drawLine(qreal(x - 2), SCALE(last->overshootPosition.x(), minMaxPosition),
+ qreal(x), SCALE(it->overshootPosition.x(), minMaxPosition));
+ p.setPen(opColor.dark());
+ p.drawLine(qreal(x - 2), SCALE(last->overshootPosition.y(), minMaxPosition),
+ qreal(x), SCALE(it->overshootPosition.y(), minMaxPosition));
+
+ last = &(*it++);
+ x += 2;
+ }
+
+ QString toptext = QString("%1 [m/s] / %2 [pix]").arg(minMaxVelocity, 0, 'f', 2).arg(minMaxPosition, 0, 'f', 2);
+ QString bottomtext = QString("-%1 [m/s] / -%2 [pix]").arg(minMaxVelocity, 0, 'f', 2).arg(minMaxPosition, 0, 'f', 2);
+
+ p.setPen(Qt::black);
+ p.drawText(rect(), Qt::AlignTop | Qt::AlignHCenter, toptext);
+ p.drawText(rect(), Qt::AlignBottom | Qt::AlignHCenter, bottomtext);
+#undef SCALE
+}
diff --git a/examples/scroller/plot/plotwidget.h b/examples/scroller/plot/plotwidget.h
new file mode 100644
index 0000000..3b4d92d
--- /dev/null
+++ b/examples/scroller/plot/plotwidget.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** 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 QtGui module 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$
+**
+****************************************************************************/
+
+#ifndef PLOTWIDGET_H
+#define PLOTWIDGET_H
+
+#include <QWidget>
+#include <QPointF>
+
+class QPushButton;
+class QLabel;
+
+class QScroller;
+
+class PlotWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ PlotWidget(bool smallscreen = false);
+
+ void setScroller(QWidget *widget);
+
+public slots:
+ void reset();
+
+protected:
+ void resizeEvent(QResizeEvent *);
+ void paintEvent(QPaintEvent *);
+
+ bool eventFilter(QObject *obj, QEvent *ev);
+
+private:
+
+ struct PlotItem {
+ QPointF velocity;
+ QPointF contentPosition;
+ QPointF overshootPosition;
+ };
+
+ void addPlotItem(const PlotItem &pi);
+
+ QWidget *m_widget;
+ QList<PlotItem> m_plotitems;
+ qreal minMaxVelocity, minMaxPosition;
+ QPushButton *m_clear;
+ QLabel *m_legend;
+};
+
+#endif
diff --git a/examples/scroller/plot/settingswidget.cpp b/examples/scroller/plot/settingswidget.cpp
new file mode 100644
index 0000000..af1e621
--- /dev/null
+++ b/examples/scroller/plot/settingswidget.cpp
@@ -0,0 +1,690 @@
+/****************************************************************************
+**
+** 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 QtGui module 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 <QVariant>
+#include <QSlider>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPushButton>
+#include <QComboBox>
+#include <QSpinBox>
+#include <QGroupBox>
+#include <QToolButton>
+#include <QCheckBox>
+#include <QScrollBar>
+#include <QPainter>
+#include <QScrollArea>
+#include <QScrollPrepareEvent>
+#include <QApplication>
+#include <QPlainTextEdit>
+#include <QTextBlock>
+#include <qnumeric.h>
+
+#include <QEasingCurve>
+
+#include <QDebug>
+
+#include "math.h"
+
+#include "settingswidget.h"
+#include "qscroller.h"
+#include "qscrollerproperties.h"
+
+class SnapOverlay : public QWidget
+{
+ Q_OBJECT
+public:
+ SnapOverlay(QWidget *w)
+ : QWidget(w)
+ {
+ setAttribute(Qt::WA_TransparentForMouseEvents);
+
+ if (QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(w)) {
+ connect(area->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(update()));
+ connect(area->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(update()));
+ area->viewport()->installEventFilter(this);
+ }
+ }
+ void clear(Qt::Orientation o)
+ {
+ m_snap[o].clear();
+ update();
+ }
+
+ void set(Qt::Orientation o, qreal first, qreal step)
+ {
+ m_snap[o] = QList<qreal>() << -Q_INFINITY << first << step;
+ update();
+ }
+
+ void set(Qt::Orientation o, const QList<qreal> &list)
+ {
+ m_snap[o] = list;
+ update();
+ }
+
+protected:
+ bool eventFilter(QObject *o, QEvent *e)
+ {
+ if (QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(parentWidget())) {
+ if (area->viewport() == o) {
+ if (e->type() == QEvent::Move || e->type() == QEvent::Resize) {
+ setGeometry(area->viewport()->rect());
+ }
+ }
+ }
+ return false;
+ }
+
+ void paintEvent(QPaintEvent *e)
+ {
+ if (QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(parentWidget())) {
+ int dx = area->horizontalScrollBar()->value();
+ int dy = area->verticalScrollBar()->value();
+
+ QPainter paint(this);
+ paint.fillRect(e->rect(), Qt::transparent);
+ paint.setPen(QPen(Qt::red, 9));
+
+ if (m_snap[Qt::Horizontal].isEmpty()) {
+ } else if (m_snap[Qt::Horizontal][0] == -Q_INFINITY) {
+ int start = int(m_snap[Qt::Horizontal][1]);
+ int step = int(m_snap[Qt::Horizontal][2]);
+ if (step > 0) {
+ for (int i = start; i < area->horizontalScrollBar()->maximum(); i += step)
+ paint.drawPoint(i - dx, 5);
+ }
+ } else {
+ foreach (qreal r, m_snap[Qt::Horizontal])
+ paint.drawPoint(int(r) - dx, 5);
+ }
+ paint.setPen(QPen(Qt::green, 9));
+ if (m_snap[Qt::Vertical].isEmpty()) {
+ } else if (m_snap[Qt::Vertical][0] == -Q_INFINITY) {
+ int start = int(m_snap[Qt::Vertical][1]);
+ int step = int(m_snap[Qt::Vertical][2]);
+ if (step > 0) {
+ for (int i = start; i < area->verticalScrollBar()->maximum(); i += step)
+ paint.drawPoint(5, i - dy);
+ }
+ } else {
+ foreach (qreal r, m_snap[Qt::Vertical])
+ paint.drawPoint(5, int(r) - dy);
+ }
+ }
+ }
+
+private:
+ QMap<Qt::Orientation, QList<qreal> > m_snap;
+};
+
+struct MetricItem
+{
+ QScrollerProperties::ScrollMetric metric;
+ const char *name;
+ int scaling;
+ const char *unit;
+ QVariant min, max;
+ QVariant step;
+};
+
+class MetricItemUpdater : public QObject
+{
+ Q_OBJECT
+public:
+ MetricItemUpdater(MetricItem *item)
+ : m_item(item)
+ , m_widget(0)
+ , m_slider(0)
+ , m_combo(0)
+ , m_valueLabel(0)
+ {
+ m_frameRateType = QVariant::fromValue(QScrollerProperties::Standard).userType();
+ m_overshootPolicyType = QVariant::fromValue(QScrollerProperties::OvershootWhenScrollable).userType();
+
+ if (m_item->min.type() == QVariant::EasingCurve) {
+ m_combo = new QComboBox();
+ m_combo->addItem("OutQuad", QEasingCurve::OutQuad);
+ m_combo->addItem("OutCubic", QEasingCurve::OutCubic);
+ m_combo->addItem("OutQuart", QEasingCurve::OutQuart);
+ m_combo->addItem("OutQuint", QEasingCurve::OutQuint);
+ m_combo->addItem("OutExpo", QEasingCurve::OutExpo);
+ m_combo->addItem("OutSine", QEasingCurve::OutSine);
+ m_combo->addItem("OutCirc", QEasingCurve::OutCirc);
+ } else if (m_item->min.userType() == m_frameRateType) {
+ m_combo = new QComboBox();
+ m_combo->addItem("Standard", QScrollerProperties::Standard);
+ m_combo->addItem("60 FPS", QScrollerProperties::Fps60);
+ m_combo->addItem("30 FPS", QScrollerProperties::Fps30);
+ m_combo->addItem("20 FPS", QScrollerProperties::Fps20);
+ } else if (m_item->min.userType() == m_overshootPolicyType) {
+ m_combo = new QComboBox();
+ m_combo->addItem("When Scrollable", QScrollerProperties::OvershootWhenScrollable);
+ m_combo->addItem("Always On", QScrollerProperties::OvershootAlwaysOn);
+ m_combo->addItem("Always Off", QScrollerProperties::OvershootAlwaysOff);
+ } else {
+ m_slider = new QSlider(Qt::Horizontal);
+ m_slider->setSingleStep(1);
+ m_slider->setMinimum(-1);
+ m_slider->setMaximum(qRound((m_item->max.toReal() - m_item->min.toReal()) / m_item->step.toReal()));
+ m_slider->setValue(-1);
+ m_valueLabel = new QLabel();
+ }
+ m_nameLabel = new QLabel(QLatin1String(m_item->name));
+ if (m_item->unit && m_item->unit[0])
+ m_nameLabel->setText(m_nameLabel->text() + QLatin1String(" [") + QLatin1String(m_item->unit) + QLatin1String("]"));
+ m_resetButton = new QToolButton();
+ m_resetButton->setText(QLatin1String("Reset"));
+ m_resetButton->setEnabled(false);
+
+ connect(m_resetButton, SIGNAL(clicked()), this, SLOT(reset()));
+ if (m_slider) {
+ connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(controlChanged(int)));
+ m_slider->setMinimum(0);
+ } else if (m_combo) {
+ connect(m_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(controlChanged(int)));
+ }
+ }
+
+ void setScroller(QWidget *widget)
+ {
+ m_widget = widget;
+ QScroller *scroller = QScroller::scroller(widget);
+ QScrollerProperties properties = QScroller::scroller(widget)->scrollerProperties();
+
+ if (m_slider)
+ m_slider->setEnabled(scroller);
+ if (m_combo)
+ m_combo->setEnabled(scroller);
+ m_nameLabel->setEnabled(scroller);
+ if (m_valueLabel)
+ m_valueLabel->setEnabled(scroller);
+ m_resetButton->setEnabled(scroller);
+
+ if (!scroller)
+ return;
+
+ m_default_value = properties.scrollMetric(m_item->metric);
+ valueChanged(m_default_value);
+ }
+
+ QWidget *nameLabel() { return m_nameLabel; }
+ QWidget *valueLabel() { return m_valueLabel; }
+ QWidget *valueControl() { if (m_combo) return m_combo; else return m_slider; }
+ QWidget *resetButton() { return m_resetButton; }
+
+private slots:
+ void valueChanged(const QVariant &v)
+ {
+ m_value = v;
+ if (m_slider) {
+ switch (m_item->min.type()) {
+ case QMetaType::Float:
+ case QVariant::Double: {
+ m_slider->setValue(qRound((m_value.toReal() * m_item->scaling - m_item->min.toReal()) / m_item->step.toReal()));
+ break;
+ }
+ case QVariant::Int: {
+ m_slider->setValue(qRound((m_value.toInt() * m_item->scaling - m_item->min.toInt()) / m_item->step.toInt()));
+ break;
+ }
+ default: break;
+ }
+ } else if (m_combo) {
+ if (m_item->min.type() == QVariant::EasingCurve) {
+ m_combo->setCurrentIndex(m_combo->findData(v.toEasingCurve().type()));
+ } else if (m_item->min.userType() == m_overshootPolicyType) {
+ m_combo->setCurrentIndex(m_combo->findData(v.value<QScrollerProperties::OvershootPolicy>()));
+ } else if (m_item->min.userType() == m_frameRateType) {
+ m_combo->setCurrentIndex(m_combo->findData(v.value<QScrollerProperties::FrameRates>()));
+ }
+ }
+ }
+
+ void controlChanged(int value)
+ {
+ bool combo = (m_combo && (sender() == m_combo));
+ QString text;
+
+ if (m_slider && !combo) {
+ switch (m_item->min.type()) {
+ case QMetaType::Float:
+ case QVariant::Double: {
+ qreal d = m_item->min.toReal() + qreal(value) * m_item->step.toReal();
+ text = QString::number(d);
+ m_value = d / qreal(m_item->scaling);
+ break;
+ }
+ case QVariant::Int: {
+ int i = m_item->min.toInt() + qRound(qreal(value) * m_item->step.toReal());
+ text = QString::number(i);
+ m_value = i / m_item->scaling;
+ break;
+ }
+ default: break;
+ }
+ } else if (m_combo && combo) {
+ if (m_item->min.type() == QVariant::EasingCurve) {
+ m_value = QVariant(QEasingCurve(static_cast<QEasingCurve::Type>(m_combo->itemData(value).toInt())));
+ } else if (m_item->min.userType() == m_overshootPolicyType) {
+ m_value = QVariant::fromValue(static_cast<QScrollerProperties::OvershootPolicy>(m_combo->itemData(value).toInt()));
+ } else if (m_item->min.userType() == m_frameRateType) {
+ m_value = QVariant::fromValue(static_cast<QScrollerProperties::FrameRates>(m_combo->itemData(value).toInt()));
+ }
+ }
+ if (m_valueLabel)
+ m_valueLabel->setText(text);
+ if (m_widget && QScroller::scroller(m_widget)) {
+ QScrollerProperties properties = QScroller::scroller(m_widget)->scrollerProperties();
+ properties.setScrollMetric(m_item->metric, m_value);
+ QScroller::scroller(m_widget)->setScrollerProperties(properties);
+ }
+
+ m_resetButton->setEnabled(m_value != m_default_value);
+ }
+
+ void reset()
+ {
+ QScrollerProperties properties = QScroller::scroller(m_widget)->scrollerProperties();
+ properties.setScrollMetric(m_item->metric, m_value);
+ QScroller::scroller(m_widget)->setScrollerProperties(properties);
+ valueChanged(m_default_value);
+ }
+
+private:
+ MetricItem *m_item;
+ int m_frameRateType;
+ int m_overshootPolicyType;
+
+ QWidget *m_widget;
+ QSlider *m_slider;
+ QComboBox *m_combo;
+ QLabel *m_nameLabel, *m_valueLabel;
+ QToolButton *m_resetButton;
+
+ QVariant m_value, m_default_value;
+};
+
+#define METRIC(x) QScrollerProperties::x, #x
+
+MetricItem items[] = {
+ { METRIC(MousePressEventDelay), 1000, "ms", qreal(0), qreal(2000), qreal(10) },
+ { METRIC(DragStartDistance), 1000, "mm", qreal(1), qreal(20), qreal(0.1) },
+ { METRIC(DragVelocitySmoothingFactor), 1, "", qreal(0), qreal(1), qreal(0.01) },
+ { METRIC(AxisLockThreshold), 1, "", qreal(0), qreal(1), qreal(0.01) },
+
+ { METRIC(ScrollingCurve), 1, "", QEasingCurve(), 0, 0 },
+ { METRIC(DecelerationFactor), 1, "", qreal(0), qreal(3), qreal(0.01) },
+
+ { METRIC(MinimumVelocity), 1, "m/s", qreal(0), qreal(7), qreal(0.01) },
+ { METRIC(MaximumVelocity), 1, "m/s", qreal(0), qreal(7), qreal(0.01) },
+ { METRIC(MaximumClickThroughVelocity), 1, "m/s", qreal(0), qreal(7), qreal(0.01) },
+
+ { METRIC(AcceleratingFlickMaximumTime), 1000, "ms", qreal(100), qreal(5000), qreal(100) },
+ { METRIC(AcceleratingFlickSpeedupFactor), 1, "", qreal(1), qreal(7), qreal(0.1) },
+
+ { METRIC(SnapPositionRatio), 1, "", qreal(0.1), qreal(0.9), qreal(0.1) },
+ { METRIC(SnapTime), 1000, "ms", qreal(0), qreal(2000), qreal(10) },
+
+ { METRIC(OvershootDragResistanceFactor), 1, "", qreal(0), qreal(1), qreal(0.01) },
+ { METRIC(OvershootDragDistanceFactor), 1, "", qreal(0), qreal(1), qreal(0.01) },
+ { METRIC(OvershootScrollDistanceFactor), 1, "", qreal(0), qreal(1), qreal(0.01) },
+ { METRIC(OvershootScrollTime), 1000, "ms", qreal(0), qreal(2000), qreal(10) },
+
+ { METRIC(HorizontalOvershootPolicy), 1, "", QVariant::fromValue(QScrollerProperties::OvershootWhenScrollable), 0, 0 },
+ { METRIC(VerticalOvershootPolicy), 1, "", QVariant::fromValue(QScrollerProperties::OvershootWhenScrollable), 0, 0 },
+ { METRIC(FrameRate), 1, "", QVariant::fromValue(QScrollerProperties::Standard), 0, 0 },
+};
+
+#undef METRIC
+
+void SettingsWidget::addToGrid(QGridLayout *grid, QWidget *label, int widgetCount, ...)
+{
+ va_list args;
+ va_start(args, widgetCount);
+
+ int rows = grid->rowCount();
+ int cols = grid->columnCount();
+
+ if (label) {
+ if (m_smallscreen)
+ grid->addWidget(label, rows++, 0, 1, qMax(cols, widgetCount));
+ else
+ grid->addWidget(label, rows, 0);
+ }
+ for (int i = 0; i < widgetCount; i++) {
+ if (QWidget *w = va_arg(args, QWidget *))
+ grid->addWidget(w, rows, m_smallscreen ? i : i + 1);
+ }
+ va_end(args);
+}
+
+SettingsWidget::SettingsWidget(bool smallscreen)
+ : QScrollArea()
+ , m_widget(0)
+ , m_snapoverlay(0)
+ , m_smallscreen(smallscreen)
+{
+ setWindowTitle(QLatin1String("Settings"));
+ QWidget *view = new QWidget();
+ QVBoxLayout *layout = new QVBoxLayout(view);
+ QGroupBox *grp;
+ QGridLayout *grid;
+
+ // GROUP: SCROLL METRICS
+
+ grp = new QGroupBox(QLatin1String("Scroll Metrics"));
+ grid = new QGridLayout();
+ grid->setVerticalSpacing(m_smallscreen ? 4 : 2);
+
+ for (int i = 0; i < int(sizeof(items) / sizeof(items[0])); i++) {
+ MetricItemUpdater *u = new MetricItemUpdater(items + i);
+ u->setParent(this);
+ addToGrid(grid, u->nameLabel(), 3, u->valueControl(), u->valueLabel(), u->resetButton());
+ m_metrics.append(u);
+ }
+ grp->setLayout(grid);
+ layout->addWidget(grp);
+
+ // GROUP: SCROLL TO
+
+ grp = new QGroupBox(QLatin1String("Scroll To"));
+ grid = new QGridLayout();
+ grid->setVerticalSpacing(m_smallscreen ? 4 : 2);
+
+ m_scrollx = new QSpinBox();
+ m_scrolly = new QSpinBox();
+ m_scrolltime = new QSpinBox();
+ m_scrolltime->setRange(0, 10000);
+ m_scrolltime->setValue(1000);
+ m_scrolltime->setSuffix(QLatin1String(" ms"));
+ QPushButton *go = new QPushButton(QLatin1String("Go"));
+ connect(go, SIGNAL(clicked()), this, SLOT(scrollTo()));
+ connect(m_scrollx, SIGNAL(editingFinished()), this, SLOT(scrollTo()));
+ connect(m_scrolly, SIGNAL(editingFinished()), this, SLOT(scrollTo()));
+ connect(m_scrolltime, SIGNAL(editingFinished()), this, SLOT(scrollTo()));
+ grid->addWidget(new QLabel(QLatin1String("X:")), 0, 0);
+ grid->addWidget(m_scrollx, 0, 1);
+ grid->addWidget(new QLabel(QLatin1String("Y:")), 0, 2);
+ grid->addWidget(m_scrolly, 0, 3);
+ int row = smallscreen ? 1 : 0;
+ int col = smallscreen ? 0 : 4;
+ grid->addWidget(new QLabel(QLatin1String("in")), row, col++);
+ grid->addWidget(m_scrolltime, row, col++);
+ if (smallscreen) {
+ grid->addWidget(go, row, col + 1);
+ } else {
+ grid->addWidget(go, row, col);
+ grid->setColumnStretch(5, 1);
+ grid->setColumnStretch(6, 1);
+ }
+ grid->setColumnStretch(1, 1);
+ grid->setColumnStretch(3, 1);
+ grp->setLayout(grid);
+ layout->addWidget(grp);
+
+ QLayout *snapbox = new QHBoxLayout();
+
+ // GROUP: SNAP POINTS X
+
+ grp = new QGroupBox(QLatin1String("Snap Positions X"));
+ QBoxLayout *vbox = new QVBoxLayout();
+ vbox->setSpacing(m_smallscreen ? 4 : 2);
+ m_snapx = new QComboBox();
+ m_snapx->addItem(QLatin1String("No Snapping"), NoSnap);
+ m_snapx->addItem(QLatin1String("Snap to Interval"), SnapToInterval);
+ m_snapx->addItem(QLatin1String("Snap to List"), SnapToList);
+ connect(m_snapx, SIGNAL(currentIndexChanged(int)), this, SLOT(snapModeChanged(int)));
+ vbox->addWidget(m_snapx);
+
+ m_snapxinterval = new QWidget();
+ grid = new QGridLayout();
+ grid->setVerticalSpacing(m_smallscreen ? 4 : 2);
+ m_snapxfirst = new QSpinBox();
+ connect(m_snapxfirst, SIGNAL(valueChanged(int)), this, SLOT(snapPositionsChanged()));
+ grid->addWidget(new QLabel("First:"), 0, 0);
+ grid->addWidget(m_snapxfirst, 0, 1);
+ m_snapxstep = new QSpinBox();
+ connect(m_snapxstep, SIGNAL(valueChanged(int)), this, SLOT(snapPositionsChanged()));
+ grid->addWidget(new QLabel("Interval:"), 0, 2);
+ grid->addWidget(m_snapxstep, 0, 3);
+ m_snapxinterval->setLayout(grid);
+ vbox->addWidget(m_snapxinterval);
+ m_snapxinterval->hide();
+
+ m_snapxlist = new QPlainTextEdit();
+ m_snapxlist->setToolTip(QLatin1String("One snap position per line. Empty lines are ignored."));
+ m_snapxlist->installEventFilter(this);
+ connect(m_snapxlist, SIGNAL(textChanged()), this, SLOT(snapPositionsChanged()));
+ vbox->addWidget(m_snapxlist);
+ m_snapxlist->hide();
+
+ vbox->addStretch(100);
+ grp->setLayout(vbox);
+ snapbox->addWidget(grp);
+
+ // GROUP: SNAP POINTS Y
+
+ grp = new QGroupBox(QLatin1String("Snap Positions Y"));
+ vbox = new QVBoxLayout();
+ vbox->setSpacing(m_smallscreen ? 4 : 2);
+ m_snapy = new QComboBox();
+ m_snapy->addItem(QLatin1String("No Snapping"), NoSnap);
+ m_snapy->addItem(QLatin1String("Snap to Interval"), SnapToInterval);
+ m_snapy->addItem(QLatin1String("Snap to List"), SnapToList);
+ connect(m_snapy, SIGNAL(currentIndexChanged(int)), this, SLOT(snapModeChanged(int)));
+ vbox->addWidget(m_snapy);
+
+ m_snapyinterval = new QWidget();
+ grid = new QGridLayout();
+ grid->setVerticalSpacing(m_smallscreen ? 4 : 2);
+ m_snapyfirst = new QSpinBox();
+ connect(m_snapyfirst, SIGNAL(valueChanged(int)), this, SLOT(snapPositionsChanged()));
+ grid->addWidget(new QLabel("First:"), 0, 0);
+ grid->addWidget(m_snapyfirst, 0, 1);
+ m_snapystep = new QSpinBox();
+ connect(m_snapystep, SIGNAL(valueChanged(int)), this, SLOT(snapPositionsChanged()));
+ grid->addWidget(new QLabel("Interval:"), 0, 2);
+ grid->addWidget(m_snapystep, 0, 3);
+ m_snapyinterval->setLayout(grid);
+ vbox->addWidget(m_snapyinterval);
+ m_snapyinterval->hide();
+
+ m_snapylist = new QPlainTextEdit();
+ m_snapylist->setToolTip(QLatin1String("One snap position per line. Empty lines are ignored."));
+ m_snapylist->installEventFilter(this);
+ connect(m_snapylist, SIGNAL(textChanged()), this, SLOT(snapPositionsChanged()));
+ vbox->addWidget(m_snapylist);
+ m_snapylist->hide();
+
+ vbox->addStretch(100);
+ grp->setLayout(vbox);
+ snapbox->addWidget(grp);
+
+ layout->addLayout(snapbox);
+
+ layout->addStretch(100);
+ setWidget(view);
+ setWidgetResizable(true);
+}
+
+void SettingsWidget::setScroller(QWidget *widget)
+{
+ delete m_snapoverlay;
+ if (m_widget)
+ m_widget->removeEventFilter(this);
+ QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(widget);
+ if (area)
+ widget = area->viewport();
+ m_widget = widget;
+ m_widget->installEventFilter(this);
+ m_snapoverlay = new SnapOverlay(area);
+ QScrollerProperties properties = QScroller::scroller(widget)->scrollerProperties();
+
+ QMutableListIterator<MetricItemUpdater *> it(m_metrics);
+ while (it.hasNext())
+ it.next()->setScroller(widget);
+
+ if (!widget)
+ return;
+
+ updateScrollRanges();
+}
+
+bool SettingsWidget::eventFilter(QObject *o, QEvent *e)
+{
+ if (o == m_widget && e->type() == QEvent::Resize)
+ updateScrollRanges();
+ return false;
+}
+
+void SettingsWidget::updateScrollRanges()
+{
+ QScrollPrepareEvent spe(QPoint(0, 0));
+ QApplication::sendEvent(m_widget, &spe);
+
+ QSizeF vp = spe.viewportSize();
+ QRectF maxc = spe.contentPosRange();
+
+ m_scrollx->setRange(qRound(-vp.width()), qRound(maxc.width() + vp.width()));
+ m_scrolly->setRange(qRound(-vp.height()), qRound(maxc.height() + vp.height()));
+
+ m_snapxfirst->setRange(maxc.left(), maxc.right());
+ m_snapxstep->setRange(0, maxc.width());
+ m_snapyfirst->setRange(maxc.top(), maxc.bottom());
+ m_snapystep->setRange(0, maxc.height());
+}
+
+void SettingsWidget::scrollTo()
+{
+ if (QApplication::activePopupWidget())
+ return;
+ if ((sender() == m_scrollx) && !m_scrollx->hasFocus())
+ return;
+ if ((sender() == m_scrolly) && !m_scrolly->hasFocus())
+ return;
+ if ((sender() == m_scrolltime) && !m_scrolltime->hasFocus())
+ return;
+
+ if (QScroller *scroller = QScroller::scroller(m_widget))
+ scroller->scrollTo(QPointF(m_scrollx->value(), m_scrolly->value()), m_scrolltime->value());
+}
+
+void SettingsWidget::snapModeChanged(int mode)
+{
+ if (sender() == m_snapx) {
+ m_snapxmode = static_cast<SnapMode>(mode);
+ m_snapxinterval->setVisible(mode == SnapToInterval);
+ m_snapxlist->setVisible(mode == SnapToList);
+ snapPositionsChanged();
+ } else if (sender() == m_snapy) {
+ m_snapymode = static_cast<SnapMode>(mode);
+ m_snapyinterval->setVisible(mode == SnapToInterval);
+ m_snapylist->setVisible(mode == SnapToList);
+ snapPositionsChanged();
+ }
+}
+
+void SettingsWidget::snapPositionsChanged()
+{
+ QScroller *s = QScroller::scroller(m_widget);
+ if (!s)
+ return;
+
+ switch (m_snapxmode) {
+ case NoSnap:
+ s->setSnapPositionsX(QList<qreal>());
+ m_snapoverlay->clear(Qt::Horizontal);
+ break;
+ case SnapToInterval:
+ s->setSnapPositionsX(m_snapxfirst->value(), m_snapxstep->value());
+ m_snapoverlay->set(Qt::Horizontal, m_snapxfirst->value(), m_snapxstep->value());
+ break;
+ case SnapToList:
+ s->setSnapPositionsX(toPositionList(m_snapxlist, m_snapxfirst->minimum(), m_snapxfirst->maximum()));
+ m_snapoverlay->set(Qt::Horizontal, toPositionList(m_snapxlist, m_snapxfirst->minimum(), m_snapxfirst->maximum()));
+ break;
+ }
+ switch (m_snapymode) {
+ case NoSnap:
+ s->setSnapPositionsY(QList<qreal>());
+ m_snapoverlay->clear(Qt::Vertical);
+ break;
+ case SnapToInterval:
+ s->setSnapPositionsY(m_snapyfirst->value(), m_snapystep->value());
+ m_snapoverlay->set(Qt::Vertical, m_snapyfirst->value(), m_snapystep->value());
+ break;
+ case SnapToList:
+ s->setSnapPositionsY(toPositionList(m_snapylist, m_snapyfirst->minimum(), m_snapyfirst->maximum()));
+ m_snapoverlay->set(Qt::Vertical, toPositionList(m_snapylist, m_snapyfirst->minimum(), m_snapyfirst->maximum()));
+ break;
+ }
+}
+
+QList<qreal> SettingsWidget::toPositionList(QPlainTextEdit *list, int vmin, int vmax)
+{
+ QList<qreal> snaps;
+ QList<QTextEdit::ExtraSelection> extrasel;
+ QTextEdit::ExtraSelection uline;
+ uline.format.setUnderlineColor(Qt::red);
+ uline.format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+ int line = 0;
+
+ foreach (const QString &str, list->toPlainText().split(QLatin1Char('\n'))) {
+ ++line;
+ if (str.isEmpty())
+ continue;
+ bool ok = false;
+ double d = str.toDouble(&ok);
+ if (ok && d >= vmin && d <= vmax) {
+ snaps << d;
+ } else {
+ QTextEdit::ExtraSelection esel = uline;
+ esel.cursor = QTextCursor(list->document()->findBlockByLineNumber(line - 1));
+ esel.cursor.select(QTextCursor::LineUnderCursor);
+ extrasel << esel;
+ }
+ }
+ list->setExtraSelections(extrasel);
+ return snaps;
+}
+
+#include "settingswidget.moc"
diff --git a/examples/scroller/plot/settingswidget.h b/examples/scroller/plot/settingswidget.h
new file mode 100644
index 0000000..2fb268c
--- /dev/null
+++ b/examples/scroller/plot/settingswidget.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** 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 QtGui module 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$
+**
+****************************************************************************/
+
+#ifndef SETTINGSWIDGET_H
+#define SETTINGSWIDGET_H
+
+#include <QScrollArea>
+
+class QScroller;
+class QGridLayout;
+class QSpinBox;
+class QComboBox;
+class QCheckBox;
+class QPlainTextEdit;
+
+class MetricItemUpdater;
+class SnapOverlay;
+
+class SettingsWidget : public QScrollArea
+{
+ Q_OBJECT
+
+public:
+ SettingsWidget(bool smallscreen = false);
+
+ void setScroller(QWidget *widget);
+
+protected:
+ bool eventFilter(QObject *, QEvent *);
+
+private slots:
+ void scrollTo();
+ void snapModeChanged(int);
+ void snapPositionsChanged();
+
+private:
+ enum SnapMode {
+ NoSnap,
+ SnapToInterval,
+ SnapToList
+ };
+
+ void addToGrid(QGridLayout *grid, QWidget *label, int widgetCount, ...);
+ QList<qreal> toPositionList(QPlainTextEdit *list, int vmin, int vmax);
+ void updateScrollRanges();
+
+ QWidget *m_widget;
+ QSpinBox *m_scrollx, *m_scrolly, *m_scrolltime;
+ QList<MetricItemUpdater *> m_metrics;
+
+ SnapMode m_snapxmode;
+ QComboBox *m_snapx;
+ QWidget *m_snapxinterval;
+ QPlainTextEdit *m_snapxlist;
+ QSpinBox *m_snapxfirst;
+ QSpinBox *m_snapxstep;
+
+ SnapMode m_snapymode;
+ QComboBox *m_snapy;
+ QWidget *m_snapyinterval;
+ QPlainTextEdit *m_snapylist;
+ QSpinBox *m_snapyfirst;
+ QSpinBox *m_snapystep;
+ SnapOverlay *m_snapoverlay;
+
+ bool m_smallscreen;
+};
+
+#endif
diff --git a/examples/scroller/scroller.pro b/examples/scroller/scroller.pro
new file mode 100644
index 0000000..e830745
--- /dev/null
+++ b/examples/scroller/scroller.pro
@@ -0,0 +1,11 @@
+TEMPLATE = subdirs
+SUBDIRS = graphicsview \
+ plot \
+ wheel
+
+# install
+sources.files = *.pro
+sources.path = $$[QT_INSTALL_EXAMPLES]/scroller
+INSTALLS += sources
+
+symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
diff --git a/examples/scroller/wheel/main.cpp b/examples/scroller/wheel/main.cpp
new file mode 100644
index 0000000..4264377
--- /dev/null
+++ b/examples/scroller/wheel/main.cpp
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** 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 QtGui module 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 <QtGui>
+#include <qmath.h>
+
+#include "wheelwidget.h"
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ MainWindow(bool touch)
+ : QMainWindow()
+ {
+ makeSlotMachine(touch);
+ setCentralWidget(m_slotMachine);
+ }
+
+ void makeSlotMachine(bool touch)
+ {
+ if (QApplication::desktop()->width() > 1000) {
+ QFont f = font();
+ f.setPointSize(f.pointSize() * 2);
+ setFont(f);
+ }
+
+ m_slotMachine = new QWidget(this);
+ QGridLayout *grid = new QGridLayout(m_slotMachine);
+ grid->setSpacing(20);
+
+ QStringList colors;
+ colors << "Red" << "Magenta" << "Peach" << "Orange" << "Yellow" << "Citro" << "Green" << "Cyan" << "Blue" << "Violet";
+
+ m_wheel1 = new StringWheelWidget(touch);
+ m_wheel1->setItems( colors );
+ grid->addWidget( m_wheel1, 0, 0 );
+
+ m_wheel2 = new StringWheelWidget(touch);
+ m_wheel2->setItems( colors );
+ grid->addWidget( m_wheel2, 0, 1 );
+
+ m_wheel3 = new StringWheelWidget(touch);
+ m_wheel3->setItems( colors );
+ grid->addWidget( m_wheel3, 0, 2 );
+
+ QPushButton *shakeButton = new QPushButton(tr("Shake"));
+ connect(shakeButton, SIGNAL(clicked()), this, SLOT(rotateRandom()));
+
+ grid->addWidget( shakeButton, 1, 0, 1, 3 );
+ }
+
+private slots:
+ void rotateRandom()
+ {
+ m_wheel1->scrollTo(m_wheel1->currentIndex() + (qrand() % 200));
+ m_wheel2->scrollTo(m_wheel2->currentIndex() + (qrand() % 200));
+ m_wheel3->scrollTo(m_wheel3->currentIndex() + (qrand() % 200));
+ }
+
+private:
+ QWidget *m_slotMachine;
+
+ StringWheelWidget *m_wheel1;
+ StringWheelWidget *m_wheel2;
+ StringWheelWidget *m_wheel3;
+};
+
+int main(int argc, char **argv)
+{
+ QApplication a(argc, argv);
+
+ bool touch = a.arguments().contains(QLatin1String("--touch"));
+
+ MainWindow *mw = new MainWindow(touch);
+ mw->show();
+
+ return a.exec();
+}
+
+#include "main.moc"
diff --git a/examples/scroller/wheel/wheel.pro b/examples/scroller/wheel/wheel.pro
new file mode 100644
index 0000000..1f9b789
--- /dev/null
+++ b/examples/scroller/wheel/wheel.pro
@@ -0,0 +1,16 @@
+HEADERS = wheelwidget.h
+SOURCES = wheelwidget.cpp \
+ main.cpp
+
+QT += webkit
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/scroller/wheel
+sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS wheel.pro
+sources.path = $$[QT_INSTALL_EXAMPLES]/scroller/wheel
+INSTALLS += target sources
+
+symbian {
+ TARGET.UID3 = 0xA000CF66
+ include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
+}
diff --git a/examples/scroller/wheel/wheelwidget.cpp b/examples/scroller/wheel/wheelwidget.cpp
new file mode 100644
index 0000000..64a459b
--- /dev/null
+++ b/examples/scroller/wheel/wheelwidget.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** 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 QtGui module 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 <QtGui>
+
+#include "wheelwidget.h"
+
+#define WHEEL_SCROLL_OFFSET 50000.0
+
+AbstractWheelWidget::AbstractWheelWidget(bool touch, QWidget *parent)
+ : QWidget(parent)
+ , m_currentItem(0)
+ , m_itemOffset(0)
+{
+// ![0]
+ QScroller::grabGesture(this, touch ? QScroller::TouchGesture : QScroller::LeftMouseButtonGesture);
+// ![0]
+}
+
+AbstractWheelWidget::~AbstractWheelWidget()
+{ }
+
+int AbstractWheelWidget::currentIndex() const
+{
+ return m_currentItem;
+}
+
+void AbstractWheelWidget::setCurrentIndex(int index)
+{
+ if (index >= 0 && index < itemCount()) {
+ m_currentItem = index;
+ m_itemOffset = 0;
+ update();
+ }
+}
+
+bool AbstractWheelWidget::event(QEvent *e)
+{
+ switch (e->type()) {
+// ![1]
+ case QEvent::ScrollPrepare:
+ {
+ // We set the snap positions as late as possible so that we are sure
+ // we get the correct itemHeight
+ QScroller *scroller = QScroller::scroller(this);
+ scroller->setSnapPositionsY( WHEEL_SCROLL_OFFSET, itemHeight() );
+
+ QScrollPrepareEvent *se = static_cast<QScrollPrepareEvent *>(e);
+ se->setViewportSize(QSizeF(size()));
+ // we claim a huge scrolling area and a huge content position and
+ // hope that the user doesn't notice that the scroll area is restricted
+ se->setContentPosRange(QRectF(0.0, 0.0, 0.0, WHEEL_SCROLL_OFFSET * 2));
+ se->setContentPos(QPointF(0.0, WHEEL_SCROLL_OFFSET + m_currentItem * itemHeight() + m_itemOffset));
+ se->accept();
+ return true;
+ }
+// ![1]
+// ![2]
+ case QEvent::Scroll:
+ {
+ QScrollEvent *se = static_cast<QScrollEvent *>(e);
+
+ qreal y = se->contentPos().y();
+ int iy = y - WHEEL_SCROLL_OFFSET;
+ int ih = itemHeight();
+
+// ![2]
+
+ // -- calculate the current item position and offset and redraw the widget
+ int ic = itemCount();
+ if (ic>0) {
+ m_currentItem = iy / ih % ic;
+ m_itemOffset = iy % ih;
+
+ // take care when scrolling backwards. Modulo returns negative numbers
+ if (m_itemOffset < 0) {
+ m_itemOffset += ih;
+ m_currentItem--;
+ }
+
+ if (m_currentItem < 0)
+ m_currentItem += ic;
+ }
+ // -- repaint
+ update();
+
+ se->accept();
+ return true;
+ }
+ default:
+ return QWidget::event(e);
+ }
+ return true;
+}
+
+void AbstractWheelWidget::paintEvent(QPaintEvent* event)
+{
+ Q_UNUSED( event );
+
+ // -- first calculate size and position.
+ int w = width();
+ int h = height();
+
+ QPainter painter(this);
+ QPalette palette = QApplication::palette();
+ QPalette::ColorGroup colorGroup = isEnabled() ? QPalette::Active : QPalette::Disabled;
+
+ // linear gradient brush
+ QLinearGradient grad(0.5, 0, 0.5, 1.0);
+ grad.setColorAt(0, palette.color(colorGroup, QPalette::ButtonText));
+ grad.setColorAt(0.2, palette.color(colorGroup, QPalette::Button));
+ grad.setColorAt(0.8, palette.color(colorGroup, QPalette::Button));
+ grad.setColorAt(1.0, palette.color(colorGroup, QPalette::ButtonText));
+ grad.setCoordinateMode( QGradient::ObjectBoundingMode );
+ QBrush gBrush( grad );
+
+ // paint a border and background
+ painter.setPen(palette.color(colorGroup, QPalette::ButtonText));
+ painter.setBrush(gBrush);
+ // painter.setBrushOrigin( QPointF( 0.0, 0.0 ) );
+ painter.drawRect( 0, 0, w-1, h-1 );
+
+ // paint inner border
+ painter.setPen(palette.color(colorGroup, QPalette::Button));
+ painter.setBrush(Qt::NoBrush);
+ painter.drawRect( 1, 1, w-3, h-3 );
+
+ // paint the items
+ painter.setClipRect( QRect( 3, 3, w-6, h-6 ) );
+ painter.setPen(palette.color(colorGroup, QPalette::ButtonText));
+
+ int iH = itemHeight();
+ int iC = itemCount();
+ if (iC > 0) {
+
+ m_itemOffset = m_itemOffset % iH;
+
+ for (int i=-h/2/iH; i<=h/2/iH+1; i++) {
+
+ int itemNum = m_currentItem + i;
+ while (itemNum < 0)
+ itemNum += iC;
+ while (itemNum >= iC)
+ itemNum -= iC;
+
+ paintItem(&painter, itemNum, QRect(6, h/2 +i*iH - m_itemOffset - iH/2, w-6, iH ));
+ }
+ }
+
+ // draw a transparent bar over the center
+ QColor highlight = palette.color(colorGroup, QPalette::Highlight);
+ highlight.setAlpha(150);
+
+ QLinearGradient grad2(0.5, 0, 0.5, 1.0);
+ grad2.setColorAt(0, highlight);
+ grad2.setColorAt(1.0, highlight.lighter());
+ grad2.setCoordinateMode( QGradient::ObjectBoundingMode );
+ QBrush gBrush2( grad2 );
+
+ QLinearGradient grad3(0.5, 0, 0.5, 1.0);
+ grad3.setColorAt(0, highlight);
+ grad3.setColorAt(1.0, highlight.darker());
+ grad3.setCoordinateMode( QGradient::ObjectBoundingMode );
+ QBrush gBrush3( grad3 );
+
+ painter.fillRect( QRect( 0, h/2 - iH/2, w, iH/2 ), gBrush2 );
+ painter.fillRect( QRect( 0, h/2, w, iH/2 ), gBrush3 );
+}
+
+/*!
+ Rotates the wheel widget to a given index.
+ You can also give an index greater than itemCount or less than zero in which
+ case the wheel widget will scroll in the given direction and end up with
+ (index % itemCount)
+*/
+void AbstractWheelWidget::scrollTo(int index)
+{
+ QScroller *scroller = QScroller::scroller(this);
+
+ scroller->scrollTo(QPointF(0, WHEEL_SCROLL_OFFSET + index * itemHeight()), 5000);
+}
+
+/*!
+ \class StringWheelWidget
+ \brief The StringWheelWidget class is an implementation of the AbstractWheelWidget class that draws QStrings as items.
+ \sa AbstractWheelWidget
+*/
+
+StringWheelWidget::StringWheelWidget(bool touch)
+ : AbstractWheelWidget(touch)
+{ }
+
+QStringList StringWheelWidget::items() const
+{
+ return m_items;
+}
+
+void StringWheelWidget::setItems( const QStringList &items )
+{
+ m_items = items;
+ if (m_currentItem >= items.count())
+ m_currentItem = items.count()-1;
+ update();
+}
+
+
+QSize StringWheelWidget::sizeHint() const
+{
+ // determine font size
+ QFontMetrics fm(font());
+
+ return QSize( fm.width("m") * 10 + 6, fm.height() * 7 + 6 );
+}
+
+QSize StringWheelWidget::minimumSizeHint() const
+{
+ QFontMetrics fm(font());
+
+ return QSize( fm.width("m") * 5 + 6, fm.height() * 3 + 6 );
+}
+
+void StringWheelWidget::paintItem(QPainter* painter, int index, const QRect &rect)
+{
+ painter->drawText(rect, Qt::AlignCenter, m_items.at(index));
+}
+
+int StringWheelWidget::itemHeight() const
+{
+ QFontMetrics fm(font());
+ return fm.height();
+}
+
+int StringWheelWidget::itemCount() const
+{
+ return m_items.count();
+}
+
+
diff --git a/examples/scroller/wheel/wheelwidget.h b/examples/scroller/wheel/wheelwidget.h
new file mode 100644
index 0000000..818b6ab
--- /dev/null
+++ b/examples/scroller/wheel/wheelwidget.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** 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 QtGui module 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$
+**
+****************************************************************************/
+
+#ifndef WHEELWIDGET_H
+#define WHEELWIDGET_H
+
+#include <QWidget>
+#include <QStringList>
+
+class QPainter;
+class QRect;
+
+class AbstractWheelWidget : public QWidget {
+ Q_OBJECT
+
+public:
+ AbstractWheelWidget(bool touch, QWidget *parent = 0);
+ virtual ~AbstractWheelWidget();
+
+ int currentIndex() const;
+ void setCurrentIndex(int index);
+
+ bool event(QEvent*);
+ void paintEvent(QPaintEvent *e);
+ virtual void paintItem(QPainter* painter, int index, const QRect &rect) = 0;
+
+ virtual int itemHeight() const = 0;
+ virtual int itemCount() const = 0;
+
+public slots:
+ void scrollTo(int index);
+
+signals:
+ void stopped(int index);
+
+protected:
+ int m_currentItem;
+ int m_itemOffset; // 0-itemHeight()
+ qreal m_lastY;
+};
+
+
+class StringWheelWidget : public AbstractWheelWidget {
+ Q_OBJECT
+
+public:
+ StringWheelWidget(bool touch);
+
+ QStringList items() const;
+ void setItems( const QStringList &items );
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ void paintItem(QPainter* painter, int index, const QRect &rect);
+
+ int itemHeight() const;
+ int itemCount() const;
+
+private:
+ QStringList m_items;
+};
+
+#endif // WHEELWIDGET_H