diff options
Diffstat (limited to 'examples/scroller/plot')
-rw-r--r-- | examples/scroller/plot/main.cpp | 223 | ||||
-rw-r--r-- | examples/scroller/plot/plot.pro | 18 | ||||
-rw-r--r-- | examples/scroller/plot/plotwidget.cpp | 205 | ||||
-rw-r--r-- | examples/scroller/plot/plotwidget.h | 88 | ||||
-rw-r--r-- | examples/scroller/plot/settingswidget.cpp | 690 | ||||
-rw-r--r-- | examples/scroller/plot/settingswidget.h | 107 |
6 files changed, 1331 insertions, 0 deletions
diff --git a/examples/scroller/plot/main.cpp b/examples/scroller/plot/main.cpp new file mode 100644 index 0000000..acf83ee --- /dev/null +++ b/examples/scroller/plot/main.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** 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 <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 |