/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** 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, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "mousepangesturerecognizer.h" class ScrollArea : public QScrollArea { Q_OBJECT public: ScrollArea(QWidget *parent = 0) : QScrollArea(parent), outside(false) { viewport()->grabGesture(Qt::PanGesture, Qt::ReceivePartialGestures); } protected: bool viewportEvent(QEvent *event) { if (event->type() == QEvent::Gesture) { gestureEvent(static_cast(event)); return true; } else if (event->type() == QEvent::GestureOverride) { QGestureEvent *ge = static_cast(event); if (QPanGesture *pan = static_cast(ge->gesture(Qt::PanGesture))) if (pan->state() == Qt::GestureStarted) { outside = false; } } return QScrollArea::viewportEvent(event); } void gestureEvent(QGestureEvent *event) { QPanGesture *pan = static_cast(event->gesture(Qt::PanGesture)); if (pan) { switch(pan->state()) { case Qt::GestureStarted: qDebug() << this << "Pan: started"; break; case Qt::GestureFinished: qDebug() << this << "Pan: finished"; break; case Qt::GestureCanceled: qDebug() << this << "Pan: canceled"; break; case Qt::GestureUpdated: break; default: qDebug() << this << "Pan: "; break; } if (pan->state() == Qt::GestureStarted) outside = false; event->ignore(); event->ignore(pan); if (outside) return; const QPointF delta = pan->delta(); const QPointF totalOffset = pan->offset(); QScrollBar *vbar = verticalScrollBar(); QScrollBar *hbar = horizontalScrollBar(); if ((vbar->value() == vbar->minimum() && totalOffset.y() > 10) || (vbar->value() == vbar->maximum() && totalOffset.y() < -10)) { outside = true; return; } if ((hbar->value() == hbar->minimum() && totalOffset.x() > 10) || (hbar->value() == hbar->maximum() && totalOffset.x() < -10)) { outside = true; return; } vbar->setValue(vbar->value() - delta.y()); hbar->setValue(hbar->value() - delta.x()); event->accept(pan); } } private: bool outside; }; class Slider : public QSlider { public: Slider(Qt::Orientation orientation, QWidget *parent = 0) : QSlider(orientation, parent) { grabGesture(Qt::PanGesture); } protected: bool event(QEvent *event) { if (event->type() == QEvent::Gesture) { gestureEvent(static_cast(event)); return true; } return QSlider::event(event); } void gestureEvent(QGestureEvent *event) { QPanGesture *pan = static_cast(event->gesture(Qt::PanGesture)); if (pan) { switch (pan->state()) { case Qt::GestureStarted: qDebug() << this << "Pan: started"; break; case Qt::GestureFinished: qDebug() << this << "Pan: finished"; break; case Qt::GestureCanceled: qDebug() << this << "Pan: canceled"; break; case Qt::GestureUpdated: break; default: qDebug() << this << "Pan: "; break; } if (pan->state() == Qt::GestureStarted) outside = false; event->ignore(); event->ignore(pan); if (outside) return; const QPointF delta = pan->delta(); const QPointF totalOffset = pan->offset(); if (orientation() == Qt::Horizontal) { if ((value() == minimum() && totalOffset.x() < -10) || (value() == maximum() && totalOffset.x() > 10)) { outside = true; return; } if (totalOffset.y() < 40 && totalOffset.y() > -40) { setValue(value() + delta.x()); event->accept(pan); } else { outside = true; } } else if (orientation() == Qt::Vertical) { if ((value() == maximum() && totalOffset.y() < -10) || (value() == minimum() && totalOffset.y() > 10)) { outside = true; return; } if (totalOffset.x() < 40 && totalOffset.x() > -40) { setValue(value() - delta.y()); event->accept(pan); } else { outside = true; } } } } private: bool outside; }; class MainWindow : public QMainWindow { public: MainWindow() { rootScrollArea = new ScrollArea; rootScrollArea->setObjectName(QLatin1String("rootScrollArea")); setCentralWidget(rootScrollArea); QWidget *root = new QWidget; root->setFixedSize(3000, 3000); rootScrollArea->setWidget(root); Slider *verticalSlider = new Slider(Qt::Vertical, root); verticalSlider->setObjectName(QLatin1String("verticalSlider")); verticalSlider ->move(650, 1100); Slider *horizontalSlider = new Slider(Qt::Horizontal, root); horizontalSlider->setObjectName(QLatin1String("horizontalSlider")); horizontalSlider ->move(600, 1000); childScrollArea = new ScrollArea(root); childScrollArea->setObjectName(QLatin1String("childScrollArea")); childScrollArea->move(500, 500); QWidget *w = new QWidget; w->setMinimumWidth(700); QVBoxLayout *l = new QVBoxLayout(w); l->setMargin(20); for (int i = 0; i < 100; ++i) { QWidget *w = new QWidget; QHBoxLayout *ll = new QHBoxLayout(w); ll->addWidget(new QLabel(QString("Label %1").arg(i))); ll->addWidget(new QPushButton(QString("Button %1").arg(i))); l->addWidget(w); } childScrollArea->setWidget(w); #if defined(Q_OS_WIN) // Windows can force Qt to create a native window handle for an // intermediate widget and that will block gesture to get touch events. // So this hack to make sure gestures get all touch events they need. foreach (QObject *w, children()) if (w->isWidgetType()) static_cast(w)->setAttribute(Qt::WA_AcceptTouchEvents); #endif } private: ScrollArea *rootScrollArea; ScrollArea *childScrollArea; }; int main(int argc, char **argv) { QApplication app(argc, argv); QGestureRecognizer::registerRecognizer(new MousePanGestureRecognizer); MainWindow w; w.show(); return app.exec(); } #include "main.moc"