diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2021-05-26 14:31:12 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2021-05-27 18:25:15 +0200 |
commit | 17babc38b42adf577d6ebf33018f9e809263cc6d (patch) | |
tree | 23ee3aeaa5090164c940f1e0a324051dae568eb3 /src | |
parent | a317f5b31dc88b2c1ad09b99c7013d8d14b4e316 (diff) |
Add the possibility of flipping vertically to Image
[ChangeLog][QtQuick] Added mirrorVertically to Image to allow vertically
mirroring an image. This complements the existing mirror property that
performs a horizontal flip.
Task-number: QTBUG-93972
Change-Id: Ib571ec27c299d918976d833fb8c8f57d2e385a56
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/quick/items/qquickborderimage.cpp | 2 | ||||
-rw-r--r-- | src/quick/items/qquickimage.cpp | 20 | ||||
-rw-r--r-- | src/quick/items/qquickimagebase.cpp | 26 | ||||
-rw-r--r-- | src/quick/items/qquickimagebase_p.h | 5 | ||||
-rw-r--r-- | src/quick/items/qquickimagebase_p_p.h | 6 | ||||
-rw-r--r-- | src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp | 26 | ||||
-rw-r--r-- | src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h | 5 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgadaptationlayer_p.h | 2 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgbasicinternalimagenode.cpp | 33 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgbasicinternalimagenode_p.h | 8 |
10 files changed, 99 insertions, 34 deletions
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp index b8828d23ba..9a1c3cc1c1 100644 --- a/src/quick/items/qquickborderimage.cpp +++ b/src/quick/items/qquickborderimage.cpp @@ -593,7 +593,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat node->setInnerSourceRect(innerSourceRect); node->setInnerTargetRect(innerTargetRect); node->setSubSourceRect(subSourceRect); - node->setMirror(d->mirror); + node->setMirror(d->mirrorHorizontally, d->mirrorVertically); node->setMipmapFiltering(QSGTexture::None); node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest); diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index 08f8825c30..c9edfebf2a 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -133,10 +133,15 @@ QQuickImagePrivate::QQuickImagePrivate() defined. Different texture compression tools have different defaults and options of when to perform vertical flipping of the input image. If an image from a texture file appears upside down, flipping may need to be toggled in the asset conditioning process. Alternatively, the - Image element itself can be flipped by setting the transform property, for example like this: + Image element itself can be flipped by either applying a suitable transformation via the + transform property or, more conveniently, by setting the mirrorVertically property: \badcode transform: [ Translate { y: -myImage.height }, Scale { yScale: -1 } ] \endcode + or + \badcode + mirrorVertically: true + \endcode \note Semi-transparent original images require alpha pre-multiplication prior to texture compression in order to be correctly displayed in Qt @@ -577,6 +582,17 @@ qreal QQuickImage::paintedHeight() const */ /*! + \qmlproperty bool QtQuick::Image::mirrorVertically + + This property holds whether the image should be vertically inverted + (effectively displaying a mirrored image). + + The default value is false. + + \since 6.2 +*/ + +/*! \qmlproperty enumeration QtQuick::Image::horizontalAlignment \qmlproperty enumeration QtQuick::Image::verticalAlignment @@ -836,7 +852,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) node->setTargetRect(targetRect); node->setInnerTargetRect(targetRect); node->setSubSourceRect(nsrect); - node->setMirror(d->mirror); + node->setMirror(d->mirrorHorizontally, d->mirrorVertically); node->setAntialiasing(d->antialiasing); node->update(); diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp index 750b71b25e..03de0bb524 100644 --- a/src/quick/items/qquickimagebase.cpp +++ b/src/quick/items/qquickimagebase.cpp @@ -217,10 +217,10 @@ QImage QQuickImageBase::image() const void QQuickImageBase::setMirror(bool mirror) { Q_D(QQuickImageBase); - if (mirror == d->mirror) + if (mirror == d->mirrorHorizontally) return; - d->mirror = mirror; + d->mirrorHorizontally = mirror; if (isComponentComplete()) update(); @@ -231,7 +231,27 @@ void QQuickImageBase::setMirror(bool mirror) bool QQuickImageBase::mirror() const { Q_D(const QQuickImageBase); - return d->mirror; + return d->mirrorHorizontally; +} + +void QQuickImageBase::setMirrorVertically(bool mirror) +{ + Q_D(QQuickImageBase); + if (mirror == d->mirrorVertically) + return; + + d->mirrorVertically = mirror; + + if (isComponentComplete()) + update(); + + emit mirrorVerticallyChanged(); +} + +bool QQuickImageBase::mirrorVertically() const +{ + Q_D(const QQuickImageBase); + return d->mirrorVertically; } void QQuickImageBase::setCurrentFrame(int frame) diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h index 9265792be1..06be96dae7 100644 --- a/src/quick/items/qquickimagebase_p.h +++ b/src/quick/items/qquickimagebase_p.h @@ -69,6 +69,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImageBase : public QQuickImplicitSizeItem Q_PROPERTY(bool cache READ cache WRITE setCache NOTIFY cacheChanged) Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize RESET resetSourceSize NOTIFY sourceSizeChanged) Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged) + Q_PROPERTY(bool mirrorVertically READ mirrorVertically WRITE setMirrorVertically NOTIFY mirrorVerticallyChanged REVISION(6, 2)) Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged REVISION(2, 14)) Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged REVISION(2, 14)) Q_PROPERTY(QColorSpace colorSpace READ colorSpace WRITE setColorSpace NOTIFY colorSpaceChanged REVISION(2, 15)) @@ -116,6 +117,9 @@ public: virtual void setMirror(bool mirror); bool mirror() const; + virtual void setMirrorVertically(bool mirror); + bool mirrorVertically() const; + virtual void setCurrentFrame(int frame); virtual int currentFrame() const; @@ -145,6 +149,7 @@ Q_SIGNALS: Q_REVISION(2, 14) void frameCountChanged(); Q_REVISION(2, 15) void sourceClipRectChanged(); Q_REVISION(2, 15) void colorSpaceChanged(); + Q_REVISION(6, 2) void mirrorVerticallyChanged(); protected: void loadEmptyUrl(); diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h index ebb7568caf..73b05272d4 100644 --- a/src/quick/items/qquickimagebase_p_p.h +++ b/src/quick/items/qquickimagebase_p_p.h @@ -72,7 +72,8 @@ public: frameCount(0), async(false), cache(true), - mirror(false), + mirrorHorizontally(false), + mirrorVertically(false), oldAutoTransform(false) { } @@ -93,7 +94,8 @@ public: int frameCount; bool async : 1; bool cache : 1; - bool mirror: 1; + bool mirrorHorizontally: 1; + bool mirrorVertically : 1; bool oldAutoTransform : 1; }; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp index f237fa26d4..f238f85f06 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp @@ -312,7 +312,8 @@ QSGSoftwareInternalImageNode::QSGSoftwareInternalImageNode() : m_innerSourceRect(0, 0, 1, 1) , m_subSourceRect(0, 0, 1, 1) , m_texture(nullptr) - , m_mirror(false) + , m_mirrorHorizontally(false) + , m_mirrorVertically(false) , m_textureIsLayer(false) , m_smooth(true) , m_tileHorizontal(false) @@ -364,13 +365,14 @@ void QSGSoftwareInternalImageNode::setTexture(QSGTexture *texture) markDirty(DirtyMaterial); } -void QSGSoftwareInternalImageNode::setMirror(bool mirror) +void QSGSoftwareInternalImageNode::setMirror(bool mirrorHorizontally, bool mirrorVertically) { - if (m_mirror != mirror) { - m_mirror = mirror; - m_cachedMirroredPixmapIsDirty = true; - markDirty(DirtyMaterial); - } + if (mirrorHorizontally == m_mirrorHorizontally && mirrorVertically == m_mirrorVertically) + return; + m_mirrorHorizontally = mirrorHorizontally; + m_mirrorVertically = mirrorVertically; + m_cachedMirroredPixmapIsDirty = true; + markDirty(DirtyMaterial); } void QSGSoftwareInternalImageNode::setMipmapFiltering(QSGTexture::Filtering /*filtering*/) @@ -410,11 +412,11 @@ void QSGSoftwareInternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrap void QSGSoftwareInternalImageNode::update() { if (m_cachedMirroredPixmapIsDirty) { - if (m_mirror || m_textureIsLayer) { + if (m_mirrorHorizontally || m_mirrorVertically || m_textureIsLayer) { QTransform transform( - (m_mirror ? -1 : 1), 0, - 0 , (m_textureIsLayer ? -1 :1), - 0 , 0 + (m_mirrorHorizontally ? -1 : 1), 0, + 0 , (m_textureIsLayer ? -1 : 1) * (m_mirrorVertically ? -1 : 1), + 0 , 0 ); m_cachedMirroredPixmap = pixmap().transformed(transform); } else { @@ -457,7 +459,7 @@ void QSGSoftwareInternalImageNode::paint(QPainter *painter) // Disable antialiased clipping. It causes transformed tiles to have gaps. painter->setRenderHint(QPainter::Antialiasing, false); - const QPixmap &pm = m_mirror || m_textureIsLayer ? m_cachedMirroredPixmap : pixmap(); + const QPixmap &pm = m_mirrorHorizontally || m_mirrorVertically || m_textureIsLayer ? m_cachedMirroredPixmap : pixmap(); if (m_innerTargetRect != m_targetRect) { // border image diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h index af912e1a3f..fadd6428dc 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h @@ -113,7 +113,7 @@ public: void setInnerSourceRect(const QRectF &rect) override; void setSubSourceRect(const QRectF &rect) override; void setTexture(QSGTexture *texture) override; - void setMirror(bool mirror) override; + void setMirror(bool mirrorHorizontally, bool mirrorVertically) override; void setMipmapFiltering(QSGTexture::Filtering filtering) override; void setFiltering(QSGTexture::Filtering filtering) override; void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) override; @@ -137,7 +137,8 @@ private: QPointer<QSGTexture> m_texture; QPixmap m_cachedMirroredPixmap; - bool m_mirror; + bool m_mirrorHorizontally; + bool m_mirrorVertically; bool m_textureIsLayer; bool m_smooth; bool m_tileHorizontal; diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h index 284239e3c7..ee0dc95945 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -163,7 +163,7 @@ public: virtual void setSubSourceRect(const QRectF &rect) = 0; virtual void setTexture(QSGTexture *texture) = 0; virtual void setAntialiasing(bool antialiasing) { Q_UNUSED(antialiasing); } - virtual void setMirror(bool mirror) = 0; + virtual void setMirror(bool horizontally, bool vertically) = 0; virtual void setMipmapFiltering(QSGTexture::Filtering filtering) = 0; virtual void setFiltering(QSGTexture::Filtering filtering) = 0; virtual void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) = 0; diff --git a/src/quick/scenegraph/qsgbasicinternalimagenode.cpp b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp index d8efda1ecc..1e175b9fac 100644 --- a/src/quick/scenegraph/qsgbasicinternalimagenode.cpp +++ b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp @@ -69,7 +69,8 @@ QSGBasicInternalImageNode::QSGBasicInternalImageNode() : m_innerSourceRect(0, 0, 1, 1) , m_subSourceRect(0, 0, 1, 1) , m_antialiasing(false) - , m_mirror(false) + , m_mirrorHorizontally(false) + , m_mirrorVertically(false) , m_dirtyGeometry(false) , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) , m_dynamicTexture(nullptr) @@ -142,11 +143,12 @@ void QSGBasicInternalImageNode::setAntialiasing(bool antialiasing) m_dirtyGeometry = true; } -void QSGBasicInternalImageNode::setMirror(bool mirror) +void QSGBasicInternalImageNode::setMirror(bool mirrorHorizontally, bool mirrorVertically) { - if (mirror == m_mirror) + if (mirrorHorizontally == m_mirrorHorizontally && mirrorVertically == m_mirrorVertically) return; - m_mirror = mirror; + m_mirrorHorizontally = mirrorHorizontally; + m_mirrorVertically = mirrorVertically; m_dirtyGeometry = true; } @@ -221,7 +223,8 @@ QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect, const QRectF &innerSourceRect, const QRectF &subSourceRect, QSGGeometry *geometry, - bool mirror, + bool mirrorHorizontally, + bool mirrorVertically, bool antialiasing) { int floorLeft = qFloor(subSourceRect.left()); @@ -282,7 +285,7 @@ QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect, xs += 2; } Q_ASSERT(xs == xData.data() + xData.size()); - if (mirror) { + if (mirrorHorizontally) { float leftPlusRight = targetRect.left() + targetRect.right(); int count = xData.size(); xs = xData.data(); @@ -323,6 +326,15 @@ QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect, ys += 2; } Q_ASSERT(ys == yData.data() + yData.size()); + if (mirrorVertically) { + float topPlusBottom = targetRect.top() + targetRect.bottom(); + int count = yData.size(); + ys = yData.data(); + for (int i = 0; i < (count >> 1); ++i) + qSwap(ys[i], ys[count - 1 - i]); + for (int i = 0; i < count; ++i) + ys[i].y = topPlusBottom - ys[i].y; + } QSGGeometry::Type indexType = QSGGeometry::UnsignedShortType; // We can handled up to 0xffff indices, but keep the limit lower here to @@ -530,11 +542,16 @@ void QSGBasicInternalImageNode::updateGeometry() sr = QRectF(m_subSourceRect.left() - floorLeft, m_subSourceRect.top() - floorTop, m_subSourceRect.width(), m_subSourceRect.height()); } - if (m_mirror) { + if (m_mirrorHorizontally) { qreal oldLeft = sr.left(); sr.setLeft(sr.right()); sr.setRight(oldLeft); } + if (m_mirrorVertically) { + qreal oldTop = sr.top(); + sr.setTop(sr.bottom()); + sr.setBottom(oldTop); + } if (m_antialiasing) { QSGGeometry *g = geometry(); @@ -580,7 +597,7 @@ void QSGBasicInternalImageNode::updateGeometry() QSGGeometry *g = geometry(); g = updateGeometry(m_targetRect, m_innerTargetRect, sourceRect, innerSourceRect, m_subSourceRect, - g, m_mirror, m_antialiasing); + g, m_mirrorHorizontally, m_mirrorVertically, m_antialiasing); if (g != geometry()) { setGeometry(g); setFlag(OwnsGeometry, true); diff --git a/src/quick/scenegraph/qsgbasicinternalimagenode_p.h b/src/quick/scenegraph/qsgbasicinternalimagenode_p.h index a5689b20aa..1c2bd2ff4e 100644 --- a/src/quick/scenegraph/qsgbasicinternalimagenode_p.h +++ b/src/quick/scenegraph/qsgbasicinternalimagenode_p.h @@ -66,7 +66,7 @@ public: void setSubSourceRect(const QRectF &rect) override; void setTexture(QSGTexture *texture) override; void setAntialiasing(bool antialiasing) override; - void setMirror(bool mirror) override; + void setMirror(bool mirrorHorizontally, bool mirrorVertically) override; void update() override; void preprocess() override; @@ -76,7 +76,8 @@ public: const QRectF &innerSourceRect, const QRectF &subSourceRect, QSGGeometry *geometry, - bool mirror = false, + bool mirrorHorizontally = false, + bool mirrorVertically = false, bool antialiasing = false); protected: @@ -94,7 +95,8 @@ protected: QRectF m_subSourceRect; uint m_antialiasing : 1; - uint m_mirror : 1; + uint m_mirrorHorizontally : 1; + uint m_mirrorVertically : 1; uint m_dirtyGeometry : 1; QSGGeometry m_geometry; |