aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2021-05-26 14:31:12 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2021-05-27 18:25:15 +0200
commit17babc38b42adf577d6ebf33018f9e809263cc6d (patch)
tree23ee3aeaa5090164c940f1e0a324051dae568eb3 /src
parenta317f5b31dc88b2c1ad09b99c7013d8d14b4e316 (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.cpp2
-rw-r--r--src/quick/items/qquickimage.cpp20
-rw-r--r--src/quick/items/qquickimagebase.cpp26
-rw-r--r--src/quick/items/qquickimagebase_p.h5
-rw-r--r--src/quick/items/qquickimagebase_p_p.h6
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp26
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h5
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h2
-rw-r--r--src/quick/scenegraph/qsgbasicinternalimagenode.cpp33
-rw-r--r--src/quick/scenegraph/qsgbasicinternalimagenode_p.h8
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;