Qt Reference Documentation

# padnavigator.cpp Example File

graphicsview/padnavigator/padnavigator.cpp

     /****************************************************************************
     **
     ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
     ** All rights reserved.
     ** Contact: Nokia Corporation (qt-info@nokia.com)
     **
     ** This file is part of the examples of the Qt Toolkit.
     **
     ** $QT_BEGIN_LICENSE:BSD$
     ** You may use this file under the terms of the BSD license as follows:
     **
     ** "Redistribution and use in source and binary forms, with or without
     ** modification, are permitted provided that the following conditions are
     ** met:
     **   * Redistributions of source code must retain the above copyright
     **     notice, this list of conditions and the following disclaimer.
     **   * Redistributions in binary form must reproduce the above copyright
     **     notice, this list of conditions and the following disclaimer in
     **     the documentation and/or other materials provided with the
     **     distribution.
     **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
     **     the names of its contributors may be used to endorse or promote
     **     products derived from this software without specific prior written
     **     permission.
     **
     ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
     ** $QT_END_LICENSE$
     **
     ****************************************************************************/

     #include "flippablepad.h"
     #include "padnavigator.h"
     #include "splashitem.h"

     #include <QtGui/QtGui>
     #ifndef QT_NO_OPENGL
     #include <QtOpenGL/QtOpenGL>
     #endif

     PadNavigator::PadNavigator(const QSize &size, QWidget *parent)
         : QGraphicsView(parent)
     {
         // Splash item
         SplashItem *splash = new SplashItem;
         splash->setZValue(1);

         // Pad item
         FlippablePad *pad = new FlippablePad(size);
         QGraphicsRotation *flipRotation = new QGraphicsRotation(pad);
         QGraphicsRotation *xRotation = new QGraphicsRotation(pad);
         QGraphicsRotation *yRotation = new QGraphicsRotation(pad);
         flipRotation->setAxis(Qt::YAxis);
         xRotation->setAxis(Qt::YAxis);
         yRotation->setAxis(Qt::XAxis);
         pad->setTransformations(QList<QGraphicsTransform *>()
                                 << flipRotation
                                 << xRotation << yRotation);

         // Back (proxy widget) item
         QGraphicsProxyWidget *backItem = new QGraphicsProxyWidget(pad);
         QWidget *widget = new QWidget;
         form.setupUi(widget);
         form.hostName->setFocus();
         backItem->setWidget(widget);
         backItem->setVisible(false);
         backItem->setFocus();
         backItem->setCacheMode(QGraphicsItem::ItemCoordinateCache);
         const QRectF r = backItem->rect();
         backItem->setTransform(QTransform()
                                .rotate(180, Qt::YAxis)
                                .translate(-r.width()/2, -r.height()/2));

         // Selection item
         RoundRectItem *selectionItem = new RoundRectItem(QRectF(-60, -60, 120, 120),
                                                          Qt::gray, pad);
         selectionItem->setZValue(0.5);

         // Splash animations
         QPropertyAnimation *smoothSplashMove = new QPropertyAnimation(splash, "y");
         QPropertyAnimation *smoothSplashOpacity = new QPropertyAnimation(splash, "opacity");
         smoothSplashMove->setEasingCurve(QEasingCurve::InQuad);
         smoothSplashMove->setDuration(250);
         smoothSplashOpacity->setDuration(250);

         // Selection animation
         QPropertyAnimation *smoothXSelection = new QPropertyAnimation(selectionItem, "x");
         QPropertyAnimation *smoothYSelection = new QPropertyAnimation(selectionItem, "y");
         QPropertyAnimation *smoothXRotation = new QPropertyAnimation(xRotation, "angle");
         QPropertyAnimation *smoothYRotation = new QPropertyAnimation(yRotation, "angle");
         smoothXSelection->setDuration(125);
         smoothYSelection->setDuration(125);
         smoothXRotation->setDuration(125);
         smoothYRotation->setDuration(125);
         smoothXSelection->setEasingCurve(QEasingCurve::InOutQuad);
         smoothYSelection->setEasingCurve(QEasingCurve::InOutQuad);
         smoothXRotation->setEasingCurve(QEasingCurve::InOutQuad);
         smoothYRotation->setEasingCurve(QEasingCurve::InOutQuad);

         // Flip animation setup
         QPropertyAnimation *smoothFlipRotation = new QPropertyAnimation(flipRotation, "angle");
         QPropertyAnimation *smoothFlipScale = new QPropertyAnimation(pad, "scale");
         QPropertyAnimation *smoothFlipXRotation = new QPropertyAnimation(xRotation, "angle");
         QPropertyAnimation *smoothFlipYRotation = new QPropertyAnimation(yRotation, "angle");
         QParallelAnimationGroup *flipAnimation = new QParallelAnimationGroup(this);
         smoothFlipScale->setDuration(500);
         smoothFlipRotation->setDuration(500);
         smoothFlipXRotation->setDuration(500);
         smoothFlipYRotation->setDuration(500);
         smoothFlipScale->setEasingCurve(QEasingCurve::InOutQuad);
         smoothFlipRotation->setEasingCurve(QEasingCurve::InOutQuad);
         smoothFlipXRotation->setEasingCurve(QEasingCurve::InOutQuad);
         smoothFlipYRotation->setEasingCurve(QEasingCurve::InOutQuad);
         smoothFlipScale->setKeyValueAt(0, qVariantValue<qreal>(1.0));
         smoothFlipScale->setKeyValueAt(0.5, qVariantValue<qreal>(0.7));
         smoothFlipScale->setKeyValueAt(1, qVariantValue<qreal>(1.0));
         flipAnimation->addAnimation(smoothFlipRotation);
         flipAnimation->addAnimation(smoothFlipScale);
         flipAnimation->addAnimation(smoothFlipXRotation);
         flipAnimation->addAnimation(smoothFlipYRotation);

         // Flip animation delayed property assignment
         QSequentialAnimationGroup *setVariablesSequence = new QSequentialAnimationGroup;
         QPropertyAnimation *setFillAnimation = new QPropertyAnimation(pad, "fill");
         QPropertyAnimation *setBackItemVisibleAnimation = new QPropertyAnimation(backItem, "visible");
         QPropertyAnimation *setSelectionItemVisibleAnimation = new QPropertyAnimation(selectionItem, "visible");
         setFillAnimation->setDuration(0);
         setBackItemVisibleAnimation->setDuration(0);
         setSelectionItemVisibleAnimation->setDuration(0);
         setVariablesSequence->addPause(250);
         setVariablesSequence->addAnimation(setBackItemVisibleAnimation);
         setVariablesSequence->addAnimation(setSelectionItemVisibleAnimation);
         setVariablesSequence->addAnimation(setFillAnimation);
         flipAnimation->addAnimation(setVariablesSequence);

         // Build the state machine
         QStateMachine *stateMachine = new QStateMachine(this);
         QState *splashState = new QState(stateMachine);
         QState *frontState = new QState(stateMachine);
         QHistoryState *historyState = new QHistoryState(frontState);
         QState *backState = new QState(stateMachine);
         frontState->assignProperty(pad, "fill", false);
         frontState->assignProperty(splash, "opacity", 0.0);
         frontState->assignProperty(backItem, "visible", false);
         frontState->assignProperty(flipRotation, "angle", qVariantValue<qreal>(0.0));
         frontState->assignProperty(selectionItem, "visible", true);
         backState->assignProperty(pad, "fill", true);
         backState->assignProperty(backItem, "visible", true);
         backState->assignProperty(xRotation, "angle", qVariantValue<qreal>(0.0));
         backState->assignProperty(yRotation, "angle", qVariantValue<qreal>(0.0));
         backState->assignProperty(flipRotation, "angle", qVariantValue<qreal>(180.0));
         backState->assignProperty(selectionItem, "visible", false);
         stateMachine->addDefaultAnimation(smoothXRotation);
         stateMachine->addDefaultAnimation(smoothYRotation);
         stateMachine->addDefaultAnimation(smoothXSelection);
         stateMachine->addDefaultAnimation(smoothYSelection);
         stateMachine->setInitialState(splashState);

         // Transitions
         QEventTransition *anyKeyTransition = new QEventTransition(this, QEvent::KeyPress, splashState);
         anyKeyTransition->setTargetState(frontState);
         anyKeyTransition->addAnimation(smoothSplashMove);
         anyKeyTransition->addAnimation(smoothSplashOpacity);

         QKeyEventTransition *enterTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                        Qt::Key_Enter, backState);
         QKeyEventTransition *returnTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                         Qt::Key_Return, backState);
         QKeyEventTransition *backEnterTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                            Qt::Key_Enter, frontState);
         QKeyEventTransition *backReturnTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                             Qt::Key_Return, frontState);
         enterTransition->setTargetState(historyState);
         returnTransition->setTargetState(historyState);
         backEnterTransition->setTargetState(backState);
         backReturnTransition->setTargetState(backState);
         enterTransition->addAnimation(flipAnimation);
         returnTransition->addAnimation(flipAnimation);
         backEnterTransition->addAnimation(flipAnimation);
         backReturnTransition->addAnimation(flipAnimation);

         // Create substates for each icon; store in temporary grid.
         int columns = size.width();
         int rows = size.height();
         QVector< QVector< QState * > > stateGrid;
         stateGrid.resize(rows);
         for (int y = 0; y < rows; ++y) {
             stateGrid[y].resize(columns);
             for (int x = 0; x < columns; ++x)
                 stateGrid[y][x] = new QState(frontState);
         }
         frontState->setInitialState(stateGrid[0][0]);
         selectionItem->setPos(pad->iconAt(0, 0)->pos());

         // Enable key navigation using state transitions
         for (int y = 0; y < rows; ++y) {
             for (int x = 0; x < columns; ++x) {
                 QState *state = stateGrid[y][x];
                 QKeyEventTransition *rightTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                                Qt::Key_Right, state);
                 QKeyEventTransition *leftTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                               Qt::Key_Left, state);
                 QKeyEventTransition *downTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                               Qt::Key_Down, state);
                 QKeyEventTransition *upTransition = new QKeyEventTransition(this, QEvent::KeyPress,
                                                                             Qt::Key_Up, state);
                 rightTransition->setTargetState(stateGrid[y][(x + 1) % columns]);
                 leftTransition->setTargetState(stateGrid[y][((x - 1) + columns) % columns]);
                 downTransition->setTargetState(stateGrid[(y + 1) % rows][x]);
                 upTransition->setTargetState(stateGrid[((y - 1) + rows) % rows][x]);
                 RoundRectItem *icon = pad->iconAt(x, y);
                 state->assignProperty(xRotation, "angle", -icon->x() / 6.0);
                 state->assignProperty(yRotation, "angle", icon->y() / 6.0);
                 state->assignProperty(selectionItem, "x", icon->x());
                 state->assignProperty(selectionItem, "y", icon->y());
                 frontState->assignProperty(icon, "visible", true);
                 backState->assignProperty(icon, "visible", false);

                 QPropertyAnimation *setIconVisibleAnimation = new QPropertyAnimation(icon, "visible");
                 setIconVisibleAnimation->setDuration(0);
                 setVariablesSequence->addAnimation(setIconVisibleAnimation);
             }
         }

         // Scene
         QGraphicsScene *scene = new QGraphicsScene(this);
         scene->setBackgroundBrush(QPixmap(":/images/blue_angle_swirl.jpg"));
         scene->setItemIndexMethod(QGraphicsScene::NoIndex);
         scene->addItem(pad);
         scene->setSceneRect(scene->itemsBoundingRect());
         setScene(scene);

         // Adjust splash item to scene contents
         const QRectF sbr = splash->boundingRect();
         splash->setPos(-sbr.width() / 2, scene->sceneRect().top() - 2);
         frontState->assignProperty(splash, "y", splash->y() - 100.0);
         scene->addItem(splash);

         // View
         setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
         setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
         setMinimumSize(50, 50);
         setViewportUpdateMode(FullViewportUpdate);
         setCacheMode(CacheBackground);
         setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);
     #ifndef QT_NO_OPENGL
         setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
     #endif

         stateMachine->start();
     }

     void PadNavigator::resizeEvent(QResizeEvent *event)
     {
         QGraphicsView::resizeEvent(event);
         fitInView(scene()->sceneRect(), Qt::KeepAspectRatio);
     }