From c7ba279815f9bd35a78ede33f516583cf8b022ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20R=C3=B8dal?= <samuel.rodal@nokia.com>
Date: Wed, 23 Nov 2011 09:36:51 +0100
Subject: [PATCH] Added rotation animation to paintedwindow example.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This serves as a useful test case for the QScreen orientation API.

Change-Id: I009ebd8b6d345453620420d84f3ff9d2d2e2663e
Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
---
 examples/opengl/paintedwindow/main.cpp        |   3 +-
 .../opengl/paintedwindow/paintedwindow.cpp    | 135 +++++++++++++++---
 examples/opengl/paintedwindow/paintedwindow.h |  26 ++++
 3 files changed, 141 insertions(+), 23 deletions(-)

diff --git a/examples/opengl/paintedwindow/main.cpp b/examples/opengl/paintedwindow/main.cpp
index d4eead9d402..c672798558e 100644
--- a/examples/opengl/paintedwindow/main.cpp
+++ b/examples/opengl/paintedwindow/main.cpp
@@ -53,7 +53,7 @@ int main(int argc, char **argv)
     QRect screenGeometry = screen->availableGeometry();
 
     QPoint center = screenGeometry.center();
-    QRect windowRect(0, 0, 640, 480);
+    QRect windowRect(0, 0, 480, 640);
 
     PaintedWindow window;
     window.setGeometry(QRect(center - windowRect.center(), windowRect.size()));
@@ -61,3 +61,4 @@ int main(int argc, char **argv)
 
     app.exec();
 }
+
diff --git a/examples/opengl/paintedwindow/paintedwindow.cpp b/examples/opengl/paintedwindow/paintedwindow.cpp
index 543c13eab30..78539d7ff17 100644
--- a/examples/opengl/paintedwindow/paintedwindow.cpp
+++ b/examples/opengl/paintedwindow/paintedwindow.cpp
@@ -64,6 +64,21 @@ PaintedWindow::PaintedWindow()
     m_context = new QOpenGLContext(this);
     m_context->setFormat(format);
     m_context->create();
+
+    m_animation = new QPropertyAnimation(this, "rotation");
+    m_animation->setStartValue(qreal(0));
+    m_animation->setEndValue(qreal(1));
+    m_animation->setDuration(500);
+
+    setOrientation(QGuiApplication::primaryScreen()->primaryOrientation());
+    m_rotation = 0;
+
+    m_targetOrientation = orientation();
+    m_nextTargetOrientation = Qt::UnknownOrientation;
+
+    connect(screen(), SIGNAL(currentOrientationChanged(Qt::ScreenOrientation)), this, SLOT(orientationChanged(Qt::ScreenOrientation)));
+    connect(m_animation, SIGNAL(finished()), this, SLOT(rotationDone()));
+    connect(this, SIGNAL(rotationChanged(qreal)), this, SLOT(paint()));
 }
 
 void PaintedWindow::resizeEvent(QResizeEvent *)
@@ -79,21 +94,18 @@ void PaintedWindow::exposeEvent(QExposeEvent *)
 void PaintedWindow::mousePressEvent(QMouseEvent *)
 {
     Qt::ScreenOrientation o = orientation();
-    if (o == Qt::UnknownOrientation)
-        o = QGuiApplication::primaryScreen()->primaryOrientation();
-
     switch (o) {
     case Qt::LandscapeOrientation:
-        setOrientation(Qt::PortraitOrientation);
+        orientationChanged(Qt::PortraitOrientation);
         break;
     case Qt::PortraitOrientation:
-        setOrientation(Qt::InvertedLandscapeOrientation);
+        orientationChanged(Qt::InvertedLandscapeOrientation);
         break;
     case Qt::InvertedLandscapeOrientation:
-        setOrientation(Qt::InvertedPortraitOrientation);
+        orientationChanged(Qt::InvertedPortraitOrientation);
         break;
     case Qt::InvertedPortraitOrientation:
-        setOrientation(Qt::LandscapeOrientation);
+        orientationChanged(Qt::LandscapeOrientation);
         break;
     default:
         Q_ASSERT(false);
@@ -102,31 +114,110 @@ void PaintedWindow::mousePressEvent(QMouseEvent *)
     paint();
 }
 
+void PaintedWindow::orientationChanged(Qt::ScreenOrientation newOrientation)
+{
+    if (orientation() == newOrientation)
+        return;
+
+    if (m_animation->state() == QAbstractAnimation::Running) {
+        m_nextTargetOrientation = newOrientation;
+        return;
+    }
+
+    Qt::ScreenOrientation screenOrientation = screen()->primaryOrientation();
+
+    QRect rect(0, 0, width(), height());
+
+    m_prevImage = QImage(width(), height(), QImage::Format_ARGB32_Premultiplied);
+    m_nextImage = QImage(width(), height(), QImage::Format_ARGB32_Premultiplied);
+    m_prevImage.fill(0);
+    m_nextImage.fill(0);
+
+    QPainter p;
+    p.begin(&m_prevImage);
+    p.setTransform(QScreen::transformBetween(orientation(), screenOrientation, rect));
+    paint(&p, QScreen::mapBetween(orientation(), screenOrientation, rect));
+    p.end();
+
+    p.begin(&m_nextImage);
+    p.setTransform(QScreen::transformBetween(newOrientation, screenOrientation, rect));
+    paint(&p, QScreen::mapBetween(newOrientation, screenOrientation, rect));
+    p.end();
+
+    m_deltaRotation = QScreen::angleBetween(newOrientation, orientation());
+    if (m_deltaRotation > 180)
+        m_deltaRotation = 180 - m_deltaRotation;
+
+    m_targetOrientation = newOrientation;
+    m_animation->start();
+}
+
+void PaintedWindow::rotationDone()
+{
+    setOrientation(m_targetOrientation);
+    if (m_nextTargetOrientation != Qt::UnknownOrientation) {
+        Q_ASSERT(m_animation->state() != QAbstractAnimation::Running);
+        orientationChanged(m_nextTargetOrientation);
+        m_nextTargetOrientation = Qt::UnknownOrientation;
+    }
+}
+
+void PaintedWindow::setRotation(qreal r)
+{
+    if (r != m_rotation) {
+        m_rotation = r;
+        emit rotationChanged(r);
+    }
+}
+
 void PaintedWindow::paint()
 {
     m_context->makeCurrent(this);
 
-    QOpenGLPaintDevice device(size());
-
-    Qt::ScreenOrientation screenOrientation = QGuiApplication::primaryScreen()->primaryOrientation();
+    Qt::ScreenOrientation screenOrientation = screen()->primaryOrientation();
     Qt::ScreenOrientation appOrientation = orientation();
 
     QRect rect(0, 0, width(), height());
-    QRect mapped = QScreen::mapBetween(appOrientation, screenOrientation, rect);
-
-    QPainterPath path;
-    path.addEllipse(mapped);
 
+    QOpenGLPaintDevice device(size());
     QPainter painter(&device);
-    painter.setTransform(QScreen::transformBetween(appOrientation, screenOrientation, rect));
-    painter.fillRect(mapped, Qt::white);
-    painter.setRenderHint(QPainter::Antialiasing);
+
+    QPainterPath path;
+    path.addEllipse(rect);
+    painter.setCompositionMode(QPainter::CompositionMode_Source);
+    painter.fillRect(rect, Qt::transparent);
+    painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
     painter.fillPath(path, Qt::blue);
-    QFont font;
-    font.setPixelSize(64);
-    painter.setFont(font);
-    painter.drawText(mapped, Qt::AlignCenter, "Hello");
-    painter.end();
+
+    if (orientation() != m_targetOrientation) {
+        painter.setRenderHint(QPainter::SmoothPixmapTransform);
+        painter.save();
+        painter.translate(width() / 2, height() / 2);
+        painter.rotate(m_deltaRotation * m_rotation);
+        painter.translate(-width() / 2, -height() / 2);
+        painter.drawImage(0, 0, m_prevImage);
+        painter.restore();
+        painter.translate(width() / 2, height() / 2);
+        painter.rotate(m_deltaRotation * m_rotation - m_deltaRotation);
+        painter.translate(-width() / 2, -height() / 2);
+        painter.setOpacity(m_rotation);
+        painter.drawImage(0, 0, m_nextImage);
+    } else {
+        QRect mapped = QScreen::mapBetween(appOrientation, screenOrientation, rect);
+
+        painter.setTransform(QScreen::transformBetween(appOrientation, screenOrientation, rect));
+        paint(&painter, mapped);
+        painter.end();
+    }
 
     m_context->swapBuffers(this);
 }
+
+void PaintedWindow::paint(QPainter *painter, const QRect &rect)
+{
+    painter->setRenderHint(QPainter::Antialiasing);
+    QFont font;
+    font.setPixelSize(64);
+    painter->setFont(font);
+    painter->drawText(rect, Qt::AlignCenter, "Hello");
+}
diff --git a/examples/opengl/paintedwindow/paintedwindow.h b/examples/opengl/paintedwindow/paintedwindow.h
index dcf8110e245..28e06ec4df1 100644
--- a/examples/opengl/paintedwindow/paintedwindow.h
+++ b/examples/opengl/paintedwindow/paintedwindow.h
@@ -44,7 +44,10 @@
 #include <QtGui/qopenglshaderprogram.h>
 #include <QtGui/qopenglframebufferobject.h>
 
+#include <QPropertyAnimation>
+
 #include <QColor>
+#include <QImage>
 #include <QTime>
 
 QT_BEGIN_NAMESPACE
@@ -54,16 +57,39 @@ QT_END_NAMESPACE
 class PaintedWindow : public QWindow
 {
     Q_OBJECT
+    Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+
 public:
     PaintedWindow();
 
+    qreal rotation() const { return m_rotation; }
+
+signals:
+    void rotationChanged(qreal rotation);
+
 private slots:
     void paint();
+    void setRotation(qreal r);
+    void orientationChanged(Qt::ScreenOrientation newOrientation);
+    void rotationDone();
 
 private:
     void resizeEvent(QResizeEvent *);
     void exposeEvent(QExposeEvent *);
     void mousePressEvent(QMouseEvent *);
 
+    void paint(QPainter *painter, const QRect &rect);
+
     QOpenGLContext *m_context;
+    qreal m_rotation;
+
+    QImage m_prevImage;
+    QImage m_nextImage;
+    qreal m_deltaRotation;
+
+    Qt::ScreenOrientation m_targetOrientation;
+    Qt::ScreenOrientation m_nextTargetOrientation;
+
+    QPropertyAnimation *m_animation;
+    QTimer *m_paintTimer;
 };
-- 
GitLab