diff options
Diffstat (limited to 'src/quick')
46 files changed, 536 insertions, 275 deletions
diff --git a/src/quick/accessible/qaccessiblequickview.cpp b/src/quick/accessible/qaccessiblequickview.cpp index 3bb40546be..41a02fc09c 100644 --- a/src/quick/accessible/qaccessiblequickview.cpp +++ b/src/quick/accessible/qaccessiblequickview.cpp @@ -91,7 +91,7 @@ QAccessibleInterface *QAccessibleQuickWindow::focusChild() const QAccessible::Role QAccessibleQuickWindow::role() const { - return QAccessible::Window; // FIXME + return QAccessible::Window; } QAccessible::State QAccessibleQuickWindow::state() const diff --git a/src/quick/designer/qquickdesignersupportitems.cpp b/src/quick/designer/qquickdesignersupportitems.cpp index 1c338fa79d..ed5fdf3a4a 100644 --- a/src/quick/designer/qquickdesignersupportitems.cpp +++ b/src/quick/designer/qquickdesignersupportitems.cpp @@ -192,19 +192,19 @@ static bool isCrashingType(const QQmlType &type) { QString name = type.qmlTypeName(); - if (type.qmlTypeName() == QLatin1String("QtMultimedia/MediaPlayer")) + if (name == QLatin1String("QtMultimedia/MediaPlayer")) return true; - if (type.qmlTypeName() == QLatin1String("QtMultimedia/Audio")) + if (name == QLatin1String("QtMultimedia/Audio")) return true; - if (type.qmlTypeName() == QLatin1String("QtQuick.Controls/MenuItem")) + if (name == QLatin1String("QtQuick.Controls/MenuItem")) return true; - if (type.qmlTypeName() == QLatin1String("QtQuick.Controls/Menu")) + if (name == QLatin1String("QtQuick.Controls/Menu")) return true; - if (type.qmlTypeName() == QLatin1String("QtQuick/Timer")) + if (name == QLatin1String("QtQuick/Timer")) return true; return false; diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc index 04682c9f33..418475f100 100644 --- a/src/quick/doc/src/qmltypereference.qdoc +++ b/src/quick/doc/src/qmltypereference.qdoc @@ -887,19 +887,3 @@ console.log(c + " " + d); // false true \sa {QML Basic Types} */ - -/*! -\qmlmodule QtTest 1.\QtMinorVersion -\title Qt Quick Test QML Types -\brief This module provides QML types to unit test your QML application -\ingroup qmlmodules - -You can import this module using the following statement: - -\qml \QtMinorVersion -import QtTest 1.\1 -\endqml - -For more information about how to use these types, see -\l{Qt Quick Test}. -*/ diff --git a/src/quick/handlers/handlers.pri b/src/quick/handlers/handlers.pri index 1258822f40..226cca22cb 100644 --- a/src/quick/handlers/handlers.pri +++ b/src/quick/handlers/handlers.pri @@ -10,6 +10,7 @@ HEADERS += \ $$PWD/qquickpointerhandler_p_p.h \ $$PWD/qquickpointhandler_p.h \ $$PWD/qquicksinglepointhandler_p.h \ + $$PWD/qquicksinglepointhandler_p_p.h \ $$PWD/qquicktaphandler_p.h \ $$PWD/qquickdragaxis_p.h diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp index ae162bed87..c0fa39fad3 100644 --- a/src/quick/handlers/qquicksinglepointhandler.cpp +++ b/src/quick/handlers/qquicksinglepointhandler.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qquicksinglepointhandler_p.h" +#include "qquicksinglepointhandler_p_p.h" QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH_TARGET) @@ -59,19 +60,25 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH_TARGET) */ QQuickSinglePointHandler::QQuickSinglePointHandler(QQuickItem *parent) - : QQuickPointerDeviceHandler(parent) + : QQuickPointerDeviceHandler(*(new QQuickSinglePointHandlerPrivate), parent) +{ +} + +QQuickSinglePointHandler::QQuickSinglePointHandler(QQuickSinglePointHandlerPrivate &dd, QQuickItem *parent) + : QQuickPointerDeviceHandler(dd, parent) { } bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event) { + Q_D(QQuickSinglePointHandler); if (!QQuickPointerDeviceHandler::wantsPointerEvent(event)) return false; if (event->device()->pointerType() != QQuickPointerDevice::Finger && (event->buttons() & acceptedButtons()) == 0 && (event->button() & acceptedButtons()) == 0) return false; - if (m_pointInfo.m_id) { + if (d->pointInfo.id()) { // We already know which one we want, so check whether it's there. // It's expected to be an update or a release. // If we no longer want it, cancel the grab. @@ -81,7 +88,7 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event) int c = event->pointCount(); for (int i = 0; i < c; ++i) { QQuickEventPoint *p = event->point(i); - const bool found = (p->pointId() == m_pointInfo.m_id); + const bool found = (p->pointId() == d->pointInfo.id()); if (found) missing = false; if (wantsEventPoint(p)) { @@ -91,10 +98,10 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event) } } if (missing) - qCWarning(DBG_TOUCH_TARGET) << this << "pointId" << hex << m_pointInfo.m_id + qCWarning(DBG_TOUCH_TARGET) << this << "pointId" << hex << d->pointInfo.id() << "is missing from current event, but was neither canceled nor released"; if (point) { - if (candidatePointCount == 1 || (candidatePointCount > 1 && m_ignoreAdditionalPoints)) { + if (candidatePointCount == 1 || (candidatePointCount > 1 && d->ignoreAdditionalPoints)) { point->setAccepted(); return true; } else { @@ -121,35 +128,37 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event) chosen->setAccepted(); } } - return m_pointInfo.m_id; + return d->pointInfo.id(); } void QQuickSinglePointHandler::handlePointerEventImpl(QQuickPointerEvent *event) { + Q_D(QQuickSinglePointHandler); QQuickPointerDeviceHandler::handlePointerEventImpl(event); - QQuickEventPoint *currentPoint = event->pointById(m_pointInfo.m_id); + QQuickEventPoint *currentPoint = event->pointById(d->pointInfo.id()); Q_ASSERT(currentPoint); - m_pointInfo.reset(currentPoint); + d->pointInfo.reset(currentPoint); handleEventPoint(currentPoint); if (currentPoint->state() == QQuickEventPoint::Released && (event->buttons() & acceptedButtons()) == Qt::NoButton) { setExclusiveGrab(currentPoint, false); - reset(); + d->reset(); } emit pointChanged(); } void QQuickSinglePointHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) { + Q_D(QQuickSinglePointHandler); if (grabber != this) return; switch (transition) { case QQuickEventPoint::GrabExclusive: - m_pointInfo.m_sceneGrabPosition = point->sceneGrabPosition(); + d->pointInfo.m_sceneGrabPosition = point->sceneGrabPosition(); setActive(true); QQuickPointerHandler::onGrabChanged(grabber, transition, point); break; case QQuickEventPoint::GrabPassive: - m_pointInfo.m_sceneGrabPosition = point->sceneGrabPosition(); + d->pointInfo.m_sceneGrabPosition = point->sceneGrabPosition(); QQuickPointerHandler::onGrabChanged(grabber, transition, point); break; case QQuickEventPoint::OverrideGrabPassive: @@ -160,32 +169,35 @@ void QQuickSinglePointHandler::onGrabChanged(QQuickPointerHandler *grabber, QQui case QQuickEventPoint::CancelGrabExclusive: // the grab is lost or relinquished, so the point is no longer relevant QQuickPointerHandler::onGrabChanged(grabber, transition, point); - reset(); + d->reset(); break; } } void QQuickSinglePointHandler::setIgnoreAdditionalPoints(bool v) { - m_ignoreAdditionalPoints = v; + Q_D(QQuickSinglePointHandler); + d->ignoreAdditionalPoints = v; } void QQuickSinglePointHandler::moveTarget(QPointF pos, QQuickEventPoint *point) { + Q_D(QQuickSinglePointHandler); target()->setPosition(pos); - m_pointInfo.m_scenePosition = point->scenePosition(); - m_pointInfo.m_position = target()->mapFromScene(m_pointInfo.m_scenePosition); + d->pointInfo.m_scenePosition = point->scenePosition(); + d->pointInfo.m_position = target()->mapFromScene(d->pointInfo.m_scenePosition); } void QQuickSinglePointHandler::setPointId(int id) { - m_pointInfo.m_id = id; + Q_D(QQuickSinglePointHandler); + d->pointInfo.m_id = id; } -void QQuickSinglePointHandler::reset() +QQuickHandlerPoint QQuickSinglePointHandler::point() const { - setActive(false); - m_pointInfo.reset(); + Q_D(const QQuickSinglePointHandler); + return d->pointInfo; } /*! @@ -196,4 +208,16 @@ void QQuickSinglePointHandler::reset() handled, this object is reset to default values (all coordinates are 0). */ +QQuickSinglePointHandlerPrivate::QQuickSinglePointHandlerPrivate() + : QQuickPointerDeviceHandlerPrivate() +{ +} + +void QQuickSinglePointHandlerPrivate::reset() +{ + Q_Q(QQuickSinglePointHandler); + q->setActive(false); + pointInfo.reset(); +} + QT_END_NAMESPACE diff --git a/src/quick/handlers/qquicksinglepointhandler_p.h b/src/quick/handlers/qquicksinglepointhandler_p.h index 7bf8eff999..edc55aaaf6 100644 --- a/src/quick/handlers/qquicksinglepointhandler_p.h +++ b/src/quick/handlers/qquicksinglepointhandler_p.h @@ -56,24 +56,29 @@ QT_BEGIN_NAMESPACE +class QQuickSinglePointHandlerPrivate; + class Q_QUICK_PRIVATE_EXPORT QQuickSinglePointHandler : public QQuickPointerDeviceHandler { Q_OBJECT Q_PROPERTY(QQuickHandlerPoint point READ point NOTIFY pointChanged) + public: explicit QQuickSinglePointHandler(QQuickItem *parent = nullptr); - QQuickHandlerPoint point() const { return m_pointInfo; } + QQuickHandlerPoint point() const; Q_SIGNALS: void pointChanged(); protected: + QQuickSinglePointHandler(QQuickSinglePointHandlerPrivate &dd, QQuickItem *parent); + bool wantsPointerEvent(QQuickPointerEvent *event) override; void handlePointerEventImpl(QQuickPointerEvent *event) override; virtual void handleEventPoint(QQuickEventPoint *point) = 0; - QQuickEventPoint *currentPoint(QQuickPointerEvent *ev) { return ev->pointById(m_pointInfo.m_id); } + QQuickEventPoint *currentPoint(QQuickPointerEvent *ev); void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) override; void setIgnoreAdditionalPoints(bool v = true); @@ -82,11 +87,7 @@ protected: void setPointId(int id); - void reset(); - -private: - QQuickHandlerPoint m_pointInfo; - bool m_ignoreAdditionalPoints = false; + Q_DECLARE_PRIVATE(QQuickSinglePointHandler) }; QT_END_NAMESPACE diff --git a/src/quick/handlers/qquicksinglepointhandler_p_p.h b/src/quick/handlers/qquicksinglepointhandler_p_p.h new file mode 100644 index 0000000000..1e66c25e14 --- /dev/null +++ b/src/quick/handlers/qquicksinglepointhandler_p_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +#ifndef QQUICKPOINTERSINGLEHANDLER_P_H +#define QQUICKPOINTERSINGLEHANDLER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickhandlerpoint_p.h" +#include "qquickpointerdevicehandler_p_p.h" +#include "qquicksinglepointhandler_p.h" + +QT_BEGIN_NAMESPACE + +class Q_QUICK_PRIVATE_EXPORT QQuickSinglePointHandlerPrivate : public QQuickPointerDeviceHandlerPrivate +{ + Q_DECLARE_PUBLIC(QQuickSinglePointHandler) + +public: + static QQuickSinglePointHandlerPrivate* get(QQuickSinglePointHandler *q) { return q->d_func(); } + static const QQuickSinglePointHandlerPrivate* get(const QQuickSinglePointHandler *q) { return q->d_func(); } + + QQuickSinglePointHandlerPrivate(); + + void reset(); + + QQuickHandlerPoint pointInfo; + bool ignoreAdditionalPoints = false; +}; + +QT_END_NAMESPACE + +#endif // QQUICKPOINTERSINGLEHANDLER_P_H + diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp index 9386676b7a..b4b6bd574e 100644 --- a/src/quick/handlers/qquicktaphandler.cpp +++ b/src/quick/handlers/qquicktaphandler.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qquicktaphandler_p.h" +#include "qquicksinglepointhandler_p_p.h" #include <qpa/qplatformtheme.h> #include <private/qguiapplication_p.h> #include <QtGui/qstylehints.h> @@ -317,7 +318,7 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QQuickEventPoint *poi setExclusiveGrab(point, false); // In case there is a filtering parent (Flickable), we should not give up the passive grab, // so that it can continue to filter future events. - reset(); + d_func()->reset(); emit pointChanged(); } } diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index 06dddabb65..14443a2f2f 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -735,7 +735,7 @@ void QQuickCanvasItem::updatePolish() for (auto it = animationCallbacks.cbegin(), end = animationCallbacks.cend(); it != end; ++it) { function = it.value().value(); - jsCall->args[0] = QV4::Value::fromUInt32(QDateTime::currentMSecsSinceEpoch() / 1000); + jsCall->args[0] = QV4::Value::fromUInt32(QDateTime::currentMSecsSinceEpoch()); function->call(jsCall); } } diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 66727e7845..de19a927a0 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -2999,7 +2999,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(const QV4::Fun if (argc >= 1) { QFontMetrics fm(r->d()->context()->state.font); - uint width = fm.width(argv[0].toQStringNoThrow()); + uint width = fm.horizontalAdvance(argv[0].toQStringNoThrow()); QV4::ScopedObject tm(scope, scope.engine->newObject()); tm->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("width"))).getPointer(), QV4::ScopedValue(scope, QV4::Value::fromDouble(width))); @@ -4079,10 +4079,10 @@ static int textAlignOffset(QQuickContext2D::TextAlignType value, const QFontMetr value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Right: QQuickContext2D::Left; switch (value) { case QQuickContext2D::Center: - offset = metrics.width(text)/2; + offset = metrics.horizontalAdvance(text) / 2; break; case QQuickContext2D::Right: - offset = metrics.width(text); + offset = metrics.horizontalAdvance(text); case QQuickContext2D::Left: default: break; diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h index f21fe94177..c54ed5ce71 100644 --- a/src/quick/items/qquickflickable_p.h +++ b/src/quick/items/qquickflickable_p.h @@ -117,7 +117,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickFlickable : public QQuickItem public: QQuickFlickable(QQuickItem *parent=nullptr); - ~QQuickFlickable(); + ~QQuickFlickable() override; QQmlListProperty<QObject> flickableData(); QQmlListProperty<QQuickItem> flickableChildren(); diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index 272d4a4df5..6638fbd3e8 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -2636,6 +2636,19 @@ bool QQuickGridViewPrivate::needsRefillForAddedOrRemovedIndex(int modelIndex) co \b Note: methods should only be called after the Component has completed. */ +/*! + \qmlmethod Item QtQuick::GridView::itemAtIndex(int index) + + Returns the item for \a index. If there is no item for that index, for example + because it has not been created yet, or because it has been panned out of + the visible area and removed from the cache, null is returned. + + \b Note: this method should only be called after the Component has completed. + The returned value should also not be stored since it can turn to null + as soon as control goes out of the calling scope, if the view releases that item. + + \since 5.13 +*/ /*! \qmlmethod QtQuick::GridView::forceLayout() diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index 49e5b7b1fa..2b71ad5f52 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -52,42 +52,28 @@ QT_BEGIN_NAMESPACE -class QQuickImageTextureProvider : public QSGTextureProvider +QQuickImageTextureProvider::QQuickImageTextureProvider() + : m_texture(nullptr) + , m_smooth(false) { - Q_OBJECT -public: - QQuickImageTextureProvider() - : m_texture(nullptr) - , m_smooth(false) - { - } +} - void updateTexture(QSGTexture *texture) { - if (m_texture == texture) - return; - m_texture = texture; - emit textureChanged(); - } +void QQuickImageTextureProvider::updateTexture(QSGTexture *texture) { + if (m_texture == texture) + return; + m_texture = texture; + emit textureChanged(); +} - QSGTexture *texture() const override { - if (m_texture) { - m_texture->setFiltering(m_smooth ? QSGTexture::Linear : QSGTexture::Nearest); - m_texture->setMipmapFiltering(m_mipmap ? QSGTexture::Linear : QSGTexture::None); - m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge); - m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge); - } - return m_texture; +QSGTexture *QQuickImageTextureProvider::texture() const { + if (m_texture) { + m_texture->setFiltering(m_smooth ? QSGTexture::Linear : QSGTexture::Nearest); + m_texture->setMipmapFiltering(m_mipmap ? QSGTexture::Linear : QSGTexture::None); + m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge); + m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge); } - - friend class QQuickImage; - - QSGTexture *m_texture; - bool m_smooth; - bool m_mipmap; -}; - -#include "qquickimage.moc" -#include "moc_qquickimage_p.cpp" + return m_texture; +} QQuickImagePrivate::QQuickImagePrivate() : fillMode(QQuickImage::Stretch) diff --git a/src/quick/items/qquickimage_p_p.h b/src/quick/items/qquickimage_p_p.h index afc33def0f..e2c467c311 100644 --- a/src/quick/items/qquickimage_p_p.h +++ b/src/quick/items/qquickimage_p_p.h @@ -53,10 +53,26 @@ #include "qquickimagebase_p_p.h" #include "qquickimage_p.h" +#include <QtQuick/qsgtextureprovider.h> QT_BEGIN_NAMESPACE -class QQuickImageTextureProvider; +class Q_QUICK_PRIVATE_EXPORT QQuickImageTextureProvider : public QSGTextureProvider +{ + Q_OBJECT +public: + QQuickImageTextureProvider(); + + void updateTexture(QSGTexture *texture); + + QSGTexture *texture() const override ; + + friend class QQuickImage; + + QSGTexture *m_texture; + bool m_smooth; + bool m_mipmap; +}; class Q_QUICK_PRIVATE_EXPORT QQuickImagePrivate : public QQuickImageBasePrivate { diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 9e32ccfee9..ec6bf5a1b8 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -4444,6 +4444,8 @@ void QQuickItem::update() When the scene graph processes the request, it will call updatePolish() on this item. + + \sa updatePolish(), QQuickTest::qIsPolishScheduled() */ void QQuickItem::polish() { diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index b2fcfb4307..ddd438e56d 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -472,6 +472,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) #if QT_CONFIG(quick_tableview) qmlRegisterType<QQuickTableView>(uri, 2, 12, "TableView"); #endif + + qmlRegisterUncreatableType<QQuickItemView, 13>(uri, 2, 13, itemViewName, itemViewMessage); + qmlRegisterType<QQuickPathView, 13>(uri, 2, 13, "PathView"); + qmlRegisterType<QQuickGridView, 13>(uri, 2, 13, "GridView"); } static void initResources() diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 8dafc16cf4..1f8a0de72b 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -951,6 +951,13 @@ QQuickItem *QQuickItemView::itemAt(qreal x, qreal y) const return item ? item->item : nullptr; } +QQuickItem *QQuickItemView::itemAtIndex(int index) const +{ + Q_D(const QQuickItemView); + const FxViewItem *item = d->visibleItem(index); + return item ? item->item : nullptr; +} + void QQuickItemView::forceLayout() { Q_D(QQuickItemView); diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h index 483fc1a09f..0a0da587b4 100644 --- a/src/quick/items/qquickitemview_p.h +++ b/src/quick/items/qquickitemview_p.h @@ -228,6 +228,7 @@ public: Q_INVOKABLE void positionViewAtIndex(int index, int mode); Q_INVOKABLE int indexAt(qreal x, qreal y) const; Q_INVOKABLE QQuickItem *itemAt(qreal x, qreal y) const; + Q_REVISION(13) Q_INVOKABLE QQuickItem *itemAtIndex(int index) const; Q_INVOKABLE void positionViewAtBeginning(); Q_INVOKABLE void positionViewAtEnd(); Q_REVISION(1) Q_INVOKABLE void forceLayout(); diff --git a/src/quick/items/qquickitemviewfxitem.cpp b/src/quick/items/qquickitemviewfxitem.cpp index f9c65967ea..60e9d7b115 100644 --- a/src/quick/items/qquickitemviewfxitem.cpp +++ b/src/quick/items/qquickitemviewfxitem.cpp @@ -45,9 +45,9 @@ QT_BEGIN_NAMESPACE QQuickItemViewFxItem::QQuickItemViewFxItem(QQuickItem *item, bool ownItem, QQuickItemChangeListener* changeListener) : item(item) - , ownItem(ownItem) , changeListener(changeListener) , transitionableItem(nullptr) + , ownItem(ownItem) , releaseAfterTransition(false) , trackGeom(false) { diff --git a/src/quick/items/qquickitemviewfxitem_p_p.h b/src/quick/items/qquickitemviewfxitem_p_p.h index 48ffe248bc..3bc5ba440c 100644 --- a/src/quick/items/qquickitemviewfxitem_p_p.h +++ b/src/quick/items/qquickitemviewfxitem_p_p.h @@ -94,13 +94,13 @@ public: virtual bool contains(qreal x, qreal y) const = 0; - int index = -1; QPointer<QQuickItem> item; - bool ownItem; QQuickItemChangeListener *changeListener; QQuickItemViewTransitionableItem *transitionableItem; - bool releaseAfterTransition; - bool trackGeom; + int index = -1; + bool ownItem : 1; + bool releaseAfterTransition : 1; + bool trackGeom : 1; }; QT_END_NAMESPACE diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 62cbfcef2b..2a59e50304 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -3513,6 +3513,20 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex */ /*! + \qmlmethod Item QtQuick::ListView::itemAtIndex(int index) + + Returns the item for \a index. If there is no item for that index, for example + because it has not been created yet, or because it has been panned out of + the visible area and removed from the cache, null is returned. + + \b Note: this method should only be called after the Component has completed. + The returned value should also not be stored since it can turn to null + as soon as control goes out of the calling scope, if the view releases that item. + + \since 5.13 +*/ + +/*! \qmlmethod QtQuick::ListView::forceLayout() Responding to changes in the model is usually batched to happen only once diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp index cad598d2c0..3aa00340b2 100644 --- a/src/quick/items/qquickopenglshadereffect.cpp +++ b/src/quick/items/qquickopenglshadereffect.cpp @@ -245,7 +245,11 @@ void QQuickOpenGLShaderEffectCommon::connectPropertySignals(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType) { - QQmlPropertyCache *propCache = QQmlData::ensurePropertyCache(qmlEngine(item), item); + auto engine = qmlEngine(item); + if (!engine) + return; + + QQmlPropertyCache *propCache = QQmlData::ensurePropertyCache(engine, item); for (int i = 0; i < uniformData[shaderType].size(); ++i) { if (signalMappers[shaderType].at(i) == 0) continue; @@ -317,7 +321,8 @@ void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code) { - QQmlPropertyCache *propCache = QQmlData::ensurePropertyCache(qmlEngine(item), item); + auto engine = qmlEngine(item); + QQmlPropertyCache *propCache = (engine) ? QQmlData::ensurePropertyCache(engine, item) : nullptr; int index = 0; int typeIndex = -1; int typeLength = 0; @@ -350,9 +355,11 @@ void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item, } else if (nameLength > srLen && qstrncmp("qt_SubRect_", s + nameIndex, srLen) == 0) { d.specialType = UniformData::SubRect; } else { - if (QQmlPropertyData *pd = propCache->property(QString::fromUtf8(d.name), nullptr, nullptr)) { - if (!pd->isFunction()) - d.propertyIndex = pd->coreIndex(); + if (propCache) { + if (QQmlPropertyData *pd = propCache->property(QString::fromUtf8(d.name), nullptr, nullptr)) { + if (!pd->isFunction()) + d.propertyIndex = pd->coreIndex(); + } } const int mappedId = uniformData[shaderType].size() | (shaderType << 16); mapper = new QtPrivate::MappedSlotObject([this, mappedId](){ diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp index 77ed8a659c..be8532bf64 100644 --- a/src/quick/items/qquickpathview.cpp +++ b/src/quick/items/qquickpathview.cpp @@ -1550,6 +1550,33 @@ QQuickItem *QQuickPathView::itemAt(qreal x, qreal y) const return nullptr; } +/*! + \qmlmethod Item QtQuick::QQuickPathView::itemAtIndex(int index) + + Returns the item for \a index. If there is no item for that index, for example + because it has not been created yet, or because it has been panned out of + the visible area and removed from the cache, null is returned. + + \b Note: this method should only be called after the Component has completed. + The returned value should also not be stored since it can turn to null + as soon as control goes out of the calling scope, if the view releases that item. + + \since 5.13 +*/ +QQuickItem *QQuickPathView::itemAtIndex(int index) const +{ + Q_D(const QQuickPathView); + if (!d->isValid()) + return nullptr; + + for (QQuickItem *item : d->items) { + if (index == d->model->indexOf(item, nullptr)) + return item; + } + + return nullptr; +} + QPointF QQuickPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercent) const { const auto pathLength = path->path().length(); diff --git a/src/quick/items/qquickpathview_p.h b/src/quick/items/qquickpathview_p.h index 0e237b7b74..66be7fa6ff 100644 --- a/src/quick/items/qquickpathview_p.h +++ b/src/quick/items/qquickpathview_p.h @@ -180,6 +180,7 @@ public: Q_INVOKABLE void positionViewAtIndex(int index, int mode); Q_INVOKABLE int indexAt(qreal x, qreal y) const; Q_INVOKABLE QQuickItem *itemAt(qreal x, qreal y) const; + Q_REVISION(13) Q_INVOKABLE QQuickItem *itemAtIndex(int index) const; static QQuickPathViewAttached *qmlAttachedProperties(QObject *); diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp index eaf0e4cf89..0b5bebb7ba 100644 --- a/src/quick/items/qquicktableview.cpp +++ b/src/quick/items/qquicktableview.cpp @@ -377,36 +377,6 @@ Q_LOGGING_CATEGORY(lcTableViewDelegateLifecycle, "qt.quick.tableview.lifecycle") static const Qt::Edge allTableEdges[] = { Qt::LeftEdge, Qt::RightEdge, Qt::TopEdge, Qt::BottomEdge }; -static QLine rectangleEdge(const QRect &rect, Qt::Edge tableEdge) -{ - switch (tableEdge) { - case Qt::LeftEdge: - return QLine(rect.topLeft(), rect.bottomLeft()); - case Qt::RightEdge: - return QLine(rect.topRight(), rect.bottomRight()); - case Qt::TopEdge: - return QLine(rect.topLeft(), rect.topRight()); - case Qt::BottomEdge: - return QLine(rect.bottomLeft(), rect.bottomRight()); - } - return QLine(); -} - -static QRect expandedRect(const QRect &rect, Qt::Edge edge, int increment) -{ - switch (edge) { - case Qt::LeftEdge: - return rect.adjusted(-increment, 0, 0, 0); - case Qt::RightEdge: - return rect.adjusted(0, 0, increment, 0); - case Qt::TopEdge: - return rect.adjusted(0, -increment, 0, 0); - case Qt::BottomEdge: - return rect.adjusted(0, 0, 0, increment); - } - return QRect(); -} - const QPoint QQuickTableViewPrivate::kLeft = QPoint(-1, 0); const QPoint QQuickTableViewPrivate::kRight = QPoint(1, 0); const QPoint QQuickTableViewPrivate::kUp = QPoint(0, -1); @@ -427,8 +397,8 @@ QQuickTableViewPrivate::~QQuickTableViewPrivate() QString QQuickTableViewPrivate::tableLayoutToString() const { return QString(QLatin1String("table cells: (%1,%2) -> (%3,%4), item count: %5, table rect: %6,%7 x %8,%9")) - .arg(loadedTable.topLeft().x()).arg(loadedTable.topLeft().y()) - .arg(loadedTable.bottomRight().x()).arg(loadedTable.bottomRight().y()) + .arg(leftColumn()).arg(topRow()) + .arg(rightColumn()).arg(bottomRow()) .arg(loadedItems.count()) .arg(loadedTableOuterRect.x()) .arg(loadedTableOuterRect.y()) @@ -489,7 +459,7 @@ void QQuickTableViewPrivate::updateContentWidth() } const qreal thresholdBeforeAdjust = 0.1; - int currentRightColumn = loadedTable.right(); + int currentRightColumn = rightColumn(); if (currentRightColumn > contentSizeBenchMarkPoint.x()) { contentSizeBenchMarkPoint.setX(currentRightColumn); @@ -526,7 +496,7 @@ void QQuickTableViewPrivate::updateContentHeight() } const qreal thresholdBeforeAdjust = 0.1; - int currentBottomRow = loadedTable.bottom(); + int currentBottomRow = bottomRow(); if (currentBottomRow > contentSizeBenchMarkPoint.y()) { contentSizeBenchMarkPoint.setY(currentBottomRow); @@ -561,7 +531,7 @@ void QQuickTableViewPrivate::enforceTableAtOrigin() bool layoutNeeded = false; const qreal flickMargin = 50; - if (loadedTable.x() == 0 && loadedTableOuterRect.x() > 0) { + if (leftColumn() == 0 && loadedTableOuterRect.x() > 0) { // The table is at the beginning, but not at the edge of the // content view. So move the table to origin. loadedTableOuterRect.moveLeft(0); @@ -569,15 +539,15 @@ void QQuickTableViewPrivate::enforceTableAtOrigin() } else if (loadedTableOuterRect.x() < 0) { // The table is outside the beginning of the content view. Move // the whole table inside, and make some room for flicking. - loadedTableOuterRect.moveLeft(loadedTable.x() == 0 ? 0 : flickMargin); + loadedTableOuterRect.moveLeft(leftColumn() == 0 ? 0 : flickMargin); layoutNeeded = true; } - if (loadedTable.y() == 0 && loadedTableOuterRect.y() > 0) { + if (topRow() == 0 && loadedTableOuterRect.y() > 0) { loadedTableOuterRect.moveTop(0); layoutNeeded = true; } else if (loadedTableOuterRect.y() < 0) { - loadedTableOuterRect.moveTop(loadedTable.y() == 0 ? 0 : flickMargin); + loadedTableOuterRect.moveTop(topRow() == 0 ? 0 : flickMargin); layoutNeeded = true; } @@ -589,8 +559,8 @@ void QQuickTableViewPrivate::enforceTableAtOrigin() void QQuickTableViewPrivate::updateAverageEdgeSize() { - int bottomCell = loadedTable.bottom(); - int rightCell = loadedTable.right(); + int bottomCell = bottomRow(); + int rightCell = rightColumn(); qreal accRowSpacing = bottomCell * cellSpacing.height(); qreal accColumnSpacing = rightCell * cellSpacing.width(); averageEdgeSize.setHeight((loadedTableOuterRect.bottom() - accRowSpacing) / (bottomCell + 1)); @@ -599,9 +569,11 @@ void QQuickTableViewPrivate::updateAverageEdgeSize() void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable() { - QRectF topLeftRect = loadedTableItem(loadedTable.topLeft())->geometry(); - QRectF bottomRightRect = loadedTableItem(loadedTable.bottomRight())->geometry(); - loadedTableOuterRect = topLeftRect.united(bottomRightRect); + const QPoint topLeft = QPoint(leftColumn(), topRow()); + const QPoint bottomRight = QPoint(rightColumn(), bottomRow()); + QRectF topLeftRect = loadedTableItem(topLeft)->geometry(); + QRectF bottomRightRect = loadedTableItem(bottomRight)->geometry(); + loadedTableOuterRect = QRectF(topLeftRect.topLeft(), bottomRightRect.bottomRight()); loadedTableInnerRect = QRectF(topLeftRect.bottomRight(), bottomRightRect.topLeft()); } @@ -609,18 +581,19 @@ void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest() { if (loadRequest.edge() == Qt::Edge(0)) { // No edge means we're loading the top-left item - loadedTable = QRect(loadRequest.firstCell(), loadRequest.lastCell()); + loadedColumns.insert(loadRequest.firstCell().x(), 0); + loadedRows.insert(loadRequest.firstCell().y(), 0); return; } switch (loadRequest.edge()) { case Qt::LeftEdge: - case Qt::TopEdge: - loadedTable.setTopLeft(loadRequest.firstCell()); - break; case Qt::RightEdge: + loadedColumns.insert(loadRequest.firstCell().x(), 0); + break; + case Qt::TopEdge: case Qt::BottomEdge: - loadedTable.setBottomRight(loadRequest.lastCell()); + loadedRows.insert(loadRequest.firstCell().y(), 0); break; } } @@ -776,23 +749,38 @@ void QQuickTableViewPrivate::unloadItems(const QLine &items) } } +int QQuickTableViewPrivate::nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge) +{ + switch (edge) { + case Qt::LeftEdge: + return leftColumn() - 1; + case Qt::RightEdge: + return rightColumn() + 1; + case Qt::TopEdge: + return topRow() - 1; + case Qt::BottomEdge: + return bottomRow() + 1; + } + return -1; +} + bool QQuickTableViewPrivate::canLoadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const { switch (tableEdge) { case Qt::LeftEdge: - if (loadedTable.topLeft().x() == 0) + if (leftColumn() == 0) return false; return loadedTableOuterRect.left() > fillRect.left() + cellSpacing.width(); case Qt::RightEdge: - if (loadedTable.bottomRight().x() >= tableSize.width() - 1) + if (rightColumn() == tableSize.width() - 1) return false; return loadedTableOuterRect.right() < fillRect.right() - cellSpacing.width(); case Qt::TopEdge: - if (loadedTable.topLeft().y() == 0) + if (topRow() == 0) return false; return loadedTableOuterRect.top() > fillRect.top() + cellSpacing.height(); case Qt::BottomEdge: - if (loadedTable.bottomRight().y() >= tableSize.height() - 1) + if (bottomRow() == tableSize.height() - 1) return false; return loadedTableOuterRect.bottom() < fillRect.bottom() - cellSpacing.height(); } @@ -806,19 +794,19 @@ bool QQuickTableViewPrivate::canUnloadTableEdge(Qt::Edge tableEdge, const QRectF // they are needed as anchor point for further layouting. switch (tableEdge) { case Qt::LeftEdge: - if (loadedTable.width() <= 1) + if (loadedColumns.count() <= 1) return false; return loadedTableInnerRect.left() <= fillRect.left(); case Qt::RightEdge: - if (loadedTable.width() <= 1) + if (loadedColumns.count() <= 1) return false; return loadedTableInnerRect.right() >= fillRect.right(); case Qt::TopEdge: - if (loadedTable.height() <= 1) + if (loadedRows.count() <= 1) return false; return loadedTableInnerRect.top() <= fillRect.top(); case Qt::BottomEdge: - if (loadedTable.height() <= 1) + if (loadedRows.count() <= 1) return false; return loadedTableInnerRect.bottom() >= fillRect.bottom(); } @@ -864,8 +852,10 @@ qreal QQuickTableViewPrivate::sizeHintForColumn(int column) { // Find the widest cell in the column, and return its width qreal columnWidth = 0; - for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) + for (auto r = loadedRows.cbegin(); r != loadedRows.cend(); ++r) { + const int row = r.key(); columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row))); + } return columnWidth; } @@ -874,8 +864,10 @@ qreal QQuickTableViewPrivate::sizeHintForRow(int row) { // Find the highest cell in the row, and return its height qreal rowHeight = 0; - for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) + for (auto c = loadedColumns.cbegin(); c != loadedColumns.cend(); ++c) { + const int column = c.key(); rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row))); + } return rowHeight; } @@ -902,7 +894,6 @@ void QQuickTableViewPrivate::calculateTableSize() qreal QQuickTableViewPrivate::resolveColumnWidth(int column) { - Q_TABLEVIEW_ASSERT(column >= loadedTable.left() && column <= loadedTable.right(), column); qreal columnWidth = -1; if (!columnWidthProvider.isUndefined()) { @@ -948,7 +939,6 @@ qreal QQuickTableViewPrivate::resolveColumnWidth(int column) qreal QQuickTableViewPrivate::resolveRowHeight(int row) { - Q_TABLEVIEW_ASSERT(row >= loadedTable.top() && row <= loadedTable.bottom(), row); qreal rowHeight = -1; if (!rowHeightProvider.isUndefined()) { @@ -1011,11 +1001,13 @@ void QQuickTableViewPrivate::relayoutTableItems() qreal nextColumnX = loadedTableOuterRect.x(); qreal nextRowY = loadedTableOuterRect.y(); - for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) { + for (auto c = loadedColumns.cbegin(); c != loadedColumns.cend(); ++c) { + const int column = c.key(); // Adjust the geometry of all cells in the current column const qreal width = resolveColumnWidth(column); - for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) { + for (auto r = loadedRows.cbegin(); r != loadedRows.cend(); ++r) { + const int row = r.key(); auto item = loadedTableItem(QPoint(column, row)); QRectF geometry = item->geometry(); geometry.moveLeft(nextColumnX); @@ -1026,11 +1018,13 @@ void QQuickTableViewPrivate::relayoutTableItems() nextColumnX += width + cellSpacing.width(); } - for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) { + for (auto r = loadedRows.cbegin(); r != loadedRows.cend(); ++r) { + const int row = r.key(); // Adjust the geometry of all cells in the current row const qreal height = resolveRowHeight(row); - for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) { + for (auto c = loadedColumns.cbegin(); c != loadedColumns.cend(); ++c) { + const int column = c.key(); auto item = loadedTableItem(QPoint(column, row)); QRectF geometry = item->geometry(); geometry.moveTop(nextRowY); @@ -1042,8 +1036,10 @@ void QQuickTableViewPrivate::relayoutTableItems() } if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) { - for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) { - for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) { + for (auto c = loadedColumns.cbegin(); c != loadedColumns.cend(); ++c) { + const int column = c.key(); + for (auto r = loadedRows.cbegin(); r != loadedRows.cend(); ++r) { + const int row = r.key(); QPoint cell = QPoint(column, row); qCDebug(lcTableViewDelegateLifecycle()) << "relayout item:" << cell << loadedTableItem(cell)->geometry(); } @@ -1053,11 +1049,12 @@ void QQuickTableViewPrivate::relayoutTableItems() void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge) { - int column = (tableEdge == Qt::LeftEdge) ? loadedTable.left() : loadedTable.right(); + int column = (tableEdge == Qt::LeftEdge) ? leftColumn() : rightColumn(); QPoint neighbourDirection = (tableEdge == Qt::LeftEdge) ? kRight : kLeft; qreal width = resolveColumnWidth(column); - for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) { + for (auto r = loadedRows.cbegin(); r != loadedRows.cend(); ++r) { + const int row = r.key(); auto fxTableItem = loadedTableItem(QPoint(column, row)); auto const neighbourItem = itemNextTo(fxTableItem, neighbourDirection); @@ -1080,11 +1077,12 @@ void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge) void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge) { - int row = (tableEdge == Qt::TopEdge) ? loadedTable.top() : loadedTable.bottom(); + int row = (tableEdge == Qt::TopEdge) ? topRow() : bottomRow(); QPoint neighbourDirection = (tableEdge == Qt::TopEdge) ? kDown : kUp; qreal height = resolveRowHeight(row); - for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) { + for (auto c = loadedColumns.cbegin(); c != loadedColumns.cend(); ++c) { + const int column = c.key(); auto fxTableItem = loadedTableItem(QPoint(column, row)); auto const neighbourItem = itemNextTo(fxTableItem, neighbourDirection); @@ -1232,14 +1230,14 @@ void QQuickTableViewPrivate::processRebuildTable() && reusableFlag == QQmlTableInstanceModel::Reusable); if (rebuildState == RebuildState::PreloadColumns) { - if (preload && loadedTable.right() < tableSize.width() - 1) + if (preload && rightColumn() < tableSize.width() - 1) loadEdge(Qt::RightEdge, QQmlIncubator::AsynchronousIfNested); if (!moveToNextRebuildState()) return; } if (rebuildState == RebuildState::PreloadRows) { - if (preload && loadedTable.bottom() < tableSize.height() - 1) + if (preload && bottomRow() < tableSize.height() - 1) loadEdge(Qt::BottomEdge, QQmlIncubator::AsynchronousIfNested); if (!moveToNextRebuildState()) return; @@ -1289,7 +1287,7 @@ void QQuickTableViewPrivate::beginRebuildTable() topLeft.ry() = qBound(0, newRow, tableSize.height() - 1); topLeftPos.ry() = topLeft.y() * (averageEdgeSize.height() + cellSpacing.height()); } else { - topLeft.ry() = qBound(0, loadedTable.topLeft().y(), tableSize.height() - 1); + topLeft.ry() = qBound(0, topRow(), tableSize.height() - 1); topLeftPos.ry() = loadedTableOuterRect.topLeft().y(); } if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) { @@ -1297,14 +1295,15 @@ void QQuickTableViewPrivate::beginRebuildTable() topLeft.rx() = qBound(0, newColumn, tableSize.width() - 1); topLeftPos.rx() = topLeft.x() * (averageEdgeSize.width() + cellSpacing.width()); } else { - topLeft.rx() = qBound(0, loadedTable.topLeft().x(), tableSize.width() - 1); + topLeft.rx() = qBound(0, leftColumn(), tableSize.width() - 1); topLeftPos.rx() = loadedTableOuterRect.topLeft().x(); } } else { Q_TABLEVIEW_UNREACHABLE(rebuildOptions); } - loadedTable = QRect(); + loadedColumns.clear(); + loadedRows.clear(); loadedTableOuterRect = QRect(); loadedTableInnerRect = QRect(); contentSizeBenchMarkPoint = QPoint(-1, -1); @@ -1351,15 +1350,44 @@ void QQuickTableViewPrivate::loadInitialTopLeftItem(const QPoint &cell, const QP void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge) { - unloadItems(rectangleEdge(loadedTable, edge)); - loadedTable = expandedRect(loadedTable, edge, -1); + qCDebug(lcTableViewDelegateLifecycle) << edge; + + switch (edge) { + case Qt::LeftEdge: + case Qt::RightEdge: { + const int column = edge == Qt::LeftEdge ? leftColumn() : rightColumn(); + unloadItems(QLine(column, topRow(), column, bottomRow())); + loadedColumns.remove(column); + break; } + case Qt::TopEdge: + case Qt::BottomEdge: { + const int row = edge == Qt::TopEdge ? topRow() : bottomRow(); + unloadItems(QLine(leftColumn(), row, rightColumn(), row)); + loadedRows.remove(row); + break; } + } + syncLoadedTableRectFromLoadedTable(); qCDebug(lcTableViewDelegateLifecycle) << tableLayoutToString(); } void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode) { - QLine cellsToLoad = rectangleEdge(expandedRect(loadedTable, edge, 1), edge); + const int edgeIndex = nextVisibleEdgeIndexAroundLoadedTable(edge); + qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex; + QLine cellsToLoad; + + switch (edge) { + case Qt::LeftEdge: + case Qt::RightEdge: + cellsToLoad = QLine(edgeIndex, topRow(), edgeIndex, bottomRow()); + break; + case Qt::TopEdge: + case Qt::BottomEdge: + cellsToLoad = QLine(leftColumn(), edgeIndex, rightColumn(), edgeIndex); + break; + } + loadRequest.begin(cellsToLoad, edge, incubationMode); processLoadRequest(); } @@ -1446,8 +1474,8 @@ void QQuickTableViewPrivate::drainReusePoolAfterLoadRequest() // in with varying sizes, causing some items not to be resued immediately), we multiply the // value by 2. Note that we also add an extra +1 to the column count, because the number of // visible columns will fluctuate between +1/-1 while flicking. - const int w = loadedTable.width(); - const int h = loadedTable.height(); + const int w = loadedColumns.count(); + const int h = loadedRows.count(); const int minTime = int(std::ceil(w > h ? qreal(w + 1) / h : qreal(h + 1) / w)); const int maxTime = minTime * 2; tableModel->drainReusableItemsPool(maxTime); @@ -1596,6 +1624,12 @@ void QQuickTableViewPrivate::syncRebuildOptions() rebuildOptions = scheduledRebuildOptions; scheduledRebuildOptions = RebuildOption::None; rebuildScheduled = false; + + if (loadedItems.isEmpty()) { + // If we have no items from before, we cannot just rebuild the viewport, but need + // to rebuild everything, since we have no top-left loaded item to start from. + rebuildOptions.setFlag(RebuildOption::All); + } } void QQuickTableViewPrivate::syncDelegate() @@ -1774,6 +1808,16 @@ QQuickTableView::QQuickTableView(QQuickItem *parent) setFlag(QQuickItem::ItemIsFocusScope); } +QQuickTableView::~QQuickTableView() +{ +} + +QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent) + : QQuickFlickable(dd, parent) +{ + setFlag(QQuickItem::ItemIsFocusScope); +} + int QQuickTableView::rows() const { return d_func()->tableSize.height(); diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h index 9fcd4c6c17..c5197b4230 100644 --- a/src/quick/items/qquicktableview_p.h +++ b/src/quick/items/qquicktableview_p.h @@ -82,7 +82,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTableView : public QQuickFlickable public: QQuickTableView(QQuickItem *parent = nullptr); - + ~QQuickTableView() override; int rows() const; int columns() const; @@ -98,8 +98,8 @@ public: QJSValue columnWidthProvider() const; void setColumnWidthProvider(QJSValue provider); - QVariant model() const; - void setModel(const QVariant &newModel); + virtual QVariant model() const; + virtual void setModel(const QVariant &newModel); QQmlComponent *delegate() const; void setDelegate(QQmlComponent *); @@ -130,6 +130,9 @@ protected: void viewportMoved(Qt::Orientations orientation) override; void componentComplete() override; +protected: + QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent); + private: Q_DISABLE_COPY(QQuickTableView) Q_DECLARE_PRIVATE(QQuickTableView) diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h index 2ed04f8d29..ed6f8026a2 100644 --- a/src/quick/items/qquicktableview_p_p.h +++ b/src/quick/items/qquicktableview_p_p.h @@ -213,13 +213,14 @@ public: QVariant assignedModel = QVariant(int(0)); QQmlComponent *assignedDelegate = nullptr; - // loadedTable describes the table cells that are currently loaded (from top left + // loadedRows/Columns describes the rows and columns that are currently loaded (from top left // row/column to bottom right row/column). loadedTableOuterRect describes the actual - // pixels that those cells cover, and is matched agains the viewport to determine when + // pixels that all the loaded delegate items cover, and is matched agains the viewport to determine when // we need to fill up with more rows/columns. loadedTableInnerRect describes the pixels // that the loaded table covers if you remove one row/column on each side of the table, and // is used to determine rows/columns that are no longer visible and can be unloaded. - QRect loadedTable; + QMap<int, int> loadedColumns; + QMap<int, int> loadedRows; QRectF loadedTableOuterRect; QRectF loadedTableInnerRect; @@ -283,6 +284,11 @@ public: qreal resolveColumnWidth(int column); qreal resolveRowHeight(int row); + inline int topRow() const { return loadedRows.firstKey(); } + inline int bottomRow() const { return loadedRows.lastKey(); } + inline int leftColumn() const { return loadedColumns.firstKey(); } + inline int rightColumn() const { return loadedColumns.lastKey(); } + void relayoutTable(); void relayoutTableItems(); @@ -299,6 +305,8 @@ public: void syncLoadedTableRectFromLoadedTable(); void syncLoadedTableFromLoadRequest(); + int nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge); + bool canLoadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const; bool canUnloadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const; Qt::Edge nextEdgeToLoad(const QRectF rect); diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index 38ca7283b4..a7a90c9134 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -998,7 +998,7 @@ QRectF QQuickTextControlPrivate::rectForPosition(int position) const if (relativePos < line.textLength() - line.textStart()) w = line.cursorToX(relativePos + 1) - x; else - w = QFontMetrics(block.layout()->font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw() + w = QFontMetrics(block.layout()->font()).horizontalAdvance(QLatin1Char(' ')); // in sync with QTextLine::draw() } r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(), textCursorWidth + w, line.height()); } else { diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 06a0fc396b..3a12ad6ba5 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1641,7 +1641,8 @@ bool QQuickTextEdit::event(QEvent *event) Q_D(QQuickTextEdit); if (event->type() == QEvent::ShortcutOverride) { d->control->processEvent(event, QPointF(-d->xoff, -d->yoff)); - return event->isAccepted(); + if (event->isAccepted()) + return true; } return QQuickImplicitSizeItem::event(event); } diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index aac7137ff3..5f6fd8f50f 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -877,7 +877,7 @@ QRectF QQuickTextInput::cursorRectangle() const if (c < text().length()) w = l.cursorToX(c + 1) - x; else - w = QFontMetrics(font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw() + w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(' ')); // in sync with QTextLine::draw() } return QRectF(x, y, w, l.height()); } @@ -1383,7 +1383,7 @@ QRectF QQuickTextInput::positionToRectangle(int pos) const if (pos < text().length()) w = l.cursorToX(pos + 1) - x; else - w = QFontMetrics(font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw() + w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(' ')); // in sync with QTextLine::draw() } return QRectF(x, y, w, l.height()); } diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index 504d629b3e..792aa31a88 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -1051,7 +1051,7 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText if (text.contains(QChar::ObjectReplacementCharacter)) { QTextFrame *frame = qobject_cast<QTextFrame *>(textDocument->objectForFormat(charFormat)); - if (frame && frame->frameFormat().position() == QTextFrameFormat::InFlow) { + if (!frame || frame->frameFormat().position() == QTextFrameFormat::InFlow) { int blockRelativePosition = textPos - block.position(); QTextLine line = block.layout()->lineForTextPosition(blockRelativePosition); if (!currentLine().isValid() diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 61c8bcc1e7..f517b5b3e9 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -4608,6 +4608,62 @@ void QQuickWindow::resetOpenGLState() */ /*! + \qmlproperty QWindow Window::transientParent + \since 5.13 + + The window for which this window is a transient pop-up. + + This is a hint to the window manager that this window is a dialog or pop-up + on behalf of the transient parent. It usually means that the transient + window will be centered over its transient parent when it is initially + shown, that minimizing the parent window will also minimize the transient + window, and so on; however results vary somewhat from platform to platform. + + Normally if you declare a Window inside an Item or inside another Window, + this relationship is deduced automatically. In that case, if you declare + this window's \l visible property \c true, it will not actually be shown + until the \c transientParent window is shown. + + However if you set this property, then Qt Quick will no longer wait until + the \c transientParent window is shown before showing this window. If you + want to to be able to show a transient window independently of the "parent" + Item or Window within which it was declared, you can remove that + relationship by setting \c transientParent to \c null: + + \l qml + import QtQuick.Window 2.13 + + Window { + // visible is false by default + Window { + transientParent: null + visible: true + } + } + \qml + + In order to cause the window to be centered above its transient parent by + default, depending on the window manager, it may also be necessary to set + the \l Window::flags property with a suitable \l Qt::WindowType (such as + \c Qt::Dialog). +*/ + +/*! + \property QQuickWindow::transientParent + \brief The window for which this window is a transient pop-up. + \since 5.13 + + This is a hint to the window manager that this window is a dialog or pop-up + on behalf of the transient parent, which may be any kind of \l QWindow. + + In order to cause the window to be centered above its transient parent by + default, depending on the window manager, it may also be necessary to set + the \l flags property with a suitable \l Qt::WindowType (such as \c Qt::Dialog). + + \sa parent() + */ + +/*! \qmlproperty Item Window::activeFocusItem \since 5.1 diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp index ab3f49d5b6..2b109c0897 100644 --- a/src/quick/items/qquickwindowmodule.cpp +++ b/src/quick/items/qquickwindowmodule.cpp @@ -124,7 +124,8 @@ void QQuickWindowQmlImpl::componentComplete() Q_D(QQuickWindowQmlImpl); d->complete = true; QQuickItem *itemParent = qmlobject_cast<QQuickItem *>(QObject::parent()); - if (itemParent && !itemParent->window()) { + const bool transientParentAlreadySet = QQuickWindowPrivate::get(this)->transientParentPropertySet; + if (!transientParentAlreadySet && itemParent && !itemParent->window()) { qCDebug(lcTransient) << "window" << title() << "has invisible Item parent" << itemParent << "transientParent" << transientParent() << "declared visibility" << d->visibility << "; delaying show"; connect(itemParent, &QQuickItem::windowChanged, this, @@ -210,6 +211,9 @@ void QQuickWindowModule::defineModule() qmlRegisterUncreatableType<QQuickScreen,1>(uri, 2, 3, "Screen", QStringLiteral("Screen can only be used via the attached property.")); qmlRegisterUncreatableType<QQuickScreenInfo,2>(uri, 2, 3, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property.")); qmlRegisterUncreatableType<QQuickScreenInfo,10>(uri, 2, 10, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property.")); + qmlRegisterRevision<QWindow,13>(uri, 2, 13); + qmlRegisterRevision<QQuickWindow,13>(uri, 2, 13); + qmlRegisterType<QQuickWindowQmlImpl,13>(uri, 2, 13, "Window"); } QT_END_NAMESPACE diff --git a/src/quick/quick.pro b/src/quick/quick.pro index 0f5f5abca3..37d2ad1172 100644 --- a/src/quick/quick.pro +++ b/src/quick/quick.pro @@ -21,7 +21,6 @@ QMAKE_DOCS = $$PWD/doc/qtquick.qdocconf ANDROID_LIB_DEPENDENCIES = \ lib/libQt5QuickParticles.so MODULE_PLUGIN_TYPES += \ - accessible/libqtaccessiblequick.so \ scenegraph ANDROID_BUNDLED_FILES += \ qml \ diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp index 405e2ab100..da5d39db20 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp @@ -473,8 +473,7 @@ void QSGSoftwareInternalImageNode::paint(QPainter *painter) painter->save(); qreal sx = m_targetRect.width()/(m_subSourceRect.width()*pm.width()); qreal sy = m_targetRect.height()/(m_subSourceRect.height()*pm.height()); - QMatrix transform(sx, 0, 0, sy, 0, 0); - painter->setMatrix(transform, true); + painter->setTransform(QTransform::fromScale(sx, sy), true); painter->drawTiledPixmap(QRectF(m_targetRect.x()/sx, m_targetRect.y()/sy, m_targetRect.width()/sx, m_targetRect.height()/sy), pm, QPointF(m_subSourceRect.left()*pm.width(), m_subSourceRect.top()*pm.height())); diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp index 1124bf1727..af0589e5d3 100644 --- a/src/quick/scenegraph/qsgdefaultcontext.cpp +++ b/src/quick/scenegraph/qsgdefaultcontext.cpp @@ -221,8 +221,14 @@ QSurfaceFormat QSGDefaultContext::defaultSurfaceFormat() const static bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER"); static bool useStencil = qEnvironmentVariableIsEmpty("QSG_NO_STENCIL_BUFFER"); static bool enableDebug = qEnvironmentVariableIsSet("QSG_OPENGL_DEBUG"); - format.setDepthBufferSize(useDepth ? 24 : 0); - format.setStencilBufferSize(useStencil ? 8 : 0); + if (useDepth && format.depthBufferSize() == -1) + format.setDepthBufferSize(24); + else if (!useDepth) + format.setDepthBufferSize(0); + if (useStencil && format.stencilBufferSize() == -1) + format.setStencilBufferSize(8); + else if (!useStencil) + format.setStencilBufferSize(0); if (enableDebug) format.setOption(QSurfaceFormat::DebugContext); if (QQuickWindow::hasDefaultAlphaBuffer()) diff --git a/src/quick/scenegraph/util/qsgimagenode.h b/src/quick/scenegraph/util/qsgimagenode.h index 526f52b7e5..3b78f78a0e 100644 --- a/src/quick/scenegraph/util/qsgimagenode.h +++ b/src/quick/scenegraph/util/qsgimagenode.h @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE class Q_QUICK_EXPORT QSGImageNode : public QSGGeometryNode { public: - ~QSGImageNode() override { } + ~QSGImageNode() override = default; virtual void setRect(const QRectF &rect) = 0; inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); } diff --git a/src/quick/scenegraph/util/qsgninepatchnode.h b/src/quick/scenegraph/util/qsgninepatchnode.h index e76afd3c4a..b690a50e9d 100644 --- a/src/quick/scenegraph/util/qsgninepatchnode.h +++ b/src/quick/scenegraph/util/qsgninepatchnode.h @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE class Q_QUICK_EXPORT QSGNinePatchNode : public QSGGeometryNode { public: - ~QSGNinePatchNode() override { } + ~QSGNinePatchNode() override = default; virtual void setTexture(QSGTexture *texture) = 0; virtual void setBounds(const QRectF &bounds) = 0; diff --git a/src/quick/scenegraph/util/qsgrectanglenode.h b/src/quick/scenegraph/util/qsgrectanglenode.h index ba52b65b07..c435dc790f 100644 --- a/src/quick/scenegraph/util/qsgrectanglenode.h +++ b/src/quick/scenegraph/util/qsgrectanglenode.h @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class Q_QUICK_EXPORT QSGRectangleNode : public QSGGeometryNode { public: - ~QSGRectangleNode() override { } + ~QSGRectangleNode() override = default; virtual void setRect(const QRectF &rect) = 0; inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); } diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index d33bdffe74..042eee19f5 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -49,6 +49,7 @@ # include <qopenglfunctions.h> # include <QtGui/qopenglcontext.h> # include <QtGui/qopenglfunctions.h> +# include <QtGui/private/qopengltextureuploader_p.h> # include <private/qsgdefaultrendercontext_p.h> #endif #include <private/qsgmaterialshader_p.h> @@ -89,7 +90,7 @@ static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK" QT_BEGIN_NAMESPACE -#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) && !defined(QT_NO_DEBUG) inline static bool isPowerOfTwo(int x) { // Assumption: x >= 1 @@ -755,9 +756,7 @@ void QSGPlainTexture::bind() // ### TODO: check for out-of-memory situations... - QImage tmp = (m_image.format() == QImage::Format_RGB32 || m_image.format() == QImage::Format_ARGB32_Premultiplied) - ? m_image - : m_image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + QOpenGLTextureUploader::BindOptions options = QOpenGLTextureUploader::PremultipliedAlphaBindOption; // Downscale the texture to fit inside the max texture limit if it is too big. // It would be better if the image was already downscaled to the right size, @@ -771,75 +770,19 @@ void QSGPlainTexture::bind() max = rc->maxTextureSize(); else funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max); - if (tmp.width() > max || tmp.height() > max) { - tmp = tmp.scaled(qMin(max, tmp.width()), qMin(max, tmp.height()), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - m_texture_size = tmp.size(); - } + + m_texture_size = m_texture_size.boundedTo(QSize(max, max)); // Scale to a power of two size if mipmapping is requested and the // texture is npot and npot textures are not properly supported. if (mipmapFiltering() != QSGTexture::None - && (!isPowerOfTwo(m_texture_size.width()) || !isPowerOfTwo(m_texture_size.height())) && !funcs->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures)) { - tmp = tmp.scaled(qNextPowerOfTwo(m_texture_size.width()), qNextPowerOfTwo(m_texture_size.height()), - Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - m_texture_size = tmp.size(); + options |= QOpenGLTextureUploader::PowerOfTwoBindOption; } - if (tmp.width() * 4 != tmp.bytesPerLine()) - tmp = tmp.copy(); - - qint64 convertTime = 0; - if (profileFrames) - convertTime = qsg_renderer_timer.nsecsElapsed(); - Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare, - QQuickProfiler::SceneGraphTexturePrepareConvert); - updateBindOptions(m_dirty_bind_options); - GLenum externalFormat = GL_RGBA; - GLenum internalFormat = GL_RGBA; - -#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) - QString *deviceName = - static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName")); - static bool wrongfullyReportsBgra8888Support = deviceName != 0 - && (deviceName->compare(QLatin1String("samsung SM-T211"), Qt::CaseInsensitive) == 0 - || deviceName->compare(QLatin1String("samsung SM-T210"), Qt::CaseInsensitive) == 0 - || deviceName->compare(QLatin1String("samsung SM-T215"), Qt::CaseInsensitive) == 0); -#else - static bool wrongfullyReportsBgra8888Support = false; -#endif - - if (context->hasExtension(QByteArrayLiteral("GL_EXT_bgra"))) { - externalFormat = GL_BGRA; -#ifdef QT_OPENGL_ES - internalFormat = GL_BGRA; -#else - if (context->isOpenGLES()) - internalFormat = GL_BGRA; -#endif // QT_OPENGL_ES - } else if (!wrongfullyReportsBgra8888Support - && (context->hasExtension(QByteArrayLiteral("GL_EXT_texture_format_BGRA8888")) - || context->hasExtension(QByteArrayLiteral("GL_IMG_texture_format_BGRA8888")))) { - externalFormat = GL_BGRA; - internalFormat = GL_BGRA; -#if defined(Q_OS_DARWIN) && !defined(Q_OS_OSX) - } else if (context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) { - externalFormat = GL_BGRA; - internalFormat = GL_RGBA; -#endif - } else { - tmp = std::move(tmp).convertToFormat(QImage::Format_RGBA8888_Premultiplied); - } - - qint64 swizzleTime = 0; - if (profileFrames) - swizzleTime = qsg_renderer_timer.nsecsElapsed(); - Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare, - QQuickProfiler::SceneGraphTexturePrepareSwizzle); - - funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_texture_size.width(), m_texture_size.height(), 0, externalFormat, GL_UNSIGNED_BYTE, tmp.constBits()); + QOpenGLTextureUploader::textureImage(GL_TEXTURE_2D, m_image, options, QSize(max, max)); qint64 uploadTime = 0; if (profileFrames) @@ -856,15 +799,11 @@ void QSGPlainTexture::bind() if (profileFrames) { mipmapTime = qsg_renderer_timer.nsecsElapsed(); qCDebug(QSG_LOG_TIME_TEXTURE, - "plain texture uploaded in: %dms (%dx%d), bind=%d, convert=%d, swizzle=%d (%s->%s), upload=%d, mipmap=%d%s", + "plain texture uploaded in: %dms (%dx%d), bind=%d, upload=%d, mipmap=%d%s", int(mipmapTime / 1000000), m_texture_size.width(), m_texture_size.height(), int(bindTime / 1000000), - int((convertTime - bindTime)/1000000), - int((swizzleTime - convertTime)/1000000), - (externalFormat == GL_BGRA ? "BGRA" : "RGBA"), - (internalFormat == GL_BGRA ? "BGRA" : "RGBA"), - int((uploadTime - swizzleTime)/1000000), + int((uploadTime - bindTime)/1000000), int((mipmapTime - uploadTime)/1000000), m_texture_size != m_image.size() ? " (scaled to GL_MAX_TEXTURE_SIZE)" : ""); } diff --git a/src/quick/scenegraph/util/qsgtexturematerial_p.h b/src/quick/scenegraph/util/qsgtexturematerial_p.h index 093d820801..a99e872580 100644 --- a/src/quick/scenegraph/util/qsgtexturematerial_p.h +++ b/src/quick/scenegraph/util/qsgtexturematerial_p.h @@ -72,7 +72,7 @@ protected: int m_matrix_id; }; -class QSGTextureMaterialShader : public QSGOpaqueTextureMaterialShader +class Q_QUICK_PRIVATE_EXPORT QSGTextureMaterialShader : public QSGOpaqueTextureMaterialShader { public: QSGTextureMaterialShader(); diff --git a/src/quick/util/qquickbehavior.cpp b/src/quick/util/qquickbehavior.cpp index d024c0099b..76d464e7f8 100644 --- a/src/quick/util/qquickbehavior.cpp +++ b/src/quick/util/qquickbehavior.cpp @@ -171,9 +171,28 @@ void QQuickBehavior::setEnabled(bool enabled) emit enabledChanged(); } +/*! + \qmlproperty Variant QtQuick::Behavior::targetValue + + This property holds the target value of the property being controlled by the Behavior. + This value is set by the Behavior before the animation is started. + + \since QtQuick 2.13 +*/ +QVariant QQuickBehavior::targetValue() const +{ + Q_D(const QQuickBehavior); + return d->targetValue; +} + void QQuickBehavior::write(const QVariant &value) { Q_D(QQuickBehavior); + const bool targetValueHasChanged = d->targetValue != value; + if (targetValueHasChanged) { + d->targetValue = value; + emit targetValueChanged(); // emitting the signal here should allow + } // d->enabled to change if scripted by the user. bool bypass = !d->enabled || !d->finalized || QQmlEnginePrivate::designerMode(); if (!bypass) qmlExecuteDeferred(this); @@ -181,16 +200,13 @@ void QQuickBehavior::write(const QVariant &value) if (d->animationInstance) d->animationInstance->stop(); QQmlPropertyPrivate::write(d->property, value, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); - d->targetValue = value; return; } bool behaviorActive = d->animation->isRunning(); - if (behaviorActive && value == d->targetValue) + if (behaviorActive && !targetValueHasChanged) return; - d->targetValue = value; - if (d->animationInstance && (d->animationInstance->duration() != -1 || d->animationInstance->isRenderThreadProxy()) diff --git a/src/quick/util/qquickbehavior_p.h b/src/quick/util/qquickbehavior_p.h index f939597d15..80a51d77af 100644 --- a/src/quick/util/qquickbehavior_p.h +++ b/src/quick/util/qquickbehavior_p.h @@ -69,6 +69,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickBehavior : public QObject, public QQmlPropert Q_CLASSINFO("DefaultProperty", "animation") Q_PROPERTY(QQuickAbstractAnimation *animation READ animation WRITE setAnimation) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + Q_PROPERTY(QVariant targetValue READ targetValue NOTIFY targetValueChanged REVISION 13) Q_CLASSINFO("DeferredPropertyNames", "animation") public: @@ -84,8 +85,11 @@ public: bool enabled() const; void setEnabled(bool enabled); + QVariant targetValue() const; + Q_SIGNALS: void enabledChanged(); + void targetValueChanged(); private Q_SLOTS: void componentFinalized(); diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index dc8bed8125..ced0acd9ab 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -61,9 +61,7 @@ #include <QThread> #include <QMutex> #include <QMutexLocker> -#include <QWaitCondition> #include <QBuffer> -#include <QWaitCondition> #include <QtCore/qdebug.h> #include <private/qobject_p.h> #include <QQmlFile> @@ -222,7 +220,6 @@ private: QMutex mutex; QQuickPixmapReaderThreadObject *threadObject; - QWaitCondition waitCondition; #if QT_CONFIG(qml_network) QNetworkAccessManager *networkAccessManager(); @@ -372,15 +369,27 @@ static void maybeRemoveAlpha(QImage *image) switch (image->format()) { case QImage::Format_RGBA8888: case QImage::Format_RGBA8888_Premultiplied: + if (image->data_ptr()->convertInPlace(QImage::Format_RGBX8888, Qt::AutoColor)) + break; + *image = image->convertToFormat(QImage::Format_RGBX8888); break; case QImage::Format_A2BGR30_Premultiplied: + if (image->data_ptr()->convertInPlace(QImage::Format_BGR30, Qt::AutoColor)) + break; + *image = image->convertToFormat(QImage::Format_BGR30); break; case QImage::Format_A2RGB30_Premultiplied: + if (image->data_ptr()->convertInPlace(QImage::Format_RGB30, Qt::AutoColor)) + break; + *image = image->convertToFormat(QImage::Format_RGB30); break; default: + if (image->data_ptr()->convertInPlace(QImage::Format_RGB32, Qt::AutoColor)) + break; + *image = image->convertToFormat(QImage::Format_RGB32); break; } diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index 8e2ac32ace..d739c8a017 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -336,6 +336,9 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, case QV4::CompiledData::Binding::Type_Boolean: var = binding->valueAsBoolean(); break; + case QV4::CompiledData::Binding::Type_Null: + var = QVariant::fromValue(nullptr); + break; default: break; } diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp index 31d4d4c437..5147ebc6f6 100644 --- a/src/quick/util/qquickutilmodule.cpp +++ b/src/quick/util/qquickutilmodule.cpp @@ -135,4 +135,6 @@ void QQuickUtilModule::defineModule() qmlRegisterUncreatableType<QQuickAbstractAnimation, 12>("QtQuick", 2, 12, "Animation", QQuickAbstractAnimation::tr("Animation is an abstract class")); + // 5.13 + qmlRegisterType<QQuickBehavior, 13>("QtQuick", 2, 13, "Behavior"); } |