diff options
Diffstat (limited to 'src/quick/items/qquickflipable.cpp')
-rw-r--r-- | src/quick/items/qquickflipable.cpp | 136 |
1 files changed, 64 insertions, 72 deletions
diff --git a/src/quick/items/qquickflipable.cpp b/src/quick/items/qquickflipable.cpp index a338985622..2e48566295 100644 --- a/src/quick/items/qquickflipable.cpp +++ b/src/quick/items/qquickflipable.cpp @@ -1,48 +1,14 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQuick module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qquickflipable_p.h" #include "qquickitem_p.h" - +#include "qquicktranslate_p.h" #include <QtQml/qqmlinfo.h> +#include <QtCore/qpointer.h> + QT_BEGIN_NAMESPACE // XXX todo - i think this needs work and a bit of a re-think @@ -70,7 +36,7 @@ class QQuickFlipablePrivate : public QQuickItemPrivate public: QQuickFlipablePrivate() : current(QQuickFlipable::Front), front(nullptr), back(nullptr), sideDirty(false) {} - void transformChanged() override; + bool transformChanged(QQuickItem *transformedItem) override; void updateSide(); void setBackTransform(); @@ -219,7 +185,7 @@ QQuickFlipable::Side QQuickFlipable::side() const return d->current; } -void QQuickFlipablePrivate::transformChanged() +bool QQuickFlipablePrivate::transformChanged(QQuickItem *transformedItem) { Q_Q(QQuickFlipable); @@ -228,7 +194,7 @@ void QQuickFlipablePrivate::transformChanged() q->polish(); } - QQuickItemPrivate::transformChanged(); + return QQuickItemPrivate::transformChanged(transformedItem); } void QQuickFlipable::updatePolish() @@ -237,9 +203,20 @@ void QQuickFlipable::updatePolish() d->updateSide(); } -// determination on the currently visible side of the flipable -// has to be done on the complete scene transform to give -// correct results. +/*! \internal + Flipable must use the complete scene transform to correctly determine the + currently visible side. + + It must also be independent of camera distance, in case the contents are + too wide: for rotation transforms we simply call QMatrix4x4::rotate(), + whereas QQuickRotation::applyTo(QMatrix4x4*) calls + QMatrix4x4::projectedRotate() which by default assumes the camera distance + is 1024 virtual pixels. So for example if contents inside Flipable are to + be flipped around the y axis, and are wider than 1024*2, some of the + rendering goes behind the "camera". That's expected for rendering (since we + didn't provide API to change camera distance), but not ok for deciding when + to flip. +*/ void QQuickFlipablePrivate::updateSide() { Q_Q(QQuickFlipable); @@ -249,35 +226,50 @@ void QQuickFlipablePrivate::updateSide() sideDirty = false; - QTransform sceneTransform; - itemToParentTransform(sceneTransform); - - 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); -#if 0 - p1 = q->mapToParent(p1); - p2 = q->mapToParent(p2); - p3 = q->mapToParent(p3); -#endif - - qreal cross = (scenep1.x() - scenep2.x()) * (scenep3.y() - scenep2.y()) - - (scenep1.y() - scenep2.y()) * (scenep3.x() - scenep2.x()); - - wantBackYFlipped = scenep1.x() >= scenep2.x(); - wantBackXFlipped = scenep2.y() >= scenep3.y(); - - QQuickFlipable::Side newSide; - if (cross > 0) { - newSide = QQuickFlipable::Back; - } else { - newSide = QQuickFlipable::Front; + QMatrix4x4 sceneTransform; + + const qreal tx = x.value(); + const qreal ty = y.value(); + if (!qFuzzyIsNull(tx) || !qFuzzyIsNull(ty)) + sceneTransform.translate(tx, ty); + + for (const auto *transform : std::as_const(transforms)) { + if (const auto *rot = qobject_cast<const QQuickRotation *>(transform)) { + // rotation is a special case: we want to call rotate() instead of projectedRotate() + const auto angle = rot->angle(); + const auto axis = rot->axis(); + if (!(qFuzzyIsNull(angle) || axis.isNull())) { + sceneTransform.translate(rot->origin()); + sceneTransform.rotate(angle, axis.x(), axis.y(), axis.z()); + sceneTransform.translate(-rot->origin()); + } + } else { + transform->applyTo(&sceneTransform); + } } + const bool hasRotation = !qFuzzyIsNull(rotation()); + const bool hasScale = !qFuzzyCompare(scale(), 1); + if (hasScale || hasRotation) { + QPointF tp = computeTransformOrigin(); + sceneTransform.translate(tp.x(), tp.y()); + if (hasScale) + sceneTransform.scale(scale(), scale()); + if (hasRotation) + sceneTransform.rotate(rotation(), 0, 0, 1); + sceneTransform.translate(-tp.x(), -tp.y()); + } + + const QVector3D origin(sceneTransform.map(QPointF(0, 0))); + const QVector3D right = QVector3D(sceneTransform.map(QPointF(1, 0))) - origin; + const QVector3D top = QVector3D(sceneTransform.map(QPointF(0, 1))) - origin; + + wantBackYFlipped = right.x() < 0; + wantBackXFlipped = top.y() < 0; + + const QQuickFlipable::Side newSide = + QVector3D::crossProduct(top, right).z() > 0 ? QQuickFlipable::Back : QQuickFlipable::Front; + if (newSide != current) { current = newSide; if (current == QQuickFlipable::Back && back) |