summaryrefslogtreecommitdiffstats
path: root/tests/manual/examples/widgets/touch
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual/examples/widgets/touch')
-rw-r--r--tests/manual/examples/widgets/touch/dials/CMakeLists.txt37
-rw-r--r--tests/manual/examples/widgets/touch/dials/dials.pro8
-rw-r--r--tests/manual/examples/widgets/touch/dials/dials.ui77
-rw-r--r--tests/manual/examples/widgets/touch/dials/doc/images/touch-dials-example.pngbin0 -> 17676 bytes
-rw-r--r--tests/manual/examples/widgets/touch/dials/doc/src/touch-dials.qdoc14
-rw-r--r--tests/manual/examples/widgets/touch/dials/main.cpp21
-rw-r--r--tests/manual/examples/widgets/touch/fingerpaint/CMakeLists.txt45
-rw-r--r--tests/manual/examples/widgets/touch/fingerpaint/doc/src/fingerpaint.qdoc18
-rw-r--r--tests/manual/examples/widgets/touch/fingerpaint/fingerpaint.pro13
-rw-r--r--tests/manual/examples/widgets/touch/fingerpaint/main.cpp14
-rw-r--r--tests/manual/examples/widgets/touch/fingerpaint/mainwindow.cpp180
-rw-r--r--tests/manual/examples/widgets/touch/fingerpaint/mainwindow.h51
-rw-r--r--tests/manual/examples/widgets/touch/fingerpaint/scribblearea.cpp190
-rw-r--r--tests/manual/examples/widgets/touch/fingerpaint/scribblearea.h43
-rw-r--r--tests/manual/examples/widgets/touch/pinchzoom/CMakeLists.txt50
-rw-r--r--tests/manual/examples/widgets/touch/pinchzoom/doc/images/pinch-zoom-example.pngbin0 -> 42493 bytes
-rw-r--r--tests/manual/examples/widgets/touch/pinchzoom/doc/src/pinchzoom.qdoc14
-rw-r--r--tests/manual/examples/widgets/touch/pinchzoom/graphicsview.cpp48
-rw-r--r--tests/manual/examples/widgets/touch/pinchzoom/graphicsview.h18
-rw-r--r--tests/manual/examples/widgets/touch/pinchzoom/images/cheese.jpgbin0 -> 3029 bytes
-rw-r--r--tests/manual/examples/widgets/touch/pinchzoom/main.cpp47
-rw-r--r--tests/manual/examples/widgets/touch/pinchzoom/mice.qrc5
-rw-r--r--tests/manual/examples/widgets/touch/pinchzoom/mouse.cpp158
-rw-r--r--tests/manual/examples/widgets/touch/pinchzoom/mouse.h33
-rw-r--r--tests/manual/examples/widgets/touch/pinchzoom/pinchzoom.pro16
25 files changed, 1100 insertions, 0 deletions
diff --git a/tests/manual/examples/widgets/touch/dials/CMakeLists.txt b/tests/manual/examples/widgets/touch/dials/CMakeLists.txt
new file mode 100644
index 0000000000..fd4b7859a9
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/dials/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(dials LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/touch/dials")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(dials
+ dials.ui
+ main.cpp
+)
+
+set_target_properties(dials PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(dials PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+install(TARGETS dials
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/touch/dials/dials.pro b/tests/manual/examples/widgets/touch/dials/dials.pro
new file mode 100644
index 0000000000..0e823551cc
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/dials/dials.pro
@@ -0,0 +1,8 @@
+QT += widgets
+
+SOURCES += main.cpp
+FORMS += dials.ui
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/touch/dials
+INSTALLS += target
diff --git a/tests/manual/examples/widgets/touch/dials/dials.ui b/tests/manual/examples/widgets/touch/dials/dials.ui
new file mode 100644
index 0000000000..8ca7ae9475
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/dials/dials.ui
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dials</class>
+ <widget class="QWidget" name="Dials">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QDial" name="dial_1">
+ <property name="notchesVisible">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QDial" name="dial_2">
+ <property name="notchesVisible">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QDial" name="dial_3">
+ <property name="notchesVisible">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QDial" name="dial_4">
+ <property name="notchesVisible">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QDial" name="dial_5">
+ <property name="notchesVisible">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QDial" name="dial_6">
+ <property name="notchesVisible">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QDial" name="dial_7">
+ <property name="notchesVisible">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QDial" name="dial_8">
+ <property name="notchesVisible">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/manual/examples/widgets/touch/dials/doc/images/touch-dials-example.png b/tests/manual/examples/widgets/touch/dials/doc/images/touch-dials-example.png
new file mode 100644
index 0000000000..60e1776fc3
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/dials/doc/images/touch-dials-example.png
Binary files differ
diff --git a/tests/manual/examples/widgets/touch/dials/doc/src/touch-dials.qdoc b/tests/manual/examples/widgets/touch/dials/doc/src/touch-dials.qdoc
new file mode 100644
index 0000000000..448430ed79
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/dials/doc/src/touch-dials.qdoc
@@ -0,0 +1,14 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example touch/dials
+ \title Touch Dials Example
+ \ingroup touchinputexamples
+ \brief Shows how to apply touch to a set of standard Qt widgets.
+
+ The Touch Dials example shows how to apply touch to a set of
+ standard Qt widgets.
+
+ \image touch-dials-example.png
+*/
diff --git a/tests/manual/examples/widgets/touch/dials/main.cpp b/tests/manual/examples/widgets/touch/dials/main.cpp
new file mode 100644
index 0000000000..63fdb7db3b
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/dials/main.cpp
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QApplication>
+#include <QWidget>
+#include <QDial>
+
+#include "ui_dials.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ QWidget window;
+ Ui::Dials dialsUi;
+ dialsUi.setupUi(&window);
+ const QList<QAbstractSlider *> sliders = window.findChildren<QAbstractSlider *>();
+ for (QAbstractSlider *slider : sliders)
+ slider->setAttribute(Qt::WA_AcceptTouchEvents);
+ window.showMaximized();
+ return app.exec();
+}
diff --git a/tests/manual/examples/widgets/touch/fingerpaint/CMakeLists.txt b/tests/manual/examples/widgets/touch/fingerpaint/CMakeLists.txt
new file mode 100644
index 0000000000..c06a91b53b
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/fingerpaint/CMakeLists.txt
@@ -0,0 +1,45 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(fingerpaint LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/touch/fingerpaint")
+
+find_package(Qt6
+ REQUIRED COMPONENTS Core Gui Widgets
+ OPTIONAL_COMPONENTS PrintSupport
+)
+
+qt_standard_project_setup()
+
+qt_add_executable(fingerpaint
+ main.cpp
+ mainwindow.cpp mainwindow.h
+ scribblearea.cpp scribblearea.h
+)
+
+set_target_properties(fingerpaint PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(fingerpaint PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+if (TARGET Qt6::PrintSupport)
+ target_link_libraries(fingerpaint PRIVATE Qt6::PrintSupport)
+endif()
+
+install(TARGETS fingerpaint
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/touch/fingerpaint/doc/src/fingerpaint.qdoc b/tests/manual/examples/widgets/touch/fingerpaint/doc/src/fingerpaint.qdoc
new file mode 100644
index 0000000000..0e3319004c
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/fingerpaint/doc/src/fingerpaint.qdoc
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example touch/fingerpaint
+ \title Finger Paint Example
+ \ingroup touchinputexamples
+ \brief Shows the use of a touchscreen to make a simple painting application.
+
+ The Finger Paint example shows the use of a touchscreen with a custom widget
+ to create a simple painting application.
+
+ \image touch-fingerpaint-example.png
+
+ This example was specifically designed to work with a touchscreen, using
+ QTouchEvent instead of QMouseEvent to handle user input over the custom
+ widget. As a result, it is not possible to draw with the mouse cursor.
+*/
diff --git a/tests/manual/examples/widgets/touch/fingerpaint/fingerpaint.pro b/tests/manual/examples/widgets/touch/fingerpaint/fingerpaint.pro
new file mode 100644
index 0000000000..6370da6607
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/fingerpaint/fingerpaint.pro
@@ -0,0 +1,13 @@
+QT += widgets
+requires(qtConfig(filedialog))
+qtHaveModule(printsupport): QT += printsupport
+
+HEADERS = mainwindow.h \
+ scribblearea.h
+SOURCES = main.cpp \
+ mainwindow.cpp \
+ scribblearea.cpp
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/touch/fingerpaint
+INSTALLS += target
diff --git a/tests/manual/examples/widgets/touch/fingerpaint/main.cpp b/tests/manual/examples/widgets/touch/fingerpaint/main.cpp
new file mode 100644
index 0000000000..d283c7b85c
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/fingerpaint/main.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QApplication>
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow window;
+ window.showMaximized();
+ return app.exec();
+}
diff --git a/tests/manual/examples/widgets/touch/fingerpaint/mainwindow.cpp b/tests/manual/examples/widgets/touch/fingerpaint/mainwindow.cpp
new file mode 100644
index 0000000000..b9109fceeb
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/fingerpaint/mainwindow.cpp
@@ -0,0 +1,180 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtWidgets>
+
+#include "mainwindow.h"
+#include "scribblearea.h"
+
+//! [0]
+MainWindow::MainWindow()
+{
+ scribbleArea = new ScribbleArea;
+ setCentralWidget(scribbleArea);
+
+ createActions();
+ createMenus();
+
+ setWindowTitle(tr("Finger Paint"));
+ resize(500, 500);
+}
+//! [0]
+
+//! [1]
+void MainWindow::closeEvent(QCloseEvent *event)
+//! [1] //! [2]
+{
+ if (maybeSave()) {
+ event->accept();
+ } else {
+ event->ignore();
+ }
+}
+//! [2]
+
+//! [3]
+void MainWindow::open()
+//! [3] //! [4]
+{
+ if (maybeSave()) {
+ QString fileName = QFileDialog::getOpenFileName(this,
+ tr("Open File"), QDir::currentPath());
+ if (!fileName.isEmpty())
+ scribbleArea->openImage(fileName);
+ }
+}
+//! [4]
+
+//! [5]
+void MainWindow::save()
+//! [5] //! [6]
+{
+ QAction *action = qobject_cast<QAction *>(sender());
+ QByteArray fileFormat = action->data().toByteArray();
+ saveFile(fileFormat);
+}
+//! [6]
+
+//! [11]
+void MainWindow::about()
+//! [11] //! [12]
+{
+ QMessageBox::about(this, tr("About Scribble"),
+ tr("<p>The <b>Scribble</b> example shows how to use QMainWindow as the "
+ "base widget for an application, and how to reimplement some of "
+ "QWidget's event handlers to receive the events generated for "
+ "the application's widgets:</p><p> We reimplement the mouse event "
+ "handlers to facilitate drawing, the paint event handler to "
+ "update the application and the resize event handler to optimize "
+ "the application's appearance. In addition we reimplement the "
+ "close event handler to intercept the close events before "
+ "terminating the application.</p><p> The example also demonstrates "
+ "how to use QPainter to draw an image in real time, as well as "
+ "to repaint widgets.</p>"));
+}
+//! [12]
+
+//! [13]
+void MainWindow::createActions()
+//! [13] //! [14]
+{
+ openAct = new QAction(tr("&Open..."), this);
+ openAct->setShortcut(tr("Ctrl+O"));
+ connect(openAct, &QAction::triggered, this, &MainWindow::open);
+
+ const QList<QByteArray> imageFormats = QImageWriter::supportedImageFormats();
+ for (const QByteArray &format : imageFormats) {
+ QString text = tr("%1...").arg(QString(format).toUpper());
+
+ QAction *action = new QAction(text, this);
+ action->setData(format);
+ connect(action, &QAction::triggered, this, &MainWindow::save);
+ saveAsActs.append(action);
+ }
+
+ printAct = new QAction(tr("&Print..."), this);
+ connect(printAct, &QAction::triggered, scribbleArea, &ScribbleArea::print);
+
+ exitAct = new QAction(tr("E&xit"), this);
+ exitAct->setShortcut(tr("Ctrl+Q"));
+ connect(exitAct, &QAction::triggered, this, &QWidget::close);
+
+ clearScreenAct = new QAction(tr("&Clear Screen"), this);
+ clearScreenAct->setShortcut(tr("Ctrl+L"));
+ connect(clearScreenAct, &QAction::triggered,
+ scribbleArea, &ScribbleArea::clearImage);
+
+ aboutAct = new QAction(tr("&About"), this);
+ connect(aboutAct, &QAction::triggered, this, &MainWindow::about);
+
+ aboutQtAct = new QAction(tr("About &Qt"), this);
+ connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt);
+}
+//! [14]
+
+//! [15]
+void MainWindow::createMenus()
+//! [15] //! [16]
+{
+ saveAsMenu = new QMenu(tr("&Save As"), this);
+ saveAsMenu->addActions(saveAsActs);
+
+ fileMenu = new QMenu(tr("&File"), this);
+ fileMenu->addAction(openAct);
+ fileMenu->addMenu(saveAsMenu);
+ fileMenu->addAction(printAct);
+ fileMenu->addSeparator();
+ fileMenu->addAction(exitAct);
+
+ optionMenu = new QMenu(tr("&Options"), this);
+ optionMenu->addAction(clearScreenAct);
+
+ helpMenu = new QMenu(tr("&Help"), this);
+ helpMenu->addAction(aboutAct);
+ helpMenu->addAction(aboutQtAct);
+
+ menuBar()->addMenu(fileMenu);
+ menuBar()->addMenu(optionMenu);
+ menuBar()->addMenu(helpMenu);
+}
+//! [16]
+
+//! [17]
+bool MainWindow::maybeSave()
+//! [17] //! [18]
+{
+ if (scribbleArea->isModified()) {
+ QMessageBox::StandardButton ret;
+ ret = QMessageBox::warning(this, tr("Scribble"),
+ tr("The image has been modified.\n"
+ "Do you want to save your changes?"),
+ QMessageBox::Save | QMessageBox::Discard
+ | QMessageBox::Cancel);
+ if (ret == QMessageBox::Save) {
+ return saveFile("png");
+ } else if (ret == QMessageBox::Cancel) {
+ return false;
+ }
+ }
+ return true;
+}
+//! [18]
+
+//! [19]
+bool MainWindow::saveFile(const QByteArray &fileFormat)
+//! [19] //! [20]
+{
+ QString initialPath = QDir::currentPath() + "/untitled." + fileFormat;
+
+ QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"),
+ initialPath,
+ tr("%1 Files (*.%2);;All Files (*)")
+ .arg(QString::fromLatin1(fileFormat.toUpper()))
+ .arg(QString::fromLatin1(fileFormat)));
+ if (fileName.isEmpty()) {
+ return false;
+ } else {
+ return scribbleArea->saveImage(fileName, fileFormat.constData());
+ }
+}
+//! [20]
diff --git a/tests/manual/examples/widgets/touch/fingerpaint/mainwindow.h b/tests/manual/examples/widgets/touch/fingerpaint/mainwindow.h
new file mode 100644
index 0000000000..a4aac1e36b
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/fingerpaint/mainwindow.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QList>
+#include <QMainWindow>
+
+class ScribbleArea;
+
+//! [0]
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+protected:
+ void closeEvent(QCloseEvent *event) override;
+
+private slots:
+ void open();
+ void save();
+ void about();
+
+private:
+ void createActions();
+ void createMenus();
+ bool maybeSave();
+ bool saveFile(const QByteArray &fileFormat);
+
+ ScribbleArea *scribbleArea;
+
+ QMenu *saveAsMenu;
+ QMenu *fileMenu;
+ QMenu *optionMenu;
+ QMenu *helpMenu;
+
+ QAction *openAct;
+ QList<QAction *> saveAsActs;
+ QAction *exitAct;
+ QAction *printAct;
+ QAction *clearScreenAct;
+ QAction *aboutAct;
+ QAction *aboutQtAct;
+};
+//! [0]
+
+#endif
diff --git a/tests/manual/examples/widgets/touch/fingerpaint/scribblearea.cpp b/tests/manual/examples/widgets/touch/fingerpaint/scribblearea.cpp
new file mode 100644
index 0000000000..fb5e62906b
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/fingerpaint/scribblearea.cpp
@@ -0,0 +1,190 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtWidgets>
+#if defined(QT_PRINTSUPPORT_LIB)
+#include <QtPrintSupport/qtprintsupportglobal.h>
+#if QT_CONFIG(printdialog)
+#include <QPrinter>
+#include <QPrintDialog>
+#endif
+#endif
+
+#include "scribblearea.h"
+
+static const qreal MinimumDiameter = 3.0;
+static const qreal MaximumDiameter = 50.0;
+
+//! [0]
+ScribbleArea::ScribbleArea(QWidget *parent)
+ : QWidget(parent)
+{
+ setAttribute(Qt::WA_AcceptTouchEvents);
+ setAttribute(Qt::WA_StaticContents);
+ modified = false;
+
+ myPenColors
+ << QColor("green")
+ << QColor("purple")
+ << QColor("red")
+ << QColor("blue")
+ << QColor("yellow")
+
+ << QColor("pink")
+ << QColor("orange")
+ << QColor("brown")
+ << QColor("grey")
+ << QColor("black");
+}
+//! [0]
+
+//! [1]
+bool ScribbleArea::openImage(const QString &fileName)
+//! [1] //! [2]
+{
+ QImage loadedImage;
+ if (!loadedImage.load(fileName))
+ return false;
+
+ QSize newSize = loadedImage.size().expandedTo(size());
+ resizeImage(&loadedImage, newSize);
+ image = loadedImage;
+ modified = false;
+ update();
+ return true;
+}
+//! [2]
+
+//! [3]
+bool ScribbleArea::saveImage(const QString &fileName, const char *fileFormat)
+//! [3] //! [4]
+{
+ QImage visibleImage = image;
+ resizeImage(&visibleImage, size());
+
+ if (visibleImage.save(fileName, fileFormat)) {
+ modified = false;
+ return true;
+ } else {
+ return false;
+ }
+}
+//! [4]
+
+//! [9]
+void ScribbleArea::clearImage()
+//! [9] //! [10]
+{
+ image.fill(qRgb(255, 255, 255));
+ modified = true;
+ update();
+}
+//! [10]
+
+//! [12] //! [13]
+void ScribbleArea::paintEvent(QPaintEvent *event)
+//! [13] //! [14]
+{
+ QPainter painter(this);
+ const QRect rect = event->rect();
+ painter.drawImage(rect.topLeft(), image, rect);
+}
+//! [14]
+
+//! [15]
+void ScribbleArea::resizeEvent(QResizeEvent *event)
+//! [15] //! [16]
+{
+ if (width() > image.width() || height() > image.height()) {
+ int newWidth = qMax(width() + 128, image.width());
+ int newHeight = qMax(height() + 128, image.height());
+ resizeImage(&image, QSize(newWidth, newHeight));
+ update();
+ }
+ QWidget::resizeEvent(event);
+}
+//! [16]
+
+//! [19]
+void ScribbleArea::resizeImage(QImage *image, const QSize &newSize)
+//! [19] //! [20]
+{
+ if (image->size() == newSize)
+ return;
+
+ QImage newImage(newSize, QImage::Format_RGB32);
+ newImage.fill(qRgb(255, 255, 255));
+ QPainter painter(&newImage);
+ painter.drawImage(QPoint(0, 0), *image);
+ *image = newImage;
+}
+//! [20]
+
+//! [21]
+void ScribbleArea::print()
+{
+#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
+ QPrinter printer(QPrinter::HighResolution);
+
+ QPrintDialog printDialog(&printer, this);
+//! [21] //! [22]
+ if (printDialog.exec() == QDialog::Accepted) {
+ QPainter painter(&printer);
+ QRect rect = painter.viewport();
+ QSize size = image.size();
+ size.scale(rect.size(), Qt::KeepAspectRatio);
+ painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
+ painter.setWindow(image.rect());
+ painter.drawImage(0, 0, image);
+ }
+#endif // QT_CONFIG(printdialog)
+}
+//! [22]
+
+bool ScribbleArea::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ {
+ const QTouchEvent *touch = static_cast<QTouchEvent *>(event);
+ const auto touchPoints = static_cast<QTouchEvent *>(event)->points();
+ for (const QTouchEvent::TouchPoint &touchPoint : touchPoints) {
+ switch (touchPoint.state()) {
+ case QEventPoint::Stationary:
+ case QEventPoint::Released:
+ // don't do anything if this touch point hasn't moved or has been released
+ continue;
+ default:
+ {
+ QSizeF diams = touchPoint.ellipseDiameters();
+ if (diams.isEmpty()) {
+ qreal diameter = MaximumDiameter;
+ if (touch->pointingDevice()->capabilities().testFlag(QPointingDevice::Capability::Pressure))
+ diameter = MinimumDiameter + (MaximumDiameter - MinimumDiameter) * touchPoint.pressure();
+ diams = QSizeF(diameter, diameter);
+ }
+
+ QPainter painter(&image);
+ painter.setPen(Qt::NoPen);
+ painter.setBrush(myPenColors.at(touchPoint.id() % myPenColors.count()));
+ painter.drawEllipse(touchPoint.position(), diams.width() / 2, diams.height() / 2);
+ painter.end();
+
+ modified = true;
+ const int rad = 2;
+ QRectF rect(QPointF(), diams);
+ rect.moveCenter(touchPoint.position());
+ update(rect.toRect().adjusted(-rad,-rad, +rad, +rad));
+ }
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ return QWidget::event(event);
+ }
+ return true;
+}
diff --git a/tests/manual/examples/widgets/touch/fingerpaint/scribblearea.h b/tests/manual/examples/widgets/touch/fingerpaint/scribblearea.h
new file mode 100644
index 0000000000..624f07074a
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/fingerpaint/scribblearea.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SCRIBBLEAREA_H
+#define SCRIBBLEAREA_H
+
+#include <QColor>
+#include <QImage>
+#include <QPoint>
+#include <QWidget>
+
+//! [0]
+class ScribbleArea : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ScribbleArea(QWidget *parent = nullptr);
+
+ bool openImage(const QString &fileName);
+ bool saveImage(const QString &fileName, const char *fileFormat);
+
+ bool isModified() const { return modified; }
+
+public slots:
+ void clearImage();
+ void print();
+
+protected:
+ void paintEvent(QPaintEvent *event) override;
+ void resizeEvent(QResizeEvent *event) override;
+ bool event(QEvent *event) override;
+
+private:
+ void resizeImage(QImage *image, const QSize &newSize);
+
+ bool modified;
+ QList<QColor> myPenColors;
+ QImage image;
+};
+//! [0]
+
+#endif
diff --git a/tests/manual/examples/widgets/touch/pinchzoom/CMakeLists.txt b/tests/manual/examples/widgets/touch/pinchzoom/CMakeLists.txt
new file mode 100644
index 0000000000..8820d8d44b
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/pinchzoom/CMakeLists.txt
@@ -0,0 +1,50 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(pinchzoom LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/touch/pinchzoom")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(pinchzoom
+ graphicsview.cpp graphicsview.h
+ main.cpp
+ mouse.cpp mouse.h
+)
+
+set_target_properties(pinchzoom PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(pinchzoom PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+# Resources:
+set(mice_resource_files
+ "images/cheese.jpg"
+)
+
+qt_add_resources(pinchzoom "mice"
+ PREFIX
+ "/"
+ FILES
+ ${mice_resource_files}
+)
+
+install(TARGETS pinchzoom
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/touch/pinchzoom/doc/images/pinch-zoom-example.png b/tests/manual/examples/widgets/touch/pinchzoom/doc/images/pinch-zoom-example.png
new file mode 100644
index 0000000000..7db51fbf55
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/pinchzoom/doc/images/pinch-zoom-example.png
Binary files differ
diff --git a/tests/manual/examples/widgets/touch/pinchzoom/doc/src/pinchzoom.qdoc b/tests/manual/examples/widgets/touch/pinchzoom/doc/src/pinchzoom.qdoc
new file mode 100644
index 0000000000..aef5c59407
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/pinchzoom/doc/src/pinchzoom.qdoc
@@ -0,0 +1,14 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example touch/pinchzoom
+ \title Pinch Zoom Example
+ \ingroup touchinputexamples
+ \brief Shows how to recognize a gesture.
+
+ The Pinch Zoom example shows how to use low-level touch information
+ to recognize a gesture.
+
+ \image touch-pinchzoom-example.png
+*/
diff --git a/tests/manual/examples/widgets/touch/pinchzoom/graphicsview.cpp b/tests/manual/examples/widgets/touch/pinchzoom/graphicsview.cpp
new file mode 100644
index 0000000000..61042e7e02
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/pinchzoom/graphicsview.cpp
@@ -0,0 +1,48 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "graphicsview.h"
+
+#include <QScrollBar>
+#include <QTouchEvent>
+
+GraphicsView::GraphicsView(QGraphicsScene *scene, QWidget *parent)
+ : QGraphicsView(scene, parent)
+{
+ viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
+ setDragMode(ScrollHandDrag);
+}
+
+bool GraphicsView::viewportEvent(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ {
+ QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
+ const auto touchPoints = touchEvent->points();
+ if (touchPoints.count() == 2) {
+ // determine scale factor
+ const QEventPoint &touchPoint0 = touchPoints.first();
+ const QEventPoint &touchPoint1 = touchPoints.last();
+ qreal currentScaleFactor =
+ QLineF(touchPoint0.position(), touchPoint1.position()).length()
+ / QLineF(touchPoint0.pressPosition(), touchPoint1.pressPosition()).length();
+ if (touchEvent->touchPointStates() & QEventPoint::Released) {
+ // if one of the fingers is released, remember the current scale
+ // factor so that adding another finger later will continue zooming
+ // by adding new scale factor to the existing remembered value.
+ totalScaleFactor *= currentScaleFactor;
+ currentScaleFactor = 1;
+ }
+ setTransform(QTransform::fromScale(totalScaleFactor * currentScaleFactor,
+ totalScaleFactor * currentScaleFactor));
+ }
+ return true;
+ }
+ default:
+ break;
+ }
+ return QGraphicsView::viewportEvent(event);
+}
diff --git a/tests/manual/examples/widgets/touch/pinchzoom/graphicsview.h b/tests/manual/examples/widgets/touch/pinchzoom/graphicsview.h
new file mode 100644
index 0000000000..e6a300f418
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/pinchzoom/graphicsview.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#pragma once
+#include <QGraphicsView>
+
+class GraphicsView : public QGraphicsView
+{
+ Q_OBJECT
+
+public:
+ GraphicsView(QGraphicsScene *scene = nullptr, QWidget *parent = nullptr);
+
+ bool viewportEvent(QEvent *event) override;
+
+private:
+ qreal totalScaleFactor = 1;
+};
diff --git a/tests/manual/examples/widgets/touch/pinchzoom/images/cheese.jpg b/tests/manual/examples/widgets/touch/pinchzoom/images/cheese.jpg
new file mode 100644
index 0000000000..dea5795fd0
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/pinchzoom/images/cheese.jpg
Binary files differ
diff --git a/tests/manual/examples/widgets/touch/pinchzoom/main.cpp b/tests/manual/examples/widgets/touch/pinchzoom/main.cpp
new file mode 100644
index 0000000000..85b5cad1f8
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/pinchzoom/main.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "graphicsview.h"
+#include "mouse.h"
+
+#include <QApplication>
+#include <cmath>
+
+static constexpr int MouseCount = 7;
+
+//! [0]
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+//! [0]
+
+//! [1]
+ QGraphicsScene scene;
+ scene.setSceneRect(-300, -300, 600, 600);
+//! [1] //! [2]
+ scene.setItemIndexMethod(QGraphicsScene::NoIndex);
+//! [2]
+
+//! [3]
+ for (int i = 0; i < MouseCount; ++i) {
+ Mouse *mouse = new Mouse;
+ mouse->setPos(::sin((i * 6.28) / MouseCount) * 200,
+ ::cos((i * 6.28) / MouseCount) * 200);
+ scene.addItem(mouse);
+ }
+//! [3]
+
+//! [4]
+ GraphicsView view(&scene);
+ view.setRenderHint(QPainter::Antialiasing);
+ view.setBackgroundBrush(QPixmap(":/images/cheese.jpg"));
+//! [4] //! [5]
+ view.setCacheMode(QGraphicsView::CacheBackground);
+ view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
+//! [5] //! [6]
+ view.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Colliding Mice"));
+ view.showMaximized();
+
+ return app.exec();
+}
+//! [6]
diff --git a/tests/manual/examples/widgets/touch/pinchzoom/mice.qrc b/tests/manual/examples/widgets/touch/pinchzoom/mice.qrc
new file mode 100644
index 0000000000..accdb4d0a6
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/pinchzoom/mice.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/" >
+ <file>images/cheese.jpg</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/examples/widgets/touch/pinchzoom/mouse.cpp b/tests/manual/examples/widgets/touch/pinchzoom/mouse.cpp
new file mode 100644
index 0000000000..ae0d497833
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/pinchzoom/mouse.cpp
@@ -0,0 +1,158 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mouse.h"
+
+#include <QGraphicsScene>
+#include <QPainter>
+#include <QRandomGenerator>
+#include <QStyleOption>
+#include <qmath.h>
+
+constexpr qreal Pi = M_PI;
+constexpr qreal TwoPi = 2 * M_PI;
+
+static qreal normalizeAngle(qreal angle)
+{
+ while (angle < 0)
+ angle += TwoPi;
+ while (angle > TwoPi)
+ angle -= TwoPi;
+ return angle;
+}
+
+//! [0]
+Mouse::Mouse() : color(QRandomGenerator::global()->bounded(256),
+ QRandomGenerator::global()->bounded(256),
+ QRandomGenerator::global()->bounded(256))
+{
+ setTransform(QTransform().rotate(QRandomGenerator::global()->bounded(360 * 16)), true);
+ startTimer(1000 / 33);
+}
+//! [0]
+
+//! [1]
+QRectF Mouse::boundingRect() const
+{
+ qreal adjust = 0.5;
+ return QRectF(-18 - adjust, -22 - adjust,
+ 36 + adjust, 60 + adjust);
+}
+//! [1]
+
+//! [2]
+QPainterPath Mouse::shape() const
+{
+ QPainterPath path;
+ path.addRect(-10, -20, 20, 40);
+ return path;
+}
+//! [2]
+
+//! [3]
+void Mouse::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ // Body
+ painter->setBrush(color);
+ painter->drawEllipse(-10, -20, 20, 40);
+
+ // Eyes
+ painter->setBrush(Qt::white);
+ painter->drawEllipse(-10, -17, 8, 8);
+ painter->drawEllipse(2, -17, 8, 8);
+
+ // Nose
+ painter->setBrush(Qt::black);
+ painter->drawEllipse(QRectF(-2, -22, 4, 4));
+
+ // Pupils
+ painter->drawEllipse(QRectF(-8.0 + mouseEyeDirection, -17, 4, 4));
+ painter->drawEllipse(QRectF(4.0 + mouseEyeDirection, -17, 4, 4));
+
+ // Ears
+ painter->setBrush(scene()->collidingItems(this).isEmpty() ? Qt::darkYellow : Qt::red);
+ painter->drawEllipse(-17, -12, 16, 16);
+ painter->drawEllipse(1, -12, 16, 16);
+
+ // Tail
+ QPainterPath path(QPointF(0, 20));
+ path.cubicTo(-5, 22, -5, 22, 0, 25);
+ path.cubicTo(5, 27, 5, 32, 0, 30);
+ path.cubicTo(-5, 32, -5, 42, 0, 35);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawPath(path);
+}
+//! [3]
+
+//! [4]
+void Mouse::timerEvent(QTimerEvent *)
+{
+//! [4]
+ // Don't move too far away
+//! [5]
+ QLineF lineToCenter(QPointF(0, 0), mapFromScene(0, 0));
+ if (lineToCenter.length() > 150) {
+ qreal angleToCenter = std::atan2(lineToCenter.dy(), lineToCenter.dx());
+ angleToCenter = normalizeAngle((Pi - angleToCenter) + Pi / 2);
+
+ if (angleToCenter < Pi && angleToCenter > Pi / 4) {
+ // Rotate left
+ angle += (angle < -Pi / 2) ? 0.25 : -0.25;
+ } else if (angleToCenter >= Pi && angleToCenter < (Pi + Pi / 2 + Pi / 4)) {
+ // Rotate right
+ angle += (angle < Pi / 2) ? 0.25 : -0.25;
+ }
+ } else if (::sin(angle) < 0) {
+ angle += 0.25;
+ } else if (::sin(angle) > 0) {
+ angle -= 0.25;
+//! [5] //! [6]
+ }
+//! [6]
+
+ // Try not to crash with any other mice
+//! [7]
+ QList<QGraphicsItem *> dangerMice = scene()->items(QPolygonF()
+ << mapToScene(0, 0)
+ << mapToScene(-30, -50)
+ << mapToScene(30, -50));
+ for (QGraphicsItem *item : dangerMice) {
+ if (item == this)
+ continue;
+
+ QLineF lineToMouse(QPointF(0, 0), mapFromItem(item, 0, 0));
+ qreal angleToMouse = std::atan2(lineToMouse.dy(), lineToMouse.dx());
+ angleToMouse = normalizeAngle((Pi - angleToMouse) + Pi / 2);
+
+ if (angleToMouse >= 0 && angleToMouse < Pi / 2) {
+ // Rotate right
+ angle += 0.5;
+ } else if (angleToMouse <= TwoPi && angleToMouse > (TwoPi - Pi / 2)) {
+ // Rotate left
+ angle -= 0.5;
+//! [7] //! [8]
+ }
+//! [8] //! [9]
+ }
+//! [9]
+
+ // Add some random movement
+//! [10]
+ if (dangerMice.size() > 1 && QRandomGenerator::global()->bounded(10) == 0) {
+ if (QRandomGenerator::global()->bounded(1))
+ angle += QRandomGenerator::global()->bounded(1 / 500.0);
+ else
+ angle -= QRandomGenerator::global()->bounded(1 / 500.0);
+ }
+//! [10]
+
+//! [11]
+ speed += (-50 + QRandomGenerator::global()->bounded(100)) / 100.0;
+
+ qreal dx = ::sin(angle) * 10;
+ mouseEyeDirection = (qAbs(dx / 5) < 1) ? 0 : dx / 5;
+
+ setTransform(QTransform().rotate(dx), true);
+ setPos(mapToParent(0, -(3 + sin(speed) * 3)));
+}
+//! [11]
diff --git a/tests/manual/examples/widgets/touch/pinchzoom/mouse.h b/tests/manual/examples/widgets/touch/pinchzoom/mouse.h
new file mode 100644
index 0000000000..6b3ef98c22
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/pinchzoom/mouse.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MOUSE_H
+#define MOUSE_H
+
+#include <QGraphicsObject>
+
+//! [0]
+class Mouse : public QGraphicsObject
+{
+ Q_OBJECT
+
+public:
+ Mouse();
+
+ QRectF boundingRect() const override;
+ QPainterPath shape() const override;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget) override;
+
+protected:
+ void timerEvent(QTimerEvent *event) override;
+
+private:
+ qreal angle = 0;
+ qreal speed = 0;
+ qreal mouseEyeDirection = 0;
+ QColor color;
+};
+//! [0]
+
+#endif
diff --git a/tests/manual/examples/widgets/touch/pinchzoom/pinchzoom.pro b/tests/manual/examples/widgets/touch/pinchzoom/pinchzoom.pro
new file mode 100644
index 0000000000..ebbc7ddf1f
--- /dev/null
+++ b/tests/manual/examples/widgets/touch/pinchzoom/pinchzoom.pro
@@ -0,0 +1,16 @@
+QT += widgets
+
+HEADERS += \
+ mouse.h \
+ graphicsview.h
+SOURCES += \
+ main.cpp \
+ mouse.cpp \
+ graphicsview.cpp
+
+RESOURCES += \
+ mice.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/touch/pinchzoom
+INSTALLS += target