aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/context2d/qquickcanvascontext_p.h3
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp10
-rw-r--r--src/quick/items/context2d/qquickcanvasitem_p.h6
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp11
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h2
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp13
-rw-r--r--src/quick/items/items.pri14
-rw-r--r--src/quick/items/qquickanimatedimage.cpp7
-rw-r--r--src/quick/items/qquickanimatedimage_p.h7
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp2
-rw-r--r--src/quick/items/qquickanimatedsprite_p.h4
-rw-r--r--src/quick/items/qquickborderimage.cpp22
-rw-r--r--src/quick/items/qquickborderimage_p_p.h2
-rw-r--r--src/quick/items/qquickdrag.cpp4
-rw-r--r--src/quick/items/qquickdrag_p.h6
-rw-r--r--src/quick/items/qquickdroparea.cpp21
-rw-r--r--src/quick/items/qquickdroparea_p.h4
-rw-r--r--src/quick/items/qquickevents.cpp9
-rw-r--r--src/quick/items/qquickevents_p_p.h1
-rw-r--r--src/quick/items/qquickflickable.cpp9
-rw-r--r--src/quick/items/qquickflickablebehavior_p.h5
-rw-r--r--src/quick/items/qquickframebufferobject.cpp4
-rw-r--r--src/quick/items/qquickframebufferobject.h3
-rw-r--r--src/quick/items/qquickgenericshadereffect.cpp53
-rw-r--r--src/quick/items/qquickgenericshadereffect_p.h4
-rw-r--r--src/quick/items/qquickgraphicsinfo.cpp7
-rw-r--r--src/quick/items/qquickgraphicsinfo_p.h11
-rw-r--r--src/quick/items/qquickimage.cpp19
-rw-r--r--src/quick/items/qquickimage_p.h8
-rw-r--r--src/quick/items/qquickimagebase.cpp47
-rw-r--r--src/quick/items/qquickimagebase_p.h9
-rw-r--r--src/quick/items/qquickimagebase_p_p.h6
-rw-r--r--src/quick/items/qquickitem.cpp55
-rw-r--r--src/quick/items/qquickitem.h4
-rw-r--r--src/quick/items/qquickitem_p.h5
-rw-r--r--src/quick/items/qquickitemsmodule.cpp93
-rw-r--r--src/quick/items/qquickitemview.cpp38
-rw-r--r--src/quick/items/qquickitemview_p.h4
-rw-r--r--src/quick/items/qquickitemview_p_p.h8
-rw-r--r--src/quick/items/qquicklistview_p.h8
-rw-r--r--src/quick/items/qquickmousearea.cpp30
-rw-r--r--src/quick/items/qquickmousearea_p.h12
-rw-r--r--src/quick/items/qquickmousearea_p_p.h2
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp4
-rw-r--r--src/quick/items/qquickopenglshadereffect.cpp12
-rw-r--r--src/quick/items/qquickopenglshadereffectnode.cpp1
-rw-r--r--src/quick/items/qquickpathview.cpp179
-rw-r--r--src/quick/items/qquickpincharea_p.h4
-rw-r--r--src/quick/items/qquickrectangle.cpp26
-rw-r--r--src/quick/items/qquickrendercontrol.cpp16
-rw-r--r--src/quick/items/qquickrepeater.cpp1
-rw-r--r--src/quick/items/qquickscreen_p.h8
-rw-r--r--src/quick/items/qquickshadereffect.cpp18
-rw-r--r--src/quick/items/qquickshadereffect_p.h2
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp2
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h4
-rw-r--r--src/quick/items/qquickspriteengine.cpp12
-rw-r--r--src/quick/items/qquickspriteengine_p.h4
-rw-r--r--src/quick/items/qquickspritesequence_p.h1
-rw-r--r--src/quick/items/qquickspritesequence_p_p.h3
-rw-r--r--src/quick/items/qquickstateoperations.cpp12
-rw-r--r--src/quick/items/qquickstateoperations_p.h12
-rw-r--r--src/quick/items/qquicktableview.cpp1122
-rw-r--r--src/quick/items/qquicktableview_p.h19
-rw-r--r--src/quick/items/qquicktableview_p_p.h65
-rw-r--r--src/quick/items/qquicktext.cpp16
-rw-r--r--src/quick/items/qquicktext_p.h1
-rw-r--r--src/quick/items/qquicktext_p_p.h1
-rw-r--r--src/quick/items/qquicktextcontrol.cpp46
-rw-r--r--src/quick/items/qquicktextcontrol_p.h9
-rw-r--r--src/quick/items/qquicktextcontrol_p_p.h3
-rw-r--r--src/quick/items/qquicktextdocument.cpp8
-rw-r--r--src/quick/items/qquicktextdocument_p.h3
-rw-r--r--src/quick/items/qquicktextedit.cpp31
-rw-r--r--src/quick/items/qquicktextedit_p.h4
-rw-r--r--src/quick/items/qquicktextedit_p_p.h3
-rw-r--r--src/quick/items/qquicktextinput.cpp9
-rw-r--r--src/quick/items/qquicktextinput_p.h8
-rw-r--r--src/quick/items/qquicktextnode.cpp2
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp13
-rw-r--r--src/quick/items/qquickview.cpp21
-rw-r--r--src/quick/items/qquickview.h1
-rw-r--r--src/quick/items/qquickview_p.h2
-rw-r--r--src/quick/items/qquickwindow.cpp627
-rw-r--r--src/quick/items/qquickwindow.h20
-rw-r--r--src/quick/items/qquickwindow_p.h26
-rw-r--r--src/quick/items/qquickwindowmodule.cpp9
-rw-r--r--src/quick/items/qquickwindowmodule_p.h4
88 files changed, 2262 insertions, 724 deletions
diff --git a/src/quick/items/context2d/qquickcanvascontext_p.h b/src/quick/items/context2d/qquickcanvascontext_p.h
index 95100d2912..3872a2ac74 100644
--- a/src/quick/items/context2d/qquickcanvascontext_p.h
+++ b/src/quick/items/context2d/qquickcanvascontext_p.h
@@ -56,7 +56,7 @@
QT_REQUIRE_CONFIG(quick_canvas);
#include <QtQuick/qquickitem.h>
-#include <private/qv8engine_p.h>
+#include <QtQml/private/qv4value_p.h>
QT_BEGIN_NAMESPACE
@@ -80,6 +80,7 @@ public:
virtual void prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing);
virtual void flush();
+ virtual QV4::ExecutionEngine *v4Engine() const = 0;
virtual void setV4Engine(QV4::ExecutionEngine *engine) = 0;
virtual QV4::ReturnedValue v4value() const = 0;
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index 3462b0dbac..b8e6d58af4 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -378,13 +378,10 @@ void QQuickCanvasItem::setContextType(const QString &contextType)
this property will contain the current drawing context, otherwise null.
*/
-QQmlV4Handle QQuickCanvasItem::context() const
+QJSValue QQuickCanvasItem::context() const
{
Q_D(const QQuickCanvasItem);
- if (d->context)
- return QQmlV4Handle(d->context->v4value());
-
- return QQmlV4Handle(QV4::Encode::null());
+ return d->context ? QJSValue(d->context->v4Engine(), d->context->v4value()) : QJSValue();
}
/*!
@@ -772,7 +769,8 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
if (!node) {
- node = QQuickWindowPrivate::get(window())->context->sceneGraphContext()->createInternalImageNode();
+ QSGRenderContext *rc = QQuickWindowPrivate::get(window())->context;
+ node = rc->sceneGraphContext()->createInternalImageNode(rc);
d->node = node;
}
diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h
index 7dc981a6eb..cd2977429b 100644
--- a/src/quick/items/context2d/qquickcanvasitem_p.h
+++ b/src/quick/items/context2d/qquickcanvasitem_p.h
@@ -56,9 +56,9 @@
QT_REQUIRE_CONFIG(quick_canvas);
#include <QtQuick/qquickitem.h>
-#include <private/qv8engine_p.h>
#include <private/qqmlrefcount_p.h>
#include <QtCore/QThread>
+#include <QtCore/qmutex.h>
#include <QtGui/QImage>
QT_BEGIN_NAMESPACE
@@ -93,7 +93,7 @@ class QQuickCanvasItem : public QQuickItem
Q_PROPERTY(bool available READ isAvailable NOTIFY availableChanged)
Q_PROPERTY(QString contextType READ contextType WRITE setContextType NOTIFY contextTypeChanged)
- Q_PROPERTY(QQmlV4Handle context READ context NOTIFY contextChanged)
+ Q_PROPERTY(QJSValue context READ context NOTIFY contextChanged)
Q_PROPERTY(QSizeF canvasSize READ canvasSize WRITE setCanvasSize NOTIFY canvasSizeChanged)
Q_PROPERTY(QSize tileSize READ tileSize WRITE setTileSize NOTIFY tileSizeChanged)
Q_PROPERTY(QRectF canvasWindow READ canvasWindow WRITE setCanvasWindow NOTIFY canvasWindowChanged)
@@ -122,7 +122,7 @@ public:
QString contextType() const;
void setContextType(const QString &contextType);
- QQmlV4Handle context() const;
+ QJSValue context() const;
QSizeF canvasSize() const;
void setCanvasSize(const QSizeF &);
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 7cd222d3c1..54cda72a36 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -56,7 +56,6 @@
#include <private/qquickimage_p_p.h>
#include <qqmlinfo.h>
-#include <private/qv8engine_p.h>
#include <qqmlengine.h>
#include <private/qv4domerrors_p.h>
@@ -474,7 +473,7 @@ static QFont qt_font_from_string(const QString& fontString, const QFont &current
return newFont;
}
-class QQuickContext2DEngineData : public QV8Engine::Deletable
+class QQuickContext2DEngineData : public QV4::ExecutionEngine::Deletable
{
public:
QQuickContext2DEngineData(QV4::ExecutionEngine *engine);
@@ -4324,7 +4323,8 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_renderTarget = QQuickCanvasItem::Image;
}
- // Disable Framebuffer Object based rendering when not running with OpenGL
+ // Disable Framebuffer Object based rendering when not running with OpenGL.
+ // Same goes for the RHI based code path (regardless of the backend in use).
if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
QSGRendererInterface *rif = canvasItem->window()->rendererInterface();
if (rif && rif->graphicsApi() != QSGRendererInterface::OpenGL)
@@ -4587,6 +4587,11 @@ void QQuickContext2D::reset()
m_buffer->clearRect(QRectF(0, 0, m_canvas->width(), m_canvas->height()));
}
+QV4::ExecutionEngine *QQuickContext2D::v4Engine() const
+{
+ return m_v4engine;
+}
+
void QQuickContext2D::setV4Engine(QV4::ExecutionEngine *engine)
{
if (m_v4engine != engine) {
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 1ece6796f3..b5626dec0c 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -65,7 +65,6 @@ QT_REQUIRE_CONFIG(quick_canvas);
#include <QtCore/qstring.h>
#include <QtCore/qstack.h>
#include <QtCore/qqueue.h>
-#include <private/qv8engine_p.h>
#include <QtCore/QWaitCondition>
#include <private/qv4value_p.h>
@@ -199,6 +198,7 @@ public:
QImage toImage(const QRectF& bounds) override;
QV4::ReturnedValue v4value() const override;
+ QV4::ExecutionEngine *v4Engine() const override;
void setV4Engine(QV4::ExecutionEngine *eng) override;
QQuickCanvasItem* canvas() const { return m_canvas; }
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index 69ff3b3852..0ebd1a66c9 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -41,7 +41,7 @@
#include "qquickcontext2dtile_p.h"
#include "qquickcanvasitem_p.h"
#include <private/qquickitem_p.h>
-#include <QtQuick/private/qsgtexture_p.h>
+#include <QtQuick/private/qsgplaintexture_p.h>
#include "qquickcontext2dcommandbuffer_p.h"
#include <QOpenGLPaintDevice>
#if QT_CONFIG(opengl)
@@ -238,15 +238,8 @@ void QQuickContext2DTexture::paintWithoutTiles(QQuickContext2DCommandBuffer *ccb
QPainter p;
p.begin(device);
- if (m_antialiasing)
- p.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing, true);
- else
- p.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing, false);
-
- if (m_smooth)
- p.setRenderHint(QPainter::SmoothPixmapTransform, true);
- else
- p.setRenderHint(QPainter::SmoothPixmapTransform, false);
+ p.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing, m_antialiasing);
+ p.setRenderHint(QPainter::SmoothPixmapTransform, m_smooth);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index e649b5429d..6f2f9fbd8e 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -52,8 +52,6 @@ HEADERS += \
$$PWD/qquickstateoperations_p.h \
$$PWD/qquickimplicitsizeitem_p.h \
$$PWD/qquickimplicitsizeitem_p_p.h \
- $$PWD/qquickdrag_p.h \
- $$PWD/qquickdroparea_p.h \
$$PWD/qquickmultipointtoucharea_p.h \
$$PWD/qquickscreen_p.h \
$$PWD/qquickwindowattached_p.h \
@@ -95,8 +93,6 @@ SOURCES += \
$$PWD/qquickstateoperations.cpp \
$$PWD/qquickimplicitsizeitem.cpp \
$$PWD/qquickaccessibleattached.cpp \
- $$PWD/qquickdrag.cpp \
- $$PWD/qquickdroparea.cpp \
$$PWD/qquickmultipointtoucharea.cpp \
$$PWD/qquickwindowmodule.cpp \
$$PWD/qquickscreen.cpp \
@@ -105,6 +101,16 @@ SOURCES += \
$$PWD/qquickgraphicsinfo.cpp \
$$PWD/qquickitemgrabresult.cpp
+qtConfig(quick-draganddrop) {
+ HEADERS += \
+ $$PWD/qquickdrag_p.h \
+ $$PWD/qquickdroparea_p.h \
+
+ SOURCES += \
+ $$PWD/qquickdrag.cpp \
+ $$PWD/qquickdroparea.cpp \
+}
+
qtConfig(quick-animatedimage) {
HEADERS += \
$$PWD/qquickanimatedimage_p.h \
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp
index fe445425e7..18d492cd68 100644
--- a/src/quick/items/qquickanimatedimage.cpp
+++ b/src/quick/items/qquickanimatedimage.cpp
@@ -67,7 +67,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine
.arg(current));
}
if (!requestedUrl.isEmpty()) {
- if (QQuickPixmap::isCached(requestedUrl, QSize(), QQuickImageProviderOptions()))
+ if (QQuickPixmap::isCached(requestedUrl, QSize(), 0, QQuickImageProviderOptions()))
pixmap = new QQuickPixmap(engine, requestedUrl);
else
pixmap = new QQuickPixmap(requestedUrl, movie->currentImage());
@@ -139,6 +139,9 @@ QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
: QQuickImage(*(new QQuickAnimatedImagePrivate), parent)
{
connect(this, &QQuickImageBase::cacheChanged, this, &QQuickAnimatedImage::onCacheChanged);
+ connect(this, &QQuickImageBase::currentFrameChanged, this, &QQuickAnimatedImage::frameChanged);
+ connect(this, &QQuickImageBase::currentFrameChanged, this, &QQuickAnimatedImage::currentFrameChanged);
+ connect(this, &QQuickImageBase::frameCountChanged, this, &QQuickAnimatedImage::frameCountChanged);
}
QQuickAnimatedImage::~QQuickAnimatedImage()
@@ -464,7 +467,7 @@ void QQuickAnimatedImage::movieUpdate()
if (d->movie) {
d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this)));
- emit frameChanged();
+ emit QQuickImageBase::currentFrameChanged();
}
}
diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h
index 6b5db215bd..13eae83350 100644
--- a/src/quick/items/qquickanimatedimage_p.h
+++ b/src/quick/items/qquickanimatedimage_p.h
@@ -85,10 +85,10 @@ public:
bool isPaused() const;
void setPaused(bool pause);
- int currentFrame() const;
- void setCurrentFrame(int frame);
+ int currentFrame() const override;
+ void setCurrentFrame(int frame) override;
- int frameCount() const;
+ int frameCount() const override;
qreal speed() const;
void setSpeed(qreal speed);
@@ -101,6 +101,7 @@ Q_SIGNALS:
void playingChanged();
void pausedChanged();
void frameChanged();
+ void currentFrameChanged();
void frameCountChanged();
Q_REVISION(11) void speedChanged();
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index 18adb4e992..d22e77c8ad 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -532,7 +532,7 @@ void QQuickAnimatedSprite::setInterpolate(bool arg)
}
}
-void QQuickAnimatedSprite::setSource(QUrl arg)
+void QQuickAnimatedSprite::setSource(const QUrl &arg)
{
Q_D(QQuickAnimatedSprite);
diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h
index ff59591c9f..d36f908c78 100644
--- a/src/quick/items/qquickanimatedsprite_p.h
+++ b/src/quick/items/qquickanimatedsprite_p.h
@@ -122,7 +122,7 @@ Q_SIGNALS:
void runningChanged(bool arg);
void interpolateChanged(bool arg);
- void sourceChanged(QUrl arg);
+ void sourceChanged(const QUrl &arg);
void reverseChanged(bool arg);
void frameSyncChanged(bool arg);
void frameCountChanged(int arg);
@@ -148,7 +148,7 @@ public Q_SLOTS:
void setRunning(bool arg);
void setPaused(bool arg);
void setInterpolate(bool arg);
- void setSource(QUrl arg);
+ void setSource(const QUrl &arg);
void setReverse(bool arg);
void setFrameSync(bool arg);
void setFrameCount(int arg);
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index b840328184..462a44634e 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -327,7 +327,7 @@ void QQuickBorderImage::load()
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 {
@@ -343,7 +343,7 @@ void QQuickBorderImage::load()
QUrl loadUrl = d->url;
resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
- d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options);
+ d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, QQuickImageProviderOptions(), d->currentFrame, d->frameCount);
if (d->pix.isLoading()) {
if (d->progress != 0.0) {
@@ -534,6 +534,10 @@ void QQuickBorderImage::requestFinished()
d->oldSourceSize = sourceSize();
emit sourceSizeChanged();
}
+ if (d->frameCount != d->pix.frameCount()) {
+ d->frameCount = d->pix.frameCount();
+ emit frameCountChanged();
+ }
pixmapChange();
}
@@ -647,7 +651,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;
}
@@ -693,6 +697,18 @@ 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.
+*/
+
QT_END_NAMESPACE
#include "moc_qquickborderimage_p.cpp"
diff --git a/src/quick/items/qquickborderimage_p_p.h b/src/quick/items/qquickborderimage_p_p.h
index 0f4e7acc05..17dab7d121 100644
--- a/src/quick/items/qquickborderimage_p_p.h
+++ b/src/quick/items/qquickborderimage_p_p.h
@@ -86,7 +86,7 @@ public:
if (!border) {
border = new QQuickScaleGrid(q);
qmlobject_connect(border, QQuickScaleGrid, SIGNAL(borderChanged()),
- q, QQuickBorderImage, SLOT(doUpdate()))
+ q, QQuickBorderImage, SLOT(doUpdate()));
}
return border;
}
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index a2cb739ff2..7c6f1caa54 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -45,7 +45,6 @@
#include <QtQuick/private/qquickevents_p_p.h>
#include <private/qquickitemchangelistener_p.h>
#include <private/qquickpixmapcache_p.h>
-#include <private/qv8engine_p.h>
#include <private/qv4scopedvalue_p.h>
#include <QtCore/qmimedata.h>
#include <QtQml/qqmlinfo.h>
@@ -53,7 +52,6 @@
#include <QtGui/qstylehints.h>
#include <QtGui/qguiapplication.h>
-#if QT_CONFIG(draganddrop)
#include <qpa/qplatformdrag.h>
#include <QtGui/qdrag.h>
@@ -1001,5 +999,3 @@ QQuickDragAttached *QQuickDrag::qmlAttachedProperties(QObject *obj)
QT_END_NAMESPACE
#include "moc_qquickdrag_p.cpp"
-
-#endif // draganddrop
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index 6bfbae74c9..094070aa2c 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -53,14 +53,14 @@
#include <QtQuick/qquickitem.h>
-#include <private/qv8engine_p.h>
+#include <private/qintrusivelist_p.h>
#include <private/qqmlguard_p.h>
#include <QtCore/qmimedata.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qurl.h>
-#if QT_CONFIG(draganddrop)
+QT_REQUIRE_CONFIG(quick_draganddrop);
QT_BEGIN_NAMESPACE
@@ -318,6 +318,4 @@ QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickDrag)
QML_DECLARE_TYPEINFO(QQuickDrag, QML_HAS_ATTACHED_PROPERTIES)
-#endif // draganddrop
-
#endif
diff --git a/src/quick/items/qquickdroparea.cpp b/src/quick/items/qquickdroparea.cpp
index fbbee31653..76be8cc261 100644
--- a/src/quick/items/qquickdroparea.cpp
+++ b/src/quick/items/qquickdroparea.cpp
@@ -43,7 +43,7 @@
#include <private/qv4arraybuffer_p.h>
-#if QT_CONFIG(draganddrop)
+#include <QtCore/qregularexpression.h>
QT_BEGIN_NAMESPACE
@@ -70,7 +70,7 @@ public:
QStringList getKeys(const QMimeData *mimeData) const;
QStringList keys;
- QRegExp keyRegExp;
+ QRegularExpression keyRegExp;
QPointF dragPosition;
QQuickDropAreaDrag *drag;
QPointer<QObject> source;
@@ -157,13 +157,15 @@ void QQuickDropArea::setKeys(const QStringList &keys)
d->keys = keys;
if (keys.isEmpty()) {
- d->keyRegExp = QRegExp();
+ d->keyRegExp = QRegularExpression();
} else {
- QString pattern = QLatin1Char('(') + QRegExp::escape(keys.first());
+ QString pattern = QLatin1Char('(') + QRegularExpression::escape(keys.first());
for (int i = 1; i < keys.count(); ++i)
- pattern += QLatin1Char('|') + QRegExp::escape(keys.at(i));
+ pattern += QLatin1Char('|') + QRegularExpression::escape(keys.at(i));
pattern += QLatin1Char(')');
- d->keyRegExp = QRegExp(pattern.replace(QLatin1String("\\*"), QLatin1String(".+")));
+ d->keyRegExp = QRegularExpression(
+ QRegularExpression::anchoredPattern(pattern.replace(QLatin1String("\\*"),
+ QLatin1String(".+"))));
}
emit keysChanged();
}
@@ -231,12 +233,11 @@ void QQuickDropArea::dragMoveEvent(QDragMoveEvent *event)
bool QQuickDropAreaPrivate::hasMatchingKey(const QStringList &keys) const
{
- if (keyRegExp.isEmpty())
+ if (keyRegExp.pattern().isEmpty())
return true;
- QRegExp copy = keyRegExp;
for (const QString &key : keys) {
- if (copy.exactMatch(key))
+ if (key.contains(keyRegExp))
return true;
}
return false;
@@ -619,5 +620,3 @@ void QQuickDropEvent::accept(QQmlV4Function *args)
QT_END_NAMESPACE
#include "moc_qquickdroparea_p.cpp"
-
-#endif // draganddrop
diff --git a/src/quick/items/qquickdroparea_p.h b/src/quick/items/qquickdroparea_p.h
index d25cd4decc..2b2ace2eae 100644
--- a/src/quick/items/qquickdroparea_p.h
+++ b/src/quick/items/qquickdroparea_p.h
@@ -55,7 +55,7 @@
#include <QtGui/qevent.h>
-#if QT_CONFIG(draganddrop)
+QT_REQUIRE_CONFIG(quick_draganddrop);
QT_BEGIN_NAMESPACE
@@ -190,6 +190,4 @@ QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickDropEvent)
QML_DECLARE_TYPE(QQuickDropArea)
-#endif // draganddrop
-
#endif // QQUICKDROPAREA_P_H
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 7d128b4a16..0c697739fa 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -41,6 +41,7 @@
#include <QtCore/qmap.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qtouchdevice_p.h>
+#include <QtGui/private/qevent_p.h>
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquickwindow_p.h>
@@ -1448,7 +1449,7 @@ QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event)
m_synthSource = ev->source();
m_inverted = ev->inverted();
- m_point->reset(Qt::TouchPointMoved, ev->posF(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
+ m_point->reset(Qt::TouchPointMoved, ev->position(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
}
#endif
// TODO else if (event->type() == QEvent::Scroll) ...
@@ -1828,6 +1829,7 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i
// but that would require changing tst_qquickwindow::touchEvent_velocity(): it expects transformed velocity
bool anyPressOrReleaseInside = false;
+ bool anyStationaryWithModifiedPropertyInside = false;
bool anyGrabber = false;
QMatrix4x4 transformMatrix(QQuickItemPrivate::get(item)->windowToItemTransform());
for (int i = 0; i < m_pointCount; ++i) {
@@ -1860,6 +1862,8 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i
anyPressOrReleaseInside = true;
const QTouchEvent::TouchPoint *tp = touchPointById(p->pointId());
if (tp) {
+ if (isInside && tp->d->stationaryWithModifiedProperty)
+ anyStationaryWithModifiedPropertyInside = true;
eventStates |= tp->state();
QTouchEvent::TouchPoint tpCopy = *tp;
tpCopy.setPos(item->mapFromScene(tpCopy.scenePos()));
@@ -1873,7 +1877,8 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i
// Now touchPoints will have only points which are inside the item.
// But if none of them were just pressed inside, and the item has no other reason to care, ignore them anyway.
- if (eventStates == Qt::TouchPointStationary || touchPoints.isEmpty() || (!anyPressOrReleaseInside && !anyGrabber && !isFiltering))
+ if ((eventStates == Qt::TouchPointStationary && !anyStationaryWithModifiedPropertyInside) ||
+ touchPoints.isEmpty() || (!anyPressOrReleaseInside && !anyGrabber && !isFiltering))
return nullptr;
// if all points have the same state, set the event type accordingly
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index e614b1bd6d..1a3737091f 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -605,6 +605,7 @@ private:
bool m_inverted = false;
friend class QQuickWindowPrivate;
+ friend class QQuickWheelHandler;
Q_DISABLE_COPY(QQuickPointerScrollEvent)
};
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 7e1f54f07e..d9ec7de611 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -266,9 +266,9 @@ void QQuickFlickablePrivate::init()
QQml_setParent_noEvent(contentItem, q);
contentItem->setParentItem(q);
qmlobject_connect(&timeline, QQuickTimeLine, SIGNAL(completed()),
- q, QQuickFlickable, SLOT(timelineCompleted()))
+ q, QQuickFlickable, SLOT(timelineCompleted()));
qmlobject_connect(&velocityTimeline, QQuickTimeLine, SIGNAL(completed()),
- q, QQuickFlickable, SLOT(velocityTimelineCompleted()))
+ q, QQuickFlickable, SLOT(velocityTimelineCompleted()));
q->setAcceptedMouseButtons(Qt::LeftButton);
q->setAcceptTouchEvents(false); // rely on mouse events synthesized from touch
q->setFiltersChildMouseEvents(true);
@@ -1489,7 +1489,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
d->vData.velocity = 0;
d->hData.velocity = 0;
d->timer.start();
- d->maybeBeginDrag(currentTimestamp, event->posF());
+ d->maybeBeginDrag(currentTimestamp, event->position());
break;
case Qt::NoScrollPhase: // default phase with an ordinary wheel mouse
case Qt::ScrollUpdate:
@@ -1571,7 +1571,8 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
QVector2D velocity(xDelta / elapsed, yDelta / elapsed);
d->lastPosTime = currentTimestamp;
d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta());
- d->drag(currentTimestamp, event->type(), event->posF(), d->accumulatedWheelPixelDelta, true, !d->scrollingPhase, true, velocity);
+ d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta,
+ true, !d->scrollingPhase, true, velocity);
event->accept();
}
diff --git a/src/quick/items/qquickflickablebehavior_p.h b/src/quick/items/qquickflickablebehavior_p.h
index ae7fe71359..fbce62f075 100644
--- a/src/quick/items/qquickflickablebehavior_p.h
+++ b/src/quick/items/qquickflickablebehavior_p.h
@@ -93,6 +93,11 @@
#define QML_FLICK_MULTIFLICK_THRESHOLD 1250
#endif
+// If the time (ms) between the last move and the release exceeds this, then velocity will be zero.
+#ifndef QML_FLICK_VELOCITY_DECAY_TIME
+#define QML_FLICK_VELOCITY_DECAY_TIME 50
+#endif
+
// Multiflick acceleration minimum contentSize/viewSize ratio
#ifndef QML_FLICK_MULTIFLICK_RATIO
#define QML_FLICK_MULTIFLICK_RATIO 10
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index 48f8b8db5c..190bc6853c 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -109,6 +109,10 @@ public:
* and can be used directly in \l {ShaderEffect}{ShaderEffects} and other
* classes that consume texture providers.
*
+ * \warning This class is only suitable when working directly with OpenGL. It
+ * is not compatible with the \l{Scene Graph Adaptations}{RHI-based rendering
+ * path}.
+ *
* \sa {Scene Graph - Rendering FBOs}, {Scene Graph and Rendering}
*/
diff --git a/src/quick/items/qquickframebufferobject.h b/src/quick/items/qquickframebufferobject.h
index d66ca40b3a..db143e48cf 100644
--- a/src/quick/items/qquickframebufferobject.h
+++ b/src/quick/items/qquickframebufferobject.h
@@ -44,11 +44,12 @@
QT_BEGIN_NAMESPACE
-
class QOpenGLFramebufferObject;
class QQuickFramebufferObjectPrivate;
class QSGFramebufferObjectNode;
+// ### Qt 6: To be removed. To be seen if an alternative will need to be introduced.
+
class Q_QUICK_EXPORT QQuickFramebufferObject : public QQuickItem
{
Q_OBJECT
diff --git a/src/quick/items/qquickgenericshadereffect.cpp b/src/quick/items/qquickgenericshadereffect.cpp
index 248c2b6ec3..df61ee853d 100644
--- a/src/quick/items/qquickgenericshadereffect.cpp
+++ b/src/quick/items/qquickgenericshadereffect.cpp
@@ -40,15 +40,32 @@
#include <private/qquickgenericshadereffect_p.h>
#include <private/qquickwindow_p.h>
#include <private/qquickitem_p.h>
-#include <QSignalMapper>
QT_BEGIN_NAMESPACE
-// The generic shader effect is used when the scenegraph backend indicates
-// SupportsShaderEffectNode. This, unlike the monolithic and interconnected (e.g.
-// with particles) OpenGL variant, passes most of the work to a scenegraph node
-// created via the adaptation layer, thus allowing different implementation in
-// the backends.
+namespace {
+class IntSignalMapper : public QObject
+{
+ Q_OBJECT
+
+ int value;
+public:
+ explicit IntSignalMapper(int v)
+ : QObject(nullptr), value(v) {}
+
+public Q_SLOTS:
+ void map() { emit mapped(value); }
+
+Q_SIGNALS:
+ void mapped(int);
+};
+} // unnamed namespace
+
+// The generic shader effect is used whenever on the RHI code path, or when the
+// scenegraph backend indicates SupportsShaderEffectNode. This, unlike the
+// monolithic and interconnected (e.g. with particles) OpenGL variant, passes
+// most of the work to a scenegraph node created via the adaptation layer, thus
+// allowing different implementation in the backends.
QQuickGenericShaderEffect::QQuickGenericShaderEffect(QQuickShaderEffect *item, QObject *parent)
: QObject(parent)
@@ -123,8 +140,8 @@ void QQuickGenericShaderEffect::setBlending(bool enable)
QVariant QQuickGenericShaderEffect::mesh() const
{
- return m_mesh ? qVariantFromValue(static_cast<QObject *>(m_mesh))
- : qVariantFromValue(m_meshResolution);
+ return m_mesh ? QVariant::fromValue(static_cast<QObject *>(m_mesh))
+ : QVariant::fromValue(m_meshResolution);
}
void QQuickGenericShaderEffect::setMesh(const QVariant &mesh)
@@ -254,6 +271,10 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
if (!node) {
QSGRenderContext *rc = QQuickWindowPrivate::get(m_item->window())->context;
node = rc->sceneGraphContext()->createShaderEffectNode(rc, mgr);
+ if (!node) {
+ qWarning("No shader effect node");
+ return nullptr;
+ }
m_dirty = QSGShaderEffectNode::DirtyShaderAll;
}
@@ -445,7 +466,7 @@ bool QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray
// provided and monitored like with an application-provided shader.
QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
v.name = QByteArrayLiteral("source");
- v.bindPoint = 0;
+ v.bindPoint = 0; // fake
v.type = texturesSeparate ? QSGGuiThreadShaderEffectManager::ShaderInfo::Texture
: QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
m_shaders[shaderType].shaderInfo.variables.append(v);
@@ -543,15 +564,10 @@ void QQuickGenericShaderEffect::updateShaderVars(Shader shaderType)
if (!mp.hasNotifySignal())
qWarning("ShaderEffect: property '%s' does not have notification method", v.name.constData());
- // Have a QSignalMapper that emits mapped() with an index+type on each property change notify signal.
+ // Have a IntSignalMapper that emits mapped() with an index+type on each property change notify signal.
auto &sm(m_signalMappers[shaderType][i]);
- if (!sm.mapper) {
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- sm.mapper = new QSignalMapper;
-QT_WARNING_POP
- sm.mapper->setMapping(m_item, i | (shaderType << 16));
- }
+ if (!sm.mapper)
+ sm.mapper = new IntSignalMapper(i | (shaderType << 16));
sm.active = true;
const QByteArray signalName = '2' + mp.notifySignal().methodSignature();
QObject::connect(m_item, signalName, sm.mapper, SLOT(map()));
@@ -559,7 +575,7 @@ QT_WARNING_POP
} else {
// Do not warn for dynamic properties.
if (!m_item->property(v.name.constData()).isValid())
- qWarning("ShaderEffect: '%s' does not have a matching property!", v.name.constData());
+ qWarning("ShaderEffect: '%s' does not have a matching property", v.name.constData());
}
vd.value = m_item->property(v.name.constData());
@@ -661,3 +677,4 @@ void QQuickGenericShaderEffect::markGeometryDirtyAndUpdateIfSupportsAtlas()
QT_END_NAMESPACE
#include "moc_qquickgenericshadereffect_p.cpp"
+#include "qquickgenericshadereffect.moc"
diff --git a/src/quick/items/qquickgenericshadereffect_p.h b/src/quick/items/qquickgenericshadereffect_p.h
index 3f6f92921b..368c32d2f8 100644
--- a/src/quick/items/qquickgenericshadereffect_p.h
+++ b/src/quick/items/qquickgenericshadereffect_p.h
@@ -59,8 +59,6 @@
QT_BEGIN_NAMESPACE
-class QSignalMapper;
-
class Q_QUICK_PRIVATE_EXPORT QQuickGenericShaderEffect : public QObject
{
Q_OBJECT
@@ -142,7 +140,7 @@ private:
struct SignalMapper {
SignalMapper() : mapper(nullptr), active(false) { }
- QSignalMapper *mapper;
+ QObject *mapper;
bool active;
};
QVector<SignalMapper> m_signalMappers[NShader];
diff --git a/src/quick/items/qquickgraphicsinfo.cpp b/src/quick/items/qquickgraphicsinfo.cpp
index cd1012c690..8f6f4386fb 100644
--- a/src/quick/items/qquickgraphicsinfo.cpp
+++ b/src/quick/items/qquickgraphicsinfo.cpp
@@ -96,6 +96,12 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
\li GraphicsInfo.Software - Qt Quick's software renderer based on QPainter with the raster paint engine
\li GraphicsInfo.OpenGL - OpenGL or OpenGL ES
\li GraphicsInfo.Direct3D12 - Direct3D 12
+ \li GraphicsInfo.OpenVG - OpenVG
+ \li GraphicsInfo.OpenGLRhi - OpenGL on top of QRhi, a graphics abstraction layer
+ \li GraphicsInfo.Direct3D11Rhi - Direct3D 11 on top of QRhi, a graphics abstraction layer
+ \li GraphicsInfo.VulkanRhi - Vulkan on top of QRhi, a graphics abstraction layer
+ \li GraphicsInfo.MetalRhi - Metal on top of QRhi, a graphics abstraction layer
+ \li GraphicsInfo.NullRhi - Null (no output) on top of QRhi, a graphics abstraction layer
\endlist
*/
@@ -109,6 +115,7 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
\li GraphicsInfo.UnknownShadingLanguage - Not yet known due to no window and scenegraph associated
\li GraphicsInfo.GLSL - GLSL or GLSL ES
\li GraphicsInfo.HLSL - HLSL
+ \li GraphicsInfo.RhiShader - QShader
\endlist
\note The value is only up-to-date once the item is associated with a
diff --git a/src/quick/items/qquickgraphicsinfo_p.h b/src/quick/items/qquickgraphicsinfo_p.h
index 9ef7bacb3e..f0a18c29cc 100644
--- a/src/quick/items/qquickgraphicsinfo_p.h
+++ b/src/quick/items/qquickgraphicsinfo_p.h
@@ -80,14 +80,21 @@ public:
Unknown = QSGRendererInterface::Unknown,
Software = QSGRendererInterface::Software,
OpenGL = QSGRendererInterface::OpenGL,
- Direct3D12 = QSGRendererInterface::Direct3D12
+ Direct3D12 = QSGRendererInterface::Direct3D12,
+ OpenVG = QSGRendererInterface::OpenVG,
+ OpenGLRhi = QSGRendererInterface::OpenGLRhi,
+ Direct3D11Rhi = QSGRendererInterface::Direct3D11Rhi,
+ VulkanRhi = QSGRendererInterface::VulkanRhi,
+ MetalRhi = QSGRendererInterface::MetalRhi,
+ NullRhi = QSGRendererInterface::NullRhi
};
Q_ENUM(GraphicsApi)
enum ShaderType {
UnknownShadingLanguage = QSGRendererInterface::UnknownShadingLanguage,
GLSL = QSGRendererInterface::GLSL,
- HLSL = QSGRendererInterface::HLSL
+ HLSL = QSGRendererInterface::HLSL,
+ RhiShader = QSGRendererInterface::RhiShader
};
Q_ENUM(ShaderType)
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 16343774e2..840cfe15da 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -663,7 +663,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
if (!node) {
d->pixmapChanged = true;
- node = d->sceneGraphContext()->createInternalImageNode();
+ node = d->sceneGraphContext()->createInternalImageNode(d->sceneGraphRenderContext());
}
QRectF targetRect;
@@ -687,7 +687,6 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
yOffset = qCeil(height() - pixHeight);
switch (d->fillMode) {
- default:
case Stretch:
targetRect = QRectF(0, 0, width(), height());
sourceRect = d->pix.rect();
@@ -699,7 +698,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
break;
case PreserveAspectCrop: {
- targetRect = QRect(0, 0, width(), height());
+ targetRect = QRectF(0, 0, width(), height());
qreal wscale = width() / qreal(d->pix.width());
qreal hscale = height() / qreal(d->pix.height());
@@ -751,7 +750,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
targetRect = QRectF(x + xOffset, y + yOffset, w, h);
sourceRect = QRectF(x, y, w, h);
break;
- };
+ }
qreal nsWidth = (hWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.width() / d->devicePixelRatio : d->pix.width();
qreal nsHeight = (vWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.height() / d->devicePixelRatio : d->pix.height();
@@ -889,4 +888,16 @@ void QQuickImage::setMipmap(bool use)
By default, this property is set to false.
*/
+/*!
+ \qmlproperty int QtQuick::Image::currentFrame
+ \qmlproperty int QtQuick::Image::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.
+*/
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickimage_p.h b/src/quick/items/qquickimage_p.h
index 7fb4413900..257cde5313 100644
--- a/src/quick/items/qquickimage_p.h
+++ b/src/quick/items/qquickimage_p.h
@@ -66,8 +66,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImage : public QQuickImageBase
Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedGeometryChanged)
Q_PROPERTY(HAlignment horizontalAlignment READ horizontalAlignment WRITE setHorizontalAlignment NOTIFY horizontalAlignmentChanged)
Q_PROPERTY(VAlignment verticalAlignment READ verticalAlignment WRITE setVerticalAlignment NOTIFY verticalAlignmentChanged)
- Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged REVISION 1)
- Q_PROPERTY(bool autoTransform READ autoTransform WRITE setAutoTransform NOTIFY autoTransformChanged REVISION 2)
+ Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged REVISION 3)
+ Q_PROPERTY(bool autoTransform READ autoTransform WRITE setAutoTransform NOTIFY autoTransformChanged REVISION 5)
public:
QQuickImage(QQuickItem *parent=nullptr);
@@ -112,8 +112,8 @@ Q_SIGNALS:
void paintedGeometryChanged();
void horizontalAlignmentChanged(HAlignment alignment);
void verticalAlignmentChanged(VAlignment alignment);
- Q_REVISION(1) void mipmapChanged(bool);
- Q_REVISION(2) void autoTransformChanged();
+ Q_REVISION(3) void mipmapChanged(bool);
+ Q_REVISION(5) void autoTransformChanged();
private Q_SLOTS:
void invalidateSceneGraph();
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 74ee859f77..8bab14bfd1 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -46,6 +46,8 @@
#include <QtQml/qqmlinfo.h>
#include <QtQml/qqmlfile.h>
+#include <QtQml/qqmlabstracturlinterceptor.h>
+
QT_BEGIN_NAMESPACE
@@ -53,7 +55,7 @@ QT_BEGIN_NAMESPACE
// if they're not happy with our implementation of it.
bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio)
{
- // QQuickImageProvider and SVG can generate a high resolution image when
+ // QQuickImageProvider and SVG and PDF can generate a high resolution image when
// sourceSize is set (this function is only called if it's set).
// If sourceSize is not set then the provider default size will be used, as usual.
bool setDevicePixelRatio = false;
@@ -62,7 +64,8 @@ bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio
} else {
QString stringUrl = url.path(QUrl::PrettyDecoded);
if (stringUrl.endsWith(QLatin1String("svg")) ||
- stringUrl.endsWith(QLatin1String("svgz"))) {
+ stringUrl.endsWith(QLatin1String("svgz")) ||
+ stringUrl.endsWith(QLatin1String("pdf"))) {
setDevicePixelRatio = true;
}
}
@@ -208,6 +211,36 @@ bool QQuickImageBase::mirror() const
return d->mirror;
}
+void QQuickImageBase::setCurrentFrame(int frame)
+{
+ Q_D(QQuickImageBase);
+ if (frame == d->currentFrame || frame < 0 || (isComponentComplete() && frame >= d->pix.frameCount()))
+ return;
+
+ d->currentFrame = frame;
+
+ if (isComponentComplete()) {
+ if (frame > 0)
+ d->cache = false;
+ load();
+ update();
+ }
+
+ emit currentFrameChanged();
+}
+
+int QQuickImageBase::currentFrame() const
+{
+ Q_D(const QQuickImageBase);
+ return d->currentFrame;
+}
+
+int QQuickImageBase::frameCount() const
+{
+ Q_D(const QQuickImageBase);
+ return d->frameCount;
+}
+
void QQuickImageBase::load()
{
Q_D(QQuickImageBase);
@@ -244,6 +277,9 @@ void QQuickImageBase::load()
d->devicePixelRatio = 1.0;
QUrl loadUrl = d->url;
+ QQmlEngine* engine = qmlEngine(this);
+ if (engine && engine->urlInterceptor())
+ loadUrl = engine->urlInterceptor()->intercept(loadUrl, QQmlAbstractUrlInterceptor::UrlString);
bool updatedDevicePixelRatio = false;
if (d->sourcesize.isValid())
@@ -255,7 +291,7 @@ void QQuickImageBase::load()
resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
}
- d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, d->providerOptions);
+ d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, d->providerOptions, d->currentFrame, d->frameCount);
if (d->pix.isLoading()) {
if (d->progress != 0.0) {
@@ -314,6 +350,11 @@ void QQuickImageBase::requestFinished()
d->oldAutoTransform = autoTransform();
emitAutoTransformBaseChanged();
}
+ if (d->frameCount != d->pix.frameCount()) {
+ d->frameCount = d->pix.frameCount();
+ emit frameCountChanged();
+ }
+
update();
}
diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h
index d8d0be9b8c..8cd59c8cea 100644
--- a/src/quick/items/qquickimagebase_p.h
+++ b/src/quick/items/qquickimagebase_p.h
@@ -68,6 +68,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImageBase : public QQuickImplicitSizeItem
Q_PROPERTY(bool cache READ cache WRITE setCache NOTIFY cacheChanged)
Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize RESET resetSourceSize NOTIFY sourceSizeChanged)
Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged)
+ Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged REVISION 14)
+ Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged REVISION 14)
public:
QQuickImageBase(QQuickItem *parent=nullptr);
@@ -95,6 +97,11 @@ public:
virtual void setMirror(bool mirror);
bool mirror() const;
+ virtual void setCurrentFrame(int frame);
+ virtual int currentFrame() const;
+
+ virtual int frameCount() const;
+
virtual void setAutoTransform(bool transform);
bool autoTransform() const;
@@ -112,6 +119,8 @@ Q_SIGNALS:
void asynchronousChanged();
void cacheChanged();
void mirrorChanged();
+ Q_REVISION(14) void currentFrameChanged();
+ Q_REVISION(14) void frameCountChanged();
protected:
virtual void load();
diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h
index 1b771166a2..88e18ba32e 100644
--- a/src/quick/items/qquickimagebase_p_p.h
+++ b/src/quick/items/qquickimagebase_p_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -68,6 +68,8 @@ public:
: status(QQuickImageBase::Null),
progress(0.0),
devicePixelRatio(1.0),
+ currentFrame(0),
+ frameCount(0),
async(false),
cache(true),
mirror(false),
@@ -85,6 +87,8 @@ public:
QSize oldSourceSize;
qreal devicePixelRatio;
QQuickImageProviderOptions providerOptions;
+ int currentFrame;
+ int frameCount;
bool async : 1;
bool cache : 1;
bool mirror: 1;
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index d90cc71997..4c20b7e2e1 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -4177,7 +4177,7 @@ void QQuickItem::hoverLeaveEvent(QHoverEvent *event)
Q_UNUSED(event);
}
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
/*!
This event handler can be reimplemented in a subclass to receive drag-enter
events for an item. The event information is provided by the
@@ -4245,7 +4245,7 @@ void QQuickItem::dropEvent(QDropEvent *event)
{
Q_UNUSED(event);
}
-#endif // draganddrop
+#endif // quick_draganddrop
/*!
Reimplement this method to filter the mouse events that are received by
@@ -5097,7 +5097,7 @@ QQuickStateGroup *QQuickItemPrivate::_states()
if (!componentComplete)
_stateGroup->classBegin();
qmlobject_connect(_stateGroup, QQuickStateGroup, SIGNAL(stateChanged(QString)),
- q, QQuickItem, SIGNAL(stateChanged(QString)))
+ q, QQuickItem, SIGNAL(stateChanged(QString)));
}
return _stateGroup;
@@ -5136,6 +5136,40 @@ void QQuickItemPrivate::transformChanged()
#endif
}
+QPointF QQuickItemPrivate::adjustedPosForTransform(const QPointF &centroidParentPos,
+ const QPointF &startPos,
+ const QVector2D &activeTranslation, //[0,0] means no additional translation from startPos
+ qreal startScale,
+ qreal activeScale, // 1.0 means no additional scale from startScale
+ qreal startRotation,
+ qreal activeRotation) // 0.0 means no additional rotation from startRotation
+{
+ Q_Q(QQuickItem);
+ QVector3D xformOrigin(q->transformOriginPoint());
+ QMatrix4x4 startMatrix;
+ startMatrix.translate(float(startPos.x()), float(startPos.y()));
+ startMatrix.translate(xformOrigin);
+ startMatrix.scale(float(startScale));
+ startMatrix.rotate(float(startRotation), 0, 0, -1);
+ startMatrix.translate(-xformOrigin);
+
+ const QVector3D centroidParentVector(centroidParentPos);
+ QMatrix4x4 mat;
+ mat.translate(centroidParentVector);
+ mat.rotate(float(activeRotation), 0, 0, 1);
+ mat.scale(float(activeScale));
+ mat.translate(-centroidParentVector);
+ mat.translate(QVector3D(activeTranslation));
+
+ mat = mat * startMatrix;
+
+ QPointF xformOriginPoint = q->transformOriginPoint();
+ QPointF pos = mat * xformOriginPoint;
+ pos -= xformOriginPoint;
+
+ return pos;
+}
+
bool QQuickItemPrivate::filterKeyEvent(QKeyEvent *e, bool post)
{
if (!extra.isAllocated() || !extra->keyHandler)
@@ -5666,6 +5700,7 @@ void QQuickItem::setRotation(qreal r)
color: "red"
x: 25; y: 25; width: 50; height: 50
scale: 1.4
+ transformOrigin: Item.TopLeft
}
}
\endqml
@@ -8098,7 +8133,7 @@ bool QQuickItem::event(QEvent *ev)
wheelEvent(static_cast<QWheelEvent*>(ev));
break;
#endif
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
case QEvent::DragEnter:
dragEnterEvent(static_cast<QDragEnterEvent*>(ev));
break;
@@ -8111,7 +8146,7 @@ bool QQuickItem::event(QEvent *ev)
case QEvent::Drop:
dropEvent(static_cast<QDropEvent*>(ev));
break;
-#endif // draganddrop
+#endif // quick_draganddrop
#if QT_CONFIG(gestures)
case QEvent::NativeGesture:
ev->ignore();
@@ -8373,7 +8408,7 @@ void QQuickItemLayer::activateEffect()
m_effect->stackAfter(m_effectSource);
}
m_effect->setVisible(m_item->isVisible());
- m_effect->setProperty(m_name, qVariantFromValue<QObject *>(m_effectSource));
+ m_effect->setProperty(m_name, QVariant::fromValue<QObject *>(m_effectSource));
QQuickItemPrivate::get(m_effect)->setTransparentForPositioner(true);
m_effectComponent->completeCreate();
}
@@ -8513,7 +8548,11 @@ void QQuickItemLayer::setSourceRect(const QRectF &sourceRect)
/*!
\qmlproperty bool QtQuick::Item::layer.smooth
- Holds whether the layer is smoothly transformed.
+ Holds whether the layer is smoothly transformed. When enabled, sampling the
+ layer's texture is performed using \c linear interpolation, while
+ non-smooth results in using the \c nearest filtering mode.
+
+ By default, this property is set to \c false.
\sa {Item Layers}
*/
@@ -8670,7 +8709,7 @@ void QQuickItemLayer::setName(const QByteArray &name) {
return;
if (m_effect) {
m_effect->setProperty(m_name, QVariant());
- m_effect->setProperty(name, qVariantFromValue<QObject *>(m_effectSource));
+ m_effect->setProperty(name, QVariant::fromValue<QObject *>(m_effectSource));
}
m_name = name;
emit nameChanged(name);
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index 6f601e0872..394a5adb8c 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -318,7 +318,7 @@ public:
void setKeepTouchGrab(bool);
// implemented in qquickitemgrabresult.cpp
- Q_REVISION(2) Q_INVOKABLE bool grabToImage(const QJSValue &callback, const QSize &targetSize = QSize());
+ Q_REVISION(4) Q_INVOKABLE bool grabToImage(const QJSValue &callback, const QSize &targetSize = QSize());
QSharedPointer<QQuickItemGrabResult> grabToImage(const QSize &targetSize = QSize());
Q_INVOKABLE virtual bool contains(const QPointF &point) const;
@@ -433,7 +433,7 @@ protected:
virtual void hoverEnterEvent(QHoverEvent *event);
virtual void hoverMoveEvent(QHoverEvent *event);
virtual void hoverLeaveEvent(QHoverEvent *event);
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
virtual void dragEnterEvent(QDragEnterEvent *);
virtual void dragMoveEvent(QDragMoveEvent *);
virtual void dragLeaveEvent(QDragLeaveEvent *);
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index f618bcf1c3..3e8feec4bf 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -592,6 +592,11 @@ public:
QPointF computeTransformOrigin() const;
virtual void transformChanged();
+ QPointF adjustedPosForTransform(const QPointF &centroid,
+ const QPointF &startPos, const QVector2D &activeTranslatation,
+ qreal startScale, qreal activeScale,
+ qreal startRotation, qreal activeRotation);
+
void deliverKeyEvent(QKeyEvent *);
bool filterKeyEvent(QKeyEvent *, bool post);
#if QT_CONFIG(im)
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 77bcf2583c..7bc6eefe0a 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -110,10 +110,11 @@
#include "qquickshadereffect_p.h"
#include "qquickshadereffectmesh_p.h"
#endif
+#if QT_CONFIG(quick_draganddrop)
#include "qquickdrag_p.h"
#include "qquickdroparea_p.h"
+#endif
#include "qquickmultipointtoucharea_p.h"
-#include <private/qqmlmetatype_p.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
#include "handlers/qquickdraghandler_p.h"
@@ -121,6 +122,7 @@
#include "handlers/qquickpinchhandler_p.h"
#include "handlers/qquickpointhandler_p.h"
#include "handlers/qquicktaphandler_p.h"
+#include "handlers/qquickwheelhandler_p.h"
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcTransient)
@@ -224,6 +226,9 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickPathCatmullRomCurve>("QtQuick",2,0,"PathCurve");
qmlRegisterType<QQuickPathArc>("QtQuick",2,0,"PathArc");
qmlRegisterType<QQuickPathSvg>("QtQuick",2,0,"PathSvg");
+ qmlRegisterType<QQuickPath, 14>(uri, 2, 14, "Path");
+ qmlRegisterType<QQuickPathPolyline>("QtQuick", 2, 14, "PathPolyline");
+ qmlRegisterType<QQuickPathMultiline>("QtQuick", 2, 14, "PathMultiline");
#endif
#if QT_CONFIG(quick_pathview)
qmlRegisterType<QQuickPathView>(uri,major,minor,"PathView");
@@ -241,28 +246,28 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickTextEdit,1>(uri,2,1,"TextEdit");
qmlRegisterType<QQuickTextInput>(uri,major,minor,"TextInput");
qmlRegisterType<QQuickTextInput,2>(uri,2,2,"TextInput");
- qmlRegisterType<QQuickTextInput,3>(uri,2,4,"TextInput");
- qmlRegisterType<QQuickItemGrabResult>();
+ qmlRegisterType<QQuickTextInput,4>(uri,2,4,"TextInput");
+ qmlRegisterAnonymousType<QQuickItemGrabResult>(uri, major);
#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickItemLayer>();
-#endif
- qmlRegisterType<QQuickAnchors>();
- qmlRegisterType<QQuickKeyEvent>();
- qmlRegisterType<QQuickMouseEvent>();
- qmlRegisterType<QQuickWheelEvent>();
- qmlRegisterType<QQuickCloseEvent>();
- qmlRegisterType<QQuickTransform>();
+ qmlRegisterAnonymousType<QQuickItemLayer>(uri, major);
+#endif
+ qmlRegisterAnonymousType<QQuickAnchors>(uri, major);
+ qmlRegisterAnonymousType<QQuickKeyEvent>(uri, major);
+ qmlRegisterAnonymousType<QQuickMouseEvent>(uri, major);
+ qmlRegisterAnonymousType<QQuickWheelEvent>(uri, major);
+ qmlRegisterAnonymousType<QQuickCloseEvent>(uri, major);
+ qmlRegisterAnonymousType<QQuickTransform>(uri, major);
#if QT_CONFIG(quick_path)
- qmlRegisterType<QQuickPathElement>();
- qmlRegisterType<QQuickCurve>();
+ qmlRegisterAnonymousType<QQuickPathElement>(uri, major);
+ qmlRegisterAnonymousType<QQuickCurve>(uri, major);
#endif
- qmlRegisterType<QQuickScaleGrid>();
- qmlRegisterType<QQuickTextLine>();
- qmlRegisterType<QQuickPen>();
- qmlRegisterType<QQuickFlickableVisibleArea>();
+ qmlRegisterAnonymousType<QQuickScaleGrid>(uri, major);
+ qmlRegisterAnonymousType<QQuickTextLine>(uri, major);
+ qmlRegisterAnonymousType<QQuickPen>(uri, major);
+ qmlRegisterAnonymousType<QQuickFlickableVisibleArea>(uri, major);
qRegisterMetaType<QQuickAnchorLine>("QQuickAnchorLine");
- qmlRegisterType<QQuickTextDocument>();
+ qmlRegisterAnonymousType<QQuickTextDocument>(uri, major);
qmlRegisterUncreatableType<QQuickKeyNavigationAttached>(uri,major,minor,"KeyNavigation",QQuickKeyNavigationAttached::tr("KeyNavigation is only available via attached properties"));
@@ -274,7 +279,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickPinchArea>(uri,major,minor,"PinchArea");
qmlRegisterType<QQuickPinch>(uri,major,minor,"Pinch");
- qmlRegisterType<QQuickPinchEvent>();
+ qmlRegisterAnonymousType<QQuickPinchEvent>(uri, major);
#if QT_CONFIG(quick_shadereffect)
qmlRegisterType<QQuickShaderEffectSource>("QtQuick", 2, 0, "ShaderEffectSource");
@@ -297,7 +302,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickParentChange>(uri, major, minor,"ParentChange");
qmlRegisterType<QQuickAnchorChanges>(uri, major, minor,"AnchorChanges");
- qmlRegisterType<QQuickAnchorSet>();
+ qmlRegisterAnonymousType<QQuickAnchorSet>(uri, major);
qmlRegisterType<QQuickAnchorAnimation>(uri, major, minor,"AnchorAnimation");
qmlRegisterType<QQuickParentAnimation>(uri, major, minor,"ParentAnimation");
#if QT_CONFIG(quick_path)
@@ -305,10 +310,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickPathInterpolator>("QtQuick",2,0,"PathInterpolator");
#endif
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
qmlRegisterType<QQuickDropArea>("QtQuick", 2, 0, "DropArea");
- qmlRegisterType<QQuickDropEvent>();
- qmlRegisterType<QQuickDropAreaDrag>();
+ qmlRegisterAnonymousType<QQuickDropEvent>(uri, 2);
+ qmlRegisterAnonymousType<QQuickDropAreaDrag>(uri, 2);
qmlRegisterUncreatableType<QQuickDrag>("QtQuick", 2, 0, "Drag", QQuickDragAttached::tr("Drag is only available via attached properties"));
#endif
@@ -329,7 +334,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
const char *itemViewName = "ItemView";
const QString itemViewMessage = QQuickItemView::tr("ItemView is an abstract base class");
qmlRegisterUncreatableType<QQuickItemView, 1>(uri, 2, 1, itemViewName, itemViewMessage);
- qmlRegisterUncreatableType<QQuickItemView, 2>(uri, 2, 3, itemViewName, itemViewMessage);
+ qmlRegisterUncreatableType<QQuickItemView, 3>(uri, 2, 3, itemViewName, itemViewMessage);
#endif
#if QT_CONFIG(quick_listview)
qmlRegisterType<QQuickListView, 1>(uri, 2, 1, "ListView");
@@ -344,23 +349,23 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickText, 3>(uri, 2, 3, "Text");
qmlRegisterType<QQuickTextEdit, 3>(uri, 2, 3, "TextEdit");
- qmlRegisterType<QQuickImage, 1>(uri, 2, 3,"Image");
+ qmlRegisterType<QQuickImage, 3>(uri, 2, 3,"Image");
- qmlRegisterType<QQuickItem, 2>(uri, 2, 4, "Item");
+ qmlRegisterType<QQuickItem, 4>(uri, 2, 4, "Item");
#if QT_CONFIG(quick_listview)
- qmlRegisterType<QQuickListView, 2>(uri, 2, 4, "ListView");
+ qmlRegisterType<QQuickListView, 4>(uri, 2, 4, "ListView");
#endif
- qmlRegisterType<QQuickMouseArea, 1>(uri, 2, 4, "MouseArea");
+ qmlRegisterType<QQuickMouseArea, 4>(uri, 2, 4, "MouseArea");
#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickShaderEffect, 1>(uri, 2, 4, "ShaderEffect");
+ qmlRegisterType<QQuickShaderEffect, 4>(uri, 2, 4, "ShaderEffect");
#endif
#if QT_CONFIG(opengl)
qmlRegisterUncreatableType<QQuickOpenGLInfo>(uri, 2, 4,"OpenGLInfo", QQuickOpenGLInfo::tr("OpenGLInfo is only available via attached properties"));
#endif
- qmlRegisterType<QQuickPinchArea, 1>(uri, 2, 5,"PinchArea");
- qmlRegisterType<QQuickImage, 2>(uri, 2, 5,"Image");
- qmlRegisterType<QQuickMouseArea, 2>(uri, 2, 5, "MouseArea");
+ qmlRegisterType<QQuickPinchArea, 5>(uri, 2, 5,"PinchArea");
+ qmlRegisterType<QQuickImage, 5>(uri, 2, 5,"Image");
+ qmlRegisterType<QQuickMouseArea, 5>(uri, 2, 5, "MouseArea");
qmlRegisterType<QQuickText, 6>(uri, 2, 6, "Text");
qmlRegisterType<QQuickTextEdit, 6>(uri, 2, 6, "TextEdit");
@@ -376,7 +381,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterUncreatableType<QQuickEnterKeyAttached, 6>(uri, 2, 6, "EnterKey",
QQuickEnterKeyAttached::tr("EnterKey is only available via attached properties"));
#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickShaderEffectSource, 1>(uri, 2, 6, "ShaderEffectSource");
+ qmlRegisterType<QQuickShaderEffectSource, 6>(uri, 2, 6, "ShaderEffectSource");
#endif
qmlRegisterType<QQuickItem, 7>(uri, 2, 7, "Item");
@@ -406,7 +411,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickMouseArea, 9>(uri, 2, 9, "MouseArea");
#if QT_CONFIG(quick_path)
- qmlRegisterType<QQuickPathArc, 2>(uri, 2, 9, "PathArc");
+ qmlRegisterType<QQuickPathArc, 9>(uri, 2, 9, "PathArc");
qmlRegisterType<QQuickPathMove>(uri, 2, 9, "PathMove");
#endif
@@ -421,7 +426,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
#endif
#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickShaderEffectSource, 2>(uri, 2, 9, "ShaderEffectSource");
+ qmlRegisterType<QQuickShaderEffectSource, 9>(uri, 2, 9, "ShaderEffectSource");
#endif
qmlRegisterType<QQuickFlickable, 10>(uri, 2, 10, "Flickable");
@@ -475,9 +480,25 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickTableView>(uri, 2, 12, "TableView");
#endif
+#if QT_CONFIG(quick_itemview)
qmlRegisterUncreatableType<QQuickItemView, 13>(uri, 2, 13, itemViewName, itemViewMessage);
+#endif
+#if QT_CONFIG(quick_pathview)
qmlRegisterType<QQuickPathView, 13>(uri, 2, 13, "PathView");
+#endif
+#if QT_CONFIG(quick_gridview)
qmlRegisterType<QQuickGridView, 13>(uri, 2, 13, "GridView");
+#endif
+#if QT_CONFIG(quick_tableview)
+ qmlRegisterType<QQuickTableView, 14>(uri, 2, 14, "TableView");
+#endif
+#if QT_CONFIG(wheelevent)
+ qmlRegisterType<QQuickWheelHandler>(uri, 2, 14, "WheelHandler");
+#endif
+ qmlRegisterUncreatableType<QQuickImageBase, 14>(uri, 2, 14, "ImageBase",
+ QQuickPointerHandler::tr("ImageBase is an abstract base class"));
+ qmlRegisterType<QQuickImage, 14>(uri, 2, 14, "Image");
+ qmlRegisterType<QQuickDragHandler, 14>(uri, 2, 14, "DragHandler");
}
static void initResources()
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 120eeb13d5..661f19509a 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -247,6 +247,8 @@ void QQuickItemView::setModel(const QVariant &m)
connect(d->model, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
this, SLOT(modelUpdated(QQmlChangeSet,bool)));
+ if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model))
+ QObjectPrivate::connect(dataModel, &QQmlDelegateModel::delegateChanged, d, &QQuickItemViewPrivate::applyDelegateChange);
emit countChanged();
}
emit modelChanged();
@@ -277,22 +279,8 @@ void QQuickItemView::setDelegate(QQmlComponent *delegate)
if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) {
int oldCount = dataModel->count();
dataModel->setDelegate(delegate);
- if (isComponentComplete()) {
- d->releaseVisibleItems();
- d->releaseItem(d->currentItem);
- d->currentItem = nullptr;
- d->updateSectionCriteria();
- d->refill();
- d->moveReason = QQuickItemViewPrivate::SetIndex;
- d->updateCurrent(d->currentIndex);
- if (d->highlight && d->currentItem) {
- if (d->autoHighlight)
- d->resetHighlightPosition();
- d->updateTrackedItem();
- }
- d->moveReason = QQuickItemViewPrivate::Other;
- d->updateViewport();
- }
+ if (isComponentComplete())
+ d->applyDelegateChange();
if (oldCount != dataModel->count())
emit countChanged();
}
@@ -1098,6 +1086,24 @@ qreal QQuickItemViewPrivate::calculatedMaxExtent() const
return maxExtent;
}
+void QQuickItemViewPrivate::applyDelegateChange()
+{
+ releaseVisibleItems();
+ releaseItem(currentItem);
+ currentItem = nullptr;
+ updateSectionCriteria();
+ refill();
+ moveReason = QQuickItemViewPrivate::SetIndex;
+ updateCurrent(currentIndex);
+ if (highlight && currentItem) {
+ if (autoHighlight)
+ resetHighlightPosition();
+ updateTrackedItem();
+ }
+ moveReason = QQuickItemViewPrivate::Other;
+ updateViewport();
+}
+
// for debugging only
void QQuickItemViewPrivate::checkVisible() const
{
diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h
index 0a0da587b4..66e09f9ed1 100644
--- a/src/quick/items/qquickitemview_p.h
+++ b/src/quick/items/qquickitemview_p.h
@@ -81,8 +81,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickItemView : public QQuickFlickable
Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged)
Q_PROPERTY(bool keyNavigationEnabled READ isKeyNavigationEnabled WRITE setKeyNavigationEnabled NOTIFY keyNavigationEnabledChanged REVISION 7)
Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
- Q_PROPERTY(int displayMarginBeginning READ displayMarginBeginning WRITE setDisplayMarginBeginning NOTIFY displayMarginBeginningChanged REVISION 2)
- Q_PROPERTY(int displayMarginEnd READ displayMarginEnd WRITE setDisplayMarginEnd NOTIFY displayMarginEndChanged REVISION 2)
+ Q_PROPERTY(int displayMarginBeginning READ displayMarginBeginning WRITE setDisplayMarginBeginning NOTIFY displayMarginBeginningChanged REVISION 3)
+ Q_PROPERTY(int displayMarginEnd READ displayMarginEnd WRITE setDisplayMarginEnd NOTIFY displayMarginEndChanged REVISION 3)
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index 1f42c847b3..6442fee27d 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -59,9 +59,9 @@ QT_REQUIRE_CONFIG(quick_itemview);
#include "qquickitemviewfxitem_p_p.h"
#include "qquickitemviewtransition_p.h"
#include "qquickflickable_p_p.h"
-#include <QtQml/private/qqmlobjectmodel_p.h>
-#include <QtQml/private/qqmldelegatemodel_p.h>
-#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQmlModels/private/qqmlobjectmodel_p.h>
+#include <QtQmlModels/private/qqmldelegatemodel_p.h>
+#include <QtQmlModels/private/qqmlchangeset_p.h>
QT_BEGIN_NAMESPACE
@@ -191,6 +191,8 @@ public:
qreal calculatedMinExtent() const;
qreal calculatedMaxExtent() const;
+ void applyDelegateChange();
+
void applyPendingChanges();
bool applyModelChanges(ChangeResult *insertionResult, ChangeResult *removalResult);
bool applyRemovalChange(const QQmlChangeSet::Change &removal, ChangeResult *changeResult, int *removedCount);
diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h
index 9a9b325b1e..f2bab9e018 100644
--- a/src/quick/items/qquicklistview_p.h
+++ b/src/quick/items/qquicklistview_p.h
@@ -126,8 +126,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickListView : public QQuickItemView
Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged)
- Q_PROPERTY(HeaderPositioning headerPositioning READ headerPositioning WRITE setHeaderPositioning NOTIFY headerPositioningChanged REVISION 2)
- Q_PROPERTY(FooterPositioning footerPositioning READ footerPositioning WRITE setFooterPositioning NOTIFY footerPositioningChanged REVISION 2)
+ Q_PROPERTY(HeaderPositioning headerPositioning READ headerPositioning WRITE setHeaderPositioning NOTIFY headerPositioningChanged REVISION 4)
+ Q_PROPERTY(FooterPositioning footerPositioning READ footerPositioning WRITE setFooterPositioning NOTIFY footerPositioningChanged REVISION 4)
Q_CLASSINFO("DefaultProperty", "data")
@@ -188,8 +188,8 @@ Q_SIGNALS:
void highlightResizeVelocityChanged();
void highlightResizeDurationChanged();
void snapModeChanged();
- Q_REVISION(2) void headerPositioningChanged();
- Q_REVISION(2) void footerPositioningChanged();
+ Q_REVISION(4) void headerPositioningChanged();
+ Q_REVISION(4) void footerPositioningChanged();
protected:
void viewportMoved(Qt::Orientations orient) override;
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 4bee4864d5..ddf34798d7 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -40,7 +40,9 @@
#include "qquickmousearea_p.h"
#include "qquickmousearea_p_p.h"
#include "qquickwindow.h"
+#if QT_CONFIG(quick_draganddrop)
#include "qquickdrag_p.h"
+#endif
#include <private/qqmldata_p.h>
#include <private/qsgadaptationlayer_p.h>
@@ -62,7 +64,7 @@ QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
propagateComposedEvents(false), overThreshold(false), pressed(nullptr),
pressAndHoldInterval(-1)
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
, drag(nullptr)
#endif
#if QT_CONFIG(cursor)
@@ -73,7 +75,7 @@ QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
QQuickMouseAreaPrivate::~QQuickMouseAreaPrivate()
{
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
delete drag;
#endif
#if QT_CONFIG(cursor)
@@ -685,7 +687,7 @@ void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
} else {
d->longPress = false;
d->saveEvent(event);
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
if (d->drag)
d->drag->setActive(false);
#endif
@@ -712,7 +714,7 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
// ### can GV handle this for us?
setHovered(contains(d->lastPos));
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
if (d->drag && d->drag->target()) {
if (!d->moved) {
d->targetStartPos = d->drag->target()->parentItem()
@@ -759,8 +761,10 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
QPointF targetPos = d->drag->target()->position();
- if (d->drag->active())
+ if (d->drag->active()) {
d->drag->target()->setPosition(boundedDragPos);
+ d->lastPos = d->lastScenePos - mapToScene(position());
+ }
bool dragOverThresholdX = QQuickWindowPrivate::dragOverThreshold(dragPos.x() - startPos.x(),
Qt::XAxis, event, d->drag->threshold());
@@ -806,7 +810,7 @@ void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
setPressed(event->button(), false, event->source());
if (!d->pressed) {
// no other buttons are pressed
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
if (d->drag)
d->drag->setActive(false);
#endif
@@ -895,7 +899,7 @@ void QQuickMouseArea::wheelEvent(QWheelEvent *event)
}
QQuickWheelEvent &we = d->quickWheelEvent;
- we.reset(event->posF().x(), event->posF().y(), event->angleDelta(), event->pixelDelta(),
+ we.reset(event->position().x(), event->position().y(), event->angleDelta(), event->pixelDelta(),
event->buttons(), event->modifiers(), event->inverted());
we.setAccepted(d->isWheelConnected());
emit wheel(&we);
@@ -916,7 +920,7 @@ void QQuickMouseArea::ungrabMouse()
d->overThreshold = false;
setKeepMouseGrab(false);
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
if (d->drag)
d->drag->setActive(false);
#endif
@@ -999,7 +1003,7 @@ bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
Q_D(QQuickMouseArea);
if (!d->pressed &&
(!d->enabled || !isVisible()
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
|| !d->drag || !d->drag->filterChildren()
#endif
)
@@ -1022,7 +1026,7 @@ void QQuickMouseArea::timerEvent(QTimerEvent *event)
Q_D(QQuickMouseArea);
if (event->timerId() == d->pressAndHoldTimer.timerId()) {
d->pressAndHoldTimer.stop();
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
bool dragged = d->drag && d->drag->active();
#else
bool dragged = false;
@@ -1065,7 +1069,7 @@ void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
Q_D(QQuickMouseArea);
switch (change) {
case ItemVisibleHasChanged:
- if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse())) {
+ if (d->effectiveEnable && d->enabled && acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse())) {
if (!d->hovered) {
QPointF cursorPos = QGuiApplicationPrivate::lastCursorPosition;
d->lastScenePos = d->window->mapFromGlobal(cursorPos.toPoint());
@@ -1198,7 +1202,7 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventS
{
Q_D(QQuickMouseArea);
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
bool dragged = d->drag && d->drag->active();
#else
bool dragged = false;
@@ -1404,7 +1408,7 @@ void QQuickMouseArea::resetPressAndHoldInterval()
*/
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
QQuickDrag *QQuickMouseArea::drag()
{
Q_D(QQuickMouseArea);
diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h
index 0a8449957f..0e01fa7915 100644
--- a/src/quick/items/qquickmousearea_p.h
+++ b/src/quick/items/qquickmousearea_p.h
@@ -71,11 +71,11 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem
Q_PROPERTY(bool containsMouse READ hovered NOTIFY hoveredChanged)
Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
- Q_PROPERTY(bool scrollGestureEnabled READ isScrollGestureEnabled WRITE setScrollGestureEnabled NOTIFY scrollGestureEnabledChanged REVISION 2)
+ Q_PROPERTY(bool scrollGestureEnabled READ isScrollGestureEnabled WRITE setScrollGestureEnabled NOTIFY scrollGestureEnabledChanged REVISION 5)
Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons NOTIFY pressedButtonsChanged)
Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged)
Q_PROPERTY(bool hoverEnabled READ hoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged)
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
Q_PROPERTY(QQuickDrag *drag READ drag CONSTANT) //### add flicking to QQuickDrag or add a QQuickFlick ???
#endif
Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged)
@@ -83,7 +83,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem
#if QT_CONFIG(cursor)
Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape RESET unsetCursor NOTIFY cursorShapeChanged)
#endif
- Q_PROPERTY(bool containsPress READ containsPress NOTIFY containsPressChanged REVISION 1)
+ Q_PROPERTY(bool containsPress READ containsPress NOTIFY containsPressChanged REVISION 4)
Q_PROPERTY(int pressAndHoldInterval READ pressAndHoldInterval WRITE setPressAndHoldInterval NOTIFY pressAndHoldIntervalChanged RESET resetPressAndHoldInterval REVISION 9)
public:
@@ -111,7 +111,7 @@ public:
bool hoverEnabled() const;
void setHoverEnabled(bool h);
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
QQuickDrag *drag();
#endif
@@ -134,7 +134,7 @@ Q_SIGNALS:
void hoveredChanged();
void pressedChanged();
void enabledChanged();
- Q_REVISION(2) void scrollGestureEnabledChanged();
+ Q_REVISION(5) void scrollGestureEnabledChanged();
void pressedButtonsChanged();
void acceptedButtonsChanged();
void hoverEnabledChanged();
@@ -156,7 +156,7 @@ Q_SIGNALS:
void entered();
void exited();
void canceled();
- Q_REVISION(1) void containsPressChanged();
+ Q_REVISION(4) void containsPressChanged();
Q_REVISION(9) void pressAndHoldIntervalChanged();
protected:
diff --git a/src/quick/items/qquickmousearea_p_p.h b/src/quick/items/qquickmousearea_p_p.h
index 0dd2690d43..fba383e268 100644
--- a/src/quick/items/qquickmousearea_p_p.h
+++ b/src/quick/items/qquickmousearea_p_p.h
@@ -97,7 +97,7 @@ public:
bool overThreshold : 1;
Qt::MouseButtons pressed;
int pressAndHoldInterval;
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
QQuickDrag *drag;
#endif
QPointer<QQuickPointerMask> mask;
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 70426a6a8c..b02e58fae4 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -40,6 +40,7 @@
#include "qquickmultipointtoucharea_p.h"
#include <QtQuick/qquickwindow.h>
#include <private/qsgadaptationlayer_p.h>
+#include <private/qevent_p.h>
#include <private/qquickitem_p.h>
#include <private/qguiapplication_p.h>
#include <QEvent>
@@ -655,7 +656,8 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
// (we may have just obtained enough points to start tracking them -- in that case moved or stationary count as newly pressed)
addTouchPoint(&p);
started = true;
- } else if (touchPointState & Qt::TouchPointMoved) {
+ } else if ((touchPointState & Qt::TouchPointMoved) || p.d->stationaryWithModifiedProperty) {
+ // React to a stationary point with a property change (velocity, pressure) as if the point moved. (QTBUG-77142)
QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
Q_ASSERT(dtp);
_movedTouchPoints.append(dtp);
diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp
index 3aa00340b2..e217fdb5d0 100644
--- a/src/quick/items/qquickopenglshadereffect.cpp
+++ b/src/quick/items/qquickopenglshadereffect.cpp
@@ -57,6 +57,10 @@
QT_BEGIN_NAMESPACE
+// Note: this legacy ShaderEffect implementation is used only when running
+// directly with OpenGL. This is going to go away in the future (Qt 6?), since
+// the RHI path uses QQuickGenericShaderEffect always.
+
namespace {
enum VariableQualifier {
@@ -185,8 +189,8 @@ class MappedSlotObject: public QtPrivate::QSlotObjectBase
public:
typedef std::function<void()> PropChangedFunc;
- explicit MappedSlotObject(PropChangedFunc func)
- : QSlotObjectBase(&impl), _signalIndex(-1), func(func)
+ explicit MappedSlotObject(PropChangedFunc f)
+ : QSlotObjectBase(&impl), _signalIndex(-1), func(std::move(f))
{ ref(); }
void setSignalIndex(int idx) { _signalIndex = idx; }
@@ -710,8 +714,8 @@ void QQuickOpenGLShaderEffect::setBlending(bool enable)
QVariant QQuickOpenGLShaderEffect::mesh() const
{
- return m_mesh ? qVariantFromValue(static_cast<QObject *>(m_mesh))
- : qVariantFromValue(m_meshResolution);
+ return m_mesh ? QVariant::fromValue(static_cast<QObject *>(m_mesh))
+ : QVariant::fromValue(m_meshResolution);
}
void QQuickOpenGLShaderEffect::setMesh(const QVariant &mesh)
diff --git a/src/quick/items/qquickopenglshadereffectnode.cpp b/src/quick/items/qquickopenglshadereffectnode.cpp
index 3ccd2a76f7..26ef59c20e 100644
--- a/src/quick/items/qquickopenglshadereffectnode.cpp
+++ b/src/quick/items/qquickopenglshadereffectnode.cpp
@@ -366,7 +366,6 @@ class QQuickOpenGLShaderEffectMaterialCache : public QObject
public:
static QQuickOpenGLShaderEffectMaterialCache *get(bool create = true) {
QOpenGLContext *ctx = QOpenGLContext::currentContext();
- Q_ASSERT(ctx);
QQuickOpenGLShaderEffectMaterialCache *me = ctx->findChild<QQuickOpenGLShaderEffectMaterialCache *>(QStringLiteral("__qt_ShaderEffectCache"), Qt::FindDirectChildrenOnly);
if (!me && create) {
me = new QQuickOpenGLShaderEffectMaterialCache();
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 8abb3f29cd..6976665134 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -60,8 +60,9 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcItemViewDelegateLifecycle)
+Q_LOGGING_CATEGORY(lcPathView, "qt.quick.pathview")
-const qreal MinimumFlickVelocity = 75.0;
+static const qreal MinimumFlickVelocity = 75;
static QQmlOpenMetaObjectType *qPathViewAttachedType = nullptr;
@@ -90,8 +91,8 @@ void QQuickPathViewAttached::setValue(const QByteArray &name, const QVariant &va
}
QQuickPathViewPrivate::QQuickPathViewPrivate()
- : path(nullptr), currentIndex(0), currentItemOffset(0.0), startPc(0)
- , offset(0.0), offsetAdj(0.0), mappedRange(1.0), mappedCache(0.0)
+ : path(nullptr), currentIndex(0), currentItemOffset(0), startPc(0)
+ , offset(0), offsetAdj(0), mappedRange(1), mappedCache(0)
, stealMouse(false), ownModel(false), interactive(true), haveHighlightRange(true)
, autoHighlight(true), highlightUp(false), layoutScheduled(false)
, moving(false), flicking(false), dragging(false), inRequest(false), delegateValidated(false)
@@ -117,10 +118,10 @@ void QQuickPathViewPrivate::init()
q->setFlag(QQuickItem::ItemIsFocusScope);
q->setFiltersChildMouseEvents(true);
qmlobject_connect(&tl, QQuickTimeLine, SIGNAL(updated()),
- q, QQuickPathView, SLOT(ticked()))
+ q, QQuickPathView, SLOT(ticked()));
timer.invalidate();
qmlobject_connect(&tl, QQuickTimeLine, SIGNAL(completed()),
- q, QQuickPathView, SLOT(movementEnding()))
+ q, QQuickPathView, SLOT(movementEnding()));
}
QQuickItem *QQuickPathViewPrivate::getItem(int modelIndex, qreal z, bool async)
@@ -163,7 +164,7 @@ void QQuickPathView::createdItem(int index, QObject *object)
att->setOnPath(false);
}
item->setParentItem(this);
- d->updateItem(item, 1.0);
+ d->updateItem(item, 1);
} else {
d->requestedIndex = -1;
if (!d->inRequest)
@@ -184,13 +185,13 @@ void QQuickPathView::initItem(int index, QObject *object)
if (att) {
att->m_view = this;
qreal percent = d->positionOfIndex(index);
- if (percent < 1.0 && d->path) {
+ if (percent < 1 && d->path) {
const auto attributes = d->path->attributes();
for (const QString &attr : attributes)
att->setValue(attr.toUtf8(), d->path->attributeAt(attr, percent));
item->setZ(d->requestedZ);
}
- att->setOnPath(percent < 1.0);
+ att->setOnPath(percent < 1);
}
}
}
@@ -264,17 +265,17 @@ void QQuickPathViewPrivate::updateMappedRange()
mappedRange = qreal(modelCount)/pathItems;
mappedCache = qreal(cacheSize)/pathItems/2; // Half of cache at each end
} else {
- mappedRange = 1.0;
- mappedCache = 0.0;
+ mappedRange = 1;
+ mappedCache = 0;
}
}
qreal QQuickPathViewPrivate::positionOfIndex(qreal index) const
{
- qreal pos = -1.0;
+ qreal pos = -1;
if (model && index >= 0 && index < modelCount) {
- qreal start = 0.0;
+ qreal start = 0;
if (haveHighlightRange && (highlightRangeMode != QQuickPathView::NoHighlightRange
|| snapMode != QQuickPathView::NoSnap))
start = highlightRangeStart;
@@ -282,10 +283,10 @@ qreal QQuickPathViewPrivate::positionOfIndex(qreal index) const
globalPos = std::fmod(globalPos, qreal(modelCount)) / modelCount;
if (pathItems != -1 && pathItems < modelCount) {
globalPos += start / mappedRange;
- globalPos = std::fmod(globalPos, qreal(1.0));
+ globalPos = std::fmod(globalPos, qreal(1));
pos = globalPos * mappedRange;
} else {
- pos = std::fmod(globalPos + start, qreal(1.0));
+ pos = std::fmod(globalPos + start, qreal(1));
}
}
@@ -296,7 +297,7 @@ qreal QQuickPathViewPrivate::positionOfIndex(qreal index) const
// account the circular space.
bool QQuickPathViewPrivate::isInBound(qreal position, qreal lower, qreal upper) const
{
- if (lower == upper)
+ if (qFuzzyCompare(lower, upper))
return true;
if (lower > upper) {
if (position > upper && position > lower)
@@ -358,7 +359,7 @@ void QQuickPathViewPrivate::updateHighlight()
} else {
qreal target = currentIndex;
- offsetAdj = 0.0;
+ offsetAdj = 0;
tl.reset(moveHighlight);
moveHighlight.setValue(highlightPosition);
@@ -367,14 +368,14 @@ void QQuickPathViewPrivate::updateHighlight()
if (target - highlightPosition > modelCount/2) {
highlightUp = false;
qreal distance = modelCount - target + highlightPosition;
- tl.move(moveHighlight, 0.0, QEasingCurve(QEasingCurve::InQuad), int(duration * highlightPosition / distance));
+ tl.move(moveHighlight, 0, QEasingCurve(QEasingCurve::InQuad), int(duration * highlightPosition / distance));
tl.set(moveHighlight, modelCount-0.01);
tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad), int(duration * (modelCount-target) / distance));
} else if (target - highlightPosition <= -modelCount/2) {
highlightUp = true;
qreal distance = modelCount - highlightPosition + target;
tl.move(moveHighlight, modelCount-0.01, QEasingCurve(QEasingCurve::InQuad), int(duration * (modelCount-highlightPosition) / distance));
- tl.set(moveHighlight, 0.0);
+ tl.set(moveHighlight, 0);
tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad), int(duration * target / distance));
} else {
highlightUp = highlightPosition - target < 0;
@@ -386,9 +387,9 @@ void QQuickPathViewPrivate::updateHighlight()
void QQuickPathViewPrivate::setHighlightPosition(qreal pos)
{
- if (pos != highlightPosition) {
- qreal start = 0.0;
- qreal end = 1.0;
+ if (!(qFuzzyCompare(pos, highlightPosition))) {
+ qreal start = 0;
+ qreal end = 1;
if (haveHighlightRange && highlightRangeMode != QQuickPathView::NoHighlightRange) {
start = highlightRangeStart;
end = highlightRangeEnd;
@@ -399,7 +400,7 @@ void QQuickPathViewPrivate::setHighlightPosition(qreal pos)
qreal relativeHighlight = std::fmod(pos + offset, range) / range;
if (!highlightUp && relativeHighlight > end / mappedRange) {
- qreal diff = 1.0 - relativeHighlight;
+ qreal diff = 1 - relativeHighlight;
setOffset(offset + diff * range);
} else if (highlightUp && relativeHighlight >= (end - start) / mappedRange) {
qreal diff = relativeHighlight - (end - start) / mappedRange;
@@ -410,7 +411,7 @@ void QQuickPathViewPrivate::setHighlightPosition(qreal pos)
qreal pathPos = positionOfIndex(pos);
updateItem(highlightItem, pathPos);
if (QQuickPathViewAttached *att = attached(highlightItem))
- att->setOnPath(pathPos < 1.0);
+ att->setOnPath(pathPos < 1);
}
}
@@ -435,10 +436,10 @@ void QQuickPathViewPrivate::updateItem(QQuickItem *item, qreal percent)
const auto attributes = path->attributes();
for (const QString &attr : attributes)
att->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
- att->setOnPath(percent < 1.0);
+ att->setOnPath(percent < 1);
}
- QQuickItemPrivate::get(item)->setCulled(percent >= 1.0);
- QPointF pf = path->pointAt(qMin(percent, qreal(1.0)));
+ QQuickItemPrivate::get(item)->setCulled(percent >= 1);
+ QPointF pf = path->pointAtPercent(qMin(percent, qreal(1)));
item->setX(pf.x() - item->width()/2);
item->setY(pf.y() - item->height()/2);
}
@@ -668,7 +669,7 @@ void QQuickPathView::setModel(const QVariant &m)
d->currentIndex = 0;
emit currentIndexChanged();
}
- if (d->offset != 0.0) {
+ if (!(qFuzzyIsNull(d->offset))) {
d->offset = 0;
emit offsetChanged();
}
@@ -820,7 +821,7 @@ void QQuickPathView::decrementCurrentIndex()
\qmlproperty real QtQuick::PathView::offset
The offset specifies how far along the path the items are from their initial positions.
- This is a real number that ranges from 0.0 to the count of items in the model.
+ This is a real number that ranges from \c 0 to the count of items in the model.
*/
qreal QQuickPathView::offset() const
{
@@ -839,7 +840,7 @@ void QQuickPathView::setOffset(qreal offset)
void QQuickPathViewPrivate::setOffset(qreal o)
{
Q_Q(QQuickPathView);
- if (offset != o) {
+ if (!qFuzzyCompare(offset, o)) {
if (isValid() && q->isComponentComplete()) {
qreal oldOffset = offset;
offset = std::fmod(o, qreal(modelCount));
@@ -882,7 +883,6 @@ void QQuickPathViewPrivate::setAdjustedOffset(qreal o)
\sa highlightItem, highlightRangeMode
*/
-
QQmlComponent *QQuickPathView::highlight() const
{
Q_D(const QQuickPathView);
@@ -901,25 +901,26 @@ void QQuickPathView::setHighlight(QQmlComponent *highlight)
}
/*!
- \qmlproperty Item QtQuick::PathView::highlightItem
+ \qmlproperty Item QtQuick::PathView::highlightItem
- \c highlightItem holds the highlight item, which was created
- from the \l highlight component.
+ \c highlightItem holds the highlight item, which was created
+ from the \l highlight component.
- \sa highlight
+ \sa highlight
*/
QQuickItem *QQuickPathView::highlightItem() const
{
Q_D(const QQuickPathView);
return d->highlightItem;
}
+
/*!
\qmlproperty real QtQuick::PathView::preferredHighlightBegin
\qmlproperty real QtQuick::PathView::preferredHighlightEnd
\qmlproperty enumeration QtQuick::PathView::highlightRangeMode
These properties set the preferred range of the highlight (current item)
- within the view. The preferred values must be in the range 0.0-1.0.
+ within the view. The preferred values must be in the range from \c 0 to \c 1.
Valid values for \c highlightRangeMode are:
@@ -960,7 +961,7 @@ qreal QQuickPathView::preferredHighlightBegin() const
void QQuickPathView::setPreferredHighlightBegin(qreal start)
{
Q_D(QQuickPathView);
- if (d->highlightRangeStart == start || start < 0 || start > 1.0)
+ if (qFuzzyCompare(d->highlightRangeStart, start) || start < 0 || start > 1)
return;
d->highlightRangeStart = start;
d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
@@ -977,7 +978,7 @@ qreal QQuickPathView::preferredHighlightEnd() const
void QQuickPathView::setPreferredHighlightEnd(qreal end)
{
Q_D(QQuickPathView);
- if (d->highlightRangeEnd == end || end < 0 || end > 1.0)
+ if (qFuzzyCompare(d->highlightRangeEnd, end) || end < 0 || end > 1)
return;
d->highlightRangeEnd = end;
d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
@@ -1048,7 +1049,7 @@ qreal QQuickPathView::dragMargin() const
void QQuickPathView::setDragMargin(qreal dragMargin)
{
Q_D(QQuickPathView);
- if (d->dragMargin == dragMargin)
+ if (qFuzzyCompare(d->dragMargin, dragMargin))
return;
d->dragMargin = dragMargin;
emit dragMarginChanged();
@@ -1069,7 +1070,7 @@ qreal QQuickPathView::flickDeceleration() const
void QQuickPathView::setFlickDeceleration(qreal dec)
{
Q_D(QQuickPathView);
- if (d->deceleration == dec)
+ if (qFuzzyCompare(d->deceleration, dec))
return;
d->deceleration = dec;
emit flickDecelerationChanged();
@@ -1090,7 +1091,7 @@ qreal QQuickPathView::maximumFlickVelocity() const
void QQuickPathView::setMaximumFlickVelocity(qreal vel)
{
Q_D(QQuickPathView);
- if (vel == d->maximumFlickVelocity)
+ if (qFuzzyCompare(vel, d->maximumFlickVelocity))
return;
d->maximumFlickVelocity = vel;
emit maximumFlickVelocityChanged();
@@ -1580,16 +1581,16 @@ QQuickItem *QQuickPathView::itemAtIndex(int index) const
QPointF QQuickPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercent) const
{
const auto pathLength = path->path().length();
- qreal samples = qMin(pathLength / 5, qreal(500.0));
+ qreal samples = qMin(pathLength / 5, qreal(500));
qreal res = pathLength / samples;
qreal mindist = 1e10; // big number
- QPointF nearPoint = path->pointAt(0);
+ QPointF nearPoint = path->pointAtPercent(0);
qreal nearPc = 0;
// get rough pos
for (qreal i=1; i < samples; i++) {
- QPointF pt = path->pointAt(i/samples);
+ QPointF pt = path->pointAtPercent(i/samples);
QPointF diff = pt - point;
qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
if (dist < mindist) {
@@ -1601,8 +1602,8 @@ QPointF QQuickPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercen
// now refine
qreal approxPc = nearPc;
- for (qreal i = approxPc-1.0; i < approxPc+1.0; i += 1/(2*res)) {
- QPointF pt = path->pointAt(i/samples);
+ for (qreal i = approxPc-1; i < approxPc+1; i += 1/(2*res)) {
+ QPointF pt = path->pointAtPercent(i/samples);
QPointF diff = pt - point;
qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
if (dist < mindist) {
@@ -1623,6 +1624,7 @@ void QQuickPathViewPrivate::addVelocitySample(qreal v)
velocityBuffer.append(v);
if (velocityBuffer.count() > QML_FLICK_SAMPLEBUFFER)
velocityBuffer.remove(0);
+ qCDebug(lcPathView) << "instantaneous velocity" << v;
}
qreal QQuickPathViewPrivate::calcVelocity() const
@@ -1635,6 +1637,7 @@ qreal QQuickPathViewPrivate::calcVelocity() const
velocity += v;
}
velocity /= count;
+ qCDebug(lcPathView) << "average velocity" << velocity << "based on" << count << "samples";
}
return velocity;
}
@@ -1642,7 +1645,7 @@ qreal QQuickPathViewPrivate::calcVelocity() const
qint64 QQuickPathViewPrivate::computeCurrentTime(QInputEvent *event) const
{
if (0 != event->timestamp())
- return event->timestamp();
+ return qint64(event->timestamp());
return timer.elapsed();
}
@@ -1669,7 +1672,7 @@ void QQuickPathViewPrivate::handleMousePressEvent(QMouseEvent *event)
if (item->contains(item->mapFromScene(event->windowPos())))
break;
}
- if (idx == items.count() && dragMargin == 0.) // didn't click on an item
+ if (idx == items.count() && qFuzzyIsNull(dragMargin)) // didn't click on an item
return;
startPoint = pointNear(event->localPos(), &startPc);
@@ -1731,7 +1734,7 @@ void QQuickPathViewPrivate::handleMouseMoveEvent(QMouseEvent *event)
moveReason = QQuickPathViewPrivate::Mouse;
int count = pathItems == -1 ? modelCount : qMin(pathItems, modelCount);
qreal diff = (newPc - startPc)*count;
- if (diff) {
+ if (!qFuzzyIsNull(diff)) {
q->setOffset(offset + diff);
if (diff > modelCount/2)
@@ -1741,7 +1744,7 @@ void QQuickPathViewPrivate::handleMouseMoveEvent(QMouseEvent *event)
qint64 elapsed = currentTimestamp - lastPosTime;
if (elapsed > 0)
- addVelocitySample(diff / (qreal(elapsed) / 1000.));
+ addVelocitySample(diff / (qreal(elapsed) / 1000));
}
if (!moving) {
moving = true;
@@ -1766,7 +1769,7 @@ void QQuickPathView::mouseReleaseEvent(QMouseEvent *event)
}
}
-void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *)
+void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *event)
{
Q_Q(QQuickPathView);
stealMouse = false;
@@ -1780,6 +1783,12 @@ void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *)
}
qreal velocity = calcVelocity();
+ qint64 elapsed = computeCurrentTime(event) - lastPosTime;
+ // Let the velocity linearly decay such that it becomes 0 if elapsed time > QML_FLICK_VELOCITY_DECAY_TIME
+ // The intention is that if you are flicking at some speed, then stop in one place for some time before releasing,
+ // the previous velocity is lost. (QTBUG-77173, QTBUG-59052)
+ velocity *= qreal(qMax(0LL, QML_FLICK_VELOCITY_DECAY_TIME - elapsed)) / QML_FLICK_VELOCITY_DECAY_TIME;
+ qCDebug(lcPathView) << "after elapsed time" << elapsed << "velocity decayed to" << velocity;
qreal count = pathItems == -1 ? modelCount : qMin(pathItems, modelCount);
const auto averageItemLength = path->path().length() / count;
qreal pixelVelocity = averageItemLength * velocity;
@@ -1797,32 +1806,32 @@ void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *)
|| snapMode != QQuickPathView::NoSnap)) {
if (snapMode == QQuickPathView::SnapOneItem) {
// encourage snapping one item in direction of motion
- if (velocity > 0.)
+ if (velocity > 0)
dist = qRound(0.5 + offset) - offset;
else
dist = qRound(0.5 - offset) + offset;
} else {
// + 0.25 to encourage moving at least one item in the flick direction
- dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2.0) + 0.25));
+ dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2) + 0.25));
// round to nearest item.
- if (velocity > 0.)
+ if (velocity > 0)
dist = qRound(dist + offset) - offset;
else
dist = qRound(dist - offset) + offset;
}
// Calculate accel required to stop on item boundary
- if (dist <= 0.) {
- dist = 0.;
- accel = 0.;
+ if (dist <= 0) {
+ dist = 0;
+ accel = 0;
} else {
- accel = v2 / (2.0f * qAbs(dist));
+ accel = v2 / (2 * qAbs(dist));
}
} else {
- dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2.0)));
+ dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2)));
}
- flickDuration = static_cast<int>(1000 * qAbs(velocity) / accel);
- offsetAdj = 0.0;
+ flickDuration = int(1000 * qAbs(velocity) / accel);
+ offsetAdj = 0;
moveOffset.setValue(offset);
tl.accel(moveOffset, velocity, accel, dist);
tl.callback(QQuickTimeLineCallback(&moveOffset, fixOffsetCallback, this));
@@ -1996,7 +2005,7 @@ void QQuickPathView::refill()
else
qCDebug(lcItemViewDelegateLifecycle) << "idx" << idx << "@" << pos << ":" << item;
}
- if (pos < 1.0) {
+ if (pos < 1) {
d->updateItem(item, pos);
if (idx == d->currentIndex) {
currentVisible = true;
@@ -2006,9 +2015,9 @@ void QQuickPathView::refill()
} else {
d->updateItem(item, pos);
if (QQuickPathViewAttached *att = d->attached(item))
- att->setOnPath(pos < 1.0);
- if (!d->isInBound(pos, d->mappedRange - d->mappedCache, 1.0 + d->mappedCache)) {
- qCDebug(lcItemViewDelegateLifecycle) << "release" << idx << "@" << pos << ", !isInBound: lower" << (d->mappedRange - d->mappedCache) << "upper" << (1.0 + d->mappedCache);
+ att->setOnPath(pos < 1);
+ if (!d->isInBound(pos, d->mappedRange - d->mappedCache, 1 + d->mappedCache)) {
+ qCDebug(lcItemViewDelegateLifecycle) << "release" << idx << "@" << pos << ", !isInBound: lower" << (d->mappedRange - d->mappedCache) << "upper" << (1 + d->mappedCache);
d->releaseItem(item);
it = d->items.erase(it);
} else {
@@ -2024,12 +2033,12 @@ void QQuickPathView::refill()
int endIdx = 0;
qreal endPos;
int startIdx = 0;
- qreal startPos = 0.0;
+ qreal startPos = 0;
const bool wasEmpty = d->items.isEmpty();
if (!wasEmpty) {
//Find the beginning and end, items may not be in sorted order
- endPos = -1.0;
- startPos = 2.0;
+ endPos = -1;
+ startPos = 2;
for (QQuickItem * item : qAsConst(d->items)) {
int idx = d->model->indexOf(item, nullptr);
@@ -2058,10 +2067,10 @@ void QQuickPathView::refill()
if (idx >= d->modelCount)
idx = 0;
qreal nextPos = d->positionOfIndex(idx);
- while ((d->isInBound(nextPos, endPos, 1.0 + d->mappedCache) || !d->items.count())
+ while ((d->isInBound(nextPos, endPos, 1 + d->mappedCache) || !d->items.count())
&& d->items.count() < count+d->cacheSize) {
qCDebug(lcItemViewDelegateLifecycle) << "append" << idx << "@" << nextPos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count();
- QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0);
+ QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
if (!item) {
waiting = true;
break;
@@ -2093,7 +2102,7 @@ void QQuickPathView::refill()
while (!waiting && d->isInBound(nextPos, d->mappedRange - d->mappedCache, startPos)
&& d->items.count() < count+d->cacheSize) {
qCDebug(lcItemViewDelegateLifecycle) << "prepend" << idx << "@" << nextPos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count();
- QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0);
+ QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
if (!item) {
waiting = true;
break;
@@ -2126,9 +2135,9 @@ void QQuickPathView::refill()
QQuickItem *lastItem = d->items.at(0);
while (idx != endIdx) {
nextPos = d->positionOfIndex(idx);
- if (d->isInBound(nextPos, d->mappedRange - d->mappedCache, 1.0 + d->mappedCache)) {
+ if (d->isInBound(nextPos, d->mappedRange - d->mappedCache, 1 + d->mappedCache)) {
//This gets the reference from the delegate model, and will not re-create
- QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0);
+ QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
if (!item) {
waiting = true;
break;
@@ -2162,13 +2171,13 @@ void QQuickPathView::refill()
bool currentChanged = false;
if (!currentVisible) {
- d->currentItemOffset = 1.0;
+ d->currentItemOffset = 1;
if (d->currentItem) {
- d->updateItem(d->currentItem, 1.0);
+ d->updateItem(d->currentItem, 1);
} else if (!waiting && d->currentIndex >= 0 && d->currentIndex < d->modelCount) {
if ((d->currentItem = d->getItem(d->currentIndex, d->currentIndex))) {
currentChanged = true;
- d->updateItem(d->currentItem, 1.0);
+ d->updateItem(d->currentItem, 1);
if (QQuickPathViewAttached *att = d->attached(d->currentItem))
att->setIsCurrentItem(true);
}
@@ -2362,7 +2371,7 @@ void QQuickPathViewPrivate::createCurrentItem()
}
} else if (currentIndex >= 0 && currentIndex < modelCount) {
if ((currentItem = getItem(currentIndex, currentIndex))) {
- updateItem(currentItem, 1.0);
+ updateItem(currentItem, 1);
if (QQuickPathViewAttached *att = attached(currentItem))
att->setIsCurrentItem(true);
}
@@ -2396,7 +2405,7 @@ void QQuickPathViewPrivate::updateCurrent()
void QQuickPathViewPrivate::fixOffsetCallback(void *d)
{
- ((QQuickPathViewPrivate *)d)->fixOffset();
+ static_cast<QQuickPathViewPrivate *>(d)->fixOffset();
}
void QQuickPathViewPrivate::fixOffset()
@@ -2421,7 +2430,7 @@ void QQuickPathViewPrivate::snapToIndex(int index, MovementReason reason)
qreal targetOffset = std::fmod(qreal(modelCount - index), qreal(modelCount));
moveReason = reason;
- offsetAdj = 0.0;
+ offsetAdj = 0;
tl.reset(moveOffset);
moveOffset.setValue(offset);
@@ -2433,20 +2442,20 @@ void QQuickPathViewPrivate::snapToIndex(int index, MovementReason reason)
if (!duration || qAbs(offset - targetOffset) < threshold || (qFuzzyIsNull(targetOffset) && qAbs(modelCount - offset) < threshold)) {
tl.set(moveOffset, targetOffset);
- } else if (moveDirection == QQuickPathView::Positive || (moveDirection == QQuickPathView::Shortest && targetOffset - offset > modelCount/2.0)) {
+ } else if (moveDirection == QQuickPathView::Positive || (moveDirection == QQuickPathView::Shortest && targetOffset - offset > modelCount/2)) {
qreal distance = modelCount - targetOffset + offset;
if (targetOffset > moveOffset) {
- tl.move(moveOffset, 0.0, QEasingCurve(QEasingCurve::InQuad), int(duration * offset / distance));
+ tl.move(moveOffset, 0, QEasingCurve(QEasingCurve::InQuad), int(duration * offset / distance));
tl.set(moveOffset, modelCount);
- tl.move(moveOffset, targetOffset, QEasingCurve(offset == 0.0 ? QEasingCurve::InOutQuad : QEasingCurve::OutQuad), int(duration * (modelCount-targetOffset) / distance));
+ tl.move(moveOffset, targetOffset, QEasingCurve(qFuzzyIsNull(offset) ? QEasingCurve::InOutQuad : QEasingCurve::OutQuad), int(duration * (modelCount-targetOffset) / distance));
} else {
tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
}
- } else if (moveDirection == QQuickPathView::Negative || targetOffset - offset <= -modelCount/2.0) {
+ } else if (moveDirection == QQuickPathView::Negative || targetOffset - offset <= -modelCount/2) {
qreal distance = modelCount - offset + targetOffset;
if (targetOffset < moveOffset) {
- tl.move(moveOffset, modelCount, QEasingCurve(targetOffset == 0 ? QEasingCurve::InOutQuad : QEasingCurve::InQuad), int(duration * (modelCount-offset) / distance));
- tl.set(moveOffset, 0.0);
+ tl.move(moveOffset, modelCount, QEasingCurve(qFuzzyIsNull(targetOffset) ? QEasingCurve::InOutQuad : QEasingCurve::InQuad), int(duration * (modelCount-offset) / distance));
+ tl.set(moveOffset, 0);
tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::OutQuad), int(duration * targetOffset / distance));
} else {
tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h
index 8eff53e6dc..cf21555823 100644
--- a/src/quick/items/qquickpincharea_p.h
+++ b/src/quick/items/qquickpincharea_p.h
@@ -59,7 +59,7 @@ class Q_AUTOTEST_EXPORT QQuickPinch : public QObject
{
Q_OBJECT
- Q_PROPERTY(QQuickItem *target READ target WRITE setTarget RESET resetTarget)
+ Q_PROPERTY(QQuickItem *target READ target WRITE setTarget RESET resetTarget NOTIFY targetChanged)
Q_PROPERTY(qreal minimumScale READ minimumScale WRITE setMinimumScale NOTIFY minimumScaleChanged)
Q_PROPERTY(qreal maximumScale READ maximumScale WRITE setMaximumScale NOTIFY maximumScaleChanged)
Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged)
@@ -283,7 +283,7 @@ Q_SIGNALS:
void pinchStarted(QQuickPinchEvent *pinch);
void pinchUpdated(QQuickPinchEvent *pinch);
void pinchFinished(QQuickPinchEvent *pinch);
- Q_REVISION(1) void smartZoom(QQuickPinchEvent *pinch);
+ Q_REVISION(5) void smartZoom(QQuickPinchEvent *pinch);
protected:
bool childMouseEventFilter(QQuickItem *i, QEvent *e) override;
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index 5e217dcd0c..f3cefc7463 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -451,8 +451,30 @@ void QQuickRectangle::setGradient(const QJSValue &gradient)
d->gradient = QJSValue();
}
} else if (gradient.isNumber() || gradient.isString()) {
- QGradient preset(gradient.toVariant().value<QGradient::Preset>());
- if (preset.type() != QGradient::NoGradient) {
+ static const QMetaEnum gradientPresetMetaEnum = QMetaEnum::fromType<QGradient::Preset>();
+ Q_ASSERT(gradientPresetMetaEnum.isValid());
+
+ QGradient result;
+
+ // This code could simply use gradient.toVariant().convert<QGradient::Preset>(),
+ // but QTBUG-76377 prevents us from doing error checks. So we need to
+ // do them manually. Also, NumPresets cannot be used.
+
+ if (gradient.isNumber()) {
+ const auto preset = QGradient::Preset(gradient.toInt());
+ if (preset != QGradient::NumPresets && gradientPresetMetaEnum.valueToKey(preset))
+ result = QGradient(preset);
+ } else if (gradient.isString()) {
+ const auto presetName = gradient.toString();
+ if (presetName != QLatin1String("NumPresets")) {
+ bool ok;
+ const auto presetInt = gradientPresetMetaEnum.keyToValue(qPrintable(presetName), &ok);
+ if (ok)
+ result = QGradient(QGradient::Preset(presetInt));
+ }
+ }
+
+ if (result.type() != QGradient::NoGradient) {
d->gradient = gradient;
} else {
qmlWarning(this) << "No such gradient preset '" << gradient.toString() << "'";
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index 76bcae1003..9f9777f199 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -188,8 +188,7 @@ void QQuickRenderControlPrivate::windowDestroyed()
if (window) {
rc->invalidate();
- delete QQuickWindowPrivate::get(window)->animationController;
- QQuickWindowPrivate::get(window)->animationController = nullptr;
+ QQuickWindowPrivate::get(window)->animationController.reset();
#if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl)
if (QOpenGLContext::currentContext())
@@ -242,7 +241,18 @@ void QQuickRenderControl::initialize(QOpenGLContext *gl)
// It cannot be done here since the surface to use may not be the
// surface belonging to window. In fact window may not have a native
// window/surface at all.
- d->rc->initialize(gl);
+ QSGDefaultRenderContext *rc = qobject_cast<QSGDefaultRenderContext *>(d->rc);
+ if (rc) {
+ QSGDefaultRenderContext::InitParams params;
+ params.sampleCount = qMax(1, gl->format().samples());
+ params.openGLContext = gl;
+ params.initialSurfacePixelSize = d->window->size() * d->window->effectiveDevicePixelRatio();
+ params.maybeSurface = d->window;
+ rc->initialize(&params);
+ } else {
+ // can this happen?
+ d->rc->initialize(nullptr);
+ }
#else
Q_UNUSED(gl)
#endif
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index 0c00fecead..c8c5281089 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -41,7 +41,6 @@
#include "qquickrepeater_p_p.h"
#include <private/qqmlglobal_p.h>
-#include <private/qqmllistaccessor_p.h>
#include <private/qqmlchangeset_p.h>
#include <private/qqmldelegatemodel_p.h>
diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h
index e9db07d14c..10e524e4a0 100644
--- a/src/quick/items/qquickscreen_p.h
+++ b/src/quick/items/qquickscreen_p.h
@@ -83,8 +83,8 @@ class Q_AUTOTEST_EXPORT QQuickScreenInfo : public QObject
// TODO Qt 6 Remove this orientation -> incomplete device orientation -> better use OrientationSensor
Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged)
- Q_PROPERTY(int virtualX READ virtualX NOTIFY virtualXChanged REVISION 1)
- Q_PROPERTY(int virtualY READ virtualY NOTIFY virtualYChanged REVISION 1)
+ Q_PROPERTY(int virtualX READ virtualX NOTIFY virtualXChanged REVISION 3)
+ Q_PROPERTY(int virtualY READ virtualY NOTIFY virtualYChanged REVISION 3)
public:
QQuickScreenInfo(QObject *parent = nullptr, QScreen *wrappedScreen = nullptr);
@@ -121,8 +121,8 @@ Q_SIGNALS:
void devicePixelRatioChanged();
void primaryOrientationChanged();
void orientationChanged();
- Q_REVISION(1) void virtualXChanged();
- Q_REVISION(1) void virtualYChanged();
+ Q_REVISION(3) void virtualXChanged();
+ Q_REVISION(3) void virtualYChanged();
protected:
QPointer<QScreen> m_screen;
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index eb5256fa4e..b3c8386fd9 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -44,6 +44,9 @@
#include <private/qquickopenglshadereffect_p.h>
#endif
#include <private/qquickgenericshadereffect_p.h>
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+#include <private/qsgrhisupport_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -506,13 +509,20 @@ QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
{
setFlag(QQuickItem::ItemHasContents);
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+ if (QSGRhiSupport::instance()->isRhiEnabled()) {
+ m_impl = new QQuickGenericShaderEffect(this, this);
+ } else
+#endif
+ {
#if QT_CONFIG(opengl)
- if (!qsg_backend_flags().testFlag(QSGContextFactoryInterface::SupportsShaderEffectNode))
- m_glImpl = new QQuickOpenGLShaderEffect(this, this);
+ if (!qsg_backend_flags().testFlag(QSGContextFactoryInterface::SupportsShaderEffectNode))
+ m_glImpl = new QQuickOpenGLShaderEffect(this, this);
- if (!m_glImpl)
+ if (!m_glImpl)
#endif
- m_impl = new QQuickGenericShaderEffect(this, this);
+ m_impl = new QQuickGenericShaderEffect(this, this);
+ }
}
QQuickShaderEffect::~QQuickShaderEffect()
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index c5bddc40d2..6e2f35882b 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -74,7 +74,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem
Q_PROPERTY(CullMode cullMode READ cullMode WRITE setCullMode NOTIFY cullModeChanged)
Q_PROPERTY(QString log READ log NOTIFY logChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
- Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 1)
+ Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 4)
public:
enum CullMode {
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 505940e673..f9f3e5cfa3 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -750,7 +750,7 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
if (!node) {
- node = d->sceneGraphContext()->createInternalImageNode();
+ node = d->sceneGraphContext()->createInternalImageNode(d->sceneGraphRenderContext());
node->setFlag(QSGNode::UsePreprocess);
node->setTexture(m_texture);
QQuickShaderSourceAttachedNode *attached = new QQuickShaderSourceAttachedNode;
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index d5bb33902a..d612d1179f 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -87,8 +87,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectSource : public QQuickItem, publi
Q_PROPERTY(bool hideSource READ hideSource WRITE setHideSource NOTIFY hideSourceChanged)
Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged)
Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
- Q_PROPERTY(TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged REVISION 1)
- Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged REVISION 2)
+ Q_PROPERTY(TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged REVISION 6)
+ Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged REVISION 9)
public:
enum WrapMode {
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index be297bbe76..8c52703938 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -554,7 +554,7 @@ void QQuickStochasticEngine::restart(int index)
bool randomStart = (m_startTimes.at(index) == NINF);
m_startTimes[index] = m_timeOffset;
if (m_addAdvance)
- m_startTimes[index] += m_advanceTime.elapsed();
+ m_startTimes[index] += m_advanceTimer.elapsed();
if (randomStart)
m_startTimes[index] -= QRandomGenerator::global()->bounded(m_duration.at(index));
int time = m_duration.at(index) + m_startTimes.at(index);
@@ -574,12 +574,12 @@ void QQuickSpriteEngine::restart(int index) //Reimplemented to recognize and han
} else {
m_startTimes[index] = m_timeOffset;
if (m_addAdvance)
- m_startTimes[index] += m_advanceTime.elapsed();
+ m_startTimes[index] += m_advanceTimer.elapsed();
if (randomStart)
m_startTimes[index] -= QRandomGenerator::global()->bounded(m_duration.at(index));
int time = spriteDuration(index) + m_startTimes.at(index);
if (randomStart) {
- int curTime = m_timeOffset + (m_addAdvance ? m_advanceTime.elapsed() : 0);
+ int curTime = m_timeOffset + (m_addAdvance ? m_advanceTimer.elapsed() : 0);
while (time < curTime) //Fast forward through psuedostates as needed
time += spriteDuration(index);
}
@@ -623,10 +623,10 @@ void QQuickSpriteEngine::advance(int idx) //Reimplemented to recognize and handl
}
//just go past the pseudostate logic
} else if (m_startTimes.at(idx) + m_duration.at(idx)
- > int(m_timeOffset + (m_addAdvance ? m_advanceTime.elapsed() : 0))) {
+ > int(m_timeOffset + (m_addAdvance ? m_advanceTimer.elapsed() : 0))) {
//only a pseduostate ended
emit stateChanged(idx);
- addToUpdateList(spriteStart(idx) + spriteDuration(idx) + (m_addAdvance ? m_advanceTime.elapsed() : 0), idx);
+ addToUpdateList(spriteStart(idx) + spriteDuration(idx) + (m_addAdvance ? m_advanceTimer.elapsed() : 0), idx);
return;
}
int nextIdx = nextState(m_things.at(idx), idx);
@@ -685,7 +685,7 @@ uint QQuickStochasticEngine::updateSprites(uint time)//### would returning a lis
}
m_stateUpdates.remove(0, i);
- m_advanceTime.start();
+ m_advanceTimer.start();
m_addAdvance = true;
if (m_stateUpdates.isEmpty())
return uint(-1);
diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h
index d3944b4620..da505be911 100644
--- a/src/quick/items/qquickspriteengine_p.h
+++ b/src/quick/items/qquickspriteengine_p.h
@@ -58,7 +58,7 @@ QT_REQUIRE_CONFIG(quick_sprite);
#include <QObject>
#include <QVector>
#include <QTimer>
-#include <QTime>
+#include <QElapsedTimer>
#include <QList>
#include <QQmlListProperty>
#include <QImage>
@@ -254,7 +254,7 @@ protected:
QVector<int> m_startTimes;
QVector<QPair<uint, QVector<int> > > m_stateUpdates;//### This could be done faster - priority queue?
- QTime m_advanceTime;
+ QElapsedTimer m_advanceTimer;
uint m_timeOffset;
QString m_globalGoal;
int m_maxFrames;
diff --git a/src/quick/items/qquickspritesequence_p.h b/src/quick/items/qquickspritesequence_p.h
index 899ce79e0e..12c80d6a27 100644
--- a/src/quick/items/qquickspritesequence_p.h
+++ b/src/quick/items/qquickspritesequence_p.h
@@ -56,7 +56,6 @@
QT_REQUIRE_CONFIG(quick_sprite);
#include <QtQuick/QQuickItem>
-#include <QTime>
QT_BEGIN_NAMESPACE
diff --git a/src/quick/items/qquickspritesequence_p_p.h b/src/quick/items/qquickspritesequence_p_p.h
index 3579833116..4788cd15aa 100644
--- a/src/quick/items/qquickspritesequence_p_p.h
+++ b/src/quick/items/qquickspritesequence_p_p.h
@@ -57,6 +57,7 @@ QT_REQUIRE_CONFIG(quick_sprite);
#include "qquickitem_p.h"
#include "qquicksprite_p.h"
+#include <QElapsedTimer>
QT_BEGIN_NAMESPACE
@@ -78,7 +79,7 @@ public:
}
QList<QQuickSprite*> m_sprites;
QQuickSpriteEngine* m_spriteEngine;
- QTime m_timestamp;
+ QElapsedTimer m_timestamp;
int m_curFrame;
bool m_pleaseReset;
bool m_running;
diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp
index fe1dfd349e..31d1c91649 100644
--- a/src/quick/items/qquickstateoperations.cpp
+++ b/src/quick/items/qquickstateoperations.cpp
@@ -200,7 +200,7 @@ QQmlScriptString QQuickParentChange::x() const
return d->xString.value;
}
-void QQuickParentChange::setX(QQmlScriptString x)
+void QQuickParentChange::setX(const QQmlScriptString &x)
{
Q_D(QQuickParentChange);
d->xString = x;
@@ -218,7 +218,7 @@ QQmlScriptString QQuickParentChange::y() const
return d->yString.value;
}
-void QQuickParentChange::setY(QQmlScriptString y)
+void QQuickParentChange::setY(const QQmlScriptString &y)
{
Q_D(QQuickParentChange);
d->yString = y;
@@ -236,7 +236,7 @@ QQmlScriptString QQuickParentChange::width() const
return d->widthString.value;
}
-void QQuickParentChange::setWidth(QQmlScriptString width)
+void QQuickParentChange::setWidth(const QQmlScriptString &width)
{
Q_D(QQuickParentChange);
d->widthString = width;
@@ -254,7 +254,7 @@ QQmlScriptString QQuickParentChange::height() const
return d->heightString.value;
}
-void QQuickParentChange::setHeight(QQmlScriptString height)
+void QQuickParentChange::setHeight(const QQmlScriptString &height)
{
Q_D(QQuickParentChange);
d->heightString = height;
@@ -272,7 +272,7 @@ QQmlScriptString QQuickParentChange::scale() const
return d->scaleString.value;
}
-void QQuickParentChange::setScale(QQmlScriptString scale)
+void QQuickParentChange::setScale(const QQmlScriptString &scale)
{
Q_D(QQuickParentChange);
d->scaleString = scale;
@@ -290,7 +290,7 @@ QQmlScriptString QQuickParentChange::rotation() const
return d->rotationString.value;
}
-void QQuickParentChange::setRotation(QQmlScriptString rotation)
+void QQuickParentChange::setRotation(const QQmlScriptString &rotation)
{
Q_D(QQuickParentChange);
d->rotationString = rotation;
diff --git a/src/quick/items/qquickstateoperations_p.h b/src/quick/items/qquickstateoperations_p.h
index e947b2213f..357366bc60 100644
--- a/src/quick/items/qquickstateoperations_p.h
+++ b/src/quick/items/qquickstateoperations_p.h
@@ -87,27 +87,27 @@ public:
QQuickItem *originalParent() const;
QQmlScriptString x() const;
- void setX(QQmlScriptString x);
+ void setX(const QQmlScriptString &x);
bool xIsSet() const;
QQmlScriptString y() const;
- void setY(QQmlScriptString y);
+ void setY(const QQmlScriptString &y);
bool yIsSet() const;
QQmlScriptString width() const;
- void setWidth(QQmlScriptString width);
+ void setWidth(const QQmlScriptString &width);
bool widthIsSet() const;
QQmlScriptString height() const;
- void setHeight(QQmlScriptString height);
+ void setHeight(const QQmlScriptString &height);
bool heightIsSet() const;
QQmlScriptString scale() const;
- void setScale(QQmlScriptString scale);
+ void setScale(const QQmlScriptString &scale);
bool scaleIsSet() const;
QQmlScriptString rotation() const;
- void setRotation(QQmlScriptString rotation);
+ void setRotation(const QQmlScriptString &rotation);
bool rotationIsSet() const;
ActionList actions() override;
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 58cd80500c..295c6898bc 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -42,10 +42,10 @@
#include <QtCore/qtimer.h>
#include <QtCore/qdir.h>
-#include <QtQml/private/qqmldelegatemodel_p.h>
-#include <QtQml/private/qqmldelegatemodel_p_p.h>
+#include <QtQmlModels/private/qqmldelegatemodel_p.h>
+#include <QtQmlModels/private/qqmldelegatemodel_p_p.h>
#include <QtQml/private/qqmlincubator_p.h>
-#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQmlModels/private/qqmlchangeset_p.h>
#include <QtQml/qqmlinfo.h>
#include <QtQuick/private/qquickflickable_p_p.h>
@@ -53,12 +53,11 @@
/*!
\qmltype TableView
- \instantiates QQuickTableView
\inqmlmodule QtQuick
\since 5.12
\ingroup qtquick-views
\inherits Flickable
- \brief Provides a table view of items provided by the model.
+ \brief Provides a table view of items to display data from a model.
A TableView has a \l model that defines the data to be displayed, and a
\l delegate that defines how the data should be displayed.
@@ -73,25 +72,34 @@
A TableView displays data from models created from built-in QML types
such as ListModel and XmlListModel, which populates the first column only
- in a TableView. To create models with multiple columns, create a model in
- C++ that inherits QAbstractItemModel, and expose it to QML.
+ in a TableView. To create models with multiple columns, either use
+ \l TableModel or a C++ model that inherits QAbstractItemModel.
\section1 Example Usage
+ \section2 C++ Models
+
The following example shows how to create a model from C++ with multiple
columns:
- \snippet qml/tableview/tablemodel.cpp 0
+ \snippet qml/tableview/cpp-tablemodel.cpp 0
And then how to use it from QML:
- \snippet qml/tableview/tablemodel.qml 0
+ \snippet qml/tableview/cpp-tablemodel.qml 0
+
+ \section2 QML Models
+
+ For prototyping and displaying very simple data (from a web API, for
+ example), \l TableModel can be used:
+
+ \snippet qml/tableview/qml-tablemodel.qml 0
\section1 Reusing items
TableView recycles delegate items by default, instead of instantiating from
the \l delegate whenever new rows and columns are flicked into view. This
- can give a huge performance boost, depending on the complexity of the
+ approach gives a huge performance boost, depending on the complexity of the
delegate.
When an item is flicked out, it moves to the \e{reuse pool}, which is an
@@ -125,8 +133,8 @@
\section1 Row heights and column widths
When a new column is flicked into view, TableView will determine its width
- by calling the \l columnWidthProvider function. TableView itself will never
- store row height or column width, as it's designed to support large models
+ by calling the \l columnWidthProvider function. TableView does not store
+ row height or column width, as it's designed to support large models
containing any number of rows and columns. Instead, it will ask the
application whenever it needs to know.
@@ -140,9 +148,9 @@
\note The calculated width of a column is discarded when it is flicked out
of the viewport, and is recalculated if the column is flicked back in. The
calculation is always based on the items that are visible when the column
- is flicked in. This means that it can end up different each time, depending
- on which row you're at when the column enters. You should therefore have the
- same \c implicitWidth for all items in a column, or set
+ is flicked in. This means that column width can be different each time,
+ depending on which row you're at when the column enters. You should
+ therefore have the same \c implicitWidth for all items in a column, or set
\l columnWidthProvider. The same logic applies for the row height
calculation.
@@ -151,10 +159,11 @@
must call \l forceLayout. This informs TableView that it needs to use the
provider functions again to recalculate and update the layout.
- Since Qt 5.13, if you want to hide a specific column, you can return \c 0 from the
- \l columnWidthProvider for that column. Likewise, you can return 0 from the
- \l rowHeightProvider to hide a row. If you return a negative number, TableView
- will fall back to calculate the size based on the delegate items.
+ Since Qt 5.13, if you want to hide a specific column, you can return \c 0
+ from the \l columnWidthProvider for that column. Likewise, you can return 0
+ from the \l rowHeightProvider to hide a row. If you return a negative
+ number, TableView will fall back to calculate the size based on the delegate
+ items.
\note The size of a row or column should be a whole number to avoid
sub-pixel alignment of items.
@@ -168,11 +177,11 @@
\section1 Overlays and underlays
- Tableview inherits \l Flickable. And when new items are instantiated from the
- delegate, it will parent them to the \l{Flickable::}{contentItem}
- with a \c z value equal to \c 1. You can add your own items inside the
- Tableview, as child items of the Flickable. By controlling their \c z
- value, you can make them be on top of or underneath the table items.
+ All new items that are instantiated from the delegate are parented to the
+ \l{Flickable::}{contentItem} with the \c z value, \c 1. You can add your
+ own items inside the Tableview, as child items of the Flickable. By
+ controlling their \c z value, you can make them be on top of or
+ underneath the table items.
Here is an example that shows how to add some text on top of the table, that
moves together with the table as you flick:
@@ -182,6 +191,7 @@
/*!
\qmlproperty int QtQuick::TableView::rows
+ \readonly
This property holds the number of rows in the table. This is
equal to the number of rows in the model.
@@ -191,10 +201,11 @@
/*!
\qmlproperty int QtQuick::TableView::columns
+ \readonly
This property holds the number of columns in the table. This is
equal to the number of columns in the model. If the model is
- a list, columns will be 1.
+ a list, columns will be \c 1.
This property is read only.
*/
@@ -204,7 +215,7 @@
This property holds the spacing between the rows.
- The default value is 0.
+ The default value is \c 0.
*/
/*!
@@ -212,20 +223,20 @@
This property holds the spacing between the columns.
- The default value is 0.
+ The default value is \c 0.
*/
/*!
\qmlproperty var QtQuick::TableView::rowHeightProvider
This property can hold a function that returns the row height for each row
- in the model. When assigned, it will be called whenever TableView needs to
- know the height of a specific row. The function takes one argument, \c row,
- for which the TableView needs to know the height.
+ in the model. It is called whenever TableView needs to know the height of
+ a specific row. The function takes one argument, \c row, for which the
+ TableView needs to know the height.
- Since Qt 5.13, if you want to hide a specific row, you can return \c 0 height for
- that row. If you return a negative number, TableView will fall back to
- calculate the height based on the delegate items.
+ Since Qt 5.13, if you want to hide a specific row, you can return \c 0
+ height for that row. If you return a negative number, TableView calculates
+ the height based on the delegate items.
\sa columnWidthProvider, {Row heights and column widths}
*/
@@ -234,13 +245,13 @@
\qmlproperty var QtQuick::TableView::columnWidthProvider
This property can hold a function that returns the column width for each
- column in the model. When assigned, it is called whenever TableView needs
- to know the width of a specific column. The function takes one argument,
- \c column, for which the TableView needs to know the width.
+ column in the model. It is called whenever TableView needs to know the
+ width of a specific column. The function takes one argument, \c column,
+ for which the TableView needs to know the width.
- Since Qt 5.13, if you want to hide a specific column, you can return \c 0 width for
- that column. If you return a negative number, TableView will fall back to
- calculate the width based on the delegate items.
+ Since Qt 5.13, if you want to hide a specific column, you can return \c 0
+ width for that column. If you return a negative number, TableView
+ calculates the width based on the delegate items.
\sa rowHeightProvider, {Row heights and column widths}
*/
@@ -250,9 +261,9 @@
This property holds the model that provides data for the table.
The model provides the set of data that is used to create the items
- in the view. Models can be created directly in QML using \l ListModel,
- \l XmlListModel or \l ObjectModel, or provided by a custom C++ model
- class. If it is a C++ model, it must be a subclass of \l QAbstractItemModel
+ in the view. Models can be created directly in QML using \l TableModel,
+ \l ListModel, \l XmlListModel, or \l ObjectModel, or provided by a custom
+ C++ model class. The C++ model must be a subclass of \l QAbstractItemModel
or a simple list.
\sa {qml-data-models}{Data Models}
@@ -266,10 +277,9 @@
applies to \c row and \c column. Properties of the model are also available
depending upon the type of \l {qml-data-models}{Data Model}.
- A delegate should specify its size using \l [QML]{Item::implicitWidth}{implicitWidth} and
- \l [QML]{Item::implicitHeight}{implicitHeight}.
- The TableView lays out the items based on that information. Explicit width or
- height settings are ignored and overwritten.
+ A delegate should specify its size using \l{Item::}{implicitWidth} and
+ \l {Item::}{implicitHeight}. The TableView lays out the items based on that
+ information. Explicit width or height settings are ignored and overwritten.
\note Delegates are instantiated as needed and may be destroyed at any time.
They are also reused if the \l reuseItems property is set to \c true. You
@@ -291,37 +301,35 @@
/*!
\qmlproperty real QtQuick::TableView::contentWidth
- This property holds the width of the \l view, which is also
- the width of the table (including margins). As a TableView cannot
- always know the exact width of the table without loading all columns
- in the model, the \c contentWidth is usually an estimated width based on
- the columns it has seen so far. This estimate is recalculated whenever
- new columns are flicked into view, which means that the content width
- can change dynamically.
+ This property holds the table width required to accommodate the number of
+ columns in the model. This is usually not the same as the \c width of the
+ \l view, which means that the table's width could be larger or smaller than
+ the viewport width. As a TableView cannot always know the exact width of
+ the table without loading all columns in the model, the \c contentWidth is
+ usually an estimate based on the initially loaded table.
- If you know up front what the width of the table will be, assign a value
- to \c contentWidth explicitly, to avoid unnecessary calculations and
- updates to the TableView.
+ If you know what the width of the table will be, assign a value to
+ \c contentWidth, to avoid unnecessary calculations and updates to the
+ TableView.
- \sa contentHeight
+ \sa contentHeight, columnWidthProvider
*/
/*!
\qmlproperty real QtQuick::TableView::contentHeight
- This property holds the height of the \l view, which is also
- the height of the table (including margins). As a TableView cannot
- always know the exact height of the table without loading all rows
- in the model, the \c contentHeight is usually an estimated height
- based on the rows it has seen so far. This estimate is recalculated
- whenever new rows are flicked into view, which means that the content height
- can change dynamically.
+ This property holds the table height required to accommodate the number of
+ rows in the data model. This is usually not the same as the \c height of the
+ \c view, which means that the table's height could be larger or smaller than the
+ viewport height. As a TableView cannot always know the exact height of the
+ table without loading all rows in the model, the \c contentHeight is
+ usually an estimate based on the initially loaded table.
- If you know up front what the height of the table will be, assign a
- value to \c contentHeight explicitly, to avoid unnecessary calculations and
- updates to the TableView.
+ If you know what the height of the table will be, assign a
+ value to \c contentHeight, to avoid unnecessary calculations and updates to
+ the TableView.
- \sa contentWidth
+ \sa contentWidth, rowHeightProvider
*/
/*!
@@ -330,7 +338,7 @@
Responding to changes in the model are batched so that they are handled
only once per frame. This means the TableView delays showing any changes
while a script is being run. The same is also true when changing
- properties such as \l rowSpacing or \l {Item::anchors.leftMargin}{leftMargin}.
+ properties, such as \l rowSpacing or \l{Item::anchors.leftMargin}{leftMargin}.
This method forces the TableView to immediately update the layout so
that any recent changes take effect.
@@ -367,9 +375,9 @@
item has been taken out of the pool and placed inside the content view,
and the model properties such as index, row, and column have been updated.
- Other properties that are not provided by the model does not change when an item
- is reused. You should avoid storing any state inside a delegate, but if you do,
- manually reset that state on receiving this signal.
+ Other properties that are not provided by the model does not change when an
+ item is reused. You should avoid storing any state inside a delegate, but if
+ you do, manually reset that state on receiving this signal.
This signal is emitted when the item is reused, and not the first time the
item is created.
@@ -425,6 +433,10 @@ bool QQuickTableViewPrivate::EdgeRange::containsIndex(Qt::Edge edge, int index)
QQuickTableViewPrivate::QQuickTableViewPrivate()
: QQuickFlickablePrivate()
{
+ QObject::connect(&columnWidths, &QQuickTableSectionSizeProvider::sizeChanged,
+ [this] { this->forceLayout();});
+ QObject::connect(&rowHeights, &QQuickTableSectionSizeProvider::sizeChanged,
+ [this] { this->forceLayout();});
}
QQuickTableViewPrivate::~QQuickTableViewPrivate()
@@ -604,6 +616,12 @@ void QQuickTableViewPrivate::updateContentWidth()
{
Q_Q(QQuickTableView);
+ if (syncHorizontally) {
+ QBoolBlocker fixupGuard(inUpdateContentSize, true);
+ q->QQuickFlickable::setContentWidth(syncView->contentWidth());
+ return;
+ }
+
if (explicitContentWidth.isValid()) {
// Don't calculate contentWidth when it
// was set explicitly by the application.
@@ -616,6 +634,8 @@ void QQuickTableViewPrivate::updateContentWidth()
const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
const qreal estimatedWidth = loadedTableOuterRect.right() + estimatedRemainingWidth;
+
+ QBoolBlocker fixupGuard(inUpdateContentSize, true);
q->QQuickFlickable::setContentWidth(estimatedWidth);
}
@@ -623,6 +643,12 @@ void QQuickTableViewPrivate::updateContentHeight()
{
Q_Q(QQuickTableView);
+ if (syncVertically) {
+ QBoolBlocker fixupGuard(inUpdateContentSize, true);
+ q->QQuickFlickable::setContentHeight(syncView->contentHeight());
+ return;
+ }
+
if (explicitContentHeight.isValid()) {
// Don't calculate contentHeight when it
// was set explicitly by the application.
@@ -635,64 +661,204 @@ void QQuickTableViewPrivate::updateContentHeight()
const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
const qreal estimatedHeight = loadedTableOuterRect.bottom() + estimatedRemainingHeight;
+
+ QBoolBlocker fixupGuard(inUpdateContentSize, true);
q->QQuickFlickable::setContentHeight(estimatedHeight);
}
-void QQuickTableViewPrivate::enforceTableAtOrigin()
+void QQuickTableViewPrivate::updateExtents()
{
- // Gaps before the first row/column can happen if rows/columns
- // changes size while flicking e.g because of spacing changes or
- // changes to a column maxWidth/row maxHeight. Check for this, and
- // move the whole table rect accordingly.
- bool layoutNeeded = false;
- const qreal flickMargin = 50;
-
- const bool noMoreColumns = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge) == kEdgeIndexAtEnd;
- const bool noMoreRows = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge) == kEdgeIndexAtEnd;
+ // When rows or columns outside the viewport are removed or added, or a rebuild
+ // forces us to guesstimate a new top-left, the edges of the table might end up
+ // out of sync with the edges of the content view. We detect this situation here, and
+ // move the origin to ensure that there will never be gaps at the end of the table.
+ // Normally we detect that the size of the whole table is not going to be equal to the
+ // size of the content view already when we load the last row/column, and especially
+ // before it's flicked completely inside the viewport. For those cases we simply adjust
+ // the origin/endExtent, to give a smooth flicking experience.
+ // But if flicking fast (e.g with a scrollbar), it can happen that the viewport ends up
+ // outside the end of the table in just one viewport update. To avoid a "blink" in the
+ // viewport when that happens, we "move" the loaded table into the viewport to cover it.
+ Q_Q(QQuickTableView);
- if (noMoreColumns) {
- if (!qFuzzyIsNull(loadedTableOuterRect.left())) {
- // There are no more columns, but the table rect
- // is not at origin. So we move it there.
- loadedTableOuterRect.moveLeft(0);
- layoutNeeded = true;
+ bool tableMovedHorizontally = false;
+ bool tableMovedVertically = false;
+
+ const int nextLeftColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge);
+ const int nextRightColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
+ const int nextTopRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge);
+ const int nextBottomRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
+
+ if (syncHorizontally) {
+ const auto syncView_d = syncView->d_func();
+ origin.rx() = syncView_d->origin.x();
+ endExtent.rwidth() = syncView_d->endExtent.width();
+ hData.markExtentsDirty();
+ } else if (nextLeftColumn == kEdgeIndexAtEnd) {
+ // There are no more columns to load on the left side of the table.
+ // In that case, we ensure that the origin match the beginning of the table.
+ if (loadedTableOuterRect.left() > viewportRect.left()) {
+ // We have a blank area at the left end of the viewport. In that case we don't have time to
+ // wait for the viewport to move (after changing origin), since that will take an extra
+ // update cycle, which will be visible as a blink. Instead, unless the blank spot is just
+ // us overshooting, we brute force the loaded table inside the already existing viewport.
+ if (loadedTableOuterRect.left() > origin.x()) {
+ const qreal diff = loadedTableOuterRect.left() - origin.x();
+ loadedTableOuterRect.moveLeft(loadedTableOuterRect.left() - diff);
+ loadedTableInnerRect.moveLeft(loadedTableInnerRect.left() - diff);
+ tableMovedHorizontally = true;
+ }
}
- } else {
- if (loadedTableOuterRect.left() <= 0) {
- // The table rect is at origin, or outside. But we still have
- // more visible columns to the left. So we need to make some
- // space so that they can be flicked in.
- loadedTableOuterRect.moveLeft(flickMargin);
- layoutNeeded = true;
+ origin.rx() = loadedTableOuterRect.left();
+ hData.markExtentsDirty();
+ } else if (loadedTableOuterRect.left() <= origin.x() + cellSpacing.width()) {
+ // The table rect is at the origin, or outside, but we still have more
+ // visible columns to the left. So we try to guesstimate how much space
+ // the rest of the columns will occupy, and move the origin accordingly.
+ const int columnsRemaining = nextLeftColumn + 1;
+ const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
+ const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
+ const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
+ origin.rx() = loadedTableOuterRect.left() - estimatedRemainingWidth;
+ hData.markExtentsDirty();
+ } else if (nextRightColumn == kEdgeIndexAtEnd) {
+ // There are no more columns to load on the right side of the table.
+ // In that case, we ensure that the end of the content view match the end of the table.
+ if (loadedTableOuterRect.right() < viewportRect.right()) {
+ // We have a blank area at the right end of the viewport. In that case we don't have time to
+ // wait for the viewport to move (after changing endExtent), since that will take an extra
+ // update cycle, which will be visible as a blink. Instead, unless the blank spot is just
+ // us overshooting, we brute force the loaded table inside the already existing viewport.
+ const qreal w = qMin(viewportRect.right(), q->contentWidth() + endExtent.width());
+ if (loadedTableOuterRect.right() < w) {
+ const qreal diff = loadedTableOuterRect.right() - w;
+ loadedTableOuterRect.moveRight(loadedTableOuterRect.right() - diff);
+ loadedTableInnerRect.moveRight(loadedTableInnerRect.right() - diff);
+ tableMovedHorizontally = true;
+ }
}
- }
-
- if (noMoreRows) {
- if (!qFuzzyIsNull(loadedTableOuterRect.top())) {
- loadedTableOuterRect.moveTop(0);
- layoutNeeded = true;
+ endExtent.rwidth() = loadedTableOuterRect.right() - q->contentWidth();
+ hData.markExtentsDirty();
+ } else if (loadedTableOuterRect.right() >= q->contentWidth() + endExtent.width() - cellSpacing.width()) {
+ // The right-most column is outside the end of the content view, and we
+ // still have more visible columns in the model. This can happen if the application
+ // has set a fixed content width.
+ const int columnsRemaining = tableSize.width() - nextRightColumn;
+ const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
+ const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
+ const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
+ const qreal pixelsOutsideContentWidth = loadedTableOuterRect.right() - q->contentWidth();
+ endExtent.rwidth() = pixelsOutsideContentWidth + estimatedRemainingWidth;
+ hData.markExtentsDirty();
+ }
+
+ if (syncVertically) {
+ const auto syncView_d = syncView->d_func();
+ origin.ry() = syncView_d->origin.y();
+ endExtent.rheight() = syncView_d->endExtent.height();
+ vData.markExtentsDirty();
+ } else if (nextTopRow == kEdgeIndexAtEnd) {
+ // There are no more rows to load on the top side of the table.
+ // In that case, we ensure that the origin match the beginning of the table.
+ if (loadedTableOuterRect.top() > viewportRect.top()) {
+ // We have a blank area at the top of the viewport. In that case we don't have time to
+ // wait for the viewport to move (after changing origin), since that will take an extra
+ // update cycle, which will be visible as a blink. Instead, unless the blank spot is just
+ // us overshooting, we brute force the loaded table inside the already existing viewport.
+ if (loadedTableOuterRect.top() > origin.y()) {
+ const qreal diff = loadedTableOuterRect.top() - origin.y();
+ loadedTableOuterRect.moveTop(loadedTableOuterRect.top() - diff);
+ loadedTableInnerRect.moveTop(loadedTableInnerRect.top() - diff);
+ tableMovedVertically = true;
+ }
}
- } else {
- if (loadedTableOuterRect.top() <= 0) {
- loadedTableOuterRect.moveTop(flickMargin);
- layoutNeeded = true;
+ origin.ry() = loadedTableOuterRect.top();
+ vData.markExtentsDirty();
+ } else if (loadedTableOuterRect.top() <= origin.y() + cellSpacing.height()) {
+ // The table rect is at the origin, or outside, but we still have more
+ // visible rows at the top. So we try to guesstimate how much space
+ // the rest of the rows will occupy, and move the origin accordingly.
+ const int rowsRemaining = nextTopRow + 1;
+ const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
+ const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
+ const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
+ origin.ry() = loadedTableOuterRect.top() - estimatedRemainingHeight;
+ vData.markExtentsDirty();
+ } else if (nextBottomRow == kEdgeIndexAtEnd) {
+ // There are no more rows to load on the bottom side of the table.
+ // In that case, we ensure that the end of the content view match the end of the table.
+ if (loadedTableOuterRect.bottom() < viewportRect.bottom()) {
+ // We have a blank area at the bottom of the viewport. In that case we don't have time to
+ // wait for the viewport to move (after changing endExtent), since that will take an extra
+ // update cycle, which will be visible as a blink. Instead, unless the blank spot is just
+ // us overshooting, we brute force the loaded table inside the already existing viewport.
+ const qreal h = qMin(viewportRect.bottom(), q->contentHeight() + endExtent.height());
+ if (loadedTableOuterRect.bottom() < h) {
+ const qreal diff = loadedTableOuterRect.bottom() - h;
+ loadedTableOuterRect.moveBottom(loadedTableOuterRect.bottom() - diff);
+ loadedTableInnerRect.moveBottom(loadedTableInnerRect.bottom() - diff);
+ tableMovedVertically = true;
+ }
+ }
+ endExtent.rheight() = loadedTableOuterRect.bottom() - q->contentHeight();
+ vData.markExtentsDirty();
+ } else if (loadedTableOuterRect.bottom() >= q->contentHeight() + endExtent.height() - cellSpacing.height()) {
+ // The bottom-most row is outside the end of the content view, and we
+ // still have more visible rows in the model. This can happen if the application
+ // has set a fixed content height.
+ const int rowsRemaining = tableSize.height() - nextBottomRow;
+ const qreal remainingRowHeigts = rowsRemaining * averageEdgeSize.height();
+ const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
+ const qreal estimatedRemainingHeight = remainingRowHeigts + remainingSpacing;
+ const qreal pixelsOutsideContentHeight = loadedTableOuterRect.bottom() - q->contentHeight();
+ endExtent.rheight() = pixelsOutsideContentHeight + estimatedRemainingHeight;
+ vData.markExtentsDirty();
+ }
+
+ if (tableMovedHorizontally || tableMovedVertically) {
+ qCDebug(lcTableViewDelegateLifecycle) << "move table to" << loadedTableOuterRect;
+
+ // relayoutTableItems() will take care of moving the existing
+ // delegate items into the new loadedTableOuterRect.
+ relayoutTableItems();
+
+ // Inform the sync children that they need to rebuild to stay in sync
+ for (auto syncChild : qAsConst(syncChildren)) {
+ auto syncChild_d = syncChild->d_func();
+ syncChild_d->scheduledRebuildOptions |= RebuildOption::ViewportOnly;
+ if (tableMovedHorizontally)
+ syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
+ if (tableMovedVertically)
+ syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
}
}
- if (layoutNeeded) {
- qCDebug(lcTableViewDelegateLifecycle);
- relayoutTableItems();
+ if (hData.minExtentDirty || vData.minExtentDirty) {
+ qCDebug(lcTableViewDelegateLifecycle) << "move origin and endExtent to:" << origin << endExtent;
+ // updateBeginningEnd() will let the new extents take effect. This will also change the
+ // visualArea of the flickable, which again will cause any attached scrollbars to adjust
+ // the position of the handle. Note the latter will cause the viewport to move once more.
+ updateBeginningEnd();
}
}
void QQuickTableViewPrivate::updateAverageEdgeSize()
{
- const int loadedRowCount = loadedRows.count();
- const int loadedColumnCount = loadedColumns.count();
- const qreal accRowSpacing = (loadedRowCount - 1) * cellSpacing.height();
- const qreal accColumnSpacing = (loadedColumnCount - 1) * cellSpacing.width();
- averageEdgeSize.setHeight((loadedTableOuterRect.height() - accRowSpacing) / loadedRowCount);
- averageEdgeSize.setWidth((loadedTableOuterRect.width() - accColumnSpacing) / loadedColumnCount);
+ if (explicitContentWidth.isValid()) {
+ const qreal accColumnSpacing = (tableSize.width() - 1) * cellSpacing.width();
+ averageEdgeSize.setWidth((explicitContentWidth - accColumnSpacing) / tableSize.width());
+ } else {
+ const qreal accColumnSpacing = (loadedColumns.count() - 1) * cellSpacing.width();
+ averageEdgeSize.setWidth((loadedTableOuterRect.width() - accColumnSpacing) / loadedColumns.count());
+ }
+
+ if (explicitContentHeight.isValid()) {
+ const qreal accRowSpacing = (tableSize.height() - 1) * cellSpacing.height();
+ averageEdgeSize.setHeight((explicitContentHeight - accRowSpacing) / tableSize.height());
+ } else {
+ const qreal accRowSpacing = (loadedRows.count() - 1) * cellSpacing.height();
+ averageEdgeSize.setHeight((loadedTableOuterRect.height() - accRowSpacing) / loadedRows.count());
+ }
}
void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
@@ -710,9 +876,8 @@ void QQuickTableViewPrivate::forceLayout()
if (loadedItems.isEmpty())
return;
- columnRowPositionsInvalid = true;
clearEdgeSizeCache();
- RebuildOptions rebuildOptions = RebuildOption::None;
+ RebuildOptions rebuildOptions = RebuildOption::LayoutOnly;
// Go through all columns from first to last, find the columns that used
// to be hidden and not loaded, and check if they should become visible
@@ -751,16 +916,14 @@ void QQuickTableViewPrivate::forceLayout()
break;
}
- if (rebuildOptions)
- scheduleRebuildTable(rebuildOptions);
+ scheduleRebuildTable(rebuildOptions);
- if (polishing) {
+ auto rootView = rootSyncView();
+ const bool updated = rootView->d_func()->updateTableRecursive();
+ if (!updated) {
qWarning() << "TableView::forceLayout(): Cannot do an immediate re-layout during an ongoing layout!";
- q_func()->polish();
- return;
+ rootView->polish();
}
-
- updatePolish();
}
void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest()
@@ -1051,6 +1214,11 @@ qreal QQuickTableViewPrivate::getColumnLayoutWidth(int column)
if (explicitColumnWidth >= 0)
return explicitColumnWidth;
+ if (syncHorizontally) {
+ if (syncView->d_func()->loadedColumns.contains(column))
+ return syncView->d_func()->getColumnLayoutWidth(column);
+ }
+
// Iterate over the currently visible items in the column. The downside
// of doing that, is that the column width will then only be based on the implicit
// width of the currently loaded items (which can be different depending on which
@@ -1080,6 +1248,11 @@ qreal QQuickTableViewPrivate::getRowLayoutHeight(int row)
if (explicitRowHeight >= 0)
return explicitRowHeight;
+ if (syncVertically) {
+ if (syncView->d_func()->loadedRows.contains(row))
+ return syncView->d_func()->getRowLayoutHeight(row);
+ }
+
// Iterate over the currently visible items in the row. The downside
// of doing that, is that the row height will then only be based on the implicit
// height of the currently loaded items (which can be different depending on which
@@ -1109,6 +1282,13 @@ qreal QQuickTableViewPrivate::getColumnWidth(int column)
if (cachedColumnWidth.startIndex == column)
return cachedColumnWidth.size;
+ if (syncHorizontally)
+ return syncView->d_func()->getColumnWidth(column);
+
+ auto cw = columnWidths.size(column);
+ if (cw >= 0)
+ return cw;
+
if (columnWidthProvider.isUndefined())
return noExplicitColumnWidth;
@@ -1143,6 +1323,13 @@ qreal QQuickTableViewPrivate::getRowHeight(int row)
if (cachedRowHeight.startIndex == row)
return cachedRowHeight.size;
+ if (syncVertically)
+ return syncView->d_func()->getRowHeight(row);
+
+ auto rh = rowHeights.size(row);
+ if (rh >= 0)
+ return rh;
+
if (rowHeightProvider.isUndefined())
return noExplicitRowHeight;
@@ -1180,23 +1367,9 @@ bool QQuickTableViewPrivate::isRowHidden(int row)
return qFuzzyIsNull(getRowHeight(row));
}
-void QQuickTableViewPrivate::relayoutTable()
-{
- clearEdgeSizeCache();
- relayoutTableItems();
- syncLoadedTableRectFromLoadedTable();
- enforceTableAtOrigin();
- updateContentWidth();
- updateContentHeight();
- // Return back to updatePolish to loadAndUnloadVisibleEdges()
- // since the re-layout might have caused some edges to be pushed
- // out, while others might have been pushed in.
-}
-
void QQuickTableViewPrivate::relayoutTableItems()
{
qCDebug(lcTableViewDelegateLifecycle);
- columnRowPositionsInvalid = false;
qreal nextColumnX = loadedTableOuterRect.x();
qreal nextRowY = loadedTableOuterRect.y();
@@ -1378,20 +1551,7 @@ void QQuickTableViewPrivate::processLoadRequest()
if (rebuildState == RebuildState::Done) {
// Loading of this edge was not done as a part of a rebuild, but
// instead as an incremental build after e.g a flick.
- switch (loadRequest.edge()) {
- case Qt::LeftEdge:
- case Qt::TopEdge:
- enforceTableAtOrigin();
- break;
- case Qt::RightEdge:
- updateAverageEdgeSize();
- updateContentWidth();
- break;
- case Qt::BottomEdge:
- updateAverageEdgeSize();
- updateContentHeight();
- break;
- }
+ updateExtents();
drainReusePoolAfterLoadRequest();
}
@@ -1402,6 +1562,22 @@ void QQuickTableViewPrivate::processLoadRequest()
void QQuickTableViewPrivate::processRebuildTable()
{
+ Q_Q(QQuickTableView);
+
+ if (rebuildState == RebuildState::Begin) {
+ if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "begin rebuild:" << q;
+ if (rebuildOptions & RebuildOption::All)
+ qCDebug(lcTableViewDelegateLifecycle()) << "RebuildOption::All, options:" << rebuildOptions;
+ else if (rebuildOptions & RebuildOption::ViewportOnly)
+ qCDebug(lcTableViewDelegateLifecycle()) << "RebuildOption::ViewportOnly, options:" << rebuildOptions;
+ else if (rebuildOptions & RebuildOption::LayoutOnly)
+ qCDebug(lcTableViewDelegateLifecycle()) << "RebuildOption::LayoutOnly, options:" << rebuildOptions;
+ else
+ Q_TABLEVIEW_UNREACHABLE(rebuildOptions);
+ }
+ }
+
moveToNextRebuildState();
if (rebuildState == RebuildState::LoadInitalTable) {
@@ -1412,12 +1588,11 @@ void QQuickTableViewPrivate::processRebuildTable()
if (rebuildState == RebuildState::VerifyTable) {
if (loadedItems.isEmpty()) {
- qCDebug(lcTableViewDelegateLifecycle()) << "no items loaded, meaning empty model, all rows or columns hidden, or no delegate";
+ qCDebug(lcTableViewDelegateLifecycle()) << "no items loaded!";
rebuildState = RebuildState::Done;
+ } else if (!moveToNextRebuildState()) {
return;
}
- if (!moveToNextRebuildState())
- return;
}
if (rebuildState == RebuildState::LayoutTable) {
@@ -1457,6 +1632,7 @@ void QQuickTableViewPrivate::processRebuildTable()
}
Q_TABLEVIEW_ASSERT(rebuildState == RebuildState::Done, int(rebuildState));
+ qCDebug(lcTableViewDelegateLifecycle()) << "rebuild complete:" << q;
}
bool QQuickTableViewPrivate::moveToNextRebuildState()
@@ -1466,53 +1642,114 @@ bool QQuickTableViewPrivate::moveToNextRebuildState()
// that the current state is not yet done.
return false;
}
- rebuildState = RebuildState(int(rebuildState) + 1);
- qCDebug(lcTableViewDelegateLifecycle()) << int(rebuildState);
- return true;
-}
-QPoint QQuickTableViewPrivate::calculateNewTopLeft()
-{
- const int firstVisibleLeft = nextVisibleEdgeIndex(Qt::RightEdge, 0);
- const int firstVisibleTop = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
+ if (rebuildState == RebuildState::Begin
+ && rebuildOptions.testFlag(RebuildOption::LayoutOnly))
+ rebuildState = RebuildState::LayoutTable;
+ else
+ rebuildState = RebuildState(int(rebuildState) + 1);
- return QPoint(firstVisibleLeft, firstVisibleTop);
+ qCDebug(lcTableViewDelegateLifecycle()) << int(rebuildState);
+ return true;
}
-void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeft, QPointF &topLeftPos)
+void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeftCell, QPointF &topLeftPos)
{
if (tableSize.isEmpty()) {
- releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
- topLeft = QPoint(kEdgeIndexAtEnd, kEdgeIndexAtEnd);
+ // There is no cell that can be top left
+ topLeftCell.rx() = kEdgeIndexAtEnd;
+ topLeftCell.ry() = kEdgeIndexAtEnd;
return;
}
- if (rebuildOptions & RebuildOption::All) {
- qCDebug(lcTableViewDelegateLifecycle()) << "RebuildOption::All";
- releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
- topLeft = calculateNewTopLeft();
- } else if (rebuildOptions & RebuildOption::ViewportOnly) {
- qCDebug(lcTableViewDelegateLifecycle()) << "RebuildOption::ViewportOnly";
- releaseLoadedItems(reusableFlag);
+ if (syncHorizontally || syncVertically) {
+ const auto syncView_d = syncView->d_func();
- if (rebuildOptions & RebuildOption::CalculateNewTopLeftRow) {
- const int newRow = int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
- topLeft.ry() = qBound(0, newRow, tableSize.height() - 1);
- topLeftPos.ry() = topLeft.y() * (averageEdgeSize.height() + cellSpacing.height());
- } else {
- topLeft.ry() = qBound(0, topRow(), tableSize.height() - 1);
- topLeftPos.ry() = loadedTableOuterRect.topLeft().y();
+ if (syncView_d->loadedItems.isEmpty()) {
+ // The sync view contains no loaded items. This probably means
+ // that it has not been rebuilt yet. Which also means that
+ // we cannot rebuild anything before this happens.
+ topLeftCell.rx() = kEdgeIndexNotSet;
+ topLeftCell.ry() = kEdgeIndexNotSet;
+ return;
+ }
+
+ // Get sync view top left, and use that as our own top left (if possible)
+ const QPoint syncViewTopLeftCell(syncView_d->leftColumn(), syncView_d->topRow());
+ const auto syncViewTopLeftFxItem = syncView_d->loadedTableItem(syncViewTopLeftCell);
+ const QPointF syncViewTopLeftPos = syncViewTopLeftFxItem->geometry().topLeft();
+
+ if (syncHorizontally) {
+ topLeftCell.rx() = syncViewTopLeftCell.x();
+ topLeftPos.rx() = syncViewTopLeftPos.x();
+
+ if (topLeftCell.x() >= tableSize.width()) {
+ // Top left is outside our own model.
+ topLeftCell.rx() = kEdgeIndexAtEnd;
+ topLeftPos.rx() = kEdgeIndexAtEnd;
+ }
+ }
+
+ if (syncVertically) {
+ topLeftCell.ry() = syncViewTopLeftCell.y();
+ topLeftPos.ry() = syncViewTopLeftPos.y();
+
+ if (topLeftCell.y() >= tableSize.height()) {
+ // Top left is outside our own model.
+ topLeftCell.ry() = kEdgeIndexAtEnd;
+ topLeftPos.ry() = kEdgeIndexAtEnd;
+ }
}
- if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
+
+ if (syncHorizontally && syncVertically) {
+ // We have a valid top left, so we're done
+ return;
+ }
+ }
+
+ // Since we're not sync-ing both horizontal and vertical, calculate the missing
+ // dimention(s) ourself. If we rebuild all, we find the first visible top-left
+ // item starting from cell(0, 0). Otherwise, guesstimate which row or column that
+ // should be the new top-left given the geometry of the viewport.
+
+ if (!syncHorizontally) {
+ if (rebuildOptions & RebuildOption::All) {
+ // Find the first visible column from the beginning
+ topLeftCell.rx() = nextVisibleEdgeIndex(Qt::RightEdge, 0);
+ if (topLeftCell.x() == kEdgeIndexAtEnd) {
+ // No visible column found
+ return;
+ }
+ } else if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
+ // Guesstimate new top left
const int newColumn = int(viewportRect.x() / (averageEdgeSize.width() + cellSpacing.width()));
- topLeft.rx() = qBound(0, newColumn, tableSize.width() - 1);
- topLeftPos.rx() = topLeft.x() * (averageEdgeSize.width() + cellSpacing.width());
+ topLeftCell.rx() = qBound(0, newColumn, tableSize.width() - 1);
+ topLeftPos.rx() = topLeftCell.x() * (averageEdgeSize.width() + cellSpacing.width());
} else {
- topLeft.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
+ // Keep the current top left, unless it's outside model
+ topLeftCell.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
topLeftPos.rx() = loadedTableOuterRect.topLeft().x();
}
- } else {
- Q_TABLEVIEW_UNREACHABLE(rebuildOptions);
+ }
+
+ if (!syncVertically) {
+ if (rebuildOptions & RebuildOption::All) {
+ // Find the first visible row from the beginning
+ topLeftCell.ry() = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
+ if (topLeftCell.y() == kEdgeIndexAtEnd) {
+ // No visible row found
+ return;
+ }
+ } else if (rebuildOptions & RebuildOption::CalculateNewTopLeftRow) {
+ // Guesstimate new top left
+ const int newRow = int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
+ topLeftCell.ry() = qBound(0, newRow, tableSize.height() - 1);
+ topLeftPos.ry() = topLeftCell.y() * (averageEdgeSize.height() + cellSpacing.height());
+ } else {
+ // Keep the current top left, unless it's outside model
+ topLeftCell.ry() = qBound(0, topRow(), tableSize.height() - 1);
+ topLeftPos.ry() = loadedTableOuterRect.topLeft().y();
+ }
}
}
@@ -1524,41 +1761,91 @@ void QQuickTableViewPrivate::beginRebuildTable()
QPointF topLeftPos;
calculateTopLeft(topLeft, topLeftPos);
+ if (rebuildOptions & RebuildOption::All)
+ releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
+ else if (rebuildOptions & RebuildOption::ViewportOnly)
+ releaseLoadedItems(reusableFlag);
+
+ if (rebuildOptions & RebuildOption::All) {
+ origin = QPointF(0, 0);
+ endExtent = QSizeF(0, 0);
+ hData.markExtentsDirty();
+ vData.markExtentsDirty();
+ updateBeginningEnd();
+ }
+
loadedColumns.clear();
loadedRows.clear();
loadedTableOuterRect = QRect();
loadedTableInnerRect = QRect();
- columnRowPositionsInvalid = false;
clearEdgeSizeCache();
- if (topLeft.x() == kEdgeIndexAtEnd || topLeft.y() == kEdgeIndexAtEnd) {
- // No visible columns or rows, so nothing to load
+ if (syncHorizontally) {
+ setLocalViewportX(syncView->contentX());
+ viewportRect.moveLeft(syncView->d_func()->viewportRect.left());
+ }
+
+ if (syncVertically) {
+ setLocalViewportY(syncView->contentY());
+ viewportRect.moveTop(syncView->d_func()->viewportRect.top());
+ }
+
+ if (!model) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "no model found, leaving table empty";
return;
}
- loadInitialTopLeftItem(topLeft, topLeftPos);
- loadAndUnloadVisibleEdges();
-}
+ if (model->count() == 0) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "empty model found, leaving table empty";
+ return;
+ }
-void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
-{
- relayoutTable();
- updateAverageEdgeSize();
- updateContentWidth();
- updateContentHeight();
-}
+ if (tableModel && !tableModel->delegate()) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "no delegate found, leaving table empty";
+ return;
+ }
-void QQuickTableViewPrivate::loadInitialTopLeftItem(const QPoint &cell, const QPointF &pos)
-{
- Q_TABLEVIEW_ASSERT(loadedItems.isEmpty(), "");
+ if (topLeft.x() == kEdgeIndexAtEnd || topLeft.y() == kEdgeIndexAtEnd) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "no visible row or column found, leaving table empty";
+ return;
+ }
- if (tableModel && !tableModel->delegate())
+ if (topLeft.x() == kEdgeIndexNotSet || topLeft.y() == kEdgeIndexNotSet) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "could not resolve top-left item, leaving table empty";
return;
+ }
// Load top-left item. After loaded, loadItemsInsideRect() will take
// care of filling out the rest of the table.
- loadRequest.begin(cell, pos, QQmlIncubator::AsynchronousIfNested);
+ loadRequest.begin(topLeft, topLeftPos, QQmlIncubator::AsynchronousIfNested);
processLoadRequest();
+ loadAndUnloadVisibleEdges();
+}
+
+void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
+{
+ clearEdgeSizeCache();
+ relayoutTableItems();
+ syncLoadedTableRectFromLoadedTable();
+
+ if (syncView || rebuildOptions.testFlag(RebuildOption::All)) {
+ // We try to limit how often we update the content size. The main reason is that is has a
+ // tendency to cause flicker in the viewport if it happens while flicking. But another just
+ // as valid reason is that we actually never really know what the size of the full table will
+ // ever be. Even if e.g spacing changes, and we normally would assume that the size of the table
+ // would increase accordingly, the model might also at some point have removed/hidden/resized
+ // rows/columns outside the viewport. This would also affect the size, but since we don't load
+ // rows or columns outside the viewport, this information is ignored. And even if we did, we
+ // might also have been fast-flicked to a new location at some point, and started a new rebuild
+ // there based on a new guesstimated top-left cell. Either way, changing the content size
+ // based on the currently visible row/columns/spacing can be really off. So instead of pretending
+ // that we know what the actual size of the table is, we just keep the first guesstimate.
+ updateAverageEdgeSize();
+ updateContentWidth();
+ updateContentHeight();
+ }
+
+ updateExtents();
}
void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
@@ -1573,8 +1860,6 @@ void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
unloadItem(QPoint(column, r.key()));
loadedColumns.remove(column);
syncLoadedTableRectFromLoadedTable();
- updateAverageEdgeSize();
- updateContentWidth();
break; }
case Qt::TopEdge:
case Qt::BottomEdge: {
@@ -1583,8 +1868,6 @@ void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
unloadItem(QPoint(c.key(), row));
loadedRows.remove(row);
syncLoadedTableRectFromLoadedTable();
- updateAverageEdgeSize();
- updateContentHeight();
break; }
}
@@ -1697,21 +1980,63 @@ void QQuickTableViewPrivate::scheduleRebuildTable(RebuildOptions options) {
return;
}
- rebuildScheduled = true;
scheduledRebuildOptions |= options;
q_func()->polish();
}
-void QQuickTableViewPrivate::invalidateColumnRowPositions() {
- columnRowPositionsInvalid = true;
- q_func()->polish();
+QQuickTableView *QQuickTableViewPrivate::rootSyncView() const
+{
+ QQuickTableView *root = const_cast<QQuickTableView *>(q_func());
+ while (QQuickTableView *view = root->d_func()->syncView)
+ root = view;
+ return root;
}
void QQuickTableViewPrivate::updatePolish()
{
+ // We always start updating from the top of the syncView tree, since
+ // the layout of a syncView child will depend on the layout of the syncView.
+ // E.g when a new column is flicked in, the syncView should load and layout
+ // the column first, before any syncChildren gets a chance to do the same.
+ Q_TABLEVIEW_ASSERT(!polishing, "recursive updatePolish() calls are not allowed!");
+ rootSyncView()->d_func()->updateTableRecursive();
+}
+
+bool QQuickTableViewPrivate::updateTableRecursive()
+{
+ if (polishing) {
+ // We're already updating the Table in this view, so
+ // we cannot continue. Signal this back by returning false.
+ // The caller can then choose to call "polish()" instead, to
+ // do the update later.
+ return false;
+ }
+
+ const bool updateComplete = updateTable();
+ if (!updateComplete)
+ return false;
+
+ for (auto syncChild : qAsConst(syncChildren)) {
+ auto syncChild_d = syncChild->d_func();
+ syncChild_d->scheduledRebuildOptions |= rebuildOptions;
+
+ const bool descendantUpdateComplete = syncChild_d->updateTableRecursive();
+ if (!descendantUpdateComplete)
+ return false;
+ }
+
+ rebuildOptions = RebuildOption::None;
+
+ return true;
+}
+
+bool QQuickTableViewPrivate::updateTable()
+{
// Whenever something changes, e.g viewport moves, spacing is set to a
// new value, model changes etc, this function will end up being called. Here
// we check what needs to be done, and load/unload cells accordingly.
+ // If we cannot complete the update (because we need to wait for an item
+ // to load async), we return false.
Q_TABLEVIEW_ASSERT(!polishing, "recursive updatePolish() calls are not allowed!");
QBoolBlocker polishGuard(polishing, true);
@@ -1721,38 +2046,42 @@ void QQuickTableViewPrivate::updatePolish()
// as an atomic operation, which means that we don't continue doing anything else until all
// items have been received and laid out. Note that updatePolish is then called once more
// after the loadRequest has completed to handle anything that might have occurred in-between.
- return;
+ return false;
}
if (rebuildState != RebuildState::Done) {
processRebuildTable();
- return;
+ return rebuildState == RebuildState::Done;
}
syncWithPendingChanges();
if (rebuildState == RebuildState::Begin) {
processRebuildTable();
- return;
+ return rebuildState == RebuildState::Done;
}
if (loadedItems.isEmpty())
- return;
-
- if (columnRowPositionsInvalid) {
- relayoutTable();
- updateAverageEdgeSize();
- updateContentWidth();
- updateContentHeight();
- }
+ return !loadRequest.isActive();
loadAndUnloadVisibleEdges();
+
+ return !loadRequest.isActive();
}
void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent)
{
- if (rebuildScheduled || rebuildState != RebuildState::Done)
+ if (inUpdateContentSize) {
+ // We update the content size dynamically as we load and unload edges.
+ // Unfortunately, this also triggers a call to this function. The base
+ // implementation will do things like start a momentum animation or move
+ // the content view somewhere else, which causes glitches. This can
+ // especially happen if flicking on one of the syncView children, which triggers
+ // an update to our content size. In that case, the base implementation don't know
+ // that the view is being indirectly dragged, and will therefore do strange things as
+ // it tries to 'fixup' the geometry. So we use a guard to prevent this from happening.
return;
+ }
QQuickFlickablePrivate::fixup(data, minExtent, maxExtent);
}
@@ -1836,25 +2165,32 @@ void QQuickTableViewPrivate::syncWithPendingChanges()
// such assignments into effect until we're in a state that allows it.
Q_Q(QQuickTableView);
viewportRect = QRectF(q->contentX(), q->contentY(), q->width(), q->height());
- syncRebuildOptions();
+
syncModel();
syncDelegate();
+ syncSyncView();
+
+ syncRebuildOptions();
}
void QQuickTableViewPrivate::syncRebuildOptions()
{
- if (!rebuildScheduled)
+ if (!scheduledRebuildOptions)
return;
rebuildState = RebuildState::Begin;
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.
+ if (loadedItems.isEmpty())
rebuildOptions.setFlag(RebuildOption::All);
+
+ // Some options are exclusive:
+ if (rebuildOptions.testFlag(RebuildOption::All)) {
+ rebuildOptions.setFlag(RebuildOption::ViewportOnly, false);
+ rebuildOptions.setFlag(RebuildOption::LayoutOnly, false);
+ } else if (rebuildOptions.testFlag(RebuildOption::ViewportOnly)) {
+ rebuildOptions.setFlag(RebuildOption::LayoutOnly, false);
}
}
@@ -1899,6 +2235,60 @@ void QQuickTableViewPrivate::syncModel()
connectToModel();
}
+void QQuickTableViewPrivate::syncSyncView()
+{
+ Q_Q(QQuickTableView);
+
+ if (assignedSyncView != syncView) {
+ if (syncView)
+ syncView->d_func()->syncChildren.removeOne(q);
+
+ if (assignedSyncView) {
+ QQuickTableView *view = assignedSyncView;
+
+ while (view) {
+ if (view == q) {
+ if (!layoutWarningIssued) {
+ layoutWarningIssued = true;
+ qmlWarning(q) << "TableView: recursive syncView connection detected!";
+ }
+ syncView = nullptr;
+ return;
+ }
+ view = view->d_func()->syncView;
+ }
+
+ assignedSyncView->d_func()->syncChildren.append(q);
+ scheduledRebuildOptions |= RebuildOption::ViewportOnly;
+ }
+
+ syncView = assignedSyncView;
+ }
+
+ syncHorizontally = syncView && assignedSyncDirection & Qt::Horizontal;
+ syncVertically = syncView && assignedSyncDirection & Qt::Vertical;
+
+ if (syncHorizontally)
+ q->setColumnSpacing(syncView->columnSpacing());
+ if (syncVertically)
+ q->setRowSpacing(syncView->rowSpacing());
+
+ if (syncView && loadedItems.isEmpty() && !tableSize.isEmpty()) {
+ // When we have a syncView, we can sometimes temporarily end up with no loaded items.
+ // This can happen if the syncView has a model with more rows or columns than us, in
+ // which case the viewport can end up in a place where we have no rows or columns to
+ // show. In that case, check now if the viewport has been flicked back again, and
+ // that we can rebuild the table with a visible top-left cell.
+ const auto syncView_d = syncView->d_func();
+ if (!syncView_d->loadedItems.isEmpty()) {
+ if (syncHorizontally && syncView_d->leftColumn() <= tableSize.width() - 1)
+ scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
+ else if (syncVertically && syncView_d->topRow() <= tableSize.height() - 1)
+ scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
+ }
+ }
+}
+
void QQuickTableViewPrivate::connectToModel()
{
Q_TABLEVIEW_ASSERT(model, "");
@@ -2028,6 +2418,83 @@ void QQuickTableViewPrivate::modelResetCallback()
scheduleRebuildTable(RebuildOption::All);
}
+void QQuickTableViewPrivate::scheduleRebuildIfFastFlick()
+{
+ Q_Q(QQuickTableView);
+ // If the viewport has moved more than one page vertically or horizontally, we switch
+ // strategy from refilling edges around the current table to instead rebuild the table
+ // from scratch inside the new viewport. This will greatly improve performance when flicking
+ // a long distance in one go, which can easily happen when dragging on scrollbars.
+
+ // Check the viewport moved more than one page vertically
+ if (!viewportRect.intersects(QRectF(viewportRect.x(), q->contentY(), 1, q->height()))) {
+ scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
+ scheduledRebuildOptions |= RebuildOption::ViewportOnly;
+ }
+
+ // Check the viewport moved more than one page horizontally
+ if (!viewportRect.intersects(QRectF(q->contentX(), viewportRect.y(), q->width(), 1))) {
+ scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
+ scheduledRebuildOptions |= RebuildOption::ViewportOnly;
+ }
+}
+
+void QQuickTableViewPrivate::setLocalViewportX(qreal contentX)
+{
+ // Set the new viewport position if changed, but don't trigger any
+ // rebuilds or updates. We use this function internally to distinguish
+ // external flicking from internal sync-ing of the content view.
+ Q_Q(QQuickTableView);
+ QBoolBlocker blocker(inSetLocalViewportPos, true);
+
+ if (qFuzzyCompare(contentX, q->contentX()))
+ return;
+
+ q->setContentX(contentX);
+}
+
+void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
+{
+ // Set the new viewport position if changed, but don't trigger any
+ // rebuilds or updates. We use this function internally to distinguish
+ // external flicking from internal sync-ing of the content view.
+ Q_Q(QQuickTableView);
+ QBoolBlocker blocker(inSetLocalViewportPos, true);
+
+ if (qFuzzyCompare(contentY, q->contentY()))
+ return;
+
+ q->setContentY(contentY);
+}
+
+void QQuickTableViewPrivate::syncViewportPosRecursive()
+{
+ Q_Q(QQuickTableView);
+ QBoolBlocker recursionGuard(inSyncViewportPosRecursive, true);
+
+ if (syncView) {
+ auto syncView_d = syncView->d_func();
+ if (!syncView_d->inSyncViewportPosRecursive) {
+ if (syncHorizontally)
+ syncView_d->setLocalViewportX(q->contentX());
+ if (syncVertically)
+ syncView_d->setLocalViewportY(q->contentY());
+ syncView_d->syncViewportPosRecursive();
+ }
+ }
+
+ for (auto syncChild : qAsConst(syncChildren)) {
+ auto syncChild_d = syncChild->d_func();
+ if (!syncChild_d->inSyncViewportPosRecursive) {
+ if (syncChild_d->syncHorizontally)
+ syncChild_d->setLocalViewportX(q->contentX());
+ if (syncChild_d->syncVertically)
+ syncChild_d->setLocalViewportY(q->contentY());
+ syncChild_d->syncViewportPosRecursive();
+ }
+ }
+}
+
QQuickTableView::QQuickTableView(QQuickItem *parent)
: QQuickFlickable(*(new QQuickTableViewPrivate), parent)
{
@@ -2044,6 +2511,26 @@ QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent)
setFlag(QQuickItem::ItemIsFocusScope);
}
+qreal QQuickTableView::minXExtent() const
+{
+ return QQuickFlickable::minXExtent() - d_func()->origin.x();
+}
+
+qreal QQuickTableView::maxXExtent() const
+{
+ return QQuickFlickable::maxXExtent() - d_func()->endExtent.width();
+}
+
+qreal QQuickTableView::minYExtent() const
+{
+ return QQuickFlickable::minYExtent() - d_func()->origin.y();
+}
+
+qreal QQuickTableView::maxYExtent() const
+{
+ return QQuickFlickable::maxYExtent() - d_func()->endExtent.height();
+}
+
int QQuickTableView::rows() const
{
return d_func()->tableSize.height();
@@ -2068,7 +2555,7 @@ void QQuickTableView::setRowSpacing(qreal spacing)
return;
d->cellSpacing.setHeight(spacing);
- d->invalidateColumnRowPositions();
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly);
emit rowSpacingChanged();
}
@@ -2086,7 +2573,7 @@ void QQuickTableView::setColumnSpacing(qreal spacing)
return;
d->cellSpacing.setWidth(spacing);
- d->invalidateColumnRowPositions();
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly);
emit columnSpacingChanged();
}
@@ -2095,7 +2582,7 @@ QJSValue QQuickTableView::rowHeightProvider() const
return d_func()->rowHeightProvider;
}
-void QQuickTableView::setRowHeightProvider(QJSValue provider)
+void QQuickTableView::setRowHeightProvider(const QJSValue &provider)
{
Q_D(QQuickTableView);
if (provider.strictlyEquals(d->rowHeightProvider))
@@ -2111,7 +2598,7 @@ QJSValue QQuickTableView::columnWidthProvider() const
return d_func()->columnWidthProvider;
}
-void QQuickTableView::setColumnWidthProvider(QJSValue provider)
+void QQuickTableView::setColumnWidthProvider(const QJSValue &provider)
{
Q_D(QQuickTableView);
if (provider.strictlyEquals(d->columnWidthProvider))
@@ -2191,6 +2678,41 @@ void QQuickTableView::setContentHeight(qreal height)
QQuickFlickable::setContentHeight(height);
}
+QQuickTableView *QQuickTableView::syncView() const
+{
+ return d_func()->assignedSyncView;
+}
+
+void QQuickTableView::setSyncView(QQuickTableView *view)
+{
+ Q_D(QQuickTableView);
+ if (d->assignedSyncView == view)
+ return;
+
+ d->assignedSyncView = view;
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
+
+ emit syncViewChanged();
+}
+
+Qt::Orientations QQuickTableView::syncDirection() const
+{
+ return d_func()->assignedSyncDirection;
+}
+
+void QQuickTableView::setSyncDirection(Qt::Orientations direction)
+{
+ Q_D(QQuickTableView);
+ if (d->assignedSyncDirection == direction)
+ return;
+
+ d->assignedSyncDirection = direction;
+ if (d->assignedSyncView)
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
+
+ emit syncDirectionChanged();
+}
+
void QQuickTableView::forceLayout()
{
d_func()->forceLayout();
@@ -2218,45 +2740,42 @@ void QQuickTableView::geometryChanged(const QRectF &newGeometry, const QRectF &o
void QQuickTableView::viewportMoved(Qt::Orientations orientation)
{
Q_D(QQuickTableView);
+
+ // If the new viewport position was set from the setLocalViewportXY()
+ // functions, we just update the position silently and return. Otherwise, if
+ // the viewport was flicked by the user, or some other control, we
+ // recursively sync all the views in the hierarchy to the same position.
QQuickFlickable::viewportMoved(orientation);
+ if (d->inSetLocalViewportPos)
+ return;
- QQuickTableViewPrivate::RebuildOptions options = QQuickTableViewPrivate::RebuildOption::None;
+ // Move all views in the syncView hierarchy to the same contentX/Y.
+ // We need to start from this view (and not the root syncView) to
+ // ensure that we respect all the individual syncDirection flags
+ // between the individual views in the hierarchy.
+ d->syncViewportPosRecursive();
- // Check the viewport moved more than one page vertically
- if (!d->viewportRect.intersects(QRectF(d->viewportRect.x(), contentY(), 1, height())))
- options |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
- // Check the viewport moved more than one page horizontally
- if (!d->viewportRect.intersects(QRectF(contentX(), d->viewportRect.y(), width(), 1)))
- options |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
-
- if (options) {
- // When the viewport has moved more than one page vertically or horizontally, we switch
- // strategy from refilling edges around the current table to instead rebuild the table
- // from scratch inside the new viewport. This will greatly improve performance when flicking
- // a long distance in one go, which can easily happen when dragging on scrollbars.
- options |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
- d->scheduleRebuildTable(options);
- }
-
- if (d->rebuildScheduled) {
- // No reason to do anything, since we're about to rebuild the whole table anyway.
- // Besides, calling updatePolish, which will start the rebuild, can easily cause
- // binding loops to happen since we usually end up modifying the geometry of the
- // viewport (contentItem) as well.
- return;
- }
+ auto rootView = d->rootSyncView();
+ auto rootView_d = rootView->d_func();
- // Calling polish() will schedule a polish event. But while the user is flicking, several
- // mouse events will be handled before we get an updatePolish() call. And the updatePolish()
- // call will only see the last mouse position. This results in a stuttering flick experience
- // (especially on windows). We improve on this by calling updatePolish() directly. But this
- // has the pitfall that we open up for recursive callbacks. E.g while inside updatePolish(), we
- // load/unload items, and emit signals. The application can listen to those signals and set a
- // new contentX/Y on the flickable. So we need to guard for this, to avoid unexpected behavior.
- if (d->polishing)
- polish();
- else
- d->updatePolish();
+ rootView_d->scheduleRebuildIfFastFlick();
+
+ if (!rootView_d->polishScheduled) {
+ if (rootView_d->scheduledRebuildOptions) {
+ // When we need to rebuild, collecting several viewport
+ // moves and do a single polish gives a quicker UI.
+ rootView->polish();
+ } else {
+ // Updating the table right away when flicking
+ // slowly gives a smoother experience.
+ const bool updated = rootView->d_func()->updateTableRecursive();
+ if (!updated) {
+ // One, or more, of the views are already in an
+ // update, so we need to wait a cycle.
+ rootView->polish();
+ }
+ }
+ }
}
void QQuickTableViewPrivate::_q_componentFinalized()
@@ -2292,6 +2811,71 @@ void QQuickTableView::componentComplete()
d_func()->registerCallbackWhenBindingsAreEvaluated();
}
+class QObjectPrivate;
+class QQuickTableSectionSizeProviderPrivate : public QObjectPrivate {
+public:
+ QQuickTableSectionSizeProviderPrivate();
+ ~QQuickTableSectionSizeProviderPrivate();
+ QHash<int, qreal> hash;
+};
+
+QQuickTableSectionSizeProvider::QQuickTableSectionSizeProvider(QObject *parent)
+ : QObject (*(new QQuickTableSectionSizeProviderPrivate), parent)
+{
+}
+
+void QQuickTableSectionSizeProvider::setSize(int section, qreal size)
+{
+ Q_D(QQuickTableSectionSizeProvider);
+ if (section < 0 || size < 0) {
+ qmlWarning(this) << "setSize: section or size less than zero";
+ return;
+ }
+ if (qFuzzyCompare(QQuickTableSectionSizeProvider::size(section), size))
+ return;
+ d->hash.insert(section, size);
+ emit sizeChanged();
+}
+
+// return -1.0 if no valid explicit size retrieved
+qreal QQuickTableSectionSizeProvider::size(int section)
+{
+ Q_D(QQuickTableSectionSizeProvider);
+ auto it = d->hash.find(section);
+ if (it != d->hash.end())
+ return *it;
+ return -1.0;
+}
+
+// return true if section is valid
+bool QQuickTableSectionSizeProvider::resetSize(int section)
+{
+ Q_D(QQuickTableSectionSizeProvider);
+ if (d->hash.empty())
+ return false;
+
+ auto ret = d->hash.remove(section);
+ if (ret)
+ emit sizeChanged();
+ return ret;
+}
+
+void QQuickTableSectionSizeProvider::resetAll()
+{
+ Q_D(QQuickTableSectionSizeProvider);
+ d->hash.clear();
+ emit sizeChanged();
+}
+
+QQuickTableSectionSizeProviderPrivate::QQuickTableSectionSizeProviderPrivate()
+ : QObjectPrivate()
+{
+}
+
+QQuickTableSectionSizeProviderPrivate::~QQuickTableSectionSizeProviderPrivate()
+{
+
+}
#include "moc_qquicktableview_p.cpp"
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
index f32c71b983..a5f727d7a4 100644
--- a/src/quick/items/qquicktableview_p.h
+++ b/src/quick/items/qquicktableview_p.h
@@ -79,6 +79,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTableView : public QQuickFlickable
Q_PROPERTY(bool reuseItems READ reuseItems WRITE setReuseItems NOTIFY reuseItemsChanged)
Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged)
Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged)
+ Q_PROPERTY(QQuickTableView *syncView READ syncView WRITE setSyncView NOTIFY syncViewChanged REVISION 14)
+ Q_PROPERTY(Qt::Orientations syncDirection READ syncDirection WRITE setSyncDirection NOTIFY syncDirectionChanged REVISION 14)
public:
QQuickTableView(QQuickItem *parent = nullptr);
@@ -93,10 +95,10 @@ public:
void setColumnSpacing(qreal spacing);
QJSValue rowHeightProvider() const;
- void setRowHeightProvider(QJSValue provider);
+ void setRowHeightProvider(const QJSValue &provider);
QJSValue columnWidthProvider() const;
- void setColumnWidthProvider(QJSValue provider);
+ void setColumnWidthProvider(const QJSValue &provider);
virtual QVariant model() const;
virtual void setModel(const QVariant &newModel);
@@ -110,6 +112,12 @@ public:
void setContentWidth(qreal width);
void setContentHeight(qreal height);
+ QQuickTableView *syncView() const;
+ void setSyncView(QQuickTableView *view);
+
+ Qt::Orientations syncDirection() const;
+ void setSyncDirection(Qt::Orientations direction);
+
Q_INVOKABLE void forceLayout();
static QQuickTableViewAttached *qmlAttachedProperties(QObject *);
@@ -124,6 +132,8 @@ Q_SIGNALS:
void modelChanged();
void delegateChanged();
void reuseItemsChanged();
+ Q_REVISION(14) void syncViewChanged();
+ Q_REVISION(14) void syncDirectionChanged();
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
@@ -137,6 +147,11 @@ private:
Q_DISABLE_COPY(QQuickTableView)
Q_DECLARE_PRIVATE(QQuickTableView)
+ qreal minXExtent() const override;
+ qreal maxXExtent() const override;
+ qreal minYExtent() const override;
+ qreal maxYExtent() const override;
+
Q_PRIVATE_SLOT(d_func(), void _q_componentFinalized())
};
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index f2fef0d774..b66ac66dec 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -54,9 +54,9 @@
#include "qquicktableview_p.h"
#include <QtCore/qtimer.h>
-#include <QtQml/private/qqmltableinstancemodel_p.h>
+#include <QtQmlModels/private/qqmltableinstancemodel_p.h>
#include <QtQml/private/qqmlincubator_p.h>
-#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQmlModels/private/qqmlchangeset_p.h>
#include <QtQml/qqmlinfo.h>
#include <QtQuick/private/qquickflickable_p_p.h>
@@ -70,6 +70,25 @@ static const qreal kDefaultRowHeight = 50;
static const qreal kDefaultColumnWidth = 50;
class FxTableItem;
+class QQuickTableSectionSizeProviderPrivate;
+
+class Q_QUICK_PRIVATE_EXPORT QQuickTableSectionSizeProvider : public QObject {
+ Q_OBJECT
+
+public:
+ QQuickTableSectionSizeProvider(QObject *parent=nullptr);
+ void setSize(int section, qreal size);
+ qreal size(int section);
+ bool resetSize(int section);
+ void resetAll();
+
+Q_SIGNALS:
+ void sizeChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickTableSectionSizeProvider)
+ Q_DECLARE_PRIVATE(QQuickTableSectionSizeProvider)
+};
class Q_QML_AUTOTEST_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate
{
@@ -188,10 +207,11 @@ public:
enum class RebuildOption {
None = 0,
- ViewportOnly = 0x1,
- CalculateNewTopLeftRow = 0x2,
- CalculateNewTopLeftColumn = 0x4,
- All = 0x8,
+ LayoutOnly = 0x1,
+ ViewportOnly = 0x2,
+ CalculateNewTopLeftRow = 0x4,
+ CalculateNewTopLeftColumn = 0x8,
+ All = 0x10,
};
Q_DECLARE_FLAGS(RebuildOptions, RebuildOption)
@@ -231,6 +251,9 @@ public:
QRectF loadedTableOuterRect;
QRectF loadedTableInnerRect;
+ QPointF origin = QPointF(0, 0);
+ QSizeF endExtent = QSizeF(0, 0);
+
QRectF viewportRect = QRectF(0, 0, -1, -1);
QSize tableSize;
@@ -246,13 +269,18 @@ public:
QQmlTableInstanceModel::ReusableFlag reusableFlag = QQmlTableInstanceModel::Reusable;
bool blockItemCreatedCallback = false;
- bool columnRowPositionsInvalid = false;
bool layoutWarningIssued = false;
bool polishing = false;
- bool rebuildScheduled = true;
+ bool syncVertically = false;
+ bool syncHorizontally = false;
+ bool inSetLocalViewportPos = false;
+ bool inSyncViewportPosRecursive = false;
+ bool inUpdateContentSize = false;
QJSValue rowHeightProvider;
QJSValue columnWidthProvider;
+ QQuickTableSectionSizeProvider rowHeights;
+ QQuickTableSectionSizeProvider columnWidths;
EdgeRange cachedNextVisibleEdgeIndex[4];
EdgeRange cachedColumnWidth;
@@ -272,6 +300,11 @@ public:
QSizeF averageEdgeSize;
+ QPointer<QQuickTableView> assignedSyncView;
+ QPointer<QQuickTableView> syncView;
+ QList<QPointer<QQuickTableView> > syncChildren;
+ Qt::Orientations assignedSyncDirection = Qt::Horizontal | Qt::Vertical;
+
const static QPoint kLeft;
const static QPoint kRight;
const static QPoint kUp;
@@ -304,7 +337,10 @@ public:
inline int leftColumn() const { return loadedColumns.firstKey(); }
inline int rightColumn() const { return loadedColumns.lastKey(); }
- void relayoutTable();
+ QQuickTableView *rootSyncView() const;
+
+ bool updateTableRecursive();
+ bool updateTable();
void relayoutTableItems();
void layoutVerticalEdge(Qt::Edge tableEdge);
@@ -317,7 +353,7 @@ public:
void updateAverageEdgeSize();
void forceLayout();
- void enforceTableAtOrigin();
+ void updateExtents();
void syncLoadedTableRectFromLoadedTable();
void syncLoadedTableFromLoadRequest();
@@ -342,7 +378,6 @@ public:
void releaseLoadedItems(QQmlTableInstanceModel::ReusableFlag reusableFlag);
void unloadItem(const QPoint &cell);
- void loadInitialTopLeftItem(const QPoint &cell, const QPointF &pos);
void loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode);
void unloadEdge(Qt::Edge edge);
void loadAndUnloadVisibleEdges();
@@ -351,13 +386,11 @@ public:
void processRebuildTable();
bool moveToNextRebuildState();
- QPoint calculateNewTopLeft();
void calculateTopLeft(QPoint &topLeft, QPointF &topLeftPos);
void beginRebuildTable();
void layoutAfterLoadingInitialTable();
void scheduleRebuildTable(QQuickTableViewPrivate::RebuildOptions options);
- void invalidateColumnRowPositions();
int resolveImportVersion();
void createWrapperModel();
@@ -372,6 +405,7 @@ public:
inline void syncDelegate();
inline void syncModel();
inline void syncRebuildOptions();
+ inline void syncSyncView();
void connectToModel();
void disconnectFromModel();
@@ -385,6 +419,11 @@ public:
void layoutChangedCallback(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
void modelResetCallback();
+ void scheduleRebuildIfFastFlick();
+ void setLocalViewportX(qreal contentX);
+ void setLocalViewportY(qreal contentY);
+ void syncViewportPosRecursive();
+
void _q_componentFinalized();
void registerCallbackWhenBindingsAreEvaluated();
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 6d343a91ce..ae849aeb4b 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -1653,13 +1653,17 @@ void QQuickText::setText(const QString &n)
if (d->text == n)
return;
- d->richText = d->format == RichText;
+ d->markdownText = d->format == MarkdownText;
+ d->richText = d->format == RichText || d->markdownText;
d->styledText = d->format == StyledText || (d->format == AutoText && Qt::mightBeRichText(n));
d->text = n;
if (isComponentComplete()) {
if (d->richText) {
d->ensureDoc();
- d->extra->doc->setText(n);
+ if (d->markdownText)
+ d->extra->doc->setMarkdownText(n);
+ else
+ d->extra->doc->setText(n);
d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
} else {
d->clearFormats();
@@ -2146,7 +2150,8 @@ void QQuickText::setTextFormat(TextFormat format)
return;
d->format = format;
bool wasRich = d->richText;
- d->richText = format == RichText;
+ d->markdownText = format == MarkdownText;
+ d->richText = format == RichText || d->markdownText;
d->styledText = format == StyledText || (format == AutoText && Qt::mightBeRichText(d->text));
if (isComponentComplete()) {
@@ -2687,7 +2692,10 @@ void QQuickText::componentComplete()
if (d->updateOnComponentComplete) {
if (d->richText) {
d->ensureDoc();
- d->extra->doc->setText(d->text);
+ if (d->markdownText)
+ d->extra->doc->setMarkdownText(d->text);
+ else
+ d->extra->doc->setText(d->text);
d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
} else {
d->rightToLeftText = d->text.isRightToLeft();
diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h
index 1af60051fb..45f387cb12 100644
--- a/src/quick/items/qquicktext_p.h
+++ b/src/quick/items/qquicktext_p.h
@@ -121,6 +121,7 @@ public:
Q_ENUM(TextStyle)
enum TextFormat { PlainText = Qt::PlainText,
RichText = Qt::RichText,
+ MarkdownText = Qt::MarkdownText,
AutoText = Qt::AutoText,
StyledText = 4 };
Q_ENUM(TextFormat)
diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h
index efa45e0958..c01998b100 100644
--- a/src/quick/items/qquicktext_p_p.h
+++ b/src/quick/items/qquicktext_p_p.h
@@ -161,6 +161,7 @@ public:
bool updateOnComponentComplete:1;
bool richText:1;
bool styledText:1;
+ bool markdownText:1;
bool widthExceeded:1;
bool heightExceeded:1;
bool internalWidthUpdate:1;
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 5c55f4f43f..3c392be751 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -113,6 +113,7 @@ QQuickTextControlPrivate::QQuickTextControlPrivate()
wordSelectionEnabled(false),
hasImState(false),
cursorRectangleChanged(false),
+ hoveredMarker(false),
lastSelectionStart(-1),
lastSelectionEnd(-1)
{}
@@ -321,6 +322,9 @@ void QQuickTextControlPrivate::setContent(Qt::TextFormat format, const QString &
formatCursor.select(QTextCursor::Document);
formatCursor.setCharFormat(charFormatForInsertion);
formatCursor.endEditBlock();
+ } else if (format == Qt::MarkdownText) {
+ doc->setBaseUrl(doc->baseUrl().adjusted(QUrl::RemoveFilename));
+ doc->setMarkdown(text);
} else {
#if QT_CONFIG(texthtmlparser)
doc->setHtml(text);
@@ -799,6 +803,12 @@ void QQuickTextControl::setPlainText(const QString &text)
d->setContent(Qt::PlainText, text);
}
+void QQuickTextControl::setMarkdownText(const QString &text)
+{
+ Q_D(QQuickTextControl);
+ d->setContent(Qt::MarkdownText, text);
+}
+
void QQuickTextControl::setHtml(const QString &text)
{
Q_D(QQuickTextControl);
@@ -1025,6 +1035,8 @@ void QQuickTextControlPrivate::mousePressEvent(QMouseEvent *e, const QPointF &po
cursor.clearSelection();
}
}
+ if (interactionFlags & Qt::TextEditable)
+ blockWithMarkerUnderMousePress = q->blockWithMarkerAt(pos);
if (e->button() & Qt::MiddleButton) {
return;
} else if (!(e->button() & Qt::LeftButton)) {
@@ -1196,6 +1208,16 @@ void QQuickTextControlPrivate::mouseReleaseEvent(QMouseEvent *e, const QPointF &
q->updateCursorRectangle(true);
}
+ if ((interactionFlags & Qt::TextEditable) && (e->button() & Qt::LeftButton) && blockWithMarkerUnderMousePress.isValid()) {
+ QTextBlock block = q->blockWithMarkerAt(pos);
+ if (block == blockWithMarkerUnderMousePress) {
+ auto fmt = block.blockFormat();
+ fmt.setMarker(fmt.marker() == QTextBlockFormat::MarkerType::Unchecked ?
+ QTextBlockFormat::MarkerType::Checked : QTextBlockFormat::MarkerType::Unchecked);
+ cursor.setBlockFormat(fmt);
+ }
+ }
+
if (interactionFlags & Qt::LinksAccessibleByMouse) {
if (!(e->button() & Qt::LeftButton))
return;
@@ -1375,7 +1397,7 @@ QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property) cons
return inputMethodQuery(property, QVariant());
}
-QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
+QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property, const QVariant &argument) const
{
Q_D(const QQuickTextControl);
QTextBlock block = d->cursor.block();
@@ -1478,8 +1500,15 @@ void QQuickTextControlPrivate::hoverEvent(QHoverEvent *e, const QPointF &pos)
if (hoveredLink != link) {
hoveredLink = link;
emit q->linkHovered(link);
+ qCDebug(DBG_HOVER_TRACE) << q << e->type() << pos << "hoveredLink" << hoveredLink;
+ } else {
+ QTextBlock block = q->blockWithMarkerAt(pos);
+ if (block.isValid() != hoveredMarker)
+ emit q->markerHovered(block.isValid());
+ hoveredMarker = block.isValid();
+ if (hoveredMarker)
+ qCDebug(DBG_HOVER_TRACE) << q << e->type() << pos << "hovered marker" << int(block.blockFormat().marker()) << block.text();
}
- qCDebug(DBG_HOVER_TRACE) << q << e->type() << pos << "hoveredLink" << hoveredLink;
}
bool QQuickTextControl::hasImState() const
@@ -1555,6 +1584,12 @@ QString QQuickTextControl::anchorAt(const QPointF &pos) const
return d->doc->documentLayout()->anchorAt(pos);
}
+QTextBlock QQuickTextControl::blockWithMarkerAt(const QPointF &pos) const
+{
+ Q_D(const QQuickTextControl);
+ return d->doc->documentLayout()->blockWithMarkerAt(pos);
+}
+
void QQuickTextControl::setAcceptRichText(bool accept)
{
Q_D(QQuickTextControl);
@@ -1784,6 +1819,13 @@ QString QQuickTextControl::toHtml() const
}
#endif
+#if QT_CONFIG(textmarkdownwriter)
+QString QQuickTextControl::toMarkdown() const
+{
+ return document()->toMarkdown();
+}
+#endif
+
bool QQuickTextControl::cursorOn() const
{
Q_D(const QQuickTextControl);
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index c99736a874..41b8ed7821 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -93,6 +93,9 @@ public:
#if QT_CONFIG(texthtmlparser)
QString toHtml() const;
#endif
+#if QT_CONFIG(textmarkdownwriter)
+ QString toMarkdown() const;
+#endif
bool hasImState() const;
bool overwriteMode() const;
@@ -107,6 +110,7 @@ public:
QString hoveredLink() const;
QString anchorAt(const QPointF &pos) const;
+ QTextBlock blockWithMarkerAt(const QPointF &pos) const;
void setCursorWidth(int width);
@@ -128,6 +132,7 @@ public:
public Q_SLOTS:
void setPlainText(const QString &text);
+ void setMarkdownText(const QString &text);
void setHtml(const QString &text);
#if QT_CONFIG(clipboard)
@@ -160,6 +165,8 @@ Q_SIGNALS:
void cursorRectangleChanged();
void linkActivated(const QString &link);
void linkHovered(const QString &link);
+ void markerClicked();
+ void markerHovered(bool marker);
public:
virtual void processEvent(QEvent *e, const QMatrix &matrix);
@@ -167,7 +174,7 @@ public:
#if QT_CONFIG(im)
virtual QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
- Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const;
+ Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, const QVariant &argument) const;
#endif
virtual QMimeData *createMimeDataFromSelection() const;
diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h
index 431bf1b6c4..d52200b49d 100644
--- a/src/quick/items/qquicktextcontrol_p_p.h
+++ b/src/quick/items/qquicktextcontrol_p_p.h
@@ -54,6 +54,7 @@
#include "QtGui/qtextdocumentfragment.h"
#include "QtGui/qtextcursor.h"
#include "QtGui/qtextformat.h"
+#include "QtGui/qtextobject.h"
#include "QtGui/qabstracttextdocumentlayout.h"
#include "QtCore/qbasictimer.h"
#include "QtCore/qpointer.h"
@@ -139,6 +140,7 @@ public:
QString anchorOnMousePress;
QString linkToCopy;
QString hoveredLink;
+ QTextBlock blockWithMarkerUnderMousePress;
QBasicTimer cursorBlinkTimer;
ulong timestampAtLastDoubleClick = 0; // will only be set at a double click
@@ -163,6 +165,7 @@ public:
bool wordSelectionEnabled : 1;
bool hasImState : 1;
bool cursorRectangleChanged : 1;
+ bool hoveredMarker: 1;
int lastSelectionStart;
int lastSelectionEnd;
diff --git a/src/quick/items/qquicktextdocument.cpp b/src/quick/items/qquicktextdocument.cpp
index 06ac5804c4..021bbca0f6 100644
--- a/src/quick/items/qquicktextdocument.cpp
+++ b/src/quick/items/qquicktextdocument.cpp
@@ -237,6 +237,14 @@ void QQuickTextDocumentWithImageResources::setText(const QString &text)
#endif
}
+#if QT_CONFIG(textmarkdownreader)
+void QQuickTextDocumentWithImageResources::setMarkdownText(const QString &text)
+{
+ clearResources();
+ QTextDocument::setMarkdown(text);
+}
+#endif
+
QSet<QUrl> QQuickTextDocumentWithImageResources::errors;
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextdocument_p.h b/src/quick/items/qquicktextdocument_p.h
index 1218b12b89..9c5152d442 100644
--- a/src/quick/items/qquicktextdocument_p.h
+++ b/src/quick/items/qquicktextdocument_p.h
@@ -73,6 +73,9 @@ public:
virtual ~QQuickTextDocumentWithImageResources();
void setText(const QString &);
+#if QT_CONFIG(textmarkdownreader)
+ void setMarkdownText(const QString &);
+#endif
int resourcesLoading() const { return outstanding; }
QSizeF intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) override;
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index bdfbb979dd..7d34cc3f56 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -194,6 +194,11 @@ QString QQuickTextEdit::text() const
d->text = d->control->toHtml();
else
#endif
+#if QT_CONFIG(textmarkdownwriter)
+ if (d->markdownText)
+ d->text = d->control->toMarkdown();
+ else
+#endif
d->text = d->control->toPlainText();
d->textCached = true;
}
@@ -407,6 +412,7 @@ void QQuickTextEdit::setText(const QString &text)
d->document->clearResources();
d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
+ d->markdownText = d->format == MarkdownText;
if (!isComponentComplete()) {
d->text = text;
} else if (d->richText) {
@@ -415,6 +421,8 @@ void QQuickTextEdit::setText(const QString &text)
#else
d->control->setPlainText(text);
#endif
+ } else if (d->markdownText) {
+ d->control->setMarkdownText(text);
} else {
d->control->setPlainText(text);
}
@@ -486,6 +494,7 @@ void QQuickTextEdit::setTextFormat(TextFormat format)
bool wasRich = d->richText;
d->richText = format == RichText || (format == AutoText && (wasRich || Qt::mightBeRichText(text())));
+ d->markdownText = format == MarkdownText;
#if QT_CONFIG(texthtmlparser)
if (isComponentComplete()) {
@@ -1463,8 +1472,12 @@ void QQuickTextEdit::componentComplete()
d->control->setHtml(d->text);
else
#endif
- if (!d->text.isEmpty())
- d->control->setPlainText(d->text);
+ if (!d->text.isEmpty()) {
+ if (d->markdownText)
+ d->control->setMarkdownText(d->text);
+ else
+ d->control->setPlainText(d->text);
+ }
if (d->dirty) {
d->determineHorizontalAlignment();
@@ -2309,6 +2322,7 @@ void QQuickTextEditPrivate::init()
QObject::connect(document, &QQuickTextDocumentWithImageResources::contentsChange, q, &QQuickTextEdit::q_contentsChange);
QObject::connect(document->documentLayout(), &QAbstractTextDocumentLayout::updateBlock, q, &QQuickTextEdit::invalidateBlock);
QObject::connect(control, &QQuickTextControl::linkHovered, q, &QQuickTextEdit::q_linkHovered);
+ QObject::connect(control, &QQuickTextControl::markerHovered, q, &QQuickTextEdit::q_markerHovered);
document->setDefaultFont(font);
document->setDocumentMargin(textMargin);
@@ -2600,6 +2614,19 @@ void QQuickTextEdit::q_linkHovered(const QString &link)
#endif
}
+void QQuickTextEdit::q_markerHovered(bool hovered)
+{
+ Q_D(QQuickTextEdit);
+#if QT_CONFIG(cursor)
+ if (!hovered) {
+ setCursor(d->cursorToRestoreAfterHover);
+ } else if (cursor().shape() != Qt::PointingHandCursor) {
+ d->cursorToRestoreAfterHover = cursor().shape();
+ setCursor(Qt::PointingHandCursor);
+ }
+#endif
+}
+
void QQuickTextEdit::q_updateAlignment()
{
Q_D(QQuickTextEdit);
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index 259a614d6b..2d1b6c7f9c 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -134,7 +134,8 @@ public:
enum TextFormat {
PlainText = Qt::PlainText,
RichText = Qt::RichText,
- AutoText = Qt::AutoText
+ AutoText = Qt::AutoText,
+ MarkdownText = Qt::MarkdownText
};
Q_ENUM(TextFormat)
@@ -375,6 +376,7 @@ private Q_SLOTS:
void invalidateBlock(const QTextBlock &block);
void updateCursor();
void q_linkHovered(const QString &link);
+ void q_markerHovered(bool hovered);
void q_updateAlignment();
void updateSize();
void triggerPreprocess();
diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h
index 389ce3175c..be555d44fd 100644
--- a/src/quick/items/qquicktextedit_p_p.h
+++ b/src/quick/items/qquicktextedit_p_p.h
@@ -127,7 +127,7 @@ public:
, focusOnPress(true), persistentSelection(false), requireImplicitWidth(false)
, selectByMouse(false), canPaste(false), canPasteValid(false), hAlignImplicit(true)
, textCached(true), inLayout(false), selectByKeyboard(false), selectByKeyboardSet(false)
- , hadSelection(false)
+ , hadSelection(false), markdownText(false)
{
}
@@ -225,6 +225,7 @@ public:
bool selectByKeyboard:1;
bool selectByKeyboardSet:1;
bool hadSelection : 1;
+ bool markdownText : 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 182889b14e..a83b9beaa5 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -1009,9 +1009,10 @@ void QQuickTextInput::setAutoScroll(bool b)
an acceptable or intermediate state. The accepted signal will only be sent
if the text is in an acceptable state when enter is pressed.
- Currently supported validators are IntValidator, DoubleValidator and
- RegExpValidator. An example of using validators is shown below, which allows
- input of integers between 11 and 31 into the text input:
+ Currently supported validators are IntValidator, DoubleValidator,
+ RegExpValidator and RegularExpressionValidator. An example of using
+ validators is shown below, which allows input of integers between 11 and 31
+ into the text input:
\code
import QtQuick 2.0
@@ -1957,7 +1958,7 @@ QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
return inputMethodQuery(property, QVariant());
}
-QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
+QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property, const QVariant &argument) const
{
Q_D(const QQuickTextInput);
switch (property) {
diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h
index c46a2f8128..c10b06d02a 100644
--- a/src/quick/items/qquicktextinput_p.h
+++ b/src/quick/items/qquicktextinput_p.h
@@ -93,7 +93,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem
Q_PROPERTY(EchoMode echoMode READ echoMode WRITE setEchoMode NOTIFY echoModeChanged)
Q_PROPERTY(bool activeFocusOnPress READ focusOnPress WRITE setFocusOnPress NOTIFY activeFocusOnPressChanged)
Q_PROPERTY(QString passwordCharacter READ passwordCharacter WRITE setPasswordCharacter NOTIFY passwordCharacterChanged)
- Q_PROPERTY(int passwordMaskDelay READ passwordMaskDelay WRITE setPasswordMaskDelay RESET resetPasswordMaskDelay NOTIFY passwordMaskDelayChanged REVISION 3)
+ Q_PROPERTY(int passwordMaskDelay READ passwordMaskDelay WRITE setPasswordMaskDelay RESET resetPasswordMaskDelay NOTIFY passwordMaskDelayChanged REVISION 4)
Q_PROPERTY(QString displayText READ displayText NOTIFY displayTextChanged)
Q_PROPERTY(QString preeditText READ preeditText NOTIFY preeditTextChanged REVISION 7)
Q_PROPERTY(bool autoScroll READ autoScroll WRITE setAutoScroll NOTIFY autoScrollChanged)
@@ -268,7 +268,7 @@ public:
#if QT_CONFIG(im)
QVariant inputMethodQuery(Qt::InputMethodQuery property) const override;
- Q_REVISION(3) Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const;
+ Q_REVISION(4) Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, const QVariant &argument) const;
#endif
QRectF boundingRect() const override;
@@ -336,7 +336,7 @@ Q_SIGNALS:
void inputMaskChanged(const QString &inputMask);
void echoModeChanged(QQuickTextInput::EchoMode echoMode);
void passwordCharacterChanged();
- Q_REVISION(3) void passwordMaskDelayChanged(int delay);
+ Q_REVISION(4) void passwordMaskDelayChanged(int delay);
void displayTextChanged();
Q_REVISION(7) void preeditTextChanged();
void activeFocusOnPressChanged(bool activeFocusOnPress);
@@ -399,7 +399,7 @@ public Q_SLOTS:
void redo();
void insert(int position, const QString &text);
void remove(int start, int end);
- Q_REVISION(3) void ensureVisible(int position);
+ Q_REVISION(4) void ensureVisible(int position);
Q_REVISION(7) void clear();
private Q_SLOTS:
diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp
index 0dd12207b7..9110a0664f 100644
--- a/src/quick/items/qquicktextnode.cpp
+++ b/src/quick/items/qquicktextnode.cpp
@@ -160,7 +160,7 @@ void QQuickTextNode::addRectangleNode(const QRectF &rect, const QColor &color)
void QQuickTextNode::addImage(const QRectF &rect, const QImage &image)
{
QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext();
- QSGInternalImageNode *node = sg->sceneGraphContext()->createInternalImageNode();
+ QSGInternalImageNode *node = sg->sceneGraphContext()->createInternalImageNode(sg);
QSGTexture *texture = sg->createTexture(image);
if (m_ownerElement->smooth())
texture->setFiltering(QSGTexture::Linear);
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index 1119a3d5b4..a0ae4e5f97 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -638,7 +638,7 @@ void QQuickTextNodeEngine::addBorder(const QRectF &rect, qreal border,
QTextFrameFormat::BorderStyle borderStyle,
const QBrush &borderBrush)
{
- QColor color = borderBrush.color();
+ const QColor &color = borderBrush.color();
// Currently we don't support other styles than solid
Q_UNUSED(borderStyle);
@@ -1011,6 +1011,17 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
break;
};
+ switch (block.blockFormat().marker()) {
+ case QTextBlockFormat::MarkerType::Checked:
+ listItemBullet = QChar(0x2612); // Checked checkbox
+ break;
+ case QTextBlockFormat::MarkerType::Unchecked:
+ listItemBullet = QChar(0x2610); // Unchecked checkbox
+ break;
+ case QTextBlockFormat::MarkerType::NoMarker:
+ break;
+ }
+
QSizeF size(fontMetrics.horizontalAdvance(listItemBullet), fontMetrics.height());
qreal xoff = fontMetrics.horizontalAdvance(QLatin1Char(' '));
if (block.textDirection() == Qt::LeftToRight)
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index c411da9519..17fc16d44b 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -44,8 +44,6 @@
#include "qquickitem_p.h"
#include "qquickitemchangelistener_p.h"
-#include <private/qqmlmemoryprofiler_p.h>
-
#include <QtQml/qqmlengine.h>
#include <private/qqmlengine_p.h>
#include <private/qv4qobjectwrapper_p.h>
@@ -101,7 +99,6 @@ void QQuickViewPrivate::execute()
component = nullptr;
}
if (!source.isEmpty()) {
- QML_MEMORY_SCOPE_URL(engine.data()->baseUrl().resolved(source));
component = new QQmlComponent(engine.data(), source, q);
if (!component->isLoading()) {
q->continueExecute();
@@ -243,6 +240,22 @@ void QQuickView::setSource(const QUrl& url)
}
/*!
+ Sets the initial properties with which the QML component gets initialized after
+ calling \l QQuickView::setSource.
+
+
+ Note that you can only use this function to initialize toplevel properties.
+
+ \sa QQmlComponent::createWithInitialProperties
+ \since 5.14
+*/
+void QQuickView::setInitialProperties(const QVariantMap &initialProperties)
+{
+ Q_D(QQuickView);
+ d->initialProperties = initialProperties;
+}
+
+/*!
\internal
Set the source \a url, \a component and content \a item (root of the QML object hierarchy) directly.
@@ -474,7 +487,7 @@ void QQuickView::continueExecute()
return;
}
- QObject *obj = d->component->create();
+ QObject *obj = d->initialProperties.empty() ? d->component->create() : d->component->createWithInitialProperties(d->initialProperties);
if (d->component->isError()) {
const QList<QQmlError> errorList = d->component->errors();
diff --git a/src/quick/items/qquickview.h b/src/quick/items/qquickview.h
index ecae25e90b..4122fcac79 100644
--- a/src/quick/items/qquickview.h
+++ b/src/quick/items/qquickview.h
@@ -88,6 +88,7 @@ public:
public Q_SLOTS:
void setSource(const QUrl&);
+ void setInitialProperties(const QVariantMap &initialProperties);
void setContent(const QUrl& url, QQmlComponent *component, QObject *item);
Q_SIGNALS:
diff --git a/src/quick/items/qquickview_p.h b/src/quick/items/qquickview_p.h
index 3f284c0519..b1ab8d8e8c 100644
--- a/src/quick/items/qquickview_p.h
+++ b/src/quick/items/qquickview_p.h
@@ -108,6 +108,8 @@ public:
QQuickView::ResizeMode resizeMode;
QSize initialSize;
QElapsedTimer frameTimer;
+
+ QVariantMap initialProperties;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 2316a6c6af..8fb023cf61 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -45,13 +45,16 @@
#include "qquickitem_p.h"
#include "qquickevents_p_p.h"
+#if QT_CONFIG(quick_draganddrop)
#include <private/qquickdrag_p.h>
+#endif
#include <private/qquickhoverhandler_p.h>
#include <private/qquickpointerhandler_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
-#include <QtQuick/private/qsgtexture_p.h>
+#include <QtQuick/private/qsgplaintexture_p.h>
#include <private/qsgrenderloop_p.h>
+#include <private/qsgrhisupport_p.h>
#include <private/qquickrendercontrol_p.h>
#include <private/qquickanimatorcontroller_p.h>
#include <private/qquickprofiler_p.h>
@@ -73,7 +76,6 @@
#include <QtQuick/private/qquickpixmapcache_p.h>
-#include <private/qqmlmemoryprofiler_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
#include <private/qqmldebugconnector_p.h>
#if QT_CONFIG(opengl)
@@ -84,6 +86,8 @@
#include <private/qdebug_p.h>
#endif
+#include <QtGui/private/qrhi_p.h>
+
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch")
@@ -98,6 +102,7 @@ Q_LOGGING_CATEGORY(DBG_DIRTY, "qt.quick.dirty")
Q_LOGGING_CATEGORY(lcTransient, "qt.quick.window.transient")
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
+extern Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1);
bool QQuickWindowPrivate::defaultAlphaBuffer = false;
@@ -418,9 +423,15 @@ void forceUpdate(QQuickItem *item)
void QQuickWindowPrivate::syncSceneGraph()
{
- QML_MEMORY_SCOPE_STRING("SceneGraph");
Q_Q(QQuickWindow);
+ // Calculate the dpr the same way renderSceneGraph() will.
+ qreal devicePixelRatio = q->effectiveDevicePixelRatio();
+ if (renderTargetId && !QQuickRenderControl::renderWindowFor(q))
+ devicePixelRatio = 1;
+
+ context->prepareSync(devicePixelRatio);
+
animationController->beforeNodeSync();
emit q->beforeSynchronizing();
@@ -451,13 +462,40 @@ void QQuickWindowPrivate::syncSceneGraph()
runAndClearJobs(&afterSynchronizingJobs);
}
-void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
+void QQuickWindowPrivate::emitBeforeRenderPassRecording(void *ud)
+{
+ QQuickWindow *w = reinterpret_cast<QQuickWindow *>(ud);
+ emit w->beforeRenderPassRecording();
+}
+
+void QQuickWindowPrivate::emitAfterRenderPassRecording(void *ud)
+{
+ QQuickWindow *w = reinterpret_cast<QQuickWindow *>(ud);
+ emit w->afterRenderPassRecording();
+}
+
+void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfaceSize)
{
- QML_MEMORY_SCOPE_STRING("SceneGraph");
Q_Q(QQuickWindow);
if (!renderer)
return;
+ if (rhi) {
+ // ### no offscreen ("renderTargetId") support yet
+ context->beginNextRhiFrame(renderer,
+ swapchain->currentFrameRenderTarget(),
+ rpDescForSwapchain,
+ swapchain->currentFrameCommandBuffer(),
+ emitBeforeRenderPassRecording,
+ emitAfterRenderPassRecording,
+ q);
+ } else {
+ context->beginNextFrame(renderer,
+ emitBeforeRenderPassRecording,
+ emitAfterRenderPassRecording,
+ q);
+ }
+
animationController->advance();
emit q->beforeRendering();
runAndClearJobs(&beforeRenderingJobs);
@@ -477,17 +515,45 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
renderer->setDevicePixelRatio(1);
}
} else {
- QRect rect(QPoint(0, 0), devicePixelRatio * size);
+ QSize pixelSize;
+ QSizeF logicalSize;
+ if (surfaceSize.isEmpty()) {
+ pixelSize = size * devicePixelRatio;
+ logicalSize = size;
+ } else {
+ pixelSize = surfaceSize;
+ logicalSize = QSizeF(surfaceSize) / devicePixelRatio;
+ }
+ QRect rect(QPoint(0, 0), pixelSize);
renderer->setDeviceRect(rect);
renderer->setViewportRect(rect);
- renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size));
+ const bool flipY = rhi ? !rhi->isYUpInNDC() : false;
+ QSGAbstractRenderer::MatrixTransformFlags matrixFlags = 0;
+ if (flipY)
+ matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY;
+ renderer->setProjectionMatrixToRect(QRectF(QPoint(0, 0), logicalSize), matrixFlags);
renderer->setDevicePixelRatio(devicePixelRatio);
}
- context->renderNextFrame(renderer, fboId);
+ if (rhi)
+ context->renderNextRhiFrame(renderer);
+ else
+ context->renderNextFrame(renderer, fboId);
}
emit q->afterRendering();
runAndClearJobs(&afterRenderingJobs);
+
+ if (rhi)
+ context->endNextRhiFrame(renderer);
+ else
+ context->endNextFrame(renderer);
+
+ if (renderer->hasCustomRenderModeWithContinuousUpdate()) {
+ // For the overdraw visualizer. This update is not urgent so avoid a
+ // direct update() call, this is only here to keep the overdraw
+ // visualization box rotating even when the scene is static.
+ QCoreApplication::postEvent(q, new QEvent(QEvent::Type(FullUpdateRequest)));
+ }
}
QQuickWindowPrivate::QQuickWindowPrivate()
@@ -496,7 +562,7 @@ QQuickWindowPrivate::QQuickWindowPrivate()
#if QT_CONFIG(cursor)
, cursorItem(nullptr)
#endif
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
, dragGrabber(nullptr)
#endif
, touchMouseId(-1)
@@ -523,8 +589,11 @@ QQuickWindowPrivate::QQuickWindowPrivate()
, renderTargetId(0)
, vaoHelper(nullptr)
, incubationController(nullptr)
+ , hasActiveSwapchain(false)
+ , hasRenderableSwapchain(false)
+ , swapchainJustBecameRenderable(false)
{
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
dragGrabber = new QQuickDragGrabber;
#endif
}
@@ -540,6 +609,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
{
q_ptr = c;
+
Q_Q(QQuickWindow);
contentItem = new QQuickRootItem;
@@ -577,8 +647,12 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
q->setSurfaceType(windowManager ? windowManager->windowSurfaceType() : QSurface::OpenGLSurface);
q->setFormat(sg->defaultSurfaceFormat());
+#if QT_CONFIG(vulkan)
+ if (q->surfaceType() == QSurface::VulkanSurface)
+ q->setVulkanInstance(QSGRhiSupport::vulkanInstance());
+#endif
- animationController = new QQuickAnimatorController(q);
+ animationController.reset(new QQuickAnimatorController(q));
QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
@@ -639,7 +713,7 @@ bool QQuickWindowPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp, QPoi
if (touchMousePressTimestamp > 0) {
QPoint distanceBetweenPresses = newPressPos - touchMousePressPos;
- const int doubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt();
+ const int doubleTapDistance = QGuiApplication::styleHints()->touchDoubleTapDistance();
doubleClicked = (qAbs(distanceBetweenPresses.x()) <= doubleTapDistance) && (qAbs(distanceBetweenPresses.y()) <= doubleTapDistance);
if (doubleClicked) {
@@ -1346,7 +1420,7 @@ QQuickWindow::~QQuickWindow()
}
delete d->incubationController; d->incubationController = nullptr;
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
delete d->dragGrabber; d->dragGrabber = nullptr;
#endif
QQuickRootItem *root = d->contentItem;
@@ -1578,6 +1652,7 @@ bool QQuickWindowPrivate::clearHover(ulong timestamp)
bool accepted = false;
for (QQuickItem* item : qAsConst(hoverItems)) {
accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), timestamp, true) || accepted;
+#if QT_CONFIG(cursor)
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (itemPrivate->hasPointerHandlers()) {
pos = q->mapFromGlobal(QCursor::pos());
@@ -1589,6 +1664,7 @@ bool QQuickWindowPrivate::clearHover(ulong timestamp)
if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h))
hh->handlePointerEvent(pointerEvent);
}
+#endif
}
hoverItems.clear();
return accepted;
@@ -1627,7 +1703,9 @@ bool QQuickWindow::event(QEvent *e)
QGuiApplication::keyboardModifiers(), 0L, accepted);
d->lastMousePosition = enter->windowPos();
enter->setAccepted(accepted);
+#if QT_CONFIG(cursor)
d->updateCursor(mapFromGlobal(QCursor::pos()));
+#endif
return delivered;
}
break;
@@ -1635,7 +1713,7 @@ bool QQuickWindow::event(QEvent *e)
d->clearHover();
d->lastMousePosition = QPointF();
break;
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
case QEvent::DragEnter:
case QEvent::DragLeave:
case QEvent::DragMove:
@@ -1717,6 +1795,13 @@ void QQuickWindowPrivate::deliverKeyEvent(QKeyEvent *e)
{
if (activeFocusItem) {
QQuickItem *item = activeFocusItem;
+
+ // In case of generated event, trigger ShortcutOverride event
+ if (e->type() == QEvent::KeyPress && e->spontaneous() == false)
+ qt_sendShortcutOverrideEvent(item, e->timestamp(),
+ e->key(), e->modifiers(), e->text(),
+ e->isAutoRepeat(), e->count());
+
e->accept();
QCoreApplication::sendEvent(item, e);
while (!e->isAccepted() && (item = item->parentItem())) {
@@ -2691,7 +2776,7 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo
// If the touch was accepted (regardless by whom or in what form),
// update accepted new points.
bool isPressOrRelease = pointerEvent->isPressEvent() || pointerEvent->isReleaseEvent();
- for (auto point: qAsConst(touchEvent->touchPoints())) {
+ for (const auto &point: qAsConst(touchEvent->touchPoints())) {
if (auto pointerEventPoint = ptEvent->pointById(point.id())) {
pointerEventPoint->setAccepted();
if (isPressOrRelease)
@@ -2701,7 +2786,7 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo
} else {
// But if the event was not accepted then we know this item
// will not be interested in further updates for those touchpoint IDs either.
- for (auto point: qAsConst(touchEvent->touchPoints())) {
+ for (const auto &point: qAsConst(touchEvent->touchPoints())) {
if (point.state() == Qt::TouchPointPressed) {
if (auto *tp = ptEvent->pointById(point.id())) {
if (tp->exclusiveGrabber() == item) {
@@ -2714,7 +2799,7 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo
}
}
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
{
grabber->resetTarget();
@@ -2743,32 +2828,49 @@ void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *e
for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
QCoreApplication::sendEvent(**grabItem, &leaveEvent);
return;
- } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
+ } else {
QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
- if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
- for (++grabItem; grabItem != grabber->end();) {
- QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
- if ((**grabItem)->contains(p)) {
- QDragMoveEvent translatedEvent(
- p.toPoint(),
- moveEvent->possibleActions(),
- moveEvent->mimeData(),
- moveEvent->mouseButtons(),
- moveEvent->keyboardModifiers());
- QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
- QCoreApplication::sendEvent(**grabItem, &translatedEvent);
- ++grabItem;
- } else {
- QDragLeaveEvent leaveEvent;
- QCoreApplication::sendEvent(**grabItem, &leaveEvent);
- grabItem = grabber->release(grabItem);
- }
+
+ // Used to ensure we don't send DragEnterEvents to current drop targets,
+ // and to detect which current drop targets we have left
+ QVarLengthArray<QQuickItem*, 64> currentGrabItems;
+ for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
+ currentGrabItems.append(**grabItem);
+
+ // Look for any other potential drop targets that are higher than the current ones
+ QDragEnterEvent enterEvent(
+ moveEvent->pos(),
+ moveEvent->possibleActions(),
+ moveEvent->mimeData(),
+ moveEvent->mouseButtons(),
+ moveEvent->keyboardModifiers());
+ QQuickDropEventEx::copyActions(&enterEvent, *moveEvent);
+ event->setAccepted(deliverDragEvent(grabber, contentItem, &enterEvent, &currentGrabItems));
+
+ for (grabItem = grabber->begin(); grabItem != grabber->end(); ++grabItem) {
+ int i = currentGrabItems.indexOf(**grabItem);
+ if (i >= 0) {
+ currentGrabItems.remove(i);
+ // Still grabbed: send move event
+ QDragMoveEvent translatedEvent(
+ (**grabItem)->mapFromScene(moveEvent->pos()).toPoint(),
+ moveEvent->possibleActions(),
+ moveEvent->mimeData(),
+ moveEvent->mouseButtons(),
+ moveEvent->keyboardModifiers());
+ QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
+ QCoreApplication::sendEvent(**grabItem, &translatedEvent);
+ event->setAccepted(translatedEvent.isAccepted());
+ QQuickDropEventEx::copyActions(moveEvent, translatedEvent);
}
- return;
- } else {
- QDragLeaveEvent leaveEvent;
- QCoreApplication::sendEvent(**grabItem, &leaveEvent);
}
+
+ // Anything left in currentGrabItems is no longer a drop target and should be sent a DragLeaveEvent
+ QDragLeaveEvent leaveEvent;
+ for (QQuickItem *i : currentGrabItems)
+ QCoreApplication::sendEvent(i, &leaveEvent);
+
+ return;
}
}
if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
@@ -2784,9 +2886,8 @@ void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *e
}
}
-bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
+bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event, QVarLengthArray<QQuickItem*, 64> *currentGrabItems)
{
- bool accepted = false;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
return false;
@@ -2805,12 +2906,24 @@ bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte
event->keyboardModifiers());
QQuickDropEventEx::copyActions(&enterEvent, *event);
QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
+
+ // Check children in front of this item first
for (int ii = children.count() - 1; ii >= 0; --ii) {
- if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
+ if (children.at(ii)->z() < 0)
+ continue;
+ if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems))
return true;
}
if (itemContained) {
+ // If this item is currently grabbed, don't send it another DragEnter,
+ // just grab it again if it's still contained.
+ if (currentGrabItems && currentGrabItems->contains(item)) {
+ grabber->grab(item);
+ grabber->setTarget(item);
+ return true;
+ }
+
if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
QDragMoveEvent translatedEvent(
p.toPoint(),
@@ -2827,17 +2940,26 @@ bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte
if (event->type() == QEvent::DragEnter) {
if (translatedEvent.isAccepted()) {
grabber->grab(item);
- accepted = true;
+ grabber->setTarget(item);
+ return true;
}
} else {
- accepted = true;
+ return true;
}
}
}
- return accepted;
+ // Check children behind this item if this item or any higher children have not accepted
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ if (children.at(ii)->z() >= 0)
+ continue;
+ if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems))
+ return true;
+ }
+
+ return false;
}
-#endif // draganddrop
+#endif // quick_draganddrop
#if QT_CONFIG(cursor)
void QQuickWindowPrivate::updateCursor(const QPointF &scenePos)
@@ -2942,7 +3064,7 @@ bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QQuickPointerEvent *event
if (filteringParent->childMouseEventFilter(receiver, filteringParentTouchEvent.data())) {
qCDebug(DBG_TOUCH) << "touch event intercepted by childMouseEventFilter of " << filteringParent;
skipDelivery.append(filteringParent);
- for (auto point: qAsConst(filteringParentTouchEvent->touchPoints())) {
+ for (const auto &point: qAsConst(filteringParentTouchEvent->touchPoints())) {
QQuickEventPoint *pt = event->pointById(point.id());
pt->setAccepted();
pt->setGrabberItem(filteringParent);
@@ -3625,24 +3747,20 @@ void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
/*!
Returns the OpenGL context used for rendering.
- If the scene graph is not ready, or the scene graph is not using OpenGL,
- this function will return null.
-
- \note If using a scene graph adaptation other than OpenGL this
- function will return nullptr.
+ \note If the scene graph is not ready, or the scene graph is not using
+ OpenGL (or RHI over OpenGL), this function will return null.
\sa sceneGraphInitialized(), sceneGraphInvalidated()
*/
-
QOpenGLContext *QQuickWindow::openglContext() const
{
#if QT_CONFIG(opengl)
Q_D(const QQuickWindow);
if (d->context && d->context->isValid()) {
QSGRendererInterface *rif = d->context->sceneGraphContext()->rendererInterface(d->context);
- if (rif && rif->graphicsApi() == QSGRendererInterface::OpenGL) {
- auto openglRenderContext = static_cast<const QSGDefaultRenderContext *>(d->context);
- return openglRenderContext->openglContext();
+ if (rif) {
+ return reinterpret_cast<QOpenGLContext *>(rif->getResource(const_cast<QQuickWindow *>(this),
+ QSGRendererInterface::OpenGLContextResource));
}
}
#endif
@@ -3781,6 +3899,8 @@ bool QQuickWindow::isSceneGraphInitialized() const
This function only has an effect when using the default OpenGL scene
graph adaptation.
+ \note This function has no effect when running on the RHI graphics abstraction.
+
\warning
This function can only be called from the thread doing
the rendering.
@@ -3789,6 +3909,9 @@ bool QQuickWindow::isSceneGraphInitialized() const
void QQuickWindow::setRenderTarget(QOpenGLFramebufferObject *fbo)
{
Q_D(QQuickWindow);
+ if (d->rhi)
+ return;
+
if (d->context && QThread::currentThread() != d->context->thread()) {
qWarning("QQuickWindow::setRenderTarget: Cannot set render target from outside the rendering thread");
return;
@@ -3870,9 +3993,11 @@ QSize QQuickWindow::renderTargetSize() const
The default is to render to the surface of the window, in which
case the render target is 0.
- \note
- This function will return nullptr when not using the OpenGL scene
+ \note This function will return nullptr when not using the OpenGL scene
graph adaptation.
+
+ \note This function has no effect and returns nullptr when running on the
+ RHI graphics abstraction.
*/
QOpenGLFramebufferObject *QQuickWindow::renderTarget() const
{
@@ -3898,12 +4023,23 @@ QImage QQuickWindow::grabWindow()
Q_D(QQuickWindow);
if (!isVisible() && !d->renderControl) {
+ // backends like software and d3d12 can grab regardless of the window state
if (d->windowManager && (d->windowManager->flags() & QSGRenderLoop::SupportsGrabWithoutExpose))
return d->windowManager->grab(this);
}
-#if QT_CONFIG(opengl)
if (!isVisible() && !d->renderControl) {
+ if (d->rhi) {
+ // ### we may need a full offscreen round when non-exposed...
+
+ if (d->renderControl)
+ return d->renderControl->grab();
+ else if (d->windowManager)
+ return d->windowManager->grab(this);
+ return QImage();
+ }
+
+#if QT_CONFIG(opengl)
auto openglRenderContext = static_cast<QSGDefaultRenderContext *>(d->context);
if (!openglRenderContext->openglContext()) {
if (!handle() || !size().isValid()) {
@@ -3916,7 +4052,9 @@ QImage QQuickWindow::grabWindow()
context.setShareContext(qt_gl_global_share_context());
context.create();
context.makeCurrent(this);
- d->context->initialize(&context);
+ QSGDefaultRenderContext::InitParams rcParams;
+ rcParams.openGLContext = &context;
+ d->context->initialize(&rcParams);
d->polishItems();
d->syncSceneGraph();
@@ -3931,8 +4069,9 @@ QImage QQuickWindow::grabWindow()
return image;
}
- }
#endif
+ }
+
if (d->renderControl)
return d->renderControl->grab();
else if (d->windowManager)
@@ -4070,6 +4209,19 @@ QQmlIncubationController *QQuickWindow::incubationController() const
The OpenGL context used for rendering the scene graph will be bound
at this point.
+ When using the RHI, the signal is emitted after the preparations for the
+ frame have been done, meaning there is a command buffer in recording mode,
+ where applicable. If desired, the slot function connected to this signal
+ can query native resources like the command before via
+ QSGRendererInterface. Note however that the recording of the main render
+ pass is not yet started at this point and it is not possible to add
+ commands within that pass. Starting a pass means clearing the color, depth,
+ and stencil buffers so it is not possible to achieve an underlay type of
+ rendering by just connecting to this signal. Rather, connect to
+ beforeRenderPassRecording(). However, connecting to this signal is still
+ important if the recording of copy type of commands is desired since those
+ cannot be enqueued within a render pass.
+
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
the connection is direct (see Qt::ConnectionType).
@@ -4091,6 +4243,18 @@ QQmlIncubationController *QQuickWindow::incubationController() const
The OpenGL context used for rendering the scene graph will be bound at this point.
+ When using the RHI, the signal is emitted after scene graph has added its
+ commands to the command buffer, which is not yet submitted to the graphics
+ queue. If desired, the slot function connected to this signal can query
+ native resources, like the command buffer, before via QSGRendererInterface.
+ Note however that the render pass (or passes) are already recorded at this
+ point and it is not possible to add more commands within the scenegraph's
+ pass. Instead, use afterRenderPassRecording() for that. This signal has
+ therefore limited use and is rarely needed in an RHI-based setup. Rather,
+ it is the combination of beforeRendering() + beforeRenderPassRecording() or
+ beforeRendering() + afterRenderPassRecording() that is typically used to
+ achieve under- or overlaying of the custom rendering.
+
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
the connection is direct (see Qt::ConnectionType).
@@ -4103,14 +4267,78 @@ QQmlIncubationController *QQuickWindow::incubationController() const
*/
/*!
+ \fn void QQuickWindow::beforeRenderPassRecording()
+
+ This signal is emitted before the scenegraph starts recording commands for
+ the main render pass. (Layers have their own passes and are fully recorded
+ by the time this signal is emitted.) The render pass is already active on
+ the command buffer when the signal is emitted.
+
+ This signal is applicable when using the RHI graphics abstraction with the
+ scenegraph. It is emitted later than beforeRendering() and it guarantees
+ that not just the frame, but also the recording of the scenegraph's main
+ render pass is active. This allows inserting commands without having to
+ generate an entire, separate render pass (which would typically clear the
+ attached images). The native graphics objects can be queried via
+ QSGRendererInterface.
+
+ When not running with the RHI (and using OpenGL directly), the signal is
+ emitted after the renderer has cleared the render target. This makes it
+ possible to create applications that function identically both with and
+ without the RHI.
+
+ \note Resource updates (uploads, copies) typically cannot be enqueued from
+ within a render pass. Therefore, more complex user rendering will need to
+ connect to both beforeRendering() and this signal.
+
+ \warning This signal is emitted from the scene graph rendering thread. If your
+ slot function needs to finish before execution continues, you must make sure that
+ the connection is direct (see Qt::ConnectionType).
+
+ \since 5.14
+*/
+
+/*!
+ \fn void QQuickWindow::afterRenderPassRecording()
+
+ This signal is emitted after the scenegraph has recorded the commands for
+ its main render pass, but the pass is not yet finalized on the command
+ buffer.
+
+ This signal is applicable when using the RHI graphics abstraction with the
+ scenegraph. It is emitted earlier than afterRendering() and it guarantees
+ that not just the frame, but also the recording of the scenegraph's main
+ render pass is still active. This allows inserting commands without having
+ to generate an entire, separate render pass (which would typically clear
+ the attached images). The native graphics objects can be queried via
+ QSGRendererInterface.
+
+ When not running with the RHI (and using OpenGL directly), the signal is
+ emitted after the renderer has finished its rendering, but before
+ afterRendering(). This makes it possible to create applications that
+ function identically both with and without the RHI.
+
+ \note Resource updates (uploads, copies) typically cannot be enqueued from
+ within a render pass. Therefore, more complex user rendering will need to
+ connect to both beforeRendering() and this signal.
+
+ \warning This signal is emitted from the scene graph rendering thread. If your
+ slot function needs to finish before execution continues, you must make sure that
+ the connection is direct (see Qt::ConnectionType).
+
+ \since 5.14
+*/
+
+/*!
\fn void QQuickWindow::afterAnimating()
This signal is emitted on the gui thread before requesting the render thread to
perform the synchronization of the scene graph.
- Unlike the other similar signals, this one is emitted on the gui thread instead
- of the render thread. It can be used to synchronize external animation systems
- with the QML content.
+ Unlike the other similar signals, this one is emitted on the gui thread
+ instead of the render thread. It can be used to synchronize external
+ animation systems with the QML content. At the same time this means that
+ this signal is not suitable for triggering graphics operations.
\since 5.3
*/
@@ -4170,7 +4398,15 @@ QQmlIncubationController *QQuickWindow::incubationController() const
The color buffer is cleared by default.
- \sa beforeRendering()
+ \warning This flag is ignored completely when running with the RHI graphics
+ abstraction instead of using OpenGL directly. As explicit clear commands
+ simply do not exist in some modern APIs, the scene graph cannot offer this
+ flexibility anymore. The images associated with a render target will always
+ get cleared when a render pass starts. As a solution, an alternative to
+ disabling scene graph issued clears is provided in form of the
+ beforeRenderPassRecording() signal.
+
+ \sa beforeRendering(), beforeRenderPassRecording()
*/
void QQuickWindow::setClearBeforeRendering(bool enabled)
@@ -4274,24 +4510,129 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText
\note This function only has an effect when using the default OpenGL scene graph
adaptation.
+ \note This function has no effect when running on the RHI graphics
+ abstraction. Use createTextureFromNativeObject() instead.
+
\sa sceneGraphInitialized(), QSGTexture
*/
QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
{
#if QT_CONFIG(opengl)
- if (openglContext()) {
- QSGPlainTexture *texture = new QSGPlainTexture();
- texture->setTextureId(id);
+ Q_D(const QQuickWindow);
+ if (!d->rhi) {
+ if (openglContext()) {
+ QSGPlainTexture *texture = new QSGPlainTexture();
+ texture->setTextureId(id);
+ texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
+ texture->setOwnsTexture(options & TextureOwnsGLTexture);
+ texture->setTextureSize(size);
+ return texture;
+ }
+ } else {
+ qWarning("createTextureFromId() must not be called when running on the RHI. "
+ "Use createTextureFromNativeObject() instead.");
+ }
+#else
+ Q_UNUSED(id)
+ Q_UNUSED(size)
+ Q_UNUSED(options)
+#endif
+ return nullptr;
+}
+
+/*!
+ \enum QQuickWindow::NativeObjectType
+ \since 5.14
+
+ Specifies the type of the native object passed to functions such as
+ createTextureFromNativeObject().
+
+ \value NativeObjectTexture The native object is a 2D texture (OpenGL,
+ Direct3D 11, Metal) or image (Vulkan).
+ */
+
+/*!
+ Creates a new QSGTexture object from an existing native object.
+
+ The native object is wrapped, but not owned, by the resulting QSGTexture.
+ The caller of the function is responsible for deleting the returned
+ QSGTexture, but that will not destroy the underlying native object.
+
+ \a type specifies the type of the object. In practice the type is
+ NativeObjectTexture, indicating that the native object is a texture or
+ image of the underlying graphics API. Other types may be introduced in the
+ future.
+
+ This function is currently suitable for 2D RGBA textures only.
+
+ Unlike createTextureFromId(), this function supports both direct OpenGL
+ usage and the RHI abstracted rendering path.
+
+ \warning This function will return null if the scenegraph has not yet been
+ initialized.
+
+ Use \a options to customize the texture attributes. Only the
+ TextureHasAlphaChannel and TextureHasMipmaps are taken into account here.
+
+ \warning Unlike createTextureFromId(), this function never takes ownership
+ of the native object, and the TextureOwnsGLTexture flag is ignored.
+
+ \a size specifies the size in pixels.
+
+ \a nativeObjectPtr is a pointer to the native object handle. With OpenGL,
+ the native handle is a GLuint value, so \a nativeObjectPtr is then a
+ pointer to a GLuint. With Vulkan, the native handle is a VkImage, so \a
+ nativeObjectPtr is a pointer to a VkImage. With Direct3D 11 and Metal \a
+ nativeObjectPtr is a pointer to a ID3D11Texture2D or MTLTexture pointer.
+
+ \note Pay attention to the fact that \a nativeObjectPtr is always a pointer
+ to the native texture handle type, even if the native type itself is a
+ pointer.
+
+ \a nativeLayout is only used for APIs like Vulkan. When applicable, it must
+ specify the current image layout, such as, a VkImageLayout value.
+
+ \sa sceneGraphInitialized(), QSGTextures
+
+ \since 5.14
+ */
+QSGTexture *QQuickWindow::createTextureFromNativeObject(NativeObjectType type,
+ const void *nativeObjectPtr,
+ int nativeLayout,
+ const QSize &size,
+ CreateTextureOptions options) const
+{
+ if (type != NativeObjectTexture) {
+ qWarning("createTextureFromNativeObject: only textures are supported");
+ return nullptr;
+ }
+
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+ Q_D(const QQuickWindow);
+ if (d->rhi) {
+ QSGPlainTexture *texture = new QSGPlainTexture;
+ texture->setTextureFromNativeObject(d->rhi, type, nativeObjectPtr, nativeLayout,
+ size, options.testFlag(TextureHasMipmaps));
+ texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
+ // note that the QRhiTexture does not (and cannot) own the native object
+ texture->setOwnsTexture(true); // texture meaning the QRhiTexture here, not the native object
+ texture->setTextureSize(size);
+ return texture;
+ } else if (openglContext()) {
+ QSGPlainTexture *texture = new QSGPlainTexture;
+ texture->setTextureId(*reinterpret_cast<const uint *>(nativeObjectPtr));
texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
texture->setOwnsTexture(options & TextureOwnsGLTexture);
texture->setTextureSize(size);
return texture;
}
#else
- Q_UNUSED(id)
- Q_UNUSED(size)
- Q_UNUSED(options)
+ Q_UNUSED(nativeObjectPtr);
+ Q_UNUSED(nativeLayout);
+ Q_UNUSED(size);
+ Q_UNUSED(options);
#endif
+
return nullptr;
}
@@ -4382,15 +4723,19 @@ void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha)
\note This function only has an effect when using the default OpenGL scene graph
adaptation.
- \sa QQuickWindow::beforeRendering()
+ \note This function has no effect when running on the RHI graphics
+ abstraction. With the RHI, the functions to call when enqueuing native
+ graphics commands are beginExternalCommands() and endExternalCommands().
+
+ \sa QQuickWindow::beforeRendering(), beginExternalCommands(), endExternalCommands()
*/
void QQuickWindow::resetOpenGLState()
{
- if (!openglContext())
- return;
-
Q_D(QQuickWindow);
+ if (d->rhi || !openglContext())
+ return;
+
QOpenGLContext *ctx = openglContext();
QOpenGLFunctions *gl = ctx->functions();
@@ -4437,6 +4782,132 @@ void QQuickWindow::resetOpenGLState()
QOpenGLFramebufferObject::bindDefault();
}
#endif
+
+/*!
+ \struct QQuickWindow::GraphicsStateInfo
+ \inmodule QtQuick
+ \since 5.14
+
+ \brief Describes some of the RHI's graphics state at the point of a
+ \l{QQuickWindow::beginExternalCommands()}{beginExternalCommands()} call.
+ */
+
+/*!
+ \return a reference to a GraphicsStateInfo struct describing some of the
+ RHI's internal state, in particular, the double or tripple buffering status
+ of the backend (such as, the Vulkan or Metal integrations). This is
+ relevant when the underlying graphics APIs is Vulkan or Metal, and the
+ external rendering code wishes to perform double or tripple buffering of
+ its own often-changing resources, such as, uniform buffers, in order to
+ avoid stalling the pipeline.
+ */
+const QQuickWindow::GraphicsStateInfo &QQuickWindow::graphicsStateInfo()
+{
+ Q_D(QQuickWindow);
+ if (d->rhi) {
+ d->rhiStateInfo.currentFrameSlot = d->rhi->currentFrameSlot();
+ d->rhiStateInfo.framesInFlight = d->rhi->resourceLimit(QRhi::FramesInFlight);
+ }
+ return d->rhiStateInfo;
+}
+
+/*!
+ When mixing raw graphics (OpenGL, Vulkan, Metal, etc.) commands with scene
+ graph rendering, it is necessary to call this function before recording
+ commands to the command buffer used by the scene graph to render its main
+ render pass. This is to avoid clobbering state.
+
+ In practice this function is often called from a slot connected to the
+ beforeRenderPassRecording() or afterRenderPassRecording() signals.
+
+ The function does not need to be called when recording commands to the
+ application's own command buffer (such as, a VkCommandBuffer or
+ MTLCommandBuffer + MTLRenderCommandEncoder created and managed by the
+ application, not retrieved from the scene graph). With graphics APIs where
+ no native command buffer concept is exposed (OpenGL, Direct 3D 11),
+ beginExternalCommands() and endExternalCommands() together provide a
+ replacement for resetOpenGLState().
+
+ Calling this function and endExternalCommands() is not necessary within the
+ \l{QSGRenderNode::render()}{render()} implementation of a QSGRenderNode
+ because the scene graph performs the necessary steps implicitly for render
+ nodes.
+
+ Native graphics objects (such as, graphics device, command buffer or
+ encoder) are accessible via QSGRendererInterface::getResource().
+
+ \warning Watch out for the fact that
+ QSGRendererInterface::CommandListResource may return a different object
+ between beginExternalCommands() - endExternalCommands(). This can happen
+ when the underlying implementation provides a dedicated secondary command
+ buffer for recording external graphics commands within a render pass.
+ Therefore, always query CommandListResource after calling this function. Do
+ not attempt to reuse an object from an earlier query.
+
+ \note This function has no effect when the scene graph is using OpenGL
+ directly and the RHI graphics abstraction layer is not in use. Refer to
+ resetOpenGLState() in that case.
+
+ \sa endExternalCommands()
+
+ \since 5.14
+ */
+void QQuickWindow::beginExternalCommands()
+{
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+ Q_D(QQuickWindow);
+ if (d->rhi && d->context && d->context->isValid()) {
+ QSGDefaultRenderContext *rc = static_cast<QSGDefaultRenderContext *>(d->context);
+ QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
+ if (cb)
+ cb->beginExternal();
+ }
+#endif
+}
+
+/*!
+ When mixing raw graphics (OpenGL, Vulkan, Metal, etc.) commands with scene
+ graph rendering, it is necessary to call this function after recording
+ commands to the command buffer used by the scene graph to render its main
+ render pass. This is to avoid clobbering state.
+
+ In practice this function is often called from a slot connected to the
+ beforeRenderPassRecording() or afterRenderPassRecording() signals.
+
+ The function does not need to be called when recording commands to the
+ application's own command buffer (such as, a VkCommandBuffer or
+ MTLCommandBuffer + MTLRenderCommandEncoder created and managed by the
+ application, not retrieved from the scene graph). With graphics APIs where
+ no native command buffer concept is exposed (OpenGL, Direct 3D 11),
+ beginExternalCommands() and endExternalCommands() together provide a
+ replacement for resetOpenGLState().
+
+ Calling this function and beginExternalCommands() is not necessary within the
+ \l{QSGRenderNode::render()}{render()} implementation of a QSGRenderNode
+ because the scene graph performs the necessary steps implicitly for render
+ nodes.
+
+ \note This function has no effect when the scene graph is using OpenGL
+ directly and the RHI graphics abstraction layer is not in use. Refer to
+ resetOpenGLState() in that case.
+
+ \sa beginExternalCommands()
+
+ \since 5.14
+ */
+void QQuickWindow::endExternalCommands()
+{
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+ Q_D(QQuickWindow);
+ if (d->rhi && d->context && d->context->isValid()) {
+ QSGDefaultRenderContext *rc = static_cast<QSGDefaultRenderContext *>(d->context);
+ QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
+ if (cb)
+ cb->endExternal();
+ }
+#endif
+}
+
/*!
\qmlproperty string Window::title
@@ -5022,6 +5493,10 @@ void QQuickWindow::setSceneGraphBackend(QSGRendererInterface::GraphicsApi api)
default:
break;
}
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+ if (QSGRendererInterface::isApiRhiBased(api))
+ QSGRhiSupport::configure(api);
+#endif
}
/*!
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 53fe0a4c4b..56d50cec2a 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -66,6 +66,7 @@ class QQuickRenderControl;
class QSGRectangleNode;
class QSGImageNode;
class QSGNinePatchNode;
+class QRhi;
class Q_QUICK_EXPORT QQuickWindow : public QWindow
{
@@ -108,6 +109,11 @@ public:
};
Q_ENUM(TextRenderType)
+ enum NativeObjectType {
+ NativeObjectTexture
+ };
+ Q_ENUM(NativeObjectType)
+
explicit QQuickWindow(QWindow *parent = nullptr);
explicit QQuickWindow(QQuickRenderControl *renderControl);
@@ -135,6 +141,13 @@ public:
#if QT_CONFIG(opengl)
void resetOpenGLState();
#endif
+ struct GraphicsStateInfo {
+ int currentFrameSlot;
+ int framesInFlight;
+ };
+ const GraphicsStateInfo &graphicsStateInfo();
+ void beginExternalCommands();
+ void endExternalCommands();
QQmlIncubationController *incubationController() const;
#if QT_CONFIG(accessibility)
@@ -145,6 +158,11 @@ public:
QSGTexture *createTextureFromImage(const QImage &image) const;
QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options) const;
QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const;
+ QSGTexture *createTextureFromNativeObject(NativeObjectType type,
+ const void *nativeObjectPtr,
+ int nativeLayout,
+ const QSize &size,
+ CreateTextureOptions options = CreateTextureOption()) const;
void setClearBeforeRendering(bool enabled);
bool clearBeforeRendering() const;
@@ -198,6 +216,8 @@ Q_SIGNALS:
Q_REVISION(1) void activeFocusItemChanged();
Q_REVISION(2) void sceneGraphError(QQuickWindow::SceneGraphError error, const QString &message);
+ Q_REVISION(14) void beforeRenderPassRecording();
+ Q_REVISION(14) void afterRenderPassRecording();
public Q_SLOTS:
void update();
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 63760a3b68..165859b5f3 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -82,6 +82,10 @@ class QQuickWindowPrivate;
class QQuickWindowRenderLoop;
class QSGRenderLoop;
class QTouchEvent;
+class QRhi;
+class QRhiSwapChain;
+class QRhiRenderBuffer;
+class QRhiRenderPassDescriptor;
//Make it easy to identify and customize the root item if needed
class QQuickRootItem : public QQuickItem
@@ -130,7 +134,7 @@ public:
#if QT_CONFIG(cursor)
QQuickItem *cursorItem;
#endif
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
QQuickDragGrabber *dragGrabber;
#endif
int touchMouseId;
@@ -186,9 +190,9 @@ public:
Qt::KeyboardModifiers modifiers, ulong timestamp, bool accepted);
bool clearHover(ulong timestamp = 0);
-#if QT_CONFIG(draganddrop)
+#if QT_CONFIG(quick_draganddrop)
void deliverDragEvent(QQuickDragGrabber *, QEvent *);
- bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *);
+ bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *, QVarLengthArray<QQuickItem*, 64> *currentGrabItems = nullptr);
#endif
#if QT_CONFIG(cursor)
void updateCursor(const QPointF &scenePos);
@@ -215,7 +219,7 @@ public:
void polishItems();
void forcePolish();
void syncSceneGraph();
- void renderSceneGraph(const QSize &size);
+ void renderSceneGraph(const QSize &size, const QSize &surfaceSize = QSize());
bool isRenderable() const;
@@ -250,7 +254,7 @@ public:
QSGRenderLoop *windowManager;
QQuickRenderControl *renderControl;
- QQuickAnimatorController *animationController;
+ QScopedPointer<QQuickAnimatorController> animationController;
QScopedPointer<QTouchEvent> delayedTouch;
int pointerEventRecursionGuard;
@@ -317,6 +321,9 @@ public:
QString *untranslatedMessage,
bool isEs);
+ static void emitBeforeRenderPassRecording(void *ud);
+ static void emitAfterRenderPassRecording(void *ud);
+
QMutex renderJobMutex;
QList<QRunnable *> beforeSynchronizingJobs;
QList<QRunnable *> afterSynchronizingJobs;
@@ -326,6 +333,15 @@ public:
void runAndClearJobs(QList<QRunnable *> *jobs);
+ QQuickWindow::GraphicsStateInfo rhiStateInfo;
+ QRhi *rhi = nullptr;
+ QRhiSwapChain *swapchain = nullptr;
+ QRhiRenderBuffer *depthStencilForSwapchain = nullptr;
+ QRhiRenderPassDescriptor *rpDescForSwapchain = nullptr;
+ uint hasActiveSwapchain : 1;
+ uint hasRenderableSwapchain : 1;
+ uint swapchainJustBecameRenderable : 1;
+
private:
static void cleanupNodesOnShutdown(QQuickItem *);
};
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index 2b109c0897..4b2b8f498d 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -205,15 +205,16 @@ void QQuickWindowModule::defineModule()
qmlRegisterRevision<QQuickWindow,1>(uri, 2, 1);//Type moved to a subclass, but also has new members
qmlRegisterRevision<QQuickWindow,2>(uri, 2, 2);
qmlRegisterType<QQuickWindowQmlImpl>(uri, 2, 1, "Window");
- qmlRegisterType<QQuickWindowQmlImpl,1>(uri, 2, 2, "Window");
- qmlRegisterType<QQuickWindowQmlImpl,2>(uri, 2, 3, "Window");
+ qmlRegisterType<QQuickWindowQmlImpl,2>(uri, 2, 2, "Window");
+ qmlRegisterType<QQuickWindowQmlImpl,3>(uri, 2, 3, "Window");
qmlRegisterUncreatableType<QQuickScreen>(uri, 2, 0, "Screen", QStringLiteral("Screen can only be used via the attached property."));
- 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<QQuickScreen,3>(uri, 2, 3, "Screen", QStringLiteral("Screen can only be used via the attached property."));
+ qmlRegisterUncreatableType<QQuickScreenInfo,3>(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");
+ qmlRegisterRevision<QQuickWindow,14>(uri, 2, 14);
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h
index e7033e9b8d..1dcf1a1021 100644
--- a/src/quick/items/qquickwindowmodule_p.h
+++ b/src/quick/items/qquickwindowmodule_p.h
@@ -67,7 +67,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public Q
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
- Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION 2)
+ Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION 3)
public:
QQuickWindowQmlImpl(QWindow *parent = nullptr);
@@ -83,7 +83,7 @@ public:
Q_SIGNALS:
void visibleChanged(bool arg);
void visibilityChanged(QWindow::Visibility visibility);
- Q_REVISION(2) void screenChanged();
+ Q_REVISION(3) void screenChanged();
protected:
void classBegin() override;