1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "flippablepad.h"
52#include "padnavigator.h"
53#include "splashitem.h"
54
55#include <QEventTransition>
56#include <QGraphicsProxyWidget>
57#include <QGraphicsRotation>
58#include <QHistoryState>
59#include <QKeyEventTransition>
60#include <QParallelAnimationGroup>
61#include <QPropertyAnimation>
62#include <QSequentialAnimationGroup>
63#include <QStateMachine>
64
65#ifndef QT_NO_OPENGL
66#include <QOpenGLWidget>
67#endif
68
69//! [0]
70PadNavigator::PadNavigator(const QSize &size, QWidget *parent)
71 : QGraphicsView(parent)
72{
73//! [0]
74//! [1]
75 // Splash item
76 SplashItem *splash = new SplashItem;
77 splash->setZValue(1);
78//! [1]
79
80//! [2]
81 // Pad item
82 FlippablePad *pad = new FlippablePad(size);
83 QGraphicsRotation *flipRotation = new QGraphicsRotation(pad);
84 QGraphicsRotation *xRotation = new QGraphicsRotation(pad);
85 QGraphicsRotation *yRotation = new QGraphicsRotation(pad);
86 flipRotation->setAxis(Qt::YAxis);
87 xRotation->setAxis(Qt::YAxis);
88 yRotation->setAxis(Qt::XAxis);
89 pad->setTransformations(QList<QGraphicsTransform *>()
90 << flipRotation
91 << xRotation << yRotation);
92//! [2]
93
94//! [3]
95 // Back (proxy widget) item
96 QGraphicsProxyWidget *backItem = new QGraphicsProxyWidget(pad);
97 QWidget *widget = new QWidget;
98 form.setupUi(widget);
99 form.hostName->setFocus();
100 backItem->setWidget(widget);
101 backItem->setVisible(false);
102 backItem->setFocus();
103 backItem->setCacheMode(mode: QGraphicsItem::ItemCoordinateCache);
104 const QRectF r = backItem->rect();
105 backItem->setTransform(matrix: QTransform()
106 .rotate(a: 180, axis: Qt::YAxis)
107 .translate(dx: -r.width()/2, dy: -r.height()/2));
108//! [3]
109
110//! [4]
111 // Selection item
112 RoundRectItem *selectionItem = new RoundRectItem(QRectF(-60, -60, 120, 120), Qt::gray, pad);
113 selectionItem->setZValue(0.5);
114//! [4]
115
116//! [5]
117 // Splash animations
118 QPropertyAnimation *smoothSplashMove = new QPropertyAnimation(splash, "y");
119 QPropertyAnimation *smoothSplashOpacity = new QPropertyAnimation(splash, "opacity");
120 smoothSplashMove->setEasingCurve(QEasingCurve::InQuad);
121 smoothSplashMove->setDuration(250);
122 smoothSplashOpacity->setDuration(250);
123//! [5]
124
125//! [6]
126 // Selection animation
127 QPropertyAnimation *smoothXSelection = new QPropertyAnimation(selectionItem, "x");
128 QPropertyAnimation *smoothYSelection = new QPropertyAnimation(selectionItem, "y");
129 QPropertyAnimation *smoothXRotation = new QPropertyAnimation(xRotation, "angle");
130 QPropertyAnimation *smoothYRotation = new QPropertyAnimation(yRotation, "angle");
131 smoothXSelection->setDuration(125);
132 smoothYSelection->setDuration(125);
133 smoothXRotation->setDuration(125);
134 smoothYRotation->setDuration(125);
135 smoothXSelection->setEasingCurve(QEasingCurve::InOutQuad);
136 smoothYSelection->setEasingCurve(QEasingCurve::InOutQuad);
137 smoothXRotation->setEasingCurve(QEasingCurve::InOutQuad);
138 smoothYRotation->setEasingCurve(QEasingCurve::InOutQuad);
139//! [6]
140
141//! [7]
142 // Flip animation setup
143 QPropertyAnimation *smoothFlipRotation = new QPropertyAnimation(flipRotation, "angle");
144 QPropertyAnimation *smoothFlipScale = new QPropertyAnimation(pad, "scale");
145 QParallelAnimationGroup *flipAnimation = new QParallelAnimationGroup(this);
146 smoothFlipScale->setDuration(500);
147 smoothFlipRotation->setDuration(500);
148 smoothFlipScale->setEasingCurve(QEasingCurve::InOutQuad);
149 smoothFlipRotation->setEasingCurve(QEasingCurve::InOutQuad);
150 smoothFlipScale->setKeyValueAt(step: 0, value: qvariant_cast<qreal>(v: 1.0));
151 smoothFlipScale->setKeyValueAt(step: 0.5, value: qvariant_cast<qreal>(v: 0.7));
152 smoothFlipScale->setKeyValueAt(step: 1, value: qvariant_cast<qreal>(v: 1.0));
153 flipAnimation->addAnimation(animation: smoothFlipRotation);
154 flipAnimation->addAnimation(animation: smoothFlipScale);
155//! [7]
156
157//! [8]
158 // Flip animation delayed property assignment
159 QSequentialAnimationGroup *setVariablesSequence = new QSequentialAnimationGroup;
160 QPropertyAnimation *setFillAnimation = new QPropertyAnimation(pad, "fill");
161 QPropertyAnimation *setBackItemVisibleAnimation = new QPropertyAnimation(backItem, "visible");
162 QPropertyAnimation *setSelectionItemVisibleAnimation = new QPropertyAnimation(selectionItem, "visible");
163 setFillAnimation->setDuration(0);
164 setBackItemVisibleAnimation->setDuration(0);
165 setSelectionItemVisibleAnimation->setDuration(0);
166 setVariablesSequence->addPause(msecs: 250);
167 setVariablesSequence->addAnimation(animation: setBackItemVisibleAnimation);
168 setVariablesSequence->addAnimation(animation: setSelectionItemVisibleAnimation);
169 setVariablesSequence->addAnimation(animation: setFillAnimation);
170 flipAnimation->addAnimation(animation: setVariablesSequence);
171//! [8]
172
173//! [9]
174 // Build the state machine
175 QStateMachine *stateMachine = new QStateMachine(this);
176 QState *splashState = new QState(stateMachine);
177 QState *frontState = new QState(stateMachine);
178 QHistoryState *historyState = new QHistoryState(frontState);
179 QState *backState = new QState(stateMachine);
180//! [9]
181//! [10]
182 frontState->assignProperty(object: pad, name: "fill", value: false);
183 frontState->assignProperty(object: splash, name: "opacity", value: 0.0);
184 frontState->assignProperty(object: backItem, name: "visible", value: false);
185 frontState->assignProperty(object: flipRotation, name: "angle", value: qvariant_cast<qreal>(v: 0.0));
186 frontState->assignProperty(object: selectionItem, name: "visible", value: true);
187 backState->assignProperty(object: pad, name: "fill", value: true);
188 backState->assignProperty(object: backItem, name: "visible", value: true);
189 backState->assignProperty(object: xRotation, name: "angle", value: qvariant_cast<qreal>(v: 0.0));
190 backState->assignProperty(object: yRotation, name: "angle", value: qvariant_cast<qreal>(v: 0.0));
191 backState->assignProperty(object: flipRotation, name: "angle", value: qvariant_cast<qreal>(v: 180.0));
192 backState->assignProperty(object: selectionItem, name: "visible", value: false);
193 stateMachine->addDefaultAnimation(animation: smoothXRotation);
194 stateMachine->addDefaultAnimation(animation: smoothYRotation);
195 stateMachine->addDefaultAnimation(animation: smoothXSelection);
196 stateMachine->addDefaultAnimation(animation: smoothYSelection);
197 stateMachine->setInitialState(splashState);
198//! [10]
199
200//! [11]
201 // Transitions
202 QEventTransition *anyKeyTransition = new QEventTransition(this, QEvent::KeyPress, splashState);
203 anyKeyTransition->setTargetState(frontState);
204 anyKeyTransition->addAnimation(animation: smoothSplashMove);
205 anyKeyTransition->addAnimation(animation: smoothSplashOpacity);
206//! [11]
207
208//! [12]
209 QKeyEventTransition *enterTransition = new QKeyEventTransition(this, QEvent::KeyPress,
210 Qt::Key_Enter, backState);
211 QKeyEventTransition *returnTransition = new QKeyEventTransition(this, QEvent::KeyPress,
212 Qt::Key_Return, backState);
213 QKeyEventTransition *backEnterTransition = new QKeyEventTransition(this, QEvent::KeyPress,
214 Qt::Key_Enter, frontState);
215 QKeyEventTransition *backReturnTransition = new QKeyEventTransition(this, QEvent::KeyPress,
216 Qt::Key_Return, frontState);
217 enterTransition->setTargetState(historyState);
218 returnTransition->setTargetState(historyState);
219 backEnterTransition->setTargetState(backState);
220 backReturnTransition->setTargetState(backState);
221 enterTransition->addAnimation(animation: flipAnimation);
222 returnTransition->addAnimation(animation: flipAnimation);
223 backEnterTransition->addAnimation(animation: flipAnimation);
224 backReturnTransition->addAnimation(animation: flipAnimation);
225//! [12]
226
227//! [13]
228 // Create substates for each icon; store in temporary grid.
229 int columns = size.width();
230 int rows = size.height();
231 QVector< QVector< QState * > > stateGrid;
232 stateGrid.resize(asize: rows);
233 for (int y = 0; y < rows; ++y) {
234 stateGrid[y].resize(asize: columns);
235 for (int x = 0; x < columns; ++x)
236 stateGrid[y][x] = new QState(frontState);
237 }
238 frontState->setInitialState(stateGrid[0][0]);
239 selectionItem->setPos(pad->iconAt(column: 0, row: 0)->pos());
240//! [13]
241
242//! [14]
243 // Enable key navigation using state transitions
244 for (int y = 0; y < rows; ++y) {
245 for (int x = 0; x < columns; ++x) {
246 QState *state = stateGrid[y][x];
247 QKeyEventTransition *rightTransition = new QKeyEventTransition(this, QEvent::KeyPress,
248 Qt::Key_Right, state);
249 QKeyEventTransition *leftTransition = new QKeyEventTransition(this, QEvent::KeyPress,
250 Qt::Key_Left, state);
251 QKeyEventTransition *downTransition = new QKeyEventTransition(this, QEvent::KeyPress,
252 Qt::Key_Down, state);
253 QKeyEventTransition *upTransition = new QKeyEventTransition(this, QEvent::KeyPress,
254 Qt::Key_Up, state);
255 rightTransition->setTargetState(stateGrid[y][(x + 1) % columns]);
256 leftTransition->setTargetState(stateGrid[y][((x - 1) + columns) % columns]);
257 downTransition->setTargetState(stateGrid[(y + 1) % rows][x]);
258 upTransition->setTargetState(stateGrid[((y - 1) + rows) % rows][x]);
259//! [14]
260//! [15]
261 RoundRectItem *icon = pad->iconAt(column: x, row: y);
262 state->assignProperty(object: xRotation, name: "angle", value: -icon->x() / 6.0);
263 state->assignProperty(object: yRotation, name: "angle", value: icon->y() / 6.0);
264 state->assignProperty(object: selectionItem, name: "x", value: icon->x());
265 state->assignProperty(object: selectionItem, name: "y", value: icon->y());
266 frontState->assignProperty(object: icon, name: "visible", value: true);
267 backState->assignProperty(object: icon, name: "visible", value: false);
268
269 QPropertyAnimation *setIconVisibleAnimation = new QPropertyAnimation(icon, "visible");
270 setIconVisibleAnimation->setDuration(0);
271 setVariablesSequence->addAnimation(animation: setIconVisibleAnimation);
272 }
273 }
274//! [15]
275
276//! [16]
277 // Scene
278 QGraphicsScene *scene = new QGraphicsScene(this);
279 scene->setBackgroundBrush(QPixmap(":/images/blue_angle_swirl.jpg"));
280 scene->setItemIndexMethod(QGraphicsScene::NoIndex);
281 scene->addItem(item: pad);
282 scene->setSceneRect(scene->itemsBoundingRect());
283 setScene(scene);
284//! [16]
285
286//! [17]
287 // Adjust splash item to scene contents
288 const QRectF sbr = splash->boundingRect();
289 splash->setPos(ax: -sbr.width() / 2, ay: scene->sceneRect().top() - 2);
290 frontState->assignProperty(object: splash, name: "y", value: splash->y() - 100.0);
291 scene->addItem(item: splash);
292//! [17]
293
294//! [18]
295 // View
296 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
297 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
298 setMinimumSize(minw: 50, minh: 50);
299 setViewportUpdateMode(FullViewportUpdate);
300 setCacheMode(CacheBackground);
301 setRenderHints(QPainter::Antialiasing
302 | QPainter::SmoothPixmapTransform
303 | QPainter::TextAntialiasing);
304#ifndef QT_NO_OPENGL
305 setViewport(new QOpenGLWidget);
306#endif
307
308 stateMachine->start();
309//! [18]
310}
311
312//! [19]
313void PadNavigator::resizeEvent(QResizeEvent *event)
314{
315 QGraphicsView::resizeEvent(event);
316 fitInView(rect: scene()->sceneRect(), aspectRadioMode: Qt::KeepAspectRatio);
317}
318//! [19]
319

source code of qtbase/examples/widgets/graphicsview/padnavigator/padnavigator.cpp