diff options
Diffstat (limited to 'src/quick/items/qquickborderimage.cpp')
-rw-r--r-- | src/quick/items/qquickborderimage.cpp | 278 |
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" |