diff options
Diffstat (limited to 'src/quick/items/qquickflipable.cpp')
-rw-r--r-- | src/quick/items/qquickflipable.cpp | 90 |
1 files changed, 59 insertions, 31 deletions
diff --git a/src/quick/items/qquickflipable.cpp b/src/quick/items/qquickflipable.cpp index d599618834..2e48566295 100644 --- a/src/quick/items/qquickflipable.cpp +++ b/src/quick/items/qquickflipable.cpp @@ -3,10 +3,12 @@ #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 @@ -201,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); @@ -213,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) |