src/declarative/graphicsitems/qdeclarativeflipable.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/declarative/graphicsitems/qdeclarativeflipable.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativeflipable_p.h"
+
+#include "private/qdeclarativeitem_p.h"
+#include "private/qdeclarativeguard_p.h"
+
+#include <qdeclarativeinfo.h>
+
+#include <QtGui/qgraphicstransform.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeFlipablePrivate : public QDeclarativeItemPrivate
+{
+    Q_DECLARE_PUBLIC(QDeclarativeFlipable)
+public:
+    QDeclarativeFlipablePrivate() : current(QDeclarativeFlipable::Front), front(0), back(0) {}
+
+    void updateSceneTransformFromParent();
+    void setBackTransform();
+
+    QDeclarativeFlipable::Side current;
+    QDeclarativeGuard<QGraphicsObject> front;
+    QDeclarativeGuard<QGraphicsObject> back;
+
+    bool wantBackXFlipped;
+    bool wantBackYFlipped;
+};
+
+/*!
+    \qmlclass Flipable QDeclarativeFlipable
+    \since 4.7
+    \brief The Flipable item provides a surface that can be flipped.
+    \inherits Item
+
+    Flipable is an item that can be visibly "flipped" between its front and
+    back sides. It is used together with Rotation and State/Transition to
+    produce a flipping effect.
+
+    Here is a Flipable that flips whenever it is clicked:
+
+    \snippet doc/src/snippets/declarative/flipable.qml 0
+
+    \image flipable.gif
+
+    The Rotation element is used to specify the angle and axis of the flip,
+    and the State defines the changes in angle which produce the flipping
+    effect. Finally, the Transition creates the animation that changes the
+    angle over one second.
+*/
+
+/*!
+    \internal
+    \class QDeclarativeFlipable
+    \brief The Flipable item provides a surface that can be flipped.
+
+    Flipable is an item that can be visibly "flipped" between its front and
+    back sides.
+*/
+
+QDeclarativeFlipable::QDeclarativeFlipable(QDeclarativeItem *parent)
+: QDeclarativeItem(*(new QDeclarativeFlipablePrivate), parent)
+{
+}
+
+QDeclarativeFlipable::~QDeclarativeFlipable()
+{
+}
+
+/*!
+  \qmlproperty Item Flipable::front
+  \qmlproperty Item Flipable::back
+
+  The front and back sides of the flipable.
+*/
+
+QGraphicsObject *QDeclarativeFlipable::front()
+{
+    Q_D(const QDeclarativeFlipable);
+    return d->front;
+}
+
+void QDeclarativeFlipable::setFront(QGraphicsObject *front)
+{
+    Q_D(QDeclarativeFlipable);
+    if (d->front) {
+        qmlInfo(this) << tr("front is a write-once property");
+        return;
+    }
+    d->front = front;
+    d->front->setParentItem(this);
+    if (Back == d->current)
+        d->front->setOpacity(0.);
+}
+
+QGraphicsObject *QDeclarativeFlipable::back()
+{
+    Q_D(const QDeclarativeFlipable);
+    return d->back;
+}
+
+void QDeclarativeFlipable::setBack(QGraphicsObject *back)
+{
+    Q_D(QDeclarativeFlipable);
+    if (d->back) {
+        qmlInfo(this) << tr("back is a write-once property");
+        return;
+    }
+    d->back = back;
+    d->back->setParentItem(this);
+    if (Front == d->current)
+        d->back->setOpacity(0.);
+    connect(back, SIGNAL(widthChanged()),
+            this, SLOT(retransformBack()));
+    connect(back, SIGNAL(heightChanged()),
+            this, SLOT(retransformBack()));
+}
+
+void QDeclarativeFlipable::retransformBack()
+{
+    Q_D(QDeclarativeFlipable);
+    if (d->current == QDeclarativeFlipable::Back && d->back)
+        d->setBackTransform();
+}
+
+/*!
+  \qmlproperty enumeration Flipable::side
+
+  The side of the Flippable currently visible. Possible values are \c
+  Flippable.Front and \c Flippable.Back.
+*/
+QDeclarativeFlipable::Side QDeclarativeFlipable::side() const
+{
+    Q_D(const QDeclarativeFlipable);
+    if (d->dirtySceneTransform)
+        const_cast<QDeclarativeFlipablePrivate *>(d)->ensureSceneTransform();
+
+    return d->current;
+}
+
+// determination on the currently visible side of the flipable
+// has to be done on the complete scene transform to give
+// correct results.
+void QDeclarativeFlipablePrivate::updateSceneTransformFromParent()
+{
+    Q_Q(QDeclarativeFlipable);
+
+    QDeclarativeItemPrivate::updateSceneTransformFromParent();
+    QPointF p1(0, 0);
+    QPointF p2(1, 0);
+    QPointF p3(1, 1);
+
+    QPointF scenep1 = sceneTransform.map(p1);
+    QPointF scenep2 = sceneTransform.map(p2);
+    QPointF scenep3 = sceneTransform.map(p3);
+    p1 = q->mapToParent(p1);
+    p2 = q->mapToParent(p2);
+    p3 = q->mapToParent(p3);
+
+    qreal cross = (scenep1.x() - scenep2.x()) * (scenep3.y() - scenep2.y()) -
+                  (scenep1.y() - scenep2.y()) * (scenep3.x() - scenep2.x());
+
+    wantBackYFlipped = p1.x() >= p2.x();
+    wantBackXFlipped = p2.y() >= p3.y();
+
+    QDeclarativeFlipable::Side newSide;
+    if (cross > 0) {
+        newSide = QDeclarativeFlipable::Back;
+    } else {
+        newSide = QDeclarativeFlipable::Front;
+    }
+
+    if (newSide != current) {
+        current = newSide;
+        if (current == QDeclarativeFlipable::Back && back)
+            setBackTransform();
+        if (front)
+            front->setOpacity((current==QDeclarativeFlipable::Front)?1.:0.);
+        if (back)
+            back->setOpacity((current==QDeclarativeFlipable::Back)?1.:0.);
+        emit q->sideChanged();
+    }
+}
+
+/* Depends on the width/height of the back item, and so needs reevaulating
+   if those change.
+*/
+void QDeclarativeFlipablePrivate::setBackTransform()
+{
+    QTransform mat;
+    QGraphicsItemPrivate *dBack = QGraphicsItemPrivate::get(back);
+    mat.translate(dBack->width()/2,dBack->height()/2);
+    if (dBack->width() && wantBackYFlipped)
+        mat.rotate(180, Qt::YAxis);
+    if (dBack->height() && wantBackXFlipped)
+        mat.rotate(180, Qt::XAxis);
+    mat.translate(-dBack->width()/2,-dBack->height()/2);
+    back->setTransform(mat);
+}
+
+QT_END_NAMESPACE