aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickflipable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickflipable.cpp')
-rw-r--r--src/quick/items/qquickflipable.cpp90
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)