padnavigator.cpp Example File
graphicsview/padnavigator/padnavigator.cpp
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, 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 The Qt Company Ltd 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"
#ifndef QT_NO_OPENGL
#include <QtOpenGL>
#else
#include <QtWidgets>
#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 , qvariant_cast< qreal > (1.0 ));
smoothFlipScale- > setKeyValueAt(0.5 , qvariant_cast< qreal > (0.7 ));
smoothFlipScale- > setKeyValueAt(1 , qvariant_cast< 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" , qvariant_cast< qreal > (0.0 ));
frontState- > assignProperty(selectionItem, "visible" , true );
backState- > assignProperty(pad, "fill" , true );
backState- > assignProperty(backItem, "visible" , true );
backState- > assignProperty(xRotation, "angle" , qvariant_cast< qreal > (0.0 ));
backState- > assignProperty(yRotation, "angle" , qvariant_cast< qreal > (0.0 ));
backState- > assignProperty(flipRotation, "angle" , qvariant_cast< 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 QOpenGLWidget );
#endif
stateMachine- > start();
}
void PadNavigator:: resizeEvent(QResizeEvent * event)
{
QGraphicsView :: resizeEvent(event);
fitInView(scene()- > sceneRect(), Qt :: KeepAspectRatio);
}