diff options
Diffstat (limited to 'examples/gestures')
-rw-r--r-- | examples/gestures/gestures.pro | 11 | ||||
-rw-r--r-- | examples/gestures/graphicsview/graphicsview.pro | 2 | ||||
-rw-r--r-- | examples/gestures/graphicsview/main.cpp | 151 | ||||
-rw-r--r-- | examples/gestures/imageviewer/imageviewer.pro | 12 | ||||
-rw-r--r-- | examples/gestures/imageviewer/imagewidget.cpp | 338 | ||||
-rw-r--r-- | examples/gestures/imageviewer/imagewidget.h | 122 | ||||
-rw-r--r-- | examples/gestures/imageviewer/main.cpp | 88 |
7 files changed, 724 insertions, 0 deletions
diff --git a/examples/gestures/gestures.pro b/examples/gestures/gestures.pro new file mode 100644 index 0000000..1e0f1a7 --- /dev/null +++ b/examples/gestures/gestures.pro @@ -0,0 +1,11 @@ +TEMPLATE = \ + subdirs +SUBDIRS = \ + imageviewer \ + graphicsview + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/gestures +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS gestures.pro README +sources.path = $$[QT_INSTALL_EXAMPLES]/gestures +INSTALLS += target sources diff --git a/examples/gestures/graphicsview/graphicsview.pro b/examples/gestures/graphicsview/graphicsview.pro new file mode 100644 index 0000000..9cef564 --- /dev/null +++ b/examples/gestures/graphicsview/graphicsview.pro @@ -0,0 +1,2 @@ +SOURCES = main.cpp + diff --git a/examples/gestures/graphicsview/main.cpp b/examples/gestures/graphicsview/main.cpp new file mode 100644 index 0000000..a0236ef --- /dev/null +++ b/examples/gestures/graphicsview/main.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui> + +class PannableGraphicsView : public QGraphicsView +{ +public: + PannableGraphicsView() + { + grabGesture(Qt::Pan); + } +protected: + bool event(QEvent *event) + { + if (event->type() == QEvent::Gesture) { + QGestureEvent *ge = static_cast<QGestureEvent*>(event); + if (const QGesture *g = ge->gesture(Qt::Pan)) { + QPoint pt = g->pos() - g->lastPos(); + horizontalScrollBar()->setValue(horizontalScrollBar()->value() - pt.x()); + verticalScrollBar()->setValue(verticalScrollBar()->value() - pt.y()); + event->accept(); + return true; + } + } + return QGraphicsView::event(event); + } +}; + +class ImageItem : public QGraphicsItem +{ +public: + ImageItem() + : colored(false) + { + grabGesture(Qt::DoubleTap); + } + + QRectF boundingRect() const + { + return pixmap.isNull() ? QRectF(0, 0, 100, 100) + : QRectF(QPointF(0,0), QSizeF(pixmap.size())); + } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) + { + if (pixmap.isNull()) { + painter->setBrush(QBrush( colored ? Qt::green : Qt::white)); + painter->drawRect(0, 0, 100, 100); + painter->drawLine(0, 0, 100, 100); + painter->drawLine(0, 100, 100, 0); + return; + } + painter->drawPixmap(0, 0, pixmap); + } + + bool sceneEvent(QEvent *event) + { + if (event->type() == QEvent::Gesture) { + QGestureEvent *gestureEvent = static_cast<QGestureEvent*>(event); + if (gestureEvent->gesture(Qt::DoubleTap)) { + event->accept(); + colored = !colored; + update(); + return true; + } else { + qWarning("Item received unknown gesture"); + } + } + return QGraphicsItem::sceneEvent(event); + } + +private: + QPixmap pixmap; + bool colored; +}; + +class MainWidget : public QWidget +{ + Q_OBJECT + +public: + MainWidget(QWidget *parent = 0) + : QWidget(parent) + { + QVBoxLayout *l = new QVBoxLayout(this); + view = new PannableGraphicsView; + l->addWidget(view); + scene = new QGraphicsScene(0, 0, 1024, 768, view); + view->setScene(scene); + + ImageItem *item = new ImageItem; + scene->addItem(item); + item->setPos(scene->width()/3, scene->height()/3); + } + +signals: +public slots: +private: + QGraphicsView *view; + QGraphicsScene *scene; +}; + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QApplication::setAttribute(Qt::AA_EnableGestures); + MainWidget w; + w.show(); + return app.exec(); +} + +#include "main.moc" diff --git a/examples/gestures/imageviewer/imageviewer.pro b/examples/gestures/imageviewer/imageviewer.pro new file mode 100644 index 0000000..4c35dce --- /dev/null +++ b/examples/gestures/imageviewer/imageviewer.pro @@ -0,0 +1,12 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Thu Sep 11 17:18:17 2008 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +# Input +HEADERS += imagewidget.h +SOURCES += imagewidget.cpp main.cpp diff --git a/examples/gestures/imageviewer/imagewidget.cpp b/examples/gestures/imageviewer/imagewidget.cpp new file mode 100644 index 0000000..8932e29 --- /dev/null +++ b/examples/gestures/imageviewer/imagewidget.cpp @@ -0,0 +1,338 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "imagewidget.h" + +#include <QtGui> + +ImageWidget::ImageWidget(QWidget *parent) + : QWidget(parent) +{ + setAttribute(Qt::WA_PaintOnScreen); + setAttribute(Qt::WA_OpaquePaintEvent); + setAttribute(Qt::WA_NoSystemBackground); + + setObjectName("ImageWidget"); + + setMinimumSize(QSize(100,100)); + + position = 0; + zoomed = rotated = false; + + zoomedIn = false; + horizontalOffset = 0; + verticalOffset = 0; + + grabGesture(Qt::DoubleTap); + grabGesture(Qt::Pan); + grabGesture(Qt::LongTap); +} + +void ImageWidget::paintEvent(QPaintEvent*) +{ + QPainter p(this); + if (currentImage.isNull()) { + p.fillRect(geometry(), Qt::white); + return; + } + int hoffset = 0; + int voffset = 0; + const int w = pixmap.width(); + const int h = pixmap.height(); + p.save(); + if (zoomedIn) { + hoffset = horizontalOffset; + voffset = verticalOffset; + if (horizontalOffset > 0) + p.fillRect(0, 0, horizontalOffset, height(), Qt::white); + if (verticalOffset > 0) + p.fillRect(0, 0, width(), verticalOffset, Qt::white); + } + p.drawPixmap(hoffset, voffset, pixmap); + if (hoffset + w < width()) + p.fillRect(hoffset + w, 0, width() - w - hoffset, height(), Qt::white); + if (voffset + h < height()) + p.fillRect(0, voffset + h, width(), height() - h - voffset, Qt::white); + + // paint touch feedback + if (touchFeedback.tapped || touchFeedback.doubleTapped) { + p.setPen(QPen(Qt::gray, 2)); + p.drawEllipse(touchFeedback.position, 5, 5); + if (touchFeedback.doubleTapped) { + p.setPen(QPen(Qt::gray, 2, Qt::DotLine)); + p.drawEllipse(touchFeedback.position, 15, 15); + } else if (touchFeedback.tapAndHoldState != 0) { + QPoint pts[8] = { + touchFeedback.position + QPoint( 0, -15), + touchFeedback.position + QPoint( 10, -10), + touchFeedback.position + QPoint( 15, 0), + touchFeedback.position + QPoint( 10, 10), + touchFeedback.position + QPoint( 0, 15), + touchFeedback.position + QPoint(-10, 10), + touchFeedback.position + QPoint(-15, 0) + }; + for (int i = 0; i < (touchFeedback.tapAndHoldState-20)/10; ++i) + p.drawEllipse(pts[i], 3, 3); + } + } else if (touchFeedback.sliding) { + p.setPen(QPen(Qt::red, 3)); + QPoint endPos = QPoint(touchFeedback.position.x(), touchFeedback.slidingStartPosition.y()); + p.drawLine(touchFeedback.slidingStartPosition, endPos); + int dx = 10; + if (touchFeedback.slidingStartPosition.x() < endPos.x()) + dx = -1*dx; + p.drawLine(endPos, endPos + QPoint(dx, 5)); + p.drawLine(endPos, endPos + QPoint(dx, -5)); + } + + for (int i = 0; i < TouchFeedback::MaximumNumberOfTouches; ++i) { + if (touchFeedback.touches[i].isNull()) + break; + p.drawEllipse(touchFeedback.touches[i], 10, 10); + } + p.restore(); +} + +void ImageWidget::gestureEvent(QGestureEvent *event) +{ + touchFeedback.doubleTapped = false; + + Q_ASSERT(event); + if (event->contains(Qt::Tap)) { + // + } else if (const QGesture *g = event->gesture(Qt::DoubleTap)) { + touchFeedback.doubleTapped = true; + horizontalOffset = g->hotSpot().x() - currentImage.width()*1.0*g->hotSpot().x()/width(); + verticalOffset = g->hotSpot().y() - currentImage.height()*1.0*g->hotSpot().y()/height(); + setZoomedIn(!zoomedIn); + zoomed = rotated = false; + updateImage(); + } else if (const QGesture *g = event->gesture(Qt::Pan)) { + if (zoomedIn) { + // usual panning + if (g->state() == Qt::GestureStarted) + setCursor(Qt::SizeAllCursor); + else + setCursor(Qt::ArrowCursor); + const int dx = g->pos().x() - g->lastPos().x(); + const int dy = g->pos().y() - g->lastPos().y(); + horizontalOffset += dx; + verticalOffset += dy; + update(); + } else { + // only slide gesture should be accepted + const QPannableGesture *pg = dynamic_cast<const QPannableGesture*>(g); + if (pg && pg->direction() != pg->lastDirection()) { + // ###: event->cancel(); + } + if (g->state() == Qt::GestureFinished) { + touchFeedback.sliding = false; + zoomed = rotated = false; + if (pg->direction() == QPannableGesture::Right) { + qDebug() << "slide right"; + goNextImage(); + } else if (pg->direction() == QPannableGesture::Left) { + qDebug() << "slide left"; + goPrevImage(); + } + updateImage(); + } + } + } else if (const QGesture *g = event->gesture(Qt::LongTap)) { + if (g->state() == Qt::GestureFinished) { + qDebug() << "tap and hold detected"; + touchFeedback.reset(); + update(); + + QMenu menu; + menu.addAction("Action 1"); + menu.addAction("Action 2"); + menu.addAction("Action 3"); + menu.exec(mapToGlobal(g->hotSpot())); + } + } else if (const QGesture *g = event->gesture(Qt::LongTap)) { + qDebug() << "long tap: " << (g->state() == Qt::GestureStarted ? "started" : "finished"); + } else { + qDebug() << "unknown gesture"; + } + feedbackFadeOutTimer.start(500, this); + event->accept(); +} + +void ImageWidget::resizeEvent(QResizeEvent*) +{ + updateImage(); +} + +void ImageWidget::updateImage() +{ + // should use qtconcurrent here? + transformation = QTransform(); + if (zoomedIn) { + } else { + if (currentImage.isNull()) + return; + if (zoomed) { + transformation = transformation.scale(zoom, zoom); + } else { + double xscale = (double)width()/currentImage.width(); + double yscale = (double)height()/currentImage.height(); + if (xscale < yscale) + yscale = xscale; + else + xscale = yscale; + transformation = transformation.scale(xscale, yscale); + } + if (rotated) + transformation = transformation.rotate(angle); + } + pixmap = QPixmap::fromImage(currentImage).transformed(transformation); + update(); +} + +void ImageWidget::openDirectory(const QString &path) +{ + this->path = path; + QDir dir(path); + QStringList nameFilters; + nameFilters << "*.jpg" << "*.png"; + files = dir.entryList(nameFilters, QDir::Files|QDir::Readable, QDir::Name); + + position = 0; + goToImage(0); + updateImage(); +} + +QImage ImageWidget::loadImage(const QString &fileName) +{ + QImageReader reader(fileName); + if (!reader.canRead()) { + qDebug() << fileName << ": can't load image"; + return QImage(); + } + QImage image; + if (!reader.read(&image)) { + qDebug() << fileName << ": corrupted image"; + return QImage(); + } + return image; +} + +void ImageWidget::setZoomedIn(bool zoomed) +{ + zoomedIn = zoomed; +} + +void ImageWidget::goNextImage() +{ + if (files.isEmpty()) + return; + if (position < files.size()-1) { + ++position; + prevImage = currentImage; + currentImage = nextImage; + if (position+1 < files.size()) + nextImage = loadImage(path+QLatin1String("/")+files.at(position+1)); + else + nextImage = QImage(); + } + setZoomedIn(false); + updateImage(); +} + +void ImageWidget::goPrevImage() +{ + if (files.isEmpty()) + return; + if (position > 0) { + --position; + nextImage = currentImage; + currentImage = prevImage; + if (position > 0) + prevImage = loadImage(path+QLatin1String("/")+files.at(position-1)); + else + prevImage = QImage(); + } + setZoomedIn(false); + updateImage(); +} + +void ImageWidget::goToImage(int index) +{ + if (files.isEmpty()) + return; + if (index < 0 || index >= files.size()) { + qDebug() << "goToImage: invalid index: " << index; + return; + } + if (index == position+1) { + goNextImage(); + return; + } + if (position > 0 && index == position-1) { + goPrevImage(); + return; + } + position = index; + pixmap = QPixmap(); + if (index > 0) + prevImage = loadImage(path+QLatin1String("/")+files.at(position-1)); + else + prevImage = QImage(); + currentImage = loadImage(path+QLatin1String("/")+files.at(position)); + if (position+1 < files.size()) + nextImage = loadImage(path+QLatin1String("/")+files.at(position+1)); + else + nextImage = QImage(); + setZoomedIn(false); + updateImage(); +} + +void ImageWidget::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == touchFeedback.tapTimer.timerId()) { + touchFeedback.tapTimer.stop(); + } else if (event->timerId() == feedbackFadeOutTimer.timerId()) { + feedbackFadeOutTimer.stop(); + touchFeedback.reset(); + } + update(); +} diff --git a/examples/gestures/imageviewer/imagewidget.h b/examples/gestures/imageviewer/imagewidget.h new file mode 100644 index 0000000..56fcb40 --- /dev/null +++ b/examples/gestures/imageviewer/imagewidget.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef IMAGEWIDGET_H +#define IMAGEWIDGET_H + +#include <QWidget> +#include <QImage> +#include <QPixmap> + +#include <QtGui> + +class ImageWidget : public QWidget +{ +public: + ImageWidget(QWidget *parent = 0); + + void openDirectory(const QString &path); + +protected: + void paintEvent(QPaintEvent*); + void gestureEvent(QGestureEvent *event); + void resizeEvent(QResizeEvent*); + void timerEvent(QTimerEvent*); + +private: + void updateImage(); + QImage loadImage(const QString &fileName); + void loadImage(); + void setZoomedIn(bool zoomed); + void goNextImage(); + void goPrevImage(); + void goToImage(int index); + + QString path; + QStringList files; + int position; + + QImage prevImage, nextImage; + QImage currentImage; + QPixmap pixmap; + QTransform transformation; + + bool zoomedIn; + int horizontalOffset; + int verticalOffset; + + bool zoomed; + qreal zoom; + bool rotated; + qreal angle; + + struct TouchFeedback + { + bool tapped; + QPoint position; + bool sliding; + QPoint slidingStartPosition; + QBasicTimer tapTimer; + int tapState; + bool doubleTapped; + int tapAndHoldState; + + enum { MaximumNumberOfTouches = 5 }; + QPoint touches[MaximumNumberOfTouches]; + + inline TouchFeedback() { reset(); } + inline void reset() + { + tapped = false; + sliding = false; + tapTimer.stop(); + tapState = 0; + doubleTapped = false; + tapAndHoldState = 0; + for (int i = 0; i < MaximumNumberOfTouches; ++i) { + touches[i] = QPoint(); + } + } + } touchFeedback; + QBasicTimer feedbackFadeOutTimer; +}; + +#endif diff --git a/examples/gestures/imageviewer/main.cpp b/examples/gestures/imageviewer/main.cpp new file mode 100644 index 0000000..5494b12 --- /dev/null +++ b/examples/gestures/imageviewer/main.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui> + +#include "imagewidget.h" + +class MainWidget : public QMainWindow +{ + Q_OBJECT + +public: + MainWidget(QWidget *parent = 0); + +public slots: + void openDirectory(const QString &path); + +private: + bool loadImage(const QString &fileName); + + ImageWidget *imageWidget; +}; + +MainWidget::MainWidget(QWidget *parent) + : QMainWindow(parent) +{ + resize(400, 300); + imageWidget = new ImageWidget(this); + setCentralWidget(imageWidget); +} + +void MainWidget::openDirectory(const QString &path) +{ + imageWidget->openDirectory(path); +} + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QApplication::setAttribute(Qt::AA_EnableGestures); + + MainWidget w; + w.show(); + + if (QApplication::arguments().size() > 1) + w.openDirectory(QApplication::arguments().at(1)); + return app.exec(); +} + +#include "main.moc" |