Extract all QtQuick 1 elements into a separate library/plugin.
[profile/ivi/qtdeclarative.git] / src / qtquick1 / graphicsitems / qdeclarativeflipable.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
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 <QtGui/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     \since 4.7
75     \ingroup qml-basic-interaction-elements
76     \brief The Flipable item provides a surface that can be flipped.
77     \inherits Item
78
79     Flipable is an item that can be visibly "flipped" between its front and
80     back sides, like a card. It is used together with \l Rotation, \l State
81     and \l Transition elements to produce a flipping effect.
82
83     The \l front and \l back properties are used to hold the items that are
84     shown respectively on the front and back sides of the flipable item.
85
86     \section1 Example Usage
87
88     The following example shows a Flipable item that flips whenever it is
89     clicked, rotating about the y-axis.
90
91     This flipable item has a \c flipped boolean property that is toggled
92     whenever the MouseArea within the flipable is clicked. When
93     \c flipped is true, the item changes to the "back" state; in this
94     state, the \c angle of the \l Rotation item is changed to 180
95     degrees to produce the flipping effect. When \c flipped is false, the
96     item reverts to the default state, in which the \c angle value is 0.
97
98     \snippet doc/src/snippets/declarative/flipable/flipable.qml 0
99
100     \image flipable.gif
101
102     The \l Transition creates the animation that changes the angle over
103     four seconds. When the item changes between its "back" and
104     default states, the NumberAnimation animates the angle between
105     its old and new values.
106
107     See \l {QML States} for details on state changes and the default
108     state, and \l {QML Animation and Transitions} for more information on how
109     animations work within transitions.
110
111     \sa {declarative/ui-components/flipable}{Flipable example}
112 */
113
114 QDeclarative1Flipable::QDeclarative1Flipable(QDeclarativeItem *parent)
115 : QDeclarativeItem(*(new QDeclarative1FlipablePrivate), parent)
116 {
117 }
118
119 QDeclarative1Flipable::~QDeclarative1Flipable()
120 {
121 }
122
123 /*!
124   \qmlproperty Item Flipable::front
125   \qmlproperty Item Flipable::back
126
127   The front and back sides of the flipable.
128 */
129
130 QGraphicsObject *QDeclarative1Flipable::front()
131 {
132     Q_D(const QDeclarative1Flipable);
133     return d->front;
134 }
135
136 void QDeclarative1Flipable::setFront(QGraphicsObject *front)
137 {
138     Q_D(QDeclarative1Flipable);
139     if (d->front) {
140         qmlInfo(this) << tr("front is a write-once property");
141         return;
142     }
143     d->front = front;
144     d->front->setParentItem(this);
145     if (Back == d->current)
146         d->front->setOpacity(0.);
147     emit frontChanged();
148 }
149
150 QGraphicsObject *QDeclarative1Flipable::back()
151 {
152     Q_D(const QDeclarative1Flipable);
153     return d->back;
154 }
155
156 void QDeclarative1Flipable::setBack(QGraphicsObject *back)
157 {
158     Q_D(QDeclarative1Flipable);
159     if (d->back) {
160         qmlInfo(this) << tr("back is a write-once property");
161         return;
162     }
163     d->back = back;
164     d->back->setParentItem(this);
165     if (Front == d->current)
166         d->back->setOpacity(0.);
167     connect(back, SIGNAL(widthChanged()),
168             this, SLOT(retransformBack()));
169     connect(back, SIGNAL(heightChanged()),
170             this, SLOT(retransformBack()));
171     emit backChanged();
172 }
173
174 void QDeclarative1Flipable::retransformBack()
175 {
176     Q_D(QDeclarative1Flipable);
177     if (d->current == QDeclarative1Flipable::Back && d->back)
178         d->setBackTransform();
179 }
180
181 /*!
182   \qmlproperty enumeration Flipable::side
183
184   The side of the Flipable currently visible. Possible values are \c
185   Flipable.Front and \c Flipable.Back.
186 */
187 QDeclarative1Flipable::Side QDeclarative1Flipable::side() const
188 {
189     Q_D(const QDeclarative1Flipable);
190     if (d->dirtySceneTransform)
191         const_cast<QDeclarative1FlipablePrivate *>(d)->ensureSceneTransform();
192
193     return d->current;
194 }
195
196 // determination on the currently visible side of the flipable
197 // has to be done on the complete scene transform to give
198 // correct results.
199 void QDeclarative1FlipablePrivate::updateSceneTransformFromParent()
200 {
201     Q_Q(QDeclarative1Flipable);
202
203     QDeclarativeItemPrivate::updateSceneTransformFromParent();
204     QPointF p1(0, 0);
205     QPointF p2(1, 0);
206     QPointF p3(1, 1);
207
208     QPointF scenep1 = sceneTransform.map(p1);
209     QPointF scenep2 = sceneTransform.map(p2);
210     QPointF scenep3 = sceneTransform.map(p3);
211     p1 = q->mapToParent(p1);
212     p2 = q->mapToParent(p2);
213     p3 = q->mapToParent(p3);
214
215     qreal cross = (scenep1.x() - scenep2.x()) * (scenep3.y() - scenep2.y()) -
216                   (scenep1.y() - scenep2.y()) * (scenep3.x() - scenep2.x());
217
218     wantBackYFlipped = p1.x() >= p2.x();
219     wantBackXFlipped = p2.y() >= p3.y();
220
221     QDeclarative1Flipable::Side newSide;
222     if (cross > 0) {
223         newSide = QDeclarative1Flipable::Back;
224     } else {
225         newSide = QDeclarative1Flipable::Front;
226     }
227
228     if (newSide != current) {
229         current = newSide;
230         if (current == QDeclarative1Flipable::Back && back)
231             setBackTransform();
232         if (front)
233             front->setOpacity((current==QDeclarative1Flipable::Front)?1.:0.);
234         if (back)
235             back->setOpacity((current==QDeclarative1Flipable::Back)?1.:0.);
236         emit q->sideChanged();
237     }
238 }
239
240 /* Depends on the width/height of the back item, and so needs reevaulating
241    if those change.
242 */
243 void QDeclarative1FlipablePrivate::setBackTransform()
244 {
245     QTransform mat;
246     QGraphicsItemPrivate *dBack = QGraphicsItemPrivate::get(back);
247     mat.translate(dBack->width()/2,dBack->height()/2);
248     if (dBack->width() && wantBackYFlipped)
249         mat.rotate(180, Qt::YAxis);
250     if (dBack->height() && wantBackXFlipped)
251         mat.rotate(180, Qt::XAxis);
252     mat.translate(-dBack->width()/2,-dBack->height()/2);
253     back->setTransform(mat);
254 }
255
256
257
258 QT_END_NAMESPACE