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