aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickborderimage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickborderimage.cpp')
-rw-r--r--src/quick/items/qquickborderimage.cpp278
1 files changed, 87 insertions, 191 deletions
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index b840328184..004f0491bd 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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 "qquickborderimage_p.h"
#include "qquickborderimage_p_p.h"
@@ -99,9 +63,8 @@ QT_BEGIN_NAMESPACE
\image qml-borderimage-normal-image.png
\endfloat
- An unscaled image is displayed using an Image. The \l border property is
- used to determine the parts of the image that will lie inside the unscaled corner
- areas and the parts that will be stretched horizontally and vertically.
+ For comparison, an unscaled image is displayed using a simple Image item.
+ Here we have overlaid lines to show how we'd like to break it up with BorderImage:
\snippet qml/borderimage/normal-image.qml normal image
@@ -110,12 +73,15 @@ QT_BEGIN_NAMESPACE
\image qml-borderimage-scaled.png
\endfloat
- A BorderImage is used to display the image, and it is given a size that is
+ But when a BorderImage is used to display the image, the \l border property is
+ used to determine the parts of the image that will lie inside the unscaled corner
+ areas, and the parts that will be stretched horizontally and vertically.
+ Then, you can give it a size that is
larger than the original image. Since the \l horizontalTileMode property is set to
\l{BorderImage::horizontalTileMode}{BorderImage.Stretch}, the parts of image in
regions 2 and 8 are stretched horizontally. Since the \l verticalTileMode property
is set to \l{BorderImage::verticalTileMode}{BorderImage.Stretch}, the parts of image
- in regions 4 and 6 are stretched vertically.
+ in regions 4 and 6 are stretched vertically:
\snippet qml/borderimage/borderimage-scaled.qml scaled border image
@@ -128,17 +94,25 @@ QT_BEGIN_NAMESPACE
\l horizontalTileMode property set to \l{BorderImage::horizontalTileMode}{BorderImage.Repeat},
the parts of image in regions 2 and 8 are tiled so that they fill the space at the
top and bottom of the item. Similarly, the \l verticalTileMode property is set to
- \l{BorderImage::verticalTileMode}{BorderImage.Repeat}, the parts of image in regions
- 4 and 6 are tiled so that they fill the space at the left and right of the item.
+ \l{BorderImage::verticalTileMode}{BorderImage.Repeat}, so the parts of image in regions
+ 4 and 6 are tiled to fill the space at the left and right of the item:
\snippet qml/borderimage/borderimage-tiled.qml tiled border image
\clearfloat
+ \beginfloatleft
+ \image qml-borderimage-rounded.png
+ \endfloat
+
In some situations, the width of regions 2 and 8 may not be an exact multiple of the width
of the corresponding regions in the source image. Similarly, the height of regions 4 and 6
- may not be an exact multiple of the height of the corresponding regions. It can be useful
- to use \l{BorderImage::horizontalTileMode}{BorderImage.Round} instead of
- \l{BorderImage::horizontalTileMode}{BorderImage.Repeat} in cases like these.
+ may not be an exact multiple of the height of the corresponding regions. If you use
+ \l{BorderImage::horizontalTileMode}{BorderImage.Round} mode, it will choose an integer
+ number of tiles and shrink them to fit:
+
+ \snippet qml/borderimage/borderimage-rounded.qml tiled border image
+
+ \clearfloat
The Border Image example in \l{Qt Quick Examples - Image Elements} shows how a BorderImage
can be used to simulate a shadow effect on a rectangular item.
@@ -168,6 +142,7 @@ QT_BEGIN_NAMESPACE
QQuickBorderImage::QQuickBorderImage(QQuickItem *parent)
: QQuickImageBase(*(new QQuickBorderImagePrivate), parent)
{
+ connect(this, &QQuickImageBase::sourceSizeChanged, this, &QQuickBorderImage::sourceSizeChanged);
}
QQuickBorderImage::~QQuickBorderImage()
@@ -184,12 +159,10 @@ QQuickBorderImage::~QQuickBorderImage()
This property describes the status of image loading. It can be one of:
- \list
- \li BorderImage.Null - no image has been set
- \li BorderImage.Ready - the image has been loaded
- \li BorderImage.Loading - the image is currently being loaded
- \li BorderImage.Error - an error occurred while loading the image
- \endlist
+ \value BorderImage.Null No image has been set
+ \value BorderImage.Ready The image has been loaded
+ \value BorderImage.Loading The image is currently being loaded
+ \value BorderImage.Error An error occurred while loading the image
\sa progress
*/
@@ -295,83 +268,33 @@ void QQuickBorderImage::load()
Q_D(QQuickBorderImage);
if (d->url.isEmpty()) {
- d->pix.clear(this);
- d->status = Null;
- setImplicitSize(0, 0);
- emit statusChanged(d->status);
- if (d->progress != 0.0) {
- d->progress = 0.0;
- emit progressChanged(d->progress);
- }
- if (sourceSize() != d->oldSourceSize) {
- d->oldSourceSize = sourceSize();
- emit sourceSizeChanged();
- }
- pixmapChange();
- return;
+ loadEmptyUrl();
} else {
if (d->url.path().endsWith(QLatin1String("sci"))) {
- QString lf = QQmlFile::urlToLocalFileOrQrc(d->url);
+ const QQmlContext *context = qmlContext(this);
+ QString lf = QQmlFile::urlToLocalFileOrQrc(context ? context->resolvedUrl(d->url)
+ : d->url);
if (!lf.isEmpty()) {
QFile file(lf);
- file.open(QIODevice::ReadOnly);
- setGridScaledImage(QQuickGridScaledImage(&file));
- return;
+ if (!file.open(QIODevice::ReadOnly))
+ d->setStatus(Error);
+ else
+ setGridScaledImage(QQuickGridScaledImage(&file));
} else {
#if QT_CONFIG(qml_network)
- if (d->progress != 0.0) {
- d->progress = 0.0;
- emit progressChanged(d->progress);
- }
- d->status = Loading;
+ d->setProgress(0);
+ d->setStatus(Loading);
+
QNetworkRequest req(d->url);
d->sciReply = qmlEngine(this)->networkAccessManager()->get(req);
qmlobject_connect(d->sciReply, QNetworkReply, SIGNAL(finished()),
- this, QQuickBorderImage, SLOT(sciRequestFinished()))
+ this, QQuickBorderImage, SLOT(sciRequestFinished()));
#endif
}
} else {
- QQuickPixmap::Options options;
- if (d->async)
- options |= QQuickPixmap::Asynchronous;
- if (d->cache)
- options |= QQuickPixmap::Cache;
- d->pix.clear(this);
-
- const qreal targetDevicePixelRatio = (window() ? window()->effectiveDevicePixelRatio() : qGuiApp->devicePixelRatio());
- d->devicePixelRatio = 1.0;
-
- QUrl loadUrl = d->url;
- resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
- d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options);
-
- if (d->pix.isLoading()) {
- if (d->progress != 0.0) {
- d->progress = 0.0;
- emit progressChanged(d->progress);
- }
- d->status = Loading;
-
- static int thisRequestProgress = -1;
- static int thisRequestFinished = -1;
- if (thisRequestProgress == -1) {
- thisRequestProgress =
- QQuickImageBase::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
- thisRequestFinished =
- QQuickImageBase::staticMetaObject.indexOfSlot("requestFinished()");
- }
- d->pix.connectFinished(this, thisRequestFinished);
- d->pix.connectDownloadProgress(this, thisRequestProgress);
-
- update(); //pixmap may have invalidated texture, updatePaintNode needs to be called before the next repaint
- } else {
- requestFinished();
- return;
- }
+ loadPixmap(d->url, LoadPixmapOptions(HandleDPR | UseProviderOptions));
}
}
-
- emit statusChanged(d->status);
}
/*!
@@ -416,11 +339,9 @@ QQuickScaleGrid *QQuickBorderImage::border()
This property describes how to repeat or stretch the middle parts of the border image.
- \list
- \li BorderImage.Stretch - Scales the image to fit to the available area.
- \li BorderImage.Repeat - Tile the image until there is no more space. May crop the last image.
- \li BorderImage.Round - Like Repeat, but scales the images down to ensure that the last image is not cropped.
- \endlist
+ \value BorderImage.Stretch Scales the image to fit to the available area.
+ \value BorderImage.Repeat Tile the image until there is no more space. May crop the last image.
+ \value BorderImage.Round Like Repeat, but scales the images down to ensure that the last image is not cropped.
The default tile mode for each property is BorderImage.Stretch.
*/
@@ -460,8 +381,7 @@ void QQuickBorderImage::setGridScaledImage(const QQuickGridScaledImage& sci)
{
Q_D(QQuickBorderImage);
if (!sci.isValid()) {
- d->status = Error;
- emit statusChanged(d->status);
+ d->setStatus(Error);
} else {
QQuickScaleGrid *sg = border();
sg->setTop(sci.gridTop());
@@ -472,39 +392,7 @@ void QQuickBorderImage::setGridScaledImage(const QQuickGridScaledImage& sci)
d->verticalTileMode = sci.verticalTileRule();
d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl()));
-
- QQuickPixmap::Options options;
- if (d->async)
- options |= QQuickPixmap::Asynchronous;
- if (d->cache)
- options |= QQuickPixmap::Cache;
- d->pix.clear(this);
- d->pix.load(qmlEngine(this), d->sciurl, options);
-
- if (d->pix.isLoading()) {
- if (d->progress != 0.0) {
- d->progress = 0.0;
- emit progressChanged(d->progress);
- }
- if (d->status != Loading) {
- d->status = Loading;
- emit statusChanged(d->status);
- }
- static int thisRequestProgress = -1;
- static int thisRequestFinished = -1;
- if (thisRequestProgress == -1) {
- thisRequestProgress =
- QQuickBorderImage::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
- thisRequestFinished =
- QQuickBorderImage::staticMetaObject.indexOfSlot("requestFinished()");
- }
-
- d->pix.connectFinished(this, thisRequestFinished);
- d->pix.connectDownloadProgress(this, thisRequestProgress);
-
- } else {
- requestFinished();
- }
+ loadPixmap(d->sciurl);
}
}
@@ -512,55 +400,44 @@ void QQuickBorderImage::requestFinished()
{
Q_D(QQuickBorderImage);
- QSize impsize = d->pix.implicitSize();
- if (d->pix.isError()) {
- d->status = Error;
- qmlWarning(this) << d->pix.error();
- if (d->progress != 0) {
- d->progress = 0;
- emit progressChanged(d->progress);
- }
- } else {
- d->status = Ready;
- if (d->progress != 1.0) {
- d->progress = 1.0;
- emit progressChanged(d->progress);
- }
+ if (d->pendingPix != d->currentPix) {
+ std::swap(d->pendingPix, d->currentPix);
+ d->pendingPix->clear(this); // Clear the old image
}
+ const QSize impsize = d->currentPix->implicitSize();
setImplicitSize(impsize.width() / d->devicePixelRatio, impsize.height() / d->devicePixelRatio);
- emit statusChanged(d->status);
+
+ if (d->currentPix->isError()) {
+ qmlWarning(this) << d->currentPix->error();
+ d->setStatus(Error);
+ d->setProgress(0);
+ } else {
+ d->setStatus(Ready);
+ d->setProgress(1);
+ }
+
if (sourceSize() != d->oldSourceSize) {
d->oldSourceSize = sourceSize();
emit sourceSizeChanged();
}
+ if (d->frameCount != d->currentPix->frameCount()) {
+ d->frameCount = d->currentPix->frameCount();
+ emit frameCountChanged();
+ }
pixmapChange();
}
#if QT_CONFIG(qml_network)
-#define BORDERIMAGE_MAX_REDIRECT 16
-
void QQuickBorderImage::sciRequestFinished()
{
Q_D(QQuickBorderImage);
- d->redirectCount++;
- if (d->redirectCount < BORDERIMAGE_MAX_REDIRECT) {
- QVariant redirect = d->sciReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
- if (redirect.isValid()) {
- QUrl url = d->sciReply->url().resolved(redirect.toUrl());
- setSource(url);
- return;
- }
- }
- d->redirectCount=0;
-
if (d->sciReply->error() != QNetworkReply::NoError) {
- d->status = Error;
+ d->setStatus(Error);
d->sciReply->deleteLater();
d->sciReply = nullptr;
- emit statusChanged(d->status);
} else {
QQuickGridScaledImage sci(d->sciReply);
d->sciReply->deleteLater();
@@ -635,7 +512,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
{
Q_D(QQuickBorderImage);
- QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window());
+ QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->currentPix->textureFactory(), window());
if (!texture || width() <= 0 || height() <= 0) {
delete oldNode;
@@ -647,7 +524,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
bool updatePixmap = d->pixmapChanged;
d->pixmapChanged = false;
if (!node) {
- node = d->sceneGraphContext()->createInternalImageNode();
+ node = d->sceneGraphContext()->createInternalImageNode(d->sceneGraphRenderContext());
updatePixmap = true;
}
@@ -660,7 +537,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
QRectF innerSourceRect;
QRectF subSourceRect;
d->calculateRects(d->border,
- QSize(d->pix.width(), d->pix.height()), QSizeF(width(), height()),
+ QSize(d->currentPix->width(), d->currentPix->height()), QSizeF(width(), height()),
d->horizontalTileMode, d->verticalTileMode, d->devicePixelRatio,
&targetRect, &innerTargetRect,
&innerSourceRect, &subSourceRect);
@@ -669,7 +546,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);
@@ -693,6 +570,25 @@ void QQuickBorderImage::pixmapChange()
update();
}
+/*!
+ \qmlproperty int QtQuick::BorderImage::currentFrame
+ \qmlproperty int QtQuick::BorderImage::frameCount
+ \since 5.14
+
+ currentFrame is the frame that is currently visible. The default is \c 0.
+ You can set it to a number between \c 0 and \c {frameCount - 1} to display a
+ different frame, if the image contains multiple frames.
+
+ frameCount is the number of frames in the image. Most images have only one frame.
+*/
+
+/*!
+ \qmlproperty bool QtQuick::BorderImage::retainWhileLoading
+ \since 6.8
+
+ \include qquickimage.cpp qml-image-retainwhileloading
+ */
+
QT_END_NAMESPACE
#include "moc_qquickborderimage_p.cpp"