d376925b2fa3d41abee98d3ad16bdd0adc9289ad
[profile/ivi/qtdeclarative.git] / src / qtquick1 / graphicsitems / qdeclarativeflipable.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "QtQuick1/private/qdeclarativeflipable_p.h"
43
44 #include "QtQuick1/private/qdeclarativeitem_p.h"
45 #include "QtDeclarative/private/qdeclarativeguard_p.h"
46
47 #include <QtDeclarative/qdeclarativeinfo.h>
48
49 #include <QtWidgets/qgraphicstransform.h>
50
51 QT_BEGIN_NAMESPACE
52
53
54
55 class QDeclarative1FlipablePrivate : public QDeclarativeItemPrivate
56 {
57     Q_DECLARE_PUBLIC(QDeclarative1Flipable)
58 public:
59     QDeclarative1FlipablePrivate() : current(QDeclarative1Flipable::Front), front(0), back(0) {}
60
61     void updateSceneTransformFromParent();
62     void setBackTransform();
63
64     QDeclarative1Flipable::Side current;
65     QDeclarativeGuard<QGraphicsObject> front;
66     QDeclarativeGuard<QGraphicsObject> back;
67
68     bool wantBackXFlipped;
69     bool wantBackYFlipped;
70 };
71
72 /*!
73     \qmlclass Flipable QDeclarative1Flipable
74     \inqmlmodule QtQuick 1
75     \since QtQuick 1.0
76     \ingroup qml-basic-interaction-elements
77     \brief The Flipable item provides a surface that can be flipped.
78     \inherits Item
79
80     Flipable is an item that can be visibly "flipped" between its front and
81     back sides, like a card. It is used together with \l Rotation, \l State
82     and \l Transition elements to produce a flipping effect.
83
84     The \l front and \l back properties are used to hold the items that are
85     shown respectively on the front and back sides of the flipable item.
86
87     \section1 Example Usage
88
89     The following example shows a Flipable item that flips whenever it is
90     clicked, rotating about the y-axis.
91
92     This flipable item has a \c flipped boolean property that is toggled
93     whenever the MouseArea within the flipable is clicked. When
94     \c flipped is true, the item changes to the "back" state; in this
95     state, the \c angle of the \l Rotation item is changed to 180
96     degrees to produce the flipping effect. When \c flipped is false, the
97     item reverts to the default state, in which the \c angle value is 0.
98
99     \snippet doc/src/snippets/qtquick1/flipable/flipable.qml 0
100
101     \image flipable.gif
102
103     The \l Transition creates the animation that changes the angle over
104     four seconds. When the item changes between its "back" and
105     default states, the NumberAnimation animates the angle between
106     its old and new values.
107
108     See \l {QML States} for details on state changes and the default
109     state, and \l {QML Animation and Transitions} for more information on how
110     animations work within transitions.
111
112     \sa {declarative/ui-components/flipable}{Flipable example}
113 */
114
115 QDeclarative1Flipable::QDeclarative1Flipable(QDeclarativeItem *parent)
116 : QDeclarativeItem(*(new QDeclarative1FlipablePrivate), parent)
117 {
118 }
119
120 QDeclarative1Flipable::~QDeclarative1Flipable()
121 {
122 }
123
124 /*!
125   \qmlproperty Item QtQuick1::Flipable::front
126   \qmlproperty Item QtQuick1::Flipable::back
127
128   The front and back sides of the flipable.
129 */
130
131 QGraphicsObject *QDeclarative1Flipable::front()
132 {
133     Q_D(const QDeclarative1Flipable);
134     return d->front;
135 }
136
137 void QDeclarative1Flipable::setFront(QGraphicsObject *front)
138 {
139     Q_D(QDeclarative1Flipable);
140     if (d->front) {
141         qmlInfo(this) << tr("front is a write-once property");
142         return;
143     }
144     d->front = front;
145     d->front->setParentItem(this);
146     if (Back == d->current)
147         d->front->setOpacity(0.);
148     emit frontChanged();
149 }
150
151 QGraphicsObject *QDeclarative1Flipable::back()
152 {
153     Q_D(const QDeclarative1Flipable);
154     return d->back;
155 }
156
157 void QDeclarative1Flipable::setBack(QGraphicsObject *back)
158 {
159     Q_D(QDeclarative1Flipable);
160     if (d->back) {
161         qmlInfo(this) << tr("back is a write-once property");
162         return;
163     }
164     d->back = back;
165     d->back->setParentItem(this);
166     if (Front == d->current)
167         d->back->setOpacity(0.);
168     connect(back, SIGNAL(widthChanged()),
169             this, SLOT(retransformBack()));
170     connect(back, SIGNAL(heightChanged()),
171             this, SLOT(retransformBack()));
172     emit backChanged();
173 }
174
175 void QDeclarative1Flipable::retransformBack()
176 {
177     Q_D(QDeclarative1Flipable);
178     if (d->current == QDeclarative1Flipable::Back && d->back)
179         d->setBackTransform();
180 }
181
182 /*!
183   \qmlproperty enumeration QtQuick1::Flipable::side
184
185   The side of the Flipable currently visible. Possible values are \c
186   Flipable.Front and \c Flipable.Back.
187 */
188 QDeclarative1Flipable::Side QDeclarative1Flipable::side() const
189 {
190     Q_D(const QDeclarative1Flipable);
191     if (d->dirtySceneTransform)
192         const_cast<QDeclarative1FlipablePrivate *>(d)->ensureSceneTransform();
193
194     return d->current;
195 }
196
197 // determination on the currently visible side of the flipable
198 // has to be done on the complete scene transform to give
199 // correct results.
200 void QDeclarative1FlipablePrivate::updateSceneTransformFromParent()
201 {
202     Q_Q(QDeclarative1Flipable);
203
204     QDeclarativeItemPrivate::updateSceneTransformFromParent();
205     QPointF p1(0, 0);
206     QPointF p2(1, 0);
207     QPointF p3(1, 1);
208
209     QPointF scenep1 = sceneTransform.map(p1);
210     QPointF scenep2 = sceneTransform.map(p2);
211     QPointF scenep3 = sceneTransform.map(p3);
212     p1 = q->mapToParent(p1);
213     p2 = q->mapToParent(p2);
214     p3 = q->mapToParent(p3);
215
216     qreal cross = (scenep1.x() - scenep2.x()) * (scenep3.y() - scenep2.y()) -
217                   (scenep1.y() - scenep2.y()) * (scenep3.x() - scenep2.x());
218
219     wantBackYFlipped = p1.x() >= p2.x();
220     wantBackXFlipped = p2.y() >= p3.y();
221
222     QDeclarative1Flipable::Side newSide;
223     if (cross > 0) {
224         newSide = QDeclarative1Flipable::Back;
225     } else {
226         newSide = QDeclarative1Flipable::Front;
227     }
228
229     if (newSide != current) {
230         current = newSide;
231         if (current == QDeclarative1Flipable::Back && back)
232             setBackTransform();
233         if (front)
234             front->setOpacity((current==QDeclarative1Flipable::Front)?1.:0.);
235         if (back)
236             back->setOpacity((current==QDeclarative1Flipable::Back)?1.:0.);
237         emit q->sideChanged();
238     }
239 }
240
241 /* Depends on the width/height of the back item, and so needs reevaulating
242    if those change.
243 */
244 void QDeclarative1FlipablePrivate::setBackTransform()
245 {
246     QTransform mat;
247     QGraphicsItemPrivate *dBack = QGraphicsItemPrivate::get(back);
248     mat.translate(dBack->width()/2,dBack->height()/2);
249     if (dBack->width() && wantBackYFlipped)
250         mat.rotate(180, Qt::YAxis);
251     if (dBack->height() && wantBackXFlipped)
252         mat.rotate(180, Qt::XAxis);
253     mat.translate(-dBack->width()/2,-dBack->height()/2);
254     back->setTransform(mat);
255 }
256
257
258
259 QT_END_NAMESPACE