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