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