1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtQml module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qquickflipable_p.h"
43 #include "qquickitem_p.h"
45 #include <private/qqmlguard_p.h>
47 #include <QtQml/qqmlinfo.h>
51 // XXX todo - i think this needs work and a bit of a re-think
53 class QQuickLocalTransform : public QQuickTransform
57 QQuickLocalTransform(QObject *parent) : QQuickTransform(parent) {}
59 void setTransform(const QTransform &t) {
63 virtual void applyTo(QMatrix4x4 *matrix) const {
70 class QQuickFlipablePrivate : public QQuickItemPrivate
72 Q_DECLARE_PUBLIC(QQuickFlipable)
74 QQuickFlipablePrivate() : current(QQuickFlipable::Front), front(0), back(0), sideDirty(false) {}
76 virtual void transformChanged();
78 void setBackTransform();
80 QQuickFlipable::Side current;
81 QQmlGuard<QQuickLocalTransform> backTransform;
82 QQmlGuard<QQuickItem> front;
83 QQmlGuard<QQuickItem> back;
86 bool wantBackXFlipped;
87 bool wantBackYFlipped;
92 \instantiates QQuickFlipable
93 \inqmlmodule QtQuick 2
95 \ingroup qtquick-input
96 \ingroup qtquick-containers
97 \brief Provides a surface that can be flipped
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.
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.
106 \section1 Example Usage
108 The following example shows a Flipable item that flips whenever it is
109 clicked, rotating about the y-axis.
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.
118 \snippet qml/flipable/flipable.qml 0
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.
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.
131 \sa {declarative/ui-components/flipable}{Flipable example}
133 QQuickFlipable::QQuickFlipable(QQuickItem *parent)
134 : QQuickItem(*(new QQuickFlipablePrivate), parent)
138 QQuickFlipable::~QQuickFlipable()
143 \qmlproperty Item QtQuick2::Flipable::front
144 \qmlproperty Item QtQuick2::Flipable::back
146 The front and back sides of the flipable.
149 QQuickItem *QQuickFlipable::front()
151 Q_D(const QQuickFlipable);
155 void QQuickFlipable::setFront(QQuickItem *front)
159 qmlInfo(this) << tr("front is a write-once property");
163 d->front->setParentItem(this);
164 if (Back == d->current)
165 d->front->setOpacity(0.);
169 QQuickItem *QQuickFlipable::back()
171 Q_D(const QQuickFlipable);
175 void QQuickFlipable::setBack(QQuickItem *back)
179 qmlInfo(this) << tr("back is a write-once property");
185 d->back->setParentItem(this);
187 d->backTransform = new QQuickLocalTransform(d->back);
188 d->backTransform->prependToItem(d->back);
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()));
199 void QQuickFlipable::retransformBack()
202 if (d->current == QQuickFlipable::Back && d->back)
203 d->setBackTransform();
207 \qmlproperty enumeration QtQuick2::Flipable::side
209 The side of the Flipable currently visible. Possible values are \c
210 Flipable.Front and \c Flipable.Back.
212 QQuickFlipable::Side QQuickFlipable::side() const
214 Q_D(const QQuickFlipable);
216 const_cast<QQuickFlipablePrivate *>(d)->updateSide();
220 void QQuickFlipablePrivate::transformChanged()
229 QQuickItemPrivate::transformChanged();
232 void QQuickFlipable::updatePolish()
238 // determination on the currently visible side of the flipable
239 // has to be done on the complete scene transform to give
241 void QQuickFlipablePrivate::updateSide()
250 QTransform sceneTransform;
251 itemToParentTransform(sceneTransform);
257 QPointF scenep1 = sceneTransform.map(p1);
258 QPointF scenep2 = sceneTransform.map(p2);
259 QPointF scenep3 = sceneTransform.map(p3);
261 p1 = q->mapToParent(p1);
262 p2 = q->mapToParent(p2);
263 p3 = q->mapToParent(p3);
266 qreal cross = (scenep1.x() - scenep2.x()) * (scenep3.y() - scenep2.y()) -
267 (scenep1.y() - scenep2.y()) * (scenep3.x() - scenep2.x());
269 wantBackYFlipped = scenep1.x() >= scenep2.x();
270 wantBackXFlipped = scenep2.y() >= scenep3.y();
272 QQuickFlipable::Side newSide;
274 newSide = QQuickFlipable::Back;
276 newSide = QQuickFlipable::Front;
279 if (newSide != current) {
281 if (current == QQuickFlipable::Back && back)
284 front->setOpacity((current==QQuickFlipable::Front)?1.:0.);
286 back->setOpacity((current==QQuickFlipable::Back)?1.:0.);
287 emit q->sideChanged();
291 /* Depends on the width/height of the back item, and so needs reevaulating
294 void QQuickFlipablePrivate::setBackTransform()
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);
305 backTransform->setTransform(mat);
310 #include "qquickflipable.moc"