aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2019-03-21 20:42:38 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2019-03-21 20:42:47 +0100
commit6767114285db9d0e16dc278d08f231e8561546b4 (patch)
tree0945902a2242fd7ec0a1f7fd3e6acbb769e723bd /src/quick/items
parentee076afedccbe1d37306a7972051f84eb036d655 (diff)
parentc32b109e9dea44c6775c2dbf8f164870c1dc8971 (diff)
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/context2d/qquickcanvascontext_p.h2
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp70
-rw-r--r--src/quick/items/context2d/qquickcanvasitem_p.h20
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp1574
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h9
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp42
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h14
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp69
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture_p.h21
-rw-r--r--src/quick/items/context2d/qquickcontext2dtile.cpp6
-rw-r--r--src/quick/items/context2d/qquickcontext2dtile_p.h2
-rw-r--r--src/quick/items/items.pri22
-rw-r--r--src/quick/items/items.qrc4
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp4
-rw-r--r--src/quick/items/qquickanchors.cpp51
-rw-r--r--src/quick/items/qquickanchors_p.h6
-rw-r--r--src/quick/items/qquickanchors_p_p.h28
-rw-r--r--src/quick/items/qquickanimatedimage.cpp175
-rw-r--r--src/quick/items/qquickanimatedimage_p.h16
-rw-r--r--src/quick/items/qquickanimatedimage_p_p.h21
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp127
-rw-r--r--src/quick/items/qquickanimatedsprite_p.h8
-rw-r--r--src/quick/items/qquickborderimage.cpp36
-rw-r--r--src/quick/items/qquickborderimage_p.h12
-rw-r--r--src/quick/items/qquickdrag.cpp29
-rw-r--r--src/quick/items/qquickdrag_p.h10
-rw-r--r--src/quick/items/qquickdroparea.cpp10
-rw-r--r--src/quick/items/qquickdroparea_p.h8
-rw-r--r--src/quick/items/qquickevents.cpp1244
-rw-r--r--src/quick/items/qquickevents_p_p.h398
-rw-r--r--src/quick/items/qquickflickable.cpp224
-rw-r--r--src/quick/items/qquickflickable_p.h43
-rw-r--r--src/quick/items/qquickflickable_p_p.h18
-rw-r--r--src/quick/items/qquickflipable.cpp10
-rw-r--r--src/quick/items/qquickflipable_p.h4
-rw-r--r--src/quick/items/qquickfocusscope.cpp2
-rw-r--r--src/quick/items/qquickfocusscope_p.h2
-rw-r--r--src/quick/items/qquickframebufferobject.cpp45
-rw-r--r--src/quick/items/qquickframebufferobject.h12
-rw-r--r--src/quick/items/qquickgenericshadereffect.cpp9
-rw-r--r--src/quick/items/qquickgenericshadereffect_p.h2
-rw-r--r--src/quick/items/qquickgraphicsinfo.cpp4
-rw-r--r--src/quick/items/qquickgridview.cpp101
-rw-r--r--src/quick/items/qquickgridview_p.h2
-rw-r--r--src/quick/items/qquickimage.cpp111
-rw-r--r--src/quick/items/qquickimage_p.h18
-rw-r--r--src/quick/items/qquickimage_p_p.h18
-rw-r--r--src/quick/items/qquickimagebase_p.h8
-rw-r--r--src/quick/items/qquickimplicitsizeitem.cpp26
-rw-r--r--src/quick/items/qquickimplicitsizeitem_p.h8
-rw-r--r--src/quick/items/qquickimplicitsizeitem_p_p.h3
-rw-r--r--src/quick/items/qquickitem.cpp678
-rw-r--r--src/quick/items/qquickitem.h27
-rw-r--r--src/quick/items/qquickitem_p.h140
-rw-r--r--src/quick/items/qquickitemanimation.cpp20
-rw-r--r--src/quick/items/qquickitemanimation_p.h12
-rw-r--r--src/quick/items/qquickitemanimation_p_p.h10
-rw-r--r--src/quick/items/qquickitemchangelistener_p.h3
-rw-r--r--src/quick/items/qquickitemgrabresult.cpp22
-rw-r--r--src/quick/items/qquickitemgrabresult.h2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp96
-rw-r--r--src/quick/items/qquickitemview.cpp363
-rw-r--r--src/quick/items/qquickitemview_p.h3
-rw-r--r--src/quick/items/qquickitemview_p_p.h51
-rw-r--r--src/quick/items/qquickitemviewfxitem.cpp165
-rw-r--r--src/quick/items/qquickitemviewfxitem_p_p.h108
-rw-r--r--src/quick/items/qquickitemviewtransition.cpp52
-rw-r--r--src/quick/items/qquickitemviewtransition_p.h18
-rw-r--r--src/quick/items/qquicklistview.cpp260
-rw-r--r--src/quick/items/qquicklistview_p.h6
-rw-r--r--src/quick/items/qquickloader.cpp106
-rw-r--r--src/quick/items/qquickloader_p.h7
-rw-r--r--src/quick/items/qquickloader_p_p.h17
-rw-r--r--src/quick/items/qquickmousearea.cpp27
-rw-r--r--src/quick/items/qquickmousearea_p.h32
-rw-r--r--src/quick/items/qquickmousearea_p_p.h3
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp67
-rw-r--r--src/quick/items/qquickmultipointtoucharea_p.h69
-rw-r--r--src/quick/items/qquickopenglinfo.cpp8
-rw-r--r--src/quick/items/qquickopenglshadereffect.cpp68
-rw-r--r--src/quick/items/qquickopenglshadereffect_p.h4
-rw-r--r--src/quick/items/qquickopenglshadereffectnode.cpp32
-rw-r--r--src/quick/items/qquickopenglshadereffectnode_p.h14
-rw-r--r--src/quick/items/qquickpainteditem.cpp26
-rw-r--r--src/quick/items/qquickpainteditem.h17
-rw-r--r--src/quick/items/qquickpathview.cpp46
-rw-r--r--src/quick/items/qquickpathview_p.h1
-rw-r--r--src/quick/items/qquickpathview_p_p.h1
-rw-r--r--src/quick/items/qquickpincharea.cpp10
-rw-r--r--src/quick/items/qquickpincharea_p.h14
-rw-r--r--src/quick/items/qquickpositioners.cpp50
-rw-r--r--src/quick/items/qquickpositioners_p.h32
-rw-r--r--src/quick/items/qquickpositioners_p_p.h10
-rw-r--r--src/quick/items/qquickrectangle.cpp132
-rw-r--r--src/quick/items/qquickrectangle_p.h29
-rw-r--r--src/quick/items/qquickrectangle_p_p.h2
-rw-r--r--src/quick/items/qquickrendercontrol.cpp38
-rw-r--r--src/quick/items/qquickrendercontrol.h8
-rw-r--r--src/quick/items/qquickrepeater.cpp44
-rw-r--r--src/quick/items/qquickrepeater_p.h10
-rw-r--r--src/quick/items/qquickrepeater_p_p.h2
-rw-r--r--src/quick/items/qquickscalegrid.cpp4
-rw-r--r--src/quick/items/qquickscalegrid_p_p.h14
-rw-r--r--src/quick/items/qquickscreen.cpp46
-rw-r--r--src/quick/items/qquickshadereffect.cpp6
-rw-r--r--src/quick/items/qquickshadereffect_p.h2
-rw-r--r--src/quick/items/qquickshadereffectmesh.cpp7
-rw-r--r--src/quick/items/qquickshadereffectmesh_p.h19
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp36
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h16
-rw-r--r--src/quick/items/qquicksprite.cpp20
-rw-r--r--src/quick/items/qquicksprite_p.h18
-rw-r--r--src/quick/items/qquickspriteengine.cpp61
-rw-r--r--src/quick/items/qquickspriteengine_p.h34
-rw-r--r--src/quick/items/qquickspritesequence.cpp31
-rw-r--r--src/quick/items/qquickspritesequence_p.h4
-rw-r--r--src/quick/items/qquickstateoperations.cpp54
-rw-r--r--src/quick/items/qquickstateoperations_p.h52
-rw-r--r--src/quick/items/qquicktableview.cpp2301
-rw-r--r--src/quick/items/qquicktableview_p.h176
-rw-r--r--src/quick/items/qquicktableview_p_p.h414
-rw-r--r--src/quick/items/qquicktext.cpp168
-rw-r--r--src/quick/items/qquicktext_p.h42
-rw-r--r--src/quick/items/qquicktext_p_p.h13
-rw-r--r--src/quick/items/qquicktextcontrol.cpp16
-rw-r--r--src/quick/items/qquicktextcontrol_p.h6
-rw-r--r--src/quick/items/qquicktextdocument.cpp2
-rw-r--r--src/quick/items/qquicktextedit.cpp175
-rw-r--r--src/quick/items/qquicktextedit_p.h49
-rw-r--r--src/quick/items/qquicktextedit_p_p.h29
-rw-r--r--src/quick/items/qquicktextinput.cpp94
-rw-r--r--src/quick/items/qquicktextinput_p.h40
-rw-r--r--src/quick/items/qquicktextinput_p_p.h22
-rw-r--r--src/quick/items/qquicktextnode.cpp14
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp99
-rw-r--r--src/quick/items/qquicktextnodeengine_p.h2
-rw-r--r--src/quick/items/qquicktextutil.cpp2
-rw-r--r--src/quick/items/qquicktextutil_p.h16
-rw-r--r--src/quick/items/qquicktranslate.cpp9
-rw-r--r--src/quick/items/qquicktranslate_p.h16
-rw-r--r--src/quick/items/qquickview.cpp38
-rw-r--r--src/quick/items/qquickview.h8
-rw-r--r--src/quick/items/qquickview_p.h2
-rw-r--r--src/quick/items/qquickwindow.cpp1356
-rw-r--r--src/quick/items/qquickwindow.h56
-rw-r--r--src/quick/items/qquickwindow_p.h57
-rw-r--r--src/quick/items/qquickwindowattached.cpp6
-rw-r--r--src/quick/items/qquickwindowattached_p.h3
-rw-r--r--src/quick/items/qquickwindowmodule.cpp25
-rw-r--r--src/quick/items/qquickwindowmodule_p.h11
-rw-r--r--src/quick/items/shaders/lineargradient.frag9
-rw-r--r--src/quick/items/shaders/lineargradient.vert15
-rw-r--r--src/quick/items/shaders/lineargradient_core.frag12
-rw-r--r--src/quick/items/shaders/lineargradient_core.vert17
154 files changed, 9924 insertions, 3490 deletions
diff --git a/src/quick/items/context2d/qquickcanvascontext_p.h b/src/quick/items/context2d/qquickcanvascontext_p.h
index 0746b7dcd3..95100d2912 100644
--- a/src/quick/items/context2d/qquickcanvascontext_p.h
+++ b/src/quick/items/context2d/qquickcanvascontext_p.h
@@ -69,7 +69,7 @@ class QQuickCanvasContext : public QObject
Q_OBJECT
public:
- QQuickCanvasContext(QObject *parent = 0);
+ QQuickCanvasContext(QObject *parent = nullptr);
~QQuickCanvasContext();
virtual QStringList contextNames() const = 0;
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index 670dc6d032..14443a2f2f 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -57,6 +57,7 @@
#include <private/qv4value_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4scopedvalue_p.h>
+#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
QT_BEGIN_NAMESPACE
@@ -65,12 +66,12 @@ class QQuickCanvasTextureProvider : public QSGTextureProvider
{
public:
QSGTexture *tex;
- QSGTexture *texture() const Q_DECL_OVERRIDE { return tex; }
+ QSGTexture *texture() const override { return tex; }
void fireTextureChanged() { emit textureChanged(); }
};
QQuickCanvasPixmap::QQuickCanvasPixmap(const QImage& image)
- : m_pixmap(0)
+ : m_pixmap(nullptr)
, m_image(image)
{
@@ -122,7 +123,7 @@ QHash<QQmlEngine *,QQuickContext2DRenderThread*> QQuickContext2DRenderThread::re
QMutex QQuickContext2DRenderThread::renderThreadsMutex;
QQuickContext2DRenderThread::QQuickContext2DRenderThread(QQmlEngine *eng)
- : QThread(eng), m_engine(eng), m_eventLoopQuitHack(0)
+ : QThread(eng), m_engine(eng), m_eventLoopQuitHack(nullptr)
{
Q_ASSERT(eng);
m_eventLoopQuitHack = new QObject;
@@ -143,7 +144,7 @@ QQuickContext2DRenderThread::~QQuickContext2DRenderThread()
QQuickContext2DRenderThread *QQuickContext2DRenderThread::instance(QQmlEngine *engine)
{
- QQuickContext2DRenderThread *thread = 0;
+ QQuickContext2DRenderThread *thread = nullptr;
renderThreadsMutex.lock();
if (renderThreads.contains(engine))
thread = renderThreads.value(engine);
@@ -182,7 +183,7 @@ public:
QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
: QQuickItemPrivate()
- , context(0)
+ , context(nullptr)
, canvasSize(1, 1)
, tileSize(1, 1)
, hasCanvasSize(false)
@@ -191,9 +192,9 @@ QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
, available(false)
, renderTarget(QQuickCanvasItem::Image)
, renderStrategy(QQuickCanvasItem::Immediate)
- , textureProvider(0)
- , node(0)
- , nodeTexture(0)
+ , textureProvider(nullptr)
+ , node(nullptr)
+ , nodeTexture(nullptr)
{
implicitAntialiasing = true;
}
@@ -212,7 +213,7 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
\inherits Item
\ingroup qtquick-canvas
\ingroup qtquick-visual
- \brief Provides a 2D canvas item enabling drawing via JavaScript
+ \brief Provides a 2D canvas item enabling drawing via JavaScript.
The Canvas item allows drawing of straight and curved lines, simple and
complex shapes, graphs, and referenced graphic images. It can also add
@@ -633,16 +634,16 @@ void QQuickCanvasItem::releaseResources()
if (d->context) {
delete d->context;
- d->context = 0;
+ d->context = nullptr;
}
- d->node = 0; // managed by the scene graph, just reset the pointer
+ d->node = nullptr; // managed by the scene graph, just reset the pointer
if (d->textureProvider) {
QQuickWindowQObjectCleanupJob::schedule(window(), d->textureProvider);
- d->textureProvider = 0;
+ d->textureProvider = nullptr;
}
if (d->nodeTexture) {
QQuickWindowQObjectCleanupJob::schedule(window(), d->nodeTexture);
- d->nodeTexture = 0;
+ d->nodeTexture = nullptr;
}
}
@@ -662,12 +663,12 @@ void QQuickCanvasItem::invalidateSceneGraph()
Q_D(QQuickCanvasItem);
if (d->context)
d->context->deleteLater();
- d->context = 0;
- d->node = 0; // managed by the scene graph, just reset the pointer
+ d->context = nullptr;
+ d->node = nullptr; // managed by the scene graph, just reset the pointer
delete d->textureProvider;
- d->textureProvider = 0;
+ d->textureProvider = nullptr;
delete d->nodeTexture;
- d->nodeTexture = 0;
+ d->nodeTexture = nullptr;
}
void QQuickCanvasItem::schedulePolish()
@@ -697,14 +698,14 @@ void QQuickCanvasItem::itemChange(QQuickItem::ItemChange change, const QQuickIte
return;
}
- if (value.window== 0)
+ if (value.window== nullptr)
return;
d->window = value.window;
QSGRenderContext *context = QQuickWindowPrivate::get(d->window)->context;
// Rendering to FramebufferObject needs a valid OpenGL context.
- if (context != 0 && (d->renderTarget != FramebufferObject || context->isValid())) {
+ if (context != nullptr && (d->renderTarget != FramebufferObject || context->isValid())) {
// Defer the call. In some (arguably incorrect) cases we get here due
// to ItemSceneChange with the user-supplied property values not yet
// set. Work this around by a deferred invoke. (QTBUG-49692)
@@ -726,15 +727,16 @@ void QQuickCanvasItem::updatePolish()
QMap<int, QV4::PersistentValue> animationCallbacks = d->animationCallbacks;
d->animationCallbacks.clear();
- QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(qmlEngine(this));
+ QV4::ExecutionEngine *v4 = qmlEngine(this)->handle();
QV4::Scope scope(v4);
- QV4::ScopedCallData callData(scope, 1);
- callData->thisObject = QV4::QObjectWrapper::wrap(v4, this);
+ QV4::ScopedFunctionObject function(scope);
+ QV4::JSCallData jsCall(scope, 1);
+ *jsCall->thisObject = QV4::QObjectWrapper::wrap(v4, this);
for (auto it = animationCallbacks.cbegin(), end = animationCallbacks.cend(); it != end; ++it) {
- QV4::ScopedFunctionObject f(scope, it.value().value());
- callData->args[0] = QV4::Primitive::fromUInt32(QDateTime::currentMSecsSinceEpoch() / 1000);
- f->call(scope, callData);
+ function = it.value().value();
+ jsCall->args[0] = QV4::Value::fromUInt32(QDateTime::currentMSecsSinceEpoch());
+ function->call(jsCall);
}
}
else {
@@ -761,11 +763,11 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
if (!d->context || d->canvasWindow.size().isEmpty()) {
if (d->textureProvider) {
- d->textureProvider->tex = 0;
+ d->textureProvider->tex = nullptr;
d->textureProvider->fireTextureChanged();
}
delete oldNode;
- return 0;
+ return nullptr;
}
QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
@@ -790,13 +792,13 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
QSGTexture *texture = factory->textureForNextFrame(d->nodeTexture, window());
if (!texture) {
delete node;
- d->node = 0;
- d->nodeTexture = 0;
+ d->node = nullptr;
+ d->nodeTexture = nullptr;
if (d->textureProvider) {
- d->textureProvider->tex = 0;
+ d->textureProvider->tex = nullptr;
d->textureProvider->fireTextureChanged();
}
- return 0;
+ return nullptr;
}
d->nodeTexture = texture;
@@ -831,7 +833,7 @@ QSGTextureProvider *QQuickCanvasItem::textureProvider() const
if (!w || !w->isSceneGraphInitialized()
|| QThread::currentThread() != QQuickWindowPrivate::get(w)->context->thread()) {
qWarning("QQuickCanvasItem::textureProvider: can only be queried on the rendering thread of an exposed window");
- return 0;
+ return nullptr;
}
#endif
if (!d->textureProvider)
@@ -877,7 +879,7 @@ void QQuickCanvasItem::getContext(QQmlV4Function *args)
QString contextId = str->toQString();
- if (d->context != 0) {
+ if (d->context != nullptr) {
if (d->context->contextNames().contains(contextId, Qt::CaseInsensitive)) {
args->setReturnValue(d->context->v4value());
return;
@@ -1208,7 +1210,7 @@ void QQuickCanvasItem::initializeContext(QQuickCanvasContext *context, const QVa
d->context = context;
d->context->init(this, args);
- d->context->setV4Engine(QQmlEnginePrivate::get(qmlEngine(this))->v4engine());
+ d->context->setV4Engine(qmlEngine(this)->handle());
connect(d->context, SIGNAL(textureChanged()), SLOT(update()));
connect(d->context, SIGNAL(textureChanged()), SIGNAL(painted()));
emit contextChanged();
diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h
index 217ae9bb69..7dc981a6eb 100644
--- a/src/quick/items/context2d/qquickcanvasitem_p.h
+++ b/src/quick/items/context2d/qquickcanvasitem_p.h
@@ -114,7 +114,7 @@ public:
};
Q_ENUM(RenderStrategy)
- QQuickCanvasItem(QQuickItem *parent = 0);
+ QQuickCanvasItem(QQuickItem *parent = nullptr);
~QQuickCanvasItem();
bool isAvailable() const;
@@ -155,8 +155,8 @@ public:
Q_INVOKABLE QString toDataURL(const QString& type = QLatin1String("image/png")) const;
QQmlRefPointer<QQuickCanvasPixmap> loadedPixmap(const QUrl& url);
- bool isTextureProvider() const Q_DECL_OVERRIDE;
- QSGTextureProvider *textureProvider() const Q_DECL_OVERRIDE;
+ bool isTextureProvider() const override;
+ QSGTextureProvider *textureProvider() const override;
Q_SIGNALS:
void paint(const QRect &region);
@@ -185,13 +185,13 @@ private Q_SLOTS:
void schedulePolish();
protected:
- void componentComplete() Q_DECL_OVERRIDE;
- void itemChange(QQuickItem::ItemChange, const QQuickItem::ItemChangeData &) Q_DECL_OVERRIDE;
- void updatePolish() Q_DECL_OVERRIDE;
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
- void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
- void releaseResources() Q_DECL_OVERRIDE;
- bool event(QEvent *event) Q_DECL_OVERRIDE;
+ void componentComplete() override;
+ void itemChange(QQuickItem::ItemChange, const QQuickItem::ItemChangeData &) override;
+ void updatePolish() override;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void releaseResources() override;
+ bool event(QEvent *event) override;
private:
Q_DECLARE_PRIVATE(QQuickCanvasItem)
Q_INVOKABLE void delayedCreate();
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 9ac7422a39..546f3011ec 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -95,7 +95,7 @@ QT_BEGIN_NAMESPACE
\inqmlmodule QtQuick
\ingroup qtquick-canvas
\since 5.0
- \brief Provides 2D context for shapes on a Canvas item
+ \brief Provides 2D context for shapes on a Canvas item.
The Context2D object can be created by \c Canvas item's \c getContext()
method:
@@ -130,10 +130,10 @@ QT_BEGIN_NAMESPACE
Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
-#define CHECK_CONTEXT(r) if (!r || !r->d()->context || !r->d()->context->bufferValid()) \
+#define CHECK_CONTEXT(r) if (!r || !r->d()->context() || !r->d()->context()->bufferValid()) \
THROW_GENERIC_ERROR("Not a Context2D object");
-#define CHECK_CONTEXT_SETTER(r) if (!r || !r->d()->context || !r->d()->context->bufferValid()) \
+#define CHECK_CONTEXT_SETTER(r) if (!r || !r->d()->context() || !r->d()->context()->bufferValid()) \
THROW_GENERIC_ERROR("Not a Context2D object");
#define qClamp(val, min, max) qMin(qMax(val, min), max)
#define CHECK_RGBA(c) (c == '-' || c == '.' || (c >=0 && c <= 9))
@@ -304,7 +304,7 @@ static QStringList qExtractFontFamiliesFromString(const QStringRef &fontFamilies
return extractedFamilies;
}
-/*!
+/*
Tries to set a family on \a font using the families provided in \a fontFamilyTokens.
The list is ordered by preference, with the first family having the highest preference.
@@ -364,7 +364,7 @@ if (!(usedTokens & token)) { \
return currentFont; \
}
-/*!
+/*
Parses a font string based on the CSS shorthand font property.
See: http://www.w3.org/TR/css3-fonts/#font-prop
@@ -491,8 +491,29 @@ namespace QV4 {
namespace Heap {
struct QQuickJSContext2D : Object {
- void init() { Object::init(); }
- QQuickContext2D* context;
+ void init()
+ {
+ Object::init();
+ m_context = nullptr;
+ }
+
+ void destroy()
+ {
+ delete m_context;
+ Object::destroy();
+ }
+
+ QQuickContext2D *context() { return m_context ? *m_context : nullptr; }
+ void setContext(QQuickContext2D *context)
+ {
+ if (m_context)
+ *m_context = context;
+ else
+ m_context = new QPointer<QQuickContext2D>(context);
+ }
+
+private:
+ QPointer<QQuickContext2D>* m_context;
};
struct QQuickJSContext2DPrototype : Object {
@@ -529,6 +550,11 @@ struct QQuickJSContext2DPixelData : Object {
struct QQuickJSContext2DImageData : Object {
void init();
+ static void markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack) {
+ static_cast<QQuickJSContext2DImageData *>(that)->pixelData.mark(markStack);
+ Object::markObjects(that, markStack);
+ }
+
QV4::Value pixelData;
};
@@ -538,47 +564,50 @@ struct QQuickJSContext2DImageData : Object {
struct QQuickJSContext2D : public QV4::Object
{
V4_OBJECT2(QQuickJSContext2D, QV4::Object)
+ V4_NEEDS_DESTROY
- static void method_get_globalAlpha(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_globalAlpha(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_globalCompositeOperation(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_globalCompositeOperation(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_fillStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_fillStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
-
- static void method_get_lineCap(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_lineCap(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_lineJoin(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_lineJoin(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_lineWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_lineWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
-
- static void method_get_shadowBlur(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_shadowBlur(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_shadowColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_shadowColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_shadowOffsetX(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_shadowOffsetX(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static QV4::ReturnedValue method_get_globalAlpha(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_globalAlpha(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_globalCompositeOperation(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_globalCompositeOperation(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_fillStyle(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_fillStyle(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_fillRule(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_fillRule(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_strokeStyle(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_strokeStyle(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+
+ static QV4::ReturnedValue method_get_lineCap(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_lineCap(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_lineJoin(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_lineJoin(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_lineWidth(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_lineWidth(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_miterLimit(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_miterLimit(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+
+ static QV4::ReturnedValue method_get_shadowBlur(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_shadowBlur(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_shadowColor(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_shadowColor(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_shadowOffsetX(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_shadowOffsetX(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_shadowOffsetY(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_shadowOffsetY(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
// should these two be on the proto?
#if QT_CONFIG(quick_path)
- static void method_get_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static QV4::ReturnedValue method_get_path(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_path(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
#endif
- static void method_get_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_textAlign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_textAlign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_textBaseline(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_set_textBaseline(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static QV4::ReturnedValue method_get_font(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_font(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_textAlign(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_textAlign(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_textBaseline(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_textBaseline(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
};
DEFINE_OBJECT_VTABLE(QQuickJSContext2D);
@@ -591,7 +620,7 @@ public:
static QV4::Heap::QQuickJSContext2DPrototype *create(QV4::ExecutionEngine *engine)
{
QV4::Scope scope(engine);
- QV4::Scoped<QQuickJSContext2DPrototype> o(scope, engine->memoryManager->allocObject<QQuickJSContext2DPrototype>());
+ QV4::Scoped<QQuickJSContext2DPrototype> o(scope, engine->memoryManager->allocate<QQuickJSContext2DPrototype>());
o->defineDefaultProperty(QStringLiteral("quadraticCurveTo"), method_quadraticCurveTo, 0);
o->defineDefaultProperty(QStringLiteral("restore"), method_restore, 0);
@@ -636,55 +665,59 @@ public:
o->defineDefaultProperty(QStringLiteral("createLinearGradient"), method_createLinearGradient, 0);
o->defineDefaultProperty(QStringLiteral("strokeRect"), method_strokeRect, 0);
o->defineDefaultProperty(QStringLiteral("closePath"), method_closePath, 0);
- o->defineAccessorProperty(QStringLiteral("canvas"), QQuickJSContext2DPrototype::method_get_canvas, 0);
+ o->defineDefaultProperty(QStringLiteral("setLineDash"), method_setLineDash, 0);
+ o->defineDefaultProperty(QStringLiteral("getLineDash"), method_getLineDash, 0);
+ o->defineAccessorProperty(QStringLiteral("canvas"), QQuickJSContext2DPrototype::method_get_canvas, nullptr);
return o->d();
}
- static void method_get_canvas(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_restore(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_reset(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_save(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_rotate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_scale(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_translate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_setTransform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_transform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_resetTransform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_shear(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_createLinearGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_createRadialGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_createConicalGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_createPattern(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_clearRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_fillRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_strokeRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_arc(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_arcTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_beginPath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_bezierCurveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_clip(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_closePath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_fill(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_lineTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_moveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_quadraticCurveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_rect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_roundedRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_ellipse(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_text(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_stroke(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_isPointInPath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_drawFocusRing(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_setCaretSelectionRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_caretBlinkRate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_fillText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_strokeText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_measureText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_drawImage(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_createImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_getImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_putImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static QV4::ReturnedValue method_get_canvas(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_restore(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_reset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_save(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_rotate(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_scale(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_translate(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_setTransform(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_transform(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_resetTransform(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_shear(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_createLinearGradient(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_createRadialGradient(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_createConicalGradient(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_createPattern(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_clearRect(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_fillRect(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_strokeRect(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_arc(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_arcTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_beginPath(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_bezierCurveTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_clip(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_closePath(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_fill(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_lineTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_moveTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_quadraticCurveTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_rect(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_roundedRect(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_ellipse(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_text(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_stroke(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_isPointInPath(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_drawFocusRing(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_setCaretSelectionRect(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_caretBlinkRate(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_fillText(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_strokeText(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_measureText(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_drawImage(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_createImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_getImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_putImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_setLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_getLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
};
@@ -696,7 +729,7 @@ struct QQuickContext2DStyle : public QV4::Object
V4_OBJECT2(QQuickContext2DStyle, QV4::Object)
V4_NEEDS_DESTROY
- static void gradient_proto_addColorStop(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static QV4::ReturnedValue gradient_proto_addColorStop(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
};
@@ -903,10 +936,10 @@ struct QQuickJSContext2DPixelData : public QV4::Object
V4_OBJECT2(QQuickJSContext2DPixelData, QV4::Object)
V4_NEEDS_DESTROY
- static QV4::ReturnedValue getIndexed(const QV4::Managed *m, uint index, bool *hasProperty);
- static bool putIndexed(QV4::Managed *m, uint index, const QV4::Value &value);
+ static QV4::ReturnedValue virtualGet(const QV4::Managed *m, QV4::PropertyKey id, const QV4::Value *receiver, bool *hasProperty);
+ static bool virtualPut(QV4::Managed *m, QV4::PropertyKey id, const QV4::Value &value, Value *receiver);
- static void proto_get_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static QV4::ReturnedValue proto_get_length(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
};
void QV4::Heap::QQuickJSContext2DPixelData::init()
@@ -924,27 +957,23 @@ struct QQuickJSContext2DImageData : public QV4::Object
{
V4_OBJECT2(QQuickJSContext2DImageData, QV4::Object)
- static void method_get_width(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_height(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void method_get_data(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static QV4::ReturnedValue method_get_width(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_height(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_get_data(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static void markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack) {
- static_cast<QQuickJSContext2DImageData::Data *>(that)->pixelData.mark(markStack);
- QV4::Object::markObjects(that, markStack);
- }
};
void QV4::Heap::QQuickJSContext2DImageData::init()
{
Object::init();
- pixelData = QV4::Primitive::undefinedValue();
+ pixelData = QV4::Value::undefinedValue();
QV4::Scope scope(internalClass->engine);
QV4::ScopedObject o(scope, this);
- o->defineAccessorProperty(QStringLiteral("width"), ::QQuickJSContext2DImageData::method_get_width, 0);
- o->defineAccessorProperty(QStringLiteral("height"), ::QQuickJSContext2DImageData::method_get_height, 0);
- o->defineAccessorProperty(QStringLiteral("data"), ::QQuickJSContext2DImageData::method_get_data, 0);
+ o->defineAccessorProperty(QStringLiteral("width"), ::QQuickJSContext2DImageData::method_get_width, nullptr);
+ o->defineAccessorProperty(QStringLiteral("height"), ::QQuickJSContext2DImageData::method_get_height, nullptr);
+ o->defineAccessorProperty(QStringLiteral("data"), ::QQuickJSContext2DImageData::method_get_data, nullptr);
}
DEFINE_OBJECT_VTABLE(QQuickJSContext2DImageData);
@@ -953,19 +982,19 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE
{
QV4::Scope scope(v4);
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, scope.engine->memoryManager->allocObject<QQuickJSContext2DPixelData>());
+ QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, scope.engine->memoryManager->allocate<QQuickJSContext2DPixelData>());
QV4::ScopedObject p(scope, ed->pixelArrayProto.value());
- pixelData->setPrototype(p);
+ pixelData->setPrototypeOf(p);
if (image.isNull()) {
*pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32);
pixelData->d()->image->fill(0x00000000);
} else {
- Q_ASSERT(image.width()== qRound(w * image.devicePixelRatio()) && image.height() == qRound(h * image.devicePixelRatio()));
+ Q_ASSERT(image.width()== qRound(w * image.devicePixelRatioF()) && image.height() == qRound(h * image.devicePixelRatioF()));
*pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
}
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, scope.engine->memoryManager->allocObject<QQuickJSContext2DImageData>());
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, scope.engine->memoryManager->allocate<QQuickJSContext2DImageData>());
imageData->d()->pixelData = pixelData.asReturnedValue();
return imageData.asReturnedValue();
}
@@ -978,12 +1007,13 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE
This property is read only.
*/
-void QQuickJSContext2DPrototype::method_get_canvas(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_get_canvas(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- scope.result = QV4::QObjectWrapper::wrap(scope.engine, r->d()->context->canvas());
+ RETURN_RESULT(QV4::QObjectWrapper::wrap(scope.engine, r->d()->context()->canvas()));
}
/*!
@@ -992,27 +1022,29 @@ void QQuickJSContext2DPrototype::method_get_canvas(const QV4::BuiltinFunction *,
\sa save()
*/
-void QQuickJSContext2DPrototype::method_restore(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_restore(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- r->d()->context->popState();
- scope.result = callData->thisObject.asReturnedValue();
+ r->d()->context()->popState();
+ RETURN_RESULT(thisObject->asReturnedValue());
}
/*!
\qmlmethod object QtQuick::Context2D::reset()
Resets the context state and properties to the default values.
*/
-void QQuickJSContext2DPrototype::method_reset(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_reset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- r->d()->context->reset();
+ r->d()->context()->reset();
- scope.result = callData->thisObject.asReturnedValue();
+ RETURN_RESULT(thisObject->asReturnedValue());
}
/*!
@@ -1045,14 +1077,15 @@ void QQuickJSContext2DPrototype::method_reset(const QV4::BuiltinFunction *, QV4:
The current path is NOT part of the drawing state. The path can be reset by
invoking the beginPath() method.
*/
-void QQuickJSContext2DPrototype::method_save(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_save(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- r->d()->context->pushState();
+ r->d()->context()->pushState();
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
// transformations
@@ -1073,14 +1106,15 @@ void QQuickJSContext2DPrototype::method_save(const QV4::BuiltinFunction *, QV4::
where the \a angle of rotation is in radians.
*/
-void QQuickJSContext2DPrototype::method_rotate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_rotate(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc >= 1)
- r->d()->context->rotate(callData->args[0].toNumber());
- scope.result = callData->thisObject;
+ if (argc >= 1)
+ r->d()->context()->rotate(argv[0].toNumber());
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -1100,15 +1134,16 @@ void QQuickJSContext2DPrototype::method_rotate(const QV4::BuiltinFunction *, QV4
\image qml-item-canvas-scale.png
*/
-void QQuickJSContext2DPrototype::method_scale(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_scale(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc >= 2)
- r->d()->context->scale(callData->args[0].toNumber(), callData->args[1].toNumber());
- scope.result = callData->thisObject;
+ if (argc >= 2)
+ r->d()->context()->scale(argv[0].toNumber(), argv[1].toNumber());
+ RETURN_RESULT(*thisObject);
}
@@ -1146,21 +1181,22 @@ void QQuickJSContext2DPrototype::method_scale(const QV4::BuiltinFunction *, QV4:
\sa transform()
*/
-void QQuickJSContext2DPrototype::method_setTransform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_setTransform(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc >= 6)
- r->d()->context->setTransform( callData->args[0].toNumber()
- , callData->args[1].toNumber()
- , callData->args[2].toNumber()
- , callData->args[3].toNumber()
- , callData->args[4].toNumber()
- , callData->args[5].toNumber());
+ if (argc >= 6)
+ r->d()->context()->setTransform( argv[0].toNumber()
+ , argv[1].toNumber()
+ , argv[2].toNumber()
+ , argv[3].toNumber()
+ , argv[4].toNumber()
+ , argv[5].toNumber());
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
@@ -1175,20 +1211,21 @@ void QQuickJSContext2DPrototype::method_setTransform(const QV4::BuiltinFunction
\sa setTransform()
*/
-void QQuickJSContext2DPrototype::method_transform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_transform(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc >= 6)
- r->d()->context->transform( callData->args[0].toNumber()
- , callData->args[1].toNumber()
- , callData->args[2].toNumber()
- , callData->args[3].toNumber()
- , callData->args[4].toNumber()
- , callData->args[5].toNumber());
+ if (argc >= 6)
+ r->d()->context()->transform( argv[0].toNumber()
+ , argv[1].toNumber()
+ , argv[2].toNumber()
+ , argv[3].toNumber()
+ , argv[4].toNumber()
+ , argv[5].toNumber());
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
@@ -1201,14 +1238,15 @@ void QQuickJSContext2DPrototype::method_transform(const QV4::BuiltinFunction *,
Translating the origin enables you to draw patterns of different objects on the canvas
without having to measure the coordinates manually for each shape.
*/
-void QQuickJSContext2DPrototype::method_translate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_translate(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc >= 2)
- r->d()->context->translate(callData->args[0].toNumber(), callData->args[1].toNumber());
- scope.result = callData->thisObject;
+ if (argc >= 2)
+ r->d()->context()->translate(argv[0].toNumber(), argv[1].toNumber());
+ RETURN_RESULT(*thisObject);
}
@@ -1221,14 +1259,15 @@ void QQuickJSContext2DPrototype::method_translate(const QV4::BuiltinFunction *,
\sa transform(), setTransform(), reset()
*/
-void QQuickJSContext2DPrototype::method_resetTransform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_resetTransform(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- r->d()->context->setTransform(1, 0, 0, 1, 0, 0);
+ r->d()->context()->setTransform(1, 0, 0, 1, 0, 0);
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
@@ -1239,15 +1278,16 @@ void QQuickJSContext2DPrototype::method_resetTransform(const QV4::BuiltinFunctio
Shears the transformation matrix by \a sh in the horizontal direction and
\a sv in the vertical direction.
*/
-void QQuickJSContext2DPrototype::method_shear(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_shear(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc >= 2)
- r->d()->context->shear(callData->args[0].toNumber(), callData->args[1].toNumber());
+ if (argc >= 2)
+ r->d()->context()->shear(argv[0].toNumber(), argv[1].toNumber());
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
// compositing
@@ -1259,30 +1299,32 @@ void QQuickJSContext2DPrototype::method_shear(const QV4::BuiltinFunction *, QV4:
The value must be in the range from \c 0.0 (fully transparent) to \c 1.0 (fully opaque).
The default value is \c 1.0.
*/
-void QQuickJSContext2D::method_get_globalAlpha(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_globalAlpha(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- scope.result = QV4::Encode(r->d()->context->state.globalAlpha);
+ RETURN_RESULT(QV4::Encode(r->d()->context()->state.globalAlpha));
}
-void QQuickJSContext2D::method_set_globalAlpha(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_globalAlpha(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- double globalAlpha = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double globalAlpha = argc ? argv[0].toNumber() : qt_qnan();
- scope.result = QV4::Encode::undefined();
if (!qt_is_finite(globalAlpha))
- return;
+ RETURN_UNDEFINED();
- if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->d()->context->state.globalAlpha != globalAlpha) {
- r->d()->context->state.globalAlpha = globalAlpha;
- r->d()->context->buffer()->setGlobalAlpha(r->d()->context->state.globalAlpha);
+ if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->d()->context()->state.globalAlpha != globalAlpha) {
+ r->d()->context()->state.globalAlpha = globalAlpha;
+ r->d()->context()->buffer()->setGlobalAlpha(r->d()->context()->state.globalAlpha);
}
+ RETURN_UNDEFINED();
}
/*!
@@ -1311,33 +1353,35 @@ void QQuickJSContext2D::method_set_globalAlpha(const QV4::BuiltinFunction *, QV4
extension composition modes are provided as "vendorName-operationName" syntax, for example: QPainter::CompositionMode_Exclusion is provided as
"qt-exclusion".
*/
-void QQuickJSContext2D::method_get_globalCompositeOperation(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_globalCompositeOperation(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- scope.result = scope.engine->newString(qt_composite_mode_to_string(r->d()->context->state.globalCompositeOperation));
+ RETURN_RESULT(scope.engine->newString(qt_composite_mode_to_string(r->d()->context()->state.globalCompositeOperation)));
}
-void QQuickJSContext2D::method_set_globalCompositeOperation(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_globalCompositeOperation(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- if (!callData->argc)
+ if (!argc)
THROW_TYPE_ERROR();
- scope.result = QV4::Encode::undefined();
-
- QString mode = callData->args[0].toQString();
+ QString mode = argv[0].toQString();
QPainter::CompositionMode cm = qt_composite_mode_from_string(mode);
if (cm == QPainter::CompositionMode_SourceOver && mode != QLatin1String("source-over"))
- return;
+ RETURN_UNDEFINED();
- if (cm != r->d()->context->state.globalCompositeOperation) {
- r->d()->context->state.globalCompositeOperation = cm;
- r->d()->context->buffer()->setGlobalCompositeOperation(cm);
+ if (cm != r->d()->context()->state.globalCompositeOperation) {
+ r->d()->context()->state.globalCompositeOperation = cm;
+ r->d()->context()->buffer()->setGlobalCompositeOperation(cm);
}
+
+ RETURN_UNDEFINED();
}
// colors and styles
@@ -1363,12 +1407,13 @@ void QQuickJSContext2D::method_set_globalCompositeOperation(const QV4::BuiltinFu
\sa createPattern()
\sa strokeStyle
*/
-void QQuickJSContext2D::method_get_fillStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_fillStyle(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- QColor color = r->d()->context->state.fillStyle.color();
+ QColor color = r->d()->context()->state.fillStyle.color();
if (color.isValid()) {
if (color.alpha() == 255)
RETURN_RESULT(scope.engine->newString(color.name()));
@@ -1380,41 +1425,42 @@ void QQuickJSContext2D::method_get_fillStyle(const QV4::BuiltinFunction *, QV4::
QString str = QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString);
RETURN_RESULT(scope.engine->newString(str));
}
- scope.result = r->d()->context->m_fillStyle.value();
+ RETURN_RESULT(r->d()->context()->m_fillStyle.value());
}
-void QQuickJSContext2D::method_set_fillStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedValue value(scope, callData->argument(0));
+ QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Value::undefinedValue());
if (value->as<Object>()) {
QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
if (color.isValid()) {
- r->d()->context->state.fillStyle = color;
- r->d()->context->buffer()->setFillStyle(color);
- r->d()->context->m_fillStyle.set(scope.engine, value);
+ r->d()->context()->state.fillStyle = color;
+ r->d()->context()->buffer()->setFillStyle(color);
+ r->d()->context()->m_fillStyle.set(scope.engine, value);
} else {
QV4::Scoped<QQuickContext2DStyle> style(scope, value->as<QQuickContext2DStyle>());
- if (style && *style->d()->brush != r->d()->context->state.fillStyle) {
- r->d()->context->state.fillStyle = *style->d()->brush;
- r->d()->context->buffer()->setFillStyle(*style->d()->brush, style->d()->patternRepeatX, style->d()->patternRepeatY);
- r->d()->context->m_fillStyle.set(scope.engine, value);
- r->d()->context->state.fillPatternRepeatX = style->d()->patternRepeatX;
- r->d()->context->state.fillPatternRepeatY = style->d()->patternRepeatY;
+ if (style && *style->d()->brush != r->d()->context()->state.fillStyle) {
+ r->d()->context()->state.fillStyle = *style->d()->brush;
+ r->d()->context()->buffer()->setFillStyle(*style->d()->brush, style->d()->patternRepeatX, style->d()->patternRepeatY);
+ r->d()->context()->m_fillStyle.set(scope.engine, value);
+ r->d()->context()->state.fillPatternRepeatX = style->d()->patternRepeatX;
+ r->d()->context()->state.fillPatternRepeatY = style->d()->patternRepeatY;
}
}
} else if (value->isString()) {
QColor color = qt_color_from_string(value);
- if (color.isValid() && r->d()->context->state.fillStyle != QBrush(color)) {
- r->d()->context->state.fillStyle = QBrush(color);
- r->d()->context->buffer()->setFillStyle(r->d()->context->state.fillStyle);
- r->d()->context->m_fillStyle.set(scope.engine, value);
+ if (color.isValid() && r->d()->context()->state.fillStyle != QBrush(color)) {
+ r->d()->context()->state.fillStyle = QBrush(color);
+ r->d()->context()->buffer()->setFillStyle(r->d()->context()->state.fillStyle);
+ r->d()->context()->m_fillStyle.set(scope.engine, value);
}
}
- scope.result = QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/*!
\qmlproperty enumeration QtQuick::Context2D::fillRule
@@ -1428,32 +1474,34 @@ void QQuickJSContext2D::method_set_fillStyle(const QV4::BuiltinFunction *, QV4::
\sa fillStyle
*/
-void QQuickJSContext2D::method_get_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_fillRule(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- scope.result = scope.engine->fromVariant(r->d()->context->state.fillRule);
+ RETURN_RESULT(scope.engine->fromVariant(r->d()->context()->state.fillRule));
}
-void QQuickJSContext2D::method_set_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_fillRule(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedValue value(scope, callData->argument(0));
+ QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Value::undefinedValue());
if ((value->isString() && value->toQString() == QLatin1String("WindingFill"))
|| (value->isInt32() && value->integerValue() == Qt::WindingFill)) {
- r->d()->context->state.fillRule = Qt::WindingFill;
+ r->d()->context()->state.fillRule = Qt::WindingFill;
} else if ((value->isString() && value->toQStringNoThrow() == QLatin1String("OddEvenFill"))
|| (value->isInt32() && value->integerValue() == Qt::OddEvenFill)) {
- r->d()->context->state.fillRule = Qt::OddEvenFill;
+ r->d()->context()->state.fillRule = Qt::OddEvenFill;
} else {
//error
}
- r->d()->context->m_path.setFillRule(r->d()->context->state.fillRule);
- scope.result = QV4::Encode::undefined();
+ r->d()->context()->m_path.setFillRule(r->d()->context()->state.fillRule);
+ RETURN_UNDEFINED();
}
/*!
\qmlproperty variant QtQuick::Context2D::strokeStyle
@@ -1468,12 +1516,13 @@ void QQuickJSContext2D::method_set_fillRule(const QV4::BuiltinFunction *, QV4::S
\sa createPattern()
\sa fillStyle
*/
-void QQuickJSContext2D::method_get_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_strokeStyle(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- QColor color = r->d()->context->state.strokeStyle.color();
+ QColor color = r->d()->context()->state.strokeStyle.color();
if (color.isValid()) {
if (color.alpha() == 255)
RETURN_RESULT(scope.engine->newString(color.name()));
@@ -1485,42 +1534,48 @@ void QQuickJSContext2D::method_get_strokeStyle(const QV4::BuiltinFunction *, QV4
QString str = QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString);
RETURN_RESULT(scope.engine->newString(str));
}
- scope.result = r->d()->context->m_strokeStyle.value();
+ RETURN_RESULT(r->d()->context()->m_strokeStyle.value());
}
-void QQuickJSContext2D::method_set_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedValue value(scope, callData->argument(0));
+ QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Value::undefinedValue());
if (value->as<Object>()) {
QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
if (color.isValid()) {
- r->d()->context->state.fillStyle = color;
- r->d()->context->buffer()->setStrokeStyle(color);
- r->d()->context->m_strokeStyle.set(scope.engine, value);
+ r->d()->context()->state.strokeStyle = color;
+ r->d()->context()->buffer()->setStrokeStyle(color);
+ r->d()->context()->m_strokeStyle.set(scope.engine, value);
} else {
QV4::Scoped<QQuickContext2DStyle> style(scope, value->as<QQuickContext2DStyle>());
- if (style && *style->d()->brush != r->d()->context->state.strokeStyle) {
- r->d()->context->state.strokeStyle = *style->d()->brush;
- r->d()->context->buffer()->setStrokeStyle(*style->d()->brush, style->d()->patternRepeatX, style->d()->patternRepeatY);
- r->d()->context->m_strokeStyle.set(scope.engine, value);
- r->d()->context->state.strokePatternRepeatX = style->d()->patternRepeatX;
- r->d()->context->state.strokePatternRepeatY = style->d()->patternRepeatY;
-
+ if (style && *style->d()->brush != r->d()->context()->state.strokeStyle) {
+ r->d()->context()->state.strokeStyle = *style->d()->brush;
+ r->d()->context()->buffer()->setStrokeStyle(*style->d()->brush, style->d()->patternRepeatX, style->d()->patternRepeatY);
+ r->d()->context()->m_strokeStyle.set(scope.engine, value);
+ r->d()->context()->state.strokePatternRepeatX = style->d()->patternRepeatX;
+ r->d()->context()->state.strokePatternRepeatY = style->d()->patternRepeatY;
+ } else if (!style && r->d()->context()->state.strokeStyle != QBrush(QColor())) {
+ // If there is no style object, then ensure that the strokeStyle is at least
+ // QColor in case it was previously set
+ r->d()->context()->state.strokeStyle = QBrush(QColor());
+ r->d()->context()->buffer()->setStrokeStyle(r->d()->context()->state.strokeStyle);
+ r->d()->context()->m_strokeStyle.set(scope.engine, value);
}
}
} else if (value->isString()) {
QColor color = qt_color_from_string(value);
- if (color.isValid() && r->d()->context->state.strokeStyle != QBrush(color)) {
- r->d()->context->state.strokeStyle = QBrush(color);
- r->d()->context->buffer()->setStrokeStyle(r->d()->context->state.strokeStyle);
- r->d()->context->m_strokeStyle.set(scope.engine, value);
+ if (color.isValid() && r->d()->context()->state.strokeStyle != QBrush(color)) {
+ r->d()->context()->state.strokeStyle = QBrush(color);
+ r->d()->context()->buffer()->setStrokeStyle(r->d()->context()->state.strokeStyle);
+ r->d()->context()->m_strokeStyle.set(scope.engine, value);
}
}
- scope.result = QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/*!
@@ -1540,16 +1595,17 @@ void QQuickJSContext2D::method_set_strokeStyle(const QV4::BuiltinFunction *, QV4
\sa strokeStyle
*/
-void QQuickJSContext2DPrototype::method_createLinearGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc >= 4) {
- qreal x0 = callData->args[0].toNumber();
- qreal y0 = callData->args[1].toNumber();
- qreal x1 = callData->args[2].toNumber();
- qreal y1 = callData->args[3].toNumber();
+ if (argc >= 4) {
+ qreal x0 = argv[0].toNumber();
+ qreal y0 = argv[1].toNumber();
+ qreal x1 = argv[2].toNumber();
+ qreal y1 = argv[3].toNumber();
if (!qt_is_finite(x0)
|| !qt_is_finite(y0)
@@ -1559,14 +1615,14 @@ void QQuickJSContext2DPrototype::method_createLinearGradient(const QV4::BuiltinF
}
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QV4::ScopedObject p(scope, ed->gradientProto.value());
- gradient->setPrototype(p);
+ gradient->setPrototypeOf(p);
*gradient->d()->brush = QLinearGradient(x0, y0, x1, y1);
- RETURN_RESULT(gradient);
+ RETURN_RESULT(*gradient);
}
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
@@ -1583,18 +1639,19 @@ void QQuickJSContext2DPrototype::method_createLinearGradient(const QV4::BuiltinF
\sa strokeStyle
*/
-void QQuickJSContext2DPrototype::method_createRadialGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc >= 6) {
- qreal x0 = callData->args[0].toNumber();
- qreal y0 = callData->args[1].toNumber();
- qreal r0 = callData->args[2].toNumber();
- qreal x1 = callData->args[3].toNumber();
- qreal y1 = callData->args[4].toNumber();
- qreal r1 = callData->args[5].toNumber();
+ if (argc >= 6) {
+ qreal x0 = argv[0].toNumber();
+ qreal y0 = argv[1].toNumber();
+ qreal r0 = argv[2].toNumber();
+ qreal x1 = argv[3].toNumber();
+ qreal y1 = argv[4].toNumber();
+ qreal r1 = argv[5].toNumber();
if (!qt_is_finite(x0)
|| !qt_is_finite(y0)
@@ -1610,14 +1667,14 @@ void QQuickJSContext2DPrototype::method_createRadialGradient(const QV4::BuiltinF
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QV4::ScopedObject p(scope, ed->gradientProto.value());
- gradient->setPrototype(p);
- *gradient->d()->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
- RETURN_RESULT(gradient);
+ gradient->setPrototypeOf(p);
+ *gradient->d()->brush = QRadialGradient(QPointF(x1, y1), r1, QPointF(x0, y0), r0);
+ RETURN_RESULT(*gradient);
}
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
@@ -1634,15 +1691,16 @@ void QQuickJSContext2DPrototype::method_createRadialGradient(const QV4::BuiltinF
\sa strokeStyle
*/
-void QQuickJSContext2DPrototype::method_createConicalGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc >= 3) {
- qreal x = callData->args[0].toNumber();
- qreal y = callData->args[1].toNumber();
- qreal angle = qRadiansToDegrees(callData->args[2].toNumber());
+ if (argc >= 3) {
+ qreal x = argv[0].toNumber();
+ qreal y = argv[1].toNumber();
+ qreal angle = qRadiansToDegrees(argv[2].toNumber());
if (!qt_is_finite(x) || !qt_is_finite(y)) {
THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
}
@@ -1653,14 +1711,14 @@ void QQuickJSContext2DPrototype::method_createConicalGradient(const QV4::Builtin
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QV4::ScopedObject p(scope, ed->gradientProto.value());
- gradient->setPrototype(p);
+ gradient->setPrototypeOf(p);
*gradient->d()->brush = QConicalGradient(x, y, angle);
- RETURN_RESULT(gradient);
+ RETURN_RESULT(*gradient);
}
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -1706,17 +1764,18 @@ void QQuickJSContext2DPrototype::method_createConicalGradient(const QV4::Builtin
\sa strokeStyle
\sa fillStyle
*/
-void QQuickJSContext2DPrototype::method_createPattern(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- if (callData->argc >= 2) {
- QV4::Scoped<QQuickContext2DStyle> pattern(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ if (argc >= 2) {
+ QV4::Scoped<QQuickContext2DStyle> pattern(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
- QColor color = scope.engine->toVariant(callData->args[0], qMetaTypeId<QColor>()).value<QColor>();
+ QColor color = scope.engine->toVariant(argv[0], qMetaTypeId<QColor>()).value<QColor>();
if (color.isValid()) {
- int patternMode = callData->args[1].toInt32();
+ int patternMode = argv[1].toInt32();
Qt::BrushStyle style = Qt::SolidPattern;
if (patternMode >= 0 && patternMode < Qt::LinearGradientPattern) {
style = static_cast<Qt::BrushStyle>(patternMode);
@@ -1725,20 +1784,20 @@ void QQuickJSContext2DPrototype::method_createPattern(const QV4::BuiltinFunction
} else {
QImage patternTexture;
- if (const QV4::Object *o = callData->args[0].as<Object>()) {
+ if (const QV4::Object *o = argv[0].as<Object>()) {
QV4::ScopedString s(scope, scope.engine->newString(QStringLiteral("data")));
QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, o->get(s));
if (!!pixelData) {
patternTexture = *pixelData->d()->image;
}
} else {
- patternTexture = r->d()->context->createPixmap(QUrl(callData->args[0].toQStringNoThrow()))->image();
+ patternTexture = r->d()->context()->createPixmap(QUrl(argv[0].toQStringNoThrow()))->image();
}
if (!patternTexture.isNull()) {
pattern->d()->brush->setTextureImage(patternTexture);
- QString repetition = callData->args[1].toQStringNoThrow();
+ QString repetition = argv[1].toQStringNoThrow();
if (repetition == QLatin1String("repeat") || repetition.isEmpty()) {
pattern->d()->patternRepeatX = true;
pattern->d()->patternRepeatY = true;
@@ -1758,10 +1817,10 @@ void QQuickJSContext2DPrototype::method_createPattern(const QV4::BuiltinFunction
}
}
- RETURN_RESULT(pattern);
+ RETURN_RESULT(*pattern);
}
- scope.result = QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
// line styles
@@ -1776,12 +1835,13 @@ void QQuickJSContext2DPrototype::method_createPattern(const QV4::BuiltinFunction
\endlist
Other values are ignored.
*/
-void QQuickJSContext2D::method_get_lineCap(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_lineCap(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- switch (r->d()->context->state.lineCap) {
+ switch (r->d()->context()->state.lineCap) {
case Qt::RoundCap:
RETURN_RESULT(scope.engine->newString(QStringLiteral("round")));
case Qt::SquareCap:
@@ -1793,12 +1853,16 @@ void QQuickJSContext2D::method_get_lineCap(const QV4::BuiltinFunction *, QV4::Sc
RETURN_RESULT(scope.engine->newString(QStringLiteral("butt")));
}
-void QQuickJSContext2D::method_set_lineCap(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_lineCap(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ if (!argc)
+ return QV4::Encode::undefined();
+
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
- QString lineCap = callData->args[0].toQString();
+ QString lineCap = argv[0].toQString();
Qt::PenCapStyle cap;
if (lineCap == QLatin1String("round"))
cap = Qt::RoundCap;
@@ -1809,9 +1873,9 @@ void QQuickJSContext2D::method_set_lineCap(const QV4::BuiltinFunction *, QV4::Sc
else
RETURN_UNDEFINED();
- if (cap != r->d()->context->state.lineCap) {
- r->d()->context->state.lineCap = cap;
- r->d()->context->buffer()->setLineCap(cap);
+ if (cap != r->d()->context()->state.lineCap) {
+ r->d()->context()->state.lineCap = cap;
+ r->d()->context()->buffer()->setLineCap(cap);
}
RETURN_UNDEFINED();
}
@@ -1830,12 +1894,13 @@ void QQuickJSContext2D::method_set_lineCap(const QV4::BuiltinFunction *, QV4::Sc
\endlist
Other values are ignored.
*/
-void QQuickJSContext2D::method_get_lineJoin(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_lineJoin(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- switch (r->d()->context->state.lineJoin) {
+ switch (r->d()->context()->state.lineJoin) {
case Qt::RoundJoin:
RETURN_RESULT(scope.engine->newString(QStringLiteral("round")));
case Qt::BevelJoin:
@@ -1847,15 +1912,16 @@ void QQuickJSContext2D::method_get_lineJoin(const QV4::BuiltinFunction *, QV4::S
RETURN_RESULT(scope.engine->newString(QStringLiteral("miter")));
}
-void QQuickJSContext2D::method_set_lineJoin(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
- if (!callData->argc)
+ if (!argc)
THROW_TYPE_ERROR();
- QString lineJoin = callData->args[0].toQString();
+ QString lineJoin = argv[0].toQString();
Qt::PenJoinStyle join;
if (lineJoin == QLatin1String("round"))
join = Qt::RoundJoin;
@@ -1866,9 +1932,9 @@ void QQuickJSContext2D::method_set_lineJoin(const QV4::BuiltinFunction *, QV4::S
else
RETURN_UNDEFINED();
- if (join != r->d()->context->state.lineJoin) {
- r->d()->context->state.lineJoin = join;
- r->d()->context->buffer()->setLineJoin(join);
+ if (join != r->d()->context()->state.lineJoin) {
+ r->d()->context()->state.lineJoin = join;
+ r->d()->context()->buffer()->setLineJoin(join);
}
RETURN_UNDEFINED();
}
@@ -1877,24 +1943,26 @@ void QQuickJSContext2D::method_set_lineJoin(const QV4::BuiltinFunction *, QV4::S
\qmlproperty real QtQuick::Context2D::lineWidth
Holds the current line width. Values that are not finite values greater than zero are ignored.
*/
-void QQuickJSContext2D::method_get_lineWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_lineWidth(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- RETURN_RESULT(QV4::Encode(r->d()->context->state.lineWidth));
+ RETURN_RESULT(QV4::Encode(r->d()->context()->state.lineWidth));
}
-void QQuickJSContext2D::method_set_lineWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_lineWidth(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal w = callData->argc ? callData->args[0].toNumber() : -1;
+ qreal w = argc ? argv[0].toNumber() : -1;
- if (w > 0 && qt_is_finite(w) && w != r->d()->context->state.lineWidth) {
- r->d()->context->state.lineWidth = w;
- r->d()->context->buffer()->setLineWidth(w);
+ if (w > 0 && qt_is_finite(w) && w != r->d()->context()->state.lineWidth) {
+ r->d()->context()->state.lineWidth = w;
+ r->d()->context()->buffer()->setLineWidth(w);
}
RETURN_UNDEFINED();
}
@@ -1904,51 +1972,171 @@ void QQuickJSContext2D::method_set_lineWidth(const QV4::BuiltinFunction *, QV4::
Holds the current miter limit ratio.
The default miter limit value is 10.0.
*/
-void QQuickJSContext2D::method_get_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_miterLimit(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
+{
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
+ CHECK_CONTEXT(r)
+
+ RETURN_RESULT(QV4::Encode(r->d()->context()->state.miterLimit));
+}
+
+QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
+{
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
+ CHECK_CONTEXT_SETTER(r)
+
+ qreal ml = argc ? argv[0].toNumber() : -1;
+
+ if (ml > 0 && qt_is_finite(ml) && ml != r->d()->context()->state.miterLimit) {
+ r->d()->context()->state.miterLimit = ml;
+ r->d()->context()->buffer()->setMiterLimit(ml);
+ }
+ RETURN_UNDEFINED();
+}
+
+/*!
+ \qmlmethod array QtQuick::Context2D::getLineDash()
+ \since QtQuick 2.11
+ Returns an array of qreals representing the dash pattern of the line.
+
+ \sa setLineDash()
+ */
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_getLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
+{
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
+ CHECK_CONTEXT(r)
+
+ const QVector<qreal> pattern = r->d()->context()->state.lineDash;
+ QV4::ScopedArrayObject array(scope, scope.engine->newArrayObject(pattern.size()));
+ array->arrayReserve(pattern.size());
+ for (int i = 0; i < pattern.size(); i++)
+ array->put(i, QV4::Value::fromDouble(pattern[i]));
+
+ array->setArrayLengthUnchecked(pattern.size());
+
+ RETURN_RESULT(*array);
+}
+
+/*!
+ \qmlmethod QtQuick::Context2D::setLineDash(array pattern)
+ \since QtQuick 2.11
+ Sets the dash pattern to the given pattern
+
+ \a pattern a list of numbers that specifies distances to alternately draw a line and a gap.
+
+ If the number of elements in the array is odd, the elements of the array get copied
+ and concatenated. For example, [5, 15, 25] will become [5, 15, 25, 5, 15, 25].
+
+ \table 100%
+ \row
+ \li \inlineimage qml-item-canvas-lineDash.png
+ \li
+ \code
+ var space = 4
+ ctx.setLineDash([1, space, 3, space, 9, space, 27, space, 9, space])
+ ...
+ ctx.stroke();
+ \endcode
+ \endtable
+
+ \sa setLineDash
+ */
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_setLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
+{
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
+ CHECK_CONTEXT_SETTER(r)
+
+ if (!argc)
+ RETURN_UNDEFINED();
+
+ QV4::ScopedArrayObject array(scope, argv[0]);
+ if (!array)
+ RETURN_UNDEFINED();
+
+ QV4::ScopedValue v(scope);
+ const uint arrayLength = array->getLength();
+ QVector<qreal> dashes;
+ dashes.reserve(arrayLength);
+ for (uint i = 0; i < arrayLength; ++i) {
+ v = array->get(i);
+ const double number = v->toNumber();
+
+ if (!qt_is_finite(number) || (number < 0))
+ RETURN_UNDEFINED();
+
+ dashes.append(v->toNumber());
+ }
+ if (dashes.size() % 2 != 0) {
+ dashes += dashes;
+ }
+
+ r->d()->context()->state.lineDash = dashes;
+ r->d()->context()->buffer()->setLineDash(dashes);
+
+ RETURN_UNDEFINED();
+}
+
+/*!
+ \qmlproperty real QtQuick::Context2D::lineDashOffset
+ \since QtQuick 2.11
+
+ Holds the current line dash offset
+ The default line dash ofset value is 0
+ */
+QV4::ReturnedValue QQuickJSContext2D::method_get_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- RETURN_RESULT(QV4::Encode(r->d()->context->state.miterLimit));
+ RETURN_RESULT(QV4::Encode(r->d()->context()->state.lineDashOffset));
}
-void QQuickJSContext2D::method_set_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal ml = callData->argc ? callData->args[0].toNumber() : -1;
+ const qreal offset = argc ? argv[0].toNumber() : -1;
- if (ml > 0 && qt_is_finite(ml) && ml != r->d()->context->state.miterLimit) {
- r->d()->context->state.miterLimit = ml;
- r->d()->context->buffer()->setMiterLimit(ml);
+ if (qt_is_finite(offset) && offset != r->d()->context()->state.lineDashOffset) {
+ r->d()->context()->state.lineDashOffset = offset;
+ r->d()->context()->buffer()->setLineDashOffset(offset);
}
RETURN_UNDEFINED();
}
+
// shadows
/*!
\qmlproperty real QtQuick::Context2D::shadowBlur
Holds the current level of blur applied to shadows
*/
-void QQuickJSContext2D::method_get_shadowBlur(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_shadowBlur(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- RETURN_RESULT(QV4::Encode(r->d()->context->state.shadowBlur));
+ RETURN_RESULT(QV4::Encode(r->d()->context()->state.shadowBlur));
}
-void QQuickJSContext2D::method_set_shadowBlur(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_shadowBlur(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal blur = callData->argc ? callData->args[0].toNumber() : -1;
+ qreal blur = argc ? argv[0].toNumber() : -1;
- if (blur > 0 && qt_is_finite(blur) && blur != r->d()->context->state.shadowBlur) {
- r->d()->context->state.shadowBlur = blur;
- r->d()->context->buffer()->setShadowBlur(blur);
+ if (blur > 0 && qt_is_finite(blur) && blur != r->d()->context()->state.shadowBlur) {
+ r->d()->context()->state.shadowBlur = blur;
+ r->d()->context()->buffer()->setShadowBlur(blur);
}
RETURN_UNDEFINED();
}
@@ -1957,26 +2145,28 @@ void QQuickJSContext2D::method_set_shadowBlur(const QV4::BuiltinFunction *, QV4:
\qmlproperty string QtQuick::Context2D::shadowColor
Holds the current shadow color.
*/
-void QQuickJSContext2D::method_get_shadowColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_shadowColor(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- RETURN_RESULT(scope.engine->newString(r->d()->context->state.shadowColor.name()));
+ RETURN_RESULT(scope.engine->newString(r->d()->context()->state.shadowColor.name()));
}
-void QQuickJSContext2D::method_set_shadowColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_shadowColor(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
QColor color;
- if (callData->argc)
- color = qt_color_from_string(callData->args[0]);
+ if (argc)
+ color = qt_color_from_string(argv[0]);
- if (color.isValid() && color != r->d()->context->state.shadowColor) {
- r->d()->context->state.shadowColor = color;
- r->d()->context->buffer()->setShadowColor(color);
+ if (color.isValid() && color != r->d()->context()->state.shadowColor) {
+ r->d()->context()->state.shadowColor = color;
+ r->d()->context()->buffer()->setShadowColor(color);
}
RETURN_UNDEFINED();
}
@@ -1988,23 +2178,25 @@ void QQuickJSContext2D::method_set_shadowColor(const QV4::BuiltinFunction *, QV4
\sa shadowOffsetY
*/
-void QQuickJSContext2D::method_get_shadowOffsetX(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetX(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- RETURN_RESULT(QV4::Encode(r->d()->context->state.shadowOffsetX));
+ RETURN_RESULT(QV4::Encode(r->d()->context()->state.shadowOffsetX));
}
-void QQuickJSContext2D::method_set_shadowOffsetX(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetX(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal offsetX = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- if (qt_is_finite(offsetX) && offsetX != r->d()->context->state.shadowOffsetX) {
- r->d()->context->state.shadowOffsetX = offsetX;
- r->d()->context->buffer()->setShadowOffsetX(offsetX);
+ qreal offsetX = argc ? argv[0].toNumber() : qt_qnan();
+ if (qt_is_finite(offsetX) && offsetX != r->d()->context()->state.shadowOffsetX) {
+ r->d()->context()->state.shadowOffsetX = offsetX;
+ r->d()->context()->buffer()->setShadowOffsetX(offsetX);
}
RETURN_UNDEFINED();
}
@@ -2014,52 +2206,56 @@ void QQuickJSContext2D::method_set_shadowOffsetX(const QV4::BuiltinFunction *, Q
\sa shadowOffsetX
*/
-void QQuickJSContext2D::method_get_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetY(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- RETURN_RESULT(QV4::Encode(r->d()->context->state.shadowOffsetY));
+ RETURN_RESULT(QV4::Encode(r->d()->context()->state.shadowOffsetY));
}
-void QQuickJSContext2D::method_set_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetY(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal offsetY = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- if (qt_is_finite(offsetY) && offsetY != r->d()->context->state.shadowOffsetY) {
- r->d()->context->state.shadowOffsetY = offsetY;
- r->d()->context->buffer()->setShadowOffsetY(offsetY);
+ qreal offsetY = argc ? argv[0].toNumber() : qt_qnan();
+ if (qt_is_finite(offsetY) && offsetY != r->d()->context()->state.shadowOffsetY) {
+ r->d()->context()->state.shadowOffsetY = offsetY;
+ r->d()->context()->buffer()->setShadowOffsetY(offsetY);
}
RETURN_UNDEFINED();
}
#if QT_CONFIG(quick_path)
-void QQuickJSContext2D::method_get_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_path(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- scope.result = r->d()->context->m_v4path.value();
+ RETURN_RESULT(r->d()->context()->m_v4path.value());
}
-void QQuickJSContext2D::method_set_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_path(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedValue value(scope, callData->argument(0));
- r->d()->context->beginPath();
+ QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Value::undefinedValue());
+ r->d()->context()->beginPath();
QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, value);
if (!!qobjectWrapper) {
if (QQuickPath *path = qobject_cast<QQuickPath*>(qobjectWrapper->object()))
- r->d()->context->m_path = path->path();
+ r->d()->context()->m_path = path->path();
} else {
QString path =value->toQStringNoThrow();
- QQuickSvgParser::parsePathDataFast(path, r->d()->context->m_path);
+ QQuickSvgParser::parsePathDataFast(path, r->d()->context()->m_path);
}
- r->d()->context->m_v4path.set(scope.engine, value);
+ r->d()->context()->m_v4path.set(scope.engine, value);
RETURN_UNDEFINED();
}
#endif // QT_CONFIG(quick_path)
@@ -2069,19 +2265,20 @@ void QQuickJSContext2D::method_set_path(const QV4::BuiltinFunction *, QV4::Scope
\qmlmethod object QtQuick::Context2D::clearRect(real x, real y, real w, real h)
Clears all pixels on the canvas in the given rectangle to transparent black.
*/
-void QQuickJSContext2DPrototype::method_clearRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_clearRect(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- if (callData->argc >= 4)
- r->d()->context->clearRect(callData->args[0].toNumber(),
- callData->args[1].toNumber(),
- callData->args[2].toNumber(),
- callData->args[3].toNumber());
+ if (argc >= 4)
+ r->d()->context()->clearRect(argv[0].toNumber(),
+ argv[1].toNumber(),
+ argv[2].toNumber(),
+ argv[3].toNumber());
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -2090,14 +2287,15 @@ void QQuickJSContext2DPrototype::method_clearRect(const QV4::BuiltinFunction *,
\sa fillStyle
*/
-void QQuickJSContext2DPrototype::method_fillRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillRect(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- if (callData->argc >= 4)
- r->d()->context->fillRect(callData->args[0].toNumber(), callData->args[1].toNumber(), callData->args[2].toNumber(), callData->args[3].toNumber());
- scope.result = callData->thisObject;
+ if (argc >= 4)
+ r->d()->context()->fillRect(argv[0].toNumber(), argv[1].toNumber(), argv[2].toNumber(), argv[3].toNumber());
+ RETURN_RESULT(*thisObject);
}
@@ -2111,15 +2309,16 @@ void QQuickJSContext2DPrototype::method_fillRect(const QV4::BuiltinFunction *, Q
\sa lineJoin
\sa miterLimit
*/
-void QQuickJSContext2DPrototype::method_strokeRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeRect(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- if (callData->argc >= 4)
- r->d()->context->strokeRect(callData->args[0].toNumber(), callData->args[1].toNumber(), callData->args[2].toNumber(), callData->args[3].toNumber());
+ if (argc >= 4)
+ r->d()->context()->strokeRect(argv[0].toNumber(), argv[1].toNumber(), argv[2].toNumber(), argv[3].toNumber());
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
@@ -2144,31 +2343,32 @@ void QQuickJSContext2DPrototype::method_strokeRect(const QV4::BuiltinFunction *,
\sa arcTo, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C's 2D
Context Standard for arc()}
*/
-void QQuickJSContext2DPrototype::method_arc(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_arc(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- if (callData->argc >= 5) {
+ if (argc >= 5) {
bool antiClockwise = false;
- if (callData->argc == 6)
- antiClockwise = callData->args[5].toBoolean();
+ if (argc == 6)
+ antiClockwise = argv[5].toBoolean();
- qreal radius = callData->args[2].toNumber();
+ qreal radius = argv[2].toNumber();
if (qt_is_finite(radius) && radius < 0)
THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
- r->d()->context->arc(callData->args[0].toNumber(),
- callData->args[1].toNumber(),
+ r->d()->context()->arc(argv[0].toNumber(),
+ argv[1].toNumber(),
radius,
- callData->args[3].toNumber(),
- callData->args[4].toNumber(),
+ argv[3].toNumber(),
+ argv[4].toNumber(),
antiClockwise);
}
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
@@ -2195,25 +2395,26 @@ void QQuickJSContext2DPrototype::method_arc(const QV4::BuiltinFunction *, QV4::S
\sa arc, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C's 2D
Context Standard for arcTo()}
*/
-void QQuickJSContext2DPrototype::method_arcTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_arcTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- if (callData->argc >= 5) {
- qreal radius = callData->args[4].toNumber();
+ if (argc >= 5) {
+ qreal radius = argv[4].toNumber();
if (qt_is_finite(radius) && radius < 0)
THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
- r->d()->context->arcTo(callData->args[0].toNumber(),
- callData->args[1].toNumber(),
- callData->args[2].toNumber(),
- callData->args[3].toNumber(),
+ r->d()->context()->arcTo(argv[0].toNumber(),
+ argv[1].toNumber(),
+ argv[2].toNumber(),
+ argv[3].toNumber(),
radius);
}
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
@@ -2222,14 +2423,15 @@ void QQuickJSContext2DPrototype::method_arcTo(const QV4::BuiltinFunction *, QV4:
Resets the current path to a new path.
*/
-void QQuickJSContext2DPrototype::method_beginPath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_beginPath(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- r->d()->context->beginPath();
+ r->d()->context()->beginPath();
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
@@ -2252,26 +2454,26 @@ void QQuickJSContext2DPrototype::method_beginPath(const QV4::BuiltinFunction *,
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto}{W3C 2d context standard for bezierCurveTo}
\sa {http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
*/
-void QQuickJSContext2DPrototype::method_bezierCurveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- scope.result = callData->thisObject;
-
- if (callData->argc >= 6) {
- qreal cp1x = callData->args[0].toNumber();
- qreal cp1y = callData->args[1].toNumber();
- qreal cp2x = callData->args[2].toNumber();
- qreal cp2y = callData->args[3].toNumber();
- qreal x = callData->args[4].toNumber();
- qreal y = callData->args[5].toNumber();
+ if (argc >= 6) {
+ qreal cp1x = argv[0].toNumber();
+ qreal cp1y = argv[1].toNumber();
+ qreal cp2x = argv[2].toNumber();
+ qreal cp2y = argv[3].toNumber();
+ qreal x = argv[4].toNumber();
+ qreal y = argv[5].toNumber();
if (!qt_is_finite(cp1x) || !qt_is_finite(cp1y) || !qt_is_finite(cp2x) || !qt_is_finite(cp2y) || !qt_is_finite(x) || !qt_is_finite(y))
- return;
+ RETURN_UNDEFINED();
- r->d()->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
+ r->d()->context()->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
}
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -2298,13 +2500,14 @@ void QQuickJSContext2DPrototype::method_bezierCurveTo(const QV4::BuiltinFunction
\sa fill()
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-clip}{W3C 2d context standard for clip}
*/
-void QQuickJSContext2DPrototype::method_clip(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_clip(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- r->d()->context->clip();
- scope.result = callData->thisObject;
+ r->d()->context()->clip();
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -2314,15 +2517,15 @@ void QQuickJSContext2DPrototype::method_clip(const QV4::BuiltinFunction *, QV4::
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath}{W3C 2d context standard for closePath}
*/
-void QQuickJSContext2DPrototype::method_closePath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_closePath(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
+ r->d()->context()->closePath();
- r->d()->context->closePath();
-
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -2334,12 +2537,13 @@ void QQuickJSContext2DPrototype::method_closePath(const QV4::BuiltinFunction *,
\sa fillStyle
*/
-void QQuickJSContext2DPrototype::method_fill(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_fill(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r);
- r->d()->context->fill();
- scope.result = callData->thisObject;
+ r->d()->context()->fill();
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -2347,22 +2551,23 @@ void QQuickJSContext2DPrototype::method_fill(const QV4::BuiltinFunction *, QV4::
Draws a line from the current position to the point (x, y).
*/
-void QQuickJSContext2DPrototype::method_lineTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_lineTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- scope.result = callData->thisObject;
-
- if (callData->argc >= 2) {
- qreal x = callData->args[0].toNumber();
- qreal y = callData->args[1].toNumber();
+ if (argc >= 2) {
+ qreal x = argv[0].toNumber();
+ qreal y = argv[1].toNumber();
if (!qt_is_finite(x) || !qt_is_finite(y))
- return;
+ RETURN_UNDEFINED();
- r->d()->context->lineTo(x, y);
+ r->d()->context()->lineTo(x, y);
}
+
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -2370,21 +2575,22 @@ void QQuickJSContext2DPrototype::method_lineTo(const QV4::BuiltinFunction *, QV4
Creates a new subpath with the given point.
*/
-void QQuickJSContext2DPrototype::method_moveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_moveTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- scope.result = callData->thisObject;
-
- if (callData->argc >= 2) {
- qreal x = callData->args[0].toNumber();
- qreal y = callData->args[1].toNumber();
+ if (argc >= 2) {
+ qreal x = argv[0].toNumber();
+ qreal y = argv[1].toNumber();
if (!qt_is_finite(x) || !qt_is_finite(y))
- return;
- r->d()->context->moveTo(x, y);
+ RETURN_UNDEFINED();
+ r->d()->context()->moveTo(x, y);
}
+
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -2394,24 +2600,25 @@ void QQuickJSContext2DPrototype::method_moveTo(const QV4::BuiltinFunction *, QV4
See \l{http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto}{W3C 2d context standard for quadraticCurveTo}
*/
-void QQuickJSContext2DPrototype::method_quadraticCurveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_quadraticCurveTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- scope.result = callData->thisObject;
-
- if (callData->argc >= 4) {
- qreal cpx = callData->args[0].toNumber();
- qreal cpy = callData->args[1].toNumber();
- qreal x = callData->args[2].toNumber();
- qreal y = callData->args[3].toNumber();
+ if (argc >= 4) {
+ qreal cpx = argv[0].toNumber();
+ qreal cpy = argv[1].toNumber();
+ qreal x = argv[2].toNumber();
+ qreal y = argv[3].toNumber();
if (!qt_is_finite(cpx) || !qt_is_finite(cpy) || !qt_is_finite(x) || !qt_is_finite(y))
- return;
+ RETURN_UNDEFINED();
- r->d()->context->quadraticCurveTo(cpx, cpy, x, y);
+ r->d()->context()->quadraticCurveTo(cpx, cpy, x, y);
}
+
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -2419,14 +2626,15 @@ void QQuickJSContext2DPrototype::method_quadraticCurveTo(const QV4::BuiltinFunct
Adds a rectangle at position (\c x, \c y), with the given width \c w and height \c h, as a closed subpath.
*/
-void QQuickJSContext2DPrototype::method_rect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_rect(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- if (callData->argc >= 4)
- r->d()->context->rect(callData->args[0].toNumber(), callData->args[1].toNumber(), callData->args[2].toNumber(), callData->args[3].toNumber());
- scope.result = callData->thisObject;
+ if (argc >= 4)
+ r->d()->context()->rect(argv[0].toNumber(), argv[1].toNumber(), argv[2].toNumber(), argv[3].toNumber());
+ RETURN_RESULT(*thisObject);
}
@@ -2436,19 +2644,20 @@ void QQuickJSContext2DPrototype::method_rect(const QV4::BuiltinFunction *, QV4::
Adds the given rectangle rect with rounded corners to the path. The \c xRadius and \c yRadius arguments specify the radius of the
ellipses defining the corners of the rounded rectangle.
*/
-void QQuickJSContext2DPrototype::method_roundedRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_roundedRect(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- if (callData->argc >= 6)
- r->d()->context->roundedRect(callData->args[0].toNumber()
- , callData->args[1].toNumber()
- , callData->args[2].toNumber()
- , callData->args[3].toNumber()
- , callData->args[4].toNumber()
- , callData->args[5].toNumber());
- scope.result = callData->thisObject;
+ if (argc >= 6)
+ r->d()->context()->roundedRect(argv[0].toNumber()
+ , argv[1].toNumber()
+ , argv[2].toNumber()
+ , argv[3].toNumber()
+ , argv[4].toNumber()
+ , argv[5].toNumber());
+ RETURN_RESULT(*thisObject);
}
@@ -2460,16 +2669,16 @@ void QQuickJSContext2DPrototype::method_roundedRect(const QV4::BuiltinFunction *
The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
*/
-void QQuickJSContext2DPrototype::method_ellipse(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_ellipse(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
+ if (argc >= 4)
+ r->d()->context()->ellipse(argv[0].toNumber(), argv[1].toNumber(), argv[2].toNumber(), argv[3].toNumber());
- if (callData->argc >= 4)
- r->d()->context->ellipse(callData->args[0].toNumber(), callData->args[1].toNumber(), callData->args[2].toNumber(), callData->args[3].toNumber());
-
- scope.result = callData->thisObject;
+ RETURN_RESULT(*thisObject);
}
@@ -2479,22 +2688,22 @@ void QQuickJSContext2DPrototype::method_ellipse(const QV4::BuiltinFunction *, QV
Adds the given \c text to the path as a set of closed subpaths created from the current context font supplied.
The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (\c x, \c y).
*/
-void QQuickJSContext2DPrototype::method_text(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_text(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- scope.result = callData->thisObject;
-
- if (callData->argc >= 3) {
- qreal x = callData->args[1].toNumber();
- qreal y = callData->args[2].toNumber();
+ if (argc >= 3) {
+ qreal x = argv[1].toNumber();
+ qreal y = argv[2].toNumber();
if (!qt_is_finite(x) || !qt_is_finite(y))
- return;
- r->d()->context->text(callData->args[0].toQStringNoThrow(), x, y);
+ RETURN_UNDEFINED();
+ r->d()->context()->text(argv[0].toQStringNoThrow(), x, y);
}
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -2506,13 +2715,14 @@ void QQuickJSContext2DPrototype::method_text(const QV4::BuiltinFunction *, QV4::
\sa strokeStyle
*/
-void QQuickJSContext2DPrototype::method_stroke(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_stroke(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- r->d()->context->stroke();
- scope.result = callData->thisObject;
+ r->d()->context()->stroke();
+ RETURN_RESULT(*thisObject);
}
@@ -2523,29 +2733,33 @@ void QQuickJSContext2DPrototype::method_stroke(const QV4::BuiltinFunction *, QV4
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath}{W3C 2d context standard for isPointInPath}
*/
-void QQuickJSContext2DPrototype::method_isPointInPath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_isPointInPath(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
bool pointInPath = false;
- if (callData->argc >= 2)
- pointInPath = r->d()->context->isPointInPath(callData->args[0].toNumber(), callData->args[1].toNumber());
- scope.result = QV4::Primitive::fromBoolean(pointInPath).asReturnedValue();
+ if (argc >= 2)
+ pointInPath = r->d()->context()->isPointInPath(argv[0].toNumber(), argv[1].toNumber());
+ RETURN_RESULT(QV4::Value::fromBoolean(pointInPath).asReturnedValue());
}
-void QQuickJSContext2DPrototype::method_drawFocusRing(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawFocusRing(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *, int)
{
+ QV4::Scope scope(b);
THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
}
-void QQuickJSContext2DPrototype::method_setCaretSelectionRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_setCaretSelectionRect(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *, int)
{
+ QV4::Scope scope(b);
THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
}
-void QQuickJSContext2DPrototype::method_caretBlinkRate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_caretBlinkRate(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *, int)
{
+ QV4::Scope scope(b);
THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::caretBlinkRate is not supported");
}
@@ -2572,25 +2786,27 @@ void QQuickJSContext2DPrototype::method_caretBlinkRate(const QV4::BuiltinFunctio
The default font value is "10px sans-serif".
*/
-void QQuickJSContext2D::method_get_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_font(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- RETURN_RESULT(scope.engine->newString(r->d()->context->state.font.toString()));
+ RETURN_RESULT(scope.engine->newString(r->d()->context()->state.font.toString()));
}
-void QQuickJSContext2D::method_set_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_font(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedString s(scope, callData->argument(0), QV4::ScopedString::Convert);
+ QV4::ScopedString s(scope, argc ? argv[0] : QV4::Value::undefinedValue(), QV4::ScopedString::Convert);
if (scope.engine->hasException)
RETURN_UNDEFINED();
- QFont font = qt_font_from_string(s->toQString(), r->d()->context->state.font);
- if (font != r->d()->context->state.font) {
- r->d()->context->state.font = font;
+ QFont font = qt_font_from_string(s->toQString(), r->d()->context()->state.font);
+ if (font != r->d()->context()->state.font) {
+ r->d()->context()->state.font = font;
}
RETURN_UNDEFINED();
}
@@ -2609,12 +2825,13 @@ void QQuickJSContext2D::method_set_font(const QV4::BuiltinFunction *, QV4::Scope
\endlist
Other values are ignored. The default value is "start".
*/
-void QQuickJSContext2D::method_get_textAlign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_textAlign(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- switch (r->d()->context->state.textAlign) {
+ switch (r->d()->context()->state.textAlign) {
case QQuickContext2D::End:
RETURN_RESULT(scope.engine->newString(QStringLiteral("end")));
case QQuickContext2D::Left:
@@ -2630,12 +2847,13 @@ void QQuickJSContext2D::method_get_textAlign(const QV4::BuiltinFunction *, QV4::
RETURN_RESULT(scope.engine->newString(QStringLiteral("start")));
}
-void QQuickJSContext2D::method_set_textAlign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedString s(scope, callData->argument(0), QV4::ScopedString::Convert);
+ QV4::ScopedString s(scope, argc ? argv[0] : QV4::Value::undefinedValue(), QV4::ScopedString::Convert);
if (scope.engine->hasException)
RETURN_UNDEFINED();
QString textAlign = s->toQString();
@@ -2654,8 +2872,8 @@ void QQuickJSContext2D::method_set_textAlign(const QV4::BuiltinFunction *, QV4::
else
RETURN_UNDEFINED();
- if (ta != r->d()->context->state.textAlign)
- r->d()->context->state.textAlign = ta;
+ if (ta != r->d()->context()->state.textAlign)
+ r->d()->context()->state.textAlign = ta;
RETURN_UNDEFINED();
}
@@ -2675,12 +2893,13 @@ void QQuickJSContext2D::method_set_textAlign(const QV4::BuiltinFunction *, QV4::
\endlist
Other values are ignored. The default value is "alphabetic".
*/
-void QQuickJSContext2D::method_get_textBaseline(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_get_textBaseline(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- switch (r->d()->context->state.textBaseline) {
+ switch (r->d()->context()->state.textBaseline) {
case QQuickContext2D::Hanging:
RETURN_RESULT(scope.engine->newString(QStringLiteral("hanging")));
case QQuickContext2D::Top:
@@ -2696,11 +2915,12 @@ void QQuickJSContext2D::method_get_textBaseline(const QV4::BuiltinFunction *, QV
RETURN_RESULT(scope.engine->newString(QStringLiteral("alphabetic")));
}
-void QQuickJSContext2D::method_set_textBaseline(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedString s(scope, callData->argument(0), QV4::ScopedString::Convert);
+ QV4::ScopedString s(scope, argc ? argv[0] : QV4::Value::undefinedValue(), QV4::ScopedString::Convert);
if (scope.engine->hasException)
RETURN_UNDEFINED();
QString textBaseline = s->toQString();
@@ -2719,8 +2939,8 @@ void QQuickJSContext2D::method_set_textBaseline(const QV4::BuiltinFunction *, QV
else
RETURN_UNDEFINED();
- if (tb != r->d()->context->state.textBaseline)
- r->d()->context->state.textBaseline = tb;
+ if (tb != r->d()->context()->state.textBaseline)
+ r->d()->context()->state.textBaseline = tb;
RETURN_UNDEFINED();
}
@@ -2733,21 +2953,22 @@ void QQuickJSContext2D::method_set_textBaseline(const QV4::BuiltinFunction *, QV
\sa textBaseline
\sa strokeText
*/
-void QQuickJSContext2DPrototype::method_fillText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillText(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- scope.result = callData->thisObject;
-
- if (callData->argc >= 3) {
- qreal x = callData->args[1].toNumber();
- qreal y = callData->args[2].toNumber();
+ if (argc >= 3) {
+ qreal x = argv[1].toNumber();
+ qreal y = argv[2].toNumber();
if (!qt_is_finite(x) || !qt_is_finite(y))
- return;
- QPainterPath textPath = r->d()->context->createTextGlyphs(x, y, callData->args[0].toQStringNoThrow());
- r->d()->context->buffer()->fill(textPath);
+ RETURN_UNDEFINED();
+ QPainterPath textPath = r->d()->context()->createTextGlyphs(x, y, argv[0].toQStringNoThrow());
+ r->d()->context()->buffer()->fill(textPath);
}
+
+ RETURN_RESULT(*thisObject);
}
/*!
\qmlmethod object QtQuick::Context2D::strokeText(text, x, y)
@@ -2757,15 +2978,16 @@ void QQuickJSContext2DPrototype::method_fillText(const QV4::BuiltinFunction *, Q
\sa textBaseline
\sa fillText
*/
-void QQuickJSContext2DPrototype::method_strokeText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeText(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- if (callData->argc >= 3)
- r->d()->context->drawText(callData->args[0].toQStringNoThrow(), callData->args[1].toNumber(), callData->args[2].toNumber(), false);
- scope.result = callData->thisObject;
+ if (argc >= 3)
+ r->d()->context()->drawText(argv[0].toQStringNoThrow(), argv[1].toNumber(), argv[2].toNumber(), false);
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -2774,18 +2996,19 @@ void QQuickJSContext2DPrototype::method_strokeText(const QV4::BuiltinFunction *,
Returns an object with a \c width property, whose value is equivalent to
calling \l {QFontMetrics::width()} with the given \a text in the current font.
*/
-void QQuickJSContext2DPrototype::method_measureText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- if (callData->argc >= 1) {
- QFontMetrics fm(r->d()->context->state.font);
- uint width = fm.width(callData->args[0].toQStringNoThrow());
+ if (argc >= 1) {
+ QFontMetrics fm(r->d()->context()->state.font);
+ uint width = fm.horizontalAdvance(argv[0].toQStringNoThrow());
QV4::ScopedObject tm(scope, scope.engine->newObject());
tm->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("width"))).getPointer(),
- QV4::ScopedValue(scope, QV4::Primitive::fromDouble(width)));
- RETURN_RESULT(tm);
+ QV4::ScopedValue(scope, QV4::Value::fromDouble(width)));
+ RETURN_RESULT(*tm);
}
RETURN_UNDEFINED();
}
@@ -2849,36 +3072,35 @@ void QQuickJSContext2DPrototype::method_measureText(const QV4::BuiltinFunction *
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
*/
-void QQuickJSContext2DPrototype::method_drawImage(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject);
CHECK_CONTEXT(r)
- scope.result = callData->thisObject;
-
qreal sx, sy, sw, sh, dx, dy, dw, dh;
- if (!callData->argc)
- return;
+ if (!argc)
+ RETURN_UNDEFINED();
//FIXME:This function should be moved to QQuickContext2D::drawImage(...)
- if (!r->d()->context->state.invertibleCTM)
- return;
+ if (!r->d()->context()->state.invertibleCTM)
+ RETURN_UNDEFINED();
QQmlRefPointer<QQuickCanvasPixmap> pixmap;
- QV4::ScopedValue arg(scope, callData->args[0]);
+ QV4::ScopedValue arg(scope, argv[0]);
if (arg->isString()) {
QUrl url(arg->toQString());
if (!url.isValid())
THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
- pixmap = r->d()->context->createPixmap(url);
+ pixmap = r->d()->context()->createPixmap(url);
} else if (arg->isObject()) {
QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, arg);
if (!!qobjectWrapper) {
if (QQuickImage *imageItem = qobject_cast<QQuickImage*>(qobjectWrapper->object())) {
- pixmap = r->d()->context->createPixmap(imageItem->source());
+ pixmap = r->d()->context()->createPixmap(imageItem->source());
} else if (QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(qobjectWrapper->object())) {
QImage img = canvas->toImage();
if (!img.isNull())
@@ -2898,7 +3120,7 @@ void QQuickJSContext2DPrototype::method_drawImage(const QV4::BuiltinFunction *,
} else {
QUrl url(arg->toQStringNoThrow());
if (url.isValid())
- pixmap = r->d()->context->createPixmap(url);
+ pixmap = r->d()->context()->createPixmap(url);
else
THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
@@ -2908,29 +3130,29 @@ void QQuickJSContext2DPrototype::method_drawImage(const QV4::BuiltinFunction *,
}
if (pixmap.isNull() || !pixmap->isValid())
- return;
+ RETURN_UNDEFINED();
- if (callData->argc >= 9) {
- sx = callData->args[1].toNumber();
- sy = callData->args[2].toNumber();
- sw = callData->args[3].toNumber();
- sh = callData->args[4].toNumber();
- dx = callData->args[5].toNumber();
- dy = callData->args[6].toNumber();
- dw = callData->args[7].toNumber();
- dh = callData->args[8].toNumber();
- } else if (callData->argc >= 5) {
+ if (argc >= 9) {
+ sx = argv[1].toNumber();
+ sy = argv[2].toNumber();
+ sw = argv[3].toNumber();
+ sh = argv[4].toNumber();
+ dx = argv[5].toNumber();
+ dy = argv[6].toNumber();
+ dw = argv[7].toNumber();
+ dh = argv[8].toNumber();
+ } else if (argc >= 5) {
sx = 0;
sy = 0;
sw = pixmap->width();
sh = pixmap->height();
- dx = callData->args[1].toNumber();
- dy = callData->args[2].toNumber();
- dw = callData->args[3].toNumber();
- dh = callData->args[4].toNumber();
- } else if (callData->argc >= 3) {
- dx = callData->args[1].toNumber();
- dy = callData->args[2].toNumber();
+ dx = argv[1].toNumber();
+ dy = argv[2].toNumber();
+ dw = argv[3].toNumber();
+ dh = argv[4].toNumber();
+ } else if (argc >= 3) {
+ dx = argv[1].toNumber();
+ dy = argv[2].toNumber();
sx = 0;
sy = 0;
sw = pixmap->width();
@@ -2938,7 +3160,7 @@ void QQuickJSContext2DPrototype::method_drawImage(const QV4::BuiltinFunction *,
dw = sw;
dh = sh;
} else {
- return;
+ RETURN_UNDEFINED();
}
if (!qt_is_finite(sx)
@@ -2949,7 +3171,7 @@ void QQuickJSContext2DPrototype::method_drawImage(const QV4::BuiltinFunction *,
|| !qt_is_finite(dy)
|| !qt_is_finite(dw)
|| !qt_is_finite(dh))
- return;
+ RETURN_UNDEFINED();
if (sx < 0
|| sy < 0
@@ -2961,7 +3183,9 @@ void QQuickJSContext2DPrototype::method_drawImage(const QV4::BuiltinFunction *,
THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
}
- r->d()->context->buffer()->drawPixmap(pixmap, QRectF(sx, sy, sw, sh), QRectF(dx, dy, dw, dh));
+ r->d()->context()->buffer()->drawPixmap(pixmap, QRectF(sx, sy, sw, sh), QRectF(dx, dy, dw, dh));
+
+ RETURN_RESULT(*thisObject);
}
// pixel manipulation
@@ -2969,7 +3193,7 @@ void QQuickJSContext2DPrototype::method_drawImage(const QV4::BuiltinFunction *,
\qmltype CanvasImageData
\inqmlmodule QtQuick
\ingroup qtquick-canvas
- \brief Contains image pixel data in RGBA order
+ \brief Contains image pixel data in RGBA order.
The CanvasImageData object holds the image pixel data.
@@ -2988,47 +3212,50 @@ void QQuickJSContext2DPrototype::method_drawImage(const QV4::BuiltinFunction *,
\qmlproperty int QtQuick::CanvasImageData::width
Holds the actual width dimension of the data in the ImageData object, in device pixels.
*/
-void QQuickJSContext2DImageData::method_get_width(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DImageData::method_get_width(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, *thisObject);
if (!imageData)
THROW_TYPE_ERROR();
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>());
int width = r ? r->d()->image->width() : 0;
- scope.result = QV4::Encode(width);
+ RETURN_RESULT(QV4::Encode(width));
}
/*!
\qmlproperty int QtQuick::CanvasImageData::height
Holds the actual height dimension of the data in the ImageData object, in device pixels.
*/
-void QQuickJSContext2DImageData::method_get_height(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DImageData::method_get_height(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, *thisObject);
if (!imageData)
THROW_TYPE_ERROR();
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>());
int height = r ? r->d()->image->height() : 0;
- scope.result = QV4::Encode(height);
+ RETURN_RESULT(QV4::Encode(height));
}
/*!
\qmlproperty object QtQuick::CanvasImageData::data
Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
*/
-void QQuickJSContext2DImageData::method_get_data(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DImageData::method_get_data(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, callData->thisObject);
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, *thisObject);
if (!imageData)
THROW_TYPE_ERROR();
- scope.result = imageData->d()->pixelData;
+ RETURN_RESULT(imageData->d()->pixelData);
}
/*!
\qmltype CanvasPixelArray
\inqmlmodule QtQuick
\ingroup qtquick-canvas
- \brief Provides ordered and indexed access to the components of each pixel in image data
+ \brief Provides ordered and indexed access to the components of each pixel in image data.
The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
The CanvasPixelArray can be accessed as normal Javascript array.
@@ -3042,17 +3269,22 @@ void QQuickJSContext2DImageData::method_get_data(const QV4::BuiltinFunction *, Q
The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
This property is read only.
*/
-void QQuickJSContext2DPixelData::proto_get_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPixelData::proto_get_length(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
- QV4::Scoped<QQuickJSContext2DPixelData> r(scope, callData->thisObject.as<QQuickJSContext2DPixelData>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2DPixelData> r(scope, thisObject->as<QQuickJSContext2DPixelData>());
if (!r || r->d()->image->isNull())
RETURN_UNDEFINED();
RETURN_RESULT(QV4::Encode(r->d()->image->width() * r->d()->image->height() * 4));
}
-QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, uint index, bool *hasProperty)
+QV4::ReturnedValue QQuickJSContext2DPixelData::virtualGet(const QV4::Managed *m, QV4::PropertyKey id, const QV4::Value *receiver, bool *hasProperty)
{
+ if (!id.isArrayIndex())
+ return QV4::Object::virtualGet(m, id, receiver, hasProperty);
+
+ uint index = id.asArrayIndex();
Q_ASSERT(m->as<QQuickJSContext2DPixelData>());
QV4::ExecutionEngine *v4 = static_cast<const QQuickJSContext2DPixelData *>(m)->engine();
QV4::Scope scope(v4);
@@ -3077,19 +3309,24 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m,
return QV4::Encode(qAlpha(*pixel));
}
}
+
if (hasProperty)
*hasProperty = false;
return QV4::Encode::undefined();
}
-bool QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const QV4::Value &value)
+bool QQuickJSContext2DPixelData::virtualPut(QV4::Managed *m, QV4::PropertyKey id, const QV4::Value &value, QV4::Value *receiver)
{
+ if (!id.isArrayIndex())
+ return Object::virtualPut(m, id, value, receiver);
+
Q_ASSERT(m->as<QQuickJSContext2DPixelData>());
QV4::ExecutionEngine *v4 = static_cast<QQuickJSContext2DPixelData *>(m)->engine();
QV4::Scope scope(v4);
if (scope.hasException())
return false;
+ uint index = id.asArrayIndex();
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, static_cast<QQuickJSContext2DPixelData *>(m));
const int v = value.toInt32();
@@ -3140,13 +3377,14 @@ bool QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q
\sa Canvas::loadImage(), QtQuick::Canvas::unloadImage(),
QtQuick::Canvas::isImageLoaded
*/
-void QQuickJSContext2DPrototype::method_createImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_createImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc == 1) {
- QV4::ScopedValue arg0(scope, callData->args[0]);
+ if (argc == 1) {
+ QV4::ScopedValue arg0(scope, argv[0]);
QV4::Scoped<QQuickJSContext2DImageData> imgData(scope, arg0);
if (!!imgData) {
QV4::Scoped<QQuickJSContext2DPixelData> pa(scope, imgData->d()->pixelData.as<QQuickJSContext2DPixelData>());
@@ -3156,12 +3394,12 @@ void QQuickJSContext2DPrototype::method_createImageData(const QV4::BuiltinFuncti
RETURN_RESULT(qt_create_image_data(w, h, scope.engine, QImage()));
}
} else if (arg0->isString()) {
- QImage image = r->d()->context->createPixmap(QUrl(arg0->toQStringNoThrow()))->image();
+ QImage image = r->d()->context()->createPixmap(QUrl(arg0->toQStringNoThrow()))->image();
RETURN_RESULT(qt_create_image_data(image.width(), image.height(), scope.engine, image));
}
- } else if (callData->argc == 2) {
- qreal w = callData->args[0].toNumber();
- qreal h = callData->args[1].toNumber();
+ } else if (argc == 2) {
+ qreal w = argv[0].toNumber();
+ qreal h = argv[1].toNumber();
if (!qt_is_finite(w) || !qt_is_finite(h))
THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments");
@@ -3178,66 +3416,66 @@ void QQuickJSContext2DPrototype::method_createImageData(const QV4::BuiltinFuncti
\qmlmethod CanvasImageData QtQuick::Context2D::getImageData(real sx, real sy, real sw, real sh)
Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
*/
-void QQuickJSContext2DPrototype::method_getImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_getImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc >= 4) {
- qreal x = callData->args[0].toNumber();
- qreal y = callData->args[1].toNumber();
- qreal w = callData->args[2].toNumber();
- qreal h = callData->args[3].toNumber();
+ if (argc >= 4) {
+ qreal x = argv[0].toNumber();
+ qreal y = argv[1].toNumber();
+ qreal w = argv[2].toNumber();
+ qreal h = argv[3].toNumber();
if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h))
THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments");
if (w <= 0 || h <= 0)
THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "getImageData(): Invalid arguments");
- QImage image = r->d()->context->canvas()->toImage(QRectF(x, y, w, h));
+ QImage image = r->d()->context()->canvas()->toImage(QRectF(x, y, w, h));
RETURN_RESULT(qt_create_image_data(w, h, scope.engine, image));
}
- scope.result = QV4::Encode::null();
+ RETURN_RESULT(QV4::Encode::null());
}
/*!
\qmlmethod object QtQuick::Context2D::putImageData(CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
Paints the data from the given ImageData object onto the canvas. If a dirty rectangle (\a dirtyX, \a dirtyY, \a dirtyWidth, \a dirtyHeight) is provided, only the pixels from that rectangle are painted.
*/
-void QQuickJSContext2DPrototype::method_putImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (callData->argc < 7)
+ if (argc < 7)
RETURN_UNDEFINED();
- QV4::ScopedValue arg0(scope, callData->args[0]);
+ QV4::ScopedValue arg0(scope, argv[0]);
if (!arg0->isObject())
THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "Context2D::putImageData, the image data type mismatch");
- qreal dx = callData->args[1].toNumber();
- qreal dy = callData->args[2].toNumber();
+ qreal dx = argv[1].toNumber();
+ qreal dy = argv[2].toNumber();
qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
if (!qt_is_finite(dx) || !qt_is_finite(dy))
THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
- scope.result = callData->thisObject;
-
QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, arg0);
if (!imageData)
- return;
+ RETURN_UNDEFINED();
QV4::Scoped<QQuickJSContext2DPixelData> pixelArray(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>());
if (pixelArray) {
w = pixelArray->d()->image->width();
h = pixelArray->d()->image->height();
- if (callData->argc == 7) {
- dirtyX = callData->args[3].toNumber();
- dirtyY = callData->args[4].toNumber();
- dirtyWidth = callData->args[5].toNumber();
- dirtyHeight = callData->args[6].toNumber();
+ if (argc == 7) {
+ dirtyX = argv[3].toNumber();
+ dirtyY = argv[4].toNumber();
+ dirtyWidth = argv[5].toNumber();
+ dirtyHeight = argv[6].toNumber();
if (!qt_is_finite(dirtyX) || !qt_is_finite(dirtyY) || !qt_is_finite(dirtyWidth) || !qt_is_finite(dirtyHeight))
THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
@@ -3272,7 +3510,7 @@ void QQuickJSContext2DPrototype::method_putImageData(const QV4::BuiltinFunction
}
if (dirtyWidth <=0 || dirtyHeight <= 0)
- return;
+ RETURN_UNDEFINED();
} else {
dirtyX = 0;
dirtyY = 0;
@@ -3281,8 +3519,10 @@ void QQuickJSContext2DPrototype::method_putImageData(const QV4::BuiltinFunction
}
QImage image = pixelArray->d()->image->copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
- r->d()->context->buffer()->drawImage(image, QRectF(dirtyX, dirtyY, dirtyWidth, dirtyHeight), QRectF(dx, dy, dirtyWidth, dirtyHeight));
+ r->d()->context()->buffer()->drawImage(image, QRectF(dirtyX, dirtyY, dirtyWidth, dirtyHeight), QRectF(dx, dy, dirtyWidth, dirtyHeight));
}
+
+ RETURN_RESULT(*thisObject);
}
/*!
@@ -3290,7 +3530,7 @@ void QQuickJSContext2DPrototype::method_putImageData(const QV4::BuiltinFunction
\inqmlmodule QtQuick
\since 5.0
\ingroup qtquick-canvas
- \brief Provides an opaque CanvasGradient interface
+ \brief Provides an opaque CanvasGradient interface.
*/
/*!
@@ -3305,24 +3545,25 @@ void QQuickJSContext2DPrototype::method_putImageData(const QV4::BuiltinFunction
gradient.addColorStop(0.7, 'rgba(0, 255, 255, 1');
\endcode
*/
-void QQuickContext2DStyle::gradient_proto_addColorStop(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
- QV4::Scoped<QQuickContext2DStyle> style(scope, callData->thisObject.as<QQuickContext2DStyle>());
+ QV4::Scope scope(b);
+ QV4::Scoped<QQuickContext2DStyle> style(scope, thisObject->as<QQuickContext2DStyle>());
if (!style)
THROW_GENERIC_ERROR("Not a CanvasGradient object");
- if (callData->argc == 2) {
+ if (argc == 2) {
if (!style->d()->brush->gradient())
THROW_GENERIC_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
QGradient gradient = *(style->d()->brush->gradient());
- qreal pos = callData->args[0].toNumber();
+ qreal pos = argv[0].toNumber();
QColor color;
- if (callData->args[1].as<Object>()) {
- color = scope.engine->toVariant(callData->args[1], qMetaTypeId<QColor>()).value<QColor>();
+ if (argv[1].as<Object>()) {
+ color = scope.engine->toVariant(argv[1], qMetaTypeId<QColor>()).value<QColor>();
} else {
- color = qt_color_from_string(callData->args[1]);
+ color = qt_color_from_string(argv[1]);
}
if (pos < 0.0 || pos > 1.0 || !qt_is_finite(pos)) {
THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range");
@@ -3336,7 +3577,7 @@ void QQuickContext2DStyle::gradient_proto_addColorStop(const QV4::BuiltinFunctio
*style->d()->brush = gradient;
}
- scope.result = callData->thisObject;
+ return thisObject->asReturnedValue();
}
void QQuickContext2D::scale(qreal x, qreal y)
@@ -3843,10 +4084,10 @@ static int textAlignOffset(QQuickContext2D::TextAlignType value, const QFontMetr
value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Right: QQuickContext2D::Left;
switch (value) {
case QQuickContext2D::Center:
- offset = metrics.width(text)/2;
+ offset = metrics.horizontalAdvance(text) / 2;
break;
case QQuickContext2D::Right:
- offset = metrics.width(text);
+ offset = metrics.horizontalAdvance(text);
case QQuickContext2D::Left:
default:
break;
@@ -3960,7 +4201,7 @@ class QQuickContext2DTextureCleanup : public QRunnable
{
public:
QQuickContext2DTexture *texture;
- void run() Q_DECL_OVERRIDE { delete texture; }
+ void run() override { delete texture; }
};
QMutex QQuickContext2D::mutex;
@@ -3968,10 +4209,10 @@ QMutex QQuickContext2D::mutex;
QQuickContext2D::QQuickContext2D(QObject *parent)
: QQuickCanvasContext(parent)
, m_buffer(new QQuickContext2DCommandBuffer)
- , m_v4engine(0)
- , m_surface(0)
- , m_glContext(0)
- , m_thread(0)
+ , m_v4engine(nullptr)
+ , m_surface(nullptr)
+ , m_glContext(nullptr)
+ , m_thread(nullptr)
, m_grabbed(false)
{
}
@@ -3979,7 +4220,7 @@ QQuickContext2D::QQuickContext2D(QObject *parent)
QQuickContext2D::~QQuickContext2D()
{
mutex.lock();
- m_texture->setItem(0);
+ m_texture->setItem(nullptr);
delete m_buffer;
if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
@@ -4159,7 +4400,7 @@ QImage QQuickContext2D::toImage(const QRectF& bounds)
} else {
#if QT_CONFIG(opengl)
QQuickWindow *window = m_canvas->window();
- QOpenGLContext *ctx = window ? window->openglContext() : 0;
+ QOpenGLContext *ctx = window ? window->openglContext() : nullptr;
if (ctx && ctx->isValid()) {
if (ctx == QOpenGLContext::currentContext()) {
flush();
@@ -4220,6 +4461,7 @@ QQuickContext2DEngineData::QQuickContext2DEngineData(QV4::ExecutionEngine *v4)
proto->defineAccessorProperty(QStringLiteral("lineWidth"), QQuickJSContext2D::method_get_lineWidth, QQuickJSContext2D::method_set_lineWidth);
proto->defineAccessorProperty(QStringLiteral("textAlign"), QQuickJSContext2D::method_get_textAlign, QQuickJSContext2D::method_set_textAlign);
proto->defineAccessorProperty(QStringLiteral("shadowBlur"), QQuickJSContext2D::method_get_shadowBlur, QQuickJSContext2D::method_set_shadowBlur);
+ proto->defineAccessorProperty(QStringLiteral("lineDashOffset"), QQuickJSContext2D::method_get_lineDashOffset, QQuickJSContext2D::method_set_lineDashOffset);
contextPrototype = proto;
proto = scope.engine->newObject();
@@ -4227,7 +4469,7 @@ QQuickContext2DEngineData::QQuickContext2DEngineData(QV4::ExecutionEngine *v4)
gradientProto = proto;
proto = scope.engine->newObject();
- proto->defineAccessorProperty(scope.engine->id_length(), QQuickJSContext2DPixelData::proto_get_length, 0);
+ proto->defineAccessorProperty(scope.engine->id_length(), QQuickJSContext2DPixelData::proto_get_length, nullptr);
pixelArrayProto = proto;
}
@@ -4283,6 +4525,10 @@ void QQuickContext2D::popState()
if (newState.shadowOffsetY != state.shadowOffsetY)
buffer()->setShadowOffsetY(newState.shadowOffsetY);
+
+ if (newState.lineDash != state.lineDash)
+ buffer()->setLineDash(newState.lineDash);
+
m_path = state.matrix.map(m_path);
state = newState;
m_path = state.matrix.inverted().map(m_path);
@@ -4311,15 +4557,15 @@ void QQuickContext2D::setV4Engine(QV4::ExecutionEngine *engine)
if (m_v4engine != engine) {
m_v4engine = engine;
- if (m_v4engine == 0)
+ if (m_v4engine == nullptr)
return;
QQuickContext2DEngineData *ed = engineData(engine);
QV4::Scope scope(engine);
- QV4::Scoped<QQuickJSContext2D> wrapper(scope, engine->memoryManager->allocObject<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> wrapper(scope, engine->memoryManager->allocate<QQuickJSContext2D>());
QV4::ScopedObject p(scope, ed->contextPrototype.value());
- wrapper->setPrototype(p);
- wrapper->d()->context = this;
+ wrapper->setPrototypeOf(p);
+ wrapper->d()->setContext(this);
m_v4value = wrapper;
}
}
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 334bf08329..1ece6796f3 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -112,6 +112,8 @@ public:
LineWidth,
LineCap,
LineJoin,
+ LineDash,
+ LineDashOffset,
MiterLimit,
ShadowOffsetX,
ShadowOffsetY,
@@ -142,6 +144,7 @@ public:
, lineWidth(1)
, lineCap(Qt::FlatCap)
, lineJoin(Qt::MiterJoin)
+ , lineDashOffset(0)
, miterLimit(10)
, shadowOffsetX(0)
, shadowOffsetY(0)
@@ -170,6 +173,8 @@ public:
qreal lineWidth;
Qt::PenCapStyle lineCap;
Qt::PenJoinStyle lineJoin;
+ QVector<qreal> lineDash;
+ qreal lineDashOffset;
qreal miterLimit;
qreal shadowOffsetX;
qreal shadowOffsetY;
@@ -181,7 +186,7 @@ public:
QQuickContext2D::TextBaseLineType textBaseline;
};
- QQuickContext2D(QObject *parent = 0);
+ QQuickContext2D(QObject *parent = nullptr);
~QQuickContext2D();
QStringList contextNames() const override;
@@ -199,7 +204,7 @@ public:
QQuickCanvasItem* canvas() const { return m_canvas; }
QQuickContext2DCommandBuffer* buffer() const { return m_buffer; }
- bool bufferValid() const { return m_buffer != 0; }
+ bool bufferValid() const { return m_buffer != nullptr; }
void popState();
void pushState();
void reset();
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index b985cb0ccc..55ebbe907c 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -100,8 +100,8 @@ namespace {
{
}
- void paint(QPainter *p) const Q_DECL_OVERRIDE { p->fillRect(m_rect, m_brush); }
- QRectF boundingRect() const Q_DECL_OVERRIDE { return m_rect; }
+ void paint(QPainter *p) const override { p->fillRect(m_rect, m_brush); }
+ QRectF boundingRect() const override { return m_rect; }
private:
QRectF m_rect;
@@ -117,8 +117,8 @@ namespace {
{
}
- void paint(QPainter *p) const Q_DECL_OVERRIDE { p->fillPath(m_path, m_brush); }
- QRectF boundingRect() const Q_DECL_OVERRIDE { return m_path.boundingRect(); }
+ void paint(QPainter *p) const override { p->fillPath(m_path, m_brush); }
+ QRectF boundingRect() const override { return m_path.boundingRect(); }
private:
QPainterPath m_path;
@@ -134,9 +134,9 @@ namespace {
{
}
- void paint(QPainter *p) const Q_DECL_OVERRIDE { p->strokePath(m_path, m_pen); }
+ void paint(QPainter *p) const override { p->strokePath(m_path, m_pen); }
- QRectF boundingRect() const Q_DECL_OVERRIDE
+ QRectF boundingRect() const override
{
qreal d = qMax(qreal(1), m_pen.widthF());
return m_path.boundingRect().adjusted(-d, -d, d, d);
@@ -156,9 +156,9 @@ namespace {
{
}
- void paint(QPainter *p) const Q_DECL_OVERRIDE { p->drawImage(m_offset, m_image); }
+ void paint(QPainter *p) const override { p->drawImage(m_offset, m_image); }
- QRectF boundingRect() const Q_DECL_OVERRIDE { return QRectF(m_image.rect()).translated(m_offset); }
+ QRectF boundingRect() const override { return QRectF(m_image.rect()).translated(m_offset); }
private:
QImage m_image;
@@ -192,6 +192,10 @@ QPen QQuickContext2DCommandBuffer::makePen(const QQuickContext2D::State& state)
pen.setJoinStyle(state.lineJoin);
pen.setMiterLimit(state.miterLimit);
pen.setBrush(state.strokeStyle);
+ if (!state.lineDash.isEmpty()) {
+ pen.setDashPattern(state.lineDash);
+ }
+ pen.setDashOffset(state.lineDashOffset);
return pen;
}
@@ -361,6 +365,28 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
p->setPen(nPen);
break;
}
+ case QQuickContext2D::LineDash:
+ {
+ const qreal count = takeReal();
+ QVector<qreal> pattern;
+ pattern.reserve(count);
+ for (uint i = 0; i < count; i++) {
+ pattern.append(takeReal());
+ }
+ state.lineDash = pattern;
+ QPen nPen = p->pen();
+ nPen.setDashPattern(pattern);
+ p->setPen(nPen);
+ break;
+ }
+ case QQuickContext2D::LineDashOffset:
+ {
+ state.lineDashOffset = takeReal();
+ QPen nPen = p->pen();
+ nPen.setDashOffset(state.lineDashOffset);
+ p->setPen(nPen);
+ break;
+ }
case QQuickContext2D::MiterLimit:
{
state.miterLimit = takeMiterLimit();
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
index 2a1ac7304e..c3e844c929 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
@@ -201,6 +201,20 @@ public:
ints << join;
}
+ inline void setLineDash(const QVector<qreal> &pattern)
+ {
+ commands << QQuickContext2D::LineDash;
+ reals << pattern.length();
+ for (qreal r : pattern)
+ reals << r;
+ }
+
+ inline void setLineDashOffset( qreal offset)
+ {
+ commands << QQuickContext2D::LineDashOffset;
+ reals << offset;
+ }
+
inline void setMiterLimit( qreal limit)
{
commands << QQuickContext2D::MiterLimit;
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index df6dd9dba2..69ff3b3852 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -54,6 +54,9 @@
#include <QtGui/QGuiApplication>
QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcCanvas, "qt.quick.canvas")
+
#if QT_CONFIG(opengl)
#define QT_MINIMUM_FBO_SIZE 64
@@ -90,12 +93,13 @@ struct GLAcquireContext {
};
#endif
QQuickContext2DTexture::QQuickContext2DTexture()
- : m_context(0)
+ : m_context(nullptr)
#if QT_CONFIG(opengl)
- , m_gl(0)
+ , m_gl(nullptr)
#endif
- , m_surface(0)
- , m_item(0)
+ , m_surface(nullptr)
+ , m_item(nullptr)
+ , m_canvasDevicePixelRatio(1)
, m_canvasWindowChanged(false)
, m_dirtyTexture(false)
, m_smooth(true)
@@ -155,18 +159,28 @@ void QQuickContext2DTexture::setItem(QQuickCanvasItem* item)
m_context = (QQuickContext2D*) item->rawContext(); // FIXME
m_state = m_context->state;
} else {
- m_context = 0;
+ m_context = nullptr;
}
}
bool QQuickContext2DTexture::setCanvasWindow(const QRect& r)
{
+ qreal canvasDevicePixelRatio = (m_item && m_item->window()) ?
+ m_item->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio();
+ if (!qFuzzyCompare(m_canvasDevicePixelRatio, canvasDevicePixelRatio)) {
+ qCDebug(lcCanvas, "%s device pixel ratio %.1lf -> %.1lf",
+ (m_item->objectName().isEmpty() ? "Canvas" : qPrintable(m_item->objectName())),
+ m_canvasDevicePixelRatio, canvasDevicePixelRatio);
+ m_canvasDevicePixelRatio = canvasDevicePixelRatio;
+ m_canvasWindowChanged = true;
+ }
+
if (m_canvasWindow != r) {
m_canvasWindow = r;
m_canvasWindowChanged = true;
- return true;
}
- return false;
+
+ return m_canvasWindowChanged;
}
bool QQuickContext2DTexture::setDirtyRect(const QRect &r)
@@ -243,7 +257,7 @@ void QQuickContext2DTexture::paintWithoutTiles(QQuickContext2DCommandBuffer *ccb
bool QQuickContext2DTexture::canvasDestroyed()
{
- return m_item == 0;
+ return m_item == nullptr;
}
void QQuickContext2DTexture::paint(QQuickContext2DCommandBuffer *ccb)
@@ -335,7 +349,7 @@ QRect QQuickContext2DTexture::createTiles(const QRect& window)
int ht = xx + h1;
int vt = yy + v1;
- QQuickContext2DTile* tile = 0;
+ QQuickContext2DTile* tile = nullptr;
QPoint pos(ht * tw, vt * th);
QRect rect(pos, m_tileSize);
@@ -406,9 +420,9 @@ static inline QSize npotAdjustedSize(const QSize &size)
QQuickContext2DFBOTexture::QQuickContext2DFBOTexture()
: QQuickContext2DTexture()
- , m_fbo(0)
- , m_multisampledFbo(0)
- , m_paint_device(0)
+ , m_fbo(nullptr)
+ , m_multisampledFbo(nullptr)
+ , m_paint_device(nullptr)
{
m_displayTextures[0] = 0;
m_displayTextures[1] = 0;
@@ -549,24 +563,21 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
{
QQuickContext2DTexture::beginPainting();
- const qreal devicePixelRatio = (m_item && m_item->window()) ?
- m_item->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio();
-
if (m_canvasWindow.size().isEmpty()) {
delete m_fbo;
delete m_multisampledFbo;
delete m_paint_device;
- m_fbo = 0;
- m_multisampledFbo = 0;
- m_paint_device = 0;
- return 0;
+ m_fbo = nullptr;
+ m_multisampledFbo = nullptr;
+ m_paint_device = nullptr;
+ return nullptr;
} else if (!m_fbo || m_canvasWindowChanged) {
delete m_fbo;
delete m_multisampledFbo;
delete m_paint_device;
- m_paint_device = 0;
+ m_paint_device = nullptr;
- m_fboSize = npotAdjustedSize(m_canvasWindow.size() * devicePixelRatio);
+ m_fboSize = npotAdjustedSize(m_canvasWindow.size() * m_canvasDevicePixelRatio);
m_canvasWindowChanged = false;
if (doMultisampling()) {
@@ -604,7 +615,10 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
QOpenGLPaintDevice *gl_device = new QOpenGLPaintDevice(m_fbo->size());
gl_device->setPaintFlipped(true);
gl_device->setSize(m_fbo->size());
- gl_device->setDevicePixelRatio(devicePixelRatio);
+ gl_device->setDevicePixelRatio(m_canvasDevicePixelRatio);
+ qCDebug(lcCanvas, "%s size %.1lf x %.1lf painting with size %d x %d DPR %.1lf",
+ (m_item->objectName().isEmpty() ? "Canvas" : qPrintable(m_item->objectName())),
+ m_item->width(), m_item->height(), m_fbo->size().width(), m_fbo->size().height(), m_canvasDevicePixelRatio);
m_paint_device = gl_device;
}
@@ -708,16 +722,17 @@ QPaintDevice* QQuickContext2DImageTexture::beginPainting()
QQuickContext2DTexture::beginPainting();
if (m_canvasWindow.size().isEmpty())
- return 0;
+ return nullptr;
- const qreal devicePixelRatio = (m_item && m_item->window()) ?
- m_item->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio();
if (m_canvasWindowChanged) {
- m_image = QImage(m_canvasWindow.size() * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
- m_image.setDevicePixelRatio(devicePixelRatio);
+ m_image = QImage(m_canvasWindow.size() * m_canvasDevicePixelRatio, QImage::Format_ARGB32_Premultiplied);
+ m_image.setDevicePixelRatio(m_canvasDevicePixelRatio);
m_image.fill(0x00000000);
m_canvasWindowChanged = false;
+ qCDebug(lcCanvas, "%s size %.1lf x %.1lf painting with size %d x %d DPR %.1lf",
+ (m_item->objectName().isEmpty() ? "Canvas" : qPrintable(m_item->objectName())),
+ m_item->width(), m_item->height(), m_image.size().width(), m_image.size().height(), m_canvasDevicePixelRatio);
}
return &m_image;
diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h
index 97135816a2..9c4870f328 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h
@@ -146,7 +146,7 @@ protected:
virtual QVector2D scaleFactor() const { return QVector2D(1, 1); }
void paintWithoutTiles(QQuickContext2DCommandBuffer *ccb);
- virtual QPaintDevice* beginPainting() {m_painting = true; return 0; }
+ virtual QPaintDevice* beginPainting() {m_painting = true; return nullptr; }
virtual void endPainting() {m_painting = false;}
virtual QQuickContext2DTile* createTile() const = 0;
virtual void compositeTile(QQuickContext2DTile* tile) = 0;
@@ -168,6 +168,7 @@ protected:
QSize m_canvasSize;
QSize m_tileSize;
QRect m_canvasWindow;
+ qreal m_canvasDevicePixelRatio;
QMutex m_mutex;
QWaitCondition m_condition;
@@ -188,21 +189,21 @@ class QQuickContext2DFBOTexture : public QQuickContext2DTexture
public:
QQuickContext2DFBOTexture();
~QQuickContext2DFBOTexture();
- QQuickContext2DTile* createTile() const Q_DECL_OVERRIDE;
- QPaintDevice* beginPainting() Q_DECL_OVERRIDE;
- void endPainting() Q_DECL_OVERRIDE;
+ QQuickContext2DTile* createTile() const override;
+ QPaintDevice* beginPainting() override;
+ void endPainting() override;
QRectF normalizedTextureSubRect() const;
- QQuickCanvasItem::RenderTarget renderTarget() const Q_DECL_OVERRIDE;
- void compositeTile(QQuickContext2DTile* tile) Q_DECL_OVERRIDE;
- QSize adjustedTileSize(const QSize &ts) Q_DECL_OVERRIDE;
+ QQuickCanvasItem::RenderTarget renderTarget() const override;
+ void compositeTile(QQuickContext2DTile* tile) override;
+ QSize adjustedTileSize(const QSize &ts) override;
- QSGTexture *textureForNextFrame(QSGTexture *, QQuickWindow *window) Q_DECL_OVERRIDE;
+ QSGTexture *textureForNextFrame(QSGTexture *, QQuickWindow *window) override;
protected:
- QVector2D scaleFactor() const Q_DECL_OVERRIDE;
+ QVector2D scaleFactor() const override;
public Q_SLOTS:
- void grabImage(const QRectF& region = QRectF()) Q_DECL_OVERRIDE;
+ void grabImage(const QRectF& region = QRectF()) override;
private:
bool doMultisampling() const;
diff --git a/src/quick/items/context2d/qquickcontext2dtile.cpp b/src/quick/items/context2d/qquickcontext2dtile.cpp
index d31fee7f91..0ee3de6bcc 100644
--- a/src/quick/items/context2d/qquickcontext2dtile.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtile.cpp
@@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE
QQuickContext2DTile::QQuickContext2DTile()
: m_dirty(true)
, m_rect(QRect(0, 0, 1, 1))
- , m_device(0)
+ , m_device(nullptr)
{
}
@@ -95,12 +95,12 @@ QPainter* QQuickContext2DTile::createPainter(bool smooth, bool antialiasing)
return &m_painter;
}
- return 0;
+ return nullptr;
}
#if QT_CONFIG(opengl)
QQuickContext2DFBOTile::QQuickContext2DFBOTile()
: QQuickContext2DTile()
- , m_fbo(0)
+ , m_fbo(nullptr)
{
}
diff --git a/src/quick/items/context2d/qquickcontext2dtile_p.h b/src/quick/items/context2d/qquickcontext2dtile_p.h
index d5255edcfc..c3d4dfef64 100644
--- a/src/quick/items/context2d/qquickcontext2dtile_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtile_p.h
@@ -93,7 +93,7 @@ class QQuickContext2DFBOTile : public QQuickContext2DTile
public:
QQuickContext2DFBOTile();
~QQuickContext2DFBOTile();
- virtual void setRect(const QRect& r) override;
+ void setRect(const QRect& r) override;
QOpenGLFramebufferObject* fbo() const {return m_fbo;}
void drawFinished() override;
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index 0f8061b5ef..e649b5429d 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -41,8 +41,6 @@ HEADERS += \
$$PWD/qquickflickable_p.h \
$$PWD/qquickflickable_p_p.h \
$$PWD/qquickflickablebehavior_p.h \
- $$PWD/qquickrepeater_p.h \
- $$PWD/qquickrepeater_p_p.h \
$$PWD/qquickloader_p.h \
$$PWD/qquickloader_p_p.h \
$$PWD/qquicktranslate_p.h \
@@ -89,7 +87,6 @@ SOURCES += \
$$PWD/qquickmousearea.cpp \
$$PWD/qquickpincharea.cpp \
$$PWD/qquickflickable.cpp \
- $$PWD/qquickrepeater.cpp \
$$PWD/qquickloader.cpp \
$$PWD/qquicktranslate.cpp \
$$PWD/qquickclipnode.cpp \
@@ -125,9 +122,11 @@ qtConfig(quick-gridview) {
qtConfig(quick-itemview) {
HEADERS += \
+ $$PWD/qquickitemviewfxitem_p_p.h \
$$PWD/qquickitemview_p.h \
$$PWD/qquickitemview_p_p.h
SOURCES += \
+ $$PWD/qquickitemviewfxitem.cpp \
$$PWD/qquickitemview.cpp
}
@@ -145,6 +144,14 @@ qtConfig(quick-listview) {
$$PWD/qquicklistview.cpp
}
+qtConfig(quick-tableview) {
+ HEADERS += \
+ $$PWD/qquicktableview_p.h \
+ $$PWD/qquicktableview_p_p.h
+ SOURCES += \
+ $$PWD/qquicktableview.cpp
+}
+
qtConfig(quick-pathview) {
HEADERS += \
$$PWD/qquickpathview_p.h \
@@ -168,6 +175,15 @@ qtConfig(quick-flipable) {
$$PWD/qquickflipable.cpp
}
+qtConfig(quick-repeater) {
+ HEADERS += \
+ $$PWD/qquickrepeater_p.h \
+ $$PWD/qquickrepeater_p_p.h
+
+ SOURCES += \
+ $$PWD/qquickrepeater.cpp
+}
+
qtConfig(quick-shadereffect) {
HEADERS += \
$$PWD/qquickshadereffectsource_p.h \
diff --git a/src/quick/items/items.qrc b/src/quick/items/items.qrc
index da9bf0c828..6aaf757c29 100644
--- a/src/quick/items/items.qrc
+++ b/src/quick/items/items.qrc
@@ -8,9 +8,5 @@
<file>shaders/shadereffect_core.vert</file>
<file>shaders/shadereffectfallback_core.frag</file>
<file>shaders/shadereffectfallback_core.vert</file>
- <file>shaders/lineargradient.vert</file>
- <file>shaders/lineargradient.frag</file>
- <file>shaders/lineargradient_core.vert</file>
- <file>shaders/lineargradient_core.frag</file>
</qresource>
</RCC>
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index c559ee8887..0168c3160c 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE
/*!
\qmltype Accessible
\instantiates QQuickAccessibleAttached
- \brief Enables accessibility of QML items
+ \brief Enables accessibility of QML items.
\inqmlmodule QtQuick
\ingroup qtquick-visual-utility
@@ -410,7 +410,7 @@ void QQuickAccessibleAttached::setIgnored(bool ignored)
bool QQuickAccessibleAttached::doAction(const QString &actionName)
{
- QMetaMethod *sig = 0;
+ QMetaMethod *sig = nullptr;
if (actionName == QAccessibleActionInterface::pressAction())
sig = &sigPress;
else if (actionName == QAccessibleActionInterface::toggleAction())
diff --git a/src/quick/items/qquickanchors.cpp b/src/quick/items/qquickanchors.cpp
index c0bec7d716..8ee4229013 100644
--- a/src/quick/items/qquickanchors.cpp
+++ b/src/quick/items/qquickanchors.cpp
@@ -252,35 +252,35 @@ void QQuickAnchorsPrivate::clearItem(QQuickItem *item)
if (!item)
return;
if (fill == item)
- fill = 0;
+ fill = nullptr;
if (centerIn == item)
- centerIn = 0;
+ centerIn = nullptr;
if (leftAnchorItem == item) {
- leftAnchorItem = 0;
+ leftAnchorItem = nullptr;
usedAnchors &= ~QQuickAnchors::LeftAnchor;
}
if (rightAnchorItem == item) {
- rightAnchorItem = 0;
+ rightAnchorItem = nullptr;
usedAnchors &= ~QQuickAnchors::RightAnchor;
}
if (topAnchorItem == item) {
- topAnchorItem = 0;
+ topAnchorItem = nullptr;
usedAnchors &= ~QQuickAnchors::TopAnchor;
}
if (bottomAnchorItem == item) {
- bottomAnchorItem = 0;
+ bottomAnchorItem = nullptr;
usedAnchors &= ~QQuickAnchors::BottomAnchor;
}
if (vCenterAnchorItem == item) {
- vCenterAnchorItem = 0;
+ vCenterAnchorItem = nullptr;
usedAnchors &= ~QQuickAnchors::VCenterAnchor;
}
if (hCenterAnchorItem == item) {
- hCenterAnchorItem = 0;
+ hCenterAnchorItem = nullptr;
usedAnchors &= ~QQuickAnchors::HCenterAnchor;
}
if (baselineAnchorItem == item) {
- baselineAnchorItem = 0;
+ baselineAnchorItem = nullptr;
usedAnchors &= ~QQuickAnchors::BaselineAnchor;
}
}
@@ -462,7 +462,7 @@ void QQuickAnchorsPrivate::updateOnComplete()
std::sort(dependencies, dependencies + 9);
- QQuickItem *lastDependency = 0;
+ QQuickItem *lastDependency = nullptr;
for (int i = 0; i < 9; ++i) {
QQuickItem *dependency = dependencies[i];
if (lastDependency != dependency) {
@@ -542,7 +542,7 @@ void QQuickAnchors::setFill(QQuickItem *f)
void QQuickAnchors::resetFill()
{
- setFill(0);
+ setFill(nullptr);
}
QQuickItem *QQuickAnchors::centerIn() const
@@ -578,7 +578,7 @@ void QQuickAnchors::setCenterIn(QQuickItem* c)
void QQuickAnchors::resetCenterIn()
{
- setCenterIn(0);
+ setCenterIn(nullptr);
}
bool QQuickAnchorsPrivate::calcStretch(QQuickItem *edge1Item,
@@ -832,7 +832,7 @@ void QQuickAnchors::resetTop()
Q_D(QQuickAnchors);
d->usedAnchors &= ~TopAnchor;
d->remDepend(d->topAnchorItem);
- d->topAnchorItem = Q_NULLPTR;
+ d->topAnchorItem = nullptr;
d->topAnchorLine = QQuickAnchors::InvalidAnchor;
emit topChanged();
d->updateVerticalAnchors();
@@ -872,7 +872,7 @@ void QQuickAnchors::resetBottom()
Q_D(QQuickAnchors);
d->usedAnchors &= ~BottomAnchor;
d->remDepend(d->bottomAnchorItem);
- d->bottomAnchorItem = Q_NULLPTR;
+ d->bottomAnchorItem = nullptr;
d->bottomAnchorLine = QQuickAnchors::InvalidAnchor;
emit bottomChanged();
d->updateVerticalAnchors();
@@ -912,7 +912,7 @@ void QQuickAnchors::resetVerticalCenter()
Q_D(QQuickAnchors);
d->usedAnchors &= ~VCenterAnchor;
d->remDepend(d->vCenterAnchorItem);
- d->vCenterAnchorItem = Q_NULLPTR;
+ d->vCenterAnchorItem = nullptr;
d->vCenterAnchorLine = QQuickAnchors::InvalidAnchor;
emit verticalCenterChanged();
d->updateVerticalAnchors();
@@ -952,7 +952,7 @@ void QQuickAnchors::resetBaseline()
Q_D(QQuickAnchors);
d->usedAnchors &= ~BaselineAnchor;
d->remDepend(d->baselineAnchorItem);
- d->baselineAnchorItem = Q_NULLPTR;
+ d->baselineAnchorItem = nullptr;
d->baselineAnchorLine = QQuickAnchors::InvalidAnchor;
emit baselineChanged();
d->updateVerticalAnchors();
@@ -992,7 +992,7 @@ void QQuickAnchors::resetLeft()
Q_D(QQuickAnchors);
d->usedAnchors &= ~LeftAnchor;
d->remDepend(d->leftAnchorItem);
- d->leftAnchorItem = Q_NULLPTR;
+ d->leftAnchorItem = nullptr;
d->leftAnchorLine = QQuickAnchors::InvalidAnchor;
emit leftChanged();
d->updateHorizontalAnchors();
@@ -1032,7 +1032,7 @@ void QQuickAnchors::resetRight()
Q_D(QQuickAnchors);
d->usedAnchors &= ~RightAnchor;
d->remDepend(d->rightAnchorItem);
- d->rightAnchorItem = Q_NULLPTR;
+ d->rightAnchorItem = nullptr;
d->rightAnchorLine = QQuickAnchors::InvalidAnchor;
emit rightChanged();
d->updateHorizontalAnchors();
@@ -1072,7 +1072,7 @@ void QQuickAnchors::resetHorizontalCenter()
Q_D(QQuickAnchors);
d->usedAnchors &= ~HCenterAnchor;
d->remDepend(d->hCenterAnchorItem);
- d->hCenterAnchorItem = Q_NULLPTR;
+ d->hCenterAnchorItem = nullptr;
d->hCenterAnchorLine = QQuickAnchors::InvalidAnchor;
emit horizontalCenterChanged();
d->updateHorizontalAnchors();
@@ -1324,6 +1324,19 @@ QQuickAnchors::Anchors QQuickAnchors::usedAnchors() const
return static_cast<QQuickAnchors::Anchors>(d->usedAnchors);
}
+Qt::Orientations QQuickAnchors::activeDirections() const
+{
+ Q_D(const QQuickAnchors);
+ if (d->fill || d->centerIn)
+ return Qt::Horizontal | Qt::Vertical;
+ Qt::Orientations o;
+ if (d->usedAnchors & QQuickAnchors::Horizontal_Mask)
+ o |= Qt::Horizontal;
+ if (d->usedAnchors & QQuickAnchors::Vertical_Mask)
+ o |= Qt::Vertical;
+ return o;
+}
+
bool QQuickAnchorsPrivate::checkHValid() const
{
if (usedAnchors & QQuickAnchors::LeftAnchor &&
diff --git a/src/quick/items/qquickanchors_p.h b/src/quick/items/qquickanchors_p.h
index f00b8b5ba7..c7995cb7a8 100644
--- a/src/quick/items/qquickanchors_p.h
+++ b/src/quick/items/qquickanchors_p.h
@@ -86,8 +86,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickAnchors : public QObject
Q_PROPERTY(bool alignWhenCentered READ alignWhenCentered WRITE setAlignWhenCentered NOTIFY centerAlignedChanged)
public:
- QQuickAnchors(QQuickItem *item, QObject *parent=0);
- virtual ~QQuickAnchors();
+ QQuickAnchors(QQuickItem *item, QObject *parent=nullptr);
+ ~QQuickAnchors() override;
enum Anchor
#if defined(Q_CC_CLANG) || !defined(Q_CC_GNU) // meaning: clang and msvc, but NOT gcc proper (because, you know, Q_CC_CLANG implies Q_CC_GNU)
@@ -108,6 +108,7 @@ public:
Vertical_Mask = TopAnchor | BottomAnchor | VCenterAnchor | BaselineAnchor
};
Q_DECLARE_FLAGS(Anchors, Anchor)
+ Q_FLAG(Anchors)
QQuickAnchorLine left() const;
void setLeft(const QQuickAnchorLine &edge);
@@ -174,6 +175,7 @@ public:
void resetCenterIn();
Anchors usedAnchors() const;
+ Qt::Orientations activeDirections() const;
bool mirrored();
diff --git a/src/quick/items/qquickanchors_p_p.h b/src/quick/items/qquickanchors_p_p.h
index 906f607302..0a834276ae 100644
--- a/src/quick/items/qquickanchors_p_p.h
+++ b/src/quick/items/qquickanchors_p_p.h
@@ -60,15 +60,15 @@ QT_BEGIN_NAMESPACE
class QQuickAnchorLine
{
public:
- QQuickAnchorLine() : item(0), anchorLine(QQuickAnchors::InvalidAnchor) {}
+ QQuickAnchorLine() {}
QQuickAnchorLine(QQuickItem *i, QQuickAnchors::Anchor l) : item(i), anchorLine(l) {}
QQuickAnchorLine(QQuickItem *i, uint l)
: item(i)
, anchorLine(static_cast<QQuickAnchors::Anchor>(l))
{ Q_ASSERT(l < ((QQuickAnchors::BaselineAnchor << 1) - 1)); }
- QQuickItem *item;
- QQuickAnchors::Anchor anchorLine;
+ QQuickItem *item = nullptr;
+ QQuickAnchors::Anchor anchorLine = QQuickAnchors::InvalidAnchor;
};
inline bool operator==(const QQuickAnchorLine& a, const QQuickAnchorLine& b)
@@ -90,15 +90,15 @@ public:
, hCenterOffset(0)
, baselineOffset(0)
, item(i)
- , fill(Q_NULLPTR)
- , centerIn(Q_NULLPTR)
- , leftAnchorItem(Q_NULLPTR)
- , rightAnchorItem(Q_NULLPTR)
- , topAnchorItem(Q_NULLPTR)
- , bottomAnchorItem(Q_NULLPTR)
- , vCenterAnchorItem(Q_NULLPTR)
- , hCenterAnchorItem(Q_NULLPTR)
- , baselineAnchorItem(Q_NULLPTR)
+ , fill(nullptr)
+ , centerIn(nullptr)
+ , leftAnchorItem(nullptr)
+ , rightAnchorItem(nullptr)
+ , topAnchorItem(nullptr)
+ , bottomAnchorItem(nullptr)
+ , vCenterAnchorItem(nullptr)
+ , hCenterAnchorItem(nullptr)
+ , baselineAnchorItem(nullptr)
, leftAnchorLine(QQuickAnchors::InvalidAnchor)
, leftMarginExplicit(false)
, rightAnchorLine(QQuickAnchors::InvalidAnchor)
@@ -141,8 +141,8 @@ public:
void updateMe();
// QQuickItemGeometryListener interface
- void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
- QQuickAnchorsPrivate *anchorPrivate() Q_DECL_OVERRIDE { return this; }
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override;
+ QQuickAnchorsPrivate *anchorPrivate() override { return this; }
bool checkHValid() const;
bool checkVValid() const;
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp
index adf460886a..fe445425e7 100644
--- a/src/quick/items/qquickanimatedimage.cpp
+++ b/src/quick/items/qquickanimatedimage.cpp
@@ -54,26 +54,26 @@ QT_BEGIN_NAMESPACE
QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine)
{
- if (!_movie)
- return 0;
+ if (!movie)
+ return nullptr;
- int current = _movie->currentFrameNumber();
+ int current = movie->currentFrameNumber();
if (!frameMap.contains(current)) {
QUrl requestedUrl;
- QQuickPixmap *pixmap = 0;
- if (engine && !_movie->fileName().isEmpty()) {
+ QQuickPixmap *pixmap = nullptr;
+ if (engine && !movie->fileName().isEmpty()) {
requestedUrl.setUrl(QString::fromUtf8("quickanimatedimage://%1#%2")
- .arg(_movie->fileName())
+ .arg(movie->fileName())
.arg(current));
}
if (!requestedUrl.isEmpty()) {
if (QQuickPixmap::isCached(requestedUrl, QSize(), QQuickImageProviderOptions()))
pixmap = new QQuickPixmap(engine, requestedUrl);
else
- pixmap = new QQuickPixmap(requestedUrl, _movie->currentImage());
+ pixmap = new QQuickPixmap(requestedUrl, movie->currentImage());
} else {
pixmap = new QQuickPixmap;
- pixmap->setImage(_movie->currentImage());
+ pixmap->setImage(movie->currentImage());
}
frameMap.insert(current, pixmap);
}
@@ -86,7 +86,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine
\instantiates QQuickAnimatedImage
\inqmlmodule QtQuick
\inherits Image
- \brief Plays animations stored as a series of images
+ \brief Plays animations stored as a series of images.
\ingroup qtquick-visual
The AnimatedImage type extends the features of the \l Image type, providing
@@ -138,7 +138,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine
QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
: QQuickImage(*(new QQuickAnimatedImagePrivate), parent)
{
- QObject::connect(this, &QQuickImageBase::cacheChanged, this, &QQuickAnimatedImage::onCacheChanged);
+ connect(this, &QQuickImageBase::cacheChanged, this, &QQuickAnimatedImage::onCacheChanged);
}
QQuickAnimatedImage::~QQuickAnimatedImage()
@@ -148,7 +148,7 @@ QQuickAnimatedImage::~QQuickAnimatedImage()
if (d->reply)
d->reply->deleteLater();
#endif
- delete d->_movie;
+ delete d->movie;
qDeleteAll(d->frameMap);
d->frameMap.clear();
}
@@ -164,9 +164,9 @@ QQuickAnimatedImage::~QQuickAnimatedImage()
bool QQuickAnimatedImage::isPaused() const
{
Q_D(const QQuickAnimatedImage);
- if (!d->_movie)
+ if (!d->movie)
return d->paused;
- return d->_movie->state()==QMovie::Paused;
+ return d->movie->state()==QMovie::Paused;
}
void QQuickAnimatedImage::setPaused(bool pause)
@@ -174,11 +174,11 @@ void QQuickAnimatedImage::setPaused(bool pause)
Q_D(QQuickAnimatedImage);
if (pause == d->paused)
return;
- if (!d->_movie) {
+ if (!d->movie) {
d->paused = pause;
emit pausedChanged();
} else {
- d->_movie->setPaused(pause);
+ d->movie->setPaused(pause);
}
}
@@ -203,9 +203,9 @@ void QQuickAnimatedImage::setPaused(bool pause)
bool QQuickAnimatedImage::isPlaying() const
{
Q_D(const QQuickAnimatedImage);
- if (!d->_movie)
+ if (!d->movie)
return d->playing;
- return d->_movie->state()!=QMovie::NotRunning;
+ return d->movie->state()!=QMovie::NotRunning;
}
void QQuickAnimatedImage::setPlaying(bool play)
@@ -213,15 +213,15 @@ void QQuickAnimatedImage::setPlaying(bool play)
Q_D(QQuickAnimatedImage);
if (play == d->playing)
return;
- if (!d->_movie) {
+ if (!d->movie) {
d->playing = play;
emit playingChanged();
return;
}
if (play)
- d->_movie->start();
+ d->movie->start();
else
- d->_movie->stop();
+ d->movie->stop();
}
/*!
@@ -237,27 +237,53 @@ void QQuickAnimatedImage::setPlaying(bool play)
int QQuickAnimatedImage::currentFrame() const
{
Q_D(const QQuickAnimatedImage);
- if (!d->_movie)
- return d->preset_currentframe;
- return d->_movie->currentFrameNumber();
+ if (!d->movie)
+ return d->presetCurrentFrame;
+ return d->movie->currentFrameNumber();
}
void QQuickAnimatedImage::setCurrentFrame(int frame)
{
Q_D(QQuickAnimatedImage);
- if (!d->_movie) {
- d->preset_currentframe = frame;
+ if (!d->movie) {
+ d->presetCurrentFrame = frame;
return;
}
- d->_movie->jumpToFrame(frame);
+ d->movie->jumpToFrame(frame);
}
int QQuickAnimatedImage::frameCount() const
{
Q_D(const QQuickAnimatedImage);
- if (!d->_movie)
+ if (!d->movie)
return 0;
- return d->_movie->frameCount();
+ return d->movie->frameCount();
+}
+
+/*!
+ \qmlproperty real QtQuick::AnimatedImage::speed
+ \since QtQuick 2.11
+
+ This property holds the speed of the animation.
+
+ The speed is measured in percentage of the original animated image speed.
+ The default speed is 1.0 (original speed).
+*/
+qreal QQuickAnimatedImage::speed() const
+{
+ Q_D(const QQuickAnimatedImage);
+ return d->speed;
+}
+
+void QQuickAnimatedImage::setSpeed(qreal speed)
+{
+ Q_D(QQuickAnimatedImage);
+ if (d->speed != speed) {
+ d->speed = speed;
+ if (d->movie)
+ d->movie->setSpeed(qRound(speed * 100.0));
+ emit speedChanged();
+ }
}
void QQuickAnimatedImage::setSource(const QUrl &url)
@@ -269,7 +295,7 @@ void QQuickAnimatedImage::setSource(const QUrl &url)
#if QT_CONFIG(qml_network)
if (d->reply) {
d->reply->deleteLater();
- d->reply = 0;
+ d->reply = nullptr;
}
#endif
@@ -278,11 +304,7 @@ void QQuickAnimatedImage::setSource(const QUrl &url)
d->frameMap.clear();
d->oldPlaying = isPlaying();
- if (d->_movie) {
- delete d->_movie;
- d->_movie = 0;
- }
-
+ d->setMovie(nullptr);
d->url = url;
emit sourceChanged(d->url);
@@ -320,7 +342,7 @@ void QQuickAnimatedImage::load()
QString lf = QQmlFile::urlToLocalFileOrQrc(loadUrl);
if (!lf.isEmpty()) {
- d->_movie = new QMovie(lf);
+ d->setMovie(new QMovie(lf));
movieRequestFinished();
} else {
#if QT_CONFIG(qml_network)
@@ -336,10 +358,8 @@ void QQuickAnimatedImage::load()
req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
d->reply = qmlEngine(this)->networkAccessManager()->get(req);
- QObject::connect(d->reply, SIGNAL(finished()),
- this, SLOT(movieRequestFinished()));
- QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
- this, SLOT(requestProgress(qint64,qint64)));
+ connect(d->reply, &QNetworkReply::finished, this, &QQuickAnimatedImage::movieRequestFinished);
+ connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(requestProgress(qint64,qint64)));
#endif
}
}
@@ -366,14 +386,13 @@ void QQuickAnimatedImage::movieRequestFinished()
}
d->redirectCount=0;
- d->_movie = new QMovie(d->reply);
+ d->setMovie(new QMovie(d->reply));
}
#endif
- if (!d->_movie->isValid()) {
+ if (!d->movie || !d->movie->isValid()) {
qmlWarning(this) << "Error Reading Animated Image File " << d->url.toString();
- delete d->_movie;
- d->_movie = 0;
+ d->setMovie(nullptr);
d->setImage(QImage());
if (d->progress != 0) {
d->progress = 0;
@@ -392,12 +411,11 @@ void QQuickAnimatedImage::movieRequestFinished()
return;
}
- connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
- this, SLOT(playingStatusChanged()));
- connect(d->_movie, SIGNAL(frameChanged(int)),
- this, SLOT(movieUpdate()));
+ connect(d->movie, &QMovie::stateChanged, this, &QQuickAnimatedImage::playingStatusChanged);
+ connect(d->movie, &QMovie::frameChanged, this, &QQuickAnimatedImage::movieUpdate);
if (d->cache)
- d->_movie->setCacheMode(QMovie::CacheAll);
+ d->movie->setCacheMode(QMovie::CacheAll);
+ d->movie->setSpeed(qRound(d->speed * 100.0));
d->status = Ready;
emit statusChanged(d->status);
@@ -408,22 +426,24 @@ void QQuickAnimatedImage::movieRequestFinished()
}
bool pausedAtStart = d->paused;
- if (d->playing) {
- d->_movie->start();
+ if (d->movie && d->playing)
+ d->movie->start();
+ if (d->movie && pausedAtStart)
+ d->movie->setPaused(true);
+ if (d->movie && (d->paused || !d->playing)) {
+ d->movie->jumpToFrame(d->presetCurrentFrame);
+ d->presetCurrentFrame = 0;
}
- if (pausedAtStart)
- d->_movie->setPaused(true);
- if (d->paused || !d->playing) {
- d->_movie->jumpToFrame(d->preset_currentframe);
- d->preset_currentframe = 0;
- }
- d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this)));
+
+ QQuickPixmap *pixmap = d->infoForCurrentFrame(qmlEngine(this));
+ if (pixmap)
+ d->setPixmap(*pixmap);
if (isPlaying() != d->oldPlaying)
emit playingChanged();
- if (d->_movie)
- d->currentSourceSize = d->_movie->currentPixmap().size();
+ if (d->movie)
+ d->currentSourceSize = d->movie->currentPixmap().size();
else
d->currentSourceSize = QSize(0, 0);
@@ -442,7 +462,7 @@ void QQuickAnimatedImage::movieUpdate()
d->frameMap.clear();
}
- if (d->_movie) {
+ if (d->movie) {
d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this)));
emit frameChanged();
}
@@ -452,12 +472,12 @@ void QQuickAnimatedImage::playingStatusChanged()
{
Q_D(QQuickAnimatedImage);
- if ((d->_movie->state() != QMovie::NotRunning) != d->playing) {
- d->playing = (d->_movie->state() != QMovie::NotRunning);
+ if ((d->movie->state() != QMovie::NotRunning) != d->playing) {
+ d->playing = (d->movie->state() != QMovie::NotRunning);
emit playingChanged();
}
- if ((d->_movie->state() == QMovie::Paused) != d->paused) {
- d->paused = (d->_movie->state() == QMovie::Paused);
+ if ((d->movie->state() == QMovie::Paused) != d->paused) {
+ d->paused = (d->movie->state() == QMovie::Paused);
emit pausedChanged();
}
}
@@ -468,13 +488,11 @@ void QQuickAnimatedImage::onCacheChanged()
if (!cache()) {
qDeleteAll(d->frameMap);
d->frameMap.clear();
- if (d->_movie) {
- d->_movie->setCacheMode(QMovie::CacheNone);
- }
+ if (d->movie)
+ d->movie->setCacheMode(QMovie::CacheNone);
} else {
- if (d->_movie) {
- d->_movie->setCacheMode(QMovie::CacheAll);
- }
+ if (d->movie)
+ d->movie->setCacheMode(QMovie::CacheAll);
}
}
@@ -490,6 +508,23 @@ void QQuickAnimatedImage::componentComplete()
load();
}
+void QQuickAnimatedImagePrivate::setMovie(QMovie *m)
+{
+ if (movie == m)
+ return;
+ Q_Q(QQuickAnimatedImage);
+ const int oldFrameCount = q->frameCount();
+
+ if (movie) {
+ movie->disconnect();
+ movie->deleteLater();
+ }
+ movie = m;
+
+ if (oldFrameCount != q->frameCount())
+ emit q->frameCountChanged();
+}
+
QT_END_NAMESPACE
#include "moc_qquickanimatedimage_p.cpp"
diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h
index 54da093259..6b5db215bd 100644
--- a/src/quick/items/qquickanimatedimage_p.h
+++ b/src/quick/items/qquickanimatedimage_p.h
@@ -69,13 +69,14 @@ class Q_AUTOTEST_EXPORT QQuickAnimatedImage : public QQuickImage
Q_PROPERTY(bool playing READ isPlaying WRITE setPlaying NOTIFY playingChanged)
Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY frameChanged)
- Q_PROPERTY(int frameCount READ frameCount)
+ Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged)
+ Q_PROPERTY(qreal speed READ speed WRITE setSpeed NOTIFY speedChanged REVISION 11)
// read-only for AnimatedImage
Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged)
public:
- QQuickAnimatedImage(QQuickItem *parent=0);
+ QQuickAnimatedImage(QQuickItem *parent=nullptr);
~QQuickAnimatedImage();
bool isPlaying() const;
@@ -89,14 +90,19 @@ public:
int frameCount() const;
+ qreal speed() const;
+ void setSpeed(qreal speed);
+
// Extends QQuickImage's src property
- void setSource(const QUrl&) Q_DECL_OVERRIDE;
+ void setSource(const QUrl&) override;
virtual QSize sourceSize();
Q_SIGNALS:
void playingChanged();
void pausedChanged();
void frameChanged();
+ void frameCountChanged();
+ Q_REVISION(11) void speedChanged();
private Q_SLOTS:
void movieUpdate();
@@ -105,8 +111,8 @@ private Q_SLOTS:
void onCacheChanged();
protected:
- void load() Q_DECL_OVERRIDE;
- void componentComplete() Q_DECL_OVERRIDE;
+ void load() override;
+ void componentComplete() override;
private:
Q_DISABLE_COPY(QQuickAnimatedImage)
diff --git a/src/quick/items/qquickanimatedimage_p_p.h b/src/quick/items/qquickanimatedimage_p_p.h
index 9eff6a44e3..1a74f67424 100644
--- a/src/quick/items/qquickanimatedimage_p_p.h
+++ b/src/quick/items/qquickanimatedimage_p_p.h
@@ -70,27 +70,30 @@ class QQuickAnimatedImagePrivate : public QQuickImagePrivate
public:
QQuickAnimatedImagePrivate()
- : playing(true), paused(false), preset_currentframe(0), _movie(0), oldPlaying(false)
+ : playing(true), paused(false), oldPlaying(false), padding(0)
+ , presetCurrentFrame(0), speed(1.0), currentSourceSize(0, 0), movie(nullptr)
#if QT_CONFIG(qml_network)
- , reply(0), redirectCount(0)
+ , reply(nullptr), redirectCount(0)
#endif
- , currentSourceSize(0, 0)
{
}
QQuickPixmap *infoForCurrentFrame(QQmlEngine *engine);
+ void setMovie(QMovie *movie);
- bool playing;
- bool paused;
- int preset_currentframe;
- QMovie *_movie;
- bool oldPlaying;
+ bool playing : 1;
+ bool paused : 1;
+ bool oldPlaying : 1;
+ unsigned padding: 29;
+ int presetCurrentFrame;
+ qreal speed;
+ QSize currentSourceSize;
+ QMovie *movie;
#if QT_CONFIG(qml_network)
QNetworkReply *reply;
int redirectCount;
#endif
QMap<int, QQuickPixmap *> frameMap;
- QSize currentSourceSize;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index 4e71b0c65f..18adb4e992 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -63,15 +63,73 @@ QT_BEGIN_NAMESPACE
\inqmlmodule QtQuick
\inherits Item
\ingroup qtquick-visual
- \brief Draws a sprite animation
+ \brief Draws a sprite animation.
AnimatedSprite provides rendering and control over animations which are provided
as multiple frames in the same image file. You can play it at a fixed speed, at the
frame rate of your display, or manually advance and control the progress.
- For details of how a sprite animation is defined see the \l{Sprite Animations} overview.
- Note that the AnimatedSprite type does not use Sprite types to define multiple animations,
- but instead encapsulates a single animation itself.
+ Consider the following sprite sheet:
+
+ \image animatedsprite-loading.png
+
+ It can be divided up into four frames:
+
+ \image animatedsprite-loading-frames.png
+
+ To play each of these frames at a speed of 500 milliseconds per frame, the
+ following code can be used:
+
+ \table
+ \header
+ \li Code
+ \li Result
+ \row
+ \li
+ \code
+ AnimatedSprite {
+ source: "loading.png"
+ frameWidth: 64
+ frameHeight: 64
+ frameCount: 4
+ frameDuration: 500
+ }
+ \endcode
+ \li
+ \image animatedsprite-loading-interpolated.gif
+ \endtable
+
+ By default, the frames are interpolated (blended together) to make the
+ animation appear smoother. To disable this, set \l interpolate to \c false:
+
+ \table
+ \header
+ \li Code
+ \li Result
+ \row
+ \li
+ \code
+ AnimatedSprite {
+ source: "loading.png"
+ frameWidth: 64
+ frameHeight: 64
+ frameCount: 4
+ frameDuration: 500
+ interpolate: false
+ }
+ \endcode
+ \li
+ \image animatedsprite-loading.gif
+ \endtable
+
+ To control how AnimatedSprite responds to being scaled, use the
+ \l {Item::}{smooth} property.
+
+ Note that unlike \l SpriteSequence, the AnimatedSprite type does not use
+ \l Sprite to define multiple animations, but instead encapsulates a
+ single animation itself.
+
+ \sa {Sprite Animations}
*/
/*!
@@ -94,10 +152,10 @@ QT_BEGIN_NAMESPACE
/*!
\qmlproperty qreal QtQuick::AnimatedSprite::frameRate
- Frames per second to show in the animation. Values equal to or below 0 are invalid.
+ Frames per second to show in the animation. Values less than or equal to \c 0 are invalid.
- If frameRate is valid then it will be used to calculate the duration of the frames.
- If not, and frameDuration is valid , then frameDuration will be used.
+ If \c frameRate is valid, it will be used to calculate the duration of the frames.
+ If not, and \l frameDuration is valid, \c frameDuration will be used.
Changing this parameter will restart the animation.
*/
@@ -105,10 +163,10 @@ QT_BEGIN_NAMESPACE
/*!
\qmlproperty int QtQuick::AnimatedSprite::frameDuration
- Duration of each frame of the animation. Values equal to or below 0 are invalid.
+ Duration of each frame of the animation in milliseconds. Values less than or equal to \c 0 are invalid.
- If frameRate is valid then it will be used to calculate the duration of the frames.
- If not, and frameDuration is valid, then frameDuration will be used.
+ If frameRate is valid, it will be used to calculate the duration of the frames.
+ If not, and \l frameDuration is valid, \c frameDuration will be used.
Changing this parameter will restart the animation.
*/
@@ -160,21 +218,21 @@ QT_BEGIN_NAMESPACE
/*!
\qmlproperty bool QtQuick::AnimatedSprite::reverse
- If true, then the animation will be played in reverse.
+ If \c true, the animation will be played in reverse.
- Default is false.
+ Default is \c false.
*/
/*!
\qmlproperty bool QtQuick::AnimatedSprite::frameSync
- If true, then the animation will have no duration. Instead, the animation will advance
+ If \c true, the animation will have no duration. Instead, the animation will advance
one frame each time a frame is rendered to the screen. This synchronizes it with the painting
rate as opposed to elapsed time.
If frameSync is set to true, it overrides both frameRate and frameDuration.
- Default is false.
+ Default is \c false.
Changing this parameter will restart the animation.
*/
@@ -184,9 +242,9 @@ QT_BEGIN_NAMESPACE
After playing the animation this many times, the animation will automatically stop. Negative values are invalid.
- If this is set to AnimatedSprite.Infinite the animation will not stop playing on its own.
+ If this is set to \c AnimatedSprite.Infinite the animation will not stop playing on its own.
- Default is AnimatedSprite.Infinite
+ Default is \c AnimatedSprite.Infinite
*/
/*!
@@ -194,13 +252,13 @@ QT_BEGIN_NAMESPACE
When paused, the current frame can be advanced manually.
- Default is false.
+ Default is \c false.
*/
/*!
\qmlproperty int QtQuick::AnimatedSprite::currentFrame
- When paused, the current frame can be advanced manually by setting this property or calling advance().
+ When paused, the current frame can be advanced manually by setting this property or calling \l advance().
*/
@@ -210,7 +268,16 @@ QT_BEGIN_NAMESPACE
Stops, then starts the sprite animation.
*/
-//TODO: Implicitly size element to size of sprite
+/*!
+ \qmlsignal QtQuick::AnimatedSprite::finished()
+ \since 5.12
+
+ This signal is emitted when the sprite has finished animating.
+
+ It is not emitted when running is set to \c false, nor for sprites whose
+ \l loops property is set to \c AnimatedSprite.Infinite.
+*/
+
QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) :
QQuickItem(*(new QQuickAnimatedSpritePrivate), parent)
{
@@ -395,7 +462,7 @@ void QQuickAnimatedSprite::maybeUpdate()
\qmlmethod int QtQuick::AnimatedSprite::pause()
Pauses the sprite animation. This does nothing if
- \l paused is true.
+ \l paused is \c true.
\sa resume()
*/
@@ -414,7 +481,7 @@ void QQuickAnimatedSprite::pause()
/*!
\qmlmethod int QtQuick::AnimatedSprite::resume()
- Resumes the sprite animation if \l paused is true;
+ Resumes the sprite animation if \l paused is \c true;
otherwise, this does nothing.
\sa pause()
@@ -470,6 +537,8 @@ void QQuickAnimatedSprite::setSource(QUrl arg)
Q_D(QQuickAnimatedSprite);
if (d->m_sprite->m_source != arg) {
+ const qreal targetDevicePixelRatio = (window() ? window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
+ d->m_sprite->setDevicePixelRatio(targetDevicePixelRatio);
d->m_sprite->setSource(arg);
Q_EMIT sourceChanged(arg);
reloadImage();
@@ -516,6 +585,7 @@ void QQuickAnimatedSprite::setFrameHeight(int arg)
if (d->m_sprite->m_frameHeight != arg) {
d->m_sprite->setFrameHeight(arg);
Q_EMIT frameHeightChanged(arg);
+ setImplicitHeight(frameHeight());
reloadImage();
}
}
@@ -527,6 +597,7 @@ void QQuickAnimatedSprite::setFrameWidth(int arg)
if (d->m_sprite->m_frameWidth != arg) {
d->m_sprite->setFrameWidth(arg);
Q_EMIT frameWidthChanged(arg);
+ setImplicitWidth(frameWidth());
reloadImage();
}
}
@@ -641,9 +712,20 @@ QSGSpriteNode* QQuickAnimatedSprite::initNode()
if (image.isNull())
return nullptr;
+ // If frameWidth or frameHeight are not explicitly set, frameWidth
+ // will be set to the width of the image divided by the number of frames,
+ // and frameHeight will be set to the height of the image.
+ // In this case, QQuickAnimatedSprite currently won't emit frameWidth/HeightChanged
+ // at all, so we have to do this here, as it's the only place where assembledImage()
+ // is called (which calculates the "implicit" frameWidth/Height.
+ // In addition, currently the "implicit" frameWidth/Height are only calculated once,
+ // even after changing to a different source.
+ setImplicitWidth(frameWidth());
+ setImplicitHeight(frameHeight());
+
QSGSpriteNode *node = d->sceneGraphContext()->createSpriteNode();
- d->m_sheetSize = QSize(image.size());
+ d->m_sheetSize = QSize(image.size() / image.devicePixelRatioF());
node->setTexture(window()->createTextureFromImage(image));
d->m_spriteEngine->start(0);
node->setTime(0.0f);
@@ -734,6 +816,7 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
frameAt = 0;
d->m_running = false;
emit runningChanged(false);
+ emit finished();
maybeUpdate();
}
} else {
diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h
index 850461a011..ff59591c9f 100644
--- a/src/quick/items/qquickanimatedsprite_p.h
+++ b/src/quick/items/qquickanimatedsprite_p.h
@@ -94,7 +94,7 @@ class Q_AUTOTEST_EXPORT QQuickAnimatedSprite : public QQuickItem
Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged)
public:
- explicit QQuickAnimatedSprite(QQuickItem *parent = 0);
+ explicit QQuickAnimatedSprite(QQuickItem *parent = nullptr);
enum LoopParameters {
Infinite = -1
};
@@ -135,6 +135,8 @@ Q_SIGNALS:
void loopsChanged(int arg);
void currentFrameChanged(int arg);
+ Q_REVISION(12) void finished();
+
public Q_SLOTS:
void start();
void stop();
@@ -169,8 +171,8 @@ protected Q_SLOTS:
void reset();
protected:
- void componentComplete() Q_DECL_OVERRIDE;
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ void componentComplete() override;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
private:
void maybeUpdate();
bool isCurrentFrameChangedConnected();
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index 75e3a3dbed..b840328184 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE
\qmltype BorderImage
\instantiates QQuickBorderImage
\inqmlmodule QtQuick
- \brief Paints a border based on an image
+ \brief Paints a border based on an image.
\inherits Item
\ingroup qtquick-visual
@@ -278,7 +278,7 @@ void QQuickBorderImage::setSource(const QUrl &url)
#if QT_CONFIG(qml_network)
if (d->sciReply) {
d->sciReply->deleteLater();
- d->sciReply = 0;
+ d->sciReply = nullptr;
}
#endif
@@ -559,12 +559,12 @@ void QQuickBorderImage::sciRequestFinished()
if (d->sciReply->error() != QNetworkReply::NoError) {
d->status = Error;
d->sciReply->deleteLater();
- d->sciReply = 0;
+ d->sciReply = nullptr;
emit statusChanged(d->status);
} else {
QQuickGridScaledImage sci(d->sciReply);
d->sciReply->deleteLater();
- d->sciReply = 0;
+ d->sciReply = nullptr;
setGridScaledImage(sci);
}
}
@@ -591,10 +591,18 @@ void QQuickBorderImagePrivate::calculateRects(const QQuickScaleGrid *border,
*innerTargetRect = *targetRect;
if (border) {
- *innerSourceRect = QRectF(border->left() * devicePixelRatio / qreal(sourceSize.width()),
- border->top() * devicePixelRatio / qreal(sourceSize.height()),
- qMax<qreal>(0, sourceSize.width() - (border->right() + border->left()) * devicePixelRatio) / sourceSize.width(),
- qMax<qreal>(0, sourceSize.height() - (border->bottom() + border->top()) * devicePixelRatio) / sourceSize.height());
+ qreal borderLeft = border->left() * devicePixelRatio;
+ qreal borderRight = border->right() * devicePixelRatio;
+ qreal borderTop = border->top() * devicePixelRatio;
+ qreal borderBottom = border->bottom() * devicePixelRatio;
+ if (borderLeft + borderRight > sourceSize.width() && borderLeft < sourceSize.width())
+ borderRight = sourceSize.width() - borderLeft;
+ if (borderTop + borderBottom > sourceSize.height() && borderTop < sourceSize.height())
+ borderBottom = sourceSize.height() - borderTop;
+ *innerSourceRect = QRectF(QPointF(borderLeft / qreal(sourceSize.width()),
+ borderTop / qreal(sourceSize.height())),
+ QPointF((sourceSize.width() - borderRight) / qreal(sourceSize.width()),
+ (sourceSize.height() - borderBottom) / qreal(sourceSize.height()))),
*innerTargetRect = QRectF(border->left(),
border->top(),
qMax<qreal>(0, targetSize.width() - (border->right() + border->left())),
@@ -604,14 +612,16 @@ void QQuickBorderImagePrivate::calculateRects(const QQuickScaleGrid *border,
qreal hTiles = 1;
qreal vTiles = 1;
const QSizeF innerTargetSize = innerTargetRect->size() * devicePixelRatio;
- if (innerSourceRect->width() != 0
- && horizontalTileMode != QQuickBorderImage::Stretch) {
+ if (innerSourceRect->width() <= 0)
+ hTiles = 0;
+ else if (horizontalTileMode != QQuickBorderImage::Stretch) {
hTiles = innerTargetSize.width() / qreal(innerSourceRect->width() * sourceSize.width());
if (horizontalTileMode == QQuickBorderImage::Round)
hTiles = qCeil(hTiles);
}
- if (innerSourceRect->height() != 0
- && verticalTileMode != QQuickBorderImage::Stretch) {
+ if (innerSourceRect->height() <= 0)
+ vTiles = 0;
+ else if (verticalTileMode != QQuickBorderImage::Stretch) {
vTiles = innerTargetSize.height() / qreal(innerSourceRect->height() * sourceSize.height());
if (verticalTileMode == QQuickBorderImage::Round)
vTiles = qCeil(vTiles);
@@ -629,7 +639,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (!texture || width() <= 0 || height() <= 0) {
delete oldNode;
- return 0;
+ return nullptr;
}
QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
diff --git a/src/quick/items/qquickborderimage_p.h b/src/quick/items/qquickborderimage_p.h
index 844f71e2c9..61bd26ba83 100644
--- a/src/quick/items/qquickborderimage_p.h
+++ b/src/quick/items/qquickborderimage_p.h
@@ -69,7 +69,7 @@ class Q_AUTOTEST_EXPORT QQuickBorderImage : public QQuickImageBase
Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged)
public:
- QQuickBorderImage(QQuickItem *parent=0);
+ QQuickBorderImage(QQuickItem *parent=nullptr);
~QQuickBorderImage();
QQuickScaleGrid *border();
@@ -83,7 +83,7 @@ public:
TileMode verticalTileMode() const;
void setVerticalTileMode(TileMode);
- void setSource(const QUrl &url) Q_DECL_OVERRIDE;
+ void setSource(const QUrl &url) override;
Q_SIGNALS:
void horizontalTileModeChanged();
@@ -91,16 +91,16 @@ Q_SIGNALS:
void sourceSizeChanged();
protected:
- void load() Q_DECL_OVERRIDE;
- void pixmapChange() Q_DECL_OVERRIDE;
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ void load() override;
+ void pixmapChange() override;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
private:
void setGridScaledImage(const QQuickGridScaledImage& sci);
private Q_SLOTS:
void doUpdate();
- void requestFinished() Q_DECL_OVERRIDE;
+ void requestFinished() override;
#if QT_CONFIG(qml_network)
void sciRequestFinished();
#endif
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index 41847e5f01..f60f3c1ccf 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -41,7 +41,6 @@
#include <private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
-#include <qpa/qplatformdrag.h>
#include <private/qquickitem_p.h>
#include <QtQuick/private/qquickevents_p_p.h>
#include <private/qquickitemchangelistener_p.h>
@@ -50,12 +49,13 @@
#include <private/qv4scopedvalue_p.h>
#include <QtCore/qmimedata.h>
#include <QtQml/qqmlinfo.h>
-#include <QtGui/qdrag.h>
#include <QtGui/qevent.h>
#include <QtGui/qstylehints.h>
#include <QtGui/qguiapplication.h>
#if QT_CONFIG(draganddrop)
+#include <qpa/qplatformdrag.h>
+#include <QtGui/qdrag.h>
QT_BEGIN_NAMESPACE
@@ -67,8 +67,8 @@ public:
return static_cast<QQuickDragAttachedPrivate *>(QObjectPrivate::get(attached)); }
QQuickDragAttachedPrivate()
- : attachedItem(0)
- , mimeData(0)
+ : attachedItem(nullptr)
+ , mimeData(nullptr)
, proposedAction(Qt::MoveAction)
, supportedActions(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction)
, active(false)
@@ -82,8 +82,8 @@ public:
{
}
- void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
- void itemParentChanged(QQuickItem *, QQuickItem *parent) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override;
+ void itemParentChanged(QQuickItem *, QQuickItem *parent) override;
void updatePosition();
void restartDrag();
void deliverEnterEvent();
@@ -123,7 +123,7 @@ public:
\instantiates QQuickDrag
\inqmlmodule QtQuick
\ingroup qtquick-input
- \brief For specifying drag and drop events for moved Items
+ \brief For specifying drag and drop events for moved Items.
Using the Drag attached property, any Item can be made a source of drag and drop
events within a scene.
@@ -231,7 +231,7 @@ void QQuickDragAttachedPrivate::deliverLeaveEvent()
if (window) {
QDragLeaveEvent event;
deliverEvent(window, &event);
- window = 0;
+ window = nullptr;
}
}
@@ -686,7 +686,7 @@ int QQuickDragAttached::drop()
return acceptedAction;
d->active = false;
- QObject *target = 0;
+ QObject *target = nullptr;
if (d->window) {
QPoint scenePos = d->attachedItem->mapToScene(d->hotSpot).toPoint();
@@ -732,7 +732,7 @@ void QQuickDragAttached::cancel()
d->deliverLeaveEvent();
if (d->target) {
- d->target = 0;
+ d->target = nullptr;
emit targetChanged();
}
@@ -772,6 +772,7 @@ Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedAct
drag->setPixmap(QPixmap::fromImage(pixmapLoader.image()));
}
+ drag->setHotSpot(hotSpot.toPoint());
emit q->dragStarted();
Qt::DropAction dropAction = drag->exec(supportedActions);
@@ -782,7 +783,7 @@ Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedAct
deliverLeaveEvent();
if (target) {
- target = 0;
+ target = nullptr;
emit q->targetChanged();
}
@@ -835,7 +836,7 @@ void QQuickDragAttached::startDrag(QQmlV4Function *args)
}
QQuickDrag::QQuickDrag(QObject *parent)
-: QObject(parent), _target(0), _axis(XAndYAxis), _xmin(-FLT_MAX),
+: QObject(parent), _target(nullptr), _axis(XAndYAxis), _xmin(-FLT_MAX),
_xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false),
_smoothed(true), _threshold(QGuiApplication::styleHints()->startDragDistance())
{
@@ -860,9 +861,9 @@ void QQuickDrag::setTarget(QQuickItem *t)
void QQuickDrag::resetTarget()
{
- if (_target == 0)
+ if (_target == nullptr)
return;
- _target = 0;
+ _target = nullptr;
emit targetChanged();
}
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index 17e9d8c690..6bfbae74c9 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -83,7 +83,7 @@ class QQuickDragGrabber
typedef QIntrusiveList<Item, &Item::node> ItemList;
public:
- QQuickDragGrabber() : m_target(0) {}
+ QQuickDragGrabber() : m_target(nullptr) {}
~QQuickDragGrabber() { while (!m_items.isEmpty()) delete m_items.first(); }
@@ -94,10 +94,10 @@ public:
else if (!m_items.isEmpty())
return *m_items.first();
else
- return 0;
+ return nullptr;
}
void setTarget(QObject *target) { m_target = target; }
- void resetTarget() { m_target = 0; }
+ void resetTarget() { m_target = nullptr; }
bool isEmpty() const { return m_items.isEmpty(); }
@@ -136,7 +136,7 @@ class QQuickDragMimeData : public QMimeData
Q_OBJECT
public:
QQuickDragMimeData()
- : m_source(0)
+ : m_source(nullptr)
{
}
@@ -173,7 +173,7 @@ class Q_AUTOTEST_EXPORT QQuickDrag : public QObject
//### consider drag and drop
public:
- QQuickDrag(QObject *parent=0);
+ QQuickDrag(QObject *parent=nullptr);
~QQuickDrag();
enum DragType { None, Automatic, Internal };
diff --git a/src/quick/items/qquickdroparea.cpp b/src/quick/items/qquickdroparea.cpp
index c7606f90e1..cb87bdce76 100644
--- a/src/quick/items/qquickdroparea.cpp
+++ b/src/quick/items/qquickdroparea.cpp
@@ -78,7 +78,7 @@ public:
};
QQuickDropAreaPrivate::QQuickDropAreaPrivate()
- : drag(0)
+ : drag(nullptr)
, containsDrag(false)
{
}
@@ -93,7 +93,7 @@ QQuickDropAreaPrivate::~QQuickDropAreaPrivate()
\instantiates QQuickDropArea
\inqmlmodule QtQuick
\ingroup qtquick-input
- \brief For specifying drag and drop handling in an area
+ \brief For specifying drag and drop handling in an area.
A DropArea is an invisible item which receives events when other items are
dragged over it.
@@ -303,7 +303,7 @@ void QQuickDropArea::dragLeaveEvent(QDragLeaveEvent *)
emit exited();
d->containsDrag = false;
- d->source = 0;
+ d->source = nullptr;
emit containsDragChanged();
if (d->drag)
emit d->drag->sourceChanged();
@@ -328,7 +328,7 @@ void QQuickDropArea::dropEvent(QDropEvent *event)
emit dropped(&dragTargetEvent);
d->containsDrag = false;
- d->source = 0;
+ d->source = nullptr;
emit containsDragChanged();
if (d->drag)
emit d->drag->sourceChanged();
@@ -339,7 +339,7 @@ void QQuickDropArea::dropEvent(QDropEvent *event)
\instantiates QQuickDropEvent
\inqmlmodule QtQuick
\ingroup qtquick-input-events
- \brief Provides information about a drag event
+ \brief Provides information about a drag event.
The position of the drag event can be obtained from the \l x and \l y
properties, and the \l keys property identifies the drag keys of the event
diff --git a/src/quick/items/qquickdroparea_p.h b/src/quick/items/qquickdroparea_p.h
index 0c4c072db7..d25cd4decc 100644
--- a/src/quick/items/qquickdroparea_p.h
+++ b/src/quick/items/qquickdroparea_p.h
@@ -175,10 +175,10 @@ Q_SIGNALS:
void dropped(QQuickDropEvent *drop);
protected:
- void dragMoveEvent(QDragMoveEvent *event) Q_DECL_OVERRIDE;
- void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE;
- void dragLeaveEvent(QDragLeaveEvent *event) Q_DECL_OVERRIDE;
- void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE;
+ void dragMoveEvent(QDragMoveEvent *event) override;
+ void dragEnterEvent(QDragEnterEvent *event) override;
+ void dragLeaveEvent(QDragLeaveEvent *event) override;
+ void dropEvent(QDropEvent *event) override;
private:
Q_DISABLE_COPY(QQuickDropArea)
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 448b63c347..c43eab6b8a 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -38,8 +38,11 @@
****************************************************************************/
#include "qquickevents_p_p.h"
+#include <QtCore/qmap.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qtouchdevice_p.h>
#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquickwindow_p.h>
#include <private/qdebug_p.h>
@@ -54,7 +57,7 @@ Q_LOGGING_CATEGORY(lcPointerGrab, "qt.quick.pointer.grab")
\inqmlmodule QtQuick
\ingroup qtquick-input-events
- \brief Provides information about a key event
+ \brief Provides information about a key event.
For example, the following changes the Item's state property when the Enter
key is pressed:
@@ -131,13 +134,13 @@ Item {
It contains a bitwise combination of:
\list
- \li Qt.NoModifier - No modifier key is pressed.
- \li Qt.ShiftModifier - A Shift key on the keyboard is pressed.
- \li Qt.ControlModifier - A Ctrl key on the keyboard is pressed.
- \li Qt.AltModifier - An Alt key on the keyboard is pressed.
- \li Qt.MetaModifier - A Meta key on the keyboard is pressed.
- \li Qt.KeypadModifier - A keypad button is pressed.
- \li Qt.GroupSwitchModifier - X11 only. A Mode_switch key on the keyboard is pressed.
+ \li \l {Qt::NoModifier} {Qt.NoModifier} - No modifier key is pressed.
+ \li \l {Qt::ShiftModifier} {Qt.ShiftModifier} - A Shift key on the keyboard is pressed.
+ \li \l {Qt::ControlModifier} {Qt.ControlModifier} - A Ctrl key on the keyboard is pressed.
+ \li \l {Qt::AltModifier} {Qt.AltModifier} - An Alt key on the keyboard is pressed.
+ \li \l {Qt::MetaModifier} {Qt.MetaModifier} - A Meta key on the keyboard is pressed.
+ \li \l {Qt::KeypadModifier} {Qt.KeypadModifier} - A keypad button is pressed.
+ \li \l {Qt::GroupSwitchModifier} {Qt.GroupSwitchModifier} - X11 only. A Mode_switch key on the keyboard is pressed.
\endlist
For example, to react to a Shift key + Enter key combination:
@@ -179,9 +182,9 @@ Item {
\inqmlmodule QtQuick
\ingroup qtquick-input-events
- \brief Provides information about a mouse event
+ \brief Provides information about a mouse event.
- The position of the mouse can be found via the \l x and \l y properties.
+ The position of the mouse can be found via the \l {Item::x} {x} and \l {Item::y} {y} properties.
The button that caused the event is available via the \l button property.
\sa MouseArea
@@ -215,17 +218,17 @@ Item {
This property holds the button that caused the event. It can be one of:
\list
- \li Qt.LeftButton
- \li Qt.RightButton
- \li Qt.MiddleButton
+ \li \l {Qt::LeftButton} {Qt.LeftButton}
+ \li \l {Qt::RightButton} {Qt.RightButton}
+ \li \l {Qt::MiddleButton} {Qt.MiddleButton}
\endlist
*/
/*!
\qmlproperty bool QtQuick::MouseEvent::wasHeld
- This property is true if the mouse button has been held pressed longer the
- threshold (800ms).
+ This property is true if the mouse button has been held pressed longer
+ than the threshold (800ms).
*/
/*!
@@ -238,9 +241,9 @@ Item {
It contains a bitwise combination of:
\list
- \li Qt.LeftButton
- \li Qt.RightButton
- \li Qt.MiddleButton
+ \li \l {Qt::LeftButton} {Qt.LeftButton}
+ \li \l {Qt::RightButton} {Qt.RightButton}
+ \li \l {Qt::MiddleButton} {Qt.MiddleButton}
\endlist
*/
@@ -252,12 +255,12 @@ Item {
It contains a bitwise combination of:
\list
- \li Qt.NoModifier - No modifier key is pressed.
- \li Qt.ShiftModifier - A Shift key on the keyboard is pressed.
- \li Qt.ControlModifier - A Ctrl key on the keyboard is pressed.
- \li Qt.AltModifier - An Alt key on the keyboard is pressed.
- \li Qt.MetaModifier - A Meta key on the keyboard is pressed.
- \li Qt.KeypadModifier - A keypad button is pressed.
+ \li \l {Qt::NoModifier} {Qt.NoModifier} - No modifier key is pressed.
+ \li \l {Qt::ShiftModifier} {Qt.ShiftModifier} - A Shift key on the keyboard is pressed.
+ \li \l {Qt::ControlModifier} {Qt.ControlModifier} - A Ctrl key on the keyboard is pressed.
+ \li \l {Qt::AltModifier} {Qt.AltModifier} - An Alt key on the keyboard is pressed.
+ \li \l {Qt::MetaModifier} {Qt.MetaModifier} - A Meta key on the keyboard is pressed.
+ \li \l {Qt::KeypadModifier} {Qt.KeypadModifier} - A keypad button is pressed.
\endlist
For example, to react to a Shift key + Left mouse button click:
@@ -285,20 +288,24 @@ Item {
The value can be one of:
- \value Qt.MouseEventNotSynthesized The most common value. On platforms where
- such information is available, this value indicates that the event
- represents a genuine mouse event from the system.
+ \list
+ \li \l{Qt::MouseEventNotSynthesized} {Qt.MouseEventNotSynthesized}
+ - The most common value. On platforms where such information is
+ available, this value indicates that the event represents a genuine
+ mouse event from the system.
- \value Qt.MouseEventSynthesizedBySystem Indicates that the mouse event was
+ \li \l{Qt::MouseEventSynthesizedBySystem} {Qt.MouseEventSynthesizedBySystem} - Indicates that the mouse event was
synthesized from a touch or tablet event by the platform.
- \value Qt.MouseEventSynthesizedByQt Indicates that the mouse event was
- synthesized from an unhandled touch or tablet event by Qt.
+ \li \l{Qt::MouseEventSynthesizedByQt} {Qt.MouseEventSynthesizedByQt}
+ - Indicates that the mouse event was synthesized from an unhandled
+ touch or tablet event by Qt.
- \value Qt.MouseEventSynthesizedByApplication Indicates that the mouse event
- was synthesized by the application. This allows distinguishing
- application-generated mouse events from the ones that are coming from the
- system or are synthesized by Qt.
+ \li \l{Qt::MouseEventSynthesizedByApplication} {Qt.MouseEventSynthesizedByApplication}
+ - Indicates that the mouse event was synthesized by the application.
+ This allows distinguishing application-generated mouse events from
+ the ones that are coming from the system or are synthesized by Qt.
+ \endlist
For example, to react only to events which come from an actual mouse:
\qml
@@ -323,13 +330,29 @@ Item {
*/
/*!
+ \qmlproperty int QtQuick::MouseEvent::flags
+ \since 5.11
+
+ This property holds the flags that provide additional information about the
+ mouse event.
+
+ \list
+ \li \l {Qt::MouseEventCreatedDoubleClick} {Qt.MouseEventCreatedDoubleClick}
+ - Indicates that Qt has created a double click event from this event.
+ This flag is set in the event originating from a button press, and not
+ in the resulting double click event.
+ \endlist
+*/
+
+/*!
\qmltype WheelEvent
\instantiates QQuickWheelEvent
\inqmlmodule QtQuick
\ingroup qtquick-input-events
- \brief Provides information about a mouse wheel event
+ \brief Provides information about a mouse wheel event.
- The position of the mouse can be found via the \l x and \l y properties.
+ The position of the mouse can be found via the
+ \l {Item::x} {x} and \l {Item::y} {y} properties.
\sa MouseArea
*/
@@ -363,9 +386,9 @@ Item {
It contains a bitwise combination of:
\list
- \li Qt.LeftButton
- \li Qt.RightButton
- \li Qt.MiddleButton
+ \li \l {Qt::LeftButton} {Qt.LeftButton}
+ \li \l {Qt::RightButton} {Qt.RightButton}
+ \li \l {Qt::MiddleButton} {Qt.MiddleButton}
\endlist
*/
@@ -403,12 +426,12 @@ Item {
It contains a bitwise combination of:
\list
- \li Qt.NoModifier - No modifier key is pressed.
- \li Qt.ShiftModifier - A Shift key on the keyboard is pressed.
- \li Qt.ControlModifier - A Ctrl key on the keyboard is pressed.
- \li Qt.AltModifier - An Alt key on the keyboard is pressed.
- \li Qt.MetaModifier - A Meta key on the keyboard is pressed.
- \li Qt.KeypadModifier - A keypad button is pressed.
+ \li \l {Qt::NoModifier} {Qt.NoModifier} - No modifier key is pressed.
+ \li \l {Qt::ShiftModifier} {Qt.ShiftModifier} - A Shift key on the keyboard is pressed.
+ \li \l {Qt::ControlModifier} {Qt.ControlModifier} - A Ctrl key on the keyboard is pressed.
+ \li \l {Qt::AltModifier} {Qt.AltModifier} - An Alt key on the keyboard is pressed.
+ \li \l {Qt::MetaModifier} {Qt.MetaModifier} - A Meta key on the keyboard is pressed.
+ \li \l {Qt::KeypadModifier} {Qt.KeypadModifier} - A keypad button is pressed.
\endlist
For example, to react to a Control key pressed during the wheel event:
@@ -445,10 +468,129 @@ Item {
\l inverted always returns false.
*/
-typedef QHash<QTouchDevice *, QQuickPointerDevice *> PointerDeviceForTouchDeviceHash;
+/*!
+ \qmltype PointerDevice
+ \instantiates QQuickPointerDevice
+ \inqmlmodule QtQuick
+ \ingroup qtquick-input-events
+
+ \brief Provides information about a pointing device.
+
+ A pointing device can be a mouse, a touchscreen, or a stylus on a graphics
+ tablet.
+
+ \sa PointerEvent, PointerHandler
+*/
+
+/*!
+ \readonly
+ \qmlproperty enumeration QtQuick::PointerDevice::type
+
+ This property holds the type of the pointing device.
+
+ Valid values are:
+
+ \value DeviceType.UnknownDevice
+ the device cannot be identified
+ \value DeviceType.Mouse
+ a mouse
+ \value DeviceType.TouchScreen
+ a touchscreen providing absolute coordinates
+ \value DeviceType.TouchPad
+ a trackpad or touchpad providing relative coordinates
+ \value DeviceType.Stylus
+ a pen-like device
+ \value DeviceType.Airbrush
+ a stylus with a thumbwheel to adjust
+ \l {QTabletEvent::tangentialPressure}{tangentialPressure}
+ \value DeviceType.Puck
+ a device that is similar to a flat mouse with a
+ transparent circle with cross-hairs
+ (same as \l {QTabletEvent::Puck} {Puck})
+ \value DeviceType.AllDevices
+ any of the above; used as a default value for construction
+
+ \sa QTouchDevice::DeviceType
+*/
+
+/*!
+ \readonly
+ \qmlproperty enumeration QtQuick::PointerDevice::pointerType
+
+ This property holds a value indicating what is interacting with
+ the device. Think of the device as having a planar 2D surface, and
+ the value of this property as identifying what interacts with the
+ device.
+
+ There is some redundancy between this property and \l {PointerDevice::type}.
+ If a tocuchscreen is used, then the device is TouchScreen and
+ pointerType is Finger (always).
+
+ Valid values are:
+
+ \value PointerDevice.GenericPointer
+ a mouse or something acting like a mouse (the core pointer on X11)
+ \value PointerDevice.Finger
+ the user's finger
+ \value PointerDevice.Pen
+ the drawing end of a stylus
+ \value PointerDevice.Eraser
+ the other end of the stylus (if it has a virtual eraser on the other end)
+ \value PointerDevice.Cursor
+ a cursor in the pre-computer sense of the word
+ \value PointerDevice.AllPointerTypes
+ any of the above (used as a default value in constructors)
+*/
+
+
+/*!
+ \readonly
+ \qmlproperty enumeration QtQuick::PointerDevice::capabilities
+
+ This property holds a bitwise combination of the capabilities of the
+ pointing device. It tells you under which conditions events are sent,
+ and which properties of PointerEvent are expected to be valid.
+
+ Valid values are:
+
+ \value CapabilityFlag.Position
+ the \l {QtQuick::EventPoint::position}{position} and
+ \l {QtQuick::EventPoint::scenePosition}{scenePosition} properties
+ \value CapabilityFlag.Area
+ the \l {QtQuick::EventTouchPoint::ellipseDiameters}{ellipseDiameters} property
+ \value CapabilityFlag.Pressure
+ the \l {QtQuick::EventTouchPoint::pressure}{pressure} property
+ \value CapabilityFlag.Velocity
+ the \l {QtQuick::EventPoint::velocity}{velocity} property
+ \value CapabilityFlag.Scroll
+ a \l {QtQuick::PointerDevice::type}{Mouse} has a wheel, or the
+ operating system recognizes scroll gestures on a
+ \l {QtQuick::PointerDevice::type}{TouchPad}
+ \value CapabilityFlag.Hover
+ events are sent even when no button is pressed, or the finger or stylus
+ is not in contact with the surface
+ \value CapabilityFlag.Rotation
+ the \l {QtQuick::EventTouchPoint::rotation}{rotation} property
+ \value CapabilityFlag.XTilt
+ horizontal angle between a stylus and the axis perpendicular to the surface
+ \value CapabilityFlag.YTilt
+ vertical angle between a stylus and the axis perpendicular to the surface
+
+ \sa QTouchDevice::capabilities
+*/
+
+typedef QHash<const QTouchDevice *, QQuickPointerDevice *> PointerDeviceForTouchDeviceHash;
Q_GLOBAL_STATIC(PointerDeviceForTouchDeviceHash, g_touchDevices)
-Q_GLOBAL_STATIC_WITH_ARGS(QQuickPointerDevice, g_genericMouseDevice,
+struct ConstructableQQuickPointerDevice : public QQuickPointerDevice
+{
+ ConstructableQQuickPointerDevice(DeviceType devType, PointerType pType, Capabilities caps,
+ int maxPoints, int buttonCount, const QString &name,
+ qint64 uniqueId = 0)
+ : QQuickPointerDevice(devType, pType, caps, maxPoints, buttonCount, name, uniqueId) {}
+
+};
+Q_GLOBAL_STATIC_WITH_ARGS(ConstructableQQuickPointerDevice, g_genericMouseDevice,
(QQuickPointerDevice::Mouse,
QQuickPointerDevice::GenericPointer,
QQuickPointerDevice::Position | QQuickPointerDevice::Scroll | QQuickPointerDevice::Hover,
@@ -457,7 +599,23 @@ Q_GLOBAL_STATIC_WITH_ARGS(QQuickPointerDevice, g_genericMouseDevice,
typedef QHash<qint64, QQuickPointerDevice *> PointerDeviceForDeviceIdHash;
Q_GLOBAL_STATIC(PointerDeviceForDeviceIdHash, g_tabletDevices)
-QQuickPointerDevice *QQuickPointerDevice::touchDevice(QTouchDevice *d)
+// debugging helpers
+static const char *pointStateString(const QQuickEventPoint *point)
+{
+ static const QMetaEnum stateMetaEnum = point->metaObject()->enumerator(point->metaObject()->indexOfEnumerator("State"));
+ return stateMetaEnum.valueToKey(point->state());
+}
+
+static const QString pointDeviceName(const QQuickEventPoint *point)
+{
+ auto device = static_cast<const QQuickPointerEvent *>(point->parent())->device();
+ QString deviceName = (device ? device->name() : QLatin1String("null device"));
+ deviceName.resize(16, ' '); // shorten, and align in case of sequential output
+ return deviceName;
+}
+
+
+QQuickPointerDevice *QQuickPointerDevice::touchDevice(const QTouchDevice *d)
{
if (g_touchDevices->contains(d))
return g_touchDevices->value(d);
@@ -467,8 +625,7 @@ QQuickPointerDevice *QQuickPointerDevice::touchDevice(QTouchDevice *d)
int maximumTouchPoints = 10;
QQuickPointerDevice::Capabilities caps = QQuickPointerDevice::Capabilities(QTouchDevice::Position);
if (d) {
- QQuickPointerDevice::Capabilities caps =
- static_cast<QQuickPointerDevice::Capabilities>(static_cast<int>(d->capabilities()) & 0x0F);
+ caps = static_cast<QQuickPointerDevice::Capabilities>(static_cast<int>(d->capabilities()) & 0xFF);
if (d->type() == QTouchDevice::TouchPad) {
type = QQuickPointerDevice::TouchPad;
caps |= QQuickPointerDevice::Scroll;
@@ -485,6 +642,11 @@ QQuickPointerDevice *QQuickPointerDevice::touchDevice(QTouchDevice *d)
return dev;
}
+const QTouchDevice *QQuickPointerDevice::qTouchDevice() const
+{
+ return g_touchDevices->key(const_cast<QQuickPointerDevice *>(this));
+}
+
QList<QQuickPointerDevice*> QQuickPointerDevice::touchDevices()
{
return g_touchDevices->values();
@@ -505,37 +667,363 @@ QQuickPointerDevice *QQuickPointerDevice::tabletDevice(qint64 id)
return nullptr;
}
-void QQuickEventPoint::reset(Qt::TouchPointState state, QPointF scenePos, quint64 pointId, ulong timestamp)
+/*!
+ \qmltype EventPoint
+ \qmlabstract
+ \instantiates QQuickEventPoint
+ \inqmlmodule QtQuick
+ \ingroup qtquick-input-events
+ \brief Provides information about an individual point within a PointerEvent.
+
+ A PointerEvent contains an EventPoint for each point of contact: one corresponding
+ to the mouse cursor, or one for each finger touching a touchscreen.
+
+ \sa PointerEvent, PointerHandler
+*/
+
+/*!
+ \readonly
+ \qmlproperty point QtQuick::EventPoint::position
+
+ This property holds the coordinates of the position supplied by the event,
+ relative to the upper-left corner of the Item which has the PointerHandler.
+ If a contact patch is available from the pointing device, this point
+ represents its centroid.
+*/
+
+/*!
+ \readonly
+ \qmlproperty point QtQuick::EventPoint::scenePosition
+
+ This property holds the coordinates of the position supplied by the event,
+ relative to the scene. If a contact patch is available from the
+ \l {QtQuick::PointerEvent::device} {device}, this point represents its centroid.
+*/
+
+/*!
+ \readonly
+ \qmlproperty point QtQuick::EventPoint::scenePressPosition
+
+ This property holds the scene-relative position at which the press event
+ (on a touch device) or most recent change in QQuickPointerEvent::buttons()
+ (on a mouse or tablet stylus) occurred.
+*/
+
+/*!
+ \readonly
+ \qmlproperty point QtQuick::EventPoint::sceneGrabPosition
+
+ This property holds the scene-relative position at which the EventPoint was
+ located when setGrabber() was called most recently.
+*/
+
+/*!
+ \readonly
+ \qmlproperty vector2d QtQuick::EventPoint::velocity
+
+ This property holds average recent velocity: how fast and in which
+ direction the event point has been moving recently.
+*/
+
+/*!
+ \readonly
+ \qmlproperty int QtQuick::EventPoint::state
+
+ This property tells what the user is currently doing at this point.
+
+ It can be one of:
+ \value Pressed
+ The user's finger is now pressing a touchscreen, button or stylus
+ which was not pressed already
+ \value Updated
+ The touchpoint or position is being moved, with no change in pressed state
+ \value Stationary
+ The touchpoint or position is not being moved, and there is also
+ no change in pressed state
+ \value Released
+ The user's finger has now released a touch point, button or stylus
+ which was pressed
+*/
+
+/*!
+ \readonly
+ \qmlproperty int QtQuick::EventPoint::pointId
+
+ This property holds the ID of the event, if any.
+
+ Touchpoints have automatically-incrementing IDs: each time the user
+ presses a finger against the touchscreen, it will be a larger number.
+ In other cases, it will be -1.
+
+ \sa {QtQuick::EventTouchPoint::uniqueId}{uniqueId}
+*/
+
+/*!
+ \readonly
+ \qmlproperty bool QtQuick::EventPoint::accepted
+
+ Setting \a accepted to true prevents the event from being propagated to
+ Items below the PointerHandler's Item.
+
+ Generally, if the handler acts on the mouse event, then it should be
+ accepted so that items lower in the stacking order do not also respond to
+ the same event.
+*/
+
+/*!
+ \readonly
+ \qmlproperty real QtQuick::EventPoint::timeHeld
+
+ This property holds the amount of time in seconds that the button or touchpoint has
+ been held. It can be used to detect a "long press", and can drive an
+ animation to show progress toward activation of the "long press" action.
+*/
+
+void QQuickEventPoint::reset(Qt::TouchPointState state, const QPointF &scenePos, int pointId, ulong timestamp, const QVector2D &velocity)
{
m_scenePos = scenePos;
m_pointId = pointId;
- m_valid = true;
m_accept = false;
m_state = static_cast<QQuickEventPoint::State>(state);
m_timestamp = timestamp;
- if (state == Qt::TouchPointPressed)
+ if (state == Qt::TouchPointPressed) {
m_pressTimestamp = timestamp;
- // TODO calculate velocity
+ m_scenePressPos = scenePos;
+ }
+ m_velocity = (Q_LIKELY(velocity.isNull()) ? estimatedVelocity() : velocity);
+}
+
+void QQuickEventPoint::localizePosition(QQuickItem *target)
+{
+ if (target)
+ m_pos = target->mapFromScene(scenePosition());
+ else
+ m_pos = QPointF();
+}
+
+/*!
+ If this point has an exclusive grabber, returns a pointer to it; else
+ returns null, if there is no grabber. The grabber could be either
+ an Item or a PointerHandler.
+*/
+QObject *QQuickEventPoint::exclusiveGrabber() const
+{
+ return m_exclusiveGrabber.data();
+}
+
+/*!
+ Set the given Item or PointerHandler as the exclusive grabber of this point.
+ If there was already an exclusive grab, it will be canceled. If there
+ were passive grabbers, they will continue to lurk, but the exclusive grab
+ is a behavioral override of the passive grab as long as it remains.
+ If you already know whether the grabber is to be an Item or a PointerHandler,
+ you should instead call setGrabberItem() or setGrabberPointerHandler(),
+ because it is slightly more efficient.
+*/
+void QQuickEventPoint::setExclusiveGrabber(QObject *grabber)
+{
+ if (QQuickPointerHandler *phGrabber = qmlobject_cast<QQuickPointerHandler *>(grabber))
+ setGrabberPointerHandler(phGrabber, true);
+ else
+ setGrabberItem(static_cast<QQuickItem *>(grabber));
+}
+
+/*!
+ If the exclusive grabber of this point is an Item, returns a
+ pointer to that Item; else returns null, if there is no grabber or if
+ the grabber is a PointerHandler.
+*/
+QQuickItem *QQuickEventPoint::grabberItem() const
+{
+ return (m_grabberIsHandler ? nullptr : static_cast<QQuickItem *>(m_exclusiveGrabber.data()));
+}
+
+/*!
+ Set the given Item \a grabber as the exclusive grabber of this point.
+ If there was already an exclusive grab, it will be canceled. If there
+ were passive grabbers, they will continue to lurk, but the exclusive grab
+ is a behavioral override of the passive grab as long as it remains.
+*/
+void QQuickEventPoint::setGrabberItem(QQuickItem *grabber)
+{
+ if (grabber != m_exclusiveGrabber.data()) {
+ QQuickPointerHandler *oldGrabberHandler = grabberPointerHandler();
+ if (oldGrabberHandler && !oldGrabberHandler->approveGrabTransition(this, grabber))
+ return;
+ if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this) << "@" << m_scenePos
+ << ": grab" << m_exclusiveGrabber << "->" << grabber;
+ }
+ QQuickItem *oldGrabberItem = grabberItem();
+ m_exclusiveGrabber = QPointer<QObject>(grabber);
+ m_grabberIsHandler = false;
+ m_sceneGrabPos = m_scenePos;
+ if (oldGrabberHandler) {
+ oldGrabberHandler->onGrabChanged(oldGrabberHandler, (grabber ? CancelGrabExclusive : UngrabExclusive), this);
+ } else if (oldGrabberItem && oldGrabberItem != grabber && grabber && grabber->window()) {
+ QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(grabber->window());
+ windowPriv->sendUngrabEvent(oldGrabberItem, windowPriv->isDeliveringTouchAsMouse());
+ }
+ if (grabber) {
+ for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers)
+ if (passiveGrabber)
+ passiveGrabber->onGrabChanged(passiveGrabber, OverrideGrabPassive, this);
+ }
+ }
+}
+
+/*!
+ If the exclusive grabber of this point is a PointerHandler, returns a
+ pointer to that handler; else returns null, if there is no grabber or if
+ the grabber is an Item.
+*/
+QQuickPointerHandler *QQuickEventPoint::grabberPointerHandler() const
+{
+ return (m_grabberIsHandler ? static_cast<QQuickPointerHandler *>(m_exclusiveGrabber.data()) : nullptr);
+}
+
+/*!
+ Set the given PointerHandler \a grabber as grabber of this point. If \a
+ exclusive is true, it will override any other grabs; if false, \a grabber
+ will be added to the list of passive grabbers of this point.
+*/
+void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, bool exclusive)
+{
+ if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
+ if (exclusive) {
+ if (m_exclusiveGrabber != grabber)
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ << ": grab (exclusive)" << m_exclusiveGrabber << "->" << grabber;
+ } else {
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ << ": grab (passive)" << grabber;
+ }
+ }
+ if (exclusive) {
+ if (grabber != m_exclusiveGrabber.data()) {
+ QQuickPointerHandler *oldGrabberHandler = grabberPointerHandler();
+ QQuickItem *oldGrabberItem = grabberItem();
+ m_exclusiveGrabber = QPointer<QObject>(grabber);
+ m_grabberIsHandler = true;
+ m_sceneGrabPos = m_scenePos;
+ if (grabber) {
+ grabber->onGrabChanged(grabber, GrabExclusive, this);
+ for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers) {
+ if (!passiveGrabber.isNull() && passiveGrabber != grabber)
+ passiveGrabber->onGrabChanged(grabber, OverrideGrabPassive, this);
+ }
+ }
+ if (oldGrabberHandler)
+ oldGrabberHandler->onGrabChanged(oldGrabberHandler, (grabber ? CancelGrabExclusive : UngrabExclusive), this);
+ else if (oldGrabberItem && pointerEvent()->asPointerTouchEvent())
+ oldGrabberItem->touchUngrabEvent();
+ // touchUngrabEvent() can result in the grabber being set to null (MPTA does that, for example).
+ // So set it again to ensure that final state is what we want.
+ m_exclusiveGrabber = QPointer<QObject>(grabber);
+ m_grabberIsHandler = true;
+ m_sceneGrabPos = m_scenePos;
+ }
+ } else {
+ if (!grabber) {
+ qDebug() << "can't set passive grabber to null";
+ return;
+ }
+ auto ptr = QPointer<QQuickPointerHandler>(grabber);
+ if (!m_passiveGrabbers.contains(ptr)) {
+ m_passiveGrabbers.append(ptr);
+ grabber->onGrabChanged(grabber, GrabPassive, this);
+ }
+ }
+}
+
+/*!
+ If this point has an existing exclusive grabber (Item or PointerHandler),
+ inform the grabber that its grab is canceled, and remove it as grabber.
+ This normally happens when the grab is stolen by another Item.
+*/
+void QQuickEventPoint::cancelExclusiveGrab()
+{
+ if (m_exclusiveGrabber.isNull())
+ qWarning("cancelGrab: no grabber");
+ else
+ cancelExclusiveGrabImpl();
}
-QQuickItem *QQuickEventPoint::grabber() const
+void QQuickEventPoint::cancelExclusiveGrabImpl(QTouchEvent *cancelEvent)
{
- return m_grabber.data();
+ if (m_exclusiveGrabber.isNull())
+ return;
+ if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ << ": grab (exclusive)" << m_exclusiveGrabber << "-> nullptr";
+ }
+ if (auto handler = grabberPointerHandler()) {
+ handler->onGrabChanged(handler, CancelGrabExclusive, this);
+ } else if (auto item = grabberItem()) {
+ if (cancelEvent)
+ QCoreApplication::sendEvent(item, cancelEvent);
+ else
+ item->touchUngrabEvent();
+ }
+ m_exclusiveGrabber.clear();
}
-void QQuickEventPoint::setGrabber(QQuickItem *grabber)
+/*!
+ If this point has the given \a handler as a passive grabber,
+ inform the grabber that its grab is canceled, and remove it as grabber.
+ This normally happens when another Item or PointerHandler does an exclusive grab.
+*/
+void QQuickEventPoint::cancelPassiveGrab(QQuickPointerHandler *handler)
{
- if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled()) && m_grabber.data() != grabber) {
- auto device = static_cast<const QQuickPointerEvent *>(parent())->device();
- static const QMetaEnum stateMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("State"));
- QString deviceName = (device ? device->name() : QLatin1String("null device"));
- deviceName.resize(16, ' '); // shorten, and align in case of sequential output
- qCDebug(lcPointerGrab) << deviceName << "point" << hex << m_pointId << stateMetaEnum.valueToKey(state())
- << ": grab" << m_grabber << "->" << grabber;
+ if (removePassiveGrabber(handler)) {
+ if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ << ": grab (passive)" << handler << "removed";
+ }
+ handler->onGrabChanged(handler, CancelGrabPassive, this);
}
- m_grabber = QPointer<QQuickItem>(grabber);
}
+/*!
+ If this point has the given \a handler as a passive grabber, remove it as grabber.
+ Returns true if it was removed, false if it wasn't a grabber.
+*/
+bool QQuickEventPoint::removePassiveGrabber(QQuickPointerHandler *handler)
+{
+ return m_passiveGrabbers.removeOne(handler);
+}
+
+/*!
+ If the given \a handler is grabbing this point passively, exclusively
+ or both, cancel the grab and remove it as grabber.
+ This normally happens when the handler decides that the behavior of this
+ point can no longer satisfy the handler's behavioral constraints within
+ the remainder of the gesture which the user is performing: for example
+ the handler tries to detect a tap but a drag is occurring instead, or
+ it tries to detect a drag in one direction but the drag is going in
+ another direction. In such cases the handler no longer needs or wants
+ to be informed of any further movements of this point.
+*/
+void QQuickEventPoint::cancelAllGrabs(QQuickPointerHandler *handler)
+{
+ if (m_exclusiveGrabber == handler) {
+ handler->onGrabChanged(handler, CancelGrabExclusive, this);
+ m_exclusiveGrabber.clear();
+ }
+ cancelPassiveGrab(handler);
+}
+
+/*!
+ Sets this point as \a accepted (true) or rejected (false).
+
+ During delivery of the current event to the Items in the scene, each Item
+ or Pointer Handler should accept the points for which it is taking
+ responsibility. As soon as all points within the event are accepted, event
+ propagation stops. However accepting the point does not imply any kind of
+ grab, passive or exclusive.
+
+ \sa setExclusiveGrabber, QQuickPointerHandler::setPassiveGrab, QQuickPointerHandler::setExclusiveGrab
+*/
void QQuickEventPoint::setAccepted(bool accepted)
{
if (m_accept != accepted) {
@@ -544,18 +1032,180 @@ void QQuickEventPoint::setAccepted(bool accepted)
}
}
+
+/*!
+ \qmltype EventTouchPoint
+ \qmlabstract
+ \instantiates QQuickEventTouchPoint
+ \inqmlmodule QtQuick
+ \ingroup qtquick-input-events
+ \brief Provides information about an individual touch point within a PointerEvent.
+
+ \sa PointerEvent, PointerHandler
+*/
+
+/*!
+ \readonly
+ \qmlproperty QPointerUniqueId QtQuick::EventTouchPoint::uniqueId
+
+ This property holds the unique ID of the fiducial or stylus in use, if any.
+
+ On touchscreens that can track physical objects (such as knobs or game
+ pieces) in addition to fingers, each object usually has a unique ID.
+ Likewise, each stylus that can be used with a graphics tablet usually has a
+ unique serial number. Qt so far only supports numeric IDs. You can get the
+ actual number as uniqueId.numeric, but that is a device-specific detail.
+ In the future, there may be support for non-numeric IDs, so you should
+ not assume that the number is meaningful.
+
+ If you need to identify specific objects, your application should provide
+ UI for registering objects and mapping them to functionality: allow the
+ user to select a meaning, virtual tool, or action, prompt the user to bring
+ the object into proximity, and store a mapping from uniqueId to its
+ purpose, for example in \l Settings.
+*/
+
+/*!
+ \readonly
+ \qmlproperty qreal QtQuick::EventTouchPoint::rotation
+
+ This property holds the rotation angle of the stylus on a graphics tablet
+ or the contact patch of a touchpoint on a touchscreen.
+
+ It is valid only with certain tablet stylus devices and touchscreens that
+ can measure the rotation angle. Otherwise, it will be zero.
+*/
+
+/*!
+ \readonly
+ \qmlproperty qreal QtQuick::EventTouchPoint::pressure
+
+ This property tells how hard the user is pressing the stylus on a graphics
+ tablet or the finger against a touchscreen, in the range from \c 0 (no
+ measurable pressure) to \c 1.0 (maximum pressure which the device can
+ measure).
+
+ It is valid only with certain tablets and touchscreens that can measure
+ pressure. Otherwise, it will be \c 1.0 when pressed.
+*/
+
+/*!
+ \readonly
+ \qmlproperty size QtQuick::EventTouchPoint::ellipseDiameters
+
+ This property holds the diameters of the contact patch, if the event
+ comes from a touchpoint and the \l {QtQuick::PointerEvent::device} {device}
+ provides this information.
+
+ A touchpoint is modeled as an elliptical area where the finger is
+ pressed against the touchscreen. (In fact, it could also be
+ modeled as a bitmap; but in that case we expect an elliptical
+ bounding estimate to be fitted to the contact patch before the
+ event is sent.) The harder the user presses, the larger the
+ contact patch; so, these diameters provide an alternate way of
+ detecting pressure, in case the device does not include a separate
+ pressure sensor. The ellipse is centered on
+ \l {QtQuick::EventPoint::scenePosition} {scenePosition}
+ (\l {QtQuick::EventPoint::position} {position} in the PointerHandler's
+ Item's local coordinates). The \l rotation property provides the
+ rotation of the ellipse, if known. It is expected that if the
+ \l rotation is zero, the verticalDiameter of the ellipse is the
+ larger one (the major axis), because of the usual hand position,
+ reaching upward or outward across the surface.
+
+ If the contact patch is unknown, or the \l {QtQuick::PointerEvent::device} {device}
+ is not a touchscreen, these values will be zero.
+*/
+
QQuickEventTouchPoint::QQuickEventTouchPoint(QQuickPointerTouchEvent *parent)
: QQuickEventPoint(parent), m_rotation(0), m_pressure(0)
{}
void QQuickEventTouchPoint::reset(const QTouchEvent::TouchPoint &tp, ulong timestamp)
{
- QQuickEventPoint::reset(tp.state(), tp.scenePos(), tp.id(), timestamp);
+ QQuickEventPoint::reset(tp.state(), tp.scenePos(), tp.id(), timestamp, tp.velocity());
+ m_exclusiveGrabber.clear();
+ m_passiveGrabbers.clear();
m_rotation = tp.rotation();
m_pressure = tp.pressure();
+ m_ellipseDiameters = tp.ellipseDiameters();
m_uniqueId = tp.uniqueId();
}
+struct PointVelocityData {
+ QVector2D velocity;
+ QPointF pos;
+ ulong timestamp;
+};
+
+typedef QMap<quint64, PointVelocityData*> PointDataForPointIdMap;
+Q_GLOBAL_STATIC(PointDataForPointIdMap, g_previousPointData)
+static const int PointVelocityAgeLimit = 500; // milliseconds
+
+/*!
+ \internal
+ Estimates the velocity based on a weighted average of all previous velocities.
+ The older the velocity is, the less significant it becomes for the estimate.
+*/
+QVector2D QQuickEventPoint::estimatedVelocity() const
+{
+ PointVelocityData *prevPoint = g_previousPointData->value(m_pointId);
+ if (!prevPoint) {
+ // cleanup events older than PointVelocityAgeLimit
+ auto end = g_previousPointData->end();
+ for (auto it = g_previousPointData->begin(); it != end; ) {
+ PointVelocityData *data = it.value();
+ if (m_timestamp - data->timestamp > PointVelocityAgeLimit) {
+ it = g_previousPointData->erase(it);
+ delete data;
+ } else {
+ ++it;
+ }
+ }
+ // TODO optimize: stop this dynamic memory thrashing
+ prevPoint = new PointVelocityData;
+ prevPoint->velocity = QVector2D();
+ prevPoint->timestamp = 0;
+ prevPoint->pos = QPointF();
+ g_previousPointData->insert(m_pointId, prevPoint);
+ }
+ const ulong timeElapsed = m_timestamp - prevPoint->timestamp;
+ if (timeElapsed == 0) // in case we call estimatedVelocity() twice on the same QQuickEventPoint
+ return m_velocity;
+
+ QVector2D newVelocity;
+ if (prevPoint->timestamp != 0)
+ newVelocity = QVector2D(m_scenePos - prevPoint->pos)/timeElapsed;
+
+ // VERY simple kalman filter: does a weighted average
+ // where the older velocities get less and less significant
+ static const float KalmanGain = 0.7f;
+ QVector2D filteredVelocity = newVelocity * KalmanGain + m_velocity * (1.0f - KalmanGain);
+
+ prevPoint->velocity = filteredVelocity;
+ prevPoint->pos = m_scenePos;
+ prevPoint->timestamp = m_timestamp;
+ return filteredVelocity;
+}
+
+/*!
+ \qmltype PointerEvent
+ \instantiates QQuickPointerEvent
+ \inqmlmodule QtQuick
+ \ingroup qtquick-input-events
+
+ \brief Provides information about an event from a pointing device.
+
+ A PointerEvent is an event describing contact or movement across a surface,
+ provided by a mouse, a touchpoint (single finger on a touchscreen), or a
+ stylus on a graphics tablet. The \l {QtQuick::PointerEvent::device} {device}
+ property provides more information about where the event came from.
+
+ \sa PointerHandler
+
+ \image touchpoint-metrics.png
+*/
+
/*!
\internal
\class QQuickPointerEvent
@@ -570,6 +1220,68 @@ void QQuickEventTouchPoint::reset(const QTouchEvent::TouchPoint &tp, ulong times
dynamically create and destroy objects of this type for each event.
*/
+/*!
+ \readonly
+ \qmlproperty enumeration QtQuick::PointerEvent::button
+
+ This property holds the \l {Qt::MouseButton}{button} that caused the event,
+ if any. If the \l {QtQuick::PointerEvent::device} {device} does not have
+ buttons, or the event is a hover event, it will be \c Qt.NoButton.
+*/
+
+/*!
+ \readonly
+ \qmlproperty int QtQuick::PointerEvent::buttons
+
+ This property holds the combination of mouse or stylus
+ \l {Qt::MouseButton}{buttons} pressed when the event was generated. For move
+ events, this is all buttons that are pressed down. For press events, this
+ includes the button that caused the event, as well as any others that were
+ already held. For release events, this excludes the button that caused the
+ event.
+*/
+
+/*!
+ \readonly
+ \qmlproperty int QtQuick::PointerEvent::modifiers
+
+ This property holds the \l {Qt::KeyboardModifier}{keyboard modifier} flags
+ that existed immediately before the event occurred.
+
+ It contains a bitwise combination of the following flags:
+ \value Qt.NoModifier
+ No modifier key is pressed.
+ \value Qt.ShiftModifier
+ A Shift key on the keyboard is pressed.
+ \value Qt.ControlModifier
+ A Ctrl key on the keyboard is pressed.
+ \value Qt.AltModifier
+ An Alt key on the keyboard is pressed.
+ \value Qt.MetaModifier
+ A Meta key on the keyboard is pressed.
+ \value Qt.KeypadModifier
+ A keypad button is pressed.
+
+ For example, to react to a Shift key + Left mouse button click:
+ \qml
+ Item {
+ TapHandler {
+ onTapped: {
+ if ((event.button == Qt.LeftButton) && (event.modifiers & Qt.ShiftModifier))
+ doSomething();
+ }
+ }
+ }
+ \endqml
+*/
+
+/*!
+ \readonly
+ \qmlproperty PointerDevice QtQuick::PointerEvent::device
+
+ This property holds the device that generated the event.
+*/
+
QQuickPointerEvent::~QQuickPointerEvent()
{}
@@ -581,11 +1293,14 @@ QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event)
return this;
m_device = QQuickPointerDevice::genericMouseDevice();
+ m_device->eventDeliveryTargets().clear();
m_button = ev->button();
m_pressedButtons = ev->buttons();
Qt::TouchPointState state = Qt::TouchPointStationary;
switch (ev->type()) {
case QEvent::MouseButtonPress:
+ m_point->clearPassiveGrabbers();
+ Q_FALLTHROUGH();
case QEvent::MouseButtonDblClick:
state = Qt::TouchPointPressed;
break;
@@ -598,10 +1313,15 @@ QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event)
default:
break;
}
- m_mousePoint->reset(state, ev->windowPos(), 0, ev->timestamp()); // mouse is 0
+ m_point->reset(state, ev->windowPos(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
return this;
}
+void QQuickSinglePointEvent::localize(QQuickItem *target)
+{
+ m_point->localizePosition(target);
+}
+
QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event)
{
auto ev = static_cast<QTouchEvent*>(event);
@@ -610,6 +1330,7 @@ QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event)
return this;
m_device = QQuickPointerDevice::touchDevice(ev->device());
+ m_device->eventDeliveryTargets().clear();
m_button = Qt::NoButton;
m_pressedButtons = Qt::NoButton;
@@ -620,47 +1341,137 @@ QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event)
for (int i = m_touchPoints.size(); i < newPointCount; ++i)
m_touchPoints.insert(i, new QQuickEventTouchPoint(this));
- // Make sure the grabbers are right from one event to the next
- QVector<QQuickItem*> grabbers;
- // Copy all grabbers, because the order of points might have changed in the event.
+ // Make sure the grabbers and on-pressed values are right from one event to the next
+ struct ToPreserve {
+ int pointId; // just for double-checking
+ ulong pressTimestamp;
+ QPointF scenePressPos;
+ QPointF sceneGrabPos;
+ QObject * grabber;
+ QVector <QPointer <QQuickPointerHandler> > passiveGrabbers;
+
+ ToPreserve() : pointId(0), pressTimestamp(0), grabber(nullptr) {}
+ };
+ QVector<ToPreserve> preserves(newPointCount); // jar of pickled touchpoints, in order of points in the _new_ event
+
+ // Copy stuff we need to preserve, because the order of points might have changed in the event.
// The ID is all that we can rely on (release might remove the first point etc).
for (int i = 0; i < newPointCount; ++i) {
- QQuickItem *grabber = nullptr;
- if (auto point = pointById(tps.at(i).id()))
- grabber = point->grabber();
- grabbers.append(grabber);
+ int pid = tps.at(i).id();
+ if (auto point = pointById(pid)) {
+ preserves[i].pointId = pid;
+ preserves[i].pressTimestamp = point->m_pressTimestamp;
+ preserves[i].scenePressPos = point->scenePressPosition();
+ preserves[i].sceneGrabPos = point->sceneGrabPosition();
+ preserves[i].grabber = point->exclusiveGrabber();
+ preserves[i].passiveGrabbers = point->passiveGrabbers();
+ }
}
for (int i = 0; i < newPointCount; ++i) {
auto point = m_touchPoints.at(i);
point->reset(tps.at(i), ev->timestamp());
+ const auto &preserved = preserves.at(i);
if (point->state() == QQuickEventPoint::Pressed) {
- if (grabbers.at(i))
+ if (preserved.grabber)
qWarning() << "TouchPointPressed without previous release event" << point;
- point->setGrabber(nullptr);
+ point->setGrabberItem(nullptr);
+ point->clearPassiveGrabbers();
} else {
- point->setGrabber(grabbers.at(i));
+ // Restore the grabbers without notifying (don't call onGrabChanged)
+ Q_ASSERT(preserved.pointId == 0 || preserved.pointId == point->pointId());
+ point->m_pressTimestamp = preserved.pressTimestamp;
+ point->m_scenePressPos = preserved.scenePressPos;
+ point->m_sceneGrabPos = preserved.sceneGrabPos;
+ point->m_exclusiveGrabber = preserved.grabber;
+ point->m_grabberIsHandler = (qmlobject_cast<QQuickPointerHandler *>(point->m_exclusiveGrabber) != nullptr);
+ point->m_passiveGrabbers = preserved.passiveGrabbers;
}
}
m_pointCount = newPointCount;
return this;
}
-QQuickEventPoint *QQuickPointerMouseEvent::point(int i) const {
+void QQuickPointerTouchEvent::localize(QQuickItem *target)
+{
+ for (auto point : qAsConst(m_touchPoints))
+ point->localizePosition(target);
+}
+
+#if QT_CONFIG(gestures)
+QQuickPointerEvent *QQuickPointerNativeGestureEvent::reset(QEvent *event)
+{
+ auto ev = static_cast<QNativeGestureEvent*>(event);
+ m_event = ev;
+ if (!event)
+ return this;
+
+ m_device = QQuickPointerDevice::touchDevice(ev->device());
+ m_device->eventDeliveryTargets().clear();
+ Qt::TouchPointState state = Qt::TouchPointMoved;
+ switch (type()) {
+ case Qt::BeginNativeGesture:
+ state = Qt::TouchPointPressed;
+ break;
+ case Qt::EndNativeGesture:
+ state = Qt::TouchPointReleased;
+ break;
+ default:
+ break;
+ }
+ quint64 deviceId = QTouchDevicePrivate::get(const_cast<QTouchDevice *>(ev->device()))->id; // a bit roundabout since QTouchDevice::mTouchDeviceId is protected
+ m_point->reset(state, ev->windowPos(), deviceId << 24, ev->timestamp());
+ return this;
+}
+#endif // QT_CONFIG(gestures)
+
+QQuickEventPoint *QQuickSinglePointEvent::point(int i) const
+{
if (i == 0)
- return m_mousePoint;
+ return m_point;
return nullptr;
}
-QQuickEventPoint *QQuickPointerTouchEvent::point(int i) const {
+QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event)
+{
+ m_event = static_cast<QInputEvent*>(event);
+ if (!event)
+ return this;
+#if QT_CONFIG(wheelevent)
+ if (event->type() == QEvent::Wheel) {
+ auto ev = static_cast<QWheelEvent*>(event);
+ m_device = QQuickPointerDevice::genericMouseDevice();
+ m_device->eventDeliveryTargets().clear();
+ // m_button = Qt::NoButton;
+ m_pressedButtons = ev->buttons();
+ m_angleDelta = QVector2D(ev->angleDelta());
+ m_pixelDelta = QVector2D(ev->pixelDelta());
+ m_phase = ev->phase();
+ 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
+ }
+#endif
+ // TODO else if (event->type() == QEvent::Scroll) ...
+ return this;
+}
+
+void QQuickPointerScrollEvent::localize(QQuickItem *target)
+{
+ m_point->localizePosition(target);
+}
+
+QQuickEventPoint *QQuickPointerTouchEvent::point(int i) const
+{
if (i >= 0 && i < m_pointCount)
return m_touchPoints.at(i);
return nullptr;
}
QQuickEventPoint::QQuickEventPoint(QQuickPointerEvent *parent)
- : QObject(parent), m_pointId(0), m_grabber(nullptr), m_timestamp(0), m_pressTimestamp(0),
- m_state(QQuickEventPoint::Released), m_valid(false), m_accept(false)
+ : QObject(parent), m_pointId(0), m_exclusiveGrabber(nullptr), m_timestamp(0), m_pressTimestamp(0),
+ m_state(QQuickEventPoint::Released), m_accept(false), m_grabberIsHandler(false)
{
Q_UNUSED(m_reserved);
}
@@ -670,8 +1481,19 @@ QQuickPointerEvent *QQuickEventPoint::pointerEvent() const
return static_cast<QQuickPointerEvent *>(parent());
}
-bool QQuickPointerMouseEvent::allPointsAccepted() const {
- return m_mousePoint->isAccepted();
+bool QQuickSinglePointEvent::allPointsAccepted() const
+{
+ return m_point->isAccepted();
+}
+
+bool QQuickSinglePointEvent::allUpdatedPointsAccepted() const
+{
+ return m_point->state() == QQuickEventPoint::Pressed || m_point->isAccepted();
+}
+
+bool QQuickSinglePointEvent::allPointsGrabbed() const
+{
+ return m_point->exclusiveGrabber() != nullptr;
}
QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) const
@@ -681,16 +1503,32 @@ QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) cons
return event;
}
-QVector<QQuickItem *> QQuickPointerMouseEvent::grabbers() const
+/*!
+ Returns the exclusive grabber of this event, if any, in a vector.
+*/
+QVector<QObject *> QQuickSinglePointEvent::exclusiveGrabbers() const
{
- QVector<QQuickItem *> result;
- if (QQuickItem *grabber = m_mousePoint->grabber())
+ QVector<QObject *> result;
+ if (QObject *grabber = m_point->exclusiveGrabber())
result << grabber;
return result;
}
-void QQuickPointerMouseEvent::clearGrabbers() const {
- m_mousePoint->setGrabber(nullptr);
+/*!
+ Remove all passive and exclusive grabbers of this event, without notifying.
+*/
+void QQuickSinglePointEvent::clearGrabbers() const
+{
+ m_point->setGrabberItem(nullptr);
+ m_point->clearPassiveGrabbers();
+}
+
+/*!
+ Returns whether the given \a handler is the exclusive grabber of this event.
+*/
+bool QQuickSinglePointEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const
+{
+ return handler && (m_point->exclusiveGrabber() == handler);
}
bool QQuickPointerMouseEvent::isPressEvent() const
@@ -700,7 +1538,26 @@ bool QQuickPointerMouseEvent::isPressEvent() const
(me->buttons() & me->button()) == me->buttons());
}
-bool QQuickPointerTouchEvent::allPointsAccepted() const {
+bool QQuickPointerMouseEvent::isDoubleClickEvent() const
+{
+ auto me = static_cast<QMouseEvent*>(m_event);
+ return (me->type() == QEvent::MouseButtonDblClick);
+}
+
+bool QQuickPointerMouseEvent::isUpdateEvent() const
+{
+ auto me = static_cast<QMouseEvent*>(m_event);
+ return me->type() == QEvent::MouseMove;
+}
+
+bool QQuickPointerMouseEvent::isReleaseEvent() const
+{
+ auto me = static_cast<QMouseEvent*>(m_event);
+ return me && me->type() == QEvent::MouseButtonRelease;
+}
+
+bool QQuickPointerTouchEvent::allPointsAccepted() const
+{
for (int i = 0; i < m_pointCount; ++i) {
if (!m_touchPoints.at(i)->isAccepted())
return false;
@@ -708,12 +1565,33 @@ bool QQuickPointerTouchEvent::allPointsAccepted() const {
return true;
}
-QVector<QQuickItem *> QQuickPointerTouchEvent::grabbers() const
+bool QQuickPointerTouchEvent::allUpdatedPointsAccepted() const
{
- QVector<QQuickItem *> result;
for (int i = 0; i < m_pointCount; ++i) {
auto point = m_touchPoints.at(i);
- if (QQuickItem *grabber = point->grabber()) {
+ if (point->state() != QQuickEventPoint::Pressed && !point->isAccepted())
+ return false;
+ }
+ return true;
+}
+
+bool QQuickPointerTouchEvent::allPointsGrabbed() const
+{
+ for (int i = 0; i < m_pointCount; ++i) {
+ if (!m_touchPoints.at(i)->exclusiveGrabber())
+ return false;
+ }
+ return true;
+}
+
+/*!
+ Returns the exclusive grabbers of all points in this event, if any, in a vector.
+*/
+QVector<QObject *> QQuickPointerTouchEvent::exclusiveGrabbers() const
+{
+ QVector<QObject *> result;
+ for (int i = 0; i < m_pointCount; ++i) {
+ if (QObject *grabber = m_touchPoints.at(i)->exclusiveGrabber()) {
if (!result.contains(grabber))
result << grabber;
}
@@ -721,14 +1599,50 @@ QVector<QQuickItem *> QQuickPointerTouchEvent::grabbers() const
return result;
}
-void QQuickPointerTouchEvent::clearGrabbers() const {
+/*!
+ Remove all passive and exclusive grabbers of all touchpoints in this event,
+ without notifying.
+*/
+void QQuickPointerTouchEvent::clearGrabbers() const
+{
+ for (auto point: m_touchPoints) {
+ point->setGrabberItem(nullptr);
+ point->clearPassiveGrabbers();
+ }
+}
+
+Qt::TouchPointStates QQuickPointerTouchEvent::touchPointStates() const
+{
+ return m_event
+ ? static_cast<QTouchEvent*>(m_event)->touchPointStates()
+ : Qt::TouchPointStates();
+}
+
+/*!
+ Returns whether the given \a handler is the exclusive grabber of any
+ touchpoint within this event.
+*/
+bool QQuickPointerTouchEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const
+{
for (auto point: m_touchPoints)
- point->setGrabber(nullptr);
+ if (point->exclusiveGrabber() == handler)
+ return true;
+ return false;
}
bool QQuickPointerTouchEvent::isPressEvent() const
{
- return static_cast<QTouchEvent*>(m_event)->touchPointStates() & Qt::TouchPointPressed;
+ return touchPointStates() & Qt::TouchPointPressed;
+}
+
+bool QQuickPointerTouchEvent::isUpdateEvent() const
+{
+ return touchPointStates() & (Qt::TouchPointMoved | Qt::TouchPointStationary);
+}
+
+bool QQuickPointerTouchEvent::isReleaseEvent() const
+{
+ return touchPointStates() & Qt::TouchPointReleased;
}
QVector<QPointF> QQuickPointerEvent::unacceptedPressedPointScenePositions() const
@@ -736,7 +1650,7 @@ QVector<QPointF> QQuickPointerEvent::unacceptedPressedPointScenePositions() cons
QVector<QPointF> points;
for (int i = 0; i < pointCount(); ++i) {
if (!point(i)->isAccepted() && point(i)->state() == QQuickEventPoint::Pressed)
- points << point(i)->scenePos();
+ points << point(i)->scenePosition();
}
return points;
}
@@ -748,7 +1662,8 @@ QVector<QPointF> QQuickPointerEvent::unacceptedPressedPointScenePositions() cons
If the touchpoint cannot be found, this returns nullptr.
Ownership of the event is NOT transferred to the caller.
*/
-QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const {
+QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const
+{
const QTouchEvent::TouchPoint *p = touchPointById(pointID);
if (!p)
return nullptr;
@@ -787,21 +1702,89 @@ QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickIte
return &m_synthMouseEvent;
}
+#if QT_CONFIG(gestures)
+bool QQuickPointerNativeGestureEvent::isPressEvent() const
+{
+ return type() == Qt::BeginNativeGesture;
+}
+
+bool QQuickPointerNativeGestureEvent::isUpdateEvent() const
+{
+ switch (type()) {
+ case Qt::BeginNativeGesture:
+ case Qt::EndNativeGesture:
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool QQuickPointerNativeGestureEvent::isReleaseEvent() const
+{
+ return type() == Qt::EndNativeGesture;
+}
+
+Qt::NativeGestureType QQuickPointerNativeGestureEvent::type() const
+{
+ return static_cast<QNativeGestureEvent *>(m_event)->gestureType();
+}
+
+qreal QQuickPointerNativeGestureEvent::value() const
+{
+ return static_cast<QNativeGestureEvent *>(m_event)->value();
+}
+#endif // QT_CONFIG(gestures)
+
+/*!
+ Returns whether the scroll event has Qt::ScrollBegin phase. On touchpads
+ which provide phase information, this is true when the fingers are placed
+ on the touchpad and scrolling begins. On other devices where this
+ information is not available, it remains false.
+*/
+bool QQuickPointerScrollEvent::isPressEvent() const
+{
+ return phase() == Qt::ScrollBegin;
+}
+
+/*!
+ Returns true when the scroll event has Qt::ScrollUpdate phase, or when the
+ phase is unknown. Some multi-touch-capable touchpads and trackpads provide
+ phase information; whereas ordinary mouse wheels and other types of
+ trackpads do not, and in such cases this is always true.
+*/
+bool QQuickPointerScrollEvent::isUpdateEvent() const
+{
+ return phase() == Qt::ScrollUpdate || phase() == Qt::NoScrollPhase;
+}
+
+/*!
+ Returns whether the scroll event has Qt::ScrollBegin phase. On touchpads
+ which provide phase information, this is true when the fingers are lifted
+ from the touchpad. On other devices where this information is not
+ available, it remains false.
+*/
+bool QQuickPointerScrollEvent::isReleaseEvent() const
+{
+ return phase() == Qt::ScrollEnd;
+}
+
/*!
\internal
Returns a pointer to the QQuickEventPoint which has the \a pointId as
\l {QQuickEventPoint::pointId}{pointId}.
Returns nullptr if there is no point with that ID.
- \fn QQuickPointerEvent::pointById(quint64 pointId) const
+ \fn QQuickPointerEvent::pointById(int pointId) const
*/
-QQuickEventPoint *QQuickPointerMouseEvent::pointById(quint64 pointId) const {
- if (m_mousePoint && pointId == m_mousePoint->pointId())
- return m_mousePoint;
+QQuickEventPoint *QQuickSinglePointEvent::pointById(int pointId) const
+{
+ if (m_point && pointId == m_point->pointId())
+ return m_point;
return nullptr;
}
-QQuickEventPoint *QQuickPointerTouchEvent::pointById(quint64 pointId) const {
+QQuickEventPoint *QQuickPointerTouchEvent::pointById(int pointId) const
+{
auto it = std::find_if(m_touchPoints.constBegin(), m_touchPoints.constEnd(),
[pointId](const QQuickEventTouchPoint *tp) { return tp->pointId() == pointId; } );
if (it != m_touchPoints.constEnd())
@@ -809,14 +1792,14 @@ QQuickEventPoint *QQuickPointerTouchEvent::pointById(quint64 pointId) const {
return nullptr;
}
-
/*!
\internal
Returns a pointer to the original TouchPoint which has the same
\l {QTouchEvent::TouchPoint::id}{id} as \a pointId, if the original event is a
QTouchEvent, and if that point is found. Otherwise, returns nullptr.
*/
-const QTouchEvent::TouchPoint *QQuickPointerTouchEvent::touchPointById(int pointId) const {
+const QTouchEvent::TouchPoint *QQuickPointerTouchEvent::touchPointById(int pointId) const
+{
const QTouchEvent *ev = asTouchEvent();
if (!ev)
return nullptr;
@@ -831,7 +1814,12 @@ const QTouchEvent::TouchPoint *QQuickPointerTouchEvent::touchPointById(int point
\internal
Make a new QTouchEvent, giving it a subset of the original touch points.
- Returns a nullptr if all points are stationary or there are no points inside the item.
+ Returns a nullptr if all points are stationary, or there are no points inside the item,
+ or none of the points were pressed inside and the item was not grabbing any of them
+ and isFiltering is false. When isFiltering is true, it is assumed that the item
+ cares about all points which are inside its bounds, because most filtering items
+ need to monitor eventpoint movements until a drag threshold is exceeded or the
+ requirements for a gesture to be recognized are met in some other way.
*/
QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool isFiltering) const
{
@@ -841,19 +1829,24 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i
// Or else just document that velocity is always scene-relative and is not scaled and rotated with the item
// but that would require changing tst_qquickwindow::touchEvent_velocity(): it expects transformed velocity
+ bool anyPressOrReleaseInside = false;
+ bool anyGrabber = false;
QMatrix4x4 transformMatrix(QQuickItemPrivate::get(item)->windowToItemTransform());
for (int i = 0; i < m_pointCount; ++i) {
auto p = m_touchPoints.at(i);
if (p->isAccepted())
continue;
// include points where item is the grabber
- bool isGrabber = p->grabber() == item;
- // include newly pressed points inside the bounds
- bool isPressInside = p->state() == QQuickEventPoint::Pressed && item->contains(item->mapFromScene(p->scenePos()));
+ bool isGrabber = p->exclusiveGrabber() == item;
+ if (isGrabber)
+ anyGrabber = true;
+ // include points inside the bounds if no other item is the grabber or if the item is filtering
+ bool isInside = item->contains(item->mapFromScene(p->scenePosition()));
+ bool hasAnotherGrabber = p->exclusiveGrabber() && p->exclusiveGrabber() != item;
// filtering: (childMouseEventFilter) include points that are grabbed by children of the target item
bool grabberIsChild = false;
- auto parent = p->grabber();
+ auto parent = p->grabberItem();
while (isFiltering && parent) {
if (parent == item) {
grabberIsChild = true;
@@ -862,11 +1855,11 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i
parent = parent->parentItem();
}
- // when filtering, send points that are grabbed by a child and points that are not grabbed but inside
- bool filterRelevant = isFiltering && (grabberIsChild || (!p->grabber() && item->contains(item->mapFromScene(p->scenePos()))));
- if (!(isGrabber || isPressInside || filterRelevant))
+ bool filterRelevant = isFiltering && grabberIsChild;
+ if (!(isGrabber || (isInside && (!hasAnotherGrabber || isFiltering)) || filterRelevant))
continue;
-
+ if ((p->state() == QQuickEventPoint::Pressed || p->state() == QQuickEventPoint::Released) && isInside)
+ anyPressOrReleaseInside = true;
const QTouchEvent::TouchPoint *tp = touchPointById(p->pointId());
if (tp) {
eventStates |= tp->state();
@@ -880,7 +1873,9 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i
}
}
- if (eventStates == Qt::TouchPointStationary || touchPoints.isEmpty())
+ // 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))
return nullptr;
// if all points have the same state, set the event type accordingly
@@ -917,7 +1912,8 @@ QTouchEvent *QQuickPointerTouchEvent::asTouchEvent() const
#ifndef QT_NO_DEBUG_STREAM
-Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerDevice *dev) {
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerDevice *dev)
+{
QDebugStateSaver saver(dbg);
dbg.nospace();
if (!dev) {
@@ -939,10 +1935,13 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerDevice *
return dbg;
}
-Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *event) {
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *event)
+{
QDebugStateSaver saver(dbg);
dbg.nospace();
- dbg << "QQuickPointerEvent(dev:";
+ dbg << "QQuickPointerEvent(";
+ dbg << event->timestamp();
+ dbg << " dev:";
QtDebugUtils::formatQEnum(dbg, event->device()->type());
if (event->buttons() != Qt::NoButton) {
dbg << " buttons:";
@@ -956,13 +1955,14 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *e
return dbg;
}
-Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *event) {
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *event)
+{
QDebugStateSaver saver(dbg);
dbg.nospace();
- dbg << "QQuickEventPoint(valid:" << event->isValid() << " accepted:" << event->isAccepted()
+ dbg << "QQuickEventPoint(accepted:" << event->isAccepted()
<< " state:";
QtDebugUtils::formatQEnum(dbg, event->state());
- dbg << " scenePos:" << event->scenePos() << " id:" << hex << event->pointId() << dec
+ dbg << " scenePos:" << event->scenePosition() << " id:" << hex << event->pointId() << dec
<< " timeHeld:" << event->timeHeld() << ')';
return dbg;
}
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index 3735d68a85..e614b1bd6d 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -66,23 +66,28 @@ QT_BEGIN_NAMESPACE
class QQuickPointerDevice;
class QQuickPointerEvent;
class QQuickPointerMouseEvent;
+#if QT_CONFIG(gestures)
+class QQuickPointerNativeGestureEvent;
+#endif
+class QQuickPointerScrollEvent;
class QQuickPointerTabletEvent;
class QQuickPointerTouchEvent;
+class QQuickPointerHandler;
class QQuickKeyEvent : public QObject
{
Q_OBJECT
- Q_PROPERTY(int key READ key)
- Q_PROPERTY(QString text READ text)
- Q_PROPERTY(int modifiers READ modifiers)
- Q_PROPERTY(bool isAutoRepeat READ isAutoRepeat)
- Q_PROPERTY(int count READ count)
- Q_PROPERTY(quint32 nativeScanCode READ nativeScanCode)
+ Q_PROPERTY(int key READ key CONSTANT)
+ Q_PROPERTY(QString text READ text CONSTANT)
+ Q_PROPERTY(int modifiers READ modifiers CONSTANT)
+ Q_PROPERTY(bool isAutoRepeat READ isAutoRepeat CONSTANT)
+ Q_PROPERTY(int count READ count CONSTANT)
+ Q_PROPERTY(quint32 nativeScanCode READ nativeScanCode CONSTANT)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public:
QQuickKeyEvent()
- : event(QEvent::None, 0, 0)
+ : event(QEvent::None, 0, nullptr)
{}
void reset(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
@@ -120,24 +125,27 @@ private:
class Q_QUICK_PRIVATE_EXPORT QQuickMouseEvent : public QObject
{
Q_OBJECT
- Q_PROPERTY(qreal x READ x)
- Q_PROPERTY(qreal y READ y)
- Q_PROPERTY(int button READ button)
- Q_PROPERTY(int buttons READ buttons)
- Q_PROPERTY(int modifiers READ modifiers)
- Q_PROPERTY(int source READ source REVISION 7)
- Q_PROPERTY(bool wasHeld READ wasHeld)
- Q_PROPERTY(bool isClick READ isClick)
+ Q_PROPERTY(qreal x READ x CONSTANT)
+ Q_PROPERTY(qreal y READ y CONSTANT)
+ Q_PROPERTY(int button READ button CONSTANT)
+ Q_PROPERTY(int buttons READ buttons CONSTANT)
+ Q_PROPERTY(int modifiers READ modifiers CONSTANT)
+ Q_PROPERTY(int source READ source CONSTANT REVISION 7)
+ Q_PROPERTY(bool wasHeld READ wasHeld CONSTANT)
+ Q_PROPERTY(bool isClick READ isClick CONSTANT)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+ Q_PROPERTY(int flags READ flags CONSTANT REVISION 11)
public:
QQuickMouseEvent()
- : _x(0), _y(0), _button(Qt::NoButton), _buttons(Qt::NoButton), _modifiers(Qt::NoModifier)
- , _source(Qt::MouseEventNotSynthesized), _wasHeld(false), _isClick(false), _accepted(false)
+ : _buttons(Qt::NoButton), _modifiers(Qt::NoModifier)
+ , _wasHeld(false), _isClick(false), _accepted(false)
+ , _flags(Qt::MouseEventFlags(nullptr))
{}
void reset(qreal x, qreal y, Qt::MouseButton button, Qt::MouseButtons buttons,
- Qt::KeyboardModifiers modifiers, bool isClick = false, bool wasHeld = false)
+ Qt::KeyboardModifiers modifiers, bool isClick = false, bool wasHeld = false,
+ Qt::MouseEventFlags flags = nullptr)
{
_x = x;
_y = y;
@@ -148,6 +156,7 @@ public:
_wasHeld = wasHeld;
_isClick = isClick;
_accepted = true;
+ _flags = flags;
}
qreal x() const { return _x; }
@@ -167,35 +176,35 @@ public:
bool isAccepted() { return _accepted; }
void setAccepted(bool accepted) { _accepted = accepted; }
-
+ int flags() const { return _flags; }
private:
- qreal _x;
- qreal _y;
- Qt::MouseButton _button;
+ qreal _x = 0;
+ qreal _y = 0;
+ Qt::MouseButton _button = Qt::NoButton;
Qt::MouseButtons _buttons;
Qt::KeyboardModifiers _modifiers;
- Qt::MouseEventSource _source;
+ Qt::MouseEventSource _source = Qt::MouseEventNotSynthesized;
bool _wasHeld : 1;
bool _isClick : 1;
bool _accepted : 1;
+ Qt::MouseEventFlags _flags;
};
class QQuickWheelEvent : public QObject
{
Q_OBJECT
- Q_PROPERTY(qreal x READ x)
- Q_PROPERTY(qreal y READ y)
- Q_PROPERTY(QPoint angleDelta READ angleDelta)
- Q_PROPERTY(QPoint pixelDelta READ pixelDelta)
- Q_PROPERTY(int buttons READ buttons)
- Q_PROPERTY(int modifiers READ modifiers)
- Q_PROPERTY(bool inverted READ inverted)
+ Q_PROPERTY(qreal x READ x CONSTANT)
+ Q_PROPERTY(qreal y READ y CONSTANT)
+ Q_PROPERTY(QPoint angleDelta READ angleDelta CONSTANT)
+ Q_PROPERTY(QPoint pixelDelta READ pixelDelta CONSTANT)
+ Q_PROPERTY(int buttons READ buttons CONSTANT)
+ Q_PROPERTY(int modifiers READ modifiers CONSTANT)
+ Q_PROPERTY(bool inverted READ inverted CONSTANT)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public:
QQuickWheelEvent()
- : _x(0), _y(0), _buttons(Qt::NoButton), _modifiers(Qt::NoModifier)
- , _inverted(false), _accepted(false)
+ : _buttons(Qt::NoButton), _modifiers(Qt::NoModifier)
{}
void reset(qreal x, qreal y, const QPoint &angleDelta, const QPoint &pixelDelta,
@@ -222,14 +231,14 @@ public:
void setAccepted(bool accepted) { _accepted = accepted; }
private:
- qreal _x;
- qreal _y;
+ qreal _x = 0;
+ qreal _y = 0;
QPoint _angleDelta;
QPoint _pixelDelta;
Qt::MouseButtons _buttons;
Qt::KeyboardModifiers _modifiers;
- bool _inverted;
- bool _accepted;
+ bool _inverted = false;
+ bool _accepted = false;
};
class Q_QUICK_PRIVATE_EXPORT QQuickCloseEvent : public QObject
@@ -238,25 +247,29 @@ class Q_QUICK_PRIVATE_EXPORT QQuickCloseEvent : public QObject
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public:
- QQuickCloseEvent()
- : _accepted(true) {}
+ QQuickCloseEvent() {}
bool isAccepted() { return _accepted; }
void setAccepted(bool accepted) { _accepted = accepted; }
private:
- bool _accepted;
+ bool _accepted = true;
};
class Q_QUICK_PRIVATE_EXPORT QQuickEventPoint : public QObject
{
Q_OBJECT
- Q_PROPERTY(QPointF scenePos READ scenePos)
- Q_PROPERTY(State state READ state)
- Q_PROPERTY(quint64 pointId READ pointId)
- Q_PROPERTY(qreal timeHeld READ timeHeld)
+ Q_PROPERTY(QQuickPointerEvent *event READ pointerEvent CONSTANT)
+ Q_PROPERTY(QPointF position READ position CONSTANT)
+ Q_PROPERTY(QPointF scenePosition READ scenePosition CONSTANT)
+ Q_PROPERTY(QPointF scenePressPosition READ scenePressPosition CONSTANT)
+ Q_PROPERTY(QPointF sceneGrabPosition READ sceneGrabPosition CONSTANT)
+ Q_PROPERTY(State state READ state CONSTANT)
+ Q_PROPERTY(int pointId READ pointId CONSTANT)
+ Q_PROPERTY(qreal timeHeld READ timeHeld CONSTANT)
+ Q_PROPERTY(QVector2D velocity READ velocity CONSTANT)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
- Q_PROPERTY(QQuickItem *grabber READ grabber WRITE setGrabber)
+ Q_PROPERTY(QObject *exclusiveGrabber READ exclusiveGrabber WRITE setExclusiveGrabber)
public:
enum State {
@@ -264,37 +277,79 @@ public:
Updated = Qt::TouchPointMoved,
Stationary = Qt::TouchPointStationary,
Released = Qt::TouchPointReleased
- // Canceled = Qt::TouchPointReleased << 1 // 0x10 // TODO maybe
};
- Q_ENUM(State)
+ Q_DECLARE_FLAGS(States, State)
+ Q_FLAG(States)
+
+ enum GrabTransition {
+ GrabPassive = 0x01,
+ UngrabPassive = 0x02,
+ CancelGrabPassive = 0x03,
+ OverrideGrabPassive = 0x04,
+ GrabExclusive = 0x10,
+ UngrabExclusive = 0x20,
+ CancelGrabExclusive = 0x30,
+ };
+ Q_ENUM(GrabTransition)
QQuickEventPoint(QQuickPointerEvent *parent);
- void reset(Qt::TouchPointState state, QPointF scenePos, quint64 pointId, ulong timestamp);
-
- void invalidate() { m_valid = false; }
+ void reset(Qt::TouchPointState state, const QPointF &scenePosition, int pointId, ulong timestamp, const QVector2D &velocity = QVector2D());
+ void localizePosition(QQuickItem *target);
QQuickPointerEvent *pointerEvent() const;
- QPointF scenePos() const { return m_scenePos; }
+ QPointF position() const { return m_pos; }
+ QPointF scenePosition() const { return m_scenePos; }
+ QPointF scenePressPosition() const { return m_scenePressPos; }
+ QPointF sceneGrabPosition() const { return m_sceneGrabPos; }
+ QVector2D velocity() const { return m_velocity; }
State state() const { return m_state; }
- quint64 pointId() const { return m_pointId; }
- bool isValid() const { return m_valid; }
+ int pointId() const { return m_pointId; }
qreal timeHeld() const { return (m_timestamp - m_pressTimestamp) / 1000.0; }
bool isAccepted() const { return m_accept; }
void setAccepted(bool accepted = true);
- QQuickItem *grabber() const;
- void setGrabber(QQuickItem *grabber);
+ QObject *exclusiveGrabber() const;
+ void setExclusiveGrabber(QObject *exclusiveGrabber);
+
+ QQuickItem *grabberItem() const;
+ void setGrabberItem(QQuickItem *exclusiveGrabber);
+
+ QQuickPointerHandler *grabberPointerHandler() const;
+ void setGrabberPointerHandler(QQuickPointerHandler *exclusiveGrabber, bool exclusive = false);
+
+ void cancelExclusiveGrab();
+ void cancelPassiveGrab(QQuickPointerHandler *handler);
+ bool removePassiveGrabber(QQuickPointerHandler *handler);
+ void cancelAllGrabs(QQuickPointerHandler *handler);
+
+ QVector<QPointer <QQuickPointerHandler> > passiveGrabbers() const { return m_passiveGrabbers; }
+ void setPassiveGrabbers(const QVector<QPointer <QQuickPointerHandler> > &grabbers) { m_passiveGrabbers = grabbers; }
+ void clearPassiveGrabbers() { m_passiveGrabbers.clear(); }
+
+protected:
+ void cancelExclusiveGrabImpl(QTouchEvent *cancelEvent = nullptr);
private:
+ QVector2D estimatedVelocity() const;
+
+protected:
+ QPointF m_pos;
QPointF m_scenePos;
- quint64 m_pointId;
- QPointer<QQuickItem> m_grabber;
+ QPointF m_scenePressPos;
+ QPointF m_sceneGrabPos;
+ QVector2D m_velocity;
+ int m_pointId;
+ QPointer<QObject> m_exclusiveGrabber;
+ QVector<QPointer <QQuickPointerHandler> > m_passiveGrabbers;
ulong m_timestamp;
ulong m_pressTimestamp;
State m_state;
- bool m_valid : 1;
bool m_accept : 1;
- int m_reserved : 30;
+ bool m_grabberIsHandler : 1;
+ int m_reserved : 29;
+
+ friend class QQuickPointerTouchEvent;
+ friend class QQuickWindowPrivate;
Q_DISABLE_COPY(QQuickEventPoint)
};
@@ -304,6 +359,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickEventTouchPoint : public QQuickEventPoint
Q_OBJECT
Q_PROPERTY(qreal rotation READ rotation)
Q_PROPERTY(qreal pressure READ pressure)
+ Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters)
Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId)
public:
@@ -313,34 +369,36 @@ public:
qreal rotation() const { return m_rotation; }
qreal pressure() const { return m_pressure; }
+ QSizeF ellipseDiameters() const { return m_ellipseDiameters; }
QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; }
private:
qreal m_rotation;
qreal m_pressure;
+ QSizeF m_ellipseDiameters;
QPointingDeviceUniqueId m_uniqueId;
+ friend class QQuickPointerTouchEvent;
+
Q_DISABLE_COPY(QQuickEventTouchPoint)
};
class Q_QUICK_PRIVATE_EXPORT QQuickPointerEvent : public QObject
{
Q_OBJECT
- Q_PROPERTY(const QQuickPointerDevice *device READ device)
- Q_PROPERTY(Qt::KeyboardModifiers modifiers READ modifiers)
- Q_PROPERTY(Qt::MouseButtons button READ button)
- Q_PROPERTY(Qt::MouseButtons buttons READ buttons)
+ Q_PROPERTY(QQuickPointerDevice *device READ device CONSTANT)
+ Q_PROPERTY(Qt::KeyboardModifiers modifiers READ modifiers CONSTANT)
+ Q_PROPERTY(Qt::MouseButtons button READ button CONSTANT)
+ Q_PROPERTY(Qt::MouseButtons buttons READ buttons CONSTANT)
public:
QQuickPointerEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
: QObject(parent)
, m_device(device)
- , m_event(nullptr)
- , m_button(Qt::NoButton)
, m_pressedButtons(Qt::NoButton)
- { }
+ {}
- virtual ~QQuickPointerEvent();
+ ~QQuickPointerEvent() override;
public: // property accessors
QQuickPointerDevice *device() const { return m_device; }
@@ -350,60 +408,94 @@ public: // property accessors
public: // helpers for C++ only (during event delivery)
virtual QQuickPointerEvent *reset(QEvent *ev) = 0;
+ virtual void localize(QQuickItem *target) = 0;
virtual bool isPressEvent() const = 0;
+ virtual bool isDoubleClickEvent() const { return false; }
+ virtual bool isUpdateEvent() const = 0;
+ virtual bool isReleaseEvent() const = 0;
virtual QQuickPointerMouseEvent *asPointerMouseEvent() { return nullptr; }
virtual QQuickPointerTouchEvent *asPointerTouchEvent() { return nullptr; }
virtual QQuickPointerTabletEvent *asPointerTabletEvent() { return nullptr; }
+#if QT_CONFIG(gestures)
+ virtual QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() { return nullptr; }
+#endif
+ virtual QQuickPointerScrollEvent *asPointerScrollEvent() { return nullptr; }
virtual const QQuickPointerMouseEvent *asPointerMouseEvent() const { return nullptr; }
virtual const QQuickPointerTouchEvent *asPointerTouchEvent() const { return nullptr; }
virtual const QQuickPointerTabletEvent *asPointerTabletEvent() const { return nullptr; }
- bool isValid() const { return m_event != nullptr; }
+#if QT_CONFIG(gestures)
+ virtual const QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() const { return nullptr; }
+#endif
+ virtual const QQuickPointerScrollEvent *asPointerScrollEvent() const { return nullptr; }
virtual bool allPointsAccepted() const = 0;
- bool isAccepted() { return m_event->isAccepted(); }
- void setAccepted(bool accepted) { m_event->setAccepted(accepted); }
+ virtual bool allUpdatedPointsAccepted() const = 0;
+ virtual bool allPointsGrabbed() const = 0;
+ bool isAccepted() { return m_event ? m_event->isAccepted() : false; }
+ void setAccepted(bool accepted) { if (m_event) m_event->setAccepted(accepted); }
QVector<QPointF> unacceptedPressedPointScenePositions() const;
virtual int pointCount() const = 0;
virtual QQuickEventPoint *point(int i) const = 0;
- virtual QQuickEventPoint *pointById(quint64 pointId) const = 0;
- virtual QVector<QQuickItem *> grabbers() const = 0;
+ virtual QQuickEventPoint *pointById(int pointId) const = 0;
+ virtual QVector<QObject *> exclusiveGrabbers() const = 0;
virtual void clearGrabbers() const = 0;
+ virtual bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const = 0;
- ulong timestamp() const { return m_event->timestamp(); }
+ ulong timestamp() const { return m_event ? m_event->timestamp() : 0; }
protected:
QQuickPointerDevice *m_device;
- QInputEvent *m_event; // original event as received by QQuickWindow
- Qt::MouseButton m_button;
+ QInputEvent *m_event = nullptr; // original event as received by QQuickWindow
+ Qt::MouseButton m_button = Qt::NoButton;
Qt::MouseButtons m_pressedButtons;
+ friend class QQuickWindowPrivate;
+
Q_DISABLE_COPY(QQuickPointerEvent)
};
-class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickPointerEvent
+class Q_QUICK_PRIVATE_EXPORT QQuickSinglePointEvent : public QQuickPointerEvent
+{
+ Q_OBJECT
+public:
+ QQuickSinglePointEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
+ : QQuickPointerEvent(parent, device), m_point(new QQuickEventPoint(this)) { }
+
+ void localize(QQuickItem *target) override;
+ int pointCount() const override { return 1; }
+ QQuickEventPoint *point(int i) const override;
+ QQuickEventPoint *pointById(int pointId) const override;
+ bool allPointsAccepted() const override;
+ bool allUpdatedPointsAccepted() const override;
+ bool allPointsGrabbed() const override;
+ QVector<QObject *> exclusiveGrabbers() const override;
+ void clearGrabbers() const override;
+ bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const override;
+
+protected:
+ QQuickEventPoint *m_point;
+
+ Q_DISABLE_COPY(QQuickSinglePointEvent)
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickSinglePointEvent
{
Q_OBJECT
public:
QQuickPointerMouseEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
- : QQuickPointerEvent(parent, device), m_mousePoint(new QQuickEventPoint(this)) { }
+ : QQuickSinglePointEvent(parent, device) { }
QQuickPointerEvent *reset(QEvent *) override;
bool isPressEvent() const override;
+ bool isDoubleClickEvent() const override;
+ bool isUpdateEvent() const override;
+ bool isReleaseEvent() const override;
QQuickPointerMouseEvent *asPointerMouseEvent() override { return this; }
const QQuickPointerMouseEvent *asPointerMouseEvent() const override { return this; }
- int pointCount() const override { return 1; }
- QQuickEventPoint *point(int i) const override;
- QQuickEventPoint *pointById(quint64 pointId) const override;
- bool allPointsAccepted() const override;
- QVector<QQuickItem *> grabbers() const override;
- void clearGrabbers() const override;
QMouseEvent *asMouseEvent(const QPointF& localPos) const;
-private:
- QQuickEventPoint *m_mousePoint;
-
Q_DISABLE_COPY(QQuickPointerMouseEvent)
};
@@ -413,21 +505,26 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerTouchEvent : public QQuickPointerEvent
public:
QQuickPointerTouchEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
: QQuickPointerEvent(parent, device)
- , m_pointCount(0)
, m_synthMouseEvent(QEvent::MouseMove, QPointF(), Qt::NoButton, Qt::NoButton, Qt::NoModifier)
- { }
+ {}
QQuickPointerEvent *reset(QEvent *) override;
+ void localize(QQuickItem *target) override;
bool isPressEvent() const override;
+ bool isUpdateEvent() const override;
+ bool isReleaseEvent() const override;
QQuickPointerTouchEvent *asPointerTouchEvent() override { return this; }
const QQuickPointerTouchEvent *asPointerTouchEvent() const override { return this; }
int pointCount() const override { return m_pointCount; }
QQuickEventPoint *point(int i) const override;
- QQuickEventPoint *pointById(quint64 pointId) const override;
+ QQuickEventPoint *pointById(int pointId) const override;
const QTouchEvent::TouchPoint *touchPointById(int pointId) const;
bool allPointsAccepted() const override;
- QVector<QQuickItem *> grabbers() const override;
+ bool allUpdatedPointsAccepted() const override;
+ bool allPointsGrabbed() const override;
+ QVector<QObject *> exclusiveGrabbers() const override;
void clearGrabbers() const override;
+ bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const override;
QMouseEvent *syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const;
QTouchEvent *touchEventForItem(QQuickItem *item, bool isFiltering = false) const;
@@ -435,13 +532,84 @@ public:
QTouchEvent *asTouchEvent() const;
private:
- int m_pointCount;
+ Qt::TouchPointStates touchPointStates() const;
+
+ int m_pointCount = 0;
QVector<QQuickEventTouchPoint *> m_touchPoints;
mutable QMouseEvent m_synthMouseEvent;
Q_DISABLE_COPY(QQuickPointerTouchEvent)
};
+#if QT_CONFIG(gestures)
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickSinglePointEvent
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::NativeGestureType type READ type CONSTANT)
+ Q_PROPERTY(qreal value READ value CONSTANT)
+
+public:
+ QQuickPointerNativeGestureEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
+ : QQuickSinglePointEvent(parent, device) { }
+
+ QQuickPointerEvent *reset(QEvent *) override;
+ bool isPressEvent() const override;
+ bool isUpdateEvent() const override;
+ bool isReleaseEvent() const override;
+ QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() override { return this; }
+ const QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() const override { return this; }
+ Qt::NativeGestureType type() const;
+ qreal value() const;
+
+ Q_DISABLE_COPY(QQuickPointerNativeGestureEvent)
+};
+#endif // QT_CONFIG(gestures)
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerScrollEvent : public QQuickSinglePointEvent
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector2D angleDelta READ angleDelta CONSTANT)
+ Q_PROPERTY(QVector2D pixelDelta READ pixelDelta CONSTANT)
+ Q_PROPERTY(bool hasAngleDelta READ hasAngleDelta CONSTANT)
+ Q_PROPERTY(bool hasPixelDelta READ hasPixelDelta CONSTANT)
+ Q_PROPERTY(bool inverted READ isInverted CONSTANT)
+
+public:
+ QQuickPointerScrollEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
+ : QQuickSinglePointEvent(parent, device) { }
+
+ QQuickPointerEvent *reset(QEvent *) override;
+ void localize(QQuickItem *target) override;
+ bool isPressEvent() const override;
+ bool isUpdateEvent() const override;
+ bool isReleaseEvent() const override;
+ QQuickPointerScrollEvent *asPointerScrollEvent() override { return this; }
+ const QQuickPointerScrollEvent *asPointerScrollEvent() const override { return this; }
+ QVector2D angleDelta() const { return m_angleDelta; }
+ QVector2D pixelDelta() const { return m_pixelDelta; }
+ bool hasAngleDelta() const { return !angleDelta().isNull(); }
+ bool hasPixelDelta() const { return !pixelDelta().isNull(); }
+ bool isInverted() const { return m_inverted; }
+ Qt::ScrollPhase phase() const { return m_phase; }
+
+private:
+ // TODO add QQuickPointerDevice source() whenever QInputEvent is extended to have a source device
+ // then maybe Qt::MouseEventSource synthSource() will be obsolete... that's why it's not public now
+ Qt::MouseEventSource synthSource() const { return m_synthSource; }
+
+private:
+ QVector2D m_angleDelta;
+ QVector2D m_pixelDelta;
+ Qt::ScrollPhase m_phase = Qt::NoScrollPhase;
+ Qt::MouseEventSource m_synthSource = Qt::MouseEventNotSynthesized;
+ bool m_inverted = false;
+
+ friend class QQuickWindowPrivate;
+
+ Q_DISABLE_COPY(QQuickPointerScrollEvent)
+};
+
+
// ### Qt 6: move this to qtbase, replace QTouchDevice and the enums in QTabletEvent
class Q_QUICK_PRIVATE_EXPORT QQuickPointerDevice : public QObject
{
@@ -455,7 +623,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerDevice : public QObject
Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId CONSTANT)
public:
- enum DeviceType {
+ enum DeviceType : qint16 {
UnknownDevice = 0x0000,
Mouse = 0x0001,
TouchScreen = 0x0002,
@@ -463,29 +631,28 @@ public:
Puck = 0x0008,
Stylus = 0x0010,
Airbrush = 0x0020,
- AllDevices = 0x003F
+ AllDevices = 0x7FFF
};
Q_DECLARE_FLAGS(DeviceTypes, DeviceType)
- Q_ENUM(DeviceType)
Q_FLAG(DeviceTypes)
- enum PointerType {
+ enum PointerType : qint16 {
GenericPointer = 0x0001,
Finger = 0x0002,
Pen = 0x0004,
Eraser = 0x0008,
Cursor = 0x0010,
- AllPointerTypes = 0x001F
+ AllPointerTypes = 0x7FFF
};
Q_DECLARE_FLAGS(PointerTypes, PointerType)
- Q_ENUM(PointerType)
Q_FLAG(PointerTypes)
- enum CapabilityFlag {
+ enum CapabilityFlag : qint16 {
Position = QTouchDevice::Position,
Area = QTouchDevice::Area,
Pressure = QTouchDevice::Pressure,
Velocity = QTouchDevice::Velocity,
+ MouseEmulation = QTouchDevice::MouseEmulation,
// some bits reserved in case we need more of QTouchDevice::Capabilities
Scroll = 0x0100, // mouse has a wheel, or there is OS-level scroll gesture recognition (dubious?)
Hover = 0x0200,
@@ -494,40 +661,48 @@ public:
YTilt = 0x1000
};
Q_DECLARE_FLAGS(Capabilities, CapabilityFlag)
- Q_ENUM(CapabilityFlag)
Q_FLAG(Capabilities)
- QQuickPointerDevice(DeviceType devType, PointerType pType, Capabilities caps, int maxPoints, int buttonCount, const QString &name, qint64 uniqueId = 0)
- : m_deviceType(devType), m_pointerType(pType), m_capabilities(caps)
- , m_maximumTouchPoints(maxPoints), m_buttonCount(buttonCount), m_name(name)
- , m_uniqueId(QPointingDeviceUniqueId::fromNumericId(uniqueId))
- {
- }
-
DeviceType type() const { return m_deviceType; }
PointerType pointerType() const { return m_pointerType; }
- Capabilities capabilities() const { return m_capabilities; }
+ Capabilities capabilities() const { return static_cast<Capabilities>(m_capabilities); }
bool hasCapability(CapabilityFlag cap) { return m_capabilities & cap; }
int maximumTouchPoints() const { return m_maximumTouchPoints; }
int buttonCount() const { return m_buttonCount; }
QString name() const { return m_name; }
QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; }
+ const QTouchDevice *qTouchDevice() const;
- static QQuickPointerDevice *touchDevice(QTouchDevice *d);
+ static QQuickPointerDevice *touchDevice(const QTouchDevice *d);
static QList<QQuickPointerDevice *> touchDevices();
static QQuickPointerDevice *genericMouseDevice();
static QQuickPointerDevice *tabletDevice(qint64);
+ QVector<QQuickPointerHandler *> &eventDeliveryTargets() { return m_eventDeliveryTargets; }
+
+private:
+ QQuickPointerDevice(DeviceType devType, PointerType pType, Capabilities caps, int maxPoints, int buttonCount, const QString &name, qint64 uniqueId = 0)
+ : m_deviceType(devType), m_pointerType(pType), m_capabilities(static_cast<qint16>(caps))
+ , m_maximumTouchPoints(static_cast<qint8>(maxPoints)), m_buttonCount(static_cast<qint8>(buttonCount)), m_name(name)
+ , m_uniqueId(QPointingDeviceUniqueId::fromNumericId(uniqueId))
+ {
+ }
+ ~QQuickPointerDevice() override { }
+
private:
+ // begin 64-bit field
DeviceType m_deviceType;
PointerType m_pointerType;
- Capabilities m_capabilities;
- int m_maximumTouchPoints;
- int m_buttonCount;
+ qint16 m_capabilities;
+ qint8 m_maximumTouchPoints;
+ qint8 m_buttonCount;
+ // end 64-bit field
QString m_name;
QPointingDeviceUniqueId m_uniqueId;
+ QVector<QQuickPointerHandler *> m_eventDeliveryTargets; // during delivery, handlers which have already seen the event
Q_DISABLE_COPY(QQuickPointerDevice)
+ friend struct ConstructableQQuickPointerDevice;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickPointerDevice::DeviceTypes)
@@ -548,5 +723,6 @@ QML_DECLARE_TYPE(QQuickCloseEvent)
QML_DECLARE_TYPE(QQuickPointerDevice)
QML_DECLARE_TYPE(QPointingDeviceUniqueId)
QML_DECLARE_TYPE(QQuickPointerEvent)
+Q_DECLARE_METATYPE(QQuickEventPoint::GrabTransition)
#endif // QQUICKEVENTS_P_P_H
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index a3bc7635a1..d6dddc3f1c 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.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.
@@ -44,6 +44,7 @@
#include "qquickwindow_p.h"
#include "qquickevents_p_p.h"
+#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquicktransition_p.h>
#include <private/qqmlglobal_p.h>
@@ -55,10 +56,13 @@
#include <QtCore/qmath.h>
#include "qplatformdefs.h"
+#include <math.h>
#include <cmath>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcHandlerParent)
+
// FlickThreshold determines how far the "mouse" must have moved
// before we perform a flick.
static const int FlickThreshold = 15;
@@ -67,10 +71,6 @@ static const int FlickThreshold = 15;
// will ensure the Flickable retains the grab on consecutive flicks.
static const int RetainGrabVelocity = 100;
-#ifdef Q_OS_OSX
-static const int MovementEndingTimerInterval = 100;
-#endif
-
// Currently std::round can't be used on Android when using ndk g++, so
// use C version instead. We could just define two versions of Round, one
// for float and one for double, but then only one of them would be used
@@ -170,13 +170,13 @@ class QQuickFlickableReboundTransition : public QQuickTransitionManager
{
public:
QQuickFlickableReboundTransition(QQuickFlickable *f, const QString &name)
- : flickable(f), axisData(0), propName(name), active(false)
+ : flickable(f), axisData(nullptr), propName(name), active(false)
{
}
~QQuickFlickableReboundTransition()
{
- flickable = 0;
+ flickable = nullptr;
}
bool startTransition(QQuickFlickablePrivate::AxisData *data, qreal toPos) {
@@ -211,7 +211,7 @@ public:
}
protected:
- void finished() Q_DECL_OVERRIDE {
+ void finished() override {
if (!flickable)
return;
axisData->move.setValue(axisData->transitionTo);
@@ -246,16 +246,17 @@ QQuickFlickablePrivate::QQuickFlickablePrivate()
, stealMouse(false), pressed(false)
, scrollingPhase(false), interactive(true), calcVelocity(false)
, pixelAligned(false)
+ , syncDrag(false)
, lastPosTime(-1)
, lastPressTime(0)
, deceleration(QML_FLICK_DEFAULTDECELERATION)
, maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100)
- , delayedPressEvent(0), pressDelay(0), fixupDuration(400)
- , flickBoost(1.0), fixupMode(Normal), vTime(0), visibleArea(0)
+ , delayedPressEvent(nullptr), pressDelay(0), fixupDuration(400)
+ , flickBoost(1.0), fixupMode(Normal), vTime(0), visibleArea(nullptr)
, flickableDirection(QQuickFlickable::AutoFlickDirection)
, boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
, boundsMovement(QQuickFlickable::FollowBoundsBehavior)
- , rebound(0)
+ , rebound(nullptr)
{
}
@@ -269,6 +270,7 @@ void QQuickFlickablePrivate::init()
qmlobject_connect(&velocityTimeline, QQuickTimeLine, SIGNAL(completed()),
q, QQuickFlickable, SLOT(velocityTimelineCompleted()))
q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setAcceptTouchEvents(false); // rely on mouse events synthesized from touch
q->setFiltersChildMouseEvents(true);
QQuickItemPrivate *viewportPrivate = QQuickItemPrivate::get(contentItem);
viewportPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
@@ -314,7 +316,7 @@ void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometr
{
Q_Q(QQuickFlickable);
if (item == contentItem) {
- Qt::Orientations orient = 0;
+ Qt::Orientations orient = nullptr;
if (change.xChange())
orient |= Qt::Horizontal;
if (change.yChange())
@@ -505,7 +507,8 @@ static bool fuzzyLessThanOrEqualTo(qreal a, qreal b)
void QQuickFlickablePrivate::updateBeginningEnd()
{
Q_Q(QQuickFlickable);
- bool atBoundaryChange = false;
+ bool atXBeginningChange = false, atXEndChange = false;
+ bool atYBeginningChange = false, atYEndChange = false;
// Vertical
const qreal maxyextent = -q->maxYExtent();
@@ -516,11 +519,11 @@ void QQuickFlickablePrivate::updateBeginningEnd()
if (atBeginning != vData.atBeginning) {
vData.atBeginning = atBeginning;
- atBoundaryChange = true;
+ atYBeginningChange = true;
}
if (atEnd != vData.atEnd) {
vData.atEnd = atEnd;
- atBoundaryChange = true;
+ atYEndChange = true;
}
// Horizontal
@@ -532,11 +535,11 @@ void QQuickFlickablePrivate::updateBeginningEnd()
if (atBeginning != hData.atBeginning) {
hData.atBeginning = atBeginning;
- atBoundaryChange = true;
+ atXBeginningChange = true;
}
if (atEnd != hData.atEnd) {
hData.atEnd = atEnd;
- atBoundaryChange = true;
+ atXEndChange = true;
}
if (vData.extentsChanged) {
@@ -557,8 +560,16 @@ void QQuickFlickablePrivate::updateBeginningEnd()
}
}
- if (atBoundaryChange)
+ if (atXEndChange || atYEndChange || atXBeginningChange || atYBeginningChange)
emit q->isAtBoundaryChanged();
+ if (atXEndChange)
+ emit q->atXEndChanged();
+ if (atXBeginningChange)
+ emit q->atXBeginningChanged();
+ if (atYEndChange)
+ emit q->atYEndChanged();
+ if (atYBeginningChange)
+ emit q->atYBeginningChanged();
if (visibleArea)
visibleArea->updateVisible();
@@ -591,7 +602,7 @@ void QQuickFlickablePrivate::updateBeginningEnd()
\ingroup qtquick-input
\ingroup qtquick-containers
- \brief Provides a surface that can be "flicked"
+ \brief Provides a surface that can be "flicked".
\inherits Item
The Flickable item places its children on a surface that can be dragged
@@ -629,6 +640,31 @@ void QQuickFlickablePrivate::updateBeginningEnd()
\c contentItem that are relevant. For example, the bound of Items added
to the Flickable will be available by \c contentItem.childrenRect
+ \section1 Examples of contentX and contentY
+
+ The following images demonstrate a flickable being flicked in various
+ directions and the resulting \l contentX and \l contentY values.
+ The blue square represents the flickable's content, and the black
+ border represents the bounds of the flickable.
+
+ \table
+ \row
+ \li \image flickable-contentXY-resting.png
+ \li The \c contentX and \c contentY are both \c 0.
+ \row
+ \li \image flickable-contentXY-top-left.png
+ \li The \c contentX and the \c contentY are both \c 50.
+ \row
+ \li \image flickable-contentXY-top-right.png
+ \li The \c contentX is \c -50 and the \c contentY is \c 50.
+ \row
+ \li \image flickable-contentXY-bottom-right.png
+ \li The \c contentX and the \c contentY are both \c -50.
+ \row
+ \li \image flickable-contentXY-bottom-left.png
+ \li The \c contentX is \c 50 and the \c contentY is \c -50.
+ \endtable
+
\section1 Limitations
\note Due to an implementation detail, items placed inside a Flickable
@@ -722,7 +758,19 @@ QQuickFlickable::~QQuickFlickable()
These properties hold the surface coordinate currently at the top-left
corner of the Flickable. For example, if you flick an image up 100 pixels,
- \c contentY will be 100.
+ \c contentY will increase by 100.
+
+ \note If you flick back to the origin (the top-left corner), after the
+ rebound animation, \c contentX will settle to the same value as \c originX,
+ and \c contentY to \c originY. These are usually (0,0), however ListView
+ and GridView may have an arbitrary origin due to delegate size variation,
+ or item insertion/removal outside the visible region. So if you want to
+ implement something like a vertical scrollbar, one way is to use
+ \c {y: (contentY - originY) * (height / contentHeight)}
+ for the position; another way is to use the normalized values in
+ \l {QtQuick::Flickable::visibleArea}{visibleArea}.
+
+ \sa {Examples of contentX and contentY}, originX, originY
*/
qreal QQuickFlickable::contentX() const
{
@@ -736,8 +784,9 @@ void QQuickFlickable::setContentX(qreal pos)
d->hData.explicitValue = true;
d->resetTimeline(d->hData);
d->hData.vTime = d->timeline.time();
- movementEnding(true, false);
- if (-pos != d->hData.move.value())
+ if (isMoving() || isFlicking())
+ movementEnding(true, false);
+ if (!qFuzzyCompare(-pos, d->hData.move.value()))
d->hData.move.setValue(-pos);
}
@@ -753,8 +802,9 @@ void QQuickFlickable::setContentY(qreal pos)
d->vData.explicitValue = true;
d->resetTimeline(d->vData);
d->vData.vTime = d->timeline.time();
- movementEnding(false, true);
- if (-pos != d->vData.move.value())
+ if (isMoving() || isFlicking())
+ movementEnding(false, true);
+ if (!qFuzzyCompare(-pos, d->vData.move.value()))
d->vData.move.setValue(-pos);
}
@@ -942,6 +992,33 @@ void QQuickFlickable::setPixelAligned(bool align)
}
}
+/*!
+ \qmlproperty bool QtQuick::Flickable::synchronousDrag
+ \since 5.12
+
+ If this property is set to true, then when the mouse or touchpoint moves
+ far enough to begin dragging the content, the content will jump, such that
+ the content pixel which was under the cursor or touchpoint when pressed
+ remains under that point.
+
+ The default is \c false, which provides a smoother experience (no jump)
+ at the cost that some of the drag distance is "lost" at the beginning.
+*/
+bool QQuickFlickable::synchronousDrag() const
+{
+ Q_D(const QQuickFlickable);
+ return d->syncDrag;
+}
+
+void QQuickFlickable::setSynchronousDrag(bool v)
+{
+ Q_D(QQuickFlickable);
+ if (v != d->syncDrag) {
+ d->syncDrag = v;
+ emit synchronousDragChanged();
+ }
+}
+
qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event) const
{
if (0 != event->timestamp())
@@ -1058,7 +1135,7 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp
if (overThreshold || elapsedSincePress > 200) {
if (!vMoved)
vData.dragStartOffset = dy;
- qreal newY = dy + vData.pressPos - vData.dragStartOffset;
+ qreal newY = dy + vData.pressPos - (syncDrag ? 0 : vData.dragStartOffset);
// Recalculate bounds in case margins have changed, but use the content
// size estimate taken at the start of the drag in case the drag causes
// the estimate to be altered
@@ -1134,7 +1211,7 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp
if (overThreshold || elapsedSincePress > 200) {
if (!hMoved)
hData.dragStartOffset = dx;
- qreal newX = dx + hData.pressPos - hData.dragStartOffset;
+ qreal newX = dx + hData.pressPos - (syncDrag ? 0 : hData.dragStartOffset);
const qreal minX = hData.dragMinBound + hData.startMargin;
const qreal maxX = hData.dragMaxBound - hData.endMargin;
if (!(boundsBehavior & QQuickFlickable::DragOverBounds)) {
@@ -1238,7 +1315,7 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp
void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
{
Q_Q(QQuickFlickable);
- if (!interactive || lastPosTime == -1)
+ if (!interactive || lastPosTime == -1 || event->buttons() == Qt::NoButton)
return;
qint64 currentTimestamp = computeCurrentTime(event);
@@ -1418,9 +1495,13 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
case Qt::ScrollUpdate:
if (d->scrollingPhase)
d->pressed = true;
-#ifdef Q_OS_OSX
- d->movementEndingTimer.start(MovementEndingTimerInterval, this);
-#endif
+ break;
+ case Qt::ScrollMomentum:
+ d->pressed = false;
+ d->scrollingPhase = false;
+ d->draggingEnding();
+ event->accept();
+ d->lastPosTime = -1;
break;
case Qt::ScrollEnd:
d->pressed = false;
@@ -1429,6 +1510,9 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
event->accept();
returnToBounds();
d->lastPosTime = -1;
+ d->stealMouse = false;
+ if (!d->velocityTimeline.isActive() && !d->timeline.isActive())
+ movementEnding(true, true);
return;
}
@@ -1532,7 +1616,7 @@ void QQuickFlickablePrivate::clearDelayedPress()
if (delayedPressEvent) {
delayedPressTimer.stop();
delete delayedPressEvent;
- delayedPressEvent = 0;
+ delayedPressEvent = nullptr;
}
}
@@ -1542,11 +1626,13 @@ void QQuickFlickablePrivate::replayDelayedPress()
if (delayedPressEvent) {
// Losing the grab will clear the delayed press event; take control of it here
QScopedPointer<QMouseEvent> mouseEvent(delayedPressEvent);
- delayedPressEvent = 0;
+ delayedPressEvent = nullptr;
delayedPressTimer.stop();
// If we have the grab, release before delivering the event
if (QQuickWindow *w = q->window()) {
+ QQuickWindowPrivate *wpriv = QQuickWindowPrivate::get(w);
+ wpriv->allowChildEventFiltering = false; // don't allow re-filtering during replay
replayingPressEvent = true;
if (w->mouseGrabberItem() == q)
q->ungrabMouse();
@@ -1554,6 +1640,7 @@ void QQuickFlickablePrivate::replayDelayedPress()
// Use the event handler that will take care of finding the proper item to propagate the event
QCoreApplication::sendEvent(w, mouseEvent.data());
replayingPressEvent = false;
+ wpriv->allowChildEventFiltering = true;
}
}
}
@@ -1621,12 +1708,6 @@ void QQuickFlickable::timerEvent(QTimerEvent *event)
if (d->delayedPressEvent) {
d->replayDelayedPress();
}
- } else if (event->timerId() == d->movementEndingTimer.timerId()) {
- d->movementEndingTimer.stop();
- d->pressed = false;
- d->stealMouse = false;
- if (!d->velocityTimeline.isActive() && !d->timeline.isActive())
- movementEnding(true, true);
}
}
@@ -1766,9 +1847,10 @@ void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity)
d->vData.reset();
d->hData.velocity = xVelocity;
d->vData.velocity = yVelocity;
+ d->hData.vTime = d->vData.vTime = d->timeline.time();
- bool flickedX = d->flickX(xVelocity);
- bool flickedY = d->flickY(yVelocity);
+ const bool flickedX = xflick() && !qFuzzyIsNull(xVelocity) && d->flickX(xVelocity);
+ const bool flickedY = yflick() && !qFuzzyIsNull(yVelocity) && d->flickY(yVelocity);
if (flickedX)
d->hMoved = true;
@@ -1817,6 +1899,8 @@ void QQuickFlickablePrivate::data_append(QQmlListProperty<QObject> *prop, QObjec
{
if (QQuickItem *i = qmlobject_cast<QQuickItem *>(o)) {
i->setParentItem(static_cast<QQuickFlickablePrivate*>(prop->data)->contentItem);
+ } else if (QQuickPointerHandler *pointerHandler = qmlobject_cast<QQuickPointerHandler *>(o)) {
+ static_cast<QQuickFlickablePrivate*>(prop->data)->addPointerHandler(pointerHandler);
} else {
o->setParent(prop->object); // XXX todo - do we want this?
}
@@ -1831,7 +1915,7 @@ int QQuickFlickablePrivate::data_count(QQmlListProperty<QObject> *)
QObject *QQuickFlickablePrivate::data_at(QQmlListProperty<QObject> *, int)
{
// XXX todo
- return 0;
+ return nullptr;
}
void QQuickFlickablePrivate::data_clear(QQmlListProperty<QObject> *)
@@ -2143,6 +2227,8 @@ void QQuickFlickable::setRightMargin(qreal m)
This is usually (0,0), however ListView and GridView may have an arbitrary
origin due to delegate size variation, or item insertion/removal outside
the visible region.
+
+ \sa contentX, contentY
*/
qreal QQuickFlickable::originY() const
@@ -2173,25 +2259,25 @@ qreal QQuickFlickable::originX() const
void QQuickFlickable::resizeContent(qreal w, qreal h, QPointF center)
{
Q_D(QQuickFlickable);
- if (w != d->hData.viewSize) {
- qreal oldSize = d->hData.viewSize;
- d->hData.viewSize = w;
- d->contentItem->setWidth(w);
+ const qreal oldHSize = d->hData.viewSize;
+ const qreal oldVSize = d->vData.viewSize;
+ const bool needToUpdateWidth = w != oldHSize;
+ const bool needToUpdateHeight = h != oldVSize;
+ d->hData.viewSize = w;
+ d->vData.viewSize = h;
+ d->contentItem->setSize(QSizeF(w, h));
+ if (needToUpdateWidth)
emit contentWidthChanged();
- if (center.x() != 0) {
- qreal pos = center.x() * w / oldSize;
- setContentX(contentX() + pos - center.x());
- }
- }
- if (h != d->vData.viewSize) {
- qreal oldSize = d->vData.viewSize;
- d->vData.viewSize = h;
- d->contentItem->setHeight(h);
+ if (needToUpdateHeight)
emit contentHeightChanged();
- if (center.y() != 0) {
- qreal pos = center.y() * h / oldSize;
- setContentY(contentY() + pos - center.y());
- }
+
+ if (center.x() != 0) {
+ qreal pos = center.x() * w / oldHSize;
+ setContentX(contentX() + pos - center.x());
+ }
+ if (center.y() != 0) {
+ qreal pos = center.y() * h / oldVSize;
+ setContentY(contentY() + pos - center.y());
}
d->updateBeginningEnd();
}
@@ -2274,6 +2360,14 @@ void QQuickFlickablePrivate::cancelInteraction()
}
}
+void QQuickFlickablePrivate::addPointerHandler(QQuickPointerHandler *h)
+{
+ Q_Q(const QQuickFlickable);
+ qCDebug(lcHandlerParent) << "reparenting handler" << h << "to contentItem of" << q;
+ h->setParent(contentItem);
+ QQuickItemPrivate::get(contentItem)->addPointerHandler(h);
+}
+
/*!
QQuickFlickable::filterMouseEvent checks filtered mouse events and potentially steals them.
@@ -2484,7 +2578,7 @@ void QQuickFlickablePrivate::draggingStarting()
void QQuickFlickablePrivate::draggingEnding()
{
Q_Q(QQuickFlickable);
- bool wasDragging = hData.dragging || vData.dragging;
+ const bool wasDragging = hData.dragging || vData.dragging;
if (hData.dragging) {
hData.dragging = false;
emit q->draggingHorizontallyChanged();
@@ -2493,12 +2587,14 @@ void QQuickFlickablePrivate::draggingEnding()
vData.dragging = false;
emit q->draggingVerticallyChanged();
}
- if (wasDragging && !hData.dragging && !vData.dragging) {
- emit q->draggingChanged();
- emit q->dragEnded();
+ if (wasDragging) {
+ if (!hData.dragging && !vData.dragging) {
+ emit q->draggingChanged();
+ emit q->dragEnded();
+ }
+ hData.inRebound = false;
+ vData.inRebound = false;
}
- hData.inRebound = false;
- vData.inRebound = false;
}
bool QQuickFlickablePrivate::isViewMoving() const
diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h
index 7558ee7df8..c54ed5ce71 100644
--- a/src/quick/items/qquickflickable_p.h
+++ b/src/quick/items/qquickflickable_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.
@@ -98,14 +98,15 @@ class Q_QUICK_PRIVATE_EXPORT QQuickFlickable : public QQuickItem
Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged)
Q_PROPERTY(int pressDelay READ pressDelay WRITE setPressDelay NOTIFY pressDelayChanged)
- Q_PROPERTY(bool atXEnd READ isAtXEnd NOTIFY isAtBoundaryChanged)
- Q_PROPERTY(bool atYEnd READ isAtYEnd NOTIFY isAtBoundaryChanged)
- Q_PROPERTY(bool atXBeginning READ isAtXBeginning NOTIFY isAtBoundaryChanged)
- Q_PROPERTY(bool atYBeginning READ isAtYBeginning NOTIFY isAtBoundaryChanged)
+ Q_PROPERTY(bool atXEnd READ isAtXEnd NOTIFY atXEndChanged)
+ Q_PROPERTY(bool atYEnd READ isAtYEnd NOTIFY atYEndChanged)
+ Q_PROPERTY(bool atXBeginning READ isAtXBeginning NOTIFY atXBeginningChanged)
+ Q_PROPERTY(bool atYBeginning READ isAtYBeginning NOTIFY atYBeginningChanged)
Q_PROPERTY(QQuickFlickableVisibleArea *visibleArea READ visibleArea CONSTANT)
Q_PROPERTY(bool pixelAligned READ pixelAligned WRITE setPixelAligned NOTIFY pixelAlignedChanged)
+ Q_PROPERTY(bool synchronousDrag READ synchronousDrag WRITE setSynchronousDrag NOTIFY synchronousDragChanged REVISION 12)
Q_PROPERTY(qreal horizontalOvershoot READ horizontalOvershoot NOTIFY horizontalOvershootChanged REVISION 9)
Q_PROPERTY(qreal verticalOvershoot READ verticalOvershoot NOTIFY verticalOvershootChanged REVISION 9)
@@ -115,8 +116,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickFlickable : public QQuickItem
Q_CLASSINFO("DefaultProperty", "flickableData")
public:
- QQuickFlickable(QQuickItem *parent=0);
- ~QQuickFlickable();
+ QQuickFlickable(QQuickItem *parent=nullptr);
+ ~QQuickFlickable() override;
QQmlListProperty<QObject> flickableData();
QQmlListProperty<QQuickItem> flickableChildren();
@@ -213,6 +214,9 @@ public:
bool pixelAligned() const;
void setPixelAligned(bool align);
+ bool synchronousDrag() const;
+ void setSynchronousDrag(bool v);
+
qreal horizontalOvershoot() const;
qreal verticalOvershoot() const;
@@ -259,18 +263,25 @@ Q_SIGNALS:
void dragStarted();
void dragEnded();
void pixelAlignedChanged();
+ Q_REVISION(12) void synchronousDragChanged();
Q_REVISION(9) void horizontalOvershootChanged();
Q_REVISION(9) void verticalOvershootChanged();
+ // The next four signals should be marked as Q_REVISION(12). See QTBUG-71243
+ void atXEndChanged();
+ void atYEndChanged();
+ void atXBeginningChanged();
+ void atYBeginningChanged();
+
protected:
- bool childMouseEventFilter(QQuickItem *, QEvent *) Q_DECL_OVERRIDE;
- void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
+ bool childMouseEventFilter(QQuickItem *, QEvent *) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
#if QT_CONFIG(wheelevent)
- void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
+ void wheelEvent(QWheelEvent *event) override;
#endif
- void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE;
+ void timerEvent(QTimerEvent *event) override;
QQuickFlickableVisibleArea *visibleArea();
@@ -288,11 +299,11 @@ protected:
virtual qreal maxYExtent() const;
qreal vWidth() const;
qreal vHeight() const;
- void componentComplete() Q_DECL_OVERRIDE;
+ void componentComplete() override;
virtual void viewportMoved(Qt::Orientations orient);
void geometryChanged(const QRectF &newGeometry,
- const QRectF &oldGeometry) Q_DECL_OVERRIDE;
- void mouseUngrabEvent() Q_DECL_OVERRIDE;
+ const QRectF &oldGeometry) override;
+ void mouseUngrabEvent() override;
bool filterMouseEvent(QQuickItem *receiver, QMouseEvent *event);
bool xflick() const;
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 8609a15fcd..835c54170f 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_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.
@@ -87,7 +87,7 @@ public:
{
Velocity(QQuickFlickablePrivate *p)
: parent(p) {}
- void setValue(qreal v) Q_DECL_OVERRIDE {
+ void setValue(qreal v) override {
if (v != value()) {
QQuickTimeLineValue::setValue(v);
parent->updateVelocity();
@@ -99,16 +99,17 @@ public:
struct AxisData {
AxisData(QQuickFlickablePrivate *fp, void (QQuickFlickablePrivate::*func)(qreal))
: move(fp, func)
- , transitionToBounds(0)
+ , transitionToBounds(nullptr)
, viewSize(-1), lastPos(0), previousDragDelta(0), velocity(0), startMargin(0), endMargin(0)
, origin(0), overshoot(0)
, transitionTo(0)
, continuousFlickVelocity(0), velocityTime(), vTime(0)
, smoothVelocity(fp), atEnd(false), atBeginning(true)
, transitionToSet(false)
- , fixingUp(false), inOvershoot(false), moving(false), flicking(false)
+ , fixingUp(false), inOvershoot(false), inRebound(false), moving(false), flicking(false)
, dragging(false), extentsChanged(false)
, explicitValue(false), minExtentDirty(true), maxExtentDirty(true)
+ , unused(0)
{}
~AxisData();
@@ -168,6 +169,7 @@ public:
bool explicitValue : 1;
mutable bool minExtentDirty : 1;
mutable bool maxExtentDirty : 1;
+ uint unused : 19;
};
bool flickX(qreal velocity);
@@ -195,7 +197,7 @@ public:
qreal overShootDistance(qreal size) const;
- void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override;
void draggingStarting();
void draggingEnding();
@@ -204,6 +206,8 @@ public:
void cancelInteraction();
+ void addPointerHandler(QQuickPointerHandler *h) override;
+
public:
QQuickItem *contentItem;
@@ -219,8 +223,8 @@ public:
bool interactive : 1;
bool calcVelocity : 1;
bool pixelAligned : 1;
+ bool syncDrag : 1;
QElapsedTimer timer;
- QBasicTimer movementEndingTimer;
qint64 lastPosTime;
qint64 lastPressTime;
QPointF lastPos;
@@ -282,7 +286,7 @@ class QQuickFlickableVisibleArea : public QObject
Q_PROPERTY(qreal heightRatio READ heightRatio NOTIFY heightRatioChanged)
public:
- QQuickFlickableVisibleArea(QQuickFlickable *parent=0);
+ QQuickFlickableVisibleArea(QQuickFlickable *parent=nullptr);
qreal xPosition() const;
qreal widthRatio() const;
diff --git a/src/quick/items/qquickflipable.cpp b/src/quick/items/qquickflipable.cpp
index a960cd8b80..a338985622 100644
--- a/src/quick/items/qquickflipable.cpp
+++ b/src/quick/items/qquickflipable.cpp
@@ -57,7 +57,7 @@ public:
transform = t;
update();
}
- void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE {
+ void applyTo(QMatrix4x4 *matrix) const override {
*matrix *= transform;
}
private:
@@ -68,9 +68,9 @@ class QQuickFlipablePrivate : public QQuickItemPrivate
{
Q_DECLARE_PUBLIC(QQuickFlipable)
public:
- QQuickFlipablePrivate() : current(QQuickFlipable::Front), front(0), back(0), sideDirty(false) {}
+ QQuickFlipablePrivate() : current(QQuickFlipable::Front), front(nullptr), back(nullptr), sideDirty(false) {}
- void transformChanged() Q_DECL_OVERRIDE;
+ void transformChanged() override;
void updateSide();
void setBackTransform();
@@ -91,7 +91,7 @@ public:
\inherits Item
\ingroup qtquick-input
\ingroup qtquick-containers
- \brief Provides a surface that can be flipped
+ \brief Provides a surface that can be flipped.
Flipable is an item that can be visibly "flipped" between its front and
back sides, like a card. It may used together with \l Rotation, \l State
@@ -178,7 +178,7 @@ void QQuickFlipable::setBack(QQuickItem *back)
qmlWarning(this) << tr("back is a write-once property");
return;
}
- if (back == 0)
+ if (back == nullptr)
return;
d->back = back;
d->back->setParentItem(this);
diff --git a/src/quick/items/qquickflipable_p.h b/src/quick/items/qquickflipable_p.h
index a76977d4ac..d70cd02d35 100644
--- a/src/quick/items/qquickflipable_p.h
+++ b/src/quick/items/qquickflipable_p.h
@@ -74,7 +74,7 @@ class Q_AUTOTEST_EXPORT QQuickFlipable : public QQuickItem
//### flipAxis
//### flipRotation
public:
- QQuickFlipable(QQuickItem *parent=0);
+ QQuickFlipable(QQuickItem *parent=nullptr);
~QQuickFlipable();
QQuickItem *front() const;
@@ -93,7 +93,7 @@ Q_SIGNALS:
void sideChanged();
protected:
- void updatePolish() Q_DECL_OVERRIDE;
+ void updatePolish() override;
private Q_SLOTS:
void retransformBack();
diff --git a/src/quick/items/qquickfocusscope.cpp b/src/quick/items/qquickfocusscope.cpp
index de4494a521..667d4d7b1d 100644
--- a/src/quick/items/qquickfocusscope.cpp
+++ b/src/quick/items/qquickfocusscope.cpp
@@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE
\inqmlmodule QtQuick
\ingroup qtquick-input
- \brief Explicitly creates a focus scope
+ \brief Explicitly creates a focus scope.
\inherits Item
Focus scopes assist in keyboard focus handling when building reusable QML
diff --git a/src/quick/items/qquickfocusscope_p.h b/src/quick/items/qquickfocusscope_p.h
index b65e543343..af750fc127 100644
--- a/src/quick/items/qquickfocusscope_p.h
+++ b/src/quick/items/qquickfocusscope_p.h
@@ -59,7 +59,7 @@ class Q_AUTOTEST_EXPORT QQuickFocusScope : public QQuickItem
{
Q_OBJECT
public:
- QQuickFocusScope(QQuickItem *parent=0);
+ QQuickFocusScope(QQuickItem *parent=nullptr);
virtual ~QQuickFocusScope();
};
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index 52b19d994c..48f8b8db5c 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -57,7 +57,7 @@ public:
QQuickFramebufferObjectPrivate()
: followsItemSize(true)
, mirrorVertically(false)
- , node(0)
+ , node(nullptr)
{
}
@@ -194,10 +194,10 @@ class QSGFramebufferObjectNode : public QSGTextureProvider, public QSGSimpleText
public:
QSGFramebufferObjectNode()
- : window(0)
- , fbo(0)
- , msDisplayFbo(0)
- , renderer(0)
+ : window(nullptr)
+ , fbo(nullptr)
+ , msDisplayFbo(nullptr)
+ , renderer(nullptr)
, renderPending(true)
, invalidatePending(false)
, devicePixelRatio(1)
@@ -219,7 +219,7 @@ public:
window->update();
}
- QSGTexture *texture() const Q_DECL_OVERRIDE
+ QSGTexture *texture() const override
{
return QSGSimpleTextureNode::texture();
}
@@ -260,7 +260,7 @@ public:
bool renderPending;
bool invalidatePending;
- int devicePixelRatio;
+ qreal devicePixelRatio;
};
static inline bool isOpenGL(QSGRenderContext *rc)
@@ -282,13 +282,13 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode
// that easily so with this logic, the renderer only goes away when
// the scenegraph is invalidated or it is removed from the scene.
if (!n && (width() <= 0 || height() <= 0))
- return 0;
+ return nullptr;
Q_D(QQuickFramebufferObject);
if (!n) {
if (!isOpenGL(d->sceneGraphRenderContext()))
- return 0;
+ return nullptr;
if (!d->node)
d->node = new QSGFramebufferObjectNode;
n = d->node;
@@ -312,14 +312,13 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode
n->devicePixelRatio = window()->effectiveDevicePixelRatio();
desiredFboSize *= n->devicePixelRatio;
- if (n->fbo && (d->followsItemSize || n->invalidatePending)) {
- if (n->fbo->size() != desiredFboSize) {
- delete n->fbo;
- n->fbo = 0;
- delete n->msDisplayFbo;
- n->msDisplayFbo = 0;
- n->invalidatePending = false;
- }
+ if (n->fbo && ((d->followsItemSize && n->fbo->size() != desiredFboSize) || n->invalidatePending)) {
+ delete n->texture();
+ delete n->fbo;
+ n->fbo = nullptr;
+ delete n->msDisplayFbo;
+ n->msDisplayFbo = nullptr;
+ n->invalidatePending = false;
}
if (!n->fbo) {
@@ -369,10 +368,10 @@ QSGTextureProvider *QQuickFramebufferObject::textureProvider() const
QQuickWindow *w = window();
if (!w || !w->openglContext() || QThread::currentThread() != w->openglContext()->thread()) {
qWarning("QQuickFramebufferObject::textureProvider: can only be queried on the rendering thread of an exposed window");
- return 0;
+ return nullptr;
}
if (!isOpenGL(d->sceneGraphRenderContext()))
- return 0;
+ return nullptr;
if (!d->node)
d->node = new QSGFramebufferObjectNode;
return d->node;
@@ -387,13 +386,13 @@ void QQuickFramebufferObject::releaseResources()
// forget about the node. Since it is the node we returned from updatePaintNode
// it will be managed by the scene graph.
Q_D(QQuickFramebufferObject);
- d->node = 0;
+ d->node = nullptr;
}
void QQuickFramebufferObject::invalidateSceneGraph()
{
Q_D(QQuickFramebufferObject);
- d->node = 0;
+ d->node = nullptr;
}
/*!
@@ -412,7 +411,7 @@ void QQuickFramebufferObject::invalidateSceneGraph()
* GUI thread is blocked.
*/
QQuickFramebufferObject::Renderer::Renderer()
- : data(0)
+ : data(nullptr)
{
}
@@ -440,7 +439,7 @@ QQuickFramebufferObject::Renderer::~Renderer()
*/
QOpenGLFramebufferObject *QQuickFramebufferObject::Renderer::framebufferObject() const
{
- return data ? ((QSGFramebufferObjectNode *) data)->fbo : 0;
+ return data ? ((QSGFramebufferObjectNode *) data)->fbo : nullptr;
}
/*!
diff --git a/src/quick/items/qquickframebufferobject.h b/src/quick/items/qquickframebufferobject.h
index 13eeb931ad..d66ca40b3a 100644
--- a/src/quick/items/qquickframebufferobject.h
+++ b/src/quick/items/qquickframebufferobject.h
@@ -75,7 +75,7 @@ public:
void *data;
};
- QQuickFramebufferObject(QQuickItem *parent = Q_NULLPTR);
+ QQuickFramebufferObject(QQuickItem *parent = nullptr);
bool textureFollowsItemSize() const;
void setTextureFollowsItemSize(bool follows);
@@ -85,15 +85,15 @@ public:
virtual Renderer *createRenderer() const = 0;
- bool isTextureProvider() const Q_DECL_OVERRIDE;
- QSGTextureProvider *textureProvider() const Q_DECL_OVERRIDE;
- void releaseResources() Q_DECL_OVERRIDE;
+ bool isTextureProvider() const override;
+ QSGTextureProvider *textureProvider() const override;
+ void releaseResources() override;
protected:
- void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
protected:
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
Q_SIGNALS:
void textureFollowsItemSizeChanged(bool);
diff --git a/src/quick/items/qquickgenericshadereffect.cpp b/src/quick/items/qquickgenericshadereffect.cpp
index b366071962..248c2b6ec3 100644
--- a/src/quick/items/qquickgenericshadereffect.cpp
+++ b/src/quick/items/qquickgenericshadereffect.cpp
@@ -61,7 +61,7 @@ QQuickGenericShaderEffect::QQuickGenericShaderEffect(QQuickShaderEffect *item, Q
, m_mgr(nullptr)
, m_fragNeedsUpdate(true)
, m_vertNeedsUpdate(true)
- , m_dirty(0)
+ , m_dirty(nullptr)
{
qRegisterMetaType<QSGGuiThreadShaderEffectManager::ShaderInfo::Type>("ShaderInfo::Type");
for (int i = 0; i < NShader; ++i)
@@ -134,7 +134,7 @@ void QQuickGenericShaderEffect::setMesh(const QVariant &mesh)
return;
if (m_mesh)
- disconnect(m_mesh, SIGNAL(geometryChanged()), this, 0);
+ disconnect(m_mesh, SIGNAL(geometryChanged()), this, nullptr);
m_mesh = newMesh;
@@ -290,7 +290,7 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
m_dirty &= ~QSGShaderEffectNode::DirtyShaderGeometry;
}
- m_dirty = 0;
+ m_dirty = nullptr;
for (int i = 0; i < NShader; ++i) {
m_dirtyConstants[i].clear();
m_dirtyTextures[i].clear();
@@ -546,7 +546,10 @@ void QQuickGenericShaderEffect::updateShaderVars(Shader shaderType)
// Have a QSignalMapper 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));
}
sm.active = true;
diff --git a/src/quick/items/qquickgenericshadereffect_p.h b/src/quick/items/qquickgenericshadereffect_p.h
index ab19816493..3f6f92921b 100644
--- a/src/quick/items/qquickgenericshadereffect_p.h
+++ b/src/quick/items/qquickgenericshadereffect_p.h
@@ -66,7 +66,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickGenericShaderEffect : public QObject
Q_OBJECT
public:
- QQuickGenericShaderEffect(QQuickShaderEffect *item, QObject *parent = 0);
+ QQuickGenericShaderEffect(QQuickShaderEffect *item, QObject *parent = nullptr);
~QQuickGenericShaderEffect();
QByteArray fragmentShader() const { return m_fragShader; }
diff --git a/src/quick/items/qquickgraphicsinfo.cpp b/src/quick/items/qquickgraphicsinfo.cpp
index a36133874b..cd1012c690 100644
--- a/src/quick/items/qquickgraphicsinfo.cpp
+++ b/src/quick/items/qquickgraphicsinfo.cpp
@@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE
\ingroup qtquick-visual
\since 5.8
\since QtQuick 2.8
- \brief Provides information about the used Qt Quick backend
+ \brief Provides information about the used Qt Quick backend.
The GraphicsInfo attached type provides information about the scenegraph
backend used to render the contents of the associated window.
@@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE
QQuickGraphicsInfo::QQuickGraphicsInfo(QQuickItem *item)
: QObject(item)
- , m_window(0)
+ , m_window(nullptr)
, m_api(Unknown)
, m_shaderType(UnknownShadingLanguage)
, m_shaderCompilationType(ShaderCompilationType(0))
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index fd78c46a16..6638fbd3e8 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -230,7 +230,7 @@ public:
: flow(QQuickGridView::FlowLeftToRight)
, cellWidth(100), cellHeight(100), columns(1)
, snapMode(QQuickGridView::NoSnap)
- , highlightXAnimator(0), highlightYAnimator(0)
+ , highlightXAnimator(nullptr), highlightYAnimator(nullptr)
{}
~QQuickGridViewPrivate()
{
@@ -390,7 +390,7 @@ FxViewItem *QQuickGridViewPrivate::snapItemAt(qreal pos) const
if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
return item;
}
- return 0;
+ return nullptr;
}
int QQuickGridViewPrivate::snapIndex() const
@@ -417,11 +417,11 @@ qreal QQuickGridViewPrivate::contentXForPosition(qreal pos) const
if (flow == QQuickGridView::FlowLeftToRight) {
// vertical scroll
if (q->effectiveLayoutDirection() == Qt::LeftToRight) {
- return 0;
+ return -q->leftMargin();
} else {
qreal colSize = cellWidth;
- int columns = q->width()/colSize;
- return -q->width() + (cellWidth * columns);
+ int columns = (q->width() - q->leftMargin() - q->rightMargin()) / colSize;
+ return -q->width() + q->rightMargin() + (cellWidth * columns);
}
} else {
// horizontal scroll
@@ -444,16 +444,18 @@ qreal QQuickGridViewPrivate::contentYForPosition(qreal pos) const
} else {
// horizontal scroll
if (verticalLayoutDirection == QQuickItemView::TopToBottom)
- return 0;
+ return -q->topMargin();
else
- return -q->height();
+ return -q->height() + q->bottomMargin();
}
}
void QQuickGridViewPrivate::resetColumns()
{
Q_Q(QQuickGridView);
- qreal length = flow == QQuickGridView::FlowLeftToRight ? q->width() : q->height();
+ qreal length = flow == QQuickGridView::FlowLeftToRight
+ ? q->width() - q->leftMargin() - q->rightMargin()
+ : q->height() - q->topMargin() - q->bottomMargin();
columns = qMax(1, qFloor(length / colSize()));
}
@@ -495,9 +497,7 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
// We've jumped more than a page. Estimate which items are now
// visible and fill from there.
int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
- for (FxViewItem *item : qAsConst(visibleItems))
- releaseItem(item);
- visibleItems.clear();
+ releaseVisibleItems();
modelIndex += count;
if (modelIndex >= model->count())
modelIndex = model->count() - 1;
@@ -510,12 +510,14 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
}
int colNum = qFloor((colPos+colSize()/2) / colSize());
- FxGridItemSG *item = 0;
+ FxGridItemSG *item = nullptr;
bool changed = false;
+ QQmlIncubator::IncubationMode incubationMode = doBuffer ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested;
+
while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
qCDebug(lcItemViewDelegateLifecycle) << "refill: append item" << modelIndex << colPos << rowPos;
- if (!(item = static_cast<FxGridItemSG*>(createItem(modelIndex, doBuffer))))
+ if (!(item = static_cast<FxGridItemSG*>(createItem(modelIndex, incubationMode))))
break;
if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
item->setPosition(colPos, rowPos, true);
@@ -537,20 +539,19 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
if (visibleItems.count()) {
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.constFirst());
rowPos = firstItem->rowPos();
- colNum = qFloor((firstItem->colPos()+colSize()/2) / colSize());
- if (--colNum < 0) {
- colNum = columns - 1;
- rowPos -= rowSize();
- }
- } else {
- colNum = qFloor((colPos+colSize()/2) / colSize());
+ colPos = firstItem->colPos();
+ }
+ colNum = qFloor((colPos+colSize()/2) / colSize());
+ if (--colNum < 0) {
+ colNum = columns - 1;
+ rowPos -= rowSize();
}
// Prepend
colPos = colNum * colSize();
while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
qCDebug(lcItemViewDelegateLifecycle) << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
- if (!(item = static_cast<FxGridItemSG*>(createItem(visibleIndex-1, doBuffer))))
+ if (!(item = static_cast<FxGridItemSG*>(createItem(visibleIndex-1, incubationMode))))
break;
--visibleIndex;
if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
@@ -581,7 +582,7 @@ void QQuickGridViewPrivate::removeItem(FxViewItem *item)
bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
{
- FxGridItemSG *item = 0;
+ FxGridItemSG *item = nullptr;
bool changed = false;
while (visibleItems.count() > 1
@@ -701,14 +702,14 @@ void QQuickGridViewPrivate::createHighlight()
bool changed = false;
if (highlight) {
if (trackedItem == highlight)
- trackedItem = 0;
+ trackedItem = nullptr;
delete highlight;
- highlight = 0;
+ highlight = nullptr;
delete highlightXAnimator;
delete highlightYAnimator;
- highlightXAnimator = 0;
- highlightYAnimator = 0;
+ highlightXAnimator = nullptr;
+ highlightYAnimator = nullptr;
changed = true;
}
@@ -746,8 +747,7 @@ void QQuickGridViewPrivate::updateHighlight()
// auto-update highlight
highlightXAnimator->to = currentItem->itemX();
highlightYAnimator->to = currentItem->itemY();
- highlight->item->setWidth(currentItem->item->width());
- highlight->item->setHeight(currentItem->item->height());
+ highlight->item->setSize(currentItem->item->size());
highlightXAnimator->restart();
highlightYAnimator->restart();
@@ -895,7 +895,6 @@ void QQuickGridViewPrivate::initializeCurrentItem()
void QQuickGridViewPrivate::fixupPosition()
{
- moveReason = Other;
if (flow == QQuickGridView::FlowLeftToRight)
fixupY();
else
@@ -917,7 +916,7 @@ void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
if (snapMode == QQuickGridView::SnapOneRow && moveReason == Mouse) {
// if we've been dragged < rowSize()/2 then bias towards the next row
- qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+ qreal dist = data.move.value() - data.pressPos;
qreal bias = 0;
if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < rowSize()/2)
bias = rowSize()/2;
@@ -928,13 +927,13 @@ void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
tempPosition -= bias;
}
FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
- if (strictHighlightRange && currentItem && (!topItem || topItem->index != currentIndex)) {
+ if (strictHighlightRange && currentItem && (!topItem || (topItem->index != currentIndex && fixupMode == Immediate))) {
// StrictlyEnforceRange always keeps an item in range
updateHighlight();
topItem = currentItem;
}
FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
- if (strictHighlightRange && currentItem && (!bottomItem || bottomItem->index != currentIndex)) {
+ if (strictHighlightRange && currentItem && (!bottomItem || (bottomItem->index != currentIndex && fixupMode == Immediate))) {
// StrictlyEnforceRange always keeps an item in range
updateHighlight();
bottomItem = currentItem;
@@ -1016,7 +1015,7 @@ bool QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
if (data.move.value() < minExtent) {
if (snapMode == QQuickGridView::SnapOneRow) {
// if we've been dragged < averageSize/2 then bias towards the next item
- qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+ qreal dist = data.move.value() - data.pressPos;
qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0;
if (isContentFlowReversed())
bias = -bias;
@@ -1033,7 +1032,7 @@ bool QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
if (data.move.value() > maxExtent) {
if (snapMode == QQuickGridView::SnapOneRow) {
// if we've been dragged < averageSize/2 then bias towards the next item
- qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+ qreal dist = data.move.value() - data.pressPos;
qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0;
if (isContentFlowReversed())
bias = -bias;
@@ -1117,7 +1116,7 @@ bool QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
\ingroup qtquick-views
\inherits Flickable
- \brief For specifying a grid view of items provided by a model
+ \brief For specifying a grid view of items provided by a model.
A GridView displays data from models created from built-in QML types like ListModel
and XmlListModel, or custom model classes defined in C++ that inherit from
@@ -1312,13 +1311,14 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
/*!
- \qmlproperty model QtQuick::GridView::model
- This property holds the model providing data for the grid.
+ \qmlproperty model QtQuick::GridView::model
+ This property holds the model providing data for the grid.
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 VisualItemModel, or provided by C++ model classes. If a C++ model class is
- used, it must be a subclass of \l QAbstractItemModel or a simple list.
+ in the view. Models can be created directly in QML using \l ListModel,
+ \l XmlListModel, \l DelegateModel, or \l ObjectModel, or provided by C++
+ model classes. If a C++ model class is used, it must be a subclass of
+ \l QAbstractItemModel or a simple list.
\sa {qml-data-models}{Data Models}
*/
@@ -2413,11 +2413,11 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
} else {
while (i >= 0) {
// item is before first visible e.g. in cache buffer
- FxViewItem *item = 0;
+ FxViewItem *item = nullptr;
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
item->index = modelIndex + i;
if (!item)
- item = createItem(modelIndex + i);
+ item = createItem(modelIndex + i, QQmlIncubator::Synchronous);
if (!item)
return false;
@@ -2465,12 +2465,12 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
int i = 0;
int to = buffer+displayMarginEnd+tempPos+size()-1;
while (i < count && rowPos <= to + rowSize()*(columns - colNum)/qreal(columns+1)) {
- FxViewItem *item = 0;
+ FxViewItem *item = nullptr;
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
item->index = modelIndex + i;
bool newItem = !item;
if (!item)
- item = createItem(modelIndex + i);
+ item = createItem(modelIndex + i, QQmlIncubator::Synchronous);
if (!item)
return false;
@@ -2636,6 +2636,19 @@ bool QQuickGridViewPrivate::needsRefillForAddedOrRemovedIndex(int modelIndex) co
\b Note: methods should only be called after the Component has completed.
*/
+/*!
+ \qmlmethod Item QtQuick::GridView::itemAtIndex(int index)
+
+ Returns the item for \a index. If there is no item for that index, for example
+ because it has not been created yet, or because it has been panned out of
+ the visible area and removed from the cache, null is returned.
+
+ \b Note: this method should only be called after the Component has completed.
+ The returned value should also not be stored since it can turn to null
+ as soon as control goes out of the calling scope, if the view releases that item.
+
+ \since 5.13
+*/
/*!
\qmlmethod QtQuick::GridView::forceLayout()
diff --git a/src/quick/items/qquickgridview_p.h b/src/quick/items/qquickgridview_p.h
index 5c6da2b433..7daeaf41a1 100644
--- a/src/quick/items/qquickgridview_p.h
+++ b/src/quick/items/qquickgridview_p.h
@@ -81,7 +81,7 @@ public:
};
Q_ENUM(Flow)
- QQuickGridView(QQuickItem *parent=0);
+ QQuickGridView(QQuickItem *parent=nullptr);
~QQuickGridView();
void setHighlightFollowsCurrentItem(bool) override;
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 7e13e5e0e1..4a0936b4d5 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -52,42 +52,28 @@
QT_BEGIN_NAMESPACE
-class QQuickImageTextureProvider : public QSGTextureProvider
+QQuickImageTextureProvider::QQuickImageTextureProvider()
+ : m_texture(nullptr)
+ , m_smooth(false)
{
- Q_OBJECT
-public:
- QQuickImageTextureProvider()
- : m_texture(0)
- , m_smooth(false)
- {
- }
+}
- void updateTexture(QSGTexture *texture) {
- if (m_texture == texture)
- return;
- m_texture = texture;
- emit textureChanged();
- }
+void QQuickImageTextureProvider::updateTexture(QSGTexture *texture) {
+ if (m_texture == texture)
+ return;
+ m_texture = texture;
+ emit textureChanged();
+}
- QSGTexture *texture() const override {
- if (m_texture) {
- m_texture->setFiltering(m_smooth ? QSGTexture::Linear : QSGTexture::Nearest);
- m_texture->setMipmapFiltering(m_mipmap ? QSGTexture::Linear : QSGTexture::None);
- m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
- m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge);
- }
- return m_texture;
+QSGTexture *QQuickImageTextureProvider::texture() const {
+ if (m_texture) {
+ m_texture->setFiltering(m_smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+ m_texture->setMipmapFiltering(m_mipmap ? QSGTexture::Linear : QSGTexture::None);
+ m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge);
}
-
- friend class QQuickImage;
-
- QSGTexture *m_texture;
- bool m_smooth;
- bool m_mipmap;
-};
-
-#include "qquickimage.moc"
-#include "moc_qquickimage_p.cpp"
+ return m_texture;
+}
QQuickImagePrivate::QQuickImagePrivate()
: fillMode(QQuickImage::Stretch)
@@ -97,7 +83,7 @@ QQuickImagePrivate::QQuickImagePrivate()
, mipmap(false)
, hAlign(QQuickImage::AlignHCenter)
, vAlign(QQuickImage::AlignVCenter)
- , provider(0)
+ , provider(nullptr)
{
}
@@ -107,7 +93,7 @@ QQuickImagePrivate::QQuickImagePrivate()
\inqmlmodule QtQuick
\ingroup qtquick-visual
\inherits Item
- \brief Displays an image
+ \brief Displays an image.
The Image type displays an image.
@@ -135,6 +121,49 @@ QQuickImagePrivate::QQuickImagePrivate()
\clearfloat
+ \section1 OpenGL Texture Files
+
+ When the default OpenGL \l{Qt Quick Scene Graph}{scene graph} backend is in
+ use, images can also be supplied in compressed texture files. The content
+ must be a simple RGB(A) format 2D texture. Supported compression schemes
+ are only limited by the underlying OpenGL driver and GPU. The following
+ container file formats are supported:
+
+ \list
+ \li \c PKM (since Qt 5.10)
+ \li \c KTX (since Qt 5.11)
+ \li \c ASTC (since Qt 5.13)
+ \endlist
+
+ \note Semi-transparent original images require alpha pre-multiplication
+ prior to texture compression in order to be correctly displayed in Qt
+ Quick. This can be done with the following ImageMagick command
+ line:
+ \badcode
+ convert foo.png \( +clone -alpha Extract \) -channel RGB -compose Multiply -composite foo_pm.png
+ \endcode
+
+ \section1 Automatic Detection of File Extension
+
+ If the \l source URL indicates a non-existing local file or resource, the
+ Image element attempts to auto-detect the file extension. If an existing
+ file can be found by appending any of the supported image file extensions
+ to the \l source URL, then that file will be loaded.
+
+ If the OpenGL \l{Qt Quick Scene Graph}{scene graph} backend is in use, the
+ file search the attempts the OpenGL texture file extensions first. If the
+ search is unsuccessful, it attempts to search with the file extensions for
+ the \l{QImageReader::supportedImageFormats()}{conventional image file
+ types}. For example:
+
+ \snippet qml/image-ext.qml ext
+
+ This functionality facilitates deploying different image asset file types
+ on different target platforms. This can be useful in order to tune
+ application performance and adapt to different graphics hardware.
+
+ This functionality was introduced in Qt 5.11.
+
\section1 Performance
By default, locally available images are loaded immediately, and the user interface
@@ -154,7 +183,7 @@ QQuickImagePrivate::QQuickImagePrivate()
size bounded via the \l sourceSize property. This is especially important for content
that is loaded from external sources or provided by the user.
- \sa {Qt Quick Examples - Image Elements}, QQuickImageProvider
+ \sa {Qt Quick Examples - Image Elements}, QQuickImageProvider, QImageReader::setAutoDetectImageFormat()
*/
QQuickImage::QQuickImage(QQuickItem *parent)
@@ -461,7 +490,7 @@ qreal QQuickImage::paintedHeight() const
The URL may be absolute, or relative to the URL of the component.
- \sa QQuickImageProvider
+ \sa QQuickImageProvider {OpenGL Texture Files} {Automatic Detection of File Extension}
*/
/*!
@@ -583,7 +612,7 @@ QSGTextureProvider *QQuickImage::textureProvider() const
if (!d->window || !d->sceneGraphRenderContext() || QThread::currentThread() != d->sceneGraphRenderContext()->thread()) {
qWarning("QQuickImage::textureProvider: can only be queried on the rendering thread of an exposed window");
- return 0;
+ return nullptr;
}
if (!d->provider) {
@@ -601,7 +630,7 @@ void QQuickImage::invalidateSceneGraph()
{
Q_D(QQuickImage);
delete d->provider;
- d->provider = 0;
+ d->provider = nullptr;
}
void QQuickImage::releaseResources()
@@ -609,7 +638,7 @@ void QQuickImage::releaseResources()
Q_D(QQuickImage);
if (d->provider) {
QQuickWindowQObjectCleanupJob::schedule(window(), d->provider);
- d->provider = 0;
+ d->provider = nullptr;
}
}
@@ -628,7 +657,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
if (!texture || width() <= 0 || height() <= 0) {
delete oldNode;
- return 0;
+ return nullptr;
}
QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
@@ -736,7 +765,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
|| nsrect.isEmpty()
|| !qt_is_finite(nsrect.width()) || !qt_is_finite(nsrect.height())) {
delete node;
- return 0;
+ return nullptr;
}
if (d->pixmapChanged) {
diff --git a/src/quick/items/qquickimage_p.h b/src/quick/items/qquickimage_p.h
index a5331266c9..7fb4413900 100644
--- a/src/quick/items/qquickimage_p.h
+++ b/src/quick/items/qquickimage_p.h
@@ -70,7 +70,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImage : public QQuickImageBase
Q_PROPERTY(bool autoTransform READ autoTransform WRITE setAutoTransform NOTIFY autoTransformChanged REVISION 2)
public:
- QQuickImage(QQuickItem *parent=0);
+ QQuickImage(QQuickItem *parent=nullptr);
~QQuickImage();
enum HAlignment { AlignLeft = Qt::AlignLeft,
@@ -91,7 +91,7 @@ public:
qreal paintedWidth() const;
qreal paintedHeight() const;
- QRectF boundingRect() const Q_DECL_OVERRIDE;
+ QRectF boundingRect() const override;
HAlignment horizontalAlignment() const;
void setHorizontalAlignment(HAlignment align);
@@ -99,13 +99,13 @@ public:
VAlignment verticalAlignment() const;
void setVerticalAlignment(VAlignment align);
- bool isTextureProvider() const Q_DECL_OVERRIDE { return true; }
- QSGTextureProvider *textureProvider() const Q_DECL_OVERRIDE;
+ bool isTextureProvider() const override { return true; }
+ QSGTextureProvider *textureProvider() const override;
bool mipmap() const;
void setMipmap(bool use);
- virtual void emitAutoTransformBaseChanged() Q_DECL_OVERRIDE { emit autoTransformChanged(); }
+ void emitAutoTransformBaseChanged() override { emit autoTransformChanged(); }
Q_SIGNALS:
void fillModeChanged();
@@ -120,12 +120,12 @@ private Q_SLOTS:
protected:
QQuickImage(QQuickImagePrivate &dd, QQuickItem *parent);
- void pixmapChange() Q_DECL_OVERRIDE;
+ void pixmapChange() override;
void updatePaintedGeometry();
- void releaseResources() Q_DECL_OVERRIDE;
+ void releaseResources() override;
- void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
private:
Q_DISABLE_COPY(QQuickImage)
diff --git a/src/quick/items/qquickimage_p_p.h b/src/quick/items/qquickimage_p_p.h
index afc33def0f..e2c467c311 100644
--- a/src/quick/items/qquickimage_p_p.h
+++ b/src/quick/items/qquickimage_p_p.h
@@ -53,10 +53,26 @@
#include "qquickimagebase_p_p.h"
#include "qquickimage_p.h"
+#include <QtQuick/qsgtextureprovider.h>
QT_BEGIN_NAMESPACE
-class QQuickImageTextureProvider;
+class Q_QUICK_PRIVATE_EXPORT QQuickImageTextureProvider : public QSGTextureProvider
+{
+ Q_OBJECT
+public:
+ QQuickImageTextureProvider();
+
+ void updateTexture(QSGTexture *texture);
+
+ QSGTexture *texture() const override ;
+
+ friend class QQuickImage;
+
+ QSGTexture *m_texture;
+ bool m_smooth;
+ bool m_mipmap;
+};
class Q_QUICK_PRIVATE_EXPORT QQuickImagePrivate : public QQuickImageBasePrivate
{
diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h
index 54b1f789c9..d8d0be9b8c 100644
--- a/src/quick/items/qquickimagebase_p.h
+++ b/src/quick/items/qquickimagebase_p.h
@@ -70,7 +70,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImageBase : public QQuickImplicitSizeItem
Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged)
public:
- QQuickImageBase(QQuickItem *parent=0);
+ QQuickImageBase(QQuickItem *parent=nullptr);
~QQuickImageBase();
enum Status { Null, Ready, Loading, Error };
Q_ENUM(Status)
@@ -98,7 +98,7 @@ public:
virtual void setAutoTransform(bool transform);
bool autoTransform() const;
- void resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio);
+ static void resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio);
// Use a virtual rather than a signal->signal to avoid the huge
// connect/conneciton overhead for this rare case.
@@ -115,9 +115,9 @@ Q_SIGNALS:
protected:
virtual void load();
- void componentComplete() Q_DECL_OVERRIDE;
+ void componentComplete() override;
virtual void pixmapChange();
- void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE;
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
QQuickImageBase(QQuickImageBasePrivate &dd, QQuickItem *parent);
private Q_SLOTS:
diff --git a/src/quick/items/qquickimplicitsizeitem.cpp b/src/quick/items/qquickimplicitsizeitem.cpp
index 1996fb9489..2569b2a224 100644
--- a/src/quick/items/qquickimplicitsizeitem.cpp
+++ b/src/quick/items/qquickimplicitsizeitem.cpp
@@ -45,29 +45,11 @@ QT_BEGIN_NAMESPACE
/*!
\internal
- The purpose of QQuickImplicitSizeItem is not immediately clear, as both
- the implicit size properties and signals exist on QQuickItem. However,
- for some items - where the implicit size has an underlying meaning (such as
- Image, where the implicit size represents the real size of the image)
- having implicit size writable is an undesirable thing.
-
- QQuickImplicitSizeItem redefines the properties as being readonly.
- Unfortunately, this also means they need to redefine the change signals.
- See QTBUG-30258 for more information.
+ QQuickImplicitSizeItem redefines the implicitWidth and implicitHeight
+ properties as readonly, as some items (e.g. Image, where the implicit size
+ represents the real size of the image) should not be able to have their
+ implicit size modified.
*/
-void QQuickImplicitSizeItemPrivate::implicitWidthChanged()
-{
- Q_Q(QQuickImplicitSizeItem);
- QQuickItemPrivate::implicitWidthChanged();
- emit q->implicitWidthChanged2();
-}
-
-void QQuickImplicitSizeItemPrivate::implicitHeightChanged()
-{
- Q_Q(QQuickImplicitSizeItem);
- QQuickItemPrivate::implicitHeightChanged();
- emit q->implicitHeightChanged2();
-}
QQuickImplicitSizeItem::QQuickImplicitSizeItem(QQuickImplicitSizeItemPrivate &dd, QQuickItem *parent)
: QQuickItem(dd, parent)
diff --git a/src/quick/items/qquickimplicitsizeitem_p.h b/src/quick/items/qquickimplicitsizeitem_p.h
index 75b04449f8..8ae8f9f447 100644
--- a/src/quick/items/qquickimplicitsizeitem_p.h
+++ b/src/quick/items/qquickimplicitsizeitem_p.h
@@ -60,16 +60,12 @@ class QQuickImplicitSizeItemPrivate;
class Q_QUICK_PRIVATE_EXPORT QQuickImplicitSizeItem : public QQuickItem
{
Q_OBJECT
- Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged2)
- Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged2)
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged)
protected:
QQuickImplicitSizeItem(QQuickImplicitSizeItemPrivate &dd, QQuickItem *parent);
-Q_SIGNALS:
- Q_REVISION(1) void implicitWidthChanged2();
- Q_REVISION(1) void implicitHeightChanged2();
-
private:
Q_DISABLE_COPY(QQuickImplicitSizeItem)
Q_DECLARE_PRIVATE(QQuickImplicitSizeItem)
diff --git a/src/quick/items/qquickimplicitsizeitem_p_p.h b/src/quick/items/qquickimplicitsizeitem_p_p.h
index 2c42fa62f2..0495cf87e1 100644
--- a/src/quick/items/qquickimplicitsizeitem_p_p.h
+++ b/src/quick/items/qquickimplicitsizeitem_p_p.h
@@ -65,9 +65,6 @@ public:
QQuickImplicitSizeItemPrivate()
{
}
-
- void implicitWidthChanged() Q_DECL_OVERRIDE;
- void implicitHeightChanged() Q_DECL_OVERRIDE;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index a8a862bb2f..ec6bf5a1b8 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -67,6 +67,8 @@
#include <QtQuick/private/qquickstate_p.h>
#include <private/qquickitem_p.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
+#include <QtQuick/private/qquickhoverhandler_p.h>
+#include <QtQuick/private/qquickpointerhandler_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4object_p.h>
@@ -86,8 +88,10 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(DBG_MOUSE_TARGET)
Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
+Q_DECLARE_LOGGING_CATEGORY(lcTransient)
+Q_LOGGING_CATEGORY(lcHandlerParent, "qt.quick.handler.parent")
-void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
+void debugFocusTree(QQuickItem *item, QQuickItem *scope = nullptr, int depth = 1)
{
if (DBG_FOCUS().isEnabled(QtDebugMsg)) {
qCDebug(DBG_FOCUS)
@@ -112,7 +116,7 @@ void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
\instantiates QQuickTransform
\inqmlmodule QtQuick
\ingroup qtquick-visual-transforms
- \brief For specifying advanced transformations on Items
+ \brief For specifying advanced transformations on Items.
The Transform type is a base type which cannot be instantiated directly.
The following concrete Transform types are available:
@@ -121,6 +125,7 @@ void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
\li \l Rotation
\li \l Scale
\li \l Translate
+ \li \l Matrix4x4
\endlist
The Transform types let you create and control advanced transformations that can be configured
@@ -300,9 +305,9 @@ void QQuickContents::itemChildAdded(QQuickItem *, QQuickItem *item)
}
QQuickItemKeyFilter::QQuickItemKeyFilter(QQuickItem *item)
-: m_processPost(false), m_next(0)
+: m_processPost(false), m_next(nullptr)
{
- QQuickItemPrivate *p = item?QQuickItemPrivate::get(item):0;
+ QQuickItemPrivate *p = item?QQuickItemPrivate::get(item):nullptr;
if (p) {
m_next = p->extra.value().keyHandler;
p->extra->keyHandler = this;
@@ -353,8 +358,8 @@ void QQuickItemKeyFilter::componentComplete()
\qmltype KeyNavigation
\instantiates QQuickKeyNavigationAttached
\inqmlmodule QtQuick
- \ingroup qtquick-input
- \brief Supports key navigation by arrow keys
+ \ingroup qtquick-input-handlers
+ \brief Supports key navigation by arrow keys.
Key-based user interfaces commonly allow the use of arrow keys to navigate between
focusable items. The KeyNavigation attached property enables this behavior by providing a
@@ -783,7 +788,7 @@ const SigMap sigMap[] = {
{ Qt::Key_Menu, "menuPressed" },
{ Qt::Key_VolumeUp, "volumeUpPressed" },
{ Qt::Key_VolumeDown, "volumeDownPressed" },
- { 0, 0 }
+ { 0, nullptr }
};
QByteArray QQuickKeysAttached::keyToSignal(int key)
@@ -812,8 +817,8 @@ bool QQuickKeysAttached::isConnected(const char *signalName) const
\qmltype Keys
\instantiates QQuickKeysAttached
\inqmlmodule QtQuick
- \ingroup qtquick-input
- \brief Provides key handling to Items
+ \ingroup qtquick-input-handlers
+ \brief Provides key handling to Items.
All visual primitives support key handling via the Keys
attached property. Keys can be handled via the onPressed
@@ -968,7 +973,7 @@ bool QQuickKeysAttached::isConnected(const char *signalName) const
Keys.onEscapePressed: {
console.log("escapeItem is handling escape");
- event.accepted = true;
+ // event.accepted is set to true by default for the specific key handlers
}
}
@@ -1504,7 +1509,7 @@ QQuickKeysAttached *QQuickKeysAttached::qmlAttachedProperties(QObject *obj)
\inqmlmodule QtQuick
\ingroup qtquick-positioners
\ingroup qml-utility-elements
- \brief Property used to mirror layout behavior
+ \brief Property used to mirror layout behavior.
The LayoutMirroring attached property is used to horizontally mirror \l {anchor-layout}{Item anchors},
\l{Item Positioners}{positioner} types (such as \l Row and \l Grid)
@@ -1541,6 +1546,13 @@ QQuickKeysAttached *QQuickKeysAttached::qmlAttachedProperties(QObject *obj)
mirroring is not the desired behavior, or if the child item already implements mirroring in
some custom way.
+ To set the layout direction based on the \l {Default Layout Direction}{default layout direction}
+ of the application, use the following code:
+
+ \code
+ LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
+ \endcode
+
See \l {Right-to-left User Interfaces} for further details on using \c LayoutMirroring and
other related features to implement right-to-left support for an application.
*/
@@ -1567,7 +1579,7 @@ QQuickKeysAttached *QQuickKeysAttached::qmlAttachedProperties(QObject *obj)
*/
-QQuickLayoutMirroringAttached::QQuickLayoutMirroringAttached(QObject *parent) : QObject(parent), itemPrivate(0)
+QQuickLayoutMirroringAttached::QQuickLayoutMirroringAttached(QObject *parent) : QObject(parent), itemPrivate(nullptr)
{
if (QQuickItem *item = qobject_cast<QQuickItem *>(parent))
itemPrivate = QQuickItemPrivate::get(item);
@@ -1721,7 +1733,7 @@ void QQuickItemPrivate::setLayoutMirror(bool mirror)
*/
QQuickEnterKeyAttached::QQuickEnterKeyAttached(QObject *parent)
- : QObject(parent), itemPrivate(0), keyType(Qt::EnterKeyDefault)
+ : QObject(parent), itemPrivate(nullptr), keyType(Qt::EnterKeyDefault)
{
if (QQuickItem *item = qobject_cast<QQuickItem*>(parent)) {
itemPrivate = QQuickItemPrivate::get(item);
@@ -1774,7 +1786,7 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
if (oldSubFocusItem) {
QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
while (sfi && sfi != scope) {
- QQuickItemPrivate::get(sfi)->subFocusItem = 0;
+ QQuickItemPrivate::get(sfi)->subFocusItem = nullptr;
sfi = sfi->parentItem();
}
}
@@ -1787,7 +1799,7 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
sfi = sfi->parentItem();
}
} else {
- scopePrivate->subFocusItem = 0;
+ scopePrivate->subFocusItem = nullptr;
}
}
@@ -1806,10 +1818,10 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
\section1 Custom Scene Graph Items
- All visual QML items are rendered using the scene graph, a
- low-level, high-performance rendering stack, closely tied to
- OpenGL. It is possible for subclasses of QQuickItem to add their
- own custom content into the scene graph by setting the
+ All visual QML items are rendered using the scene graph, the default
+ implementation of which is a low-level, high-performance rendering stack,
+ closely tied to OpenGL. It is possible for subclasses of QQuickItem to add
+ their own custom content into the scene graph by setting the
QQuickItem::ItemHasContents flag and reimplementing the
QQuickItem::updatePaintNode() function.
@@ -1914,7 +1926,7 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
\inherits QtObject
\inqmlmodule QtQuick
\ingroup qtquick-visual
- \brief A basic visual QML type
+ \brief A basic visual QML type.
The Item type is the base type for all visual items in Qt Quick.
@@ -2065,7 +2077,7 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
In the QPainter / QWidget world, it is some times favorable to
cache complex content in a pixmap, image or texture. In Qt Quick,
because of the techniques already applied by the \l {Qt Quick
- Scene Graph Renderer} {scene graph renderer}, this will in most
+ Scene Graph OpenGL Renderer} {scene graph renderer}, this will in most
cases not be the case. Excessive draw calls are already reduced
because of batching and a cache will in most cases end up blending
more pixels than the original content. The overhead of rendering
@@ -2138,6 +2150,9 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
\value ItemAntialiasingHasChanged The antialiasing has changed. The current
(boolean) value can be found in QQuickItem::antialiasing.
+
+ \value ItemEnabledHasChanged The item's enabled state has changed.
+ ItemChangeData::boolValue contains the new enabled state. (since Qt 5.10)
*/
/*!
@@ -2342,6 +2357,9 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
\fn QQuickItem::QQuickItem(QQuickItem *parent)
Constructs a QQuickItem with the given \a parent.
+
+ The \c parent will be used as both the \l {setParentItem()}{visual parent}
+ and the \l QObject parent.
*/
QQuickItem::QQuickItem(QQuickItem* parent)
: QObject(*(new QQuickItemPrivate), parent)
@@ -2369,13 +2387,13 @@ QQuickItem::~QQuickItem()
if (d->windowRefCount > 1)
d->windowRefCount = 1; // Make sure window is set to null in next call to derefWindow().
if (d->parentItem)
- setParentItem(0);
+ setParentItem(nullptr);
else if (d->window)
d->derefWindow();
// XXX todo - optimize
while (!d->childItems.isEmpty())
- d->childItems.constFirst()->setParentItem(0);
+ d->childItems.constFirst()->setParentItem(nullptr);
if (!d->changeListeners.isEmpty()) {
const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
@@ -2415,14 +2433,14 @@ QQuickItem::~QQuickItem()
}
if (d->extra.isAllocated()) {
- delete d->extra->contents; d->extra->contents = 0;
+ delete d->extra->contents; d->extra->contents = nullptr;
#if QT_CONFIG(quick_shadereffect)
- delete d->extra->layer; d->extra->layer = 0;
+ delete d->extra->layer; d->extra->layer = nullptr;
#endif
}
- delete d->_anchors; d->_anchors = 0;
- delete d->_stateGroup; d->_stateGroup = 0;
+ delete d->_anchors; d->_anchors = nullptr;
+ delete d->_stateGroup; d->_stateGroup = nullptr;
}
/*!
@@ -2437,20 +2455,19 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
return true;
#if QT_CONFIG(accessibility)
- if (QObject *acc = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(item, false)) {
- int role = acc->property("role").toInt();
- if (role == QAccessible::EditableText
- || role == QAccessible::Table
- || role == QAccessible::List
- || role == QAccessible::SpinBox) {
- return true;
- } else if (role == QAccessible::ComboBox) {
- QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(item);
+ QAccessible::Role role = QQuickItemPrivate::get(item)->accessibleRole();
+ if (role == QAccessible::EditableText || role == QAccessible::Table || role == QAccessible::List) {
+ return true;
+ } else if (role == QAccessible::ComboBox || role == QAccessible::SpinBox) {
+ if (QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(item))
return iface->state().editable;
- }
}
#endif
+ QVariant editable = item->property("editable");
+ if (editable.isValid())
+ return editable.toBool();
+
QVariant readonly = item->property("readOnly");
if (readonly.isValid() && !readonly.toBool() && item->property("text").isValid())
return true;
@@ -2484,13 +2501,13 @@ QQuickItem *QQuickItemPrivate::nextTabChildItem(const QQuickItem *item, int star
{
if (!item) {
qWarning() << "QQuickItemPrivate::nextTabChildItem called with null item.";
- return Q_NULLPTR;
+ return nullptr;
}
const QList<QQuickItem *> &children = item->childItems();
const int count = children.count();
if (start < 0 || start >= count) {
qWarning() << "QQuickItemPrivate::nextTabChildItem: Start index value out of range for item" << item;
- return Q_NULLPTR;
+ return nullptr;
}
while (start < count) {
QQuickItem *child = children.at(start);
@@ -2498,14 +2515,14 @@ QQuickItem *QQuickItemPrivate::nextTabChildItem(const QQuickItem *item, int star
return child;
++start;
}
- return Q_NULLPTR;
+ return nullptr;
}
QQuickItem *QQuickItemPrivate::prevTabChildItem(const QQuickItem *item, int start)
{
if (!item) {
qWarning() << "QQuickItemPrivate::prevTabChildItem called with null item.";
- return Q_NULLPTR;
+ return nullptr;
}
const QList<QQuickItem *> &children = item->childItems();
const int count = children.count();
@@ -2513,7 +2530,7 @@ QQuickItem *QQuickItemPrivate::prevTabChildItem(const QQuickItem *item, int star
start = count - 1;
if (start < 0 || start >= count) {
qWarning() << "QQuickItemPrivate::prevTabChildItem: Start index value out of range for item" << item;
- return Q_NULLPTR;
+ return nullptr;
}
while (start >= 0) {
QQuickItem *child = children.at(start);
@@ -2521,7 +2538,7 @@ QQuickItem *QQuickItemPrivate::prevTabChildItem(const QQuickItem *item, int star
return child;
--start;
}
- return Q_NULLPTR;
+ return nullptr;
}
QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, bool forward)
@@ -2537,7 +2554,7 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
bool all = QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls;
- QQuickItem *from = 0;
+ QQuickItem *from = nullptr;
bool isTabFence = item->d_func()->isTabFence;
if (forward) {
if (!isTabFence)
@@ -2549,8 +2566,19 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
from = item->parentItem();
}
bool skip = false;
- QQuickItem * startItem = item;
- QQuickItem * firstFromItem = from;
+
+ QQuickItem *startItem = item;
+ // Protect from endless loop:
+ // If we start on an invisible item we will not find it again.
+ // If there is no other item which can become the focus item, we have a forever loop,
+ // since the protection only works if we encounter the first item again.
+ while (startItem && !startItem->isVisible()) {
+ startItem = startItem->parentItem();
+ }
+ if (!startItem)
+ return item;
+
+ QQuickItem *firstFromItem = from;
QQuickItem *current = item;
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: startItem:" << startItem;
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: firstFromItem:" << firstFromItem;
@@ -2561,8 +2589,8 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
QQuickItem *last = current;
bool hasChildren = !current->childItems().isEmpty() && current->isEnabled() && current->isVisible();
- QQuickItem *firstChild = Q_NULLPTR;
- QQuickItem *lastChild = Q_NULLPTR;
+ QQuickItem *firstChild = nullptr;
+ QQuickItem *lastChild = nullptr;
if (hasChildren) {
firstChild = nextTabChildItem(current, 0);
if (!firstChild)
@@ -2594,11 +2622,11 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
if (!current->childItems().isEmpty())
skip = true;
// back to the parent
- } else if (QQuickItem *parent = !isTabFence ? current->parentItem() : Q_NULLPTR) {
+ } else if (QQuickItem *parent = !isTabFence ? current->parentItem() : nullptr) {
// we would evaluate the parent twice, thus we skip
if (forward) {
skip = true;
- } else if (QQuickItem *firstSibling = !forward ? nextTabChildItem(parent, 0) : Q_NULLPTR) {
+ } else if (QQuickItem *firstSibling = !forward ? nextTabChildItem(parent, 0) : nullptr) {
if (last != firstSibling
|| (parent->isFocusScope() && parent->activeFocusOnTab() && parent->hasActiveFocus()))
skip = true;
@@ -2672,7 +2700,7 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
if (parentItem) {
QQuickItem *itemAncestor = parentItem;
- while (itemAncestor != 0) {
+ while (itemAncestor != nullptr) {
if (Q_UNLIKELY(itemAncestor == this)) {
qWarning() << "QQuickItem::setParentItem: Parent" << parentItem << "is already part of the subtree of" << this;
return;
@@ -2684,12 +2712,12 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
d->removeFromDirtyList();
QQuickItem *oldParentItem = d->parentItem;
- QQuickItem *scopeFocusedItem = 0;
+ QQuickItem *scopeFocusedItem = nullptr;
if (oldParentItem) {
QQuickItemPrivate *op = QQuickItemPrivate::get(oldParentItem);
- QQuickItem *scopeItem = 0;
+ QQuickItem *scopeItem = nullptr;
if (hasFocus() || op->subFocusItem == this)
scopeFocusedItem = this;
@@ -2719,7 +2747,7 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
QQuickWindowPrivate::get(d->window)->parentlessItems.remove(this);
}
- QQuickWindow *parentWindow = parentItem ? QQuickItemPrivate::get(parentItem)->window : 0;
+ QQuickWindow *parentWindow = parentItem ? QQuickItemPrivate::get(parentItem)->window : nullptr;
if (d->window == parentWindow) {
// Avoid freeing and reallocating resources if the window stays the same.
d->parentItem = parentItem;
@@ -2739,7 +2767,7 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
QQuickWindowPrivate::get(d->window)->parentlessItems.insert(this);
d->setEffectiveVisibleRecur(d->calcEffectiveVisible());
- d->setEffectiveEnableRecur(0, d->calcEffectiveEnable());
+ d->setEffectiveEnableRecur(nullptr, d->calcEffectiveEnable());
if (d->parentItem) {
if (!scopeFocusedItem) {
@@ -2803,7 +2831,8 @@ void QQuickItem::stackBefore(const QQuickItem *sibling)
{
Q_D(QQuickItem);
if (!sibling || sibling == this || !d->parentItem || d->parentItem != QQuickItemPrivate::get(sibling)->parentItem) {
- qWarning("QQuickItem::stackBefore: Cannot stack before %p, which must be a sibling", sibling);
+ qWarning().nospace() << "QQuickItem::stackBefore: Cannot stack "
+ << this << " before " << sibling << ", which must be a sibling";
return;
}
@@ -2847,7 +2876,8 @@ void QQuickItem::stackAfter(const QQuickItem *sibling)
{
Q_D(QQuickItem);
if (!sibling || sibling == this || !d->parentItem || d->parentItem != QQuickItemPrivate::get(sibling)->parentItem) {
- qWarning("QQuickItem::stackAfter: Cannot stack after %p, which must be a sibling", sibling);
+ qWarning().nospace() << "QQuickItem::stackAfter: Cannot stack "
+ << this << " after " << sibling << ", which must be a sibling";
return;
}
@@ -2937,6 +2967,7 @@ void QQuickItemPrivate::addChild(QQuickItem *child)
if (childPrivate->subtreeHoverEnabled && !subtreeHoverEnabled)
setHasHoverInChild(true);
+ childPrivate->recursiveRefFromEffectItem(extra.value().recursiveEffectRefCount);
markSortedChildrenDirty(child);
dirty(QQuickItemPrivate::ChildrenChanged);
@@ -2965,6 +2996,7 @@ void QQuickItemPrivate::removeChild(QQuickItem *child)
if (childPrivate->subtreeHoverEnabled && subtreeHoverEnabled)
setHasHoverInChild(false);
+ childPrivate->recursiveRefFromEffectItem(-extra.value().recursiveEffectRefCount);
markSortedChildrenDirty(child);
dirty(QQuickItemPrivate::ChildrenChanged);
@@ -2985,7 +3017,7 @@ void QQuickItemPrivate::refWindow(QQuickWindow *c)
// derefWindow() decrements the reference count.
Q_Q(QQuickItem);
- Q_ASSERT((window != 0) == (windowRefCount > 0));
+ Q_ASSERT((window != nullptr) == (windowRefCount > 0));
Q_ASSERT(c);
if (++windowRefCount > 1) {
if (c != window)
@@ -2993,7 +3025,7 @@ void QQuickItemPrivate::refWindow(QQuickWindow *c)
return; // Window already set.
}
- Q_ASSERT(window == 0);
+ Q_ASSERT(window == nullptr);
window = c;
if (polishScheduled)
@@ -3017,7 +3049,7 @@ void QQuickItemPrivate::refWindow(QQuickWindow *c)
void QQuickItemPrivate::derefWindow()
{
Q_Q(QQuickItem);
- Q_ASSERT((window != 0) == (windowRefCount > 0));
+ Q_ASSERT((window != nullptr) == (windowRefCount > 0));
if (!window)
return; // This can happen when destroying recursive shader effect sources.
@@ -3033,7 +3065,7 @@ void QQuickItemPrivate::derefWindow()
c->removeGrabber(q);
#if QT_CONFIG(cursor)
if (c->cursorItem == q) {
- c->cursorItem = 0;
+ c->cursorItem = nullptr;
window->unsetCursor();
}
#endif
@@ -3043,17 +3075,17 @@ void QQuickItemPrivate::derefWindow()
if (!parentItem)
c->parentlessItems.remove(q);
- window = 0;
+ window = nullptr;
- itemNodeInstance = 0;
+ itemNodeInstance = nullptr;
if (extra.isAllocated()) {
- extra->opacityNode = 0;
- extra->clipNode = 0;
- extra->rootNode = 0;
+ extra->opacityNode = nullptr;
+ extra->clipNode = nullptr;
+ extra->rootNode = nullptr;
}
- paintNode = 0;
+ paintNode = nullptr;
for (int ii = 0; ii < childItems.count(); ++ii) {
QQuickItem *child = childItems.at(ii);
@@ -3063,8 +3095,8 @@ void QQuickItemPrivate::derefWindow()
dirty(Window);
if (extra.isAllocated() && extra->screenAttached)
- extra->screenAttached->windowChanged(0);
- itemChange(QQuickItem::ItemSceneChange, (QQuickWindow *)0);
+ extra->screenAttached->windowChanged(nullptr);
+ itemChange(QQuickItem::ItemSceneChange, (QQuickWindow *)nullptr);
}
@@ -3117,6 +3149,9 @@ void QQuickItemPrivate::itemToParentTransform(QTransform &t) const
*/
QTransform QQuickItemPrivate::windowToGlobalTransform() const
{
+ if (Q_UNLIKELY(window == nullptr))
+ return QTransform();
+
QPoint quickWidgetOffset;
QWindow *renderWindow = QQuickRenderControl::renderWindowFor(window, &quickWidgetOffset);
QPointF pos = (renderWindow ? renderWindow : window)->mapToGlobal(quickWidgetOffset);
@@ -3128,6 +3163,9 @@ QTransform QQuickItemPrivate::windowToGlobalTransform() const
*/
QTransform QQuickItemPrivate::globalToWindowTransform() const
{
+ if (Q_UNLIKELY(window == nullptr))
+ return QTransform();
+
QPoint quickWidgetOffset;
QWindow *renderWindow = QQuickRenderControl::renderWindowFor(window, &quickWidgetOffset);
QPointF pos = (renderWindow ? renderWindow : window)->mapToGlobal(quickWidgetOffset);
@@ -3150,8 +3188,8 @@ bool QQuickItem::isComponentComplete() const
}
QQuickItemPrivate::QQuickItemPrivate()
- : _anchors(0)
- , _stateGroup(0)
+ : _anchors(nullptr)
+ , _stateGroup(nullptr)
, flags(0)
, widthValid(false)
, heightValid(false)
@@ -3186,14 +3224,19 @@ QQuickItemPrivate::QQuickItemPrivate()
, antialiasingValid(false)
, isTabFence(false)
, replayingPressEvent(false)
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ , touchEnabled(true)
+#else
+ , touchEnabled(false)
+#endif
, dirtyAttributes(0)
- , nextDirtyItem(0)
- , prevDirtyItem(0)
- , window(0)
+ , nextDirtyItem(nullptr)
+ , prevDirtyItem(nullptr)
+ , window(nullptr)
, windowRefCount(0)
- , parentItem(0)
+ , parentItem(nullptr)
, sortedChildItems(&childItems)
- , subFocusItem(0)
+ , subFocusItem(nullptr)
, x(0)
, y(0)
, width(0)
@@ -3201,8 +3244,8 @@ QQuickItemPrivate::QQuickItemPrivate()
, implicitWidth(0)
, implicitHeight(0)
, baselineOffset(0)
- , itemNodeInstance(0)
- , paintNode(0)
+ , itemNodeInstance(nullptr)
+ , paintNode(nullptr)
{
}
@@ -3237,7 +3280,13 @@ void QQuickItemPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
} else {
if (o->inherits("QGraphicsItem"))
qWarning("Cannot add a QtQuick 1.0 item (%s) into a QtQuick 2.0 scene!", o->metaObject()->className());
- else {
+ else if (QQuickPointerHandler *pointerHandler = qmlobject_cast<QQuickPointerHandler *>(o)) {
+ if (pointerHandler->parent() != that) {
+ qCDebug(lcHandlerParent) << "reparenting handler" << pointerHandler << ":" << pointerHandler->parent() << "->" << that;
+ pointerHandler->setParent(that);
+ }
+ QQuickItemPrivate::get(that)->addPointerHandler(pointerHandler);
+ } else {
QQuickWindow *thisWindow = qmlobject_cast<QQuickWindow *>(o);
QQuickItem *item = that;
QQuickWindow *itemWindow = that->window();
@@ -3247,11 +3296,13 @@ void QQuickItemPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
}
if (thisWindow) {
- if (itemWindow)
+ if (itemWindow) {
+ qCDebug(lcTransient) << thisWindow << "is transient for" << itemWindow;
thisWindow->setTransientParent(itemWindow);
- else
+ } else {
QObject::connect(item, SIGNAL(windowChanged(QQuickWindow*)),
thisWindow, SLOT(setTransientParent_helper(QQuickWindow*)));
+ }
}
o->setParent(that);
}
@@ -3318,7 +3369,7 @@ QObject *QQuickItemPrivate::data_at(QQmlListProperty<QObject> *property, int i)
const int j = i - resourcesCount;
if (j < children_count(&childrenProperty))
return children_at(&childrenProperty, j);
- return 0;
+ return nullptr;
}
void QQuickItemPrivate::data_clear(QQmlListProperty<QObject> *property)
@@ -3372,7 +3423,7 @@ QQuickItem *QQuickItemPrivate::children_at(QQmlListProperty<QQuickItem> *prop, i
{
QQuickItemPrivate *p = QQuickItemPrivate::get(static_cast<QQuickItem *>(prop->object));
if (index >= p->childItems.count() || index < 0)
- return 0;
+ return nullptr;
else
return p->childItems.at(index);
}
@@ -3384,7 +3435,7 @@ void QQuickItemPrivate::children_append(QQmlListProperty<QQuickItem> *prop, QQui
QQuickItem *that = static_cast<QQuickItem *>(prop->object);
if (o->parentItem() == that)
- o->setParentItem(0);
+ o->setParentItem(nullptr);
o->setParentItem(that);
}
@@ -3400,7 +3451,7 @@ void QQuickItemPrivate::children_clear(QQmlListProperty<QQuickItem> *prop)
QQuickItem *that = static_cast<QQuickItem *>(prop->object);
QQuickItemPrivate *p = QQuickItemPrivate::get(that);
while (!p->childItems.isEmpty())
- p->childItems.at(0)->setParentItem(0);
+ p->childItems.at(0)->setParentItem(nullptr);
}
int QQuickItemPrivate::visibleChildren_count(QQmlListProperty<QQuickItem> *prop)
@@ -3420,14 +3471,14 @@ QQuickItem *QQuickItemPrivate::visibleChildren_at(QQmlListProperty<QQuickItem> *
QQuickItemPrivate *p = QQuickItemPrivate::get(static_cast<QQuickItem *>(prop->object));
const int childCount = p->childItems.count();
if (index >= childCount || index < 0)
- return 0;
+ return nullptr;
int visibleCount = -1;
for (int i = 0; i < childCount; i++) {
if (p->childItems.at(i)->isVisible()) visibleCount++;
if (visibleCount == index) return p->childItems.at(i);
}
- return 0;
+ return nullptr;
}
int QQuickItemPrivate::transform_count(QQmlListProperty<QQuickTransform> *prop)
@@ -3491,7 +3542,7 @@ QQuickTransform *QQuickItemPrivate::transform_at(QQmlListProperty<QQuickTransfor
QQuickItemPrivate *p = QQuickItemPrivate::get(that);
if (idx < 0 || idx >= p->transforms.count())
- return 0;
+ return nullptr;
else
return p->transforms.at(idx);
}
@@ -3638,7 +3689,7 @@ void QQuickItemPrivate::siblingOrderChanged()
QQmlListProperty<QObject> QQuickItemPrivate::data()
{
- return QQmlListProperty<QObject>(q_func(), 0, QQuickItemPrivate::data_append,
+ return QQmlListProperty<QObject>(q_func(), nullptr, QQuickItemPrivate::data_append,
QQuickItemPrivate::data_count,
QQuickItemPrivate::data_at,
QQuickItemPrivate::data_clear);
@@ -3650,8 +3701,9 @@ QQmlListProperty<QObject> QQuickItemPrivate::data()
\qmlproperty real QtQuick::Item::childrenRect.y
\qmlproperty real QtQuick::Item::childrenRect.width
\qmlproperty real QtQuick::Item::childrenRect.height
+ \readonly
- This property holds the collective position and size of the item's
+ This read-only property holds the collective position and size of the item's
children.
This property is useful if you need to access the collective geometry
@@ -3816,11 +3868,11 @@ QSGNode *QQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *upda
{
Q_UNUSED(updatePaintNodeData)
delete oldNode;
- return 0;
+ return nullptr;
}
QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
-: transformNode(0)
+: transformNode(nullptr)
{
}
@@ -3867,6 +3919,16 @@ void QQuickItemPrivate::addItemChangeListener(QQuickItemChangeListener *listener
changeListeners.append(ChangeListener(listener, types));
}
+void QQuickItemPrivate::updateOrAddItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types)
+{
+ const ChangeListener changeListener(listener, types);
+ const int index = changeListeners.indexOf(changeListener);
+ if (index > -1)
+ changeListeners[index].types = changeListener.types;
+ else
+ changeListeners.append(changeListener);
+}
+
void QQuickItemPrivate::removeItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types)
{
ChangeListener change(listener, types);
@@ -3901,6 +3963,8 @@ void QQuickItemPrivate::updateOrRemoveGeometryChangeListener(QQuickItemChangeLis
This event handler can be reimplemented in a subclass to receive key
press events for an item. The event information is provided by the
\a event parameter.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::keyPressEvent(QKeyEvent *event)
{
@@ -3911,6 +3975,8 @@ void QQuickItem::keyPressEvent(QKeyEvent *event)
This event handler can be reimplemented in a subclass to receive key
release events for an item. The event information is provided by the
\a event parameter.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::keyReleaseEvent(QKeyEvent *event)
{
@@ -3922,6 +3988,8 @@ void QQuickItem::keyReleaseEvent(QKeyEvent *event)
This event handler can be reimplemented in a subclass to receive input
method events for an item. The event information is provided by the
\a event parameter.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::inputMethodEvent(QInputMethodEvent *event)
{
@@ -3931,8 +3999,13 @@ void QQuickItem::inputMethodEvent(QInputMethodEvent *event)
/*!
This event handler can be reimplemented in a subclass to receive focus-in
- events for an item. The event information is provided by the
- \a event parameter.
+ events for an item. The event information is provided by the \c event
+ parameter.
+
+ \input item.qdocinc accepting-events
+
+ If you do reimplement this function, you should call the base class
+ implementation.
*/
void QQuickItem::focusInEvent(QFocusEvent * /*event*/)
{
@@ -3948,8 +4021,10 @@ void QQuickItem::focusInEvent(QFocusEvent * /*event*/)
/*!
This event handler can be reimplemented in a subclass to receive focus-out
- events for an item. The event information is provided by the
- \a event parameter.
+ events for an item. The event information is provided by the \c event
+ parameter.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::focusOutEvent(QFocusEvent * /*event*/)
{
@@ -3959,6 +4034,8 @@ void QQuickItem::focusOutEvent(QFocusEvent * /*event*/)
This event handler can be reimplemented in a subclass to receive mouse
press events for an item. The event information is provided by the
\a event parameter.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::mousePressEvent(QMouseEvent *event)
{
@@ -3969,6 +4046,8 @@ void QQuickItem::mousePressEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse
move events for an item. The event information is provided by the
\a event parameter.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::mouseMoveEvent(QMouseEvent *event)
{
@@ -3979,6 +4058,8 @@ void QQuickItem::mouseMoveEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse
release events for an item. The event information is provided by the
\a event parameter.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::mouseReleaseEvent(QMouseEvent *event)
{
@@ -3989,6 +4070,8 @@ void QQuickItem::mouseReleaseEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse
double-click events for an item. The event information is provided by the
\a event parameter.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::mouseDoubleClickEvent(QMouseEvent *)
{
@@ -3997,8 +4080,6 @@ void QQuickItem::mouseDoubleClickEvent(QMouseEvent *)
/*!
This event handler can be reimplemented in a subclass to be notified
when a mouse ungrab event has occurred on this item.
-
- \sa ungrabMouse()
*/
void QQuickItem::mouseUngrabEvent()
{
@@ -4019,6 +4100,8 @@ void QQuickItem::touchUngrabEvent()
This event handler can be reimplemented in a subclass to receive
wheel events for an item. The event information is provided by the
\a event parameter.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::wheelEvent(QWheelEvent *event)
{
@@ -4030,6 +4113,8 @@ void QQuickItem::wheelEvent(QWheelEvent *event)
This event handler can be reimplemented in a subclass to receive touch
events for an item. The event information is provided by the
\a event parameter.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::touchEvent(QTouchEvent *event)
{
@@ -4042,6 +4127,8 @@ void QQuickItem::touchEvent(QTouchEvent *event)
\a event parameter.
Hover events are only provided if acceptHoverEvents() is true.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::hoverEnterEvent(QHoverEvent *event)
{
@@ -4054,6 +4141,8 @@ void QQuickItem::hoverEnterEvent(QHoverEvent *event)
\a event parameter.
Hover events are only provided if acceptHoverEvents() is true.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::hoverMoveEvent(QHoverEvent *event)
{
@@ -4066,6 +4155,8 @@ void QQuickItem::hoverMoveEvent(QHoverEvent *event)
\a event parameter.
Hover events are only provided if acceptHoverEvents() is true.
+
+ \input item.qdocinc accepting-events
*/
void QQuickItem::hoverLeaveEvent(QHoverEvent *event)
{
@@ -4081,6 +4172,8 @@ void QQuickItem::hoverLeaveEvent(QHoverEvent *event)
Drag and drop events are only provided if the ItemAcceptsDrops flag
has been set for this item.
+ \input item.qdocinc accepting-events
+
\sa Drag, {Drag and Drop}
*/
void QQuickItem::dragEnterEvent(QDragEnterEvent *event)
@@ -4096,6 +4189,8 @@ void QQuickItem::dragEnterEvent(QDragEnterEvent *event)
Drag and drop events are only provided if the ItemAcceptsDrops flag
has been set for this item.
+ \input item.qdocinc accepting-events
+
\sa Drag, {Drag and Drop}
*/
void QQuickItem::dragMoveEvent(QDragMoveEvent *event)
@@ -4111,6 +4206,8 @@ void QQuickItem::dragMoveEvent(QDragMoveEvent *event)
Drag and drop events are only provided if the ItemAcceptsDrops flag
has been set for this item.
+ \input item.qdocinc accepting-events
+
\sa Drag, {Drag and Drop}
*/
void QQuickItem::dragLeaveEvent(QDragLeaveEvent *event)
@@ -4126,6 +4223,8 @@ void QQuickItem::dragLeaveEvent(QDragLeaveEvent *event)
Drag and drop events are only provided if the ItemAcceptsDrops flag
has been set for this item.
+ \input item.qdocinc accepting-events
+
\sa Drag, {Drag and Drop}
*/
void QQuickItem::dropEvent(QDropEvent *event)
@@ -4345,6 +4444,8 @@ void QQuickItem::update()
When the scene graph processes the request, it will call updatePolish()
on this item.
+
+ \sa updatePolish(), QQuickTest::qIsPolishScheduled()
*/
void QQuickItem::polish()
{
@@ -4368,6 +4469,8 @@ void QQuickItem::polish()
item's coordinate system, to this item's coordinate system, and returns a \l point or \l rect
matching the mapped coordinate.
+ \input item.qdocinc mapping
+
If \a item is a \c null value, this maps the point or rect from the coordinate system of
the root QML view.
*/
@@ -4385,7 +4488,7 @@ void QQuickItem::mapFromItem(QQmlV4Function *args) const
QV4::Scope scope(v4);
QV4::ScopedValue item(scope, (*args)[0]);
- QQuickItem *itemObj = 0;
+ QQuickItem *itemObj = nullptr;
if (!item->isNull()) {
QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, item->as<QV4::QObjectWrapper>());
if (qobjectWrapper)
@@ -4456,6 +4559,8 @@ QTransform QQuickItem::itemTransform(QQuickItem *other, bool *ok) const
item's coordinate system, to \a item's coordinate system, and returns a \l point or \l rect
matching the mapped coordinate.
+ \input item.qdocinc mapping
+
If \a item is a \c null value, this maps the point or rect to the coordinate system of the
root QML view.
*/
@@ -4473,7 +4578,7 @@ void QQuickItem::mapToItem(QQmlV4Function *args) const
QV4::Scope scope(v4);
QV4::ScopedValue item(scope, (*args)[0]);
- QQuickItem *itemObj = 0;
+ QQuickItem *itemObj = nullptr;
if (!item->isNull()) {
QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, item->as<QV4::QObjectWrapper>());
if (qobjectWrapper)
@@ -4525,6 +4630,8 @@ void QQuickItem::mapToItem(QQmlV4Function *args) const
Maps the point (\a x, \a y), which is in the global coordinate system, to the
item's coordinate system, and returns a \l point matching the mapped coordinate.
+
+ \input item.qdocinc mapping
*/
/*!
\internal
@@ -4560,6 +4667,8 @@ void QQuickItem::mapFromGlobal(QQmlV4Function *args) const
Maps the point (\a x, \a y), which is in this item's coordinate system, to the
global coordinate system, and returns a \l point matching the mapped coordinate.
+
+ \input item.qdocinc mapping
*/
/*!
\internal
@@ -4691,7 +4800,7 @@ QQuickItem *QQuickItem::nextItemInFocusChain(bool forward)
Returns the first visible child item found at point (\a x, \a y) within
the coordinate system of this item.
- Returns 0 if there is no such item.
+ Returns \nullptr if there is no such item.
*/
QQuickItem *QQuickItem::childAt(qreal x, qreal y) const
{
@@ -4706,12 +4815,12 @@ QQuickItem *QQuickItem::childAt(qreal x, qreal y) const
&& child->height() > point.y())
return child;
}
- return 0;
+ return nullptr;
}
QQmlListProperty<QObject> QQuickItemPrivate::resources()
{
- return QQmlListProperty<QObject>(q_func(), 0, QQuickItemPrivate::resources_append,
+ return QQmlListProperty<QObject>(q_func(), nullptr, QQuickItemPrivate::resources_append,
QQuickItemPrivate::resources_count,
QQuickItemPrivate::resources_at,
QQuickItemPrivate::resources_clear);
@@ -4736,7 +4845,7 @@ QQmlListProperty<QObject> QQuickItemPrivate::resources()
*/
QQmlListProperty<QQuickItem> QQuickItemPrivate::children()
{
- return QQmlListProperty<QQuickItem>(q_func(), 0, QQuickItemPrivate::children_append,
+ return QQmlListProperty<QQuickItem>(q_func(), nullptr, QQuickItemPrivate::children_append,
QQuickItemPrivate::children_count,
QQuickItemPrivate::children_at,
QQuickItemPrivate::children_clear);
@@ -4756,7 +4865,7 @@ QQmlListProperty<QQuickItem> QQuickItemPrivate::children()
QQmlListProperty<QQuickItem> QQuickItemPrivate::visibleChildren()
{
return QQmlListProperty<QQuickItem>(q_func(),
- 0,
+ nullptr,
QQuickItemPrivate::visibleChildren_count,
QQuickItemPrivate::visibleChildren_at);
@@ -4906,7 +5015,7 @@ void QQuickItem::setState(const QString &state)
*/
QQmlListProperty<QQuickTransform> QQuickItem::transform()
{
- return QQmlListProperty<QQuickTransform>(this, 0, QQuickItemPrivate::transform_append,
+ return QQmlListProperty<QQuickTransform>(this, nullptr, QQuickItemPrivate::transform_append,
QQuickItemPrivate::transform_count,
QQuickItemPrivate::transform_at,
QQuickItemPrivate::transform_clear);
@@ -5013,22 +5122,31 @@ void QQuickItemPrivate::transformChanged()
#endif
}
+bool QQuickItemPrivate::filterKeyEvent(QKeyEvent *e, bool post)
+{
+ if (!extra.isAllocated() || !extra->keyHandler)
+ return false;
+
+ if (post)
+ e->accept();
+
+ if (e->type() == QEvent::KeyPress)
+ extra->keyHandler->keyPressed(e, post);
+ else
+ extra->keyHandler->keyReleased(e, post);
+
+ return e->isAccepted();
+}
+
void QQuickItemPrivate::deliverKeyEvent(QKeyEvent *e)
{
Q_Q(QQuickItem);
Q_ASSERT(e->isAccepted());
- if (extra.isAllocated() && extra->keyHandler) {
- if (e->type() == QEvent::KeyPress)
- extra->keyHandler->keyPressed(e, false);
- else
- extra->keyHandler->keyReleased(e, false);
-
- if (e->isAccepted())
- return;
- else
- e->accept();
- }
+ if (filterKeyEvent(e, false))
+ return;
+ else
+ e->accept();
if (e->type() == QEvent::KeyPress)
q->keyPressEvent(e);
@@ -5038,16 +5156,7 @@ void QQuickItemPrivate::deliverKeyEvent(QKeyEvent *e)
if (e->isAccepted())
return;
- if (extra.isAllocated() && extra->keyHandler) {
- e->accept();
-
- if (e->type() == QEvent::KeyPress)
- extra->keyHandler->keyPressed(e, true);
- else
- extra->keyHandler->keyReleased(e, true);
- }
-
- if (e->isAccepted() || !q->window())
+ if (filterKeyEvent(e, true) || !q->window())
return;
//only care about KeyPress now
@@ -5101,6 +5210,39 @@ void QQuickItemPrivate::deliverShortcutOverrideEvent(QKeyEvent *event)
}
}
+bool QQuickItemPrivate::anyPointerHandlerWants(QQuickEventPoint *point) const
+{
+ if (!hasPointerHandlers())
+ return false;
+ for (QQuickPointerHandler *handler : extra->pointerHandlers) {
+ if (handler->wantsEventPoint(point))
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \internal
+ Deliver the \a event to all PointerHandlers which are in the pre-determined
+ eventDeliveryTargets() vector. If \a avoidExclusiveGrabber is true, it skips
+ delivery to any handler which is the exclusive grabber of any point within this event
+ (because delivery to exclusive grabbers is handled separately).
+*/
+bool QQuickItemPrivate::handlePointerEvent(QQuickPointerEvent *event, bool avoidExclusiveGrabber)
+{
+ bool delivered = false;
+ QVector<QQuickPointerHandler *> &eventDeliveryTargets = event->device()->eventDeliveryTargets();
+ if (extra.isAllocated()) {
+ for (QQuickPointerHandler *handler : extra->pointerHandlers) {
+ if ((!avoidExclusiveGrabber || !event->hasExclusiveGrabber(handler)) && !eventDeliveryTargets.contains(handler)) {
+ handler->handlePointerEvent(event);
+ delivered = true;
+ }
+ }
+ }
+ return delivered;
+}
+
/*!
Called when \a change occurs for this item.
@@ -5132,8 +5274,8 @@ void QQuickItem::updateInputMethod(Qt::InputMethodQueries queries)
}
#endif // im
-/*! \internal */
// XXX todo - do we want/need this anymore?
+/*! \internal */
QRectF QQuickItem::boundingRect() const
{
Q_D(const QQuickItem);
@@ -5767,19 +5909,24 @@ bool QQuickItem::isVisible() const
return d->effectiveVisible;
}
-void QQuickItem::setVisible(bool v)
+void QQuickItemPrivate::setVisible(bool visible)
{
- Q_D(QQuickItem);
- if (v == d->explicitVisible)
+ if (visible == explicitVisible)
return;
- d->explicitVisible = v;
- if (!v)
- d->dirty(QQuickItemPrivate::Visible);
+ explicitVisible = visible;
+ if (!visible)
+ dirty(QQuickItemPrivate::Visible);
+
+ const bool childVisibilityChanged = setEffectiveVisibleRecur(calcEffectiveVisible());
+ if (childVisibilityChanged && parentItem)
+ emit parentItem->visibleChildrenChanged(); // signal the parent, not this!
+}
- const bool childVisibilityChanged = d->setEffectiveVisibleRecur(d->calcEffectiveVisible());
- if (childVisibilityChanged && d->parentItem)
- emit d->parentItem->visibleChildrenChanged(); // signal the parent, not this!
+void QQuickItem::setVisible(bool v)
+{
+ Q_D(QQuickItem);
+ d->setVisible(v);
}
/*!
@@ -5794,7 +5941,7 @@ void QQuickItem::setVisible(bool v)
are returned to \c true, unless they have explicitly been set to \c false.
Setting this property to \c false automatically causes \l activeFocus to be
- set to \c false, and this item will longer receive keyboard events.
+ set to \c false, and this item will no longer receive keyboard events.
\sa visible
*/
@@ -5927,6 +6074,7 @@ void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffec
scope, q, Qt::OtherFocusReason, QQuickWindowPrivate::DontChangeFocusProperty | QQuickWindowPrivate::DontChangeSubFocusItem);
}
+ itemChange(QQuickItem::ItemEnabledHasChanged, effectiveEnable);
emit q->enabledChanged();
}
@@ -6012,8 +6160,8 @@ void QQuickItemPrivate::removeFromDirtyList()
if (prevDirtyItem) {
if (nextDirtyItem) QQuickItemPrivate::get(nextDirtyItem)->prevDirtyItem = prevDirtyItem;
*prevDirtyItem = nextDirtyItem;
- prevDirtyItem = 0;
- nextDirtyItem = 0;
+ prevDirtyItem = nullptr;
+ nextDirtyItem = nullptr;
}
Q_ASSERT(!prevDirtyItem);
Q_ASSERT(!nextDirtyItem);
@@ -6022,28 +6170,48 @@ void QQuickItemPrivate::removeFromDirtyList()
void QQuickItemPrivate::refFromEffectItem(bool hide)
{
++extra.value().effectRefCount;
- if (1 == extra->effectRefCount) {
+ if (extra->effectRefCount == 1) {
dirty(EffectReference);
- if (parentItem) QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged);
+ if (parentItem)
+ QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged);
}
if (hide) {
if (++extra->hideRefCount == 1)
dirty(HideReference);
}
+ recursiveRefFromEffectItem(1);
+}
+
+void QQuickItemPrivate::recursiveRefFromEffectItem(int refs)
+{
+ Q_Q(QQuickItem);
+ if (!refs)
+ return;
+ extra.value().recursiveEffectRefCount += refs;
+ for (int ii = 0; ii < childItems.count(); ++ii) {
+ QQuickItem *child = childItems.at(ii);
+ QQuickItemPrivate::get(child)->recursiveRefFromEffectItem(refs);
+ }
+ // Polish may rely on the effect ref count so trigger one, if item is not visible
+ // (if visible, it will be triggered automatically).
+ if (!effectiveVisible && refs > 0 && extra.value().recursiveEffectRefCount == 1) // it wasn't referenced, now it's referenced
+ q->polish();
}
void QQuickItemPrivate::derefFromEffectItem(bool unhide)
{
Q_ASSERT(extra->effectRefCount);
--extra->effectRefCount;
- if (0 == extra->effectRefCount) {
+ if (extra->effectRefCount == 0) {
dirty(EffectReference);
- if (parentItem) QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged);
+ if (parentItem)
+ QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged);
}
if (unhide) {
if (--extra->hideRefCount == 0)
dirty(HideReference);
}
+ recursiveRefFromEffectItem(-1);
}
void QQuickItemPrivate::setCulled(bool cull)
@@ -6099,6 +6267,18 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
}
break;
}
+ case QQuickItem::ItemEnabledHasChanged: {
+ q->itemChange(change, data);
+ if (!changeListeners.isEmpty()) {
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
+ if (change.types & QQuickItemPrivate::Enabled) {
+ change.listener->itemEnabledChanged(q);
+ }
+ }
+ }
+ break;
+ }
case QQuickItem::ItemParentHasChanged: {
q->itemChange(change, data);
if (!changeListeners.isEmpty()) {
@@ -7044,13 +7224,13 @@ bool QQuickItem::isFocusScope() const
If this item is a focus scope, this returns the item in its focus chain
that currently has focus.
- Returns 0 if this item is not a focus scope.
+ Returns \nullptr if this item is not a focus scope.
*/
QQuickItem *QQuickItem::scopedFocusItem() const
{
Q_D(const QQuickItem);
if (!isFocusScope())
- return 0;
+ return nullptr;
else
return d->subFocusItem;
}
@@ -7173,6 +7353,36 @@ void QQuickItem::setAcceptHoverEvents(bool enabled)
d->setHasHoverInChild(enabled);
}
+/*!
+ Returns whether touch events are accepted by this item.
+
+ The default value is false.
+
+ If this is false, then the item will not receive any touch events through
+ the touchEvent() function.
+
+ \since 5.10
+*/
+bool QQuickItem::acceptTouchEvents() const
+{
+ Q_D(const QQuickItem);
+ return d->touchEnabled;
+}
+
+/*!
+ If \a enabled is true, this sets the item to accept touch events;
+ otherwise, touch events are not accepted by this item.
+
+ \since 5.10
+
+ \sa acceptTouchEvents()
+*/
+void QQuickItem::setAcceptTouchEvents(bool enabled)
+{
+ Q_D(QQuickItem);
+ d->touchEnabled = enabled;
+}
+
void QQuickItemPrivate::setHasCursorInChild(bool hasCursor)
{
#if QT_CONFIG(cursor)
@@ -7214,6 +7424,8 @@ void QQuickItemPrivate::setHasHoverInChild(bool hasHover)
QQuickItemPrivate *otherChildPrivate = QQuickItemPrivate::get(otherChild);
if (otherChildPrivate->subtreeHoverEnabled || otherChildPrivate->hoverEnabled)
return; // nope! sorry, something else wants it kept on.
+ if (otherChildPrivate->hasHoverHandlers())
+ return; // nope! sorry, we have pointer handlers which are interested.
}
}
@@ -7327,10 +7539,15 @@ void QQuickItem::unsetCursor()
void QQuickItem::grabMouse()
{
Q_D(QQuickItem);
- if (!d->window)
+ if (!d->window || d->window->mouseGrabberItem() == this)
return;
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window);
- windowPriv->setMouseGrabber(this);
+ bool fromTouch = windowPriv->isDeliveringTouchAsMouse();
+ auto point = fromTouch ?
+ windowPriv->pointerEventInstance(windowPriv->touchMouseDevice)->pointById(windowPriv->touchMouseId) :
+ windowPriv->pointerEventInstance(QQuickPointerDevice::genericMouseDevice())->point(0);
+ if (point)
+ point->setGrabberItem(this);
}
/*!
@@ -7348,7 +7565,7 @@ void QQuickItem::ungrabMouse()
if (!d->window)
return;
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window);
- windowPriv->removeGrabber(this, true, false);
+ windowPriv->removeGrabber(this, true, windowPriv->isDeliveringTouchAsMouse());
}
@@ -7478,9 +7695,75 @@ void QQuickItem::setKeepTouchGrab(bool keep)
bool QQuickItem::contains(const QPointF &point) const
{
Q_D(const QQuickItem);
- qreal x = point.x();
- qreal y = point.y();
- return x >= 0 && y >= 0 && x <= d->width && y <= d->height;
+ if (d->mask) {
+ bool res = false;
+ d->extra->maskContains.invoke(d->mask,
+ Qt::DirectConnection,
+ Q_RETURN_ARG(bool, res),
+ Q_ARG(QPointF, point));
+ return res;
+ } else {
+ qreal x = point.x();
+ qreal y = point.y();
+ return x >= 0 && y >= 0 && x <= d->width && y <= d->height;
+ }
+}
+
+/*!
+ \qmlproperty QObject* QtQuick::Item::containmentMask
+ \since 5.11
+ This property holds an optional mask for the Item to be used in the
+ QtQuick::Item::contains method.
+ QtQuick::Item::contains main use is currently to determine whether
+ an input event has landed into the item or not.
+
+ By default the \l contains method will return true for any point
+ within the Item's bounding box. \c containmentMask allows for a
+ more fine-grained control. For example, the developer could
+ define and use an AnotherItem element as containmentMask,
+ which has a specialized contains method, like:
+
+ \code
+ Item { id: item; containmentMask: AnotherItem { id: anotherItem } }
+ \endcode
+
+ \e{item}'s contains method would then return true only if
+ \e{anotherItem}'s contains implementation returns true.
+*/
+QObject *QQuickItem::containmentMask() const
+{
+ Q_D(const QQuickItem);
+ return d->mask.data();
+}
+
+void QQuickItem::setContainmentMask(QObject *mask)
+{
+ Q_D(QQuickItem);
+ // an Item can't mask itself (to prevent infinite loop in contains())
+ if (d->mask.data() == mask || mask == static_cast<QObject *>(this))
+ return;
+
+ QQuickItem *quickMask = qobject_cast<QQuickItem *>(d->mask);
+ if (quickMask) {
+ QQuickItemPrivate *maskPrivate = QQuickItemPrivate::get(quickMask);
+ maskPrivate->registerAsContainmentMask(this, false); // removed from use as my mask
+ }
+
+ if (mask) {
+ int methodIndex = mask->metaObject()->indexOfMethod(QByteArrayLiteral("contains(QPointF)"));
+ if (methodIndex < 0) {
+ qmlWarning(this) << QStringLiteral("QQuickItem: Object set as mask does not have an invokable contains method, ignoring it.");
+ return;
+ }
+ d->extra.value().maskContains = mask->metaObject()->method(methodIndex);
+ }
+ d->mask = mask;
+ quickMask = qobject_cast<QQuickItem *>(mask);
+ if (quickMask) {
+ QQuickItemPrivate *maskPrivate = QQuickItemPrivate::get(quickMask);
+ maskPrivate->registerAsContainmentMask(this, true); // telling maskPrivate that "this" is using it as mask
+ }
+ emit containmentMaskChanged();
}
/*!
@@ -7488,6 +7771,8 @@ bool QQuickItem::contains(const QPointF &point) const
point within \a item's coordinate system, and returns the mapped
coordinate.
+ \input item.qdocinc mapping
+
If \a item is 0, this maps \a point to the coordinate system of the
scene.
@@ -7506,6 +7791,8 @@ QPointF QQuickItem::mapToItem(const QQuickItem *item, const QPointF &point) cons
point within the scene's coordinate system, and returns the mapped
coordinate.
+ \input item.qdocinc mapping
+
\sa {Concepts - Visual Coordinates in Qt Quick}
*/
QPointF QQuickItem::mapToScene(const QPointF &point) const
@@ -7519,6 +7806,8 @@ QPointF QQuickItem::mapToScene(const QPointF &point) const
point within global screen coordinate system, and returns the mapped
coordinate.
+ \input item.qdocinc mapping
+
For example, this may be helpful to add a popup to a Qt Quick component.
\note Window positioning is done by the window manager and this value is
@@ -7540,6 +7829,8 @@ QPointF QQuickItem::mapToGlobal(const QPointF &point) const
rectangular area within \a item's coordinate system, and returns the mapped
rectangle value.
+ \input item.qdocinc mapping
+
If \a item is 0, this maps \a rect to the coordinate system of the
scene.
@@ -7559,6 +7850,8 @@ QRectF QQuickItem::mapRectToItem(const QQuickItem *item, const QRectF &rect) con
rectangular area within the scene's coordinate system, and returns the mapped
rectangle value.
+ \input item.qdocinc mapping
+
\sa {Concepts - Visual Coordinates in Qt Quick}
*/
QRectF QQuickItem::mapRectToScene(const QRectF &rect) const
@@ -7572,6 +7865,8 @@ QRectF QQuickItem::mapRectToScene(const QRectF &rect) const
point within this item's coordinate system, and returns the mapped
coordinate.
+ \input item.qdocinc mapping
+
If \a item is 0, this maps \a point from the coordinate system of the
scene.
@@ -7588,6 +7883,8 @@ QPointF QQuickItem::mapFromItem(const QQuickItem *item, const QPointF &point) co
point within this item's coordinate system, and returns the mapped
coordinate.
+ \input item.qdocinc mapping
+
\sa {Concepts - Visual Coordinates in Qt Quick}
*/
QPointF QQuickItem::mapFromScene(const QPointF &point) const
@@ -7601,6 +7898,8 @@ QPointF QQuickItem::mapFromScene(const QPointF &point) const
equivalent point within this item's coordinate system, and returns the
mapped coordinate.
+ \input item.qdocinc mapping
+
For example, this may be helpful to add a popup to a Qt Quick component.
\note Window positioning is done by the window manager and this value is
@@ -7622,6 +7921,8 @@ QPointF QQuickItem::mapFromGlobal(const QPointF &point) const
rectangular area within this item's coordinate system, and returns the mapped
rectangle value.
+ \input item.qdocinc mapping
+
If \a item is 0, this maps \a rect from the coordinate system of the
scene.
@@ -7640,6 +7941,8 @@ QRectF QQuickItem::mapRectFromItem(const QQuickItem *item, const QRectF &rect) c
rectangular area within this item's coordinate system, and returns the mapped
rectangle value.
+ \input item.qdocinc mapping
+
\sa {Concepts - Visual Coordinates in Qt Quick}
*/
QRectF QQuickItem::mapRectFromScene(const QRectF &rect) const
@@ -7857,7 +8160,7 @@ bool QQuickItem::isTextureProvider() const
\fn QSGTextureProvider *QQuickItem::textureProvider() const
Returns the texture provider for an item. The default implementation
- returns 0.
+ returns \nullptr.
This function may only be called on the rendering thread.
*/
@@ -7867,7 +8170,7 @@ QSGTextureProvider *QQuickItem::textureProvider() const
#if QT_CONFIG(quick_shadereffect)
Q_D(const QQuickItem);
return d->extra.isAllocated() && d->extra->layer && d->extra->layer->effectSource() ?
- d->extra->layer->effectSource()->textureProvider() : 0;
+ d->extra->layer->effectSource()->textureProvider() : nullptr;
#else
return 0;
#endif
@@ -7891,6 +8194,32 @@ QQuickItemLayer *QQuickItemPrivate::layer() const
#endif
}
+bool QQuickItemPrivate::hasPointerHandlers() const
+{
+ return extra.isAllocated() && !extra->pointerHandlers.isEmpty();
+}
+
+bool QQuickItemPrivate::hasHoverHandlers() const
+{
+ if (!hasPointerHandlers())
+ return false;
+ for (QQuickPointerHandler *h : extra->pointerHandlers)
+ if (qmlobject_cast<QQuickHoverHandler *>(h))
+ return true;
+ return false;
+}
+
+void QQuickItemPrivate::addPointerHandler(QQuickPointerHandler *h)
+{
+ Q_Q(QQuickItem);
+ // Accept all buttons, and leave filtering to pointerEvent() and/or user JS,
+ // because there can be multiple handlers...
+ q->setAcceptedMouseButtons(Qt::AllButtons);
+ auto &handlers = extra.value().pointerHandlers;
+ if (!handlers.contains(h))
+ handlers.prepend(h);
+}
+
#if QT_CONFIG(quick_shadereffect)
QQuickItemLayer::QQuickItemLayer(QQuickItem *item)
: m_item(item)
@@ -7901,9 +8230,9 @@ QQuickItemLayer::QQuickItemLayer(QQuickItem *item)
, m_wrapMode(QQuickShaderEffectSource::ClampToEdge)
, m_format(QQuickShaderEffectSource::RGBA)
, m_name("source")
- , m_effectComponent(0)
- , m_effect(0)
- , m_effectSource(0)
+ , m_effectComponent(nullptr)
+ , m_effect(nullptr)
+ , m_effectSource(nullptr)
, m_textureMirroring(QQuickShaderEffectSource::MirrorVertically)
, m_samples(0)
{
@@ -8004,7 +8333,7 @@ void QQuickItemLayer::deactivate()
deactivateEffect();
delete m_effectSource;
- m_effectSource = 0;
+ m_effectSource = nullptr;
QQuickItemPrivate *id = QQuickItemPrivate::get(m_item);
id->removeItemChangeListener(this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Opacity | QQuickItemPrivate::Parent | QQuickItemPrivate::Visibility | QQuickItemPrivate::SiblingOrder);
@@ -8041,7 +8370,7 @@ void QQuickItemLayer::deactivateEffect()
Q_ASSERT(m_effectComponent);
delete m_effect;
- m_effect = 0;
+ m_effect = nullptr;
}
@@ -8349,7 +8678,7 @@ void QQuickItemLayer::itemParentChanged(QQuickItem *item, QQuickItem *parent)
Q_UNUSED(item)
Q_ASSERT(item == m_item);
Q_ASSERT(parent != m_effectSource);
- Q_ASSERT(parent == 0 || parent != m_effect);
+ Q_ASSERT(parent == nullptr || parent != m_effect);
m_effectSource->setParentItem(parent);
if (parent)
@@ -8397,10 +8726,8 @@ void QQuickItemLayer::updateGeometry()
QQuickItem *l = m_effect ? (QQuickItem *) m_effect : (QQuickItem *) m_effectSource;
Q_ASSERT(l);
QRectF bounds = m_item->clipRect();
- l->setWidth(bounds.width());
- l->setHeight(bounds.height());
- l->setX(bounds.x() + m_item->x());
- l->setY(bounds.y() + m_item->y());
+ l->setSize(bounds.size());
+ l->setPosition(bounds.topLeft() + m_item->position());
}
void QQuickItemLayer::updateMatrix()
@@ -8423,15 +8750,16 @@ void QQuickItemLayer::updateMatrix()
QQuickItemPrivate::ExtraData::ExtraData()
: z(0), scale(1), rotation(0), opacity(1),
- contents(0), screenAttached(0), layoutDirectionAttached(0),
- enterKeyAttached(0),
- keyHandler(0),
+ contents(nullptr), screenAttached(nullptr), layoutDirectionAttached(nullptr),
+ enterKeyAttached(nullptr),
+ keyHandler(nullptr),
#if QT_CONFIG(quick_shadereffect)
- layer(0),
+ layer(nullptr),
#endif
effectRefCount(0), hideRefCount(0),
- opacityNode(0), clipNode(0), rootNode(0),
- acceptedMouseButtons(0), origin(QQuickItem::Center),
+ recursiveEffectRefCount(0),
+ opacityNode(nullptr), clipNode(nullptr), rootNode(nullptr),
+ acceptedMouseButtons(nullptr), origin(QQuickItem::Center),
transparentForPositioner(false)
{
}
@@ -8454,30 +8782,30 @@ QAccessible::Role QQuickItemPrivate::accessibleRole() const
namespace QV4 {
namespace Heap {
struct QQuickItemWrapper : public QObjectWrapper {
+ static void markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack);
};
}
}
struct QQuickItemWrapper : public QV4::QObjectWrapper {
V4_OBJECT2(QQuickItemWrapper, QV4::QObjectWrapper)
- static void markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack);
};
DEFINE_OBJECT_VTABLE(QQuickItemWrapper);
-void QQuickItemWrapper::markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack)
+void QV4::Heap::QQuickItemWrapper::markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack)
{
- QObjectWrapper::Data *This = static_cast<QObjectWrapper::Data *>(that);
+ QObjectWrapper *This = static_cast<QObjectWrapper *>(that);
if (QQuickItem *item = static_cast<QQuickItem*>(This->object())) {
for (QQuickItem *child : qAsConst(QQuickItemPrivate::get(item)->childItems))
QV4::QObjectWrapper::markWrapper(child, markStack);
}
- QV4::QObjectWrapper::markObjects(that, markStack);
+ QObjectWrapper::markObjects(that, markStack);
}
quint64 QQuickItemPrivate::_q_createJSWrapper(QV4::ExecutionEngine *engine)
{
- return (engine->memoryManager->allocObject<QQuickItemWrapper>(q_func()))->asReturnedValue();
+ return (engine->memoryManager->allocate<QQuickItemWrapper>(q_func()))->asReturnedValue();
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index f58946d01d..6f601e0872 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -59,8 +59,8 @@ class Q_QUICK_EXPORT QQuickTransform : public QObject
{
Q_OBJECT
public:
- explicit QQuickTransform(QObject *parent = Q_NULLPTR);
- ~QQuickTransform();
+ explicit QQuickTransform(QObject *parent = nullptr);
+ ~QQuickTransform() override;
void appendToItem(QQuickItem *);
void prependToItem(QQuickItem *);
@@ -144,6 +144,7 @@ class Q_QUICK_EXPORT QQuickItem : public QObject, public QQmlParserStatus
Q_PROPERTY(bool antialiasing READ antialiasing WRITE setAntialiasing NOTIFY antialiasingChanged RESET resetAntialiasing)
Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged)
Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged)
+ Q_PROPERTY(QObject *containmentMask READ containmentMask WRITE setContainmentMask NOTIFY containmentMaskChanged REVISION 11)
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQuickItemLayer *layer READ layer DESIGNABLE false CONSTANT FINAL)
@@ -162,6 +163,7 @@ public:
// Remember to increment the size of QQuickItemPrivate::flags
};
Q_DECLARE_FLAGS(Flags, Flag)
+ Q_FLAG(Flags)
enum ItemChange {
ItemChildAddedChange, // value.item
@@ -173,7 +175,8 @@ public:
ItemActiveFocusHasChanged, // value.boolValue
ItemRotationHasChanged, // value.realValue
ItemAntialiasingHasChanged, // value.boolValue
- ItemDevicePixelRatioHasChanged // value.realValue
+ ItemDevicePixelRatioHasChanged, // value.realValue
+ ItemEnabledHasChanged // value.boolValue
};
union ItemChangeData {
@@ -195,8 +198,8 @@ public:
};
Q_ENUM(TransformOrigin)
- explicit QQuickItem(QQuickItem *parent = Q_NULLPTR);
- virtual ~QQuickItem();
+ explicit QQuickItem(QQuickItem *parent = nullptr);
+ ~QQuickItem() override;
QQuickWindow *window() const;
QQuickItem *parentItem() const;
@@ -292,6 +295,8 @@ public:
void setAcceptedMouseButtons(Qt::MouseButtons buttons);
bool acceptHoverEvents() const;
void setAcceptHoverEvents(bool enabled);
+ bool acceptTouchEvents() const;
+ void setAcceptTouchEvents(bool accept);
#if QT_CONFIG(cursor)
QCursor cursor() const;
@@ -317,6 +322,8 @@ public:
QSharedPointer<QQuickItemGrabResult> grabToImage(const QSize &targetSize = QSize());
Q_INVOKABLE virtual bool contains(const QPointF &point) const;
+ QObject *containmentMask() const;
+ void setContainmentMask(QObject *mask);
QTransform itemTransform(QQuickItem *, bool *) const;
QPointF mapToItem(const QQuickItem *item, const QPointF &point) const;
@@ -387,9 +394,10 @@ Q_SIGNALS:
void zChanged();
void implicitWidthChanged();
void implicitHeightChanged();
+ Q_REVISION(11) void containmentMaskChanged();
protected:
- bool event(QEvent *) Q_DECL_OVERRIDE;
+ bool event(QEvent *) override;
bool isComponentComplete() const;
virtual void itemChange(ItemChange, const ItemChangeData &);
@@ -402,8 +410,8 @@ protected:
bool heightValid() const; // ### better name?
void setImplicitSize(qreal, qreal);
- void classBegin() Q_DECL_OVERRIDE;
- void componentComplete() Q_DECL_OVERRIDE;
+ void classBegin() override;
+ void componentComplete() override;
virtual void keyPressEvent(QKeyEvent *event);
virtual void keyReleaseEvent(QKeyEvent *event);
@@ -442,12 +450,13 @@ protected:
virtual void updatePolish();
protected:
- QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent = Q_NULLPTR);
+ QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent = nullptr);
private:
Q_PRIVATE_SLOT(d_func(), void _q_resourceObjectDeleted(QObject *))
Q_PRIVATE_SLOT(d_func(), quint64 _q_createJSWrapper(QV4::ExecutionEngine *))
+ friend class QQuickEventPoint;
friend class QQuickWindow;
friend class QQuickWindowPrivate;
friend class QSGRenderer;
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index e56d839de9..771228914b 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -87,28 +87,29 @@ class QQuickItemKeyFilter;
class QQuickLayoutMirroringAttached;
class QQuickEnterKeyAttached;
class QQuickScreenAttached;
+class QQuickPointerHandler;
class QQuickContents : public QQuickItemChangeListener
{
public:
QQuickContents(QQuickItem *item);
- ~QQuickContents();
+ ~QQuickContents() override;
QRectF rectF() const { return m_contents; }
- inline void calcGeometry(QQuickItem *changed = 0);
+ inline void calcGeometry(QQuickItem *changed = nullptr);
void complete();
protected:
- void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE;
- void itemDestroyed(QQuickItem *item) Q_DECL_OVERRIDE;
- void itemChildAdded(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE;
- void itemChildRemoved(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) override;
+ void itemDestroyed(QQuickItem *item) override;
+ void itemChildAdded(QQuickItem *, QQuickItem *) override;
+ void itemChildRemoved(QQuickItem *, QQuickItem *) override;
//void itemVisibilityChanged(QQuickItem *item)
private:
- bool calcHeight(QQuickItem *changed = 0);
- bool calcWidth(QQuickItem *changed = 0);
+ bool calcHeight(QQuickItem *changed = nullptr);
+ bool calcWidth(QQuickItem *changed = nullptr);
void updateRect();
QQuickItem *m_item;
@@ -153,7 +154,7 @@ class QQuickItemLayer : public QObject, public QQuickItemChangeListener
public:
QQuickItemLayer(QQuickItem *item);
- ~QQuickItemLayer();
+ ~QQuickItemLayer() override;
void classBegin();
void componentComplete();
@@ -193,11 +194,11 @@ public:
QQuickShaderEffectSource *effectSource() const { return m_effectSource; }
- void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
- void itemOpacityChanged(QQuickItem *) Q_DECL_OVERRIDE;
- void itemParentChanged(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE;
- void itemSiblingOrderChanged(QQuickItem *) Q_DECL_OVERRIDE;
- void itemVisibilityChanged(QQuickItem *) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override;
+ void itemOpacityChanged(QQuickItem *) override;
+ void itemParentChanged(QQuickItem *, QQuickItem *) override;
+ void itemSiblingOrderChanged(QQuickItem *) override;
+ void itemVisibilityChanged(QQuickItem *) override;
void updateMatrix();
void updateGeometry();
@@ -254,7 +255,7 @@ public:
static const QQuickItemPrivate* get(const QQuickItem *item) { return item->d_func(); }
QQuickItemPrivate();
- ~QQuickItemPrivate();
+ ~QQuickItemPrivate() override;
void init(QQuickItem *parent);
QQmlListProperty<QObject> data();
@@ -278,6 +279,10 @@ public:
QQuickItemLayer *layer() const;
+ bool hasPointerHandlers() const;
+ bool hasHoverHandlers() const;
+ virtual void addPointerHandler(QQuickPointerHandler *h);
+
// data property
static void data_append(QQmlListProperty<QObject> *, QObject *);
static int data_count(QQmlListProperty<QObject> *);
@@ -308,7 +313,6 @@ public:
static void transform_clear(QQmlListProperty<QQuickTransform> *list);
void _q_resourceObjectDeleted(QObject *);
- void _q_windowChanged(QQuickWindow *w);
quint64 _q_createJSWrapper(QV4::ExecutionEngine *engine);
enum ChangeType {
@@ -321,18 +325,33 @@ public:
Children = 0x40,
Rotation = 0x80,
ImplicitWidth = 0x100,
- ImplicitHeight = 0x200
+ ImplicitHeight = 0x200,
+ Enabled = 0x400,
};
Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
struct ChangeListener {
- ChangeListener(QQuickItemChangeListener *l = nullptr, QQuickItemPrivate::ChangeTypes t = 0) : listener(l), types(t), gTypes(QQuickGeometryChange::All) {}
- ChangeListener(QQuickItemChangeListener *l, QQuickGeometryChange gt) : listener(l), types(Geometry), gTypes(gt) {}
+ using ChangeTypes = QQuickItemPrivate::ChangeTypes;
+
+ ChangeListener(QQuickItemChangeListener *l = nullptr, ChangeTypes t = nullptr)
+ : listener(l)
+ , types(t)
+ , gTypes(QQuickGeometryChange::All)
+ {}
+
+ ChangeListener(QQuickItemChangeListener *l, QQuickGeometryChange gt)
+ : listener(l)
+ , types(Geometry)
+ , gTypes(gt)
+ {}
+
+ bool operator==(const ChangeListener &other) const
+ { return listener == other.listener && types == other.types; }
+
QQuickItemChangeListener *listener;
- QQuickItemPrivate::ChangeTypes types;
+ ChangeTypes types;
QQuickGeometryChange gTypes; //NOTE: not used for ==
- bool operator==(const ChangeListener &other) const { return listener == other.listener && types == other.types; }
};
struct ExtraData {
@@ -348,6 +367,7 @@ public:
QQuickLayoutMirroringAttached* layoutDirectionAttached;
QQuickEnterKeyAttached *enterKeyAttached;
QQuickItemKeyFilter *keyHandler;
+ QVector<QQuickPointerHandler *> pointerHandlers;
#if QT_CONFIG(quick_shadereffect)
mutable QQuickItemLayer *layer;
#endif
@@ -356,13 +376,19 @@ public:
#endif
QPointF userTransformOriginPoint;
+ // these do not include child items
int effectRefCount;
int hideRefCount;
+ // updated recursively for child items as well
+ int recursiveEffectRefCount;
QSGOpacityNode *opacityNode;
QQuickDefaultClipNode *clipNode;
QSGRootNode *rootNode;
+ // Mask contains() method
+ QMetaMethod maskContains;
+
QObjectList resourcesList;
// Although acceptedMouseButtons is inside ExtraData, we actually store
@@ -377,6 +403,10 @@ public:
// 26 bits padding
};
QLazilyAllocated<ExtraData> extra;
+ // Contains mask
+ QPointer<QObject> mask;
+ // If the mask is an Item, inform it that it's being used as a mask (true) or is no longer being used (false)
+ virtual void registerAsContainmentMask(QQuickItem * /* maskedItem */, bool /* set */) { }
QQuickAnchors *anchors() const;
mutable QQuickAnchors *_anchors;
@@ -386,6 +416,7 @@ public:
QVector<QQuickItemPrivate::ChangeListener> changeListeners;
void addItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types);
+ void updateOrAddItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types);
void removeItemChangeListener(QQuickItemChangeListener *, ChangeTypes types);
void updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener, QQuickGeometryChange types);
void updateOrRemoveGeometryChangeListener(QQuickItemChangeListener *listener, QQuickGeometryChange types);
@@ -437,6 +468,7 @@ public:
// focus chain and prevents tabbing outside.
bool isTabFence:1;
bool replayingPressEvent:1;
+ bool touchEnabled:1;
enum DirtyType {
TransformOrigin = 0x00000001,
@@ -560,11 +592,17 @@ public:
virtual void transformChanged();
void deliverKeyEvent(QKeyEvent *);
+ bool filterKeyEvent(QKeyEvent *, bool post);
#if QT_CONFIG(im)
void deliverInputMethodEvent(QInputMethodEvent *);
#endif
void deliverShortcutOverrideEvent(QKeyEvent *);
+ bool anyPointerHandlerWants(QQuickEventPoint *point) const;
+ virtual bool handlePointerEvent(QQuickPointerEvent *, bool avoidExclusiveGrabber = false);
+
+ virtual void setVisible(bool visible);
+
bool isTransparentForPositioner() const;
void setTransparentForPositioner(bool trans);
@@ -585,9 +623,9 @@ public:
- (rootNode) (shader effect source's root node)
*/
- QSGOpacityNode *opacityNode() const { return extra.isAllocated()?extra->opacityNode:0; }
- QQuickDefaultClipNode *clipNode() const { return extra.isAllocated()?extra->clipNode:0; }
- QSGRootNode *rootNode() const { return extra.isAllocated()?extra->rootNode:0; }
+ QSGOpacityNode *opacityNode() const { return extra.isAllocated()?extra->opacityNode:nullptr; }
+ QQuickDefaultClipNode *clipNode() const { return extra.isAllocated()?extra->clipNode:nullptr; }
+ QSGRootNode *rootNode() const { return extra.isAllocated()?extra->rootNode:nullptr; }
QSGTransformNode *itemNodeInstance;
QSGNode *paintNode;
@@ -597,6 +635,7 @@ public:
// A reference from an effect item means that this item is used by the effect, so
// it should insert a root node.
void refFromEffectItem(bool hide);
+ void recursiveRefFromEffectItem(int refs);
void derefFromEffectItem(bool unhide);
void itemChange(QQuickItem::ItemChange, const QQuickItem::ItemChangeData &);
@@ -618,7 +657,7 @@ public:
class QQuickItemKeyFilter
{
public:
- QQuickItemKeyFilter(QQuickItem * = 0);
+ QQuickItemKeyFilter(QQuickItem * = nullptr);
virtual ~QQuickItemKeyFilter();
virtual void keyPressed(QKeyEvent *event, bool post);
@@ -640,17 +679,15 @@ class QQuickKeyNavigationAttachedPrivate : public QObjectPrivate
{
public:
QQuickKeyNavigationAttachedPrivate()
- : QObjectPrivate(),
- left(0), right(0), up(0), down(0), tab(0), backtab(0),
- leftSet(false), rightSet(false), upSet(false), downSet(false),
+ : leftSet(false), rightSet(false), upSet(false), downSet(false),
tabSet(false), backtabSet(false) {}
- QQuickItem *left;
- QQuickItem *right;
- QQuickItem *up;
- QQuickItem *down;
- QQuickItem *tab;
- QQuickItem *backtab;
+ QQuickItem *left = nullptr;
+ QQuickItem *right = nullptr;
+ QQuickItem *up = nullptr;
+ QQuickItem *down = nullptr;
+ QQuickItem *tab = nullptr;
+ QQuickItem *backtab = nullptr;
bool leftSet : 1;
bool rightSet : 1;
bool upSet : 1;
@@ -673,7 +710,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickKeyNavigationAttached : public QObject, publi
Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
public:
- QQuickKeyNavigationAttached(QObject * = 0);
+ QQuickKeyNavigationAttached(QObject * = nullptr);
QQuickItem *left() const;
void setLeft(QQuickItem *);
@@ -705,8 +742,8 @@ Q_SIGNALS:
void priorityChanged();
private:
- void keyPressed(QKeyEvent *event, bool post) Q_DECL_OVERRIDE;
- void keyReleased(QKeyEvent *event, bool post) Q_DECL_OVERRIDE;
+ void keyPressed(QKeyEvent *event, bool post) override;
+ void keyReleased(QKeyEvent *event, bool post) override;
void setFocusNavigation(QQuickItem *currentItem, const char *dir,
Qt::FocusReason reason = Qt::OtherFocusReason);
};
@@ -718,7 +755,7 @@ class QQuickLayoutMirroringAttached : public QObject
Q_PROPERTY(bool childrenInherit READ childrenInherit WRITE setChildrenInherit NOTIFY childrenInheritChanged)
public:
- explicit QQuickLayoutMirroringAttached(QObject *parent = 0);
+ explicit QQuickLayoutMirroringAttached(QObject *parent = nullptr);
bool enabled() const;
void setEnabled(bool);
@@ -742,7 +779,7 @@ class QQuickEnterKeyAttached : public QObject
Q_PROPERTY(Qt::EnterKeyType type READ type WRITE setType NOTIFY typeChanged)
public:
- explicit QQuickEnterKeyAttached(QObject *parent = Q_NULLPTR);
+ explicit QQuickEnterKeyAttached(QObject *parent = nullptr);
Qt::EnterKeyType type() const;
void setType(Qt::EnterKeyType type);
@@ -761,8 +798,7 @@ class QQuickKeysAttachedPrivate : public QObjectPrivate
{
public:
QQuickKeysAttachedPrivate()
- : QObjectPrivate(), inPress(false), inRelease(false)
- , inIM(false), enabled(true), imeItem(0), item(0)
+ : inPress(false), inRelease(false), inIM(false), enabled(true)
{}
//loop detection
@@ -772,9 +808,9 @@ public:
bool enabled : 1;
- QQuickItem *imeItem;
+ QQuickItem *imeItem = nullptr;
QList<QQuickItem *> targets;
- QQuickItem *item;
+ QQuickItem *item = nullptr;
QQuickKeyEvent theKeyEvent;
};
@@ -788,8 +824,8 @@ class QQuickKeysAttached : public QObject, public QQuickItemKeyFilter
Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
public:
- QQuickKeysAttached(QObject *parent=0);
- ~QQuickKeysAttached();
+ QQuickKeysAttached(QObject *parent=nullptr);
+ ~QQuickKeysAttached() override;
bool enabled() const { Q_D(const QQuickKeysAttached); return d->enabled; }
void setEnabled(bool enabled) {
@@ -810,7 +846,7 @@ public:
return QQmlListProperty<QQuickItem>(this, d->targets);
}
- void componentComplete() Q_DECL_OVERRIDE;
+ void componentComplete() override;
static QQuickKeysAttached *qmlAttachedProperties(QObject *);
@@ -862,11 +898,11 @@ Q_SIGNALS:
void volumeDownPressed(QQuickKeyEvent *event);
private:
- void keyPressed(QKeyEvent *event, bool post) Q_DECL_OVERRIDE;
- void keyReleased(QKeyEvent *event, bool post) Q_DECL_OVERRIDE;
+ void keyPressed(QKeyEvent *event, bool post) override;
+ void keyReleased(QKeyEvent *event, bool post) override;
#if QT_CONFIG(im)
- void inputMethodEvent(QInputMethodEvent *, bool post) Q_DECL_OVERRIDE;
- QVariant inputMethodQuery(Qt::InputMethodQuery query) const Q_DECL_OVERRIDE;
+ void inputMethodEvent(QInputMethodEvent *, bool post) override;
+ QVariant inputMethodQuery(Qt::InputMethodQuery query) const override;
#endif
void shortcutOverride(QKeyEvent *event) override;
static QByteArray keyToSignal(int key);
@@ -877,7 +913,7 @@ private:
Qt::MouseButtons QQuickItemPrivate::acceptedMouseButtons() const
{
return ((extra.flag() ? Qt::LeftButton : Qt::MouseButton(0)) |
- (extra.isAllocated() ? extra->acceptedMouseButtons : Qt::MouseButtons(0)));
+ (extra.isAllocated() ? extra->acceptedMouseButtons : Qt::MouseButtons(nullptr)));
}
QSGContext *QQuickItemPrivate::sceneGraphContext() const
@@ -899,7 +935,7 @@ void QQuickItemPrivate::markSortedChildrenDirty(QQuickItem *child)
if (child->z() != 0. || sortedChildItems != &childItems) {
if (sortedChildItems != &childItems)
delete sortedChildItems;
- sortedChildItems = 0;
+ sortedChildItems = nullptr;
}
}
diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp
index d4d346def9..8251282736 100644
--- a/src/quick/items/qquickitemanimation.cpp
+++ b/src/quick/items/qquickitemanimation.cpp
@@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
\ingroup qtquick-animation-properties
\since 5.0
\inherits Animation
- \brief Animates changes in parent values
+ \brief Animates changes in parent values.
ParentAnimation is used to animate a parent change for an \l Item.
@@ -211,7 +211,7 @@ struct QQuickParentAnimationData : public QAbstractAnimationAction
//### reverse should probably apply on a per-action basis
bool reverse;
QList<QQuickParentChange *> pc;
- void doAction() Q_DECL_OVERRIDE
+ void doAction() override
{
for (int ii = 0; ii < actions.count(); ++ii) {
const QQuickStateAction &action = actions.at(ii);
@@ -371,7 +371,7 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act
if (data->actions.count()) {
QSequentialAnimationGroupJob *topLevelGroup = new QSequentialAnimationGroupJob;
- QActionAnimation *viaAction = d->via ? new QActionAnimation : 0;
+ QActionAnimation *viaAction = d->via ? new QActionAnimation : nullptr;
QActionAnimation *targetAction = new QActionAnimation;
//we'll assume the common case by far is to have children, and always create ag
QParallelAnimationGroupJob *ag = new QParallelAnimationGroupJob;
@@ -409,7 +409,7 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act
delete data;
delete viaData;
}
- return 0;
+ return nullptr;
}
/*!
@@ -418,7 +418,7 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act
\inqmlmodule QtQuick
\ingroup qtquick-animation-properties
\inherits Animation
- \brief Animates changes in anchor values
+ \brief Animates changes in anchor values.
AnchorAnimation is used to animate an anchor change.
@@ -565,7 +565,7 @@ QAbstractAnimationJob* QQuickAnchorAnimation::transition(QQuickStateActions &act
\ingroup qtquick-animation-properties
\inherits Animation
\since 5.0
- \brief Animates an item along a path
+ \brief Animates an item along a path.
When used in a transition, the path can be specified without start
or end points, for example:
@@ -922,12 +922,12 @@ QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actio
pa->setEasingCurve(d->easingCurve);
return initInstance(pa);
} else {
- pa->setFromSourcedValue(0);
- pa->setAnimValue(0);
+ pa->setFromSourcedValue(nullptr);
+ pa->setAnimValue(nullptr);
delete pa;
delete data;
}
- return 0;
+ return nullptr;
}
void QQuickPathAnimationUpdater::setValue(qreal v)
@@ -955,7 +955,7 @@ void QQuickPathAnimationUpdater::setValue(qreal v)
qreal angle;
bool fixed = orientation == QQuickPathAnimation::Fixed;
- QPointF currentPos = !painterPath.isEmpty() ? path->sequentialPointAt(painterPath, pathLength, attributePoints, prevBez, v, fixed ? 0 : &angle) : path->sequentialPointAt(v, fixed ? 0 : &angle);
+ QPointF currentPos = !painterPath.isEmpty() ? path->sequentialPointAt(painterPath, pathLength, attributePoints, prevBez, v, fixed ? nullptr : &angle) : path->sequentialPointAt(v, fixed ? nullptr : &angle);
//adjust position according to anchor point
if (!anchorPoint.isNull()) {
diff --git a/src/quick/items/qquickitemanimation_p.h b/src/quick/items/qquickitemanimation_p.h
index a503cff223..b803455f12 100644
--- a/src/quick/items/qquickitemanimation_p.h
+++ b/src/quick/items/qquickitemanimation_p.h
@@ -68,7 +68,7 @@ class Q_AUTOTEST_EXPORT QQuickParentAnimation : public QQuickAnimationGroup
Q_PROPERTY(QQuickItem *via READ via WRITE setVia NOTIFY viaChanged)
public:
- QQuickParentAnimation(QObject *parent=0);
+ QQuickParentAnimation(QObject *parent=nullptr);
virtual ~QQuickParentAnimation();
QQuickItem *target() const;
@@ -89,7 +89,7 @@ protected:
QAbstractAnimationJob* transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
- QObject *defaultTarget = 0) Q_DECL_OVERRIDE;
+ QObject *defaultTarget = nullptr) override;
};
class QQuickAnchorAnimationPrivate;
@@ -102,7 +102,7 @@ class Q_AUTOTEST_EXPORT QQuickAnchorAnimation : public QQuickAbstractAnimation
Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged)
public:
- QQuickAnchorAnimation(QObject *parent=0);
+ QQuickAnchorAnimation(QObject *parent=nullptr);
virtual ~QQuickAnchorAnimation();
QQmlListProperty<QQuickItem> targets();
@@ -121,7 +121,7 @@ protected:
QAbstractAnimationJob* transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
- QObject *defaultTarget = 0) Q_DECL_OVERRIDE;
+ QObject *defaultTarget = nullptr) override;
};
#if QT_CONFIG(quick_path)
@@ -145,7 +145,7 @@ class Q_AUTOTEST_EXPORT QQuickPathAnimation : public QQuickAbstractAnimation
Q_PROPERTY(qreal endRotation READ endRotation WRITE setEndRotation NOTIFY endRotationChanged)
public:
- QQuickPathAnimation(QObject *parent=0);
+ QQuickPathAnimation(QObject *parent=nullptr);
virtual ~QQuickPathAnimation();
enum Orientation {
@@ -188,7 +188,7 @@ protected:
QAbstractAnimationJob* transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
- QObject *defaultTarget = 0) Q_DECL_OVERRIDE;
+ QObject *defaultTarget = nullptr) override;
Q_SIGNALS:
void durationChanged(int);
void easingChanged(const QEasingCurve &);
diff --git a/src/quick/items/qquickitemanimation_p_p.h b/src/quick/items/qquickitemanimation_p_p.h
index 2d075dfab3..83b9899197 100644
--- a/src/quick/items/qquickitemanimation_p_p.h
+++ b/src/quick/items/qquickitemanimation_p_p.h
@@ -65,7 +65,7 @@ class QQuickParentAnimationPrivate : public QQuickAnimationGroupPrivate
Q_DECLARE_PUBLIC(QQuickParentAnimation)
public:
QQuickParentAnimationPrivate()
- : QQuickAnimationGroupPrivate(), target(0), newParent(0), via(0) {}
+ : QQuickAnimationGroupPrivate(), target(nullptr), newParent(nullptr), via(nullptr) {}
QQuickItem *target;
QQuickItem *newParent;
@@ -91,7 +91,7 @@ public:
class QQuickPathAnimationUpdater : public QQuickBulkValueUpdater
{
public:
- QQuickPathAnimationUpdater() : path(0), pathLength(0), target(0), reverse(false),
+ QQuickPathAnimationUpdater() : path(nullptr), pathLength(0), target(nullptr), reverse(false),
fromSourced(false), fromDefined(false), toDefined(false),
toX(0), toY(0), currentV(0), orientation(QQuickPathAnimation::Fixed),
entryInterval(0), exitInterval(0) {}
@@ -128,10 +128,10 @@ class QQuickPathAnimationPrivate;
class QQuickPathAnimationAnimator : public QQuickBulkValueAnimator
{
public:
- QQuickPathAnimationAnimator(QQuickPathAnimationPrivate * = 0);
+ QQuickPathAnimationAnimator(QQuickPathAnimationPrivate * = nullptr);
~QQuickPathAnimationAnimator();
- void clearTemplate() { animationTemplate = 0; }
+ void clearTemplate() { animationTemplate = nullptr; }
QQuickPathAnimationUpdater *pathUpdater() const { return static_cast<QQuickPathAnimationUpdater*>(getAnimValue()); }
private:
@@ -142,7 +142,7 @@ class QQuickPathAnimationPrivate : public QQuickAbstractAnimationPrivate
{
Q_DECLARE_PUBLIC(QQuickPathAnimation)
public:
- QQuickPathAnimationPrivate() : path(0), target(0),
+ QQuickPathAnimationPrivate() : path(nullptr), target(nullptr),
orientation(QQuickPathAnimation::Fixed), entryDuration(0), exitDuration(0), duration(250) {}
QQuickPath *path;
diff --git a/src/quick/items/qquickitemchangelistener_p.h b/src/quick/items/qquickitemchangelistener_p.h
index 83c69a9330..31d06c9983 100644
--- a/src/quick/items/qquickitemchangelistener_p.h
+++ b/src/quick/items/qquickitemchangelistener_p.h
@@ -125,6 +125,7 @@ public:
virtual void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF & /* oldGeometry */) {}
virtual void itemSiblingOrderChanged(QQuickItem *) {}
virtual void itemVisibilityChanged(QQuickItem *) {}
+ virtual void itemEnabledChanged(QQuickItem *) {}
virtual void itemOpacityChanged(QQuickItem *) {}
virtual void itemDestroyed(QQuickItem *) {}
virtual void itemChildAdded(QQuickItem *, QQuickItem * /* child */ ) {}
@@ -134,7 +135,7 @@ public:
virtual void itemImplicitWidthChanged(QQuickItem *) {}
virtual void itemImplicitHeightChanged(QQuickItem *) {}
- virtual QQuickAnchorsPrivate *anchorPrivate() { return 0; }
+ virtual QQuickAnchorsPrivate *anchorPrivate() { return nullptr; }
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp
index c3f8d4f024..f298803c7f 100644
--- a/src/quick/items/qquickitemgrabresult.cpp
+++ b/src/quick/items/qquickitemgrabresult.cpp
@@ -62,9 +62,9 @@ class QQuickItemGrabResultPrivate : public QObjectPrivate
{
public:
QQuickItemGrabResultPrivate()
- : cacheEntry(0)
- , qmlEngine(0)
- , texture(0)
+ : cacheEntry(nullptr)
+ , qmlEngine(nullptr)
+ , texture(nullptr)
{
}
@@ -139,7 +139,7 @@ public:
* This property holds the pixel results from a grab.
*
* If the grab is not yet complete or if it failed,
- * an empty image is returned.
+ * a null image is returned (\c {image.isNull()} will return \c true).
*/
/*!
@@ -226,10 +226,12 @@ bool QQuickItemGrabResult::event(QEvent *e)
Q_D(QQuickItemGrabResult);
if (e->type() == Event_Grab_Completed) {
// JS callback
- if (d->qmlEngine && d->callback.isCallable())
+ if (d->qmlEngine && d->callback.isCallable()) {
d->callback.call(QJSValueList() << d->qmlEngine->newQObject(this));
- else
+ deleteLater();
+ } else {
Q_EMIT ready();
+ }
return true;
}
return QObject::event(e);
@@ -266,7 +268,7 @@ void QQuickItemGrabResult::render()
d->image = d->texture->toImage();
delete d->texture;
- d->texture = 0;
+ d->texture = nullptr;
disconnect(d->window.data(), &QQuickWindow::beforeSynchronizing, this, &QQuickItemGrabResult::setup);
disconnect(d->window.data(), &QQuickWindow::afterRendering, this, &QQuickItemGrabResult::render);
@@ -281,17 +283,17 @@ QQuickItemGrabResult *QQuickItemGrabResultPrivate::create(QQuickItem *item, cons
if (size.width() < 1 || size.height() < 1) {
qmlWarning(item) << "grabToImage: item has invalid dimensions";
- return 0;
+ return nullptr;
}
if (!item->window()) {
qmlWarning(item) << "grabToImage: item is not attached to a window";
- return 0;
+ return nullptr;
}
if (!item->window()->isVisible()) {
qmlWarning(item) << "grabToImage: item's window is not visible";
- return 0;
+ return nullptr;
}
QQuickItemGrabResult *result = new QQuickItemGrabResult();
diff --git a/src/quick/items/qquickitemgrabresult.h b/src/quick/items/qquickitemgrabresult.h
index 30f8f0c2ef..3dc10e2d75 100644
--- a/src/quick/items/qquickitemgrabresult.h
+++ b/src/quick/items/qquickitemgrabresult.h
@@ -82,7 +82,7 @@ private Q_SLOTS:
private:
friend class QQuickItem;
- QQuickItemGrabResult(QObject *parent = Q_NULLPTR);
+ QQuickItemGrabResult(QObject *parent = nullptr);
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index e6321e9365..cd5cca5ac9 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -64,6 +64,9 @@
#if QT_CONFIG(quick_pathview)
#include "qquickpathview_p.h"
#endif
+#if QT_CONFIG(quick_tableview)
+#include "qquicktableview_p.h"
+#endif
#if QT_CONFIG(quick_viewtransitions)
#include "qquickitemviewtransition_p.h"
#endif
@@ -74,7 +77,9 @@
#if QT_CONFIG(quick_positioners)
#include "qquickpositioners_p.h"
#endif
+#if QT_CONFIG(quick_repeater)
#include "qquickrepeater_p.h"
+#endif
#include "qquickloader_p.h"
#if QT_CONFIG(quick_animatedimage)
#include "qquickanimatedimage_p.h"
@@ -108,9 +113,18 @@
#include "qquickdrag_p.h"
#include "qquickdroparea_p.h"
#include "qquickmultipointtoucharea_p.h"
-#include <private/qqmlmetatype_p.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
+#include "handlers/qquickdraghandler_p.h"
+#include "handlers/qquickhoverhandler_p.h"
+#include "handlers/qquickpinchhandler_p.h"
+#include "handlers/qquickpointhandler_p.h"
+#include "handlers/qquicktaphandler_p.h"
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcTransient)
+QT_END_NAMESPACE
+
static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject *parent)
{
// When setting a parent (especially during dynamic object creation) in QML,
@@ -125,24 +139,31 @@ static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject
QQuickWindow *win = qmlobject_cast<QQuickWindow *>(obj);
if (win) {
// A Window inside an Item should be transient for that item's window
+ qCDebug(lcTransient) << win << "is transient for" << parentItem->window();
win->setTransientParent(parentItem->window());
return QQmlPrivate::Parented;
}
+ } else if (QQuickPointerHandler *handler = qmlobject_cast<QQuickPointerHandler *>(obj)) {
+ QQuickItemPrivate::get(parentItem)->addPointerHandler(handler);
+ handler->setParent(parent);
+ return QQmlPrivate::Parented;
}
return QQmlPrivate::IncompatibleObject;
} else if (QQuickWindow *parentWindow = qmlobject_cast<QQuickWindow *>(parent)) {
QQuickWindow *win = qmlobject_cast<QQuickWindow *>(obj);
if (win) {
// A Window inside a Window should be transient for it
+ qCDebug(lcTransient) << win << "is transient for" << parentWindow;
win->setTransientParent(parentWindow);
return QQmlPrivate::Parented;
- } else {
- QQuickItem *item = qmlobject_cast<QQuickItem *>(obj);
- if (item) {
- // The parent of an Item inside a Window is actually the implicit content Item
- item->setParentItem(parentWindow->contentItem());
- return QQmlPrivate::Parented;
- }
+ } else if (QQuickItem *item = qmlobject_cast<QQuickItem *>(obj)) {
+ // The parent of an Item inside a Window is actually the implicit content Item
+ item->setParentItem(parentWindow->contentItem());
+ return QQmlPrivate::Parented;
+ } else if (QQuickPointerHandler *handler = qmlobject_cast<QQuickPointerHandler *>(obj)) {
+ QQuickItemPrivate::get(parentWindow->contentItem())->addPointerHandler(handler);
+ handler->setParent(parentWindow->contentItem());
+ return QQmlPrivate::Parented;
}
return QQmlPrivate::IncompatibleObject;
} else if (qmlobject_cast<QQuickItem *>(obj)) {
@@ -156,6 +177,9 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
QQmlPrivate::RegisterAutoParent autoparent = { 0, &qquickitem_autoParent };
QQmlPrivate::qmlregister(QQmlPrivate::AutoParentRegistration, &autoparent);
+ // Register the latest version, even if there are no new types or new revisions for existing types yet.
+ qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
+
#if !QT_CONFIG(quick_animatedimage)
qmlRegisterTypeNotAvailable(uri,major,minor,"AnimatedImage", QCoreApplication::translate("QQuickAnimatedImage","Qt was built without support for QMovie"));
#else
@@ -204,7 +228,9 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickPathView>(uri,major,minor,"PathView");
#endif
qmlRegisterType<QQuickRectangle>(uri,major,minor,"Rectangle");
+#if QT_CONFIG(quick_repeater)
qmlRegisterType<QQuickRepeater>(uri,major,minor,"Repeater");
+#endif
qmlRegisterType<QQuickTranslate>(uri,major,minor,"Translate");
qmlRegisterType<QQuickRotation>(uri,major,minor,"Rotation");
qmlRegisterType<QQuickScale>(uri,major,minor,"Scale");
@@ -287,7 +313,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickMultiPointTouchArea>("QtQuick", 2, 0, "MultiPointTouchArea");
qmlRegisterType<QQuickTouchPoint>("QtQuick", 2, 0, "TouchPoint");
- qmlRegisterType<QQuickGrabGestureEvent>();
+ qmlRegisterUncreatableType<QQuickGrabGestureEvent>(uri,major,minor, "GestureEvent",
+ QQuickMouseEvent::tr("GestureEvent is only available in the context of handling the gestureStarted signal from MultiPointTouchArea"));
#if QT_CONFIG(accessibility)
qmlRegisterUncreatableType<QQuickAccessibleAttached>("QtQuick", 2, 0, "Accessible",QQuickAccessibleAttached::tr("Accessible is only available via attached properties"));
@@ -397,6 +424,57 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
#endif
qmlRegisterType<QQuickFlickable, 10>(uri, 2, 10, "Flickable");
+ qmlRegisterType<QQuickTextEdit, 10>(uri, 2, 10, "TextEdit");
+ qmlRegisterType<QQuickText, 10>(uri, 2, 10, "Text");
+
+#if QT_CONFIG(quick_path)
+ qmlRegisterType<QQuickPathAngleArc>(uri, 2, 11, "PathAngleArc");
+#endif
+
+#if QT_CONFIG(quick_animatedimage)
+ qmlRegisterType<QQuickAnimatedImage, 11>(uri, 2, 11,"AnimatedImage");
+#endif
+ qmlRegisterType<QQuickItem, 11>(uri, 2, 11,"Item");
+ qmlRegisterType<QQuickFlickable, 12>(uri, 2, 12, "Flickable");
+
+ // classes related to Input Handlers which are newly exposed since 5.12
+ qmlRegisterUncreatableType<QQuickPointerEvent>(uri, 2, 12, "PointerEvent",
+ QQuickPointerHandler::tr("PointerEvent is only available as a parameter of several signals in PointerHandler"));
+ qmlRegisterUncreatableType<QQuickPointerMouseEvent>(uri, 2, 12, "PointerMouseEvent",
+ QQuickPointerHandler::tr("PointerMouseEvent is only available as a parameter of several signals in PointerHandler"));
+ qmlRegisterUncreatableType<QQuickPointerTouchEvent>(uri, 2, 12, "PointerTouchEvent",
+ QQuickPointerHandler::tr("PointerTouchEvent is only available as a parameter of several signals in PointerHandler"));
+ qmlRegisterUncreatableType<QQuickEventPoint>(uri, 2, 12, "EventPoint",
+ QQuickPointerHandler::tr("EventPoint is only available as a member of PointerEvent"));
+ qmlRegisterUncreatableType<QQuickEventTouchPoint>(uri, 2, 12, "EventTouchPoint",
+ QQuickPointerHandler::tr("EventTouchPoint is only available as a member of PointerEvent"));
+ qmlRegisterUncreatableType<QQuickPointerDevice>(uri, 2, 12, "PointerDevice",
+ QQuickPointerHandler::tr("PointerDevice is only available as a property of PointerEvent"));
+
+ // Input Handlers are part of QtQuick, not a separate module, since 5.12
+ qmlRegisterUncreatableType<QQuickPointerHandler>(uri, 2, 12, "PointerHandler",
+ QQuickPointerHandler::tr("PointerHandler is an abstract base class"));
+ qmlRegisterType<QQuickPointHandler>(uri, 2, 12, "PointHandler");
+ qmlRegisterType<QQuickDragHandler>(uri, 2, 12, "DragHandler");
+ qmlRegisterUncreatableType<QQuickDragAxis>(uri, 2, 12, "DragAxis",
+ QQuickDragHandler::tr("DragAxis is only available as a grouped property of DragHandler"));
+ qmlRegisterType<QQuickHoverHandler>(uri, 2, 12, "HoverHandler");
+ qmlRegisterType<QQuickPinchHandler>(uri, 2, 12, "PinchHandler");
+ qmlRegisterType<QQuickTapHandler>(uri, 2, 12, "TapHandler");
+ qRegisterMetaType<QQuickHandlerPoint>();
+
+ // The rest of the 5.12 revisions
+ qmlRegisterType<QQuickAnimatedSprite, 12>("QtQuick", 2, 12, "AnimatedSprite");
+ qmlRegisterType<QQuickGradient, 12>(uri, 2, 12, "Gradient");
+ qmlRegisterType<QQuickFlickable, 12>(uri, 2, 12, "Flickable");
+ qmlRegisterType<QQuickText, 12>(uri, 2, 12, "Text");
+#if QT_CONFIG(quick_tableview)
+ qmlRegisterType<QQuickTableView>(uri, 2, 12, "TableView");
+#endif
+
+ qmlRegisterUncreatableType<QQuickItemView, 13>(uri, 2, 13, itemViewName, itemViewMessage);
+ qmlRegisterType<QQuickPathView, 13>(uri, 2, 13, "PathView");
+ qmlRegisterType<QQuickGridView, 13>(uri, 2, 13, "GridView");
}
static void initResources()
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 555db03962..1f8a0de72b 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qquickitemview_p_p.h"
+#include "qquickitemviewfxitem_p_p.h"
#include <QtQuick/private/qquicktransition_p.h>
#include <QtQml/QQmlInfo>
#include "qplatformdefs.h"
@@ -52,117 +53,14 @@ Q_LOGGING_CATEGORY(lcItemViewDelegateLifecycle, "qt.quick.itemview.lifecycle")
#endif
FxViewItem::FxViewItem(QQuickItem *i, QQuickItemView *v, bool own, QQuickItemViewAttached *attached)
- : item(i)
+ : QQuickItemViewFxItem(i, own, QQuickItemViewPrivate::get(v))
, view(v)
- , transitionableItem(0)
, attached(attached)
- , ownItem(own)
- , releaseAfterTransition(false)
- , trackGeom(false)
{
if (attached) // can be null for default components (see createComponentItem)
attached->setView(view);
}
-FxViewItem::~FxViewItem()
-{
- delete transitionableItem;
- if (ownItem && item) {
- trackGeometry(false);
- item->setParentItem(0);
- item->deleteLater();
- item = 0;
- }
-}
-
-qreal FxViewItem::itemX() const
-{
- return transitionableItem ? transitionableItem->itemX() : (item ? item->x() : 0);
-}
-
-qreal FxViewItem::itemY() const
-{
- return transitionableItem ? transitionableItem->itemY() : (item ? item->y() : 0);
-}
-
-void FxViewItem::moveTo(const QPointF &pos, bool immediate)
-{
- if (transitionableItem)
- transitionableItem->moveTo(pos, immediate);
- else if (item)
- item->setPosition(pos);
-}
-
-void FxViewItem::setVisible(bool visible)
-{
- if (!visible && transitionableItem && transitionableItem->transitionScheduledOrRunning())
- return;
- if (item)
- QQuickItemPrivate::get(item)->setCulled(!visible);
-}
-
-void FxViewItem::trackGeometry(bool track)
-{
- if (track) {
- if (!trackGeom) {
- if (item) {
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
- }
- trackGeom = true;
- }
- } else {
- if (trackGeom) {
- if (item) {
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
- }
- trackGeom = false;
- }
- }
-}
-
-QQuickItemViewTransitioner::TransitionType FxViewItem::scheduledTransitionType() const
-{
- return transitionableItem ? transitionableItem->nextTransitionType : QQuickItemViewTransitioner::NoTransition;
-}
-
-bool FxViewItem::transitionScheduledOrRunning() const
-{
- return transitionableItem ? transitionableItem->transitionScheduledOrRunning() : false;
-}
-
-bool FxViewItem::transitionRunning() const
-{
- return transitionableItem ? transitionableItem->transitionRunning() : false;
-}
-
-bool FxViewItem::isPendingRemoval() const
-{
- return transitionableItem ? transitionableItem->isPendingRemoval() : false;
-}
-
-void FxViewItem::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
-{
- if (!transitioner)
- return;
- if (!transitionableItem)
- transitionableItem = new QQuickItemViewTransitionableItem(item);
- transitioner->transitionNextReposition(transitionableItem, type, asTarget);
-}
-
-bool FxViewItem::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds)
-{
- return transitionableItem ? transitionableItem->prepareTransition(transitioner, index, viewBounds) : false;
-}
-
-void FxViewItem::startTransition(QQuickItemViewTransitioner *transitioner)
-{
- if (transitionableItem)
- transitionableItem->startTransition(transitioner, index);
-}
-
-
QQuickItemViewChangeSet::QQuickItemViewChangeSet()
: active(false)
{
@@ -275,7 +173,7 @@ QQuickItemView::~QQuickItemView()
QQuickItem *QQuickItemView::currentItem() const
{
Q_D(const QQuickItemView);
- return d->currentItem ? d->currentItem->item : 0;
+ return d->currentItem ? d->currentItem->item : nullptr;
}
QVariant QQuickItemView::model() const
@@ -304,12 +202,12 @@ void QQuickItemView::setModel(const QVariant &m)
QQmlInstanceModel *oldModel = d->model;
d->clear();
- d->model = 0;
+ d->model = nullptr;
d->setPosition(d->contentStartOffset());
d->modelVariant = model;
QObject *object = qvariant_cast<QObject*>(model);
- QQmlInstanceModel *vim = 0;
+ QQmlInstanceModel *vim = nullptr;
if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
if (d->ownModel) {
delete oldModel;
@@ -362,7 +260,7 @@ QQmlComponent *QQuickItemView::delegate() const
return dataModel->delegate();
}
- return 0;
+ return nullptr;
}
void QQuickItemView::setDelegate(QQmlComponent *delegate)
@@ -380,11 +278,9 @@ void QQuickItemView::setDelegate(QQmlComponent *delegate)
int oldCount = dataModel->count();
dataModel->setDelegate(delegate);
if (isComponentComplete()) {
- for (FxViewItem *item : qAsConst(d->visibleItems))
- d->releaseItem(item);
- d->visibleItems.clear();
+ d->releaseVisibleItems();
d->releaseItem(d->currentItem);
- d->currentItem = 0;
+ d->currentItem = nullptr;
d->updateSectionCriteria();
d->refill();
d->moveReason = QQuickItemViewPrivate::SetIndex;
@@ -588,7 +484,7 @@ QQmlComponent *QQuickItemView::header() const
QQuickItem *QQuickItemView::headerItem() const
{
Q_D(const QQuickItemView);
- return d->header ? d->header->item : 0;
+ return d->header ? d->header->item : nullptr;
}
void QQuickItemView::setHeader(QQmlComponent *headerComponent)
@@ -597,7 +493,7 @@ void QQuickItemView::setHeader(QQmlComponent *headerComponent)
if (d->headerComponent != headerComponent) {
d->applyPendingChanges();
delete d->header;
- d->header = 0;
+ d->header = nullptr;
d->headerComponent = headerComponent;
d->markExtentsDirty();
@@ -623,7 +519,7 @@ QQmlComponent *QQuickItemView::footer() const
QQuickItem *QQuickItemView::footerItem() const
{
Q_D(const QQuickItemView);
- return d->footer ? d->footer->item : 0;
+ return d->footer ? d->footer->item : nullptr;
}
void QQuickItemView::setFooter(QQmlComponent *footerComponent)
@@ -632,7 +528,7 @@ void QQuickItemView::setFooter(QQmlComponent *footerComponent)
if (d->footerComponent != footerComponent) {
d->applyPendingChanges();
delete d->footer;
- d->footer = 0;
+ d->footer = nullptr;
d->footerComponent = footerComponent;
if (isComponentComplete()) {
@@ -668,7 +564,7 @@ void QQuickItemView::setHighlight(QQmlComponent *highlightComponent)
QQuickItem *QQuickItemView::highlightItem() const
{
Q_D(const QQuickItemView);
- return d->highlight ? d->highlight->item : 0;
+ return d->highlight ? d->highlight->item : nullptr;
}
bool QQuickItemView::highlightFollowsCurrentItem() const
@@ -801,7 +697,7 @@ void QQuickItemView::setHighlightMoveDuration(int duration)
QQuickTransition *QQuickItemView::populateTransition() const
{
Q_D(const QQuickItemView);
- return d->transitioner ? d->transitioner->populateTransition : 0;
+ return d->transitioner ? d->transitioner->populateTransition : nullptr;
}
void QQuickItemView::setPopulateTransition(QQuickTransition *transition)
@@ -817,7 +713,7 @@ void QQuickItemView::setPopulateTransition(QQuickTransition *transition)
QQuickTransition *QQuickItemView::addTransition() const
{
Q_D(const QQuickItemView);
- return d->transitioner ? d->transitioner->addTransition : 0;
+ return d->transitioner ? d->transitioner->addTransition : nullptr;
}
void QQuickItemView::setAddTransition(QQuickTransition *transition)
@@ -833,7 +729,7 @@ void QQuickItemView::setAddTransition(QQuickTransition *transition)
QQuickTransition *QQuickItemView::addDisplacedTransition() const
{
Q_D(const QQuickItemView);
- return d->transitioner ? d->transitioner->addDisplacedTransition : 0;
+ return d->transitioner ? d->transitioner->addDisplacedTransition : nullptr;
}
void QQuickItemView::setAddDisplacedTransition(QQuickTransition *transition)
@@ -849,7 +745,7 @@ void QQuickItemView::setAddDisplacedTransition(QQuickTransition *transition)
QQuickTransition *QQuickItemView::moveTransition() const
{
Q_D(const QQuickItemView);
- return d->transitioner ? d->transitioner->moveTransition : 0;
+ return d->transitioner ? d->transitioner->moveTransition : nullptr;
}
void QQuickItemView::setMoveTransition(QQuickTransition *transition)
@@ -865,7 +761,7 @@ void QQuickItemView::setMoveTransition(QQuickTransition *transition)
QQuickTransition *QQuickItemView::moveDisplacedTransition() const
{
Q_D(const QQuickItemView);
- return d->transitioner ? d->transitioner->moveDisplacedTransition : 0;
+ return d->transitioner ? d->transitioner->moveDisplacedTransition : nullptr;
}
void QQuickItemView::setMoveDisplacedTransition(QQuickTransition *transition)
@@ -881,7 +777,7 @@ void QQuickItemView::setMoveDisplacedTransition(QQuickTransition *transition)
QQuickTransition *QQuickItemView::removeTransition() const
{
Q_D(const QQuickItemView);
- return d->transitioner ? d->transitioner->removeTransition : 0;
+ return d->transitioner ? d->transitioner->removeTransition : nullptr;
}
void QQuickItemView::setRemoveTransition(QQuickTransition *transition)
@@ -897,7 +793,7 @@ void QQuickItemView::setRemoveTransition(QQuickTransition *transition)
QQuickTransition *QQuickItemView::removeDisplacedTransition() const
{
Q_D(const QQuickItemView);
- return d->transitioner ? d->transitioner->removeDisplacedTransition : 0;
+ return d->transitioner ? d->transitioner->removeDisplacedTransition : nullptr;
}
void QQuickItemView::setRemoveDisplacedTransition(QQuickTransition *transition)
@@ -913,7 +809,7 @@ void QQuickItemView::setRemoveDisplacedTransition(QQuickTransition *transition)
QQuickTransition *QQuickItemView::displacedTransition() const
{
Q_D(const QQuickItemView);
- return d->transitioner ? d->transitioner->displacedTransition : 0;
+ return d->transitioner ? d->transitioner->displacedTransition : nullptr;
}
void QQuickItemView::setDisplacedTransition(QQuickTransition *transition)
@@ -928,12 +824,13 @@ void QQuickItemView::setDisplacedTransition(QQuickTransition *transition)
void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode)
{
- Q_Q(QQuickItemView);
if (!isValid())
return;
if (mode < QQuickItemView::Beginning || mode > QQuickItemView::SnapPosition)
return;
+ Q_Q(QQuickItemView);
+ q->cancelFlick();
applyPendingChanges();
const int modelCount = model->count();
int idx = qMax(qMin(index, modelCount - 1), 0);
@@ -955,11 +852,16 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode)
item = visibleItem(idx);
}
if (item) {
+ const bool stickyHeader = hasStickyHeader();
+ const bool stickyFooter = hasStickyFooter();
+ const qreal stickyHeaderSize = stickyHeader ? headerSize() : 0;
+ const qreal stickyFooterSize = stickyFooter ? footerSize() : 0;
+
const qreal itemPos = item->position();
switch (mode) {
case QQuickItemView::Beginning:
pos = itemPos;
- if (header && (index < 0 || hasStickyHeader()))
+ if (header && (index < 0 || stickyHeader))
pos -= headerSize();
break;
case QQuickItemView::Center:
@@ -967,30 +869,29 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode)
break;
case QQuickItemView::End:
pos = itemPos - viewSize + item->size();
- if (footer && (index >= modelCount || hasStickyFooter()))
+ if (footer && (index >= modelCount || stickyFooter))
pos += footerSize();
break;
case QQuickItemView::Visible:
- if (itemPos > pos + viewSize)
- pos = itemPos - viewSize + item->size();
- else if (item->endPosition() <= pos)
- pos = itemPos;
+ if (itemPos > pos + viewSize - stickyFooterSize)
+ pos = item->endPosition() - viewSize + stickyFooterSize;
+ else if (item->endPosition() <= pos - stickyHeaderSize)
+ pos = itemPos - stickyHeaderSize;
break;
case QQuickItemView::Contain:
- if (item->endPosition() >= pos + viewSize)
- pos = itemPos - viewSize + item->size();
- if (itemPos < pos)
- pos = itemPos;
+ if (item->endPosition() >= pos + viewSize + stickyFooterSize)
+ pos = itemPos - viewSize + item->size() + stickyFooterSize;
+ if (itemPos - stickyHeaderSize < pos)
+ pos = itemPos - stickyHeaderSize;
break;
case QQuickItemView::SnapPosition:
- pos = itemPos - highlightRangeStart;
+ pos = itemPos - highlightRangeStart - stickyHeaderSize;
break;
}
pos = qMin(pos, maxExtent);
qreal minExtent = calculatedMinExtent();
pos = qMax(pos, minExtent);
moveReason = QQuickItemViewPrivate::Other;
- q->cancelFlick();
setPosition(pos);
if (highlight) {
@@ -1050,6 +951,13 @@ QQuickItem *QQuickItemView::itemAt(qreal x, qreal y) const
return item ? item->item : nullptr;
}
+QQuickItem *QQuickItemView::itemAtIndex(int index) const
+{
+ Q_D(const QQuickItemView);
+ const FxViewItem *item = d->visibleItem(index);
+ return item ? item->item : nullptr;
+}
+
void QQuickItemView::forceLayout()
{
Q_D(QQuickItemView);
@@ -1233,7 +1141,7 @@ void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometry
// start new transitions
bool prevInLayout = inLayout;
if (!inLayout) {
- FxViewItem *actualItem = transitioner ? visibleItem(currentIndex) : 0;
+ FxViewItem *actualItem = transitioner ? visibleItem(currentIndex) : nullptr;
if (actualItem && actualItem->transitionRunning())
inLayout = true;
}
@@ -1248,16 +1156,26 @@ void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometry
void QQuickItemView::destroyRemoved()
{
Q_D(QQuickItemView);
+
+ bool hasRemoveTransition = false;
+ bool hasRemoveTransitionAsTarget = false;
+ if (d->transitioner) {
+ hasRemoveTransition = d->transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false);
+ hasRemoveTransitionAsTarget = d->transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, true);
+ }
+
for (QList<FxViewItem*>::Iterator it = d->visibleItems.begin();
it != d->visibleItems.end();) {
FxViewItem *item = *it;
if (item->index == -1 && (!item->attached || item->attached->delayRemove() == false)) {
- if (d->transitioner && d->transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, true)) {
+ if (hasRemoveTransitionAsTarget) {
// don't remove from visibleItems until next layout()
d->runDelayedRemoveTransition = true;
QObject::disconnect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()));
++it;
} else {
+ if (hasRemoveTransition)
+ d->runDelayedRemoveTransition = true;
d->releaseItem(item);
it = d->visibleItems.erase(it);
}
@@ -1274,6 +1192,7 @@ void QQuickItemView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
{
Q_D(QQuickItemView);
if (reset) {
+ cancelFlick();
if (d->transitioner)
d->transitioner->setPopulateTransitionEnabled(true);
d->moveReason = QQuickItemViewPrivate::SetIndex;
@@ -1318,6 +1237,12 @@ void QQuickItemView::trackedPositionChanged()
Q_D(QQuickItemView);
if (!d->trackedItem || !d->currentItem)
return;
+
+ if (d->inLayout) {
+ polish();
+ return;
+ }
+
if (d->moveReason == QQuickItemViewPrivate::SetIndex) {
qreal trackedPos = d->trackedItem->position();
qreal trackedSize = d->trackedItem->size();
@@ -1386,7 +1311,6 @@ void QQuickItemView::trackedPositionChanged()
pos = qMax(trackedPos, toItemPos);
}
if (viewPos != pos) {
- cancelFlick();
d->calcVelocity = true;
d->setPosition(pos);
d->calcVelocity = false;
@@ -1548,14 +1472,14 @@ QQuickItemViewPrivate::QQuickItemViewPrivate()
, layoutDirection(Qt::LeftToRight), verticalLayoutDirection(QQuickItemView::TopToBottom)
, moveReason(Other)
, visibleIndex(0)
- , currentIndex(-1), currentItem(0)
- , trackedItem(0), requestedIndex(-1)
- , highlightComponent(0), highlight(0)
+ , currentIndex(-1), currentItem(nullptr)
+ , trackedItem(nullptr), requestedIndex(-1)
+ , highlightComponent(nullptr), highlight(nullptr)
, highlightRange(QQuickItemView::NoHighlightRange)
, highlightRangeStart(0), highlightRangeEnd(0)
, highlightMoveDuration(150)
- , headerComponent(0), header(0), footerComponent(0), footer(0)
- , transitioner(0)
+ , headerComponent(nullptr), header(nullptr), footerComponent(nullptr), footer(nullptr)
+ , transitioner(nullptr)
, minExtent(0), maxExtent(0)
, ownModel(false), wrap(false)
, keyNavigationEnabled(true)
@@ -1573,7 +1497,7 @@ QQuickItemViewPrivate::QQuickItemViewPrivate()
QQuickItemViewPrivate::~QQuickItemViewPrivate()
{
if (transitioner)
- transitioner->setChangeListener(0);
+ transitioner->setChangeListener(nullptr);
delete transitioner;
}
@@ -1639,7 +1563,7 @@ FxViewItem *QQuickItemViewPrivate::visibleItem(int modelIndex) const {
return item;
}
}
- return 0;
+ return nullptr;
}
// should rename to firstItemInView() to avoid confusion with other "*visible*" methods
@@ -1699,7 +1623,7 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
if (currentItem->attached)
currentItem->attached->setIsCurrentItem(false);
releaseItem(currentItem);
- currentItem = 0;
+ currentItem = nullptr;
currentIndex = modelIndex;
emit q->currentIndexChanged();
emit q->currentItemChanged();
@@ -1719,7 +1643,7 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
FxViewItem *oldCurrentItem = currentItem;
int oldCurrentIndex = currentIndex;
currentIndex = modelIndex;
- currentItem = createItem(modelIndex, false);
+ currentItem = createItem(modelIndex, QQmlIncubator::AsynchronousIfNested);
if (oldCurrentItem && oldCurrentItem->attached && (!currentItem || oldCurrentItem->item != currentItem->item))
oldCurrentItem->attached->setIsCurrentItem(false);
if (currentItem) {
@@ -1740,12 +1664,12 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
void QQuickItemViewPrivate::clear()
{
+ Q_Q(QQuickItemView);
currentChanges.reset();
+ bufferedChanges.reset();
timeline.clear();
- for (FxViewItem *item : qAsConst(visibleItems))
- releaseItem(item);
- visibleItems.clear();
+ releaseVisibleItems();
visibleIndex = 0;
for (FxViewItem *item : qAsConst(releasePendingTransition)) {
@@ -1754,10 +1678,13 @@ void QQuickItemViewPrivate::clear()
}
releasePendingTransition.clear();
+ auto oldCurrentItem = currentItem;
releaseItem(currentItem);
- currentItem = 0;
+ currentItem = nullptr;
+ if (oldCurrentItem)
+ emit q->currentItemChanged();
createHighlight();
- trackedItem = 0;
+ trackedItem = nullptr;
if (requestedIndex >= 0) {
if (model)
@@ -1800,56 +1727,61 @@ void QQuickItemViewPrivate::refill(qreal from, qreal to)
if (!isValid() || !q->isComponentComplete())
return;
- bufferPause.stop();
- currentChanges.reset();
+ do {
+ bufferPause.stop();
+ if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges()) {
+ currentChanges.reset();
+ bufferedChanges.reset();
+ releaseVisibleItems();
+ }
- int prevCount = itemCount;
- itemCount = model->count();
- qreal bufferFrom = from - buffer;
- qreal bufferTo = to + buffer;
- qreal fillFrom = from;
- qreal fillTo = to;
-
- bool added = addVisibleItems(fillFrom, fillTo, bufferFrom, bufferTo, false);
- bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
-
- if (requestedIndex == -1 && buffer && bufferMode != NoBuffer) {
- if (added) {
- // We've already created a new delegate this frame.
- // Just schedule a buffer refill.
- bufferPause.start();
- } else {
- if (bufferMode & BufferAfter)
- fillTo = bufferTo;
- if (bufferMode & BufferBefore)
- fillFrom = bufferFrom;
- added |= addVisibleItems(fillFrom, fillTo, bufferFrom, bufferTo, true);
+ int prevCount = itemCount;
+ itemCount = model->count();
+ qreal bufferFrom = from - buffer;
+ qreal bufferTo = to + buffer;
+ qreal fillFrom = from;
+ qreal fillTo = to;
+
+ bool added = addVisibleItems(fillFrom, fillTo, bufferFrom, bufferTo, false);
+ bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
+
+ if (requestedIndex == -1 && buffer && bufferMode != NoBuffer) {
+ if (added) {
+ // We've already created a new delegate this frame.
+ // Just schedule a buffer refill.
+ bufferPause.start();
+ } else {
+ if (bufferMode & BufferAfter)
+ fillTo = bufferTo;
+ if (bufferMode & BufferBefore)
+ fillFrom = bufferFrom;
+ added |= addVisibleItems(fillFrom, fillTo, bufferFrom, bufferTo, true);
+ }
}
- }
- if (added || removed) {
- markExtentsDirty();
- updateBeginningEnd();
- visibleItemsChanged();
- updateHeader();
- updateFooter();
- updateViewport();
- }
+ if (added || removed) {
+ markExtentsDirty();
+ updateBeginningEnd();
+ visibleItemsChanged();
+ updateHeader();
+ updateFooter();
+ updateViewport();
+ }
- if (prevCount != itemCount)
- emit q->countChanged();
+ if (prevCount != itemCount)
+ emit q->countChanged();
+ } while (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges());
}
void QQuickItemViewPrivate::regenerate(bool orientationChanged)
{
Q_Q(QQuickItemView);
if (q->isComponentComplete()) {
- currentChanges.reset();
if (orientationChanged) {
delete header;
- header = 0;
+ header = nullptr;
delete footer;
- footer = 0;
+ footer = nullptr;
}
clear();
updateHeader();
@@ -1880,6 +1812,9 @@ void QQuickItemViewPrivate::layout()
inLayout = true;
+ // viewBounds contains bounds before any add/remove/move operation to the view
+ QRectF viewBounds(q->contentX(), q->contentY(), q->width(), q->height());
+
if (!isValid() && !visibleItems.count()) {
clear();
setPosition(contentStartOffset());
@@ -1925,7 +1860,7 @@ void QQuickItemViewPrivate::layout()
markExtentsDirty();
updateHighlight();
- if (!q->isMoving() && !q->isFlicking()) {
+ if (!q->isMoving() && !q->isFlicking() && !movingFromHighlight()) {
fixupPosition();
refill();
}
@@ -1938,14 +1873,14 @@ void QQuickItemViewPrivate::layout()
if (transitioner) {
// items added in the last refill() may need to be transitioned in - e.g. a remove
// causes items to slide up into view
- if (transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, false)
- || transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false)) {
+ if (lastIndexInView != -1 &&
+ (transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, false)
+ || transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false))) {
translateAndTransitionItemsAfter(lastIndexInView, insertionPosChanges, removalPosChanges);
}
prepareVisibleItemTransitions();
- QRectF viewBounds(q->contentX(), q->contentY(), q->width(), q->height());
for (QList<FxViewItem*>::Iterator it = releasePendingTransition.begin();
it != releasePendingTransition.end(); ) {
FxViewItem *item = *it;
@@ -1982,7 +1917,6 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
}
updateUnrequestedIndexes();
- moveReason = QQuickItemViewPrivate::Other;
FxViewItem *prevVisibleItemsFirst = visibleItems.count() ? *visibleItems.constBegin() : 0;
int prevItemCount = itemCount;
@@ -2104,8 +2038,11 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
if (currentChanges.currentRemoved && currentItem) {
if (currentItem->item && currentItem->attached)
currentItem->attached->setIsCurrentItem(false);
+ auto oldCurrentItem = currentItem;
releaseItem(currentItem);
- currentItem = 0;
+ currentItem = nullptr;
+ if (oldCurrentItem)
+ emit q->currentItemChanged();
}
if (!currentIndexCleared)
updateCurrent(currentChanges.newCurrentIndex);
@@ -2317,12 +2254,12 @@ void QQuickItemViewPrivate::viewItemTransitionFinished(QQuickItemViewTransitiona
When the item becomes available, refill() will be called and the item
will be returned on the next call to createItem().
*/
-FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, bool asynchronous)
+FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, QQmlIncubator::IncubationMode incubationMode)
{
Q_Q(QQuickItemView);
- if (requestedIndex == modelIndex && asynchronous)
- return 0;
+ if (requestedIndex == modelIndex && incubationMode == QQmlIncubator::Asynchronous)
+ return nullptr;
for (int i=0; i<releasePendingTransition.count(); i++) {
if (releasePendingTransition.at(i)->index == modelIndex
@@ -2332,14 +2269,20 @@ FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, bool asynchronous)
}
}
- if (asynchronous)
- requestedIndex = modelIndex;
inRequest = true;
- QObject* object = model->object(modelIndex, asynchronous);
+ QObject* object = model->object(modelIndex, incubationMode);
QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
+
if (!item) {
- if (object) {
+ if (!object) {
+ if (requestedIndex == -1 && model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
+ // The reason we didn't receive an item is because it's incubating async. We keep track
+ // of this by assigning the index we're waiting for to 'requestedIndex'. This will e.g. let
+ // the view avoid unnecessary layout calls until the item has been loaded.
+ requestedIndex = modelIndex;
+ }
+ } else {
model->release(object);
if (!delegateValidated) {
delegateValidated = true;
@@ -2348,7 +2291,7 @@ FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, bool asynchronous)
}
}
inRequest = false;
- return 0;
+ return nullptr;
} else {
item->setParentItem(q->contentItem());
if (requestedIndex == modelIndex)
@@ -2401,7 +2344,7 @@ void QQuickItemView::destroyingItem(QObject *object)
Q_D(QQuickItemView);
QQuickItem* item = qmlobject_cast<QQuickItem*>(object);
if (item) {
- item->setParentItem(0);
+ item->setParentItem(nullptr);
d->unrequestedItems.remove(item);
}
}
@@ -2412,7 +2355,7 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
if (!item || !model)
return true;
if (trackedItem == item)
- trackedItem = 0;
+ trackedItem = nullptr;
item->trackGeometry(false);
QQmlInstanceModel::ReleaseFlags flags = model->release(item->item);
@@ -2422,7 +2365,7 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
QQuickItemPrivate::get(item->item)->setCulled(true);
unrequestedItems.insert(item->item, model->indexOf(item->item, q));
} else if (flags & QQmlInstanceModel::Destroyed) {
- item->item->setParentItem(0);
+ item->item->setParentItem(nullptr);
}
}
delete item;
@@ -2438,7 +2381,7 @@ QQuickItem *QQuickItemViewPrivate::createComponentItem(QQmlComponent *component,
{
Q_Q(const QQuickItemView);
- QQuickItem *item = 0;
+ QQuickItem *item = nullptr;
if (component) {
QQmlContext *creationContext = component->creationContext();
QQmlContext *context = new QQmlContext(
diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h
index b38bc6174f..0a0da587b4 100644
--- a/src/quick/items/qquickitemview_p.h
+++ b/src/quick/items/qquickitemview_p.h
@@ -128,7 +128,7 @@ public:
};
Q_ENUM(VerticalLayoutDirection)
- QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent = 0);
+ QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent = nullptr);
~QQuickItemView();
QVariant model() const;
@@ -228,6 +228,7 @@ public:
Q_INVOKABLE void positionViewAtIndex(int index, int mode);
Q_INVOKABLE int indexAt(qreal x, qreal y) const;
Q_INVOKABLE QQuickItem *itemAt(qreal x, qreal y) const;
+ Q_REVISION(13) Q_INVOKABLE QQuickItem *itemAtIndex(int index) const;
Q_INVOKABLE void positionViewAtBeginning();
Q_INVOKABLE void positionViewAtEnd();
Q_REVISION(1) Q_INVOKABLE void forceLayout();
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index 3087682ac7..ea5b5df9c6 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -56,6 +56,7 @@
QT_REQUIRE_CONFIG(quick_itemview);
#include "qquickitemview_p.h"
+#include "qquickitemviewfxitem_p_p.h"
#include "qquickitemviewtransition_p.h"
#include "qquickflickable_p_p.h"
#include <QtQml/private/qqmlobjectmodel_p.h>
@@ -65,47 +66,13 @@ QT_REQUIRE_CONFIG(quick_itemview);
QT_BEGIN_NAMESPACE
-
-class Q_AUTOTEST_EXPORT FxViewItem
+class Q_AUTOTEST_EXPORT FxViewItem : public QQuickItemViewFxItem
{
public:
FxViewItem(QQuickItem *, QQuickItemView *, bool own, QQuickItemViewAttached *attached);
- virtual ~FxViewItem();
-
- qreal itemX() const;
- qreal itemY() const;
- inline qreal itemWidth() const { return item ? item->width() : 0; }
- inline qreal itemHeight() const { return item ? item->height() : 0; }
-
- void moveTo(const QPointF &pos, bool immediate);
- void setVisible(bool visible);
- void trackGeometry(bool track);
-
- QQuickItemViewTransitioner::TransitionType scheduledTransitionType() const;
- bool transitionScheduledOrRunning() const;
- bool transitionRunning() const;
- bool isPendingRemoval() const;
-
- void transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget);
- bool prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds);
- void startTransition(QQuickItemViewTransitioner *transitioner);
- // these are positions and sizes along the current direction of scrolling/flicking
- virtual qreal position() const = 0;
- virtual qreal endPosition() const = 0;
- virtual qreal size() const = 0;
- virtual qreal sectionSize() const = 0;
-
- virtual bool contains(qreal x, qreal y) const = 0;
-
- QPointer<QQuickItem> item;
QQuickItemView *view;
- QQuickItemViewTransitionableItem *transitionableItem;
QQuickItemViewAttached *attached;
- int index;
- bool ownItem;
- bool releaseAfterTransition;
- bool trackGeom;
};
@@ -201,12 +168,12 @@ public:
void regenerate(bool orientationChanged=false);
void layout();
- virtual void animationFinished(QAbstractAnimationJob *) override;
+ void animationFinished(QAbstractAnimationJob *) override;
void refill();
void refill(qreal from, qreal to);
void mirrorChange() override;
- FxViewItem *createItem(int modelIndex, bool asynchronous = false);
+ FxViewItem *createItem(int modelIndex,QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested);
virtual bool releaseItem(FxViewItem *item);
QQuickItem *createHighlightItem() const;
@@ -269,6 +236,15 @@ public:
q->polish();
}
+ void releaseVisibleItems() {
+ // make a copy and clear the visibleItems first to avoid destroyed
+ // items being accessed during the loop (QTBUG-61294)
+ const QList<FxViewItem *> oldVisible = visibleItems;
+ visibleItems.clear();
+ for (FxViewItem *item : oldVisible)
+ releaseItem(item);
+ }
+
QPointer<QQmlInstanceModel> model;
QVariant modelVariant;
int itemCount;
@@ -354,6 +330,7 @@ protected:
virtual void createHighlight() = 0;
virtual void updateHighlight() = 0;
virtual void resetHighlightPosition() = 0;
+ virtual bool movingFromHighlight() { return false; }
virtual void setPosition(qreal pos) = 0;
virtual void fixupPosition() = 0;
diff --git a/src/quick/items/qquickitemviewfxitem.cpp b/src/quick/items/qquickitemviewfxitem.cpp
new file mode 100644
index 0000000000..60e9d7b115
--- /dev/null
+++ b/src/quick/items/qquickitemviewfxitem.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickitemviewfxitem_p_p.h"
+#include "qquickitem_p.h"
+#include "qquickitemview_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQuickItemViewFxItem::QQuickItemViewFxItem(QQuickItem *item, bool ownItem, QQuickItemChangeListener* changeListener)
+ : item(item)
+ , changeListener(changeListener)
+ , transitionableItem(nullptr)
+ , ownItem(ownItem)
+ , releaseAfterTransition(false)
+ , trackGeom(false)
+{
+}
+
+QQuickItemViewFxItem::~QQuickItemViewFxItem()
+{
+ delete transitionableItem;
+ if (ownItem && item) {
+ trackGeometry(false);
+ item->setParentItem(0);
+ item->deleteLater();
+ }
+}
+
+qreal QQuickItemViewFxItem::itemX() const
+{
+ return transitionableItem ? transitionableItem->itemX() : (item ? item->x() : 0);
+}
+
+qreal QQuickItemViewFxItem::itemY() const
+{
+ return transitionableItem ? transitionableItem->itemY() : (item ? item->y() : 0);
+}
+
+void QQuickItemViewFxItem::moveTo(const QPointF &pos, bool immediate)
+{
+ if (transitionableItem)
+ transitionableItem->moveTo(pos, immediate);
+ else if (item)
+ item->setPosition(pos);
+}
+
+void QQuickItemViewFxItem::setVisible(bool visible)
+{
+ if (!visible && transitionableItem && transitionableItem->transitionScheduledOrRunning())
+ return;
+ if (item)
+ QQuickItemPrivate::get(item)->setCulled(!visible);
+}
+
+void QQuickItemViewFxItem::trackGeometry(bool track)
+{
+ if (track) {
+ if (!trackGeom) {
+ if (item) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(changeListener, QQuickItemPrivate::Geometry);
+ }
+ trackGeom = true;
+ }
+ } else {
+ if (trackGeom) {
+ if (item) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->removeItemChangeListener(changeListener, QQuickItemPrivate::Geometry);
+ }
+ trackGeom = false;
+ }
+ }
+}
+
+QRectF QQuickItemViewFxItem::geometry() const
+{
+ return QRectF(item->position(), item->size());
+}
+
+void QQuickItemViewFxItem::setGeometry(const QRectF &geometry)
+{
+ item->setPosition(geometry.topLeft());
+ item->setSize(geometry.size());
+}
+
+QQuickItemViewTransitioner::TransitionType QQuickItemViewFxItem::scheduledTransitionType() const
+{
+ return transitionableItem ? transitionableItem->nextTransitionType : QQuickItemViewTransitioner::NoTransition;
+}
+
+bool QQuickItemViewFxItem::transitionScheduledOrRunning() const
+{
+ return transitionableItem ? transitionableItem->transitionScheduledOrRunning() : false;
+}
+
+bool QQuickItemViewFxItem::transitionRunning() const
+{
+ return transitionableItem ? transitionableItem->transitionRunning() : false;
+}
+
+bool QQuickItemViewFxItem::isPendingRemoval() const
+{
+ return transitionableItem ? transitionableItem->isPendingRemoval() : false;
+}
+
+void QQuickItemViewFxItem::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
+{
+ if (!transitioner)
+ return;
+ if (!transitionableItem)
+ transitionableItem = new QQuickItemViewTransitionableItem(item);
+ transitioner->transitionNextReposition(transitionableItem, type, asTarget);
+}
+
+bool QQuickItemViewFxItem::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds)
+{
+ return transitionableItem ? transitionableItem->prepareTransition(transitioner, index, viewBounds) : false;
+}
+
+void QQuickItemViewFxItem::startTransition(QQuickItemViewTransitioner *transitioner)
+{
+ if (transitionableItem)
+ transitionableItem->startTransition(transitioner, index);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/quick/items/qquickitemviewfxitem_p_p.h b/src/quick/items/qquickitemviewfxitem_p_p.h
new file mode 100644
index 0000000000..3bc5ba440c
--- /dev/null
+++ b/src/quick/items/qquickitemviewfxitem_p_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFXVIEWITEM_P_P_H
+#define QQUICKFXVIEWITEM_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qtquickglobal_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickitemviewtransition_p.h>
+
+QT_REQUIRE_CONFIG(quick_itemview);
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQuickItemViewFxItem
+{
+public:
+ QQuickItemViewFxItem(QQuickItem *item, bool ownItem, QQuickItemChangeListener *changeListener);
+ virtual ~QQuickItemViewFxItem();
+
+ qreal itemX() const;
+ qreal itemY() const;
+ inline qreal itemWidth() const { return item ? item->width() : 0; }
+ inline qreal itemHeight() const { return item ? item->height() : 0; }
+
+ void moveTo(const QPointF &pos, bool immediate);
+ void setVisible(bool visible);
+ void trackGeometry(bool track);
+
+ QRectF geometry() const;
+ void setGeometry(const QRectF &geometry);
+
+ QQuickItemViewTransitioner::TransitionType scheduledTransitionType() const;
+ bool transitionScheduledOrRunning() const;
+ bool transitionRunning() const;
+ bool isPendingRemoval() const;
+
+ void transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget);
+ bool prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds);
+ void startTransition(QQuickItemViewTransitioner *transitioner);
+
+ // these are positions and sizes along the current direction of scrolling/flicking
+ virtual qreal position() const = 0;
+ virtual qreal endPosition() const = 0;
+ virtual qreal size() const = 0;
+ virtual qreal sectionSize() const = 0;
+
+ virtual bool contains(qreal x, qreal y) const = 0;
+
+ QPointer<QQuickItem> item;
+ QQuickItemChangeListener *changeListener;
+ QQuickItemViewTransitionableItem *transitionableItem;
+ int index = -1;
+ bool ownItem : 1;
+ bool releaseAfterTransition : 1;
+ bool trackGeom : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFXVIEWITEM_P_P_H
diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp
index 04d93937eb..0fde0beb75 100644
--- a/src/quick/items/qquickitemviewtransition.cpp
+++ b/src/quick/items/qquickitemviewtransition.cpp
@@ -69,11 +69,11 @@ protected:
QQuickItemViewTransitionJob::QQuickItemViewTransitionJob()
- : m_transitioner(0)
- , m_item(0)
+ : m_transitioner(nullptr)
+ , m_item(nullptr)
, m_type(QQuickItemViewTransitioner::NoTransition)
, m_isTarget(false)
- , m_wasDeleted(0)
+ , m_wasDeleted(nullptr)
{
}
@@ -143,12 +143,12 @@ void QQuickItemViewTransitionJob::finished()
m_transitioner->finishedTransition(this, m_item);
if (deleted)
return;
- m_wasDeleted = 0;
+ m_wasDeleted = nullptr;
- m_transitioner = 0;
+ m_transitioner = nullptr;
}
- m_item = 0;
+ m_item = nullptr;
m_toPos.setX(0);
m_toPos.setY(0);
m_type = QQuickItemViewTransitioner::NoTransition;
@@ -157,12 +157,12 @@ void QQuickItemViewTransitionJob::finished()
QQuickItemViewTransitioner::QQuickItemViewTransitioner()
- : populateTransition(0)
- , addTransition(0), addDisplacedTransition(0)
- , moveTransition(0), moveDisplacedTransition(0)
- , removeTransition(0), removeDisplacedTransition(0)
- , displacedTransition(0)
- , changeListener(0)
+ : populateTransition(nullptr)
+ , addTransition(nullptr), addDisplacedTransition(nullptr)
+ , moveTransition(nullptr), moveDisplacedTransition(nullptr)
+ , removeTransition(nullptr), removeDisplacedTransition(nullptr)
+ , displacedTransition(nullptr)
+ , changeListener(nullptr)
, usePopulateTransition(false)
{
}
@@ -172,7 +172,7 @@ QQuickItemViewTransitioner::~QQuickItemViewTransitioner()
typedef QSet<QQuickItemViewTransitionJob *>::iterator JobIt;
for (JobIt it = runningJobs.begin(), end = runningJobs.end(); it != end; ++it)
- (*it)->m_transitioner = 0;
+ (*it)->m_transitioner = nullptr;
}
bool QQuickItemViewTransitioner::canTransition(QQuickItemViewTransitioner::TransitionType type, bool asTarget) const
@@ -249,12 +249,12 @@ void QQuickItemViewTransitioner::resetTargetLists()
QQuickTransition *QQuickItemViewTransitioner::transitionObject(QQuickItemViewTransitioner::TransitionType type, bool asTarget) const
{
if (type == QQuickItemViewTransitioner::NoTransition)
- return 0;
+ return nullptr;
if (type == PopulateTransition)
asTarget = true; // no separate displaced transition
- QQuickTransition *trans = 0;
+ QQuickTransition *trans = nullptr;
switch (type) {
case NoTransition:
break;
@@ -276,7 +276,7 @@ QQuickTransition *QQuickItemViewTransitioner::transitionObject(QQuickItemViewTra
trans = displacedTransition;
if (trans && trans->enabled())
return trans;
- return 0;
+ return nullptr;
}
const QList<int> &QQuickItemViewTransitioner::targetIndexes(QQuickItemViewTransitioner::TransitionType type) const
@@ -328,7 +328,7 @@ void QQuickItemViewTransitioner::finishedTransition(QQuickItemViewTransitionJob
QQuickItemViewTransitionableItem::QQuickItemViewTransitionableItem(QQuickItem *i)
: item(i)
- , transition(0)
+ , transition(nullptr)
, nextTransitionType(QQuickItemViewTransitioner::NoTransition)
, isTransitionTarget(false)
, nextTransitionToSet(false)
@@ -500,6 +500,8 @@ void QQuickItemViewTransitionableItem::startTransition(QQuickItemViewTransitione
}
if (!transition || transition->m_type != nextTransitionType || transition->m_isTarget != isTransitionTarget) {
+ if (transition)
+ transition->cancel();
delete transition;
transition = new QQuickItemViewTransitionJob;
}
@@ -563,7 +565,7 @@ void QQuickItemViewTransitionableItem::stopTransition()
QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
- : QObject(parent), m_item(0), m_index(-1)
+ : QObject(parent), m_item(nullptr), m_index(-1)
{
}
/*!
@@ -571,7 +573,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
\instantiates QQuickViewTransitionAttached
\inqmlmodule QtQuick
\ingroup qtquick-transitions-animations
- \brief Specifies items under transition in a view
+ \brief Specifies items under transition in a view.
With ListView and GridView, it is possible to specify transitions that should be applied whenever
the items in the view change as a result of modifications to the view's model. They both have the
@@ -639,7 +641,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
attached property can be used to augment view transitions.
- \section2 View transitions: a simple example
+ \section2 View Transitions: a Simple Example
Here is a basic example of the use of view transitions. The view below specifies transitions for
the \c add and \c displaced properties, which will be run when items are added to the view:
@@ -668,7 +670,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
are some examples of how this can be achieved.
- \section2 Using the ViewTransition attached property
+ \section2 Using the ViewTransition Attached Property
As stated, the various ViewTransition properties provide details specific to the individual item
being transitioned as well as the operation that triggered the transition. In the animation above,
@@ -719,7 +721,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
that is triggered by a particular add operation.
- \section3 Delaying animations based on index
+ \section3 Delaying Animations Based on Index
Since each view transition is run once for each item affected by the transition, the ViewTransition
properties can be used within a transition to define custom behavior for each item's transition.
@@ -738,7 +740,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
\image viewtransitions-delayedbyindex.gif
- \section3 Animating items to intermediate positions
+ \section3 Animating Items to Intermediate Positions
The ViewTransition.item property gives a reference to the item to which the transition is being
applied. This can be used to access any of the item's attributes, custom \c property values,
@@ -775,7 +777,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
\image viewtransitions-pathanim.gif
- \section2 Handling interrupted animations
+ \section2 Handling Interrupted Animations
A view transition may be interrupted at any time if a different view transition needs to be
applied while the original transition is in progress. For example, say Item A is inserted at index 0
@@ -819,7 +821,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
properties.
- \section2 Restrictions regarding ScriptAction
+ \section2 Restrictions Regarding ScriptAction
When a view transition is initialized, any property bindings that refer to the ViewTransition
attached property are evaluated in preparation for the transition. Due to the nature of the
diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h
index 3d2f5361b1..29a62f7f10 100644
--- a/src/quick/items/qquickitemviewtransition_p.h
+++ b/src/quick/items/qquickitemviewtransition_p.h
@@ -58,6 +58,8 @@ QT_REQUIRE_CONFIG(quick_viewtransitions);
#include <QtCore/qobject.h>
#include <QtCore/qpoint.h>
#include <QtQml/qqml.h>
+#include <private/qqmlguard_p.h>
+#include <private/qquicktransition_p.h>
QT_BEGIN_NAMESPACE
@@ -115,14 +117,14 @@ public:
QList<QObject *> moveTransitionTargets;
QList<QObject *> removeTransitionTargets;
- QQuickTransition *populateTransition;
- QQuickTransition *addTransition;
- QQuickTransition *addDisplacedTransition;
- QQuickTransition *moveTransition;
- QQuickTransition *moveDisplacedTransition;
- QQuickTransition *removeTransition;
- QQuickTransition *removeDisplacedTransition;
- QQuickTransition *displacedTransition;
+ QQmlGuard<QQuickTransition> populateTransition;
+ QQmlGuard<QQuickTransition> addTransition;
+ QQmlGuard<QQuickTransition> addDisplacedTransition;
+ QQmlGuard<QQuickTransition> moveTransition;
+ QQmlGuard<QQuickTransition> moveDisplacedTransition;
+ QQmlGuard<QQuickTransition> removeTransition;
+ QQmlGuard<QQuickTransition> removeDisplacedTransition;
+ QQmlGuard<QQuickTransition> displacedTransition;
private:
friend class QQuickItemViewTransitionJob;
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index f739115e6b..81d019a26d 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -101,6 +101,7 @@ public:
void createHighlight() override;
void updateHighlight() override;
void resetHighlightPosition() override;
+ bool movingFromHighlight() override;
void setPosition(qreal pos) override;
void layoutVisibleItems(int fromModelIndex = 0) override;
@@ -175,9 +176,9 @@ public:
, snapMode(QQuickListView::NoSnap)
, headerPositioning(QQuickListView::InlineHeader)
, footerPositioning(QQuickListView::InlineFooter)
- , highlightPosAnimator(0), highlightWidthAnimator(0), highlightHeightAnimator(0)
+ , highlightPosAnimator(nullptr), highlightWidthAnimator(nullptr), highlightHeightAnimator(nullptr)
, highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
- , sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
+ , sectionCriteria(nullptr), currentSectionItem(nullptr), nextSectionItem(nullptr)
, overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
{
highlightMoveDuration = -1; //override default value set in base class
@@ -194,8 +195,8 @@ public:
//----------------------------------------------------------------------------
QQuickViewSection::QQuickViewSection(QQuickListView *parent)
- : QObject(parent), m_criteria(FullString), m_delegate(0), m_labelPositioning(InlineLabels)
- , m_view(parent ? QQuickListViewPrivate::get(parent) : 0)
+ : QObject(parent), m_criteria(FullString), m_delegate(nullptr), m_labelPositioning(InlineLabels)
+ , m_view(parent ? QQuickListViewPrivate::get(parent) : nullptr)
{
}
@@ -257,7 +258,7 @@ public:
}
inline QQuickItem *section() const {
- return item && attached ? static_cast<QQuickListViewAttached*>(attached)->m_sectionItem : 0;
+ return item && attached ? static_cast<QQuickListViewAttached*>(attached)->m_sectionItem : nullptr;
}
void setSection(QQuickItem *s) {
static_cast<QQuickListViewAttached*>(attached)->m_sectionItem = s;
@@ -388,7 +389,7 @@ bool QQuickListViewPrivate::isBottomToTop() const
FxViewItem *QQuickListViewPrivate::itemBefore(int modelIndex) const
{
if (modelIndex < visibleIndex)
- return 0;
+ return nullptr;
int idx = 1;
int lastIndex = -1;
while (idx < visibleItems.count()) {
@@ -401,7 +402,7 @@ FxViewItem *QQuickListViewPrivate::itemBefore(int modelIndex) const
}
if (lastIndex == modelIndex-1)
return visibleItems.constLast();
- return 0;
+ return nullptr;
}
void QQuickListViewPrivate::setPosition(qreal pos)
@@ -514,8 +515,8 @@ QString QQuickListViewPrivate::sectionAt(int modelIndex)
qreal QQuickListViewPrivate::snapPosAt(qreal pos)
{
- if (FxViewItem *snapItem = snapItemAt(pos))
- return snapItem->position();
+ if (FxListItemSG *snapItem = static_cast<FxListItemSG*>(snapItemAt(pos)))
+ return snapItem->itemPosition();
if (visibleItems.count()) {
qreal firstPos = (*visibleItems.constBegin())->position();
qreal endPos = (*(--visibleItems.constEnd()))->position();
@@ -529,17 +530,35 @@ qreal QQuickListViewPrivate::snapPosAt(qreal pos)
FxViewItem *QQuickListViewPrivate::snapItemAt(qreal pos)
{
- FxViewItem *snapItem = 0;
+ const qreal velocity = orient == QQuickListView::Vertical ? vData.velocity : hData.velocity;
+ FxViewItem *snapItem = nullptr;
+ FxViewItem *prevItem = nullptr;
qreal prevItemSize = 0;
for (FxViewItem *item : qAsConst(visibleItems)) {
if (item->index == -1)
continue;
- qreal itemTop = item->position();
- if (highlight && itemTop >= pos && item->endPosition() <= pos + highlight->size())
+
+ const FxListItemSG *listItem = static_cast<FxListItemSG *>(item);
+ qreal itemTop = listItem->position();
+ qreal itemSize = listItem->size();
+ if (highlight && itemTop >= pos && listItem->endPosition() <= pos + highlight->size())
return item;
- if (itemTop+item->size()/2 >= pos && itemTop-prevItemSize/2 < pos)
+
+ if (listItem->section() && velocity > 0) {
+ if (itemTop + listItem->sectionSize() / 2 >= pos && itemTop - prevItemSize / 2 < pos)
+ snapItem = prevItem;
+ itemTop = listItem->itemPosition();
+ itemSize = listItem->itemSize();
+ }
+
+ // Middle of item and spacing (i.e. the middle of the distance between this item and the next
+ qreal halfwayToNextItem = itemTop + (itemSize+spacing) / 2;
+ qreal halfwayToPrevItem = itemTop - (prevItemSize+spacing) / 2;
+ if (halfwayToNextItem >= pos && halfwayToPrevItem < pos)
snapItem = item;
- prevItemSize = item->size();
+
+ prevItemSize = listItem->itemSize();
+ prevItem = item;
}
return snapItem;
}
@@ -560,13 +579,13 @@ void QQuickListViewPrivate::clear()
{
for (int i = 0; i < sectionCacheSize; ++i) {
delete sectionCache[i];
- sectionCache[i] = 0;
+ sectionCache[i] = nullptr;
}
visiblePos = 0;
releaseSectionItem(currentSectionItem);
- currentSectionItem = 0;
+ currentSectionItem = nullptr;
releaseSectionItem(nextSectionItem);
- nextSectionItem = 0;
+ nextSectionItem = nullptr;
lastVisibleSection = QString();
QQuickItemViewPrivate::clear();
}
@@ -628,13 +647,13 @@ bool QQuickListViewPrivate::releaseItem(FxViewItem *item)
if (!sectionCache[i]) {
sectionCache[i] = att->m_sectionItem;
sectionCache[i]->setVisible(false);
- att->m_sectionItem = 0;
+ att->m_sectionItem = nullptr;
break;
}
++i;
} while (i < sectionCacheSize);
delete att->m_sectionItem;
- att->m_sectionItem = 0;
+ att->m_sectionItem = nullptr;
}
return released;
@@ -660,9 +679,7 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
int newModelIdx = qBound(0, modelIndex + count, model->count());
count = newModelIdx - modelIndex;
if (count) {
- for (FxViewItem *item : qAsConst(visibleItems))
- releaseItem(item);
- visibleItems.clear();
+ releaseVisibleItems();
modelIndex = newModelIdx;
visibleIndex = modelIndex;
visiblePos = itemEnd + count * (averageSize + spacing);
@@ -670,11 +687,13 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
}
}
+ QQmlIncubator::IncubationMode incubationMode = doBuffer ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested;
+
bool changed = false;
- FxListItemSG *item = 0;
+ FxListItemSG *item = nullptr;
qreal pos = itemEnd;
while (modelIndex < model->count() && pos <= fillTo) {
- if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, doBuffer))))
+ if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, incubationMode))))
break;
qCDebug(lcItemViewDelegateLifecycle) << "refill: append item" << modelIndex << "pos" << pos << "buffer" << doBuffer << "item" << (QObject *)(item->item);
if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
@@ -691,7 +710,7 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
return changed;
while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
- if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, doBuffer))))
+ if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, incubationMode))))
break;
qCDebug(lcItemViewDelegateLifecycle) << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos << "buffer" << doBuffer << "item" << (QObject *)(item->item);
--visibleIndex;
@@ -721,7 +740,7 @@ void QQuickListViewPrivate::removeItem(FxViewItem *item)
bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
{
- FxViewItem *item = 0;
+ FxViewItem *item = nullptr;
bool changed = false;
// Remove items from the start of the view.
@@ -863,16 +882,16 @@ void QQuickListViewPrivate::createHighlight()
bool changed = false;
if (highlight) {
if (trackedItem == highlight)
- trackedItem = 0;
+ trackedItem = nullptr;
delete highlight;
- highlight = 0;
+ highlight = nullptr;
delete highlightPosAnimator;
delete highlightWidthAnimator;
delete highlightHeightAnimator;
- highlightPosAnimator = 0;
- highlightWidthAnimator = 0;
- highlightHeightAnimator = 0;
+ highlightPosAnimator = nullptr;
+ highlightWidthAnimator = nullptr;
+ highlightHeightAnimator = nullptr;
changed = true;
}
@@ -947,16 +966,27 @@ void QQuickListViewPrivate::resetHighlightPosition()
static_cast<FxListItemSG*>(highlight)->setPosition(static_cast<FxListItemSG*>(currentItem)->itemPosition());
}
+bool QQuickListViewPrivate::movingFromHighlight()
+{
+ if (!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange)
+ return false;
+
+ return (highlightPosAnimator && highlightPosAnimator->isRunning()) ||
+ (highlightHeightAnimator && highlightHeightAnimator->isRunning()) ||
+ (highlightWidthAnimator && highlightWidthAnimator->isRunning());
+}
+
+
QQuickItem * QQuickListViewPrivate::getSectionItem(const QString &section)
{
Q_Q(QQuickListView);
- QQuickItem *sectionItem = 0;
+ QQuickItem *sectionItem = nullptr;
int i = sectionCacheSize-1;
while (i >= 0 && !sectionCache[i])
--i;
if (i >= 0) {
sectionItem = sectionCache[i];
- sectionCache[i] = 0;
+ sectionCache[i] = nullptr;
sectionItem->setVisible(true);
QQmlContext *context = QQmlEngine::contextForObject(sectionItem)->parentContext();
context->setContextProperty(QLatin1String("section"), section);
@@ -1013,13 +1043,13 @@ void QQuickListViewPrivate::releaseSectionItems()
if (listItem->section()) {
qreal pos = listItem->position();
releaseSectionItem(listItem->section());
- listItem->setSection(0);
+ listItem->setSection(nullptr);
listItem->setPosition(pos);
}
}
for (int i = 0; i < sectionCacheSize; ++i) {
delete sectionCache[i];
- sectionCache[i] = 0;
+ sectionCache[i] = nullptr;
}
}
@@ -1041,7 +1071,7 @@ void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
} else if (listItem->section()) {
qreal pos = listItem->position();
releaseSectionItem(listItem->section());
- listItem->setSection(0);
+ listItem->setSection(nullptr);
listItem->setPosition(pos);
}
}
@@ -1057,8 +1087,8 @@ void QQuickListViewPrivate::updateStickySections()
qreal startPos = hasStickyHeader() ? header->endPosition() : viewPos;
qreal endPos = hasStickyFooter() ? footer->position() : viewPos + size();
- QQuickItem *sectionItem = 0;
- QQuickItem *lastSectionItem = 0;
+ QQuickItem *sectionItem = nullptr;
+ QQuickItem *lastSectionItem = nullptr;
int index = 0;
while (index < visibleItems.count()) {
if (QQuickItem *section = static_cast<FxListItemSG *>(visibleItems.at(index))->section()) {
@@ -1117,7 +1147,7 @@ void QQuickListViewPrivate::updateStickySections()
currentSectionItem->setX(pos);
} else if (currentSectionItem) {
releaseSectionItem(currentSectionItem);
- currentSectionItem = 0;
+ currentSectionItem = nullptr;
}
// Next section footer
@@ -1149,7 +1179,7 @@ void QQuickListViewPrivate::updateStickySections()
nextSectionItem->setX(pos);
} else if (nextSectionItem) {
releaseSectionItem(nextSectionItem);
- nextSectionItem = 0;
+ nextSectionItem = nullptr;
}
}
@@ -1165,7 +1195,7 @@ void QQuickListViewPrivate::updateSections()
QString prevSection;
if (visibleIndex > 0)
prevSection = sectionAt(visibleIndex-1);
- QQuickListViewAttached *prevAtt = 0;
+ QQuickListViewAttached *prevAtt = nullptr;
int prevIdx = -1;
int idx = -1;
for (FxViewItem *item : qAsConst(visibleItems)) {
@@ -1456,9 +1486,6 @@ void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometry
void QQuickListViewPrivate::fixupPosition()
{
- if ((haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange)
- || snapMode != QQuickListView::NoSnap)
- moveReason = Other;
if (orient == QQuickListView::Vertical)
fixupY();
else
@@ -1487,7 +1514,7 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) {
// if we've been dragged < averageSize/2 then bias towards the next item
- qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+ qreal dist = data.move.value() - data.pressPos;
qreal bias = 0;
if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < averageSize/2)
bias = averageSize/2;
@@ -1498,13 +1525,13 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
tempPosition -= bias;
}
FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
- if (strictHighlightRange && currentItem && (!topItem || topItem->index != currentIndex)) {
+ if (strictHighlightRange && currentItem && (!topItem || (topItem->index != currentIndex && fixupMode == Immediate))) {
// StrictlyEnforceRange always keeps an item in range
updateHighlight();
topItem = currentItem;
}
FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
- if (strictHighlightRange && currentItem && (!bottomItem || bottomItem->index != currentIndex)) {
+ if (strictHighlightRange && currentItem && (!bottomItem || (bottomItem->index != currentIndex && fixupMode == Immediate))) {
// StrictlyEnforceRange always keeps an item in range
updateHighlight();
bottomItem = currentItem;
@@ -1516,15 +1543,15 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
pos = isContentFlowReversed() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart;
} else {
if (isContentFlowReversed())
- pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
+ pos = qMax(qMin(-static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size(), -maxExtent), -minExtent);
else
- pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
+ pos = qMax(qMin(static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart, -maxExtent), -minExtent);
}
} else if (bottomItem && isInBounds) {
if (isContentFlowReversed())
- pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
+ pos = qMax(qMin(-static_cast<FxListItemSG*>(bottomItem)->itemPosition() + highlightRangeEnd - size(), -maxExtent), -minExtent);
else
- pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
+ pos = qMax(qMin(static_cast<FxListItemSG*>(bottomItem)->itemPosition() - highlightRangeEnd, -maxExtent), -minExtent);
} else {
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
return;
@@ -1554,7 +1581,10 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
timeline.reset(data.move);
if (viewPos != position()) {
if (fixupMode != Immediate) {
- timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+ if (fixupMode == ExtentChanged && data.fixingUp)
+ timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::OutQuad), fixupDuration/2);
+ else
+ timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
data.fixingUp = true;
} else {
timeline.set(data.move, -viewPos);
@@ -1585,7 +1615,7 @@ bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
if (data.move.value() < minExtent) {
if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
// if we've been dragged < averageSize/2 then bias towards the next item
- qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+ qreal dist = data.move.value() - data.pressPos;
qreal bias = dist < averageSize/2 ? averageSize/2 : 0;
if (isContentFlowReversed())
bias = -bias;
@@ -1602,7 +1632,7 @@ bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
if (data.move.value() > maxExtent) {
if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
// if we've been dragged < averageSize/2 then bias towards the next item
- qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+ qreal dist = data.move.value() - data.pressPos;
qreal bias = -dist < averageSize/2 ? averageSize/2 : 0;
if (isContentFlowReversed())
bias = -bias;
@@ -1729,7 +1759,7 @@ bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
\inqmlmodule QtQuick
\ingroup qtquick-views
\inherits Flickable
- \brief Provides a list view of items provided by a model
+ \brief Provides a list view of items provided by a model.
A ListView displays data from models created from built-in QML types like ListModel
and XmlListModel, or custom model classes defined in C++ that inherit from
@@ -1837,6 +1867,38 @@ bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
\snippet qml/listview/listview.qml flickBothDirections
+ \section1 Stacking Order in ListView
+
+ The \l {QQuickItem::z}{Z value} of items determines whether they are
+ rendered above or below other items. ListView uses several different
+ default Z values, depending on what type of item is being created:
+
+ \table
+ \header
+ \li Property
+ \li Default Z value
+ \row
+ \li \l delegate
+ \li 1
+ \row
+ \li \l footer
+ \li 1
+ \row
+ \li \l header
+ \li 1
+ \row
+ \li \l highlight
+ \li 0
+ \row
+ \li \l section.delegate
+ \li 2
+ \endtable
+
+ These default values are set if the Z value of the item is \c 0, so setting
+ the Z value of these items to \c 0 has no effect. Note that the Z value is
+ of type \l [QML] {real}, so it is possible to set fractional
+ values like \c 0.1.
+
\sa {QML Data Models}, GridView, PathView, {Qt Quick Examples - Views}
*/
QQuickListView::QQuickListView(QQuickItem *parent)
@@ -1936,7 +1998,7 @@ QQuickListView::~QQuickListView()
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 VisualItemModel, or provided by C++ model classes. If a C++ model class is
+ or \l ObjectModel, or provided by C++ model classes. If a C++ model class is
used, it must be a subclass of \l QAbstractItemModel or a simple list.
\sa {qml-data-models}{Data Models}
@@ -1965,6 +2027,8 @@ QQuickListView::~QQuickListView()
\note Delegates are instantiated as needed and may be destroyed at any time.
They are parented to ListView's \l {Flickable::contentItem}{contentItem}, not to the view itself.
State should \e never be stored in a delegate.
+
+ \sa {Stacking Order in ListView}
*/
/*!
\qmlproperty int QtQuick::ListView::currentIndex
@@ -1992,7 +2056,7 @@ QQuickListView::~QQuickListView()
The default \l {QQuickItem::z}{stacking order}
of the highlight item is \c 0.
- \sa highlight, highlightFollowsCurrentItem
+ \sa highlight, highlightFollowsCurrentItem, {Stacking Order in ListView}
*/
/*!
@@ -2011,7 +2075,8 @@ QQuickListView::~QQuickListView()
highlight item is \c 0.
\sa highlightItem, highlightFollowsCurrentItem,
- {Qt Quick Examples - Views#Highlight}{ListView highlight example}
+ {Qt Quick Examples - Views#Highlight}{ListView highlight example},
+ {Stacking Order in ListView}
*/
/*!
@@ -2354,7 +2419,8 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
differing sections will result in a section header being created
even if that section exists elsewhere.
- \sa {Qt Quick Examples - Views}{ListView examples}
+ \sa {Qt Quick Examples - Views}{ListView examples},
+ {Stacking Order in ListView}
*/
QQuickViewSection *QQuickListView::sectionCriteria()
{
@@ -2390,7 +2456,23 @@ QString QQuickListView::currentSection() const
The default value for the duration properties is -1, i.e. the
highlight will take as much time as necessary to move at the set speed.
- These properties have the same characteristics as a SmoothedAnimation.
+ These properties have the same characteristics as a SmoothedAnimation:
+ if both the velocity and duration are set, the animation will use
+ whichever gives the shorter duration.
+
+ The move velocity and duration properties are used to control movement due
+ to index changes; for example, when incrementCurrentIndex() is called. When
+ the user flicks a ListView, the velocity from the flick is used to control
+ the movement instead.
+
+ To set only one property, the other can be set to \c -1. For example,
+ if you only want to animate the duration and not velocity, use the
+ following code:
+
+ \code
+ highlightMoveDuration: 1000
+ highlightMoveVelocity: -1
+ \endcode
\sa highlightFollowsCurrentItem
*/
@@ -2471,7 +2553,11 @@ void QQuickListView::setHighlightResizeDuration(int duration)
the view.
\li ListView.SnapOneItem - the view settles no more than one item away from the first
visible item at the time the mouse button is released. This mode is particularly
- useful for moving one page at a time.
+ useful for moving one page at a time. When SnapOneItem is enabled, the ListView will
+ show a stronger affinity to neighboring items when movement occurs. For example, a
+ short drag that snaps back to the current item with SnapToItem might snap to a
+ neighboring item with SnapOneItem.
+
\endlist
\c snapMode does not affect the \l currentIndex. To update the
@@ -2505,7 +2591,7 @@ void QQuickListView::setSnapMode(SnapMode mode)
footer is positioned at the end of the view, after any items. The
default \l {QQuickItem::z}{stacking order} of the footer is \c 1.
- \sa header, footerItem
+ \sa header, footerItem, {Stacking Order in ListView}
*/
@@ -2517,7 +2603,7 @@ void QQuickListView::setSnapMode(SnapMode mode)
header is positioned at the beginning of the view, before any items.
The default \l {QQuickItem::z}{stacking order} of the header is \c 1.
- \sa footer, headerItem
+ \sa footer, headerItem, {Stacking Order in ListView}
*/
/*!
@@ -2528,7 +2614,7 @@ void QQuickListView::setSnapMode(SnapMode mode)
header is positioned at the beginning of the view, before any items.
The default \l {QQuickItem::z}{stacking order} of the header is \c 1.
- \sa header, footerItem
+ \sa header, footerItem, {Stacking Order in ListView}
*/
/*!
@@ -2539,7 +2625,7 @@ void QQuickListView::setSnapMode(SnapMode mode)
footer is positioned at the end of the view, after any items. The
default \l {QQuickItem::z}{stacking order} of the footer is \c 1.
- \sa footer, headerItem
+ \sa footer, headerItem, {Stacking Order in ListView}
*/
/*!
@@ -2557,6 +2643,12 @@ void QQuickListView::setSnapMode(SnapMode mode)
The header can be pushed away by moving the content forwards, and pulled back by
moving the content backwards.
\endlist
+
+ \note This property has no effect on the \l {QQuickItem::z}{stacking order}
+ of the header. For example, if the header should be shown above the
+ \l delegate items when using \c ListView.OverlayHeader, its Z value
+ should be set to a value higher than that of the delegates. For more
+ information, see \l {Stacking Order in ListView}.
*/
QQuickListView::HeaderPositioning QQuickListView::headerPositioning() const
{
@@ -2594,6 +2686,12 @@ void QQuickListView::setHeaderPositioning(QQuickListView::HeaderPositioning posi
The footer can be pushed away by moving the content backwards, and pulled back by
moving the content forwards.
\endlist
+
+ \note This property has no effect on the \l {QQuickItem::z}{stacking order}
+ of the footer. For example, if the footer should be shown above the
+ \l delegate items when using \c ListView.OverlayFooter, its Z value
+ should be set to a value higher than that of the delegates. For more
+ information, see \l {Stacking Order in ListView}.
*/
QQuickListView::FooterPositioning QQuickListView::footerPositioning() const
{
@@ -3150,6 +3248,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
qreal tempPos = isContentFlowReversed() ? -position()-size() : position();
int index = visibleItems.count() ? mapFromModel(modelIndex) : 0;
+ qreal lastVisiblePos = buffer + displayMarginEnd + tempPos + size();
if (index < 0) {
int i = visibleItems.count() - 1;
@@ -3159,7 +3258,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
// there are no visible items except items marked for removal
index = visibleItems.count();
} else if (visibleItems.at(i)->index + 1 == modelIndex
- && visibleItems.at(i)->endPosition() <= buffer+displayMarginEnd+tempPos+size()) {
+ && visibleItems.at(i)->endPosition() <= lastVisiblePos) {
// Special case of appending an item to the model.
index = visibleItems.count();
} else {
@@ -3208,11 +3307,11 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
} else {
for (i = count-1; i >= 0 && pos >= from; --i) {
// item is before first visible e.g. in cache buffer
- FxViewItem *item = 0;
+ FxViewItem *item = nullptr;
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
item->index = modelIndex + i;
if (!item)
- item = createItem(modelIndex + i);
+ item = createItem(modelIndex + i, QQmlIncubator::Synchronous);
if (!item)
return false;
@@ -3247,17 +3346,14 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
}
} else {
- qreal to = buffer + displayMarginEnd + tempPos + size();
-
- visibleAffected = count > 0 && pos < to;
-
- for (int i = 0; i < count && pos <= to; ++i) {
- FxViewItem *item = 0;
+ for (int i = 0; i < count && pos <= lastVisiblePos; ++i) {
+ visibleAffected = true;
+ FxViewItem *item = nullptr;
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
item->index = modelIndex + i;
bool newItem = !item;
if (!item)
- item = createItem(modelIndex + i);
+ item = createItem(modelIndex + i, QQmlIncubator::Synchronous);
if (!item)
return false;
@@ -3422,6 +3518,20 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
*/
/*!
+ \qmlmethod Item QtQuick::ListView::itemAtIndex(int index)
+
+ Returns the item for \a index. If there is no item for that index, for example
+ because it has not been created yet, or because it has been panned out of
+ the visible area and removed from the cache, null is returned.
+
+ \b Note: this method should only be called after the Component has completed.
+ The returned value should also not be stored since it can turn to null
+ as soon as control goes out of the calling scope, if the view releases that item.
+
+ \since 5.13
+*/
+
+/*!
\qmlmethod QtQuick::ListView::forceLayout()
Responding to changes in the model is usually batched to happen only once
diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h
index f8db0f0f8f..9a9b325b1e 100644
--- a/src/quick/items/qquicklistview_p.h
+++ b/src/quick/items/qquicklistview_p.h
@@ -71,7 +71,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickViewSection : public QObject
Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
Q_PROPERTY(int labelPositioning READ labelPositioning WRITE setLabelPositioning NOTIFY labelPositioningChanged)
public:
- QQuickViewSection(QQuickListView *parent=0);
+ QQuickViewSection(QQuickListView *parent=nullptr);
QString property() const { return m_property; }
void setProperty(const QString &);
@@ -132,7 +132,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickListView : public QQuickItemView
Q_CLASSINFO("DefaultProperty", "data")
public:
- QQuickListView(QQuickItem *parent=0);
+ QQuickListView(QQuickItem *parent=nullptr);
~QQuickListView();
qreal spacing() const;
@@ -206,7 +206,7 @@ class QQuickListViewAttached : public QQuickItemViewAttached
public:
QQuickListViewAttached(QObject *parent)
- : QQuickItemViewAttached(parent), m_sectionItem(0) {}
+ : QQuickItemViewAttached(parent), m_sectionItem(nullptr) {}
~QQuickListViewAttached() {}
public:
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 5d5934bbd2..d0e29c204e 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -48,11 +48,13 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcTransient)
+
static const QQuickItemPrivate::ChangeTypes watchedChanges
= QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
QQuickLoaderPrivate::QQuickLoaderPrivate()
- : item(0), object(0), component(0), itemContext(0), incubator(0), updatingSize(false),
+ : item(nullptr), object(nullptr), itemContext(nullptr), incubator(nullptr), updatingSize(false),
active(true), loadingFromSource(false), asynchronous(false)
{
}
@@ -60,7 +62,7 @@ QQuickLoaderPrivate::QQuickLoaderPrivate()
QQuickLoaderPrivate::~QQuickLoaderPrivate()
{
delete itemContext;
- itemContext = 0;
+ itemContext = nullptr;
delete incubator;
disposeInitialPropertyValues();
}
@@ -94,7 +96,13 @@ void QQuickLoaderPrivate::clear()
incubator->clear();
delete itemContext;
- itemContext = 0;
+ itemContext = nullptr;
+
+ // Prevent any bindings from running while waiting for deletion. Without
+ // this we may get transient errors from use of 'parent', for example.
+ QQmlContext *context = qmlContext(object);
+ if (context)
+ QQmlContextData::get(context)->clearContextRecursively();
if (loadingFromSource && component) {
// disconnect since we deleteLater
@@ -103,9 +111,10 @@ void QQuickLoaderPrivate::clear()
QObject::disconnect(component, SIGNAL(progressChanged(qreal)),
q, SIGNAL(progressChanged()));
component->deleteLater();
- component = 0;
+ component.setObject(nullptr, q);
+ } else if (component) {
+ component.setObject(nullptr, q);
}
- componentStrongReference.clear();
source = QUrl();
if (item) {
@@ -114,13 +123,13 @@ void QQuickLoaderPrivate::clear()
// We can't delete immediately because our item may have triggered
// the Loader to load a different item.
- item->setParentItem(0);
+ item->setParentItem(nullptr);
item->setVisible(false);
- item = 0;
+ item = nullptr;
}
if (object) {
object->deleteLater();
- object = 0;
+ object = nullptr;
}
}
@@ -162,7 +171,7 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const
\ingroup qtquick-dynamic
\inherits Item
- \brief Allows dynamic loading of a subtree from a URL or Component
+ \brief Allows dynamic loading of a subtree from a URL or Component.
Loader is used to dynamically load QML components.
@@ -185,7 +194,7 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const
\l sourceComponent to \c undefined destroys the currently loaded object,
freeing resources and leaving the Loader empty.
- \section2 Loader sizing behavior
+ \section2 Loader Sizing Behavior
If the source component is not an Item type, Loader does not
apply any special sizing rules. When used to load visual types,
@@ -217,7 +226,7 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const
\endtable
- \section2 Receiving signals from loaded objects
+ \section2 Receiving Signals from Loaded Objects
Any signals emitted from the loaded object can be received using the
\l Connections type. For example, the following \c application.qml
@@ -238,7 +247,7 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const
its parent \l Item.
- \section2 Focus and key events
+ \section2 Focus and Key Events
Loader is a focus scope. Its \l {Item::}{focus} property must be set to
\c true for any of its children to get the \e {active focus}. (See
@@ -266,10 +275,11 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const
Since \c {QtQuick 2.0}, Loader can also load non-visual components.
- \section2 Using a Loader within a view delegate
+ \section2 Using a Loader within a View Delegate
In some cases you may wish to use a Loader within a view delegate to improve delegate
loading performance. This works well in most cases, but there is one important issue to
+ be aware of related to the \l{QtQml::Component#Creation Context}{creation context} of a Component.
In the following example, the \c index context property inserted by the ListView into \c delegateComponent's
context will be inaccessible to Text, as the Loader will use the creation context of \c myComponent as the parent
@@ -302,10 +312,7 @@ QQuickLoader::QQuickLoader(QQuickItem *parent)
QQuickLoader::~QQuickLoader()
{
Q_D(QQuickLoader);
- if (d->item) {
- QQuickItemPrivate *p = QQuickItemPrivate::get(d->item);
- p->removeItemChangeListener(d, watchedChanges);
- }
+ d->clear();
}
/*!
@@ -347,22 +354,28 @@ void QQuickLoader::setActive(bool newVal)
if (d->incubator) {
d->incubator->clear();
delete d->itemContext;
- d->itemContext = 0;
+ d->itemContext = nullptr;
}
+ // Prevent any bindings from running while waiting for deletion. Without
+ // this we may get transient errors from use of 'parent', for example.
+ QQmlContext *context = qmlContext(d->object);
+ if (context)
+ QQmlContextData::get(context)->clearContextRecursively();
+
if (d->item) {
QQuickItemPrivate *p = QQuickItemPrivate::get(d->item);
p->removeItemChangeListener(d, watchedChanges);
// We can't delete immediately because our item may have triggered
// the Loader to load a different item.
- d->item->setParentItem(0);
+ d->item->setParentItem(nullptr);
d->item->setVisible(false);
- d->item = 0;
+ d->item = nullptr;
}
if (d->object) {
d->object->deleteLater();
- d->object = 0;
+ d->object = nullptr;
emit itemChanged();
}
emit statusChanged();
@@ -426,7 +439,8 @@ void QQuickLoader::loadFromSource()
if (isComponentComplete()) {
QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
- d->component = new QQmlComponent(qmlEngine(this), d->source, mode, this);
+ if (!d->component)
+ d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this);
d->load();
}
}
@@ -469,11 +483,7 @@ void QQuickLoader::setSourceComponent(QQmlComponent *comp)
d->clear();
- d->component = comp;
- if (comp) {
- if (QQmlData *ddata = QQmlData::get(comp))
- d->componentStrongReference = ddata->jsWrapper;
- }
+ d->component.setObject(comp, this);
d->loadingFromSource = false;
if (d->active)
@@ -484,7 +494,7 @@ void QQuickLoader::setSourceComponent(QQmlComponent *comp)
void QQuickLoader::resetSourceComponent()
{
- setSourceComponent(0);
+ setSourceComponent(nullptr);
}
void QQuickLoader::loadFromSourceComponent()
@@ -641,7 +651,7 @@ void QQuickLoaderPrivate::setInitialState(QObject *obj)
if (obj) {
QQml_setParent_noEvent(itemContext, obj);
QQml_setParent_noEvent(obj, q);
- itemContext = 0;
+ itemContext = nullptr;
}
if (initialPropertyValues.isUndefined())
@@ -649,7 +659,7 @@ void QQuickLoaderPrivate::setInitialState(QObject *obj)
QQmlComponentPrivate *d = QQmlComponentPrivate::get(component);
Q_ASSERT(d && d->engine);
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(d->engine);
+ QV4::ExecutionEngine *v4 = d->engine->handle();
Q_ASSERT(v4);
QV4::Scope scope(v4);
QV4::ScopedValue ipv(scope, initialPropertyValues.value());
@@ -671,6 +681,13 @@ void QQuickLoaderPrivate::incubatorStateChanged(QQmlIncubator::Status status)
if (status == QQmlIncubator::Ready) {
object = incubator->object();
item = qmlobject_cast<QQuickItem*>(object);
+ if (!item) {
+ QQuickWindow *window = qmlobject_cast<QQuickWindow*>(object);
+ if (window) {
+ qCDebug(lcTransient) << window << "is transient for" << q->window();
+ window->setTransientParent(q->window());
+ }
+ }
emit q->itemChanged();
initResize();
incubator->clear();
@@ -678,7 +695,7 @@ void QQuickLoaderPrivate::incubatorStateChanged(QQmlIncubator::Status status)
if (!incubator->errors().isEmpty())
QQmlEnginePrivate::warning(qmlEngine(q), incubator->errors());
delete itemContext;
- itemContext = 0;
+ itemContext = nullptr;
delete incubator->object();
source = QUrl();
emit q->itemChanged();
@@ -809,12 +826,25 @@ void QQuickLoader::componentComplete()
if (active()) {
if (d->loadingFromSource) {
QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
- d->component = new QQmlComponent(qmlEngine(this), d->source, mode, this);
+ if (!d->component)
+ d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this);
}
d->load();
}
}
+void QQuickLoader::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
+{
+ if (change == ItemSceneChange) {
+ QQuickWindow *loadedWindow = qmlobject_cast<QQuickWindow *>(item());
+ if (loadedWindow) {
+ qCDebug(lcTransient) << loadedWindow << "is transient for" << value.window;
+ loadedWindow->setTransientParent(value.window);
+ }
+ }
+ QQuickItem::itemChange(change, value);
+}
+
/*!
\qmlsignal QtQuick::Loader::loaded()
@@ -851,6 +881,7 @@ qreal QQuickLoader::progress() const
\qmlproperty bool QtQuick::Loader::asynchronous
This property holds whether the component will be instantiated asynchronously.
+By default it is \c false.
When used in conjunction with the \l source property, loading and compilation
will also be performed in a background thread.
@@ -914,9 +945,14 @@ void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
if (!item)
return;
- if (loaderGeometryChanged && q->widthValid())
+ const bool needToUpdateWidth = loaderGeometryChanged && q->widthValid();
+ const bool needToUpdateHeight = loaderGeometryChanged && q->heightValid();
+
+ if (needToUpdateWidth && needToUpdateHeight)
+ item->setSize(QSizeF(q->width(), q->height()));
+ else if (needToUpdateWidth)
item->setWidth(q->width());
- if (loaderGeometryChanged && q->heightValid())
+ else if (needToUpdateHeight)
item->setHeight(q->height());
if (updatingSize)
@@ -966,7 +1002,7 @@ QUrl QQuickLoaderPrivate::resolveSourceUrl(QQmlV4Function *args)
QV4::ReturnedValue QQuickLoaderPrivate::extractInitialPropertyValues(QQmlV4Function *args, QObject *loader, bool *error)
{
QV4::Scope scope(args->v4engine());
- QV4::ScopedValue valuemap(scope, QV4::Primitive::undefinedValue());
+ QV4::ScopedValue valuemap(scope, QV4::Encode::undefined());
if (args->length() >= 2) {
QV4::ScopedValue v(scope, (*args)[1]);
if (!v->isObject() || v->as<QV4::ArrayObject>()) {
diff --git a/src/quick/items/qquickloader_p.h b/src/quick/items/qquickloader_p.h
index db171dcd1e..de1dfa9da5 100644
--- a/src/quick/items/qquickloader_p.h
+++ b/src/quick/items/qquickloader_p.h
@@ -69,7 +69,7 @@ class Q_AUTOTEST_EXPORT QQuickLoader : public QQuickImplicitSizeItem
Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged)
public:
- QQuickLoader(QQuickItem *parent = 0);
+ QQuickLoader(QQuickItem *parent = nullptr);
virtual ~QQuickLoader();
bool active() const;
@@ -105,8 +105,9 @@ Q_SIGNALS:
void asynchronousChanged();
protected:
- void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
- void componentComplete() Q_DECL_OVERRIDE;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void componentComplete() override;
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
private:
void setSource(const QUrl &sourceUrl, bool needsClear);
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 9b6267e011..349b5c6c06 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -68,8 +68,8 @@ public:
QQuickLoaderIncubator(QQuickLoaderPrivate *l, IncubationMode mode) : QQmlIncubator(mode), loader(l) {}
protected:
- void statusChanged(Status) Q_DECL_OVERRIDE;
- void setInitialState(QObject *) Q_DECL_OVERRIDE;
+ void statusChanged(Status) override;
+ void setInitialState(QObject *) override;
private:
QQuickLoaderPrivate *loader;
@@ -84,9 +84,9 @@ public:
QQuickLoaderPrivate();
~QQuickLoaderPrivate();
- void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
- void itemImplicitWidthChanged(QQuickItem *) Q_DECL_OVERRIDE;
- void itemImplicitHeightChanged(QQuickItem *) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeometry) override;
+ void itemImplicitWidthChanged(QQuickItem *) override;
+ void itemImplicitHeightChanged(QQuickItem *) override;
void clear();
void initResize();
void load();
@@ -97,14 +97,13 @@ public:
static QUrl resolveSourceUrl(QQmlV4Function *args);
QV4::ReturnedValue extractInitialPropertyValues(QQmlV4Function *args, QObject *loader, bool *error);
- qreal getImplicitWidth() const Q_DECL_OVERRIDE;
- qreal getImplicitHeight() const Q_DECL_OVERRIDE;
+ qreal getImplicitWidth() const override;
+ qreal getImplicitHeight() const override;
QUrl source;
QQuickItem *item;
QObject *object;
- QQmlComponent *component;
- QV4::PersistentValue componentStrongReference; // To ensure GC doesn't delete components created by Qt.createComponent
+ QQmlStrongJSQObjectReference<QQmlComponent> component;
QQmlContext *itemContext;
QQuickLoaderIncubator *incubator;
QV4::PersistentValue initialPropertyValues;
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index d8bad7d793..0b345697ec 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -60,13 +60,13 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
: enabled(true), scrollGestureEnabled(true), hovered(false), longPress(false),
moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
- propagateComposedEvents(false), overThreshold(false), pressed(0),
+ propagateComposedEvents(false), overThreshold(false), pressed(nullptr),
pressAndHoldInterval(-1)
#if QT_CONFIG(draganddrop)
- , drag(0)
+ , drag(nullptr)
#endif
#if QT_CONFIG(cursor)
- , cursor(0)
+ , cursor(nullptr)
#endif
{
}
@@ -85,6 +85,7 @@ void QQuickMouseAreaPrivate::init()
{
Q_Q(QQuickMouseArea);
q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setAcceptTouchEvents(false); // rely on mouse events synthesized from touch
q->setFiltersChildMouseEvents(true);
if (qmlVisualTouchDebugging()) {
q->setFlag(QQuickItem::ItemHasContents);
@@ -98,6 +99,7 @@ void QQuickMouseAreaPrivate::saveEvent(QMouseEvent *event)
lastButton = event->button();
lastButtons = event->buttons();
lastModifiers = event->modifiers();
+ lastFlags = event->flags();
}
bool QQuickMouseAreaPrivate::isPressAndHoldConnected()
@@ -194,7 +196,7 @@ bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *i
\instantiates QQuickMouseArea
\inqmlmodule QtQuick
\ingroup qtquick-input
- \brief Enables simple mouse handling
+ \brief Enables simple mouse handling.
\inherits Item
A MouseArea is an invisible item that is typically used in conjunction with
@@ -783,7 +785,7 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
#endif
QQuickMouseEvent &me = d->quickMouseEvent;
- me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress, event->flags());
me.setSource(event->source());
emit mouseXChanged(&me);
me.setPosition(d->lastPos);
@@ -826,7 +828,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
if (d->enabled) {
d->saveEvent(event);
QQuickMouseEvent &me = d->quickMouseEvent;
- me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
+ me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true,
+ false, event->flags());
me.setSource(event->source());
me.setAccepted(d->isDoubleClickConnected());
emit this->doubleClicked(&me);
@@ -907,7 +910,7 @@ void QQuickMouseArea::ungrabMouse()
if (d->pressed) {
// if our mouse grab has been removed (probably by Flickable), fix our
// state
- d->pressed = 0;
+ d->pressed = Qt::NoButton;
d->stealMouse = false;
d->doubleClick = false;
d->overThreshold = false;
@@ -941,7 +944,7 @@ bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
QPointF localPos = mapFromScene(event->windowPos());
QQuickWindow *c = window();
- QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
+ QQuickItem *grabber = c ? c->mouseGrabberItem() : nullptr;
bool stealThisEvent = d->stealMouse;
if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
QMouseEvent mouseEvent(event->type(), localPos, event->windowPos(), event->screenPos(),
@@ -962,7 +965,7 @@ bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
default:
break;
}
- grabber = c ? c->mouseGrabberItem() : 0;
+ grabber = c ? c->mouseGrabberItem() : nullptr;
if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
grabMouse();
@@ -1027,7 +1030,7 @@ void QQuickMouseArea::timerEvent(QTimerEvent *event)
if (d->pressed && dragged == false && d->hovered == true) {
d->longPress = true;
QQuickMouseEvent &me = d->quickMouseEvent;
- me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress, d->lastFlags);
me.setSource(Qt::MouseEventSynthesizedByQt);
me.setAccepted(d->isPressAndHoldConnected());
emit pressAndHold(&me);
@@ -1206,7 +1209,7 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventS
if (wasPressed != p) {
QQuickMouseEvent &me = d->quickMouseEvent;
- me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
+ me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress, d->lastFlags);
me.setSource(source);
if (p) {
d->pressed |= button;
@@ -1417,7 +1420,7 @@ QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
Q_D(QQuickMouseArea);
if (!qmlVisualTouchDebugging())
- return 0;
+ return nullptr;
QSGInternalRectangleNode *rectangle = static_cast<QSGInternalRectangleNode *>(oldNode);
if (!rectangle) rectangle = d->sceneGraphContext()->createInternalRectangleNode();
diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h
index ee166a2082..0a8449957f 100644
--- a/src/quick/items/qquickmousearea_p.h
+++ b/src/quick/items/qquickmousearea_p.h
@@ -87,7 +87,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem
Q_PROPERTY(int pressAndHoldInterval READ pressAndHoldInterval WRITE setPressAndHoldInterval NOTIFY pressAndHoldIntervalChanged RESET resetPressAndHoldInterval REVISION 9)
public:
- QQuickMouseArea(QQuickItem *parent=0);
+ QQuickMouseArea(QQuickItem *parent=nullptr);
~QQuickMouseArea();
qreal mouseX() const;
@@ -164,25 +164,25 @@ protected:
bool setPressed(Qt::MouseButton button, bool p, Qt::MouseEventSource source);
bool sendMouseEvent(QMouseEvent *event);
- void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseUngrabEvent() Q_DECL_OVERRIDE;
- void hoverEnterEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
- void hoverMoveEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
- void hoverLeaveEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseDoubleClickEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseUngrabEvent() override;
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverMoveEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
#if QT_CONFIG(wheelevent)
- void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
+ void wheelEvent(QWheelEvent *event) override;
#endif
- bool childMouseEventFilter(QQuickItem *i, QEvent *e) Q_DECL_OVERRIDE;
- void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE;
- void windowDeactivateEvent() Q_DECL_OVERRIDE;
+ bool childMouseEventFilter(QQuickItem *i, QEvent *e) override;
+ void timerEvent(QTimerEvent *event) override;
+ void windowDeactivateEvent() override;
void geometryChanged(const QRectF &newGeometry,
- const QRectF &oldGeometry) Q_DECL_OVERRIDE;
- void itemChange(ItemChange change, const ItemChangeData& value) Q_DECL_OVERRIDE;
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ const QRectF &oldGeometry) override;
+ void itemChange(ItemChange change, const ItemChangeData& value) override;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
private:
void handlePress();
diff --git a/src/quick/items/qquickmousearea_p_p.h b/src/quick/items/qquickmousearea_p_p.h
index 2fa5f7cd44..0dd2690d43 100644
--- a/src/quick/items/qquickmousearea_p_p.h
+++ b/src/quick/items/qquickmousearea_p_p.h
@@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE
class QQuickMouseEvent;
class QQuickMouseArea;
+class QQuickPointerMask;
class QQuickMouseAreaPrivate : public QQuickItemPrivate
{
Q_DECLARE_PUBLIC(QQuickMouseArea)
@@ -99,6 +100,7 @@ public:
#if QT_CONFIG(draganddrop)
QQuickDrag *drag;
#endif
+ QPointer<QQuickPointerMask> mask;
QPointF startScene;
QPointF targetStartPos;
QPointF lastPos;
@@ -112,6 +114,7 @@ public:
#endif
QQuickMouseEvent quickMouseEvent;
QQuickWheelEvent quickWheelEvent;
+ Qt::MouseEventFlags lastFlags;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index d4c447a384..3eca535a67 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -56,7 +56,7 @@ DEFINE_BOOL_CONFIG_OPTION(qmlVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING)
\instantiates QQuickTouchPoint
\inqmlmodule QtQuick
\ingroup qtquick-input-events
- \brief Describes a touch point in a MultiPointTouchArea
+ \brief Describes a touch point in a MultiPointTouchArea.
The TouchPoint type contains information about a touch point, such as the current
position, pressure, and area.
@@ -285,13 +285,50 @@ void QQuickTouchPoint::setUniqueId(const QPointingDeviceUniqueId &id)
emit uniqueIdChanged();
}
+
+/*!
+ \qmltype GestureEvent
+ \instantiates QQuickGrabGestureEvent
+ \inqmlmodule QtQuick
+ \ingroup qtquick-input-events
+ \brief The parameter given with the gestureStarted signal.
+
+ The GestureEvent object has the current touch points, which you may choose
+ to interpret as a gesture, and an invokable method to grab the involved
+ points exclusively.
+*/
+
+/*!
+ \qmlproperty real QtQuick::GestureEvent::dragThreshold
+
+ This property holds the system setting for the distance a finger must move
+ before it is interpreted as a drag. It comes from
+ QStyleHints::startDragDistance().
+*/
+
+/*!
+ \qmlproperty list<TouchPoint> QtQuick::GestureEvent::touchPoints
+
+ This property holds the set of current touch points.
+*/
+
+/*!
+ \qmlmethod QtQuick::GestureEvent::grab()
+
+ Acquires an exclusive grab of the mouse and all the \l touchPoints, and
+ calls \l {QQuickItem::setKeepTouchGrab()}{setKeepTouchGrab()} and
+ \l {QQuickItem::setKeepMouseGrab()}{setKeepMouseGrab()} so that any
+ parent Item that \l {QQuickItem::filtersChildMouseEvents()}{filters} its
+ children's events will not be allowed to take over the grabs.
+*/
+
/*!
\qmltype MultiPointTouchArea
\instantiates QQuickMultiPointTouchArea
\inqmlmodule QtQuick
\inherits Item
\ingroup qtquick-input
- \brief Enables handling of multiple touch points
+ \brief Enables handling of multiple touch points.
A MultiPointTouchArea is an invisible item that is used to track multiple touch points.
@@ -418,6 +455,7 @@ QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent)
if (qmlVisualTouchDebugging()) {
setFlag(QQuickItem::ItemHasContents);
}
+ setAcceptTouchEvents(true);
#ifdef Q_OS_OSX
setAcceptHoverEvents(true); // needed to enable touch events on mouse hover.
#endif
@@ -490,7 +528,7 @@ void QQuickMultiPointTouchArea::setMouseEnabled(bool arg)
if (_mouseEnabled != arg) {
_mouseEnabled = arg;
if (_mouseTouchPoint && !arg)
- _mouseTouchPoint = Q_NULLPTR;
+ _mouseTouchPoint = nullptr;
emit mouseEnabledChanged();
}
}
@@ -503,7 +541,7 @@ void QQuickMultiPointTouchArea::touchEvent(QTouchEvent *event)
case QEvent::TouchEnd: {
//if e.g. a parent Flickable has the mouse grab, don't process the touch events
QQuickWindow *c = window();
- QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
+ QQuickItem *grabber = c ? c->mouseGrabberItem() : nullptr;
if (grabber && grabber != this && grabber->keepMouseGrab() && grabber->isEnabled()) {
QQuickItem *item = this;
while ((item = item->parentItem())) {
@@ -572,6 +610,9 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
else { // QEvent::MouseButtonPress
addTouchPoint(me);
started = true;
+ _mouseQpaTouchPoint.setStartPos(me->localPos());
+ _mouseQpaTouchPoint.setStartScenePos(me->windowPos());
+ _mouseQpaTouchPoint.setStartScreenPos(me->screenPos());
_mouseQpaTouchPoint.setState(Qt::TouchPointPressed);
}
touchPoints << _mouseQpaTouchPoint;
@@ -681,7 +722,7 @@ void QQuickMultiPointTouchArea::clearTouchLists()
void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
{
- QQuickTouchPoint *dtp = 0;
+ QQuickTouchPoint *dtp = nullptr;
for (QQuickTouchPoint* tp : qAsConst(_touchPrototypes)) {
if (!tp->inUse()) {
tp->setInUse(true);
@@ -690,7 +731,7 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
}
}
- if (dtp == 0)
+ if (dtp == nullptr)
dtp = new QQuickTouchPoint(false);
dtp->setPointId(p->id());
updateTouchPoint(dtp,p);
@@ -701,7 +742,7 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
void QQuickMultiPointTouchArea::addTouchPoint(const QMouseEvent *e)
{
- QQuickTouchPoint *dtp = 0;
+ QQuickTouchPoint *dtp = nullptr;
for (QQuickTouchPoint *tp : qAsConst(_touchPrototypes))
if (!tp->inUse()) {
tp->setInUse(true);
@@ -709,7 +750,7 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QMouseEvent *e)
break;
}
- if (dtp == 0)
+ if (dtp == nullptr)
dtp = new QQuickTouchPoint(false);
updateTouchPoint(dtp, e);
dtp->setPressed(true);
@@ -834,7 +875,7 @@ void QQuickMultiPointTouchArea::mouseReleaseEvent(QMouseEvent *event)
updateTouchData(event);
_mouseTouchPoint->setInUse(false);
_releasedTouchPoints.removeAll(_mouseTouchPoint);
- _mouseTouchPoint = Q_NULLPTR;
+ _mouseTouchPoint = nullptr;
}
QQuickWindow *c = window();
@@ -882,7 +923,7 @@ bool QQuickMultiPointTouchArea::sendMouseEvent(QMouseEvent *event)
QPointF localPos = mapFromScene(event->windowPos());
QQuickWindow *c = window();
- QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
+ QQuickItem *grabber = c ? c->mouseGrabberItem() : nullptr;
bool stealThisEvent = _stealMouse;
if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
QMouseEvent mouseEvent(event->type(), localPos, event->windowPos(), event->screenPos(),
@@ -906,7 +947,7 @@ bool QQuickMultiPointTouchArea::sendMouseEvent(QMouseEvent *event)
default:
break;
}
- grabber = c ? c->mouseGrabberItem() : 0;
+ grabber = c ? c->mouseGrabberItem() : nullptr;
if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
grabMouse();
@@ -953,7 +994,7 @@ bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *receiver, QEve
bool QQuickMultiPointTouchArea::shouldFilter(QEvent *event)
{
QQuickWindow *c = window();
- QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
+ QQuickItem *grabber = c ? c->mouseGrabberItem() : nullptr;
bool disabledItem = grabber && !grabber->isEnabled();
bool stealThisEvent = _stealMouse;
bool containsPoint = false;
@@ -994,7 +1035,7 @@ QSGNode *QQuickMultiPointTouchArea::updatePaintNode(QSGNode *oldNode, UpdatePain
Q_UNUSED(data);
if (!qmlVisualTouchDebugging())
- return 0;
+ return nullptr;
QSGInternalRectangleNode *rectangle = static_cast<QSGInternalRectangleNode *>(oldNode);
if (!rectangle) rectangle = QQuickItemPrivate::get(this)->sceneGraphContext()->createInternalRectangleNode();
diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h
index 25e1056712..634ea1c2e2 100644
--- a/src/quick/items/qquickmultipointtoucharea_p.h
+++ b/src/quick/items/qquickmultipointtoucharea_p.h
@@ -86,16 +86,7 @@ class Q_AUTOTEST_EXPORT QQuickTouchPoint : public QObject
public:
QQuickTouchPoint(bool qmlDefined = true)
- : _id(0),
- _x(0.0), _y(0.0),
- _pressure(0.0),
- _rotation(0),
- _qmlDefined(qmlDefined),
- _inUse(false),
- _pressed(false),
- _startX(0.0), _startY(0.0),
- _previousX(0.0), _previousY(0.0),
- _sceneX(0.0), _sceneY(0.0)
+ : _qmlDefined(qmlDefined)
{}
int pointId() const { return _id; }
@@ -171,33 +162,33 @@ Q_SIGNALS:
private:
friend class QQuickMultiPointTouchArea;
- int _id;
- qreal _x;
- qreal _y;
- qreal _pressure;
- qreal _rotation;
+ int _id = 0;
+ qreal _x = 0.0;
+ qreal _y = 0.0;
+ qreal _pressure = 0.0;
+ qreal _rotation = 0;
QSizeF _ellipseDiameters;
QVector2D _velocity;
QRectF _area;
bool _qmlDefined;
- bool _inUse; //whether the point is currently in use (only valid when _qmlDefined == true)
- bool _pressed;
- qreal _startX;
- qreal _startY;
- qreal _previousX;
- qreal _previousY;
- qreal _sceneX;
- qreal _sceneY;
+ bool _inUse = false; //whether the point is currently in use (only valid when _qmlDefined == true)
+ bool _pressed = false;
+ qreal _startX = 0.0;
+ qreal _startY = 0.0;
+ qreal _previousX = 0.0;
+ qreal _previousY = 0.0;
+ qreal _sceneX = 0.0;
+ qreal _sceneY = 0.0;
QPointingDeviceUniqueId _uniqueId;
};
class QQuickGrabGestureEvent : public QObject
{
Q_OBJECT
- Q_PROPERTY(QQmlListProperty<QObject> touchPoints READ touchPoints)
- Q_PROPERTY(qreal dragThreshold READ dragThreshold)
+ Q_PROPERTY(QQmlListProperty<QObject> touchPoints READ touchPoints CONSTANT)
+ Q_PROPERTY(qreal dragThreshold READ dragThreshold CONSTANT)
public:
- QQuickGrabGestureEvent() : _grab(false), _dragThreshold(QGuiApplication::styleHints()->startDragDistance()) {}
+ QQuickGrabGestureEvent() : _dragThreshold(QGuiApplication::styleHints()->startDragDistance()) {}
Q_INVOKABLE void grab() { _grab = true; }
bool wantsGrab() const { return _grab; }
@@ -209,7 +200,7 @@ public:
private:
friend class QQuickMultiPointTouchArea;
- bool _grab;
+ bool _grab = false;
qreal _dragThreshold;
QList<QObject*> _touchPoints;
};
@@ -224,7 +215,7 @@ class Q_AUTOTEST_EXPORT QQuickMultiPointTouchArea : public QQuickItem
Q_PROPERTY(bool mouseEnabled READ mouseEnabled WRITE setMouseEnabled NOTIFY mouseEnabledChanged)
public:
- QQuickMultiPointTouchArea(QQuickItem *parent=0);
+ QQuickMultiPointTouchArea(QQuickItem *parent=nullptr);
~QQuickMultiPointTouchArea();
int minimumTouchPoints() const;
@@ -235,7 +226,7 @@ public:
void setMouseEnabled(bool arg);
QQmlListProperty<QQuickTouchPoint> touchPoints() {
- return QQmlListProperty<QQuickTouchPoint>(this, 0, QQuickMultiPointTouchArea::touchPoint_append, QQuickMultiPointTouchArea::touchPoint_count, QQuickMultiPointTouchArea::touchPoint_at, 0);
+ return QQmlListProperty<QQuickTouchPoint>(this, nullptr, QQuickMultiPointTouchArea::touchPoint_append, QQuickMultiPointTouchArea::touchPoint_count, QQuickMultiPointTouchArea::touchPoint_at, nullptr);
}
static void touchPoint_append(QQmlListProperty<QQuickTouchPoint> *list, QQuickTouchPoint* touch) {
@@ -265,13 +256,13 @@ Q_SIGNALS:
void mouseEnabledChanged();
protected:
- void touchEvent(QTouchEvent *) Q_DECL_OVERRIDE;
- bool childMouseEventFilter(QQuickItem *receiver, QEvent *event) Q_DECL_OVERRIDE;
- void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseUngrabEvent() Q_DECL_OVERRIDE;
- void touchUngrabEvent() Q_DECL_OVERRIDE;
+ void touchEvent(QTouchEvent *) override;
+ bool childMouseEventFilter(QQuickItem *receiver, QEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseUngrabEvent() override;
+ void touchUngrabEvent() override;
void addTouchPrototype(QQuickTouchPoint* prototype);
void addTouchPoint(const QTouchEvent::TouchPoint *p);
@@ -285,10 +276,10 @@ protected:
bool sendMouseEvent(QMouseEvent *event);
bool shouldFilter(QEvent *event);
void grabGesture();
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
#ifdef Q_OS_OSX
- void hoverEnterEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
- void hoverLeaveEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
void setTouchEventsEnabled(bool enable);
#endif
diff --git a/src/quick/items/qquickopenglinfo.cpp b/src/quick/items/qquickopenglinfo.cpp
index 7f5364031a..3e634725f4 100644
--- a/src/quick/items/qquickopenglinfo.cpp
+++ b/src/quick/items/qquickopenglinfo.cpp
@@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE
\inqmlmodule QtQuick
\ingroup qtquick-effects
\since 5.4
- \brief Provides information about the used OpenGL version
+ \brief Provides information about the used OpenGL version.
The OpenGLInfo attached type provides information about the OpenGL
version being used to render the surface of the attachee item.
@@ -69,7 +69,7 @@ QT_BEGIN_NAMESPACE
*/
QQuickOpenGLInfo::QQuickOpenGLInfo(QQuickItem *item)
: QObject(item)
- , m_window(0)
+ , m_window(nullptr)
, m_majorVersion(2)
, m_minorVersion(0)
, m_profile(NoProfile)
@@ -150,12 +150,12 @@ QQuickOpenGLInfo *QQuickOpenGLInfo::qmlAttachedProperties(QObject *object)
{
if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
return new QQuickOpenGLInfo(item);
- return 0;
+ return nullptr;
}
void QQuickOpenGLInfo::updateFormat()
{
- QOpenGLContext *context = 0;
+ QOpenGLContext *context = nullptr;
if (m_window)
context = m_window->openglContext();
QSurfaceFormat format = context ? context->format() : QSurfaceFormat::defaultFormat();
diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp
index 4fcfe04b55..3aa00340b2 100644
--- a/src/quick/items/qquickopenglshadereffect.cpp
+++ b/src/quick/items/qquickopenglshadereffect.cpp
@@ -139,7 +139,7 @@ namespace {
expected = TypeIdentifier;
break;
}
- // Fall through.
+ Q_FALLTHROUGH();
case TypeIdentifier:
typeIndex = idIndex;
typeLength = idLength;
@@ -230,7 +230,7 @@ void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item,
auto mapper = signalMappers[shaderType].at(i);
void *a = mapper;
QObjectPrivate::disconnect(item, mapper->signalIndex(), &a);
- if (d.specialType == UniformData::Sampler) {
+ if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
if (item->window())
@@ -245,7 +245,11 @@ void QQuickOpenGLShaderEffectCommon::connectPropertySignals(QQuickItem *item,
const QMetaObject *itemMetaObject,
Key::ShaderType shaderType)
{
- QQmlPropertyCache *propCache = QQmlData::ensurePropertyCache(qmlEngine(item), item);
+ auto engine = qmlEngine(item);
+ if (!engine)
+ return;
+
+ QQmlPropertyCache *propCache = QQmlData::ensurePropertyCache(engine, item);
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
if (signalMappers[shaderType].at(i) == 0)
continue;
@@ -272,7 +276,7 @@ void QQuickOpenGLShaderEffectCommon::connectPropertySignals(QQuickItem *item,
qWarning("QQuickOpenGLShaderEffect: '%s' does not have a matching property!", d.name.constData());
}
- if (d.specialType == UniformData::Sampler) {
+ if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
if (item->window())
@@ -317,7 +321,8 @@ void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item,
Key::ShaderType shaderType,
const QByteArray &code)
{
- QQmlPropertyCache *propCache = QQmlData::ensurePropertyCache(qmlEngine(item), item);
+ auto engine = qmlEngine(item);
+ QQmlPropertyCache *propCache = (engine) ? QQmlData::ensurePropertyCache(engine, item) : nullptr;
int index = 0;
int typeIndex = -1;
int typeLength = 0;
@@ -335,6 +340,7 @@ void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item,
Q_ASSERT(decl == UniformQualifier);
const int sampLen = sizeof("sampler2D") - 1;
+ const int sampExtLen = sizeof("samplerExternalOES") - 1;
const int opLen = sizeof("qt_Opacity") - 1;
const int matLen = sizeof("qt_Matrix") - 1;
const int srLen = sizeof("qt_SubRect_") - 1;
@@ -349,16 +355,22 @@ void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item,
} else if (nameLength > srLen && qstrncmp("qt_SubRect_", s + nameIndex, srLen) == 0) {
d.specialType = UniformData::SubRect;
} else {
- if (QQmlPropertyData *pd = propCache->property(QString::fromUtf8(d.name), nullptr, nullptr)) {
- if (!pd->isFunction())
- d.propertyIndex = pd->coreIndex();
+ if (propCache) {
+ if (QQmlPropertyData *pd = propCache->property(QString::fromUtf8(d.name), nullptr, nullptr)) {
+ if (!pd->isFunction())
+ d.propertyIndex = pd->coreIndex();
+ }
}
const int mappedId = uniformData[shaderType].size() | (shaderType << 16);
mapper = new QtPrivate::MappedSlotObject([this, mappedId](){
this->mappedPropertyChanged(mappedId);
});
- bool sampler = typeLength == sampLen && qstrncmp("sampler2D", s + typeIndex, sampLen) == 0;
- d.specialType = sampler ? UniformData::Sampler : UniformData::None;
+ if (typeLength == sampLen && qstrncmp("sampler2D", s + typeIndex, sampLen) == 0)
+ d.specialType = UniformData::Sampler;
+ else if (typeLength == sampExtLen && qstrncmp("samplerExternalOES", s + typeIndex, sampExtLen) == 0)
+ d.specialType = UniformData::SamplerExternal;
+ else
+ d.specialType = UniformData::None;
d.setValueFromProperty(item, itemMetaObject);
}
uniformData[shaderType].append(d);
@@ -417,8 +429,9 @@ void QQuickOpenGLShaderEffectCommon::updateShader(QQuickItem *item,
d.specialType = UniformData::Opacity;
uniformData[Key::FragmentShader].append(d);
signalMappers[Key::FragmentShader].append(0);
- const int mappedId = 1 | (Key::FragmentShader << 16);
- auto mapper = new QtPrivate::MappedSlotObject([this, mappedId](){mappedPropertyChanged(mappedId);});
+ auto mapper = new QtPrivate::MappedSlotObject([this](){
+ mappedPropertyChanged(1 | (Key::FragmentShader << 16));
+ });
const char *sourceName = "source";
d.name = sourceName;
d.setValueFromProperty(item, itemMetaObject);
@@ -451,7 +464,8 @@ void QQuickOpenGLShaderEffectCommon::updateMaterial(QQuickOpenGLShaderEffectNode
int textureProviderCount = 0;
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
- if (uniformData[shaderType].at(i).specialType == UniformData::Sampler)
+ if (uniformData[shaderType].at(i).specialType == UniformData::Sampler ||
+ uniformData[shaderType].at(i).specialType == UniformData::SamplerExternal)
++textureProviderCount;
}
material->uniforms[shaderType] = uniformData[shaderType];
@@ -474,10 +488,10 @@ void QQuickOpenGLShaderEffectCommon::updateMaterial(QQuickOpenGLShaderEffectNode
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
const UniformData &d = uniformData[shaderType].at(i);
- if (d.specialType != UniformData::Sampler)
+ if (d.specialType != UniformData::Sampler && d.specialType != UniformData::SamplerExternal)
continue;
QSGTextureProvider *oldProvider = material->textureProviders.at(index);
- QSGTextureProvider *newProvider = 0;
+ QSGTextureProvider *newProvider = nullptr;
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source && source->isTextureProvider())
newProvider = source->textureProvider();
@@ -513,7 +527,7 @@ void QQuickOpenGLShaderEffectCommon::updateWindow(QQuickWindow *window)
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
const UniformData &d = uniformData[shaderType].at(i);
- if (d.specialType == UniformData::Sampler) {
+ if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source)
QQuickItemPrivate::get(source)->refWindow(window);
@@ -524,7 +538,7 @@ void QQuickOpenGLShaderEffectCommon::updateWindow(QQuickWindow *window)
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
const UniformData &d = uniformData[shaderType].at(i);
- if (d.specialType == UniformData::Sampler) {
+ if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source)
QQuickItemPrivate::get(source)->derefWindow();
@@ -539,7 +553,7 @@ void QQuickOpenGLShaderEffectCommon::sourceDestroyed(QObject *object)
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
UniformData &d = uniformData[shaderType][i];
- if (d.specialType == UniformData::Sampler && d.value.canConvert<QObject *>()) {
+ if ((d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) && d.value.canConvert<QObject *>()) {
if (qvariant_cast<QObject *>(d.value) == object)
d.value = QVariant();
}
@@ -554,7 +568,7 @@ static bool qquick_uniqueInUniformData(QQuickItem *source, const QVector<QQuickO
if (s == typeToSkip && i == indexToSkip)
continue;
const QQuickOpenGLShaderEffectMaterial::UniformData &d = uniformData[s][i];
- if (d.specialType == QQuickOpenGLShaderEffectMaterial::UniformData::Sampler && qvariant_cast<QObject *>(d.value) == source)
+ if ((d.specialType == QQuickOpenGLShaderEffectMaterial::UniformData::Sampler || d.specialType == QQuickOpenGLShaderEffectMaterial::UniformData::SamplerExternal) && qvariant_cast<QObject *>(d.value) == source)
return false;
}
}
@@ -568,7 +582,7 @@ void QQuickOpenGLShaderEffectCommon::propertyChanged(QQuickItem *item,
Key::ShaderType shaderType = Key::ShaderType(mappedId >> 16);
int index = mappedId & 0xffff;
UniformData &d = uniformData[shaderType][index];
- if (d.specialType == UniformData::Sampler) {
+ if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
if (item->window())
@@ -617,7 +631,7 @@ QQuickOpenGLShaderEffect::QQuickOpenGLShaderEffect(QQuickShaderEffect *item, QOb
, m_item(item)
, m_itemMetaObject(nullptr)
, m_meshResolution(1, 1)
- , m_mesh(0)
+ , m_mesh(nullptr)
, m_cullMode(QQuickShaderEffect::NoCulling)
, m_status(QQuickShaderEffect::Uncompiled)
, m_common(this, [this](int mappedId){this->propertyChanged(mappedId);})
@@ -706,7 +720,7 @@ void QQuickOpenGLShaderEffect::setMesh(const QVariant &mesh)
if (newMesh && newMesh == m_mesh)
return;
if (m_mesh)
- disconnect(m_mesh, SIGNAL(geometryChanged()), this, 0);
+ disconnect(m_mesh, SIGNAL(geometryChanged()), this, nullptr);
m_mesh = newMesh;
if (m_mesh) {
connect(m_mesh, SIGNAL(geometryChanged()), this, SLOT(updateGeometry()));
@@ -759,7 +773,7 @@ QString QQuickOpenGLShaderEffect::parseLog()
maybeUpdateShaders(true);
if (m_dirtyParseLog) {
- m_common.updateParseLog(m_mesh != 0);
+ m_common.updateParseLog(m_mesh != nullptr);
m_dirtyParseLog = false;
}
return m_common.parseLog;
@@ -831,7 +845,7 @@ QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuic
if (m_common.attributes.isEmpty() || m_item->width() <= 0 || m_item->height() <= 0) {
if (node)
delete node;
- return 0;
+ return nullptr;
}
if (!node) {
@@ -890,7 +904,7 @@ QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuic
bool geometryUsesTextureSubRect = false;
if (m_supportsAtlasTextures && material->textureProviders.size() == 1) {
QSGTextureProvider *provider = material->textureProviders.at(0);
- if (provider->texture()) {
+ if (provider && provider->texture()) {
srcRect = provider->texture()->normalizedTextureSubRect();
geometryUsesTextureSubRect = true;
}
@@ -907,7 +921,7 @@ QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuic
}
if (m_dirtyMesh) {
- node->setGeometry(0);
+ node->setGeometry(nullptr);
m_dirtyMesh = false;
m_dirtyGeometry = true;
}
@@ -928,7 +942,7 @@ QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuic
emit m_item->statusChanged();
}
delete node;
- return 0;
+ return nullptr;
}
geometry = mesh->updateGeometry(geometry, m_common.attributes.count(), posIndex, srcRect, rect);
diff --git a/src/quick/items/qquickopenglshadereffect_p.h b/src/quick/items/qquickopenglshadereffect_p.h
index bc2e2975ee..0c2adadc62 100644
--- a/src/quick/items/qquickopenglshadereffect_p.h
+++ b/src/quick/items/qquickopenglshadereffect_p.h
@@ -120,8 +120,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffect : public QObject
Q_OBJECT
public:
- QQuickOpenGLShaderEffect(QQuickShaderEffect *item, QObject *parent = 0);
- ~QQuickOpenGLShaderEffect();
+ QQuickOpenGLShaderEffect(QQuickShaderEffect *item, QObject *parent = nullptr);
+ ~QQuickOpenGLShaderEffect() override;
QByteArray fragmentShader() const { return m_common.source.sourceCode[Key::FragmentShader]; }
void setFragmentShader(const QByteArray &code);
diff --git a/src/quick/items/qquickopenglshadereffectnode.cpp b/src/quick/items/qquickopenglshadereffectnode.cpp
index e1ea98641d..f32b32491b 100644
--- a/src/quick/items/qquickopenglshadereffectnode.cpp
+++ b/src/quick/items/qquickopenglshadereffectnode.cpp
@@ -47,6 +47,10 @@
#include <QtCore/qmutex.h>
#include <QtGui/qopenglfunctions.h>
+#ifndef GL_TEXTURE_EXTERNAL_OES
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#endif
+
QT_BEGIN_NAMESPACE
static bool hasAtlasTexture(const QVector<QSGTextureProvider *> &textureProviders)
@@ -63,16 +67,16 @@ class QQuickCustomMaterialShader : public QSGMaterialShader
{
public:
QQuickCustomMaterialShader(const QQuickOpenGLShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes);
- void deactivate() Q_DECL_OVERRIDE;
- void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) Q_DECL_OVERRIDE;
- char const *const *attributeNames() const Q_DECL_OVERRIDE;
+ void deactivate() override;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
protected:
friend class QQuickOpenGLShaderEffectNode;
- void compile() Q_DECL_OVERRIDE;
- const char *vertexShader() const Q_DECL_OVERRIDE;
- const char *fragmentShader() const Q_DECL_OVERRIDE;
+ void compile() override;
+ const char *vertexShader() const override;
+ const char *fragmentShader() const override;
const QQuickOpenGLShaderEffectMaterialKey m_key;
QVector<QByteArray> m_attributes;
@@ -107,7 +111,7 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
{
typedef QQuickOpenGLShaderEffectMaterial::UniformData UniformData;
- Q_ASSERT(newEffect != 0);
+ Q_ASSERT(newEffect != nullptr);
QQuickOpenGLShaderEffectMaterial *material = static_cast<QQuickOpenGLShaderEffectMaterial *>(newEffect);
if (!material->m_emittedLogChanged && material->m_node) {
@@ -124,7 +128,7 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
for (int i = 0; i < material->uniforms[shaderType].size(); ++i) {
const UniformData &d = material->uniforms[shaderType].at(i);
QByteArray name = d.name;
- if (d.specialType == UniformData::Sampler) {
+ if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) {
program()->setUniformValue(d.name.constData(), textureProviderIndex++);
// We don't need to store the sampler uniform locations, since their values
// only need to be set once. Look for the "qt_SubRect_" uniforms instead.
@@ -143,7 +147,7 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
for (int i = 0; i < material->uniforms[shaderType].size(); ++i) {
const UniformData &d = material->uniforms[shaderType].at(i);
int loc = m_uniformLocs[shaderType].at(i);
- if (d.specialType == UniformData::Sampler) {
+ if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) {
int idx = textureProviderIndex++;
functions->glActiveTexture(GL_TEXTURE0 + idx);
if (QSGTextureProvider *provider = material->textureProviders.at(idx)) {
@@ -164,7 +168,10 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
continue;
}
}
- functions->glBindTexture(GL_TEXTURE_2D, 0);
+ if (d.specialType == UniformData::Sampler)
+ functions->glBindTexture(GL_TEXTURE_2D, 0);
+ else if (d.specialType == UniformData::SamplerExternal)
+ functions->glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
} else if (d.specialType == UniformData::Opacity) {
program()->setUniformValue(loc, state.opacity());
} else if (d.specialType == UniformData::Matrix) {
@@ -232,7 +239,7 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
functions->glActiveTexture(GL_TEXTURE0);
const QQuickOpenGLShaderEffectMaterial *oldMaterial = static_cast<const QQuickOpenGLShaderEffectMaterial *>(oldEffect);
- if (oldEffect == 0 || material->cullMode != oldMaterial->cullMode) {
+ if (oldEffect == nullptr || material->cullMode != oldMaterial->cullMode) {
switch (material->cullMode) {
case QQuickShaderEffect::FrontFaceCulling:
functions->glEnable(GL_CULL_FACE);
@@ -359,6 +366,7 @@ 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();
@@ -396,7 +404,7 @@ bool QQuickOpenGLShaderEffectMaterial::UniformData::operator == (const UniformDa
if (name != other.name)
return false;
- if (specialType == UniformData::Sampler) {
+ if (specialType == UniformData::Sampler || specialType == UniformData::SamplerExternal) {
// We can't check the source objects as these live in the GUI thread,
// so return true here and rely on the textureProvider check for
// equality of these..
diff --git a/src/quick/items/qquickopenglshadereffectnode_p.h b/src/quick/items/qquickopenglshadereffectnode_p.h
index aea28e6612..7c75bb3126 100644
--- a/src/quick/items/qquickopenglshadereffectnode_p.h
+++ b/src/quick/items/qquickopenglshadereffectnode_p.h
@@ -90,7 +90,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectMaterial : public QSGMateri
public:
struct UniformData
{
- enum SpecialType { None, Sampler, SubRect, Opacity, Matrix };
+ enum SpecialType { None, Sampler, SamplerExternal, SubRect, Opacity, Matrix };
QByteArray name;
QVariant value;
@@ -109,10 +109,10 @@ public:
}
};
- explicit QQuickOpenGLShaderEffectMaterial(QQuickOpenGLShaderEffectNode *node = 0);
- QSGMaterialType *type() const Q_DECL_OVERRIDE;
- QSGMaterialShader *createShader() const Q_DECL_OVERRIDE;
- int compare(const QSGMaterial *other) const Q_DECL_OVERRIDE;
+ explicit QQuickOpenGLShaderEffectMaterial(QQuickOpenGLShaderEffectNode *node = nullptr);
+ QSGMaterialType *type() const override;
+ QSGMaterialShader *createShader() const override;
+ int compare(const QSGMaterial *other) const override;
QVector<QByteArray> attributes;
QVector<UniformData> uniforms[QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount];
@@ -149,9 +149,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectNode : public QObject, publ
Q_OBJECT
public:
QQuickOpenGLShaderEffectNode();
- virtual ~QQuickOpenGLShaderEffectNode();
+ ~QQuickOpenGLShaderEffectNode() override;
- void preprocess() Q_DECL_OVERRIDE;
+ void preprocess() override;
Q_SIGNALS:
void logAndStatusChanged(const QString &, int status);
diff --git a/src/quick/items/qquickpainteditem.cpp b/src/quick/items/qquickpainteditem.cpp
index 34d71f00e8..57848919f3 100644
--- a/src/quick/items/qquickpainteditem.cpp
+++ b/src/quick/items/qquickpainteditem.cpp
@@ -53,7 +53,7 @@ class QQuickPaintedItemTextureProvider : public QSGTextureProvider
{
public:
QSGPainterNode *node;
- QSGTexture *texture() const override { return node ? node->texture() : 0; }
+ QSGTexture *texture() const override { return node ? node->texture() : nullptr; }
void fireTextureChanged() { emit textureChanged(); }
};
@@ -133,12 +133,12 @@ QQuickPaintedItemPrivate::QQuickPaintedItemPrivate()
, contentsScale(1.0)
, fillColor(Qt::transparent)
, renderTarget(QQuickPaintedItem::Image)
- , performanceHints(0)
+ , performanceHints(nullptr)
, opaquePainting(false)
, antialiasing(false)
, mipmap(false)
- , textureProvider(0)
- , node(0)
+ , textureProvider(nullptr)
+ , node(nullptr)
{
}
@@ -566,10 +566,10 @@ QSGNode *QQuickPaintedItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (width() <= 0 || height() <= 0) {
delete oldNode;
if (d->textureProvider) {
- d->textureProvider->node = 0;
+ d->textureProvider->node = nullptr;
d->textureProvider->fireTextureChanged();
}
- return 0;
+ return nullptr;
}
QSGPainterNode *node = static_cast<QSGPainterNode *>(oldNode);
@@ -628,17 +628,17 @@ void QQuickPaintedItem::releaseResources()
Q_D(QQuickPaintedItem);
if (d->textureProvider) {
QQuickWindowQObjectCleanupJob::schedule(window(), d->textureProvider);
- d->textureProvider = 0;
+ d->textureProvider = nullptr;
}
- d->node = 0; // Managed by the scene graph, just clear the pointer.
+ d->node = nullptr; // Managed by the scene graph, just clear the pointer.
}
void QQuickPaintedItem::invalidateSceneGraph()
{
Q_D(QQuickPaintedItem);
delete d->textureProvider;
- d->textureProvider = 0;
- d->node = 0; // Managed by the scene graph, just clear the pointer
+ d->textureProvider = nullptr;
+ d->node = nullptr; // Managed by the scene graph, just clear the pointer
}
/*!
@@ -666,7 +666,7 @@ QSGTextureProvider *QQuickPaintedItem::textureProvider() const
QQuickWindow *w = window();
if (!w || !w->openglContext() || QThread::currentThread() != w->openglContext()->thread()) {
qWarning("QQuickPaintedItem::textureProvider: can only be queried on the rendering thread of an exposed window");
- return 0;
+ return nullptr;
}
#endif
if (!d->textureProvider)
@@ -675,6 +675,10 @@ QSGTextureProvider *QQuickPaintedItem::textureProvider() const
return d->textureProvider;
}
+
+/*!
+ \reimp
+*/
void QQuickPaintedItem::itemChange(ItemChange change, const ItemChangeData &value)
{
if (change == ItemDevicePixelRatioHasChanged)
diff --git a/src/quick/items/qquickpainteditem.h b/src/quick/items/qquickpainteditem.h
index e8b471ac01..ddc1fd99d9 100644
--- a/src/quick/items/qquickpainteditem.h
+++ b/src/quick/items/qquickpainteditem.h
@@ -57,8 +57,8 @@ class Q_QUICK_EXPORT QQuickPaintedItem : public QQuickItem
Q_PROPERTY(QSize textureSize READ textureSize WRITE setTextureSize NOTIFY textureSizeChanged)
public:
- explicit QQuickPaintedItem(QQuickItem *parent = Q_NULLPTR);
- virtual ~QQuickPaintedItem();
+ explicit QQuickPaintedItem(QQuickItem *parent = nullptr);
+ ~QQuickPaintedItem() override;
enum RenderTarget {
Image,
@@ -71,6 +71,7 @@ public:
FastFBOResizing = 0x1
};
Q_DECLARE_FLAGS(PerformanceHints, PerformanceHint)
+ Q_FLAG(PerformanceHints)
void update(const QRect &rect = QRect());
@@ -107,8 +108,8 @@ public:
virtual void paint(QPainter *painter) = 0;
- bool isTextureProvider() const Q_DECL_OVERRIDE;
- QSGTextureProvider *textureProvider() const Q_DECL_OVERRIDE;
+ bool isTextureProvider() const override;
+ QSGTextureProvider *textureProvider() const override;
Q_SIGNALS:
void fillColorChanged();
@@ -118,10 +119,10 @@ Q_SIGNALS:
void textureSizeChanged();
protected:
- QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent = Q_NULLPTR);
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
- void releaseResources() Q_DECL_OVERRIDE;
- void itemChange(ItemChange, const ItemChangeData &) Q_DECL_OVERRIDE;
+ QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent = nullptr);
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
+ void releaseResources() override;
+ void itemChange(ItemChange, const ItemChangeData &) override;
private Q_SLOTS:
void invalidateSceneGraph();
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index aac2b0296a..be8532bf64 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -66,7 +66,7 @@ const qreal MinimumFlickVelocity = 75.0;
static QQmlOpenMetaObjectType *qPathViewAttachedType = nullptr;
QQuickPathViewAttached::QQuickPathViewAttached(QObject *parent)
-: QObject(parent), m_percent(-1), m_view(0), m_onPath(false), m_isCurrent(false)
+: QObject(parent), m_percent(-1), m_view(nullptr), m_onPath(false), m_isCurrent(false)
{
if (qPathViewAttachedType) {
m_metaobject = new QQmlOpenMetaObject(this, qPathViewAttachedType);
@@ -129,7 +129,7 @@ QQuickItem *QQuickPathViewPrivate::getItem(int modelIndex, qreal z, bool async)
requestedIndex = modelIndex;
requestedZ = z;
inRequest = true;
- QObject *object = model->object(modelIndex, async);
+ QObject *object = model->object(modelIndex, async ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
if (!item) {
if (object) {
@@ -240,9 +240,13 @@ void QQuickPathViewPrivate::clear()
releaseItem(currentItem);
currentItem = nullptr;
}
+
for (QQuickItem *p : qAsConst(items))
releaseItem(p);
+ for (QQuickItem *p : qAsConst(itemCache))
+ releaseItem(p);
+
if (requestedIndex >= 0) {
if (model)
model->cancel(requestedIndex);
@@ -250,6 +254,7 @@ void QQuickPathViewPrivate::clear()
}
items.clear();
+ itemCache.clear();
tl.clear();
}
@@ -475,7 +480,7 @@ void QQuickPathViewPrivate::setDragging(bool d)
\ingroup qtquick-paths
\ingroup qtquick-views
\inherits Item
- \brief Lays out model-provided items on a path
+ \brief Lays out model-provided items on a path.
A PathView displays data from models created from built-in QML types like ListModel
and XmlListModel, or custom model classes defined in C++ that inherit from
@@ -1545,6 +1550,33 @@ QQuickItem *QQuickPathView::itemAt(qreal x, qreal y) const
return nullptr;
}
+/*!
+ \qmlmethod Item QtQuick::QQuickPathView::itemAtIndex(int index)
+
+ Returns the item for \a index. If there is no item for that index, for example
+ because it has not been created yet, or because it has been panned out of
+ the visible area and removed from the cache, null is returned.
+
+ \b Note: this method should only be called after the Component has completed.
+ The returned value should also not be stored since it can turn to null
+ as soon as control goes out of the calling scope, if the view releases that item.
+
+ \since 5.13
+*/
+QQuickItem *QQuickPathView::itemAtIndex(int index) const
+{
+ Q_D(const QQuickPathView);
+ if (!d->isValid())
+ return nullptr;
+
+ for (QQuickItem *item : d->items) {
+ if (index == d->model->indexOf(item, nullptr))
+ return item;
+ }
+
+ return nullptr;
+}
+
QPointF QQuickPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercent) const
{
const auto pathLength = path->path().length();
@@ -1627,6 +1659,7 @@ void QQuickPathView::mousePressEvent(QMouseEvent *event)
void QQuickPathViewPrivate::handleMousePressEvent(QMouseEvent *event)
{
+ Q_Q(QQuickPathView);
if (!interactive || !items.count() || !model || !modelCount)
return;
velocityBuffer.clear();
@@ -1652,6 +1685,7 @@ void QQuickPathViewPrivate::handleMousePressEvent(QMouseEvent *event)
stealMouse = true; // If we've been flicked then steal the click.
else
stealMouse = false;
+ q->setKeepMouseGrab(stealMouse);
timer.start();
lastPosTime = computeCurrentTime(event);
@@ -2396,7 +2430,11 @@ void QQuickPathViewPrivate::snapToIndex(int index, MovementReason reason)
const int duration = highlightMoveDuration;
- if (!duration) {
+ const qreal count = pathItems == -1 ? modelCount : qMin(pathItems, modelCount);
+ const qreal averageItemLength = path->path().length() / count;
+ const qreal threshold = 0.5 / averageItemLength; // if we are within .5 px, we want to immediately assign rather than animate
+
+ 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)) {
qreal distance = modelCount - targetOffset + offset;
diff --git a/src/quick/items/qquickpathview_p.h b/src/quick/items/qquickpathview_p.h
index 0e237b7b74..66be7fa6ff 100644
--- a/src/quick/items/qquickpathview_p.h
+++ b/src/quick/items/qquickpathview_p.h
@@ -180,6 +180,7 @@ public:
Q_INVOKABLE void positionViewAtIndex(int index, int mode);
Q_INVOKABLE int indexAt(qreal x, qreal y) const;
Q_INVOKABLE QQuickItem *itemAt(qreal x, qreal y) const;
+ Q_REVISION(13) Q_INVOKABLE QQuickItem *itemAtIndex(int index) const;
static QQuickPathViewAttached *qmlAttachedProperties(QObject *);
diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h
index d58c986d1a..274086ea7c 100644
--- a/src/quick/items/qquickpathview_p_p.h
+++ b/src/quick/items/qquickpathview_p_p.h
@@ -153,7 +153,6 @@ public:
bool moving : 1;
bool flicking : 1;
bool dragging : 1;
- bool requestedOnPath : 1;
bool inRequest : 1;
bool delegateValidated : 1;
bool inRefill : 1;
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index 3f6ce7b8ba..3d4f195380 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE
\instantiates QQuickPinchEvent
\inqmlmodule QtQuick
\ingroup qtquick-input-events
- \brief For specifying information about a pinch event
+ \brief For specifying information about a pinch event.
\b {The PinchEvent type was added in QtQuick 1.1}
@@ -151,7 +151,7 @@ QT_BEGIN_NAMESPACE
*/
QQuickPinch::QQuickPinch()
- : m_target(0), m_minScale(1.0), m_maxScale(1.0)
+ : m_target(nullptr), m_minScale(1.0), m_maxScale(1.0)
, m_minRotation(0.0), m_maxRotation(0.0)
, m_axis(NoDrag), m_xmin(-FLT_MAX), m_xmax(FLT_MAX)
, m_ymin(-FLT_MAX), m_ymax(FLT_MAX), m_active(false)
@@ -169,7 +169,7 @@ QQuickPinchAreaPrivate::~QQuickPinchAreaPrivate()
\inqmlmodule QtQuick
\ingroup qtquick-input
\inherits Item
- \brief Enables simple pinch gesture handling
+ \brief Enables simple pinch gesture handling.
\b {The PinchArea type was added in QtQuick 1.1}
@@ -288,6 +288,7 @@ QQuickPinchArea::QQuickPinchArea(QQuickItem *parent)
{
Q_D(QQuickPinchArea);
d->init();
+ setAcceptTouchEvents(true);
#ifdef Q_OS_OSX
setAcceptHoverEvents(true); // needed to enable touch events on mouse hover.
#endif
@@ -643,7 +644,8 @@ bool QQuickPinchArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
return QQuickItem::childMouseEventFilter(i, e);
switch (e->type()) {
case QEvent::TouchBegin:
- clearPinch(); // fall through
+ clearPinch();
+ Q_FALLTHROUGH();
case QEvent::TouchUpdate: {
QTouchEvent *touch = static_cast<QTouchEvent*>(e);
d->touchPoints.clear();
diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h
index fc96594a4b..8eff53e6dc 100644
--- a/src/quick/items/qquickpincharea_p.h
+++ b/src/quick/items/qquickpincharea_p.h
@@ -84,7 +84,7 @@ public:
void resetTarget() {
if (!m_target)
return;
- m_target = 0;
+ m_target = nullptr;
Q_EMIT targetChanged();
}
@@ -270,7 +270,7 @@ class Q_AUTOTEST_EXPORT QQuickPinchArea : public QQuickItem
Q_PROPERTY(QQuickPinch *pinch READ pinch CONSTANT)
public:
- QQuickPinchArea(QQuickItem *parent=0);
+ QQuickPinchArea(QQuickItem *parent=nullptr);
~QQuickPinchArea();
bool isEnabled() const;
@@ -286,13 +286,13 @@ Q_SIGNALS:
Q_REVISION(1) void smartZoom(QQuickPinchEvent *pinch);
protected:
- bool childMouseEventFilter(QQuickItem *i, QEvent *e) Q_DECL_OVERRIDE;
- void touchEvent(QTouchEvent *event) Q_DECL_OVERRIDE;
+ bool childMouseEventFilter(QQuickItem *i, QEvent *e) override;
+ void touchEvent(QTouchEvent *event) override;
void geometryChanged(const QRectF &newGeometry,
- const QRectF &oldGeometry) Q_DECL_OVERRIDE;
- void itemChange(ItemChange change, const ItemChangeData& value) Q_DECL_OVERRIDE;
- bool event(QEvent *) Q_DECL_OVERRIDE;
+ const QRectF &oldGeometry) override;
+ void itemChange(ItemChange change, const ItemChangeData& value) override;
+ bool event(QEvent *) override;
private:
void clearPinch();
diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp
index e752e2538f..512f59d799 100644
--- a/src/quick/items/qquickpositioners.cpp
+++ b/src/quick/items/qquickpositioners.cpp
@@ -69,7 +69,7 @@ void QQuickBasePositionerPrivate::unwatchChanges(QQuickItem* other)
QQuickBasePositioner::PositionedItem::PositionedItem(QQuickItem *i)
: item(i)
- , transitionableItem(0)
+ , transitionableItem(nullptr)
, index(-1)
, isNew(false)
, isVisible(true)
@@ -203,7 +203,7 @@ void QQuickBasePositioner::setSpacing(qreal s)
QQuickTransition *QQuickBasePositioner::populate() const
{
Q_D(const QQuickBasePositioner);
- return d->transitioner ? d->transitioner->populateTransition : 0;
+ return d->transitioner ? d->transitioner->populateTransition : nullptr;
}
void QQuickBasePositioner::setPopulate(QQuickTransition *transition)
@@ -220,7 +220,7 @@ void QQuickBasePositioner::setPopulate(QQuickTransition *transition)
QQuickTransition *QQuickBasePositioner::move() const
{
Q_D(const QQuickBasePositioner);
- return d->transitioner ? d->transitioner->displacedTransition : 0;
+ return d->transitioner ? d->transitioner->displacedTransition : nullptr;
}
void QQuickBasePositioner::setMove(QQuickTransition *mt)
@@ -238,7 +238,7 @@ void QQuickBasePositioner::setMove(QQuickTransition *mt)
QQuickTransition *QQuickBasePositioner::add() const
{
Q_D(const QQuickBasePositioner);
- return d->transitioner ? d->transitioner->addTransition : 0;
+ return d->transitioner ? d->transitioner->addTransition : nullptr;
}
void QQuickBasePositioner::setAdd(QQuickTransition *add)
@@ -460,15 +460,15 @@ void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *sp
// be changed to run only when there are attached properties present. This
// could be a flag in the positioner that is set by the attached property
// constructor.
- QQuickPositionerAttached *prevLastProperty = 0;
- QQuickPositionerAttached *lastProperty = 0;
+ QQuickPositionerAttached *prevLastProperty = nullptr;
+ QQuickPositionerAttached *lastProperty = nullptr;
for (int ii = 0; ii < positionedItems.count(); ++ii) {
const PositionedItem &child = positionedItems.at(ii);
if (!child.item)
continue;
- QQuickPositionerAttached *property = 0;
+ QQuickPositionerAttached *property = nullptr;
if (specificProperty) {
if (specificPropertyOwner == child.item) {
@@ -503,7 +503,7 @@ void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *sp
if (!child.item)
continue;
- QQuickPositionerAttached *property = 0;
+ QQuickPositionerAttached *property = nullptr;
if (specificProperty) {
if (specificPropertyOwner == child.item) {
@@ -705,7 +705,7 @@ void QQuickBasePositionerPrivate::setBottomPadding(qreal value, bool reset)
\instantiates QQuickPositionerAttached
\inqmlmodule QtQuick
\ingroup qtquick-positioners
- \brief Provides attached properties that contain details on where an item exists in a positioner
+ \brief Provides attached properties that contain details on where an item exists in a positioner.
An object of type Positioner is attached to the top-level child item within a
Column, Row, Flow or Grid. It provides properties that allow a child item to determine
@@ -789,7 +789,7 @@ void QQuickPositionerAttached::setIsLastItem(bool isLastItem)
\inqmlmodule QtQuick
\inherits Item
\ingroup qtquick-positioners
- \brief Positions its children in a column
+ \brief Positions its children in a column.
Column is a type that positions its child items along a single column.
It can be used as a convenient way to vertically position a series of items without
@@ -900,11 +900,7 @@ void QQuickPositionerAttached::setIsLastItem(bool isLastItem)
cases, these lists will be empty. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \note In \l {Qt Quick 1}, this transition was applied to all items that were part of the
- positioner at the time of its creation. From \l {Qt Quick}{Qt Quick 2} onwards, positioners apply the
- \l populate transition to these items instead.
-
- \sa add, ViewTransition, {Qt Quick Examples - Positioners}
+ \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty real QtQuick::Column::spacing
@@ -993,7 +989,7 @@ void QQuickColumn::reportConflictingAnchors()
\inqmlmodule QtQuick
\inherits Item
\ingroup qtquick-positioners
- \brief Positions its children in a row
+ \brief Positions its children in a row.
Row is a type that positions its child items along a single row.
It can be used as a convenient way to horizontally position a series of items without
@@ -1089,11 +1085,7 @@ void QQuickColumn::reportConflictingAnchors()
cases, these lists will be empty. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \note In \l {Qt Quick 1}, this transition was applied to all items that were part of the
- positioner at the time of its creation. From \l {Qt Quick}{QtQuick 2} onwards, positioners apply the
- \l populate transition to these items instead.
-
- \sa add, ViewTransition, {Qt Quick Examples - Positioners}
+ \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty real QtQuick::Row::spacing
@@ -1281,7 +1273,7 @@ void QQuickRow::reportConflictingAnchors()
\inqmlmodule QtQuick
\inherits Item
\ingroup qtquick-positioners
- \brief Positions its children in grid formation
+ \brief Positions its children in grid formation.
Grid is a type that positions its child items in grid formation.
@@ -1378,11 +1370,7 @@ void QQuickRow::reportConflictingAnchors()
cases, these lists will be empty. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \note In \l {Qt Quick 1}, this transition was applied to all items that were part of the
- positioner at the time of its creation. From \l {Qt Quick}{QtQuick 2} onwards, positioners apply the
- \l populate transition to these items instead.
-
- \sa add, ViewTransition, {Qt Quick Examples - Positioners}
+ \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty qreal QtQuick::Grid::spacing
@@ -1885,7 +1873,7 @@ void QQuickGrid::reportConflictingAnchors()
\inqmlmodule QtQuick
\inherits Item
\ingroup qtquick-positioners
- \brief Positions its children side by side, wrapping as necessary
+ \brief Positions its children side by side, wrapping as necessary.
The Flow item positions its child items like words on a page, wrapping them
to create rows or columns of items.
@@ -1974,11 +1962,7 @@ void QQuickGrid::reportConflictingAnchors()
cases, these lists will be empty. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \note In \l {Qt Quick 1}, this transition was applied to all items that were part of the
- positioner at the time of its creation. From \l {Qt Quick}{QtQuick 2} onwards, positioners apply the
- \l populate transition to these items instead.
-
- \sa add, ViewTransition, {Qt Quick Examples - Positioners}
+ \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty real QtQuick::Flow::spacing
diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h
index 9ae7029d69..94a737e1f1 100644
--- a/src/quick/items/qquickpositioners_p.h
+++ b/src/quick/items/qquickpositioners_p.h
@@ -132,7 +132,7 @@ public:
static QQuickPositionerAttached *qmlAttachedProperties(QObject *obj);
- void updateAttachedProperties(QQuickPositionerAttached *specificProperty = 0, QQuickItem *specificPropertyOwner = 0) const;
+ void updateAttachedProperties(QQuickPositionerAttached *specificProperty = nullptr, QQuickItem *specificPropertyOwner = nullptr) const;
qreal padding() const;
void setPadding(qreal padding);
@@ -158,10 +158,10 @@ public:
protected:
QQuickBasePositioner(QQuickBasePositionerPrivate &dd, PositionerType at, QQuickItem *parent);
- void componentComplete() Q_DECL_OVERRIDE;
- void itemChange(ItemChange, const ItemChangeData &) Q_DECL_OVERRIDE;
+ void componentComplete() override;
+ void itemChange(ItemChange, const ItemChangeData &) override;
- void updatePolish() Q_DECL_OVERRIDE;
+ void updatePolish() override;
Q_SIGNALS:
void spacingChanged();
@@ -231,11 +231,11 @@ class Q_AUTOTEST_EXPORT QQuickColumn : public QQuickBasePositioner
{
Q_OBJECT
public:
- QQuickColumn(QQuickItem *parent=0);
+ QQuickColumn(QQuickItem *parent=nullptr);
protected:
- void doPositioning(QSizeF *contentSize) Q_DECL_OVERRIDE;
- void reportConflictingAnchors() Q_DECL_OVERRIDE;
+ void doPositioning(QSizeF *contentSize) override;
+ void reportConflictingAnchors() override;
private:
Q_DISABLE_COPY(QQuickColumn)
};
@@ -247,7 +247,7 @@ class Q_AUTOTEST_EXPORT QQuickRow: public QQuickBasePositioner
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
public:
- QQuickRow(QQuickItem *parent=0);
+ QQuickRow(QQuickItem *parent=nullptr);
Qt::LayoutDirection layoutDirection() const;
void setLayoutDirection (Qt::LayoutDirection);
@@ -258,8 +258,8 @@ Q_SIGNALS:
void effectiveLayoutDirectionChanged();
protected:
- void doPositioning(QSizeF *contentSize) Q_DECL_OVERRIDE;
- void reportConflictingAnchors() Q_DECL_OVERRIDE;
+ void doPositioning(QSizeF *contentSize) override;
+ void reportConflictingAnchors() override;
private:
Q_DISABLE_COPY(QQuickRow)
Q_DECLARE_PRIVATE(QQuickRow)
@@ -281,7 +281,7 @@ class Q_AUTOTEST_EXPORT QQuickGrid : public QQuickBasePositioner
Q_PROPERTY(VAlignment verticalItemAlignment READ vItemAlign WRITE setVItemAlign NOTIFY verticalAlignmentChanged REVISION 1)
public:
- QQuickGrid(QQuickItem *parent=0);
+ QQuickGrid(QQuickItem *parent=nullptr);
int rows() const { return m_rows; }
void setRows(const int rows);
@@ -335,8 +335,8 @@ Q_SIGNALS:
Q_REVISION(1) void verticalAlignmentChanged(VAlignment alignment);
protected:
- void doPositioning(QSizeF *contentSize) Q_DECL_OVERRIDE;
- void reportConflictingAnchors() Q_DECL_OVERRIDE;
+ void doPositioning(QSizeF *contentSize) override;
+ void reportConflictingAnchors() override;
private:
int m_rows;
@@ -360,7 +360,7 @@ class Q_AUTOTEST_EXPORT QQuickFlow: public QQuickBasePositioner
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
public:
- QQuickFlow(QQuickItem *parent=0);
+ QQuickFlow(QQuickItem *parent=nullptr);
enum Flow { LeftToRight, TopToBottom };
Q_ENUM(Flow)
@@ -377,8 +377,8 @@ Q_SIGNALS:
void effectiveLayoutDirectionChanged();
protected:
- void doPositioning(QSizeF *contentSize) Q_DECL_OVERRIDE;
- void reportConflictingAnchors() Q_DECL_OVERRIDE;
+ void doPositioning(QSizeF *contentSize) override;
+ void reportConflictingAnchors() override;
protected:
QQuickFlow(QQuickFlowPrivate &dd, QQuickItem *parent);
private:
diff --git a/src/quick/items/qquickpositioners_p_p.h b/src/quick/items/qquickpositioners_p_p.h
index 0be4c56df6..f4cb283a22 100644
--- a/src/quick/items/qquickpositioners_p_p.h
+++ b/src/quick/items/qquickpositioners_p_p.h
@@ -122,7 +122,7 @@ public:
Qt::LayoutDirection layoutDirection;
- void mirrorChange() Q_DECL_OVERRIDE {
+ void mirrorChange() override {
effectiveLayoutDirectionChange();
}
bool isLeftToRight() const {
@@ -132,24 +132,24 @@ public:
return effectiveLayoutMirror ? layoutDirection == Qt::RightToLeft : layoutDirection == Qt::LeftToRight;
}
- void itemSiblingOrderChanged(QQuickItem* other) Q_DECL_OVERRIDE
+ void itemSiblingOrderChanged(QQuickItem* other) override
{
Q_UNUSED(other);
setPositioningDirty();
}
- void itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &) override
{
if (change.sizeChange())
setPositioningDirty();
}
- void itemVisibilityChanged(QQuickItem *) Q_DECL_OVERRIDE
+ void itemVisibilityChanged(QQuickItem *) override
{
setPositioningDirty();
}
- void itemDestroyed(QQuickItem *item) Q_DECL_OVERRIDE
+ void itemDestroyed(QQuickItem *item) override
{
Q_Q(QQuickBasePositioner);
int index = q->positionedItems.find(QQuickBasePositioner::PositionedItem(item));
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index 65284eb532..5e217dcd0c 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -40,9 +40,13 @@
#include "qquickrectangle_p.h"
#include "qquickrectangle_p_p.h"
+#include <QtQml/qqmlinfo.h>
+
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qsgadaptationlayer_p.h>
+#include <private/qqmlmetatype_p.h>
+
#include <QtGui/qpixmapcache.h>
#include <QtCore/qmath.h>
#include <QtCore/qmetaobject.h>
@@ -132,7 +136,7 @@ bool QQuickPen::isValid() const
\instantiates QQuickGradientStop
\inqmlmodule QtQuick
\ingroup qtquick-visual-utility
- \brief Defines the color at a position in a Gradient
+ \brief Defines the color at a position in a Gradient.
\sa Gradient
*/
@@ -184,7 +188,7 @@ void QQuickGradientStop::updateGradient()
\instantiates QQuickGradient
\inqmlmodule QtQuick
\ingroup qtquick-visual-utility
- \brief Defines a gradient fill
+ \brief Defines a gradient fill.
A gradient is defined by two or more colors, which will be blended seamlessly.
@@ -219,10 +223,11 @@ void QQuickGradientStop::updateGradient()
of solid color fills or images. Consider using gradients for static items
in a user interface.
- In Qt 5.0, only vertical, linear gradients can be applied to items. If you
- need to apply different orientations of gradients, a combination of rotation
- and clipping will need to be applied to the relevant items. This can
- introduce additional performance requirements for your application.
+ Since Qt 5.12, vertical and horizontal linear gradients can be applied to items.
+ If you need to apply angled gradients, a combination of rotation and clipping
+ can be applied to the relevant items. Alternatively, consider using
+ QtQuick.Shapes::LinearGradient or QtGraphicalEffects::LinearGradient. These
+ approaches can all introduce additional performance requirements for your application.
The use of animations involving gradient stops may not give the desired
result. An alternative way to animate gradients is to use pre-generated
@@ -255,6 +260,28 @@ QQmlListProperty<QQuickGradientStop> QQuickGradient::stops()
return QQmlListProperty<QQuickGradientStop>(this, m_stops);
}
+/*!
+ \qmlproperty enumeration QtQuick::Gradient::orientation
+ \since 5.12
+
+ Set this property to define the direction of the gradient.
+ \list
+ \li Gradient.Vertical - a vertical gradient
+ \li Gradient.Horizontal - a horizontal gradient
+ \endlist
+
+ The default is Gradient.Vertical.
+*/
+void QQuickGradient::setOrientation(Orientation orientation)
+{
+ if (m_orientation == orientation)
+ return;
+
+ m_orientation = orientation;
+ emit orientationChanged();
+ emit updated();
+}
+
QGradientStops QQuickGradient::gradientStops() const
{
QGradientStops stops;
@@ -280,7 +307,7 @@ int QQuickRectanglePrivate::doUpdateSlotIdx = -1;
\inqmlmodule QtQuick
\inherits Item
\ingroup qtquick-visual
- \brief Paints a filled rectangle with an optional border
+ \brief Paints a filled rectangle with an optional border.
Rectangle items are used to fill areas with solid color or gradients, and/or
to provide a rectangular border.
@@ -325,6 +352,9 @@ QQuickRectangle::QQuickRectangle(QQuickItem *parent)
: QQuickItem(*(new QQuickRectanglePrivate), parent)
{
setFlag(ItemHasContents);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ setAcceptTouchEvents(false);
+#endif
}
void QQuickRectangle::doUpdate()
@@ -367,11 +397,11 @@ QQuickPen *QQuickRectangle::border()
}
/*!
- \qmlproperty Gradient QtQuick::Rectangle::gradient
+ \qmlproperty any QtQuick::Rectangle::gradient
The gradient to use to fill the rectangle.
- This property allows for the construction of simple vertical gradients.
+ This property allows for the construction of simple vertical or horizontal gradients.
Other gradients may be formed by adding rotation to the rectangle.
\div {class="float-left"}
@@ -381,37 +411,66 @@ QQuickPen *QQuickRectangle::border()
\snippet qml/rectangle/rectangle-gradient.qml rectangles
\clearfloat
+ The property also accepts gradient presets from QGradient::Preset. Note however
+ that due to Rectangle only supporting simple vertical or horizontal gradients,
+ any preset with an unsupported angle will revert to the closest representation.
+
+ \snippet qml/rectangle/rectangle-gradient.qml presets
+ \clearfloat
+
If both a gradient and a color are specified, the gradient will be used.
\sa Gradient, color
*/
-QQuickGradient *QQuickRectangle::gradient() const
+QJSValue QQuickRectangle::gradient() const
{
Q_D(const QQuickRectangle);
return d->gradient;
}
-void QQuickRectangle::setGradient(QQuickGradient *gradient)
+void QQuickRectangle::setGradient(const QJSValue &gradient)
{
Q_D(QQuickRectangle);
- if (d->gradient == gradient)
+ if (d->gradient.equals(gradient))
return;
- static int updatedSignalIdx = -1;
- if (updatedSignalIdx < 0)
- updatedSignalIdx = QMetaMethod::fromSignal(&QQuickGradient::updated).methodIndex();
+
+ static int updatedSignalIdx = QMetaMethod::fromSignal(&QQuickGradient::updated).methodIndex();
if (d->doUpdateSlotIdx < 0)
d->doUpdateSlotIdx = QQuickRectangle::staticMetaObject.indexOfSlot("doUpdate()");
- if (d->gradient)
- QMetaObject::disconnect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
- d->gradient = gradient;
- if (d->gradient)
- QMetaObject::connect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
+
+ if (auto oldGradient = qobject_cast<QQuickGradient*>(d->gradient.toQObject()))
+ QMetaObject::disconnect(oldGradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
+
+ if (gradient.isQObject()) {
+ if (auto newGradient = qobject_cast<QQuickGradient*>(gradient.toQObject())) {
+ d->gradient = gradient;
+ QMetaObject::connect(newGradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
+ } else {
+ qmlWarning(this) << "Can't assign "
+ << QQmlMetaType::prettyTypeName(gradient.toQObject()) << " to gradient property";
+ d->gradient = QJSValue();
+ }
+ } else if (gradient.isNumber() || gradient.isString()) {
+ QGradient preset(gradient.toVariant().value<QGradient::Preset>());
+ if (preset.type() != QGradient::NoGradient) {
+ d->gradient = gradient;
+ } else {
+ qmlWarning(this) << "No such gradient preset '" << gradient.toString() << "'";
+ d->gradient = QJSValue();
+ }
+ } else if (gradient.isNull() || gradient.isUndefined()) {
+ d->gradient = gradient;
+ } else {
+ qmlWarning(this) << "Unknown gradient type. Expected int, string, or Gradient";
+ d->gradient = QJSValue();
+ }
+
update();
}
void QQuickRectangle::resetGradient()
{
- setGradient(0);
+ setGradient(QJSValue());
}
/*!
@@ -486,7 +545,7 @@ QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
if (width() <= 0 || height() <= 0
|| (d->color.alpha() == 0 && (!d->pen || d->pen->width() == 0 || d->pen->color().alpha() == 0))) {
delete oldNode;
- return 0;
+ return nullptr;
}
QSGInternalRectangleNode *rectangle = static_cast<QSGInternalRectangleNode *>(oldNode);
@@ -507,10 +566,35 @@ QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
rectangle->setAntialiasing(antialiasing());
QGradientStops stops;
- if (d->gradient) {
- stops = d->gradient->gradientStops();
+ bool vertical = true;
+ if (d->gradient.isQObject()) {
+ auto gradient = qobject_cast<QQuickGradient*>(d->gradient.toQObject());
+ Q_ASSERT(gradient);
+ stops = gradient->gradientStops();
+ vertical = gradient->orientation() == QQuickGradient::Vertical;
+ } else if (d->gradient.isNumber() || d->gradient.isString()) {
+ QGradient preset(d->gradient.toVariant().value<QGradient::Preset>());
+ if (preset.type() == QGradient::LinearGradient) {
+ auto linearGradient = static_cast<QLinearGradient&>(preset);
+ const QPointF start = linearGradient.start();
+ const QPointF end = linearGradient.finalStop();
+ vertical = qAbs(start.y() - end.y()) >= qAbs(start.x() - end.x());
+ stops = linearGradient.stops();
+ if ((vertical && start.y() > end.y()) || (!vertical && start.x() > end.x())) {
+ // QSGInternalRectangleNode doesn't support stops in the wrong order,
+ // so we need to manually reverse them here.
+ QGradientStops reverseStops;
+ for (auto it = stops.rbegin(); it != stops.rend(); ++it) {
+ auto stop = *it;
+ stop.first = 1 - stop.first;
+ reverseStops.append(stop);
+ }
+ stops = reverseStops;
+ }
+ }
}
rectangle->setGradientStops(stops);
+ rectangle->setGradientVertical(vertical);
rectangle->update();
diff --git a/src/quick/items/qquickrectangle_p.h b/src/quick/items/qquickrectangle_p.h
index 724a06013c..d56a03d22d 100644
--- a/src/quick/items/qquickrectangle_p.h
+++ b/src/quick/items/qquickrectangle_p.h
@@ -67,7 +67,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPen : public QObject
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY penChanged)
Q_PROPERTY(bool pixelAligned READ pixelAligned WRITE setPixelAligned NOTIFY penChanged)
public:
- QQuickPen(QObject *parent=0);
+ QQuickPen(QObject *parent=nullptr);
qreal width() const;
void setWidth(qreal w);
@@ -98,7 +98,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickGradientStop : public QObject
Q_PROPERTY(QColor color READ color WRITE setColor)
public:
- QQuickGradientStop(QObject *parent=0);
+ QQuickGradientStop(QObject *parent=nullptr);
qreal position() const;
void setPosition(qreal position);
@@ -119,24 +119,35 @@ class Q_QUICK_PRIVATE_EXPORT QQuickGradient : public QObject
Q_OBJECT
Q_PROPERTY(QQmlListProperty<QQuickGradientStop> stops READ stops)
+ Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged REVISION 12)
Q_CLASSINFO("DefaultProperty", "stops")
+ Q_ENUMS(QGradient::Preset)
public:
- QQuickGradient(QObject *parent=0);
- ~QQuickGradient();
+ QQuickGradient(QObject *parent=nullptr);
+ ~QQuickGradient() override;
+
+ enum Orientation { Vertical = Qt::Vertical,
+ Horizontal = Qt::Horizontal };
+ Q_ENUM(Orientation)
QQmlListProperty<QQuickGradientStop> stops();
+ Orientation orientation() const { return m_orientation; }
+ void setOrientation(Orientation orientation);
+
QGradientStops gradientStops() const;
Q_SIGNALS:
void updated();
+ void orientationChanged();
private:
void doUpdate();
private:
QList<QQuickGradientStop *> m_stops;
+ Orientation m_orientation = Vertical;
friend class QQuickRectangle;
friend class QQuickGradientStop;
};
@@ -147,19 +158,19 @@ class Q_QUICK_PRIVATE_EXPORT QQuickRectangle : public QQuickItem
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
- Q_PROPERTY(QQuickGradient *gradient READ gradient WRITE setGradient RESET resetGradient)
+ Q_PROPERTY(QJSValue gradient READ gradient WRITE setGradient RESET resetGradient)
Q_PROPERTY(QQuickPen * border READ border CONSTANT)
Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
public:
- QQuickRectangle(QQuickItem *parent=0);
+ QQuickRectangle(QQuickItem *parent=nullptr);
QColor color() const;
void setColor(const QColor &);
QQuickPen *border();
- QQuickGradient *gradient() const;
- void setGradient(QQuickGradient *gradient);
+ QJSValue gradient() const;
+ void setGradient(const QJSValue &gradient);
void resetGradient();
qreal radius() const;
@@ -170,7 +181,7 @@ Q_SIGNALS:
void radiusChanged();
protected:
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
private Q_SLOTS:
void doUpdate();
diff --git a/src/quick/items/qquickrectangle_p_p.h b/src/quick/items/qquickrectangle_p_p.h
index 3c1aaf7661..c7c5293f9b 100644
--- a/src/quick/items/qquickrectangle_p_p.h
+++ b/src/quick/items/qquickrectangle_p_p.h
@@ -73,7 +73,7 @@ public:
}
QColor color;
- QQuickGradient *gradient;
+ QJSValue gradient;
QQuickPen *pen;
qreal radius;
static int doUpdateSlotIdx;
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index f2828bbedd..f6d4e7ed49 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -133,11 +133,11 @@ extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_
\inmodule QtQuick
*/
-QSGContext *QQuickRenderControlPrivate::sg = 0;
+QSGContext *QQuickRenderControlPrivate::sg = nullptr;
QQuickRenderControlPrivate::QQuickRenderControlPrivate()
: initialized(0),
- window(0)
+ window(nullptr)
{
if (!sg) {
qAddPostRoutine(cleanup);
@@ -149,7 +149,7 @@ QQuickRenderControlPrivate::QQuickRenderControlPrivate()
void QQuickRenderControlPrivate::cleanup()
{
delete sg;
- sg = 0;
+ sg = nullptr;
}
/*!
@@ -173,7 +173,7 @@ QQuickRenderControl::~QQuickRenderControl()
invalidate();
if (d->window)
- QQuickWindowPrivate::get(d->window)->renderControl = 0;
+ QQuickWindowPrivate::get(d->window)->renderControl = nullptr;
// It is likely that the cleanup in windowDestroyed() is not called since
// the standard pattern is to destroy the rendercontrol before the QQuickWindow.
@@ -187,16 +187,16 @@ void QQuickRenderControlPrivate::windowDestroyed()
{
if (window) {
rc->invalidate();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete QQuickWindowPrivate::get(window)->animationController;
- QQuickWindowPrivate::get(window)->animationController = 0;
+ QQuickWindowPrivate::get(window)->animationController = nullptr;
#if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl)
- QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
+ if (QOpenGLContext::currentContext())
+ QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
#endif
- window = 0;
+ window = nullptr;
}
}
@@ -284,6 +284,7 @@ bool QQuickRenderControl::sync()
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
cd->syncSceneGraph();
+ d->rc->endSync();
// TODO: find out if the sync actually caused a scenegraph update.
return true;
@@ -312,9 +313,6 @@ bool QQuickRenderControl::sync()
void QQuickRenderControl::invalidate()
{
Q_D(QQuickRenderControl);
- if (!d->initialized)
- return;
-
if (!d->window)
return;
@@ -322,6 +320,9 @@ void QQuickRenderControl::invalidate()
cd->fireAboutToStop();
cd->cleanupNodesOnShutdown();
+ if (!d->initialized)
+ return;
+
// We must invalidate since the context can potentially be destroyed by the
// application right after returning from this function. Invalidating is
// also essential to allow a subsequent initialize() to succeed.
@@ -383,14 +384,19 @@ QImage QQuickRenderControl::grab()
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
cd->polishItems();
cd->syncSceneGraph();
+ d->rc->endSync();
render();
- grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
+ const bool alpha = d->window->format().alphaBufferSize() > 0 && d->window->color().alpha() < 255;
+ grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), alpha, alpha);
if (QQuickRenderControl::renderWindowFor(d->window)) {
grabContent.setDevicePixelRatio(d->window->effectiveDevicePixelRatio());
}
#endif
+#if QT_CONFIG(thread)
} else if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) {
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
+ cd->polishItems();
+ cd->syncSceneGraph();
QSGSoftwareRenderer *softwareRenderer = static_cast<QSGSoftwareRenderer *>(cd->renderer);
if (softwareRenderer) {
const qreal dpr = d->window->effectiveDevicePixelRatio();
@@ -400,11 +406,11 @@ QImage QQuickRenderControl::grab()
QPaintDevice *prevDev = softwareRenderer->currentPaintDevice();
softwareRenderer->setCurrentPaintDevice(&grabContent);
softwareRenderer->markDirty();
- cd->polishItems();
- cd->syncSceneGraph();
+ d->rc->endSync();
render();
softwareRenderer->setCurrentPaintDevice(prevDev);
}
+#endif
} else {
qWarning("QQuickRenderControl: grabs are not supported with the current Qt Quick backend");
}
@@ -449,11 +455,11 @@ void QQuickRenderControlPrivate::maybeUpdate()
QWindow *QQuickRenderControl::renderWindowFor(QQuickWindow *win, QPoint *offset)
{
if (!win)
- return 0;
+ return nullptr;
QQuickRenderControl *rc = QQuickWindowPrivate::get(win)->renderControl;
if (rc)
return rc->renderWindow(offset);
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickrendercontrol.h b/src/quick/items/qquickrendercontrol.h
index 31ea176cc1..8ec9b8aafc 100644
--- a/src/quick/items/qquickrendercontrol.h
+++ b/src/quick/items/qquickrendercontrol.h
@@ -55,8 +55,8 @@ class Q_QUICK_EXPORT QQuickRenderControl : public QObject
Q_OBJECT
public:
- explicit QQuickRenderControl(QObject *parent = Q_NULLPTR);
- ~QQuickRenderControl();
+ explicit QQuickRenderControl(QObject *parent = nullptr);
+ ~QQuickRenderControl() override;
void prepareThread(QThread *targetThread);
void initialize(QOpenGLContext *gl);
@@ -68,8 +68,8 @@ public:
QImage grab();
- static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = Q_NULLPTR);
- virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return Q_NULLPTR; }
+ static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = nullptr);
+ virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return nullptr; }
Q_SIGNALS:
void renderRequested();
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index 9ad7d27b18..805b6fe190 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -50,7 +50,7 @@
QT_BEGIN_NAMESPACE
QQuickRepeaterPrivate::QQuickRepeaterPrivate()
- : model(0)
+ : model(nullptr)
, ownModel(false)
, dataSourceIsObject(false)
, delegateValidated(false)
@@ -72,7 +72,7 @@ QQuickRepeaterPrivate::~QQuickRepeaterPrivate()
\ingroup qtquick-models
\ingroup qtquick-positioning
\inherits Item
- \brief Instantiates a number of Item-based components using a provided model
+ \brief Instantiates a number of Item-based components using a provided model.
The Repeater type is used to create a large number of
similar items. Like other view types, a Repeater has a \l model and a \l delegate:
@@ -216,8 +216,8 @@ void QQuickRepeater::setModel(const QVariant &m)
d->dataSource = model;
QObject *object = qvariant_cast<QObject*>(model);
d->dataSourceAsObject = object;
- d->dataSourceIsObject = object != 0;
- QQmlInstanceModel *vim = 0;
+ d->dataSourceIsObject = object != nullptr;
+ QQmlInstanceModel *vim = nullptr;
if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
if (d->ownModel) {
delete d->model;
@@ -288,7 +288,7 @@ QQmlComponent *QQuickRepeater::delegate() const
return dataModel->delegate();
}
- return 0;
+ return nullptr;
}
void QQuickRepeater::setDelegate(QQmlComponent *delegate)
@@ -314,7 +314,11 @@ void QQuickRepeater::setDelegate(QQmlComponent *delegate)
/*!
\qmlproperty int QtQuick::Repeater::count
- This property holds the number of items in the repeater.
+ This property holds the number of items in the model.
+
+ \note The number of items in the model as reported by count may differ from
+ the number of created delegates if the Repeater is in the process of
+ instantiating delegates or is incorrectly set up.
*/
int QQuickRepeater::count() const
{
@@ -335,7 +339,7 @@ QQuickItem *QQuickRepeater::itemAt(int index) const
Q_D(const QQuickRepeater);
if (index >= 0 && index < d->deletables.count())
return d->deletables[index];
- return 0;
+ return nullptr;
}
void QQuickRepeater::componentComplete()
@@ -370,9 +374,12 @@ void QQuickRepeater::clear()
if (complete)
emit itemRemoved(i, item);
d->model->release(item);
- item->setParentItem(0);
}
}
+ for (QQuickItem *item : qAsConst(d->deletables)) {
+ if (item)
+ item->setParentItem(nullptr);
+ }
}
d->deletables.clear();
d->itemCount = 0;
@@ -397,7 +404,7 @@ void QQuickRepeater::regenerate()
void QQuickRepeaterPrivate::requestItems()
{
for (int i = 0; i < itemCount; i++) {
- QObject *object = model->object(i, false);
+ QObject *object = model->object(i, QQmlIncubator::AsynchronousIfNested);
if (object)
model->release(object);
}
@@ -406,7 +413,7 @@ void QQuickRepeaterPrivate::requestItems()
void QQuickRepeater::createdItem(int index, QObject *)
{
Q_D(QQuickRepeater);
- QObject *object = d->model->object(index, false);
+ QObject *object = d->model->object(index, QQmlIncubator::AsynchronousIfNested);
QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
emit itemAdded(index, item);
}
@@ -475,7 +482,7 @@ void QQuickRepeater::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
emit itemRemoved(index, item);
if (item) {
d->model->release(item);
- item->setParentItem(0);
+ item->setParentItem(nullptr);
}
--d->itemCount;
}
@@ -491,13 +498,20 @@ void QQuickRepeater::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
QQuickItem *stackBefore = index + items.count() < d->deletables.count()
? d->deletables.at(index + items.count())
: this;
- for (int i = index; i < index + items.count(); ++i)
- d->deletables.at(i)->stackBefore(stackBefore);
+ if (stackBefore) {
+ for (int i = index; i < index + items.count(); ++i) {
+ if (i < d->deletables.count()) {
+ QPointer<QQuickItem> item = d->deletables.at(i);
+ if (item)
+ item->stackBefore(stackBefore);
+ }
+ }
+ }
} else for (int i = 0; i < insert.count; ++i) {
int modelIndex = index + i;
++d->itemCount;
- d->deletables.insert(modelIndex, 0);
- QObject *object = d->model->object(modelIndex, false);
+ d->deletables.insert(modelIndex, nullptr);
+ QObject *object = d->model->object(modelIndex, QQmlIncubator::AsynchronousIfNested);
if (object)
d->model->release(object);
}
diff --git a/src/quick/items/qquickrepeater_p.h b/src/quick/items/qquickrepeater_p.h
index c14c1fb8cb..dbe3cd0c55 100644
--- a/src/quick/items/qquickrepeater_p.h
+++ b/src/quick/items/qquickrepeater_p.h
@@ -53,6 +53,10 @@
#include "qquickitem.h"
+#include <private/qtquickglobal_p.h>
+
+QT_REQUIRE_CONFIG(quick_repeater);
+
QT_BEGIN_NAMESPACE
class QQmlChangeSet;
@@ -68,7 +72,7 @@ class Q_AUTOTEST_EXPORT QQuickRepeater : public QQuickItem
Q_CLASSINFO("DefaultProperty", "delegate")
public:
- QQuickRepeater(QQuickItem *parent=0);
+ QQuickRepeater(QQuickItem *parent=nullptr);
virtual ~QQuickRepeater();
QVariant model() const;
@@ -94,8 +98,8 @@ private:
void regenerate();
protected:
- void componentComplete() Q_DECL_OVERRIDE;
- void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE;
+ void componentComplete() override;
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
private Q_SLOTS:
void createdItem(int index, QObject *item);
diff --git a/src/quick/items/qquickrepeater_p_p.h b/src/quick/items/qquickrepeater_p_p.h
index 64380688c9..942f428904 100644
--- a/src/quick/items/qquickrepeater_p_p.h
+++ b/src/quick/items/qquickrepeater_p_p.h
@@ -56,6 +56,8 @@
#include <QtCore/qpointer.h>
+QT_REQUIRE_CONFIG(quick_repeater);
+
QT_BEGIN_NAMESPACE
class QQmlContext;
diff --git a/src/quick/items/qquickscalegrid.cpp b/src/quick/items/qquickscalegrid.cpp
index d7a0f1b681..23f179be1d 100644
--- a/src/quick/items/qquickscalegrid.cpp
+++ b/src/quick/items/qquickscalegrid.cpp
@@ -66,6 +66,7 @@ void QQuickScaleGrid::setLeft(int pos)
{
if (_left != pos) {
_left = pos;
+ emit leftBorderChanged();
emit borderChanged();
}
}
@@ -74,6 +75,7 @@ void QQuickScaleGrid::setTop(int pos)
{
if (_top != pos) {
_top = pos;
+ emit topBorderChanged();
emit borderChanged();
}
}
@@ -82,6 +84,7 @@ void QQuickScaleGrid::setRight(int pos)
{
if (_right != pos) {
_right = pos;
+ emit rightBorderChanged();
emit borderChanged();
}
}
@@ -90,6 +93,7 @@ void QQuickScaleGrid::setBottom(int pos)
{
if (_bottom != pos) {
_bottom = pos;
+ emit bottomBorderChanged();
emit borderChanged();
}
}
diff --git a/src/quick/items/qquickscalegrid_p_p.h b/src/quick/items/qquickscalegrid_p_p.h
index 7f6a31a7bd..f5187a8eea 100644
--- a/src/quick/items/qquickscalegrid_p_p.h
+++ b/src/quick/items/qquickscalegrid_p_p.h
@@ -65,13 +65,13 @@ class Q_AUTOTEST_EXPORT QQuickScaleGrid : public QObject
{
Q_OBJECT
- Q_PROPERTY(int left READ left WRITE setLeft NOTIFY borderChanged)
- Q_PROPERTY(int top READ top WRITE setTop NOTIFY borderChanged)
- Q_PROPERTY(int right READ right WRITE setRight NOTIFY borderChanged)
- Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY borderChanged)
+ Q_PROPERTY(int left READ left WRITE setLeft NOTIFY leftBorderChanged)
+ Q_PROPERTY(int top READ top WRITE setTop NOTIFY topBorderChanged)
+ Q_PROPERTY(int right READ right WRITE setRight NOTIFY rightBorderChanged)
+ Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY bottomBorderChanged)
public:
- QQuickScaleGrid(QObject *parent=0);
+ QQuickScaleGrid(QObject *parent=nullptr);
~QQuickScaleGrid();
bool isNull() const;
@@ -90,6 +90,10 @@ public:
Q_SIGNALS:
void borderChanged();
+ void leftBorderChanged();
+ void topBorderChanged();
+ void rightBorderChanged();
+ void bottomBorderChanged();
private:
int _left;
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index 6a3eab957e..b057fd9d8f 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -396,24 +396,24 @@ void QQuickScreenInfo::setWrappedScreen(QScreen *screen)
if (!oldScreen || screen->devicePixelRatio() != oldScreen->devicePixelRatio())
emit devicePixelRatioChanged();
- connect(screen, SIGNAL(geometryChanged(QRect)),
- this, SIGNAL(widthChanged()));
- connect(screen, SIGNAL(geometryChanged(QRect)),
- this, SIGNAL(heightChanged()));
- connect(screen, SIGNAL(geometryChanged(QRect)),
- this, SIGNAL(virtualXChanged()));
- connect(screen, SIGNAL(geometryChanged(QRect)),
- this, SIGNAL(virtualYChanged()));
- connect(screen, SIGNAL(orientationChanged(Qt::ScreenOrientation)),
- this, SIGNAL(orientationChanged()));
- connect(screen, SIGNAL(primaryOrientationChanged(Qt::ScreenOrientation)),
- this, SIGNAL(primaryOrientationChanged()));
- connect(screen, SIGNAL(virtualGeometryChanged(QRect)),
- this, SIGNAL(desktopGeometryChanged()));
- connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)),
- this, SIGNAL(logicalPixelDensityChanged()));
- connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)),
- this, SIGNAL(pixelDensityChanged()));
+ qmlobject_connect(screen, QScreen, SIGNAL(geometryChanged(QRect)),
+ this, QQuickScreenInfo, SIGNAL(widthChanged()));
+ qmlobject_connect(screen, QScreen, SIGNAL(geometryChanged(QRect)),
+ this, QQuickScreenInfo, SIGNAL(heightChanged()));
+ qmlobject_connect(screen, QScreen, SIGNAL(geometryChanged(QRect)),
+ this, QQuickScreenInfo, SIGNAL(virtualXChanged()));
+ qmlobject_connect(screen, QScreen, SIGNAL(geometryChanged(QRect)),
+ this, QQuickScreenInfo, SIGNAL(virtualYChanged()));
+ qmlobject_connect(screen, QScreen, SIGNAL(orientationChanged(Qt::ScreenOrientation)),
+ this, QQuickScreenInfo, SIGNAL(orientationChanged()));
+ qmlobject_connect(screen, QScreen, SIGNAL(primaryOrientationChanged(Qt::ScreenOrientation)),
+ this, QQuickScreenInfo, SIGNAL(primaryOrientationChanged()));
+ qmlobject_connect(screen, QScreen, SIGNAL(virtualGeometryChanged(QRect)),
+ this, QQuickScreenInfo, SIGNAL(desktopGeometryChanged()));
+ qmlobject_connect(screen, QScreen, SIGNAL(logicalDotsPerInchChanged(qreal)),
+ this, QQuickScreenInfo, SIGNAL(logicalPixelDensityChanged()));
+ qmlobject_connect(screen, QScreen, SIGNAL(physicalDotsPerInchChanged(qreal)),
+ this, QQuickScreenInfo, SIGNAL(pixelDensityChanged()));
}
QScreen *QQuickScreenInfo::wrappedScreen() const
@@ -423,8 +423,8 @@ QScreen *QQuickScreenInfo::wrappedScreen() const
QQuickScreenAttached::QQuickScreenAttached(QObject* attachee)
: QQuickScreenInfo(attachee)
- , m_window(NULL)
- , m_updateMask(0)
+ , m_window(nullptr)
+ , m_updateMask(nullptr)
, m_updateMaskSet(false)
{
m_attachee = qobject_cast<QQuickItem*>(attachee);
@@ -473,11 +473,11 @@ int QQuickScreenAttached::angleBetween(int a, int b)
void QQuickScreenAttached::windowChanged(QQuickWindow* c)
{
if (m_window)
- disconnect(m_window, SIGNAL(screenChanged(QScreen*)), this, SLOT(screenChanged(QScreen*)));
+ qmlobject_disconnect(m_window, QQuickWindow, SIGNAL(screenChanged(QScreen*)), this, QQuickScreenAttached, SLOT(screenChanged(QScreen*)));
m_window = c;
- screenChanged(c ? c->screen() : NULL);
+ screenChanged(c ? c->screen() : nullptr);
if (c)
- connect(c, SIGNAL(screenChanged(QScreen*)), this, SLOT(screenChanged(QScreen*)));
+ qmlobject_connect(c, QQuickWindow, SIGNAL(screenChanged(QScreen*)), this, QQuickScreenAttached, SLOT(screenChanged(QScreen*)));
}
void QQuickScreenAttached::screenChanged(QScreen *screen)
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index a41e9324f3..ab79b69c8c 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE
\inqmlmodule QtQuick
\inherits Item
\ingroup qtquick-effects
- \brief Applies custom shaders to a rectangle
+ \brief Applies custom shaders to a rectangle.
The ShaderEffect type applies a custom
\l{vertexShader}{vertex} and \l{fragmentShader}{fragment (pixel)} shader to a
@@ -475,7 +475,7 @@ QT_BEGIN_NAMESPACE
\li \snippet qml/opacitymask.qml 1
\endtable
- \section1 Other notes
+ \section1 Other Notes
By default, the ShaderEffect consists of four vertices, one for each
corner. For non-linear vertex transformations, like page curl, you can
@@ -876,7 +876,7 @@ void QQuickShaderEffectPrivate::updatePolish()
#if QT_CONFIG(opengl)
bool QQuickShaderEffect::isOpenGLShaderEffect() const
{
- return m_glImpl != Q_NULLPTR;
+ return m_glImpl != nullptr;
}
#endif
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index 30bd018098..cabad930fc 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -91,7 +91,7 @@ public:
};
Q_ENUM(Status)
- QQuickShaderEffect(QQuickItem *parent = 0);
+ QQuickShaderEffect(QQuickItem *parent = nullptr);
QByteArray fragmentShader() const;
void setFragmentShader(const QByteArray &code);
diff --git a/src/quick/items/qquickshadereffectmesh.cpp b/src/quick/items/qquickshadereffectmesh.cpp
index 4ea976a272..804f548d21 100644
--- a/src/quick/items/qquickshadereffectmesh.cpp
+++ b/src/quick/items/qquickshadereffectmesh.cpp
@@ -64,13 +64,18 @@ QQuickShaderEffectMesh::QQuickShaderEffectMesh(QObject *parent)
{
}
+QQuickShaderEffectMesh::QQuickShaderEffectMesh(QObjectPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+}
+
/*!
\qmltype GridMesh
\instantiates QQuickGridMesh
\inqmlmodule QtQuick
\since 5.0
\ingroup qtquick-effects
- \brief Defines a mesh with vertices arranged in a grid
+ \brief Defines a mesh with vertices arranged in a grid.
GridMesh defines a rectangular mesh consisting of vertices arranged in an
evenly spaced grid. It is used to generate \l{QSGGeometry}{geometry}.
diff --git a/src/quick/items/qquickshadereffectmesh_p.h b/src/quick/items/qquickshadereffectmesh_p.h
index aa3112b5a5..62a9798e40 100644
--- a/src/quick/items/qquickshadereffectmesh_p.h
+++ b/src/quick/items/qquickshadereffectmesh_p.h
@@ -72,11 +72,11 @@ const char *qtTexCoordAttributeName();
class QSGGeometry;
class QRectF;
-class QQuickShaderEffectMesh : public QObject
+class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectMesh : public QObject
{
Q_OBJECT
public:
- QQuickShaderEffectMesh(QObject *parent = 0);
+ QQuickShaderEffectMesh(QObject *parent = nullptr);
virtual bool validateAttributes(const QVector<QByteArray> &attributes, int *posIndex) = 0;
// If 'geometry' != 0, 'attrCount' is the same as last time the function was called.
virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
@@ -87,18 +87,21 @@ public:
Q_SIGNALS:
// Emitted when the geometry needs to be updated.
void geometryChanged();
+
+protected:
+ QQuickShaderEffectMesh(QObjectPrivate &dd, QObject *parent = nullptr);
};
-class QQuickGridMesh : public QQuickShaderEffectMesh
+class Q_QUICK_PRIVATE_EXPORT QQuickGridMesh : public QQuickShaderEffectMesh
{
Q_OBJECT
Q_PROPERTY(QSize resolution READ resolution WRITE setResolution NOTIFY resolutionChanged)
public:
- QQuickGridMesh(QObject *parent = 0);
- bool validateAttributes(const QVector<QByteArray> &attributes, int *posIndex) Q_DECL_OVERRIDE;
+ QQuickGridMesh(QObject *parent = nullptr);
+ bool validateAttributes(const QVector<QByteArray> &attributes, int *posIndex) override;
QSGGeometry *updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
- const QRectF &srcRect, const QRectF &rect) Q_DECL_OVERRIDE;
- QString log() const Q_DECL_OVERRIDE { return m_log; }
+ const QRectF &srcRect, const QRectF &rect) override;
+ QString log() const override { return m_log; }
void setResolution(const QSize &res);
QSize resolution() const;
@@ -121,7 +124,7 @@ class QQuickBorderImageMesh : public QQuickShaderEffectMesh
Q_PROPERTY(TileMode horizontalTileMode READ horizontalTileMode WRITE setHorizontalTileMode NOTIFY horizontalTileModeChanged)
Q_PROPERTY(TileMode verticalTileMode READ verticalTileMode WRITE setVerticalTileMode NOTIFY verticalTileModeChanged)
public:
- QQuickBorderImageMesh(QObject *parent = 0);
+ QQuickBorderImageMesh(QObject *parent = nullptr);
bool validateAttributes(const QVector<QByteArray> &attributes, int *posIndex) override;
QSGGeometry *updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index f61bad1179..505940e673 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -56,7 +56,7 @@ class QQuickShaderEffectSourceTextureProvider : public QSGTextureProvider
Q_OBJECT
public:
QQuickShaderEffectSourceTextureProvider()
- : sourceTexture(0)
+ : sourceTexture(nullptr)
, mipmapFiltering(QSGTexture::None)
, filtering(QSGTexture::Nearest)
, horizontalWrap(QSGTexture::ClampToEdge)
@@ -87,7 +87,7 @@ public:
: texture(t)
, provider(p)
{}
- void run() Q_DECL_OVERRIDE {
+ void run() override {
delete texture;
delete provider;
}
@@ -102,7 +102,7 @@ public:
\since 5.0
\inherits Item
\ingroup qtquick-effects
- \brief Renders a \l {Qt Quick} item into a texture and displays it
+ \brief Renders a \l {Qt Quick} item into a texture and displays it.
The ShaderEffectSource type renders \l sourceItem into a texture and
displays it in the scene. \l sourceItem is drawn into the texture as though
@@ -183,10 +183,10 @@ public:
QQuickShaderEffectSource::QQuickShaderEffectSource(QQuickItem *parent)
: QQuickItem(parent)
- , m_provider(0)
- , m_texture(0)
+ , m_provider(nullptr)
+ , m_texture(nullptr)
, m_wrapMode(ClampToEdge)
- , m_sourceItem(0)
+ , m_sourceItem(nullptr)
, m_textureSize(0, 0)
, m_format(RGBA)
, m_samples(0)
@@ -246,7 +246,7 @@ QSGTextureProvider *QQuickShaderEffectSource::textureProvider() const
const QQuickItemPrivate *d = QQuickItemPrivate::get(this);
if (!d->window || !d->sceneGraphRenderContext() || QThread::currentThread() != d->sceneGraphRenderContext()->thread()) {
qWarning("QQuickShaderEffectSource::textureProvider: can only be queried on the rendering thread of an exposed window");
- return 0;
+ return nullptr;
}
if (!m_provider) {
@@ -334,8 +334,8 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
if (m_sourceItem) {
if (window() == m_sourceItem->window()
- || (window() == 0 && m_sourceItem->window())
- || (m_sourceItem->window() == 0 && window())) {
+ || (window() == nullptr && m_sourceItem->window())
+ || (m_sourceItem->window() == nullptr && window())) {
QQuickItemPrivate *d = QQuickItemPrivate::get(item);
// 'item' needs a window to get a scene graph node. It usually gets one through its
// parent, but if the source item is "inline" rather than a reference -- i.e.
@@ -350,7 +350,7 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
} else {
qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window.");
- m_sourceItem = 0;
+ m_sourceItem = nullptr;
}
}
update();
@@ -361,7 +361,7 @@ void QQuickShaderEffectSource::sourceItemDestroyed(QObject *item)
{
Q_ASSERT(item == m_sourceItem);
Q_UNUSED(item);
- m_sourceItem = 0;
+ m_sourceItem = nullptr;
update();
emit sourceItemChanged();
}
@@ -662,8 +662,8 @@ void QQuickShaderEffectSource::releaseResources()
if (m_texture || m_provider) {
window()->scheduleRenderJob(new QQuickShaderEffectSourceCleanup(m_texture, m_provider),
QQuickWindow::AfterSynchronizingStage);
- m_texture = 0;
- m_provider = 0;
+ m_texture = nullptr;
+ m_provider = nullptr;
}
}
@@ -684,9 +684,9 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
{
if (!m_sourceItem || m_sourceItem->width() <= 0 || m_sourceItem->height() <= 0) {
if (m_texture)
- m_texture->setItem(0);
+ m_texture->setItem(nullptr);
delete oldNode;
- return 0;
+ return nullptr;
}
ensureTexture();
@@ -745,7 +745,7 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
// Don't create the paint node if we're not spanning any area
if (width() <= 0 || height() <= 0) {
delete oldNode;
- return 0;
+ return nullptr;
}
QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
@@ -779,8 +779,8 @@ void QQuickShaderEffectSource::invalidateSceneGraph()
delete m_texture;
if (m_provider)
delete m_provider;
- m_texture = 0;
- m_provider = 0;
+ m_texture = nullptr;
+ m_provider = nullptr;
}
void QQuickShaderEffectSource::itemChange(ItemChange change, const ItemChangeData &value)
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index d9f9079a3d..d5bb33902a 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -113,8 +113,8 @@ public:
};
Q_ENUM(TextureMirroring)
- QQuickShaderEffectSource(QQuickItem *parent = 0);
- ~QQuickShaderEffectSource();
+ QQuickShaderEffectSource(QQuickItem *parent = nullptr);
+ ~QQuickShaderEffectSource() override;
WrapMode wrapMode() const;
void setWrapMode(WrapMode mode);
@@ -146,8 +146,8 @@ public:
TextureMirroring textureMirroring() const;
void setTextureMirroring(TextureMirroring mirroring);
- bool isTextureProvider() const Q_DECL_OVERRIDE { return true; }
- QSGTextureProvider *textureProvider() const Q_DECL_OVERRIDE;
+ bool isTextureProvider() const override { return true; }
+ QSGTextureProvider *textureProvider() const override;
Q_INVOKABLE void scheduleUpdate();
@@ -174,11 +174,11 @@ private Q_SLOTS:
void invalidateSceneGraph();
protected:
- void releaseResources() Q_DECL_OVERRIDE;
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ void releaseResources() override;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
- void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE;
- void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) override;
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
private:
void ensureTexture();
diff --git a/src/quick/items/qquicksprite.cpp b/src/quick/items/qquicksprite.cpp
index aae657b749..58f3de8b7b 100644
--- a/src/quick/items/qquicksprite.cpp
+++ b/src/quick/items/qquicksprite.cpp
@@ -38,8 +38,10 @@
****************************************************************************/
#include "qquicksprite_p.h"
+#include "qquickimagebase_p.h"
#include <qqml.h>
#include <QDebug>
+#include <QRandomGenerator>
QT_BEGIN_NAMESPACE
@@ -48,10 +50,10 @@ QT_BEGIN_NAMESPACE
\instantiates QQuickSprite
\inqmlmodule QtQuick
\ingroup qtquick-visual-utility
- \brief Specifies sprite animations
+ \brief Specifies sprite animations.
- QQuickSprite renders sprites of one or more frames and animates them. The sprites
- can be in the middle of an image file, or split along multiple rows, as long as they form
+ Sprite defines a series of one or more frames to be animated and rendered by SpriteSequence.
+ The sprites can be in the middle of an image file, or split along multiple rows, as long as they form
a contiguous line wrapping to the next row of the file from the left edge of the file.
For full details, see the \l{Sprite Animations} overview.
@@ -99,7 +101,7 @@ QT_BEGIN_NAMESPACE
/*!
\qmlproperty int QtQuick::Sprite::frameDuration
- Duration of each frame of the animation. Values below 0 are invalid.
+ Duration of each frame of the animation in milliseconds. Values below 0 are invalid.
If frameRate is valid then it will be used to calculate the duration of the frames.
If not, and frameDuration is valid, then frameDuration will be used. Otherwise duration is used.
@@ -221,6 +223,7 @@ QQuickSprite::QQuickSprite(QObject *parent)
, m_frameDuration(unsetDuration)
, m_frameDurationVariation(0)
, m_frameSync(false)
+ , m_devicePixelRatio(1.0)
{
}
@@ -236,12 +239,12 @@ int QQuickSprite::variedDuration() const //Deals with precedence when multiple d
if (m_frameRate != unsetDuration) {
qreal fpms = (m_frameRate
- + (m_frameRateVariation * ((qreal)qrand()/RAND_MAX) * 2)
+ + (m_frameRateVariation * QRandomGenerator::global()->generateDouble() * 2)
- m_frameRateVariation) / 1000.0;
return qMax(qreal(0.0) , m_frames / fpms);
} else if (m_frameDuration != unsetDuration) {
int mspf = m_frameDuration
- + (m_frameDurationVariation * ((qreal)qrand()/RAND_MAX) * 2)
+ + (m_frameDurationVariation * QRandomGenerator::global()->generateDouble() * 2)
- m_frameDurationVariation;
return qMax(0, m_frames * mspf);
} else if (duration() >= 0) {
@@ -264,7 +267,10 @@ void QQuickSprite::startImageLoading()
if (!e)
qWarning() << "QQuickSprite: Cannot find QQmlEngine - this class is only for use in QML and may not work";
}
- m_pix.load(e, m_source);
+ QUrl loadUrl = m_source;
+ QQuickImageBase::resolve2xLocalFile(m_source, m_devicePixelRatio, &loadUrl, &m_devicePixelRatio);
+
+ m_pix.load(e, loadUrl);
}
}
diff --git a/src/quick/items/qquicksprite_p.h b/src/quick/items/qquicksprite_p.h
index d68a45ecc0..fab9e75190 100644
--- a/src/quick/items/qquicksprite_p.h
+++ b/src/quick/items/qquicksprite_p.h
@@ -88,8 +88,8 @@ class Q_QUICK_EXPORT QQuickSprite : public QQuickStochasticState
Q_PROPERTY(int frameDurationVariation READ frameDurationVariation WRITE setFrameDurationVariation NOTIFY frameDurationVariationChanged)
public:
- explicit QQuickSprite(QObject *parent = 0);
- ~QQuickSprite();
+ explicit QQuickSprite(QObject *parent = nullptr);
+ ~QQuickSprite() override;
QUrl source() const
{
@@ -161,13 +161,23 @@ public:
return m_frameDurationVariation;
}
- int variedDuration() const Q_DECL_OVERRIDE;
+ int variedDuration() const override;
bool frameSync() const
{
return m_frameSync;
}
+ void setDevicePixelRatio(qreal dpr)
+ {
+ m_devicePixelRatio = dpr;
+ }
+
+ qreal devicePixelRatio() const
+ {
+ return m_devicePixelRatio;
+ }
+
Q_SIGNALS:
void sourceChanged(QUrl arg);
@@ -308,6 +318,7 @@ private:
friend class QQuickAnimatedSprite;
friend class QQuickSpriteEngine;
friend class QQuickStochasticEngine;
+
int m_generatedCount;
int m_framesPerRow;
int m_rowY;
@@ -325,6 +336,7 @@ private:
int m_frameDuration;
int m_frameDurationVariation;
bool m_frameSync;
+ qreal m_devicePixelRatio;
QQuickPixmap m_pix;
};
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index 92b60a8e3a..be297bbe76 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -43,6 +43,7 @@
#include <qqml.h>
#include <QDebug>
#include <QPainter>
+#include <QRandomGenerator>
#include <QSet>
#include <QtGui/qopengl.h>
#include <QOpenGLFunctions>
@@ -389,6 +390,7 @@ QImage QQuickSpriteEngine::assembledImage(int maxSize)
int w = 0;
m_maxFrames = 0;
m_imageStateCount = 0;
+ qreal pixelRatio = 1.0;
for (QQuickSprite* state : qAsConst(m_sprites)) {
if (state->frames() > m_maxFrames)
@@ -412,6 +414,8 @@ QImage QQuickSpriteEngine::assembledImage(int maxSize)
if (!state->m_frameHeight)
state->m_frameHeight = img.height();
+ pixelRatio = qMax(pixelRatio, state->devicePixelRatio());
+
if (state->frames() * state->frameWidth() > maxSize){
struct helper{
static int divRoundUp(int a, int b){return (a+b-1)/b;}
@@ -436,43 +440,58 @@ QImage QQuickSpriteEngine::assembledImage(int maxSize)
}
}
+ if (h > maxSize){
+ qWarning() << "SpriteEngine: Too many animations to fit in one texture...";
+ qWarning() << "SpriteEngine: Your texture max size today is " << maxSize;
+ return QImage();
+ }
+
//maxFrames is max number in a line of the texture
- QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
+ QImage image(w * pixelRatio, h * pixelRatio, QImage::Format_ARGB32_Premultiplied);
+ image.setDevicePixelRatio(pixelRatio);
image.fill(0);
QPainter p(&image);
int y = 0;
for (QQuickSprite* state : qAsConst(m_sprites)) {
QImage img(state->m_pix.image());
- int frameWidth = state->m_frameWidth;
- int frameHeight = state->m_frameHeight;
- if (img.height() == frameHeight && img.width() < maxSize){//Simple case
- p.drawImage(0,y,img.copy(state->m_frameX,0,state->m_frames * frameWidth, frameHeight));
+ const int frameWidth = state->m_frameWidth;
+ const int frameHeight = state->m_frameHeight;
+ const int imgHeight = img.height() / img.devicePixelRatioF();
+ const int imgWidth = img.width() / img.devicePixelRatioF();
+ if (imgHeight == frameHeight && imgWidth < maxSize){ //Simple case
+ p.drawImage(QRect(0, y, state->m_frames * frameWidth, frameHeight),
+ img,
+ QRect(state->m_frameX * img.devicePixelRatioF(), 0, state->m_frames * frameWidth * img.devicePixelRatioF(), frameHeight * img.devicePixelRatioF()));
state->m_rowStartX = 0;
state->m_rowY = y;
y += frameHeight;
- }else{//Chopping up image case
- state->m_framesPerRow = image.width()/frameWidth;
+ } else { //Chopping up image case
+ state->m_framesPerRow = w/frameWidth;
state->m_rowY = y;
int x = 0;
int curX = state->m_frameX;
int curY = state->m_frameY;
int framesLeft = state->frames();
while (framesLeft > 0){
- if (image.width() - x + curX <= img.width()){//finish a row in image (dest)
- int copied = image.width() - x;
+ if (w - x + curX <= imgWidth){//finish a row in image (dest)
+ int copied = w - x;
framesLeft -= copied/frameWidth;
- p.drawImage(x,y,img.copy(curX,curY,copied,frameHeight));
+ p.drawImage(QRect(x, y, copied, frameHeight),
+ img,
+ QRect(curX * img.devicePixelRatioF(), curY * img.devicePixelRatioF(), copied * img.devicePixelRatioF(), frameHeight * img.devicePixelRatioF()));
y += frameHeight;
curX += copied;
x = 0;
- if (curX == img.width()){
+ if (curX == imgWidth){
curX = 0;
curY += frameHeight;
}
}else{//finish a row in img (src)
- int copied = img.width() - curX;
+ int copied = imgWidth - curX;
framesLeft -= copied/frameWidth;
- p.drawImage(x,y,img.copy(curX,curY,copied,frameHeight));
+ p.drawImage(QRect(x, y, copied, frameHeight),
+ img,
+ QRect(curX * img.devicePixelRatioF(), curY * img.devicePixelRatioF(), copied * img.devicePixelRatioF(), frameHeight * img.devicePixelRatioF()));
curY += frameHeight;
x += copied;
curX = 0;
@@ -483,12 +502,6 @@ QImage QQuickSpriteEngine::assembledImage(int maxSize)
}
}
- if (image.height() > maxSize){
- qWarning() << "SpriteEngine: Too many animations to fit in one texture...";
- qWarning() << "SpriteEngine: Your texture max size today is " << maxSize;
- return QImage();
- }
-
#ifdef SPRITE_IMAGE_DEBUG
QString fPath = QDir::tempPath() + "/SpriteImage.%1.png";
int acc = 0;
@@ -543,7 +556,7 @@ void QQuickStochasticEngine::restart(int index)
if (m_addAdvance)
m_startTimes[index] += m_advanceTime.elapsed();
if (randomStart)
- m_startTimes[index] -= qrand() % m_duration.at(index);
+ m_startTimes[index] -= QRandomGenerator::global()->bounded(m_duration.at(index));
int time = m_duration.at(index) + m_startTimes.at(index);
for (int i=0; i<m_stateUpdates.count(); i++)
m_stateUpdates[i].second.removeAll(index);
@@ -557,13 +570,13 @@ void QQuickSpriteEngine::restart(int index) //Reimplemented to recognize and han
if (m_loaded && m_sprites.at(m_things.at(index))->frameSync()) {//Manually advanced
m_startTimes[index] = 0;
if (randomStart && m_sprites.at(m_things.at(index))->m_generatedCount)
- m_startTimes[index] += qrand() % m_sprites.at(m_things.at(index))->m_generatedCount;
+ m_startTimes[index] += QRandomGenerator::global()->bounded(m_sprites.at(m_things.at(index))->m_generatedCount);
} else {
m_startTimes[index] = m_timeOffset;
if (m_addAdvance)
m_startTimes[index] += m_advanceTime.elapsed();
if (randomStart)
- m_startTimes[index] -= qrand() % m_duration.at(index);
+ 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);
@@ -629,7 +642,7 @@ int QQuickStochasticEngine::nextState(int curState, int curThing)
int nextIdx = -1;
int goalPath = goalSeek(curState, curThing);
if (goalPath == -1){//Random
- qreal r =(qreal) qrand() / (qreal) RAND_MAX;
+ qreal r = QRandomGenerator::global()->generateDouble();
qreal total = 0.0;
for (QVariantMap::const_iterator iter=m_states.at(curState)->m_to.constBegin();
iter!=m_states.at(curState)->m_to.constEnd(); ++iter)
@@ -719,7 +732,7 @@ int QQuickStochasticEngine::goalSeek(int curIdx, int spriteIdx, int dist)
if (options.count()==1)
return *(options.begin());
int option = -1;
- qreal r =(qreal) qrand() / (qreal) RAND_MAX;
+ qreal r = QRandomGenerator::global()->generateDouble();
qreal total = 0;
for (QSet<int>::const_iterator iter=options.constBegin();
iter!=options.constEnd(); ++iter)
diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h
index 90ee68b2f6..d3944b4620 100644
--- a/src/quick/items/qquickspriteengine_p.h
+++ b/src/quick/items/qquickspriteengine_p.h
@@ -63,6 +63,7 @@ QT_REQUIRE_CONFIG(quick_sprite);
#include <QQmlListProperty>
#include <QImage>
#include <QPair>
+#include <QRandomGenerator>
#include <private/qquickpixmapcache_p.h>
#include <private/qtquickglobal_p.h>
@@ -80,11 +81,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickStochasticState : public QObject //Currently
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
public:
- QQuickStochasticState(QObject* parent = 0)
+ QQuickStochasticState(QObject* parent = nullptr)
: QObject(parent)
- , m_duration(-1)
- , m_durationVariation(0)
- , m_randomStart(false)
{
}
@@ -111,8 +109,8 @@ public:
virtual int variedDuration() const
{
- return qMax(qreal(0.0) , m_duration
- + (m_durationVariation * ((qreal)qrand()/RAND_MAX) * 2)
+ return qMax(0.0 , m_duration
+ + (m_durationVariation * QRandomGenerator::global()->bounded(2.0))
- m_durationVariation);
}
@@ -178,11 +176,11 @@ public Q_SLOTS:
private:
QString m_name;
QVariantMap m_to;
- int m_duration;
- int m_durationVariation;
+ int m_duration = -1;
+ int m_durationVariation = 0;
friend class QQuickStochasticEngine;
- bool m_randomStart;
+ bool m_randomStart = false;
};
class Q_QUICK_PRIVATE_EXPORT QQuickStochasticEngine : public QObject
@@ -192,9 +190,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickStochasticEngine : public QObject
Q_PROPERTY(QString globalGoal READ globalGoal WRITE setGlobalGoal NOTIFY globalGoalChanged)
Q_PROPERTY(QQmlListProperty<QQuickStochasticState> states READ states)
public:
- explicit QQuickStochasticEngine(QObject *parent = 0);
- QQuickStochasticEngine(const QList<QQuickStochasticState*> &states, QObject *parent = 0);
- ~QQuickStochasticEngine();
+ explicit QQuickStochasticEngine(QObject *parent = nullptr);
+ QQuickStochasticEngine(const QList<QQuickStochasticState*> &states, QObject *parent = nullptr);
+ ~QQuickStochasticEngine() override;
QQmlListProperty<QQuickStochasticState> states()
{
@@ -269,9 +267,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickSpriteEngine : public QQuickStochasticEngine
Q_OBJECT
Q_PROPERTY(QQmlListProperty<QQuickSprite> sprites READ sprites)
public:
- explicit QQuickSpriteEngine(QObject *parent = 0);
- QQuickSpriteEngine(const QList<QQuickSprite*> &sprites, QObject *parent = 0);
- ~QQuickSpriteEngine();
+ explicit QQuickSpriteEngine(QObject *parent = nullptr);
+ QQuickSpriteEngine(const QList<QQuickSprite*> &sprites, QObject *parent = nullptr);
+ ~QQuickSpriteEngine() override;
QQmlListProperty<QQuickSprite> sprites()
{
return QQmlListProperty<QQuickSprite>(this, m_sprites);
@@ -289,8 +287,8 @@ public:
int spriteCount() const;//Like state count
int maxFrames() const;
- void restart(int index=0) Q_DECL_OVERRIDE;
- void advance(int index=0) Q_DECL_OVERRIDE;
+ void restart(int index=0) override;
+ void advance(int index=0) override;
//Similar API to QQuickPixmap for async loading convenience
bool isNull() const { return status() == QQuickPixmap::Null; }
@@ -302,7 +300,7 @@ public:
QImage assembledImage(int maxSize = 2048);
private:
- int pseudospriteProgress(int, int, int *rd = 0) const;
+ int pseudospriteProgress(int, int, int *rd = nullptr) const;
QList<QQuickSprite*> m_sprites;
bool m_startedImageAssembly;
bool m_loaded;
diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp
index ae466aa482..eb4b5335e7 100644
--- a/src/quick/items/qquickspritesequence.cpp
+++ b/src/quick/items/qquickspritesequence.cpp
@@ -61,50 +61,51 @@ QT_BEGIN_NAMESPACE
\inqmlmodule QtQuick
\ingroup qtquick-visual-utility
\inherits Item
- \brief Draws a sprite animation
+ \brief Draws a sprite animation.
SpriteSequence renders and controls a list of animations defined
by \l Sprite types.
For full details, see the \l{Sprite Animations} overview.
+ \sa {Sprite animations with SpriteSequence}
*/
/*!
\qmlproperty bool QtQuick::SpriteSequence::running
Whether the sprite is animating or not.
- Default is true
+ Default is \c true.
*/
/*!
\qmlproperty bool QtQuick::SpriteSequence::interpolate
- If true, interpolation will occur between sprite frames to make the
+ If \c true, interpolation will occur between sprite frames to make the
animation appear smoother.
- Default is true.
+ Default is \c true.
*/
/*!
\qmlproperty string QtQuick::SpriteSequence::currentSprite
- The name of the Sprite which is currently animating.
+ The name of the \l Sprite that is currently animating.
*/
/*!
\qmlproperty string QtQuick::SpriteSequence::goalSprite
- The name of the Sprite which the animation should move to.
+ The name of the \l Sprite that the animation should move to.
- Sprite states have defined durations and transitions between them, setting goalState
- will cause it to disregard any path weightings (including 0) and head down the path
- which will reach the goalState quickest (fewest animations). It will pass through
+ Sprite states have defined durations and transitions between them; setting \c goalSprite
+ will cause it to disregard any path weightings (including \c 0) and head down the path
+ that will reach the \c goalSprite quickest (fewest animations). It will pass through
intermediate states on that path, and animate them for their duration.
- If it is possible to return to the goalState from the starting point of the goalState
- it will continue to do so until goalState is set to "" or an unreachable state.
+ If it is possible to return to the \c goalSprite from the starting point of the \c goalSprite,
+ it will continue to do so until \c goalSprite is set to \c "" or an unreachable state.
*/
/*! \qmlmethod QtQuick::SpriteSequence::jumpTo(string sprite)
- This function causes the SpriteSequence to jump to the specified sprite immediately, intermediate
- sprites are not played. The \a sprite argument is the name of the sprite you wish to jump to.
+ This function causes the SpriteSequence to jump to the specified \a sprite immediately;
+ intermediate sprites are not played.
*/
/*!
\qmlproperty list<Sprite> QtQuick::SpriteSequence::sprites
@@ -199,7 +200,7 @@ void QQuickSpriteSequence::createEngine()
if (!d->m_goalState.isEmpty())
d->m_spriteEngine->setGoal(d->m_spriteEngine->stateIndex(d->m_goalState));
} else {
- d->m_spriteEngine = 0;
+ d->m_spriteEngine = nullptr;
}
reset();
}
@@ -226,7 +227,7 @@ QSGSpriteNode *QQuickSpriteSequence::initNode()
QSGSpriteNode *node = d->sceneGraphContext()->createSpriteNode();
- d->m_sheetSize = QSize(image.size());
+ d->m_sheetSize = QSize(image.size() / image.devicePixelRatioF());
node->setTexture(window()->createTextureFromImage(image));
d->m_spriteEngine->start(0);
node->setTime(0.0f);
diff --git a/src/quick/items/qquickspritesequence_p.h b/src/quick/items/qquickspritesequence_p.h
index b80a8348aa..899ce79e0e 100644
--- a/src/quick/items/qquickspritesequence_p.h
+++ b/src/quick/items/qquickspritesequence_p.h
@@ -77,7 +77,7 @@ class Q_AUTOTEST_EXPORT QQuickSpriteSequence : public QQuickItem
Q_CLASSINFO("DefaultProperty", "sprites")
public:
- explicit QQuickSpriteSequence(QQuickItem *parent = 0);
+ explicit QQuickSpriteSequence(QQuickItem *parent = nullptr);
QQmlListProperty<QQuickSprite> sprites();
@@ -105,7 +105,7 @@ private Q_SLOTS:
protected:
void reset();
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
private:
void prepareNextFrame(QSGSpriteNode *node);
QSGSpriteNode* initNode();
diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp
index a4ce13a199..fe1dfd349e 100644
--- a/src/quick/items/qquickstateoperations.cpp
+++ b/src/quick/items/qquickstateoperations.cpp
@@ -51,8 +51,8 @@ class QQuickParentChangePrivate : public QQuickStateOperationPrivate
{
Q_DECLARE_PUBLIC(QQuickParentChange)
public:
- QQuickParentChangePrivate() : target(0), parent(0), origParent(0), origStackBefore(0),
- rewindParent(0), rewindStackBefore(0) {}
+ QQuickParentChangePrivate() : target(nullptr), parent(nullptr), origParent(nullptr), origStackBefore(nullptr),
+ rewindParent(nullptr), rewindStackBefore(nullptr) {}
QQuickItem *target;
QPointer<QQuickItem> parent;
@@ -68,7 +68,7 @@ public:
QQmlNullableValue<QQmlScriptString> scaleString;
QQmlNullableValue<QQmlScriptString> rotationString;
- void doChange(QQuickItem *targetParent, QQuickItem *stackBefore = 0);
+ void doChange(QQuickItem *targetParent, QQuickItem *stackBefore = nullptr);
};
void QQuickParentChangePrivate::doChange(QQuickItem *targetParent, QQuickItem *stackBefore)
@@ -149,7 +149,7 @@ void QQuickParentChangePrivate::doChange(QQuickItem *targetParent, QQuickItem *s
\instantiates QQuickParentChange
\inqmlmodule QtQuick
\ingroup qtquick-states
- \brief Specifies how to reparent an Item in a state change
+ \brief Specifies how to reparent an Item in a state change.
ParentChange reparents an item while preserving its visual appearance (position, size,
rotation, and scale) on screen. You can then specify a transition to move/resize/rotate/scale
@@ -510,7 +510,7 @@ QQuickStateActionEvent::EventType QQuickParentChange::type() const
return ParentChange;
}
-bool QQuickParentChange::override(QQuickStateActionEvent*other)
+bool QQuickParentChange::mayOverride(QQuickStateActionEvent*other)
{
Q_D(QQuickParentChange);
if (other->type() != ParentChange)
@@ -524,13 +524,13 @@ void QQuickParentChange::saveCurrentValues()
{
Q_D(QQuickParentChange);
if (!d->target) {
- d->rewindParent = 0;
- d->rewindStackBefore = 0;
+ d->rewindParent = nullptr;
+ d->rewindStackBefore = nullptr;
return;
}
d->rewindParent = d->target->parentItem();
- d->rewindStackBefore = 0;
+ d->rewindStackBefore = nullptr;
if (!d->rewindParent)
return;
@@ -555,7 +555,7 @@ void QQuickParentChange::rewind()
\instantiates QQuickAnchorChanges
\inqmlmodule QtQuick
\ingroup qtquick-states
- \brief Specifies how to change the anchors of an item in a state
+ \brief Specifies how to change the anchors of an item in a state.
The AnchorChanges type is used to modify the anchors of an item in a \l State.
@@ -588,7 +588,7 @@ class QQuickAnchorSetPrivate : public QObjectPrivate
Q_DECLARE_PUBLIC(QQuickAnchorSet)
public:
QQuickAnchorSetPrivate()
- : usedAnchors(0), resetAnchors(0)
+ : usedAnchors(nullptr), resetAnchors(nullptr)
{
}
@@ -771,7 +771,7 @@ class QQuickAnchorChangesPrivate : public QQuickStateOperationPrivate
{
public:
QQuickAnchorChangesPrivate()
- : target(0), anchorSet(new QQuickAnchorSet)
+ : target(nullptr), anchorSet(new QQuickAnchorSet)
{
}
@@ -855,7 +855,7 @@ QQuickAnchorChanges::ActionList QQuickAnchorChanges::actions()
Q_D(QQuickAnchorChanges);
//### ASSERT these are all 0?
d->leftBinding = d->rightBinding = d->hCenterBinding = d->topBinding
- = d->bottomBinding = d->vCenterBinding = d->baselineBinding = 0;
+ = d->bottomBinding = d->vCenterBinding = d->baselineBinding = nullptr;
d->leftProp = QQmlProperty(d->target, QLatin1String("anchors.left"));
d->rightProp = QQmlProperty(d->target, QLatin1String("anchors.right"));
@@ -1236,20 +1236,20 @@ void QQuickAnchorChanges::copyOriginals(QQuickStateActionEvent *other)
//clear old values from other
//### could this be generalized for all QQuickStateActionEvents, and called after copyOriginals?
- acp->leftBinding = 0;
- acp->rightBinding = 0;
- acp->hCenterBinding = 0;
- acp->topBinding = 0;
- acp->bottomBinding = 0;
- acp->vCenterBinding = 0;
- acp->baselineBinding = 0;
- acp->origLeftBinding = 0;
- acp->origRightBinding = 0;
- acp->origHCenterBinding = 0;
- acp->origTopBinding = 0;
- acp->origBottomBinding = 0;
- acp->origVCenterBinding = 0;
- acp->origBaselineBinding = 0;
+ acp->leftBinding = nullptr;
+ acp->rightBinding = nullptr;
+ acp->hCenterBinding = nullptr;
+ acp->topBinding = nullptr;
+ acp->bottomBinding = nullptr;
+ acp->vCenterBinding = nullptr;
+ acp->baselineBinding = nullptr;
+ acp->origLeftBinding = nullptr;
+ acp->origRightBinding = nullptr;
+ acp->origHCenterBinding = nullptr;
+ acp->origTopBinding = nullptr;
+ acp->origBottomBinding = nullptr;
+ acp->origVCenterBinding = nullptr;
+ acp->origBaselineBinding = nullptr;
saveCurrentValues();
}
@@ -1302,7 +1302,7 @@ void QQuickAnchorChanges::clearBindings()
}
}
-bool QQuickAnchorChanges::override(QQuickStateActionEvent*other)
+bool QQuickAnchorChanges::mayOverride(QQuickStateActionEvent*other)
{
if (other->type() != AnchorChanges)
return false;
diff --git a/src/quick/items/qquickstateoperations_p.h b/src/quick/items/qquickstateoperations_p.h
index 48b4b23a76..e947b2213f 100644
--- a/src/quick/items/qquickstateoperations_p.h
+++ b/src/quick/items/qquickstateoperations_p.h
@@ -75,7 +75,7 @@ class Q_AUTOTEST_EXPORT QQuickParentChange : public QQuickStateOperation, public
Q_PROPERTY(QQmlScriptString scale READ scale WRITE setScale)
Q_PROPERTY(QQmlScriptString rotation READ rotation WRITE setRotation)
public:
- QQuickParentChange(QObject *parent=0);
+ QQuickParentChange(QObject *parent=nullptr);
~QQuickParentChange();
QQuickItem *object() const;
@@ -110,17 +110,17 @@ public:
void setRotation(QQmlScriptString rotation);
bool rotationIsSet() const;
- ActionList actions() Q_DECL_OVERRIDE;
+ ActionList actions() override;
- void saveOriginals() Q_DECL_OVERRIDE;
+ void saveOriginals() override;
//virtual void copyOriginals(QQuickStateActionEvent*);
- void execute() Q_DECL_OVERRIDE;
- bool isReversable() Q_DECL_OVERRIDE;
- void reverse() Q_DECL_OVERRIDE;
- EventType type() const Q_DECL_OVERRIDE;
- bool override(QQuickStateActionEvent*other) Q_DECL_OVERRIDE;
- void rewind() Q_DECL_OVERRIDE;
- void saveCurrentValues() Q_DECL_OVERRIDE;
+ void execute() override;
+ bool isReversable() override;
+ void reverse() override;
+ EventType type() const override;
+ bool mayOverride(QQuickStateActionEvent*other) override;
+ void rewind() override;
+ void saveCurrentValues() override;
};
class QQuickAnchorChanges;
@@ -138,7 +138,7 @@ class Q_AUTOTEST_EXPORT QQuickAnchorSet : public QObject
Q_PROPERTY(QQmlScriptString baseline READ baseline WRITE setBaseline RESET resetBaseline)
public:
- QQuickAnchorSet(QObject *parent=0);
+ QQuickAnchorSet(QObject *parent=nullptr);
virtual ~QQuickAnchorSet();
QQmlScriptString left() const;
@@ -187,31 +187,31 @@ class Q_AUTOTEST_EXPORT QQuickAnchorChanges : public QQuickStateOperation, publi
Q_PROPERTY(QQuickAnchorSet *anchors READ anchors CONSTANT)
public:
- QQuickAnchorChanges(QObject *parent=0);
+ QQuickAnchorChanges(QObject *parent=nullptr);
~QQuickAnchorChanges();
- ActionList actions() Q_DECL_OVERRIDE;
+ ActionList actions() override;
QQuickAnchorSet *anchors() const;
QQuickItem *object() const;
void setObject(QQuickItem *);
- void execute() Q_DECL_OVERRIDE;
- bool isReversable() Q_DECL_OVERRIDE;
- void reverse() Q_DECL_OVERRIDE;
- EventType type() const Q_DECL_OVERRIDE;
- bool override(QQuickStateActionEvent*other) Q_DECL_OVERRIDE;
- bool changesBindings() Q_DECL_OVERRIDE;
- void saveOriginals() Q_DECL_OVERRIDE;
- bool needsCopy() Q_DECL_OVERRIDE { return true; }
- void copyOriginals(QQuickStateActionEvent*) Q_DECL_OVERRIDE;
- void clearBindings() Q_DECL_OVERRIDE;
- void rewind() Q_DECL_OVERRIDE;
- void saveCurrentValues() Q_DECL_OVERRIDE;
+ void execute() override;
+ bool isReversable() override;
+ void reverse() override;
+ EventType type() const override;
+ bool mayOverride(QQuickStateActionEvent*other) override;
+ bool changesBindings() override;
+ void saveOriginals() override;
+ bool needsCopy() override { return true; }
+ void copyOriginals(QQuickStateActionEvent*) override;
+ void clearBindings() override;
+ void rewind() override;
+ void saveCurrentValues() override;
QList<QQuickStateAction> additionalActions() const;
- void saveTargetValues() Q_DECL_OVERRIDE;
+ void saveTargetValues() override;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
new file mode 100644
index 0000000000..ac3397d2a9
--- /dev/null
+++ b/src/quick/items/qquicktableview.cpp
@@ -0,0 +1,2301 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktableview_p.h"
+#include "qquicktableview_p_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtCore/qdir.h>
+#include <QtQml/private/qqmldelegatemodel_p.h>
+#include <QtQml/private/qqmldelegatemodel_p_p.h>
+#include <QtQml/private/qqmlincubator_p.h>
+#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQml/qqmlinfo.h>
+
+#include <QtQuick/private/qquickflickable_p_p.h>
+#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
+
+/*!
+ \qmltype TableView
+ \instantiates QQuickTableView
+ \inqmlmodule QtQuick
+ \ingroup qtquick-views
+ \inherits Flickable
+ \brief Provides a table view of items provided by the 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.
+
+ TableView inherits \l Flickable. This means that while the model can have
+ any number of rows and columns, only a subsection of the table is usually
+ visible inside the viewport. As soon as you flick, new rows and columns
+ enter the viewport, while old ones exit and are removed from the viewport.
+ The rows and columns that move out are reused for building the rows and columns
+ that move into the viewport. As such, the TableView support models of any
+ size without affecting performance.
+
+ 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.
+
+ \section1 Example Usage
+
+ The following example shows how to create a model from C++ with multiple
+ columns:
+
+ \snippet qml/tableview/tablemodel.cpp 0
+
+ And then how to use it from QML:
+
+ \snippet qml/tableview/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
+ delegate.
+
+ When an item is flicked out, it moves to the \e{reuse pool}, which is an
+ internal cache of unused items. When this happens, the \l TableView::pooled
+ signal is emitted to inform the item about it. Likewise, when the item is
+ moved back from the pool, the \l TableView::reused signal is emitted.
+
+ Any item properties that come from the model are updated when the
+ item is reused. This includes \c index, \c row, and \c column, but also
+ any model roles.
+
+ \note Avoid storing any state inside a delegate. If you do, reset it
+ manually on receiving the \l TableView::reused signal.
+
+ If an item has timers or animations, consider pausing them on receiving
+ the \l TableView::pooled signal. That way you avoid using the CPU resources
+ for items that are not visible. Likewise, if an item has resources that
+ cannot be reused, they could be freed up.
+
+ If you don't want to reuse items or if the \l delegate cannot support it,
+ you can set the \l reuseItems property to \c false.
+
+ \note While an item is in the pool, it might still be alive and respond
+ to connected signals and bindings.
+
+ The following example shows a delegate that animates a spinning rectangle. When
+ it is pooled, the animation is temporarily paused:
+
+ \snippet qml/tableview/reusabledelegate.qml 0
+
+ \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
+ containing any number of rows and columns. Instead, it will ask the
+ application whenever it needs to know.
+
+ TableView uses the largest \c implicitWidth among the items as the column
+ width, unless the \l columnWidthProvider property is explicitly set. Once
+ the column width is found, all other items in the same column are resized
+ to this width, even if new items that are flicked in later have larger
+ \c implicitWidth. Setting an explicit \c width on an item is ignored and
+ overwritten.
+
+ \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
+ \l columnWidthProvider. The same logic applies for the row height
+ calculation.
+
+ If you change the values that a \l rowHeightProvider or a
+ \l columnWidthProvider return for rows and columns inside the viewport, you
+ 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.
+
+ \note The size of a row or column should be a whole number to avoid
+ sub-pixel alignment of items.
+
+ The following example shows how to set a simple \c columnWidthProvider
+ together with a timer that modifies the values the function returns. When
+ the array is modified, \l forceLayout is called to let the changes
+ take effect:
+
+ \snippet qml/tableview/tableviewwithprovider.qml 0
+
+ \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.
+
+ 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:
+
+ \snippet qml/tableview/tableviewwithheader.qml 0
+*/
+
+/*!
+ \qmlproperty int QtQuick::TableView::rows
+
+ This property holds the number of rows in the table. This is
+ equal to the number of rows in the model.
+
+ This property is read only.
+*/
+
+/*!
+ \qmlproperty int QtQuick::TableView::columns
+
+ 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.
+
+ This property is read only.
+*/
+
+/*!
+ \qmlproperty real QtQuick::TableView::rowSpacing
+
+ This property holds the spacing between the rows.
+
+ The default value is 0.
+*/
+
+/*!
+ \qmlproperty real QtQuick::TableView::columnSpacing
+
+ This property holds the spacing between the columns.
+
+ The default value is 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.
+
+ 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.
+
+ \sa columnWidthProvider, {Row heights and column widths}
+*/
+
+/*!
+ \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.
+
+ 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.
+
+ \sa rowHeightProvider, {Row heights and column widths}
+*/
+
+/*!
+ \qmlproperty model QtQuick::TableView::model
+ 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
+ or a simple list.
+
+ \sa {qml-data-models}{Data Models}
+*/
+
+/*!
+ \qmlproperty Component QtQuick::TableView::delegate
+
+ The delegate provides a template defining each cell item instantiated by the
+ view. The model index is exposed as an accessible \c index property. The same
+ 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.
+
+ \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
+ should therefore avoid storing state information in the delegates.
+
+ \sa {Row heights and column widths}, {Reusing items}
+*/
+
+/*!
+ \qmlproperty bool QtQuick::TableView::reuseItems
+
+ This property holds whether or not items instantiated from the \l delegate
+ should be reused. If set to \c false, any currently pooled items
+ are destroyed.
+
+ \sa {Reusing items}, TableView::pooled, TableView::reused
+*/
+
+/*!
+ \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.
+
+ 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.
+
+ \sa contentHeight
+*/
+
+/*!
+ \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.
+
+ 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.
+
+ \sa contentWidth
+*/
+
+/*!
+ \qmlmethod QtQuick::TableView::forceLayout
+
+ 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}.
+
+ This method forces the TableView to immediately update the layout so
+ that any recent changes take effect.
+
+ Calling this function re-evaluates the size and position of each visible
+ row and column. This is needed if the functions assigned to
+ \l rowHeightProvider or \l columnWidthProvider return different values than
+ what is already assigned.
+*/
+
+/*!
+ \qmlattachedproperty TableView QtQuick::TableView::view
+
+ This attached property holds the view that manages the delegate instance.
+ It is attached to each instance of the delegate.
+*/
+
+/*!
+ \qmlattachedsignal QtQuick::TableView::pooled
+
+ This signal is emitted after an item has been added to the reuse
+ pool. You can use it to pause ongoing timers or animations inside
+ the item, or free up resources that cannot be reused.
+
+ This signal is emitted only if the \l reuseItems property is \c true.
+
+ \sa {Reusing items}, reuseItems, reused
+*/
+
+/*!
+ \qmlattachedsignal QtQuick::TableView::reused
+
+ This signal is emitted after an item has been reused. At this point, the
+ 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.
+
+ This signal is emitted when the item is reused, and not the first time the
+ item is created.
+
+ This signal is emitted only if the \l reuseItems property is \c true.
+
+ \sa {Reusing items}, reuseItems, pooled
+*/
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcTableViewDelegateLifecycle, "qt.quick.tableview.lifecycle")
+
+#define Q_TABLEVIEW_UNREACHABLE(output) { dumpTable(); qWarning() << "output:" << output; Q_UNREACHABLE(); }
+#define Q_TABLEVIEW_ASSERT(cond, output) Q_ASSERT((cond) || [&](){ dumpTable(); qWarning() << "output:" << output; return false;}())
+
+static const Qt::Edge allTableEdges[] = { Qt::LeftEdge, Qt::RightEdge, Qt::TopEdge, Qt::BottomEdge };
+static const int kEdgeIndexNotSet = -2;
+static const int kEdgeIndexAtEnd = -3;
+
+const QPoint QQuickTableViewPrivate::kLeft = QPoint(-1, 0);
+const QPoint QQuickTableViewPrivate::kRight = QPoint(1, 0);
+const QPoint QQuickTableViewPrivate::kUp = QPoint(0, -1);
+const QPoint QQuickTableViewPrivate::kDown = QPoint(0, 1);
+
+QQuickTableViewPrivate::EdgeRange::EdgeRange()
+ : startIndex(kEdgeIndexNotSet)
+ , endIndex(kEdgeIndexNotSet)
+ , size(0)
+{}
+
+bool QQuickTableViewPrivate::EdgeRange::containsIndex(Qt::Edge edge, int index)
+{
+ if (startIndex == kEdgeIndexNotSet)
+ return false;
+
+ if (endIndex == kEdgeIndexAtEnd) {
+ switch (edge) {
+ case Qt::LeftEdge:
+ case Qt::TopEdge:
+ return index <= startIndex;
+ case Qt::RightEdge:
+ case Qt::BottomEdge:
+ return index >= startIndex;
+ }
+ }
+
+ const int s = std::min(startIndex, endIndex);
+ const int e = std::max(startIndex, endIndex);
+ return index >= s && index <= e;
+}
+
+QQuickTableViewPrivate::QQuickTableViewPrivate()
+ : QQuickFlickablePrivate()
+{
+}
+
+QQuickTableViewPrivate::~QQuickTableViewPrivate()
+{
+ releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
+ if (tableModel)
+ delete tableModel;
+}
+
+QString QQuickTableViewPrivate::tableLayoutToString() const
+{
+ return QString(QLatin1String("table cells: (%1,%2) -> (%3,%4), item count: %5, table rect: %6,%7 x %8,%9"))
+ .arg(leftColumn()).arg(topRow())
+ .arg(rightColumn()).arg(bottomRow())
+ .arg(loadedItems.count())
+ .arg(loadedTableOuterRect.x())
+ .arg(loadedTableOuterRect.y())
+ .arg(loadedTableOuterRect.width())
+ .arg(loadedTableOuterRect.height());
+}
+
+void QQuickTableViewPrivate::dumpTable() const
+{
+ auto listCopy = loadedItems.values();
+ std::stable_sort(listCopy.begin(), listCopy.end(),
+ [](const FxTableItem *lhs, const FxTableItem *rhs)
+ { return lhs->index < rhs->index; });
+
+ qWarning() << QStringLiteral("******* TABLE DUMP *******");
+ for (int i = 0; i < listCopy.count(); ++i)
+ qWarning() << static_cast<FxTableItem *>(listCopy.at(i))->cell;
+ qWarning() << tableLayoutToString();
+
+ const QString filename = QStringLiteral("QQuickTableView_dumptable_capture.png");
+ const QString path = QDir::current().absoluteFilePath(filename);
+ if (q_func()->window() && q_func()->window()->grabWindow().save(path))
+ qWarning() << "Window capture saved to:" << path;
+}
+
+QQuickTableViewAttached *QQuickTableViewPrivate::getAttachedObject(const QObject *object) const
+{
+ QObject *attachedObject = qmlAttachedPropertiesObject<QQuickTableView>(object);
+ return static_cast<QQuickTableViewAttached *>(attachedObject);
+}
+
+int QQuickTableViewPrivate::modelIndexAtCell(const QPoint &cell) const
+{
+ int availableRows = tableSize.height();
+ int modelIndex = cell.y() + (cell.x() * availableRows);
+ Q_TABLEVIEW_ASSERT(modelIndex < model->count(),
+ "modelIndex:" << modelIndex << "cell:" << cell << "count:" << model->count());
+ return modelIndex;
+}
+
+QPoint QQuickTableViewPrivate::cellAtModelIndex(int modelIndex) const
+{
+ int availableRows = tableSize.height();
+ Q_TABLEVIEW_ASSERT(availableRows > 0, availableRows);
+ int column = int(modelIndex / availableRows);
+ int row = modelIndex % availableRows;
+ return QPoint(column, row);
+}
+
+int QQuickTableViewPrivate::edgeToArrayIndex(Qt::Edge edge)
+{
+ return int(log2(float(edge)));
+}
+
+void QQuickTableViewPrivate::clearEdgeSizeCache()
+{
+ cachedColumnWidth.startIndex = kEdgeIndexNotSet;
+ cachedRowHeight.startIndex = kEdgeIndexNotSet;
+
+ for (Qt::Edge edge : allTableEdges)
+ cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)].startIndex = kEdgeIndexNotSet;
+}
+
+int QQuickTableViewPrivate::nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge)
+{
+ // Find the next column (or row) around the loaded table that is
+ // visible, and should be loaded next if the content item moves.
+ int startIndex = -1;
+ switch (edge) {
+ case Qt::LeftEdge: startIndex = loadedColumns.firstKey() - 1; break;
+ case Qt::RightEdge: startIndex = loadedColumns.lastKey() + 1; break;
+ case Qt::TopEdge: startIndex = loadedRows.firstKey() - 1; break;
+ case Qt::BottomEdge: startIndex = loadedRows.lastKey() + 1; break;
+ }
+
+ return nextVisibleEdgeIndex(edge, startIndex);
+}
+
+int QQuickTableViewPrivate::nextVisibleEdgeIndex(Qt::Edge edge, int startIndex)
+{
+ // First check if we have already searched for the first visible index
+ // after the given startIndex recently, and if so, return the cached result.
+ // The cached result is valid if startIndex is inside the range between the
+ // startIndex and the first visible index found after it.
+ auto &cachedResult = cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)];
+ if (cachedResult.containsIndex(edge, startIndex))
+ return cachedResult.endIndex;
+
+ // Search for the first column (or row) in the direction of edge that is
+ // visible, starting from the given column (startIndex).
+ int foundIndex = kEdgeIndexNotSet;
+ int testIndex = startIndex;
+
+ switch (edge) {
+ case Qt::LeftEdge: {
+ forever {
+ if (testIndex < 0) {
+ foundIndex = kEdgeIndexAtEnd;
+ break;
+ }
+
+ if (!isColumnHidden(testIndex)) {
+ foundIndex = testIndex;
+ break;
+ }
+
+ --testIndex;
+ }
+ break; }
+ case Qt::RightEdge: {
+ forever {
+ if (testIndex > tableSize.width() - 1) {
+ foundIndex = kEdgeIndexAtEnd;
+ break;
+ }
+
+ if (!isColumnHidden(testIndex)) {
+ foundIndex = testIndex;
+ break;
+ }
+
+ ++testIndex;
+ }
+ break; }
+ case Qt::TopEdge: {
+ forever {
+ if (testIndex < 0) {
+ foundIndex = kEdgeIndexAtEnd;
+ break;
+ }
+
+ if (!isRowHidden(testIndex)) {
+ foundIndex = testIndex;
+ break;
+ }
+
+ --testIndex;
+ }
+ break; }
+ case Qt::BottomEdge: {
+ forever {
+ if (testIndex > tableSize.height() - 1) {
+ foundIndex = kEdgeIndexAtEnd;
+ break;
+ }
+
+ if (!isRowHidden(testIndex)) {
+ foundIndex = testIndex;
+ break;
+ }
+
+ ++testIndex;
+ }
+ break; }
+ }
+
+ cachedResult.startIndex = startIndex;
+ cachedResult.endIndex = foundIndex;
+ return foundIndex;
+}
+
+void QQuickTableViewPrivate::updateContentWidth()
+{
+ Q_Q(QQuickTableView);
+
+ if (explicitContentWidth.isValid()) {
+ // Don't calculate contentWidth when it
+ // was set explicitly by the application.
+ return;
+ }
+
+ const int nextColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
+ const int columnsRemaining = nextColumn == kEdgeIndexAtEnd ? 0 : tableSize.width() - nextColumn;
+ const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
+ const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
+ const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
+ const qreal estimatedWidth = loadedTableOuterRect.right() + estimatedRemainingWidth;
+ q->QQuickFlickable::setContentWidth(estimatedWidth);
+}
+
+void QQuickTableViewPrivate::updateContentHeight()
+{
+ Q_Q(QQuickTableView);
+
+ if (explicitContentHeight.isValid()) {
+ // Don't calculate contentHeight when it
+ // was set explicitly by the application.
+ return;
+ }
+
+ const int nextRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
+ const int rowsRemaining = nextRow == kEdgeIndexAtEnd ? 0 : tableSize.height() - nextRow;
+ const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
+ const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
+ const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
+ const qreal estimatedHeight = loadedTableOuterRect.bottom() + estimatedRemainingHeight;
+ q->QQuickFlickable::setContentHeight(estimatedHeight);
+}
+
+void QQuickTableViewPrivate::enforceTableAtOrigin()
+{
+ // 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;
+
+ 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;
+ }
+ } 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;
+ }
+ }
+
+ if (noMoreRows) {
+ if (!qFuzzyIsNull(loadedTableOuterRect.top())) {
+ loadedTableOuterRect.moveTop(0);
+ layoutNeeded = true;
+ }
+ } else {
+ if (loadedTableOuterRect.top() <= 0) {
+ loadedTableOuterRect.moveTop(flickMargin);
+ layoutNeeded = true;
+ }
+ }
+
+ if (layoutNeeded) {
+ qCDebug(lcTableViewDelegateLifecycle);
+ relayoutTableItems();
+ }
+}
+
+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);
+}
+
+void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
+{
+ const QPoint topLeft = QPoint(leftColumn(), topRow());
+ const QPoint bottomRight = QPoint(rightColumn(), bottomRow());
+ QRectF topLeftRect = loadedTableItem(topLeft)->geometry();
+ QRectF bottomRightRect = loadedTableItem(bottomRight)->geometry();
+ loadedTableOuterRect = QRectF(topLeftRect.topLeft(), bottomRightRect.bottomRight());
+ loadedTableInnerRect = QRectF(topLeftRect.bottomRight(), bottomRightRect.topLeft());
+}
+
+void QQuickTableViewPrivate::forceLayout()
+{
+ columnRowPositionsInvalid = true;
+ clearEdgeSizeCache();
+ RebuildOptions rebuildOptions = RebuildOption::None;
+
+ // 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
+ // (and vice versa). If there is a change, we need to rebuild.
+ for (int column = leftColumn(); column <= rightColumn(); ++column) {
+ const bool wasVisibleFromBefore = loadedColumns.contains(column);
+ const bool isVisibleNow = !qFuzzyIsNull(getColumnWidth(column));
+ if (wasVisibleFromBefore == isVisibleNow)
+ continue;
+
+ // A column changed visibility. This means that it should
+ // either be loaded or unloaded. So we need a rebuild.
+ qCDebug(lcTableViewDelegateLifecycle) << "Column" << column << "changed visibility to" << isVisibleNow;
+ rebuildOptions.setFlag(RebuildOption::ViewportOnly);
+ if (column == leftColumn()) {
+ // The first loaded column should now be hidden. This means that we
+ // need to calculate which column should now be first instead.
+ rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
+ }
+ break;
+ }
+
+ // Go through all rows from first to last, and do the same as above
+ for (int row = topRow(); row <= bottomRow(); ++row) {
+ const bool wasVisibleFromBefore = loadedRows.contains(row);
+ const bool isVisibleNow = !qFuzzyIsNull(getRowHeight(row));
+ if (wasVisibleFromBefore == isVisibleNow)
+ continue;
+
+ // A row changed visibility. This means that it should
+ // either be loaded or unloaded. So we need a rebuild.
+ qCDebug(lcTableViewDelegateLifecycle) << "Row" << row << "changed visibility to" << isVisibleNow;
+ rebuildOptions.setFlag(RebuildOption::ViewportOnly);
+ if (row == topRow())
+ rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
+ break;
+ }
+
+ if (rebuildOptions)
+ scheduleRebuildTable(rebuildOptions);
+
+ if (polishing) {
+ qWarning() << "TableView::forceLayout(): Cannot do an immediate re-layout during an ongoing layout!";
+ q_func()->polish();
+ return;
+ }
+
+ updatePolish();
+}
+
+void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest()
+{
+ if (loadRequest.edge() == Qt::Edge(0)) {
+ // No edge means we're loading the top-left item
+ loadedColumns.insert(loadRequest.column(), 0);
+ loadedRows.insert(loadRequest.row(), 0);
+ return;
+ }
+
+ switch (loadRequest.edge()) {
+ case Qt::LeftEdge:
+ case Qt::RightEdge:
+ loadedColumns.insert(loadRequest.column(), 0);
+ break;
+ case Qt::TopEdge:
+ case Qt::BottomEdge:
+ loadedRows.insert(loadRequest.row(), 0);
+ break;
+ }
+}
+
+FxTableItem *QQuickTableViewPrivate::loadedTableItem(const QPoint &cell) const
+{
+ const int modelIndex = modelIndexAtCell(cell);
+ Q_TABLEVIEW_ASSERT(loadedItems.contains(modelIndex), modelIndex << cell);
+ return loadedItems.value(modelIndex);
+}
+
+FxTableItem *QQuickTableViewPrivate::createFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
+{
+ Q_Q(QQuickTableView);
+
+ bool ownItem = false;
+ int modelIndex = modelIndexAtCell(cell);
+
+ QObject* object = model->object(modelIndex, incubationMode);
+ if (!object) {
+ if (model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
+ // Item is incubating. Return nullptr for now, and let the table call this
+ // function again once we get a callback to itemCreatedCallback().
+ return nullptr;
+ }
+
+ qWarning() << "TableView: failed loading index:" << modelIndex;
+ object = new QQuickItem();
+ ownItem = true;
+ }
+
+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
+ if (!item) {
+ // The model could not provide an QQuickItem for the
+ // given index, so we create a placeholder instead.
+ qWarning() << "TableView: delegate is not an item:" << modelIndex;
+ model->release(object);
+ item = new QQuickItem();
+ ownItem = true;
+ } else {
+ QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
+ if (anchors && anchors->activeDirections())
+ qmlWarning(item) << "TableView: detected anchors on delegate with index: " << modelIndex
+ << ". Use implicitWidth and implicitHeight instead.";
+ }
+
+ if (ownItem) {
+ // Parent item is normally set early on from initItemCallback (to
+ // allow bindings to the parent property). But if we created the item
+ // within this function, we need to set it explicit.
+ item->setImplicitWidth(kDefaultColumnWidth);
+ item->setImplicitHeight(kDefaultRowHeight);
+ item->setParentItem(q->contentItem());
+ }
+ Q_TABLEVIEW_ASSERT(item->parentItem() == q->contentItem(), item->parentItem());
+
+ FxTableItem *fxTableItem = new FxTableItem(item, q, ownItem);
+ fxTableItem->setVisible(false);
+ fxTableItem->cell = cell;
+ fxTableItem->index = modelIndex;
+ return fxTableItem;
+}
+
+FxTableItem *QQuickTableViewPrivate::loadFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
+{
+#ifdef QT_DEBUG
+ // Since TableView needs to work flawlessly when e.g incubating inside an async
+ // loader, being able to override all loading to async while debugging can be helpful.
+ static const bool forcedAsync = forcedIncubationMode == QLatin1String("async");
+ if (forcedAsync)
+ incubationMode = QQmlIncubator::Asynchronous;
+#endif
+
+ // Note that even if incubation mode is asynchronous, the item might
+ // be ready immediately since the model has a cache of items.
+ QBoolBlocker guard(blockItemCreatedCallback);
+ auto item = createFxTableItem(cell, incubationMode);
+ qCDebug(lcTableViewDelegateLifecycle) << cell << "ready?" << bool(item);
+ return item;
+}
+
+void QQuickTableViewPrivate::releaseLoadedItems(QQmlTableInstanceModel::ReusableFlag reusableFlag) {
+ // Make a copy and clear the list of items first to avoid destroyed
+ // items being accessed during the loop (QTBUG-61294)
+ auto const tmpList = loadedItems;
+ loadedItems.clear();
+ for (FxTableItem *item : tmpList)
+ releaseItem(item, reusableFlag);
+}
+
+void QQuickTableViewPrivate::releaseItem(FxTableItem *fxTableItem, QQmlTableInstanceModel::ReusableFlag reusableFlag)
+{
+ Q_Q(QQuickTableView);
+ auto item = fxTableItem->item;
+ Q_TABLEVIEW_ASSERT(item, fxTableItem->index);
+
+ if (fxTableItem->ownItem) {
+ delete item;
+ } else {
+ // Only QQmlTableInstanceModel supports reusing items
+ auto releaseFlag = tableModel ?
+ tableModel->release(item, reusableFlag) :
+ model->release(item);
+
+ if (releaseFlag != QQmlInstanceModel::Destroyed) {
+ // When items are not destroyed, it typically means that the
+ // item is reused, or that the model is an ObjectModel. If
+ // so, we just hide the item instead.
+ fxTableItem->setVisible(false);
+
+ // If the item (or a descendant) has focus, remove it, so
+ // that the item doesn't enter with focus when it's reused.
+ if (QQuickWindow *window = item->window()) {
+ const auto focusItem = qobject_cast<QQuickItem *>(window->focusObject());
+ if (focusItem) {
+ const bool hasFocus = item == focusItem || item->isAncestorOf(focusItem);
+ if (hasFocus) {
+ const auto focusChild = QQuickItemPrivate::get(q)->subFocusItem;
+ QQuickWindowPrivate::get(window)->clearFocusInScope(q, focusChild, Qt::OtherFocusReason);
+ }
+ }
+ }
+ }
+ }
+
+ delete fxTableItem;
+}
+
+void QQuickTableViewPrivate::unloadItem(const QPoint &cell)
+{
+ const int modelIndex = modelIndexAtCell(cell);
+ Q_TABLEVIEW_ASSERT(loadedItems.contains(modelIndex), modelIndex << cell);
+ releaseItem(loadedItems.take(modelIndex), reusableFlag);
+}
+
+bool QQuickTableViewPrivate::canLoadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const
+{
+ switch (tableEdge) {
+ case Qt::LeftEdge:
+ return loadedTableOuterRect.left() > fillRect.left() + cellSpacing.width();
+ case Qt::RightEdge:
+ return loadedTableOuterRect.right() < fillRect.right() - cellSpacing.width();
+ case Qt::TopEdge:
+ return loadedTableOuterRect.top() > fillRect.top() + cellSpacing.height();
+ case Qt::BottomEdge:
+ return loadedTableOuterRect.bottom() < fillRect.bottom() - cellSpacing.height();
+ }
+
+ return false;
+}
+
+bool QQuickTableViewPrivate::canUnloadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const
+{
+ // Note: if there is only one row or column left, we cannot unload, since
+ // they are needed as anchor point for further layouting.
+ switch (tableEdge) {
+ case Qt::LeftEdge:
+ if (loadedColumns.count() <= 1)
+ return false;
+ return loadedTableInnerRect.left() <= fillRect.left();
+ case Qt::RightEdge:
+ if (loadedColumns.count() <= 1)
+ return false;
+ return loadedTableInnerRect.right() >= fillRect.right();
+ case Qt::TopEdge:
+ if (loadedRows.count() <= 1)
+ return false;
+ return loadedTableInnerRect.top() <= fillRect.top();
+ case Qt::BottomEdge:
+ if (loadedRows.count() <= 1)
+ return false;
+ return loadedTableInnerRect.bottom() >= fillRect.bottom();
+ }
+ Q_TABLEVIEW_UNREACHABLE(tableEdge);
+ return false;
+}
+
+Qt::Edge QQuickTableViewPrivate::nextEdgeToLoad(const QRectF rect)
+{
+ for (Qt::Edge edge : allTableEdges) {
+ if (!canLoadTableEdge(edge, rect))
+ continue;
+ const int nextIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
+ if (nextIndex == kEdgeIndexAtEnd)
+ continue;
+ return edge;
+ }
+
+ return Qt::Edge(0);
+}
+
+Qt::Edge QQuickTableViewPrivate::nextEdgeToUnload(const QRectF rect)
+{
+ for (Qt::Edge edge : allTableEdges) {
+ if (canUnloadTableEdge(edge, rect))
+ return edge;
+ }
+ return Qt::Edge(0);
+}
+
+qreal QQuickTableViewPrivate::cellWidth(const QPoint& cell)
+{
+ // Using an items width directly is not an option, since we change
+ // it during layout (which would also cause problems when recycling items).
+ auto const cellItem = loadedTableItem(cell)->item;
+ return cellItem->implicitWidth();
+}
+
+qreal QQuickTableViewPrivate::cellHeight(const QPoint& cell)
+{
+ // Using an items height directly is not an option, since we change
+ // it during layout (which would also cause problems when recycling items).
+ auto const cellItem = loadedTableItem(cell)->item;
+ return cellItem->implicitHeight();
+}
+
+qreal QQuickTableViewPrivate::sizeHintForColumn(int column)
+{
+ // Find the widest cell in the column, and return its width
+ qreal columnWidth = 0;
+ for (auto r = loadedRows.cbegin(); r != loadedRows.cend(); ++r) {
+ const int row = r.key();
+ columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
+ }
+
+ return columnWidth;
+}
+
+qreal QQuickTableViewPrivate::sizeHintForRow(int row)
+{
+ // Find the highest cell in the row, and return its height
+ qreal rowHeight = 0;
+ for (auto c = loadedColumns.cbegin(); c != loadedColumns.cend(); ++c) {
+ const int column = c.key();
+ rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
+ }
+
+ return rowHeight;
+}
+
+void QQuickTableViewPrivate::calculateTableSize()
+{
+ // tableSize is the same as row and column count, and will always
+ // be the same as the number of rows and columns in the model.
+ Q_Q(QQuickTableView);
+ QSize prevTableSize = tableSize;
+
+ if (tableModel)
+ tableSize = QSize(tableModel->columns(), tableModel->rows());
+ else if (model)
+ tableSize = QSize(1, model->count());
+ else
+ tableSize = QSize(0, 0);
+
+ if (prevTableSize.width() != tableSize.width())
+ emit q->columnsChanged();
+ if (prevTableSize.height() != tableSize.height())
+ emit q->rowsChanged();
+}
+
+qreal QQuickTableViewPrivate::getColumnLayoutWidth(int column)
+{
+ // Return the column width specified by the application, or go
+ // through the loaded items and calculate it as a fallback. For
+ // layouting, the width can never be zero (or negative), as this
+ // can lead us to be stuck in an infinite loop trying to load and
+ // fill out the empty viewport space with empty columns.
+ const qreal explicitColumnWidth = getColumnWidth(column);
+ if (explicitColumnWidth >= 0)
+ return explicitColumnWidth;
+
+ // 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
+ // row you're at when the column is flicked in). The upshot is that you don't have to
+ // bother setting columnWidthProvider for small tables, or if the implicit width doesn't vary.
+ qreal columnWidth = sizeHintForColumn(column);
+
+ if (qIsNaN(columnWidth) || columnWidth <= 0) {
+ if (!layoutWarningIssued) {
+ layoutWarningIssued = true;
+ qmlWarning(q_func()) << "the delegate's implicitHeight needs to be greater than zero";
+ }
+ columnWidth = kDefaultRowHeight;
+ }
+
+ return columnWidth;
+}
+
+qreal QQuickTableViewPrivate::getRowLayoutHeight(int row)
+{
+ // Return the row height specified by the application, or go
+ // through the loaded items and calculate it as a fallback. For
+ // layouting, the height can never be zero (or negative), as this
+ // can lead us to be stuck in an infinite loop trying to load and
+ // fill out the empty viewport space with empty rows.
+ const qreal explicitRowHeight = getRowHeight(row);
+ if (explicitRowHeight >= 0)
+ return explicitRowHeight;
+
+ // 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
+ // column you're at when the row is flicked in). The upshot is that you don't have to
+ // bother setting rowHeightProvider for small tables, or if the implicit height doesn't vary.
+ qreal rowHeight = sizeHintForRow(row);
+
+ if (qIsNaN(rowHeight) || rowHeight <= 0) {
+ if (!layoutWarningIssued) {
+ layoutWarningIssued = true;
+ qmlWarning(q_func()) << "the delegate's implicitHeight needs to be greater than zero";
+ }
+ rowHeight = kDefaultRowHeight;
+ }
+
+ return rowHeight;
+}
+
+qreal QQuickTableViewPrivate::getColumnWidth(int column)
+{
+ // Return the width of the given column, if explicitly set. Return 0 if the column
+ // is hidden, and -1 if the width is not set (which means that the width should
+ // instead be calculated from the implicit size of the delegate items. This function
+ // can be overridden by e.g HeaderView to provide the column widths by other means.
+ const int noExplicitColumnWidth = -1;
+
+ if (cachedColumnWidth.startIndex == column)
+ return cachedColumnWidth.size;
+
+ if (columnWidthProvider.isUndefined())
+ return noExplicitColumnWidth;
+
+ qreal columnWidth = noExplicitColumnWidth;
+
+ if (columnWidthProvider.isCallable()) {
+ auto const columnAsArgument = QJSValueList() << QJSValue(column);
+ columnWidth = columnWidthProvider.call(columnAsArgument).toNumber();
+ if (qIsNaN(columnWidth) || columnWidth < 0)
+ columnWidth = noExplicitColumnWidth;
+ } else {
+ if (!layoutWarningIssued) {
+ layoutWarningIssued = true;
+ qmlWarning(q_func()) << "columnWidthProvider doesn't contain a function";
+ }
+ columnWidth = noExplicitColumnWidth;
+ }
+
+ cachedColumnWidth.startIndex = column;
+ cachedColumnWidth.size = columnWidth;
+ return columnWidth;
+}
+
+qreal QQuickTableViewPrivate::getRowHeight(int row)
+{
+ // Return the height of the given row, if explicitly set. Return 0 if the row
+ // is hidden, and -1 if the height is not set (which means that the height should
+ // instead be calculated from the implicit size of the delegate items. This function
+ // can be overridden by e.g HeaderView to provide the row heights by other means.
+ const int noExplicitRowHeight = -1;
+
+ if (cachedRowHeight.startIndex == row)
+ return cachedRowHeight.size;
+
+ if (rowHeightProvider.isUndefined())
+ return noExplicitRowHeight;
+
+ qreal rowHeight = noExplicitRowHeight;
+
+ if (rowHeightProvider.isCallable()) {
+ auto const rowAsArgument = QJSValueList() << QJSValue(row);
+ rowHeight = rowHeightProvider.call(rowAsArgument).toNumber();
+ if (qIsNaN(rowHeight) || rowHeight < 0)
+ rowHeight = noExplicitRowHeight;
+ } else {
+ if (!layoutWarningIssued) {
+ layoutWarningIssued = true;
+ qmlWarning(q_func()) << "rowHeightProvider doesn't contain a function";
+ }
+ rowHeight = noExplicitRowHeight;
+ }
+
+ cachedRowHeight.startIndex = row;
+ cachedRowHeight.size = rowHeight;
+ return rowHeight;
+}
+
+bool QQuickTableViewPrivate::isColumnHidden(int column)
+{
+ // A column is hidden if the width is explicit set to zero (either by
+ // using a columnWidthProvider, or by overriding getColumnWidth()).
+ return qFuzzyIsNull(getColumnWidth(column));
+}
+
+bool QQuickTableViewPrivate::isRowHidden(int row)
+{
+ // A row is hidden if the height is explicit set to zero (either by
+ // using a rowHeightProvider, or by overriding getRowHeight()).
+ 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();
+
+ for (auto c = loadedColumns.cbegin(); c != loadedColumns.cend(); ++c) {
+ const int column = c.key();
+ // Adjust the geometry of all cells in the current column
+ const qreal width = getColumnLayoutWidth(column);
+
+ for (auto r = loadedRows.cbegin(); r != loadedRows.cend(); ++r) {
+ const int row = r.key();
+ auto item = loadedTableItem(QPoint(column, row));
+ QRectF geometry = item->geometry();
+ geometry.moveLeft(nextColumnX);
+ geometry.setWidth(width);
+ item->setGeometry(geometry);
+ }
+
+ if (width > 0)
+ nextColumnX += width + cellSpacing.width();
+ }
+
+ for (auto r = loadedRows.cbegin(); r != loadedRows.cend(); ++r) {
+ const int row = r.key();
+ // Adjust the geometry of all cells in the current row
+ const qreal height = getRowLayoutHeight(row);
+
+ for (auto c = loadedColumns.cbegin(); c != loadedColumns.cend(); ++c) {
+ const int column = c.key();
+ auto item = loadedTableItem(QPoint(column, row));
+ QRectF geometry = item->geometry();
+ geometry.moveTop(nextRowY);
+ geometry.setHeight(height);
+ item->setGeometry(geometry);
+ }
+
+ if (height > 0)
+ nextRowY += height + cellSpacing.height();
+ }
+
+ if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) {
+ for (auto c = loadedColumns.cbegin(); c != loadedColumns.cend(); ++c) {
+ const int column = c.key();
+ for (auto r = loadedRows.cbegin(); r != loadedRows.cend(); ++r) {
+ const int row = r.key();
+ QPoint cell = QPoint(column, row);
+ qCDebug(lcTableViewDelegateLifecycle()) << "relayout item:" << cell << loadedTableItem(cell)->geometry();
+ }
+ }
+ }
+}
+
+void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge)
+{
+ int columnThatNeedsLayout;
+ int neighbourColumn;
+ qreal columnX;
+ qreal columnWidth;
+
+ if (tableEdge == Qt::LeftEdge) {
+ columnThatNeedsLayout = leftColumn();
+ neighbourColumn = loadedColumns.keys().value(1);
+ columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
+ const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
+ columnX = neighbourItem->geometry().left() - cellSpacing.width() - columnWidth;
+ } else {
+ columnThatNeedsLayout = rightColumn();
+ neighbourColumn = loadedColumns.keys().value(loadedColumns.count() - 2);
+ columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
+ const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
+ columnX = neighbourItem->geometry().right() + cellSpacing.width();
+ }
+
+ for (auto r = loadedRows.cbegin(); r != loadedRows.cend(); ++r) {
+ const int row = r.key();
+ auto fxTableItem = loadedTableItem(QPoint(columnThatNeedsLayout, row));
+ auto const neighbourItem = loadedTableItem(QPoint(neighbourColumn, row));
+ const qreal rowY = neighbourItem->geometry().y();
+ const qreal rowHeight = neighbourItem->geometry().height();
+
+ fxTableItem->setGeometry(QRectF(columnX, rowY, columnWidth, rowHeight));
+ fxTableItem->setVisible(true);
+
+ qCDebug(lcTableViewDelegateLifecycle()) << "layout item:" << QPoint(columnThatNeedsLayout, row) << fxTableItem->geometry();
+ }
+}
+
+void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge)
+{
+ int rowThatNeedsLayout;
+ int neighbourRow;
+ qreal rowY;
+ qreal rowHeight;
+
+ if (tableEdge == Qt::TopEdge) {
+ rowThatNeedsLayout = topRow();
+ neighbourRow = loadedRows.keys().value(1);
+ rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
+ const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
+ rowY = neighbourItem->geometry().top() - cellSpacing.height() - rowHeight;
+ } else {
+ rowThatNeedsLayout = bottomRow();
+ neighbourRow = loadedRows.keys().value(loadedRows.count() - 2);
+ rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
+ const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
+ rowY = neighbourItem->geometry().bottom() + cellSpacing.height();
+ }
+
+ for (auto c = loadedColumns.cbegin(); c != loadedColumns.cend(); ++c) {
+ const int column = c.key();
+ auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
+ auto const neighbourItem = loadedTableItem(QPoint(column, neighbourRow));
+ const qreal columnX = neighbourItem->geometry().x();
+ const qreal columnWidth = neighbourItem->geometry().width();
+
+ fxTableItem->setGeometry(QRectF(columnX, rowY, columnWidth, rowHeight));
+ fxTableItem->setVisible(true);
+
+ qCDebug(lcTableViewDelegateLifecycle()) << "layout item:" << QPoint(column, rowThatNeedsLayout) << fxTableItem->geometry();
+ }
+}
+
+void QQuickTableViewPrivate::layoutTopLeftItem()
+{
+ const QPoint cell(loadRequest.column(), loadRequest.row());
+ auto topLeftItem = loadedTableItem(cell);
+ auto item = topLeftItem->item;
+
+ item->setPosition(loadRequest.startPosition());
+ item->setSize(QSizeF(getColumnLayoutWidth(cell.x()), getRowLayoutHeight(cell.y())));
+ topLeftItem->setVisible(true);
+ qCDebug(lcTableViewDelegateLifecycle) << "geometry:" << topLeftItem->geometry();
+}
+
+void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
+{
+ if (loadRequest.edge() == Qt::Edge(0)) {
+ // No edge means we're loading the top-left item
+ layoutTopLeftItem();
+ return;
+ }
+
+ switch (loadRequest.edge()) {
+ case Qt::LeftEdge:
+ case Qt::RightEdge:
+ layoutVerticalEdge(loadRequest.edge());
+ break;
+ case Qt::TopEdge:
+ case Qt::BottomEdge:
+ layoutHorizontalEdge(loadRequest.edge());
+ break;
+ }
+}
+
+void QQuickTableViewPrivate::processLoadRequest()
+{
+ Q_TABLEVIEW_ASSERT(loadRequest.isActive(), "");
+
+ while (loadRequest.hasCurrentCell()) {
+ QPoint cell = loadRequest.currentCell();
+ FxTableItem *fxTableItem = loadFxTableItem(cell, loadRequest.incubationMode());
+
+ if (!fxTableItem) {
+ // Requested item is not yet ready. Just leave, and wait for this
+ // function to be called again when the item is ready.
+ return;
+ }
+
+ loadedItems.insert(modelIndexAtCell(cell), fxTableItem);
+ loadRequest.moveToNextCell();
+ }
+
+ qCDebug(lcTableViewDelegateLifecycle()) << "all items loaded!";
+
+ syncLoadedTableFromLoadRequest();
+ layoutTableEdgeFromLoadRequest();
+ syncLoadedTableRectFromLoadedTable();
+
+ 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;
+ }
+ drainReusePoolAfterLoadRequest();
+ }
+
+ loadRequest.markAsDone();
+
+ qCDebug(lcTableViewDelegateLifecycle()) << "request completed! Table:" << tableLayoutToString();
+}
+
+void QQuickTableViewPrivate::processRebuildTable()
+{
+ moveToNextRebuildState();
+
+ if (rebuildState == RebuildState::LoadInitalTable) {
+ beginRebuildTable();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::VerifyTable) {
+ if (loadedItems.isEmpty()) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "no items loaded, meaning empty model, all rows or columns hidden, or no delegate";
+ rebuildState = RebuildState::Done;
+ return;
+ }
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::LayoutTable) {
+ layoutAfterLoadingInitialTable();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::LoadAndUnloadAfterLayout) {
+ loadAndUnloadVisibleEdges();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ const bool preload = (rebuildOptions & RebuildOption::All
+ && reusableFlag == QQmlTableInstanceModel::Reusable);
+
+ if (rebuildState == RebuildState::PreloadColumns) {
+ if (preload && nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge) != kEdgeIndexAtEnd)
+ loadEdge(Qt::RightEdge, QQmlIncubator::AsynchronousIfNested);
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::PreloadRows) {
+ if (preload && nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge) != kEdgeIndexAtEnd)
+ loadEdge(Qt::BottomEdge, QQmlIncubator::AsynchronousIfNested);
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::MovePreloadedItemsToPool) {
+ while (Qt::Edge edge = nextEdgeToUnload(viewportRect))
+ unloadEdge(edge);
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ Q_TABLEVIEW_ASSERT(rebuildState == RebuildState::Done, int(rebuildState));
+}
+
+bool QQuickTableViewPrivate::moveToNextRebuildState()
+{
+ if (loadRequest.isActive()) {
+ // Items are still loading async, which means
+ // 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);
+
+ return QPoint(firstVisibleLeft, firstVisibleTop);
+}
+
+void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeft, QPointF &topLeftPos)
+{
+ if (tableSize.isEmpty()) {
+ releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
+ topLeft = QPoint(kEdgeIndexAtEnd, 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 (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 (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
+ 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());
+ } else {
+ topLeft.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
+ topLeftPos.rx() = loadedTableOuterRect.topLeft().x();
+ }
+ } else {
+ Q_TABLEVIEW_UNREACHABLE(rebuildOptions);
+ }
+}
+
+void QQuickTableViewPrivate::beginRebuildTable()
+{
+ calculateTableSize();
+
+ QPoint topLeft;
+ QPointF topLeftPos;
+ calculateTopLeft(topLeft, topLeftPos);
+
+ 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
+ return;
+ }
+
+ loadInitialTopLeftItem(topLeft, topLeftPos);
+ loadAndUnloadVisibleEdges();
+}
+
+void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
+{
+ if (rowHeightProvider.isUndefined() || columnWidthProvider.isUndefined()) {
+ // Since we don't have both size providers, we need to calculate the
+ // size of each row and column based on the size of the delegate items.
+ // This couldn't be done while we were loading the initial rows and
+ // columns, since during the process, we didn't have all the items
+ // available yet for the calculation. So we do it now.
+ relayoutTable();
+ }
+
+ updateAverageEdgeSize();
+ updateContentWidth();
+ updateContentHeight();
+}
+
+void QQuickTableViewPrivate::loadInitialTopLeftItem(const QPoint &cell, const QPointF &pos)
+{
+ Q_TABLEVIEW_ASSERT(loadedItems.isEmpty(), "");
+
+ if (tableModel && !tableModel->delegate())
+ 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);
+ processLoadRequest();
+}
+
+void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
+{
+ qCDebug(lcTableViewDelegateLifecycle) << edge;
+
+ switch (edge) {
+ case Qt::LeftEdge:
+ case Qt::RightEdge: {
+ const int column = edge == Qt::LeftEdge ? leftColumn() : rightColumn();
+ for (auto r = loadedRows.cbegin(); r != loadedRows.cend(); ++r)
+ unloadItem(QPoint(column, r.key()));
+ loadedColumns.remove(column);
+ syncLoadedTableRectFromLoadedTable();
+ updateAverageEdgeSize();
+ updateContentWidth();
+ break; }
+ case Qt::TopEdge:
+ case Qt::BottomEdge: {
+ const int row = edge == Qt::TopEdge ? topRow() : bottomRow();
+ for (auto c = loadedColumns.cbegin(); c != loadedColumns.cend(); ++c)
+ unloadItem(QPoint(c.key(), row));
+ loadedRows.remove(row);
+ syncLoadedTableRectFromLoadedTable();
+ updateAverageEdgeSize();
+ updateContentHeight();
+ break; }
+ }
+
+ qCDebug(lcTableViewDelegateLifecycle) << tableLayoutToString();
+}
+
+void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
+{
+ const int edgeIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
+ qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex;
+
+ const QList<int> visibleCells = edge & (Qt::LeftEdge | Qt::RightEdge)
+ ? loadedRows.keys() : loadedColumns.keys();
+ loadRequest.begin(edge, edgeIndex, visibleCells, incubationMode);
+ processLoadRequest();
+}
+
+void QQuickTableViewPrivate::loadAndUnloadVisibleEdges()
+{
+ // Unload table edges that have been moved outside the visible part of the
+ // table (including buffer area), and load new edges that has been moved inside.
+ // Note: an important point is that we always keep the table rectangular
+ // and without holes to reduce complexity (we never leave the table in
+ // a half-loaded state, or keep track of multiple patches).
+ // We load only one edge (row or column) at a time. This is especially
+ // important when loading into the buffer, since we need to be able to
+ // cancel the buffering quickly if the user starts to flick, and then
+ // focus all further loading on the edges that are flicked into view.
+
+ if (loadRequest.isActive()) {
+ // Don't start loading more edges while we're
+ // already waiting for another one to load.
+ return;
+ }
+
+ if (loadedItems.isEmpty()) {
+ // We need at least the top-left item to be loaded before we can
+ // start loading edges around it. Not having a top-left item at
+ // this point means that the model is empty (or no delegate).
+ return;
+ }
+
+ bool tableModified;
+
+ do {
+ tableModified = false;
+
+ if (Qt::Edge edge = nextEdgeToUnload(viewportRect)) {
+ tableModified = true;
+ unloadEdge(edge);
+ }
+
+ if (Qt::Edge edge = nextEdgeToLoad(viewportRect)) {
+ tableModified = true;
+ loadEdge(edge, QQmlIncubator::AsynchronousIfNested);
+ if (loadRequest.isActive())
+ return;
+ }
+ } while (tableModified);
+
+}
+
+void QQuickTableViewPrivate::drainReusePoolAfterLoadRequest()
+{
+ Q_Q(QQuickTableView);
+
+ if (reusableFlag == QQmlTableInstanceModel::NotReusable || !tableModel)
+ return;
+
+ if (!qFuzzyIsNull(q->verticalOvershoot()) || !qFuzzyIsNull(q->horizontalOvershoot())) {
+ // Don't drain while we're overshooting, since this will fill up the
+ // pool, but we expect to reuse them all once the content item moves back.
+ return;
+ }
+
+ // When loading edges, we don't want to drain the reuse pool too aggressively. Normally,
+ // all the items in the pool are reused rapidly as the content view is flicked around
+ // anyway. Even if the table is temporarily flicked to a section that contains fewer
+ // cells than what used to be (e.g if the flicked-in rows are taller than average), it
+ // still makes sense to keep all the items in circulation; Chances are, that soon enough,
+ // thinner rows are flicked back in again (meaning that we can fit more items into the
+ // view). But at the same time, if a delegate chooser is in use, the pool might contain
+ // items created from different delegates. And some of those delegates might be used only
+ // occasionally. So to avoid situations where an item ends up in the pool for too long, we
+ // call drain after each load request, but with a sufficiently large pool time. (If an item
+ // in the pool has a large pool time, it means that it hasn't been reused for an equal
+ // amount of load cycles, and should be released).
+ //
+ // We calculate an appropriate pool time by figuring out what the minimum time must be to
+ // not disturb frequently reused items. Since the number of items in a row might be higher
+ // than in a column (or vice versa), the minimum pool time should take into account that
+ // you might be flicking out a single row (filling up the pool), before you continue
+ // flicking in several new columns (taking them out again, but now in smaller chunks). This
+ // will increase the number of load cycles items are kept in the pool (poolTime), but still,
+ // we shouldn't release them, as they are still being reused frequently.
+ // To get a flexible maxValue (that e.g tolerates rows and columns being flicked
+ // in with varying sizes, causing some items not to be resued immediately), we multiply the
+ // value by 2. Note that we also add an extra +1 to the column count, because the number of
+ // visible columns will fluctuate between +1/-1 while flicking.
+ const int w = loadedColumns.count();
+ const int h = loadedRows.count();
+ const int minTime = int(std::ceil(w > h ? qreal(w + 1) / h : qreal(h + 1) / w));
+ const int maxTime = minTime * 2;
+ tableModel->drainReusableItemsPool(maxTime);
+}
+
+void QQuickTableViewPrivate::scheduleRebuildTable(RebuildOptions options) {
+ if (!q_func()->isComponentComplete()) {
+ // We'll rebuild the table once complete anyway
+ return;
+ }
+
+ rebuildScheduled = true;
+ scheduledRebuildOptions |= options;
+ q_func()->polish();
+}
+
+void QQuickTableViewPrivate::invalidateColumnRowPositions() {
+ columnRowPositionsInvalid = true;
+ q_func()->polish();
+}
+
+void QQuickTableViewPrivate::updatePolish()
+{
+ // 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.
+
+ Q_TABLEVIEW_ASSERT(!polishing, "recursive updatePolish() calls are not allowed!");
+ QBoolBlocker polishGuard(polishing, true);
+
+ if (loadRequest.isActive()) {
+ // We're currently loading items async to build a new edge in the table. We see the loading
+ // 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;
+ }
+
+ if (rebuildState != RebuildState::Done) {
+ processRebuildTable();
+ return;
+ }
+
+ syncWithPendingChanges();
+
+ if (rebuildState == RebuildState::Begin) {
+ processRebuildTable();
+ return;
+ }
+
+ if (loadedItems.isEmpty())
+ return;
+
+ if (columnRowPositionsInvalid) {
+ relayoutTable();
+ updateAverageEdgeSize();
+ updateContentWidth();
+ updateContentHeight();
+ }
+
+ loadAndUnloadVisibleEdges();
+}
+
+void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent)
+{
+ if (rebuildScheduled || rebuildState != RebuildState::Done)
+ return;
+
+ QQuickFlickablePrivate::fixup(data, minExtent, maxExtent);
+}
+
+int QQuickTableViewPrivate::resolveImportVersion()
+{
+ const auto data = QQmlData::get(q_func());
+ if (!data || !data->propertyCache)
+ return 0;
+
+ const auto cppMetaObject = data->propertyCache->firstCppMetaObject();
+ const auto qmlTypeView = QQmlMetaType::qmlType(cppMetaObject);
+ return qmlTypeView.minorVersion();
+}
+
+void QQuickTableViewPrivate::createWrapperModel()
+{
+ Q_Q(QQuickTableView);
+ // When the assigned model is not an instance model, we create a wrapper
+ // model (QQmlTableInstanceModel) that keeps a pointer to both the
+ // assigned model and the assigned delegate. This model will give us a
+ // common interface to any kind of model (js arrays, QAIM, number etc), and
+ // help us create delegate instances.
+ tableModel = new QQmlTableInstanceModel(qmlContext(q));
+ tableModel->useImportVersion(resolveImportVersion());
+ model = tableModel;
+}
+
+void QQuickTableViewPrivate::itemCreatedCallback(int modelIndex, QObject*)
+{
+ if (blockItemCreatedCallback)
+ return;
+
+ qCDebug(lcTableViewDelegateLifecycle) << "item done loading:"
+ << cellAtModelIndex(modelIndex);
+
+ // Since the item we waited for has finished incubating, we can
+ // continue with the load request. processLoadRequest will
+ // ask the model for the requested item once more, which will be
+ // quick since the model has cached it.
+ processLoadRequest();
+ loadAndUnloadVisibleEdges();
+ updatePolish();
+}
+
+void QQuickTableViewPrivate::initItemCallback(int modelIndex, QObject *object)
+{
+ Q_UNUSED(modelIndex);
+ Q_Q(QQuickTableView);
+
+ if (auto item = qmlobject_cast<QQuickItem*>(object)) {
+ item->setParentItem(q->contentItem());
+ item->setZ(1);
+ }
+
+ if (auto attached = getAttachedObject(object))
+ attached->setView(q);
+}
+
+void QQuickTableViewPrivate::itemPooledCallback(int modelIndex, QObject *object)
+{
+ Q_UNUSED(modelIndex);
+
+ if (auto attached = getAttachedObject(object))
+ emit attached->pooled();
+}
+
+void QQuickTableViewPrivate::itemReusedCallback(int modelIndex, QObject *object)
+{
+ Q_UNUSED(modelIndex);
+
+ if (auto attached = getAttachedObject(object))
+ emit attached->reused();
+}
+
+void QQuickTableViewPrivate::syncWithPendingChanges()
+{
+ // The application can change properties like the model or the delegate while
+ // we're e.g in the middle of e.g loading a new row. Since this will lead to
+ // unpredicted behavior, and possibly a crash, we need to postpone taking
+ // 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();
+}
+
+void QQuickTableViewPrivate::syncRebuildOptions()
+{
+ if (!rebuildScheduled)
+ 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.
+ rebuildOptions.setFlag(RebuildOption::All);
+ }
+}
+
+void QQuickTableViewPrivate::syncDelegate()
+{
+ if (tableModel && assignedDelegate == tableModel->delegate())
+ return;
+
+ if (!tableModel)
+ createWrapperModel();
+
+ tableModel->setDelegate(assignedDelegate);
+}
+
+void QQuickTableViewPrivate::syncModel()
+{
+ if (modelVariant == assignedModel)
+ return;
+
+ if (model)
+ disconnectFromModel();
+
+ modelVariant = assignedModel;
+ QVariant effectiveModelVariant = modelVariant;
+ if (effectiveModelVariant.userType() == qMetaTypeId<QJSValue>())
+ effectiveModelVariant = effectiveModelVariant.value<QJSValue>().toVariant();
+
+ const auto instanceModel = qobject_cast<QQmlInstanceModel *>(qvariant_cast<QObject*>(effectiveModelVariant));
+
+ if (instanceModel) {
+ if (tableModel) {
+ delete tableModel;
+ tableModel = nullptr;
+ }
+ model = instanceModel;
+ } else {
+ if (!tableModel)
+ createWrapperModel();
+ tableModel->setModel(effectiveModelVariant);
+ }
+
+ connectToModel();
+}
+
+void QQuickTableViewPrivate::connectToModel()
+{
+ Q_TABLEVIEW_ASSERT(model, "");
+
+ QObjectPrivate::connect(model, &QQmlInstanceModel::createdItem, this, &QQuickTableViewPrivate::itemCreatedCallback);
+ QObjectPrivate::connect(model, &QQmlInstanceModel::initItem, this, &QQuickTableViewPrivate::initItemCallback);
+
+ if (tableModel) {
+ const auto tm = tableModel.data();
+ QObjectPrivate::connect(tm, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback);
+ QObjectPrivate::connect(tm, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback);
+ }
+
+ if (auto const aim = model->abstractItemModel()) {
+ // When the model exposes a QAIM, we connect to it directly. This means that if the current model is
+ // a QQmlDelegateModel, we just ignore all the change sets it emits. In most cases, the model will instead
+ // be our own QQmlTableInstanceModel, which doesn't bother creating change sets at all. For models that are
+ // not based on QAIM (like QQmlObjectModel, QQmlListModel, javascript arrays etc), there is currently no way
+ // to modify the model at runtime without also re-setting the model on the view.
+ connect(aim, &QAbstractItemModel::rowsMoved, this, &QQuickTableViewPrivate::rowsMovedCallback);
+ connect(aim, &QAbstractItemModel::columnsMoved, this, &QQuickTableViewPrivate::columnsMovedCallback);
+ connect(aim, &QAbstractItemModel::rowsInserted, this, &QQuickTableViewPrivate::rowsInsertedCallback);
+ connect(aim, &QAbstractItemModel::rowsRemoved, this, &QQuickTableViewPrivate::rowsRemovedCallback);
+ connect(aim, &QAbstractItemModel::columnsInserted, this, &QQuickTableViewPrivate::columnsInsertedCallback);
+ connect(aim, &QAbstractItemModel::columnsRemoved, this, &QQuickTableViewPrivate::columnsRemovedCallback);
+ connect(aim, &QAbstractItemModel::modelReset, this, &QQuickTableViewPrivate::modelResetCallback);
+ connect(aim, &QAbstractItemModel::layoutChanged, this, &QQuickTableViewPrivate::layoutChangedCallback);
+ } else {
+ QObjectPrivate::connect(model, &QQmlInstanceModel::modelUpdated, this, &QQuickTableViewPrivate::modelUpdated);
+ }
+}
+
+void QQuickTableViewPrivate::disconnectFromModel()
+{
+ Q_TABLEVIEW_ASSERT(model, "");
+
+ QObjectPrivate::disconnect(model, &QQmlInstanceModel::createdItem, this, &QQuickTableViewPrivate::itemCreatedCallback);
+ QObjectPrivate::disconnect(model, &QQmlInstanceModel::initItem, this, &QQuickTableViewPrivate::initItemCallback);
+
+ if (tableModel) {
+ const auto tm = tableModel.data();
+ QObjectPrivate::disconnect(tm, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback);
+ QObjectPrivate::disconnect(tm, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback);
+ }
+
+ if (auto const aim = model->abstractItemModel()) {
+ disconnect(aim, &QAbstractItemModel::rowsMoved, this, &QQuickTableViewPrivate::rowsMovedCallback);
+ disconnect(aim, &QAbstractItemModel::columnsMoved, this, &QQuickTableViewPrivate::columnsMovedCallback);
+ disconnect(aim, &QAbstractItemModel::rowsInserted, this, &QQuickTableViewPrivate::rowsInsertedCallback);
+ disconnect(aim, &QAbstractItemModel::rowsRemoved, this, &QQuickTableViewPrivate::rowsRemovedCallback);
+ disconnect(aim, &QAbstractItemModel::columnsInserted, this, &QQuickTableViewPrivate::columnsInsertedCallback);
+ disconnect(aim, &QAbstractItemModel::columnsRemoved, this, &QQuickTableViewPrivate::columnsRemovedCallback);
+ disconnect(aim, &QAbstractItemModel::modelReset, this, &QQuickTableViewPrivate::modelResetCallback);
+ disconnect(aim, &QAbstractItemModel::layoutChanged, this, &QQuickTableViewPrivate::layoutChangedCallback);
+ } else {
+ QObjectPrivate::disconnect(model, &QQmlInstanceModel::modelUpdated, this, &QQuickTableViewPrivate::modelUpdated);
+ }
+}
+
+void QQuickTableViewPrivate::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
+{
+ Q_UNUSED(changeSet);
+ Q_UNUSED(reset);
+
+ Q_TABLEVIEW_ASSERT(!model->abstractItemModel(), "");
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+}
+
+void QQuickTableViewPrivate::rowsMovedCallback(const QModelIndex &parent, int, int, const QModelIndex &, int )
+{
+ if (parent != QModelIndex())
+ return;
+
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+}
+
+void QQuickTableViewPrivate::columnsMovedCallback(const QModelIndex &parent, int, int, const QModelIndex &, int)
+{
+ if (parent != QModelIndex())
+ return;
+
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+}
+
+void QQuickTableViewPrivate::rowsInsertedCallback(const QModelIndex &parent, int, int)
+{
+ if (parent != QModelIndex())
+ return;
+
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+}
+
+void QQuickTableViewPrivate::rowsRemovedCallback(const QModelIndex &parent, int, int)
+{
+ if (parent != QModelIndex())
+ return;
+
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+}
+
+void QQuickTableViewPrivate::columnsInsertedCallback(const QModelIndex &parent, int, int)
+{
+ if (parent != QModelIndex())
+ return;
+
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+}
+
+void QQuickTableViewPrivate::columnsRemovedCallback(const QModelIndex &parent, int, int)
+{
+ if (parent != QModelIndex())
+ return;
+
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+}
+
+void QQuickTableViewPrivate::layoutChangedCallback(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
+{
+ Q_UNUSED(parents);
+ Q_UNUSED(hint);
+
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+}
+
+void QQuickTableViewPrivate::modelResetCallback()
+{
+ scheduleRebuildTable(RebuildOption::All);
+}
+
+QQuickTableView::QQuickTableView(QQuickItem *parent)
+ : QQuickFlickable(*(new QQuickTableViewPrivate), parent)
+{
+ setFlag(QQuickItem::ItemIsFocusScope);
+}
+
+QQuickTableView::~QQuickTableView()
+{
+}
+
+QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent)
+ : QQuickFlickable(dd, parent)
+{
+ setFlag(QQuickItem::ItemIsFocusScope);
+}
+
+int QQuickTableView::rows() const
+{
+ return d_func()->tableSize.height();
+}
+
+int QQuickTableView::columns() const
+{
+ return d_func()->tableSize.width();
+}
+
+qreal QQuickTableView::rowSpacing() const
+{
+ return d_func()->cellSpacing.height();
+}
+
+void QQuickTableView::setRowSpacing(qreal spacing)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(spacing) || !qt_is_finite(spacing) || spacing < 0)
+ return;
+ if (qFuzzyCompare(d->cellSpacing.height(), spacing))
+ return;
+
+ d->cellSpacing.setHeight(spacing);
+ d->invalidateColumnRowPositions();
+ emit rowSpacingChanged();
+}
+
+qreal QQuickTableView::columnSpacing() const
+{
+ return d_func()->cellSpacing.width();
+}
+
+void QQuickTableView::setColumnSpacing(qreal spacing)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(spacing) || !qt_is_finite(spacing) || spacing < 0)
+ return;
+ if (qFuzzyCompare(d->cellSpacing.width(), spacing))
+ return;
+
+ d->cellSpacing.setWidth(spacing);
+ d->invalidateColumnRowPositions();
+ emit columnSpacingChanged();
+}
+
+QJSValue QQuickTableView::rowHeightProvider() const
+{
+ return d_func()->rowHeightProvider;
+}
+
+void QQuickTableView::setRowHeightProvider(QJSValue provider)
+{
+ Q_D(QQuickTableView);
+ if (provider.strictlyEquals(d->rowHeightProvider))
+ return;
+
+ d->rowHeightProvider = provider;
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
+ emit rowHeightProviderChanged();
+}
+
+QJSValue QQuickTableView::columnWidthProvider() const
+{
+ return d_func()->columnWidthProvider;
+}
+
+void QQuickTableView::setColumnWidthProvider(QJSValue provider)
+{
+ Q_D(QQuickTableView);
+ if (provider.strictlyEquals(d->columnWidthProvider))
+ return;
+
+ d->columnWidthProvider = provider;
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
+ emit columnWidthProviderChanged();
+}
+
+QVariant QQuickTableView::model() const
+{
+ return d_func()->assignedModel;
+}
+
+void QQuickTableView::setModel(const QVariant &newModel)
+{
+ Q_D(QQuickTableView);
+ if (newModel == d->assignedModel)
+ return;
+
+ d->assignedModel = newModel;
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
+ emit modelChanged();
+}
+
+QQmlComponent *QQuickTableView::delegate() const
+{
+ return d_func()->assignedDelegate;
+}
+
+void QQuickTableView::setDelegate(QQmlComponent *newDelegate)
+{
+ Q_D(QQuickTableView);
+ if (newDelegate == d->assignedDelegate)
+ return;
+
+ d->assignedDelegate = newDelegate;
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
+
+ emit delegateChanged();
+}
+
+bool QQuickTableView::reuseItems() const
+{
+ return bool(d_func()->reusableFlag == QQmlTableInstanceModel::Reusable);
+}
+
+void QQuickTableView::setReuseItems(bool reuse)
+{
+ Q_D(QQuickTableView);
+ if (reuseItems() == reuse)
+ return;
+
+ d->reusableFlag = reuse ? QQmlTableInstanceModel::Reusable : QQmlTableInstanceModel::NotReusable;
+
+ if (!reuse && d->tableModel) {
+ // When we're told to not reuse items, we
+ // immediately, as documented, drain the pool.
+ d->tableModel->drainReusableItemsPool(0);
+ }
+
+ emit reuseItemsChanged();
+}
+
+void QQuickTableView::setContentWidth(qreal width)
+{
+ Q_D(QQuickTableView);
+ d->explicitContentWidth = width;
+ QQuickFlickable::setContentWidth(width);
+}
+
+void QQuickTableView::setContentHeight(qreal height)
+{
+ Q_D(QQuickTableView);
+ d->explicitContentHeight = height;
+ QQuickFlickable::setContentHeight(height);
+}
+
+void QQuickTableView::forceLayout()
+{
+ d_func()->forceLayout();
+}
+
+QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
+{
+ return new QQuickTableViewAttached(obj);
+}
+
+void QQuickTableView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickTableView);
+ QQuickFlickable::geometryChanged(newGeometry, oldGeometry);
+
+ if (d->tableModel) {
+ // When the view changes size, we force the pool to
+ // shrink by releasing all pooled items.
+ d->tableModel->drainReusableItemsPool(0);
+ }
+
+ polish();
+}
+
+void QQuickTableView::viewportMoved(Qt::Orientations orientation)
+{
+ Q_D(QQuickTableView);
+ QQuickFlickable::viewportMoved(orientation);
+
+ QQuickTableViewPrivate::RebuildOptions options = QQuickTableViewPrivate::RebuildOption::None;
+
+ // 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;
+ }
+
+ // 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();
+}
+
+void QQuickTableViewPrivate::_q_componentFinalized()
+{
+ // Now that all bindings are evaluated, and we know
+ // our final geometery, we can build the table.
+ qCDebug(lcTableViewDelegateLifecycle);
+ updatePolish();
+}
+
+void QQuickTableViewPrivate::registerCallbackWhenBindingsAreEvaluated()
+{
+ // componentComplete() is called on us after all static values have been assigned, but
+ // before bindings to any anchestors has been evaluated. Especially this means that
+ // if our size is bound to the parents size, it will still be empty at that point.
+ // And we cannot build the table without knowing our own size. We could wait until we
+ // got the first updatePolish() callback, but at that time, any asynchronous loaders that we
+ // might be inside have already finished loading, which means that we would load all
+ // the delegate items synchronously instead of asynchronously. We therefore add a componentFinalized
+ // function that gets called after all the bindings we rely on has been evaluated.
+ // When receiving this call, we load the delegate items (and build the table).
+ Q_Q(QQuickTableView);
+ QQmlEnginePrivate *engPriv = QQmlEnginePrivate::get(qmlEngine(q));
+ static int finalizedIdx = -1;
+ if (finalizedIdx < 0)
+ finalizedIdx = q->metaObject()->indexOfSlot("_q_componentFinalized()");
+ engPriv->registerFinalizeCallback(q, finalizedIdx);
+}
+
+void QQuickTableView::componentComplete()
+{
+ QQuickFlickable::componentComplete();
+ d_func()->registerCallbackWhenBindingsAreEvaluated();
+}
+
+#include "moc_qquicktableview_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
new file mode 100644
index 0000000000..f32c71b983
--- /dev/null
+++ b/src/quick/items/qquicktableview_p.h
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTABLEVIEW_P_H
+#define QQUICKTABLEVIEW_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtquickglobal_p.h>
+QT_REQUIRE_CONFIG(quick_tableview);
+
+#include <QtCore/qpointer.h>
+#include <QtQuick/private/qtquickglobal_p.h>
+#include <QtQuick/private/qquickflickable_p.h>
+#include <QtQml/private/qqmlnullablevalue_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTableViewAttached;
+class QQuickTableViewPrivate;
+
+class Q_QUICK_PRIVATE_EXPORT QQuickTableView : public QQuickFlickable
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int rows READ rows NOTIFY rowsChanged)
+ Q_PROPERTY(int columns READ columns NOTIFY columnsChanged)
+ Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged)
+ Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged)
+ Q_PROPERTY(QJSValue rowHeightProvider READ rowHeightProvider WRITE setRowHeightProvider NOTIFY rowHeightProviderChanged)
+ Q_PROPERTY(QJSValue columnWidthProvider READ columnWidthProvider WRITE setColumnWidthProvider NOTIFY columnWidthProviderChanged)
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ 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)
+
+public:
+ QQuickTableView(QQuickItem *parent = nullptr);
+ ~QQuickTableView() override;
+ int rows() const;
+ int columns() const;
+
+ qreal rowSpacing() const;
+ void setRowSpacing(qreal spacing);
+
+ qreal columnSpacing() const;
+ void setColumnSpacing(qreal spacing);
+
+ QJSValue rowHeightProvider() const;
+ void setRowHeightProvider(QJSValue provider);
+
+ QJSValue columnWidthProvider() const;
+ void setColumnWidthProvider(QJSValue provider);
+
+ virtual QVariant model() const;
+ virtual void setModel(const QVariant &newModel);
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *);
+
+ bool reuseItems() const;
+ void setReuseItems(bool reuseItems);
+
+ void setContentWidth(qreal width);
+ void setContentHeight(qreal height);
+
+ Q_INVOKABLE void forceLayout();
+
+ static QQuickTableViewAttached *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void rowsChanged();
+ void columnsChanged();
+ void rowSpacingChanged();
+ void columnSpacingChanged();
+ void rowHeightProviderChanged();
+ void columnWidthProviderChanged();
+ void modelChanged();
+ void delegateChanged();
+ void reuseItemsChanged();
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void viewportMoved(Qt::Orientations orientation) override;
+ void componentComplete() override;
+
+protected:
+ QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent);
+
+private:
+ Q_DISABLE_COPY(QQuickTableView)
+ Q_DECLARE_PRIVATE(QQuickTableView)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_componentFinalized())
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickTableViewAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickTableView *view READ view NOTIFY viewChanged)
+
+public:
+ QQuickTableViewAttached(QObject *parent)
+ : QObject(parent) {}
+
+ QQuickTableView *view() const { return m_view; }
+ void setView(QQuickTableView *newTableView) {
+ if (newTableView == m_view)
+ return;
+ m_view = newTableView;
+ Q_EMIT viewChanged();
+ }
+
+Q_SIGNALS:
+ void viewChanged();
+ void pooled();
+ void reused();
+
+private:
+ QPointer<QQuickTableView> m_view;
+
+ friend class QQuickTableViewPrivate;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickTableView)
+QML_DECLARE_TYPEINFO(QQuickTableView, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKTABLEVIEW_P_H
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
new file mode 100644
index 0000000000..f2fef0d774
--- /dev/null
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -0,0 +1,414 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTABLEVIEW_P_P_H
+#define QQUICKTABLEVIEW_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquicktableview_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtQml/private/qqmltableinstancemodel_p.h>
+#include <QtQml/private/qqmlincubator_p.h>
+#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQml/qqmlinfo.h>
+
+#include <QtQuick/private/qquickflickable_p_p.h>
+#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcTableViewDelegateLifecycle)
+
+static const qreal kDefaultRowHeight = 50;
+static const qreal kDefaultColumnWidth = 50;
+
+class FxTableItem;
+
+class Q_QML_AUTOTEST_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickTableView)
+
+public:
+ class TableEdgeLoadRequest
+ {
+ // Whenever we need to load new rows or columns in the
+ // table, we fill out a TableEdgeLoadRequest.
+ // TableEdgeLoadRequest is just a struct that keeps track
+ // of which cells that needs to be loaded, and which cell
+ // the table is currently loading. The loading itself is
+ // done by QQuickTableView.
+
+ public:
+ void begin(const QPoint &cell, const QPointF &pos, QQmlIncubator::IncubationMode incubationMode)
+ {
+ Q_ASSERT(!m_active);
+ m_active = true;
+ m_edge = Qt::Edge(0);
+ m_mode = incubationMode;
+ m_edgeIndex = cell.x();
+ m_visibleCellsInEdge.clear();
+ m_visibleCellsInEdge.append(cell.y());
+ m_currentIndex = 0;
+ m_startPos = pos;
+ qCDebug(lcTableViewDelegateLifecycle()) << "begin top-left:" << toString();
+ }
+
+ void begin(Qt::Edge edgeToLoad, int edgeIndex, const QList<int> visibleCellsInEdge, QQmlIncubator::IncubationMode incubationMode)
+ {
+ Q_ASSERT(!m_active);
+ m_active = true;
+ m_edge = edgeToLoad;
+ m_edgeIndex = edgeIndex;
+ m_visibleCellsInEdge = visibleCellsInEdge;
+ m_mode = incubationMode;
+ m_currentIndex = 0;
+ qCDebug(lcTableViewDelegateLifecycle()) << "begin:" << toString();
+ }
+
+ inline void markAsDone() { m_active = false; }
+ inline bool isActive() { return m_active; }
+
+ inline QPoint currentCell() { return cellAt(m_currentIndex); }
+ inline bool hasCurrentCell() { return m_currentIndex < m_visibleCellsInEdge.count(); }
+ inline void moveToNextCell() { ++m_currentIndex; }
+
+ inline Qt::Edge edge() { return m_edge; }
+ inline int row() { return cellAt(0).y(); }
+ inline int column() { return cellAt(0).x(); }
+ inline QQmlIncubator::IncubationMode incubationMode() { return m_mode; }
+
+ inline QPointF startPosition() { return m_startPos; }
+
+ QString toString()
+ {
+ QString str;
+ QDebug dbg(&str);
+ dbg.nospace() << "TableSectionLoadRequest(" << "edge:"
+ << m_edge << ", edgeIndex:" << m_edgeIndex << ", incubation:";
+
+ switch (m_mode) {
+ case QQmlIncubator::Asynchronous:
+ dbg << "Asynchronous";
+ break;
+ case QQmlIncubator::AsynchronousIfNested:
+ dbg << "AsynchronousIfNested";
+ break;
+ case QQmlIncubator::Synchronous:
+ dbg << "Synchronous";
+ break;
+ }
+
+ return str;
+ }
+
+ private:
+ Qt::Edge m_edge = Qt::Edge(0);
+ QList<int> m_visibleCellsInEdge;
+ int m_edgeIndex = 0;
+ int m_currentIndex = 0;
+ bool m_active = false;
+ QQmlIncubator::IncubationMode m_mode = QQmlIncubator::AsynchronousIfNested;
+ QPointF m_startPos;
+
+ inline QPoint cellAt(int index) {
+ return !m_edge || (m_edge & (Qt::LeftEdge | Qt::RightEdge))
+ ? QPoint(m_edgeIndex, m_visibleCellsInEdge[index])
+ : QPoint(m_visibleCellsInEdge[index], m_edgeIndex);
+ }
+ };
+
+ class EdgeRange {
+ public:
+ EdgeRange();
+ bool containsIndex(Qt::Edge edge, int index);
+
+ int startIndex;
+ int endIndex;
+ qreal size;
+ };
+
+ enum class RebuildState {
+ Begin = 0,
+ LoadInitalTable,
+ VerifyTable,
+ LayoutTable,
+ LoadAndUnloadAfterLayout,
+ PreloadColumns,
+ PreloadRows,
+ MovePreloadedItemsToPool,
+ Done
+ };
+
+ enum class RebuildOption {
+ None = 0,
+ ViewportOnly = 0x1,
+ CalculateNewTopLeftRow = 0x2,
+ CalculateNewTopLeftColumn = 0x4,
+ All = 0x8,
+ };
+ Q_DECLARE_FLAGS(RebuildOptions, RebuildOption)
+
+public:
+ QQuickTableViewPrivate();
+ ~QQuickTableViewPrivate() override;
+
+ static inline QQuickTableViewPrivate *get(QQuickTableView *q) { return q->d_func(); }
+
+ void updatePolish() override;
+ void fixup(AxisData &data, qreal minExtent, qreal maxExtent) override;
+
+public:
+ QHash<int, FxTableItem *> loadedItems;
+
+ // model, tableModel and modelVariant all point to the same model. modelVariant
+ // is the model assigned by the user. And tableModel is the wrapper model we create
+ // around it. But if the model is an instance model directly, we cannot wrap it, so
+ // we need a pointer for that case as well.
+ QQmlInstanceModel* model = nullptr;
+ QPointer<QQmlTableInstanceModel> tableModel = nullptr;
+ QVariant modelVariant;
+
+ // When the applications assignes a new model or delegate to the view, we keep them
+ // around until we're ready to take them into use (syncWithPendingChanges).
+ QVariant assignedModel = QVariant(int(0));
+ QQmlComponent *assignedDelegate = nullptr;
+
+ // loadedRows/Columns describes the rows and columns that are currently loaded (from top left
+ // row/column to bottom right row/column). loadedTableOuterRect describes the actual
+ // pixels that all the loaded delegate items cover, and is matched agains the viewport to determine when
+ // we need to fill up with more rows/columns. loadedTableInnerRect describes the pixels
+ // that the loaded table covers if you remove one row/column on each side of the table, and
+ // is used to determine rows/columns that are no longer visible and can be unloaded.
+ QMap<int, int> loadedColumns;
+ QMap<int, int> loadedRows;
+ QRectF loadedTableOuterRect;
+ QRectF loadedTableInnerRect;
+
+ QRectF viewportRect = QRectF(0, 0, -1, -1);
+
+ QSize tableSize;
+
+ RebuildState rebuildState = RebuildState::Done;
+ RebuildOptions rebuildOptions = RebuildOption::All;
+ RebuildOptions scheduledRebuildOptions = RebuildOption::All;
+
+ TableEdgeLoadRequest loadRequest;
+
+ QSizeF cellSpacing = QSizeF(0, 0);
+
+ QQmlTableInstanceModel::ReusableFlag reusableFlag = QQmlTableInstanceModel::Reusable;
+
+ bool blockItemCreatedCallback = false;
+ bool columnRowPositionsInvalid = false;
+ bool layoutWarningIssued = false;
+ bool polishing = false;
+ bool rebuildScheduled = true;
+
+ QJSValue rowHeightProvider;
+ QJSValue columnWidthProvider;
+
+ EdgeRange cachedNextVisibleEdgeIndex[4];
+ EdgeRange cachedColumnWidth;
+ EdgeRange cachedRowHeight;
+
+ // TableView uses contentWidth/height to report the size of the table (this
+ // will e.g make scrollbars written for Flickable work out of the box). This
+ // value is continuously calculated, and will change/improve as more columns
+ // are loaded into view. At the same time, we want to open up for the
+ // possibility that the application can set the content width explicitly, in
+ // case it knows what the exact width should be from the start. We therefore
+ // override the contentWidth/height properties from QQuickFlickable, to be able
+ // to implement this combined behavior. This also lets us lazy build the table
+ // if the application needs to know the content size early on.
+ QQmlNullableValue<qreal> explicitContentWidth;
+ QQmlNullableValue<qreal> explicitContentHeight;
+
+ QSizeF averageEdgeSize;
+
+ const static QPoint kLeft;
+ const static QPoint kRight;
+ const static QPoint kUp;
+ const static QPoint kDown;
+
+#ifdef QT_DEBUG
+ QString forcedIncubationMode = qEnvironmentVariable("QT_TABLEVIEW_INCUBATION_MODE");
+#endif
+
+public:
+ QQuickTableViewAttached *getAttachedObject(const QObject *object) const;
+
+ int modelIndexAtCell(const QPoint &cell) const;
+ QPoint cellAtModelIndex(int modelIndex) const;
+
+ qreal sizeHintForColumn(int column);
+ qreal sizeHintForRow(int row);
+ void calculateTableSize();
+
+ inline bool isColumnHidden(int column);
+ inline bool isRowHidden(int row);
+
+ qreal getColumnLayoutWidth(int column);
+ qreal getRowLayoutHeight(int row);
+ qreal getColumnWidth(int column);
+ qreal getRowHeight(int row);
+
+ inline int topRow() const { return loadedRows.firstKey(); }
+ inline int bottomRow() const { return loadedRows.lastKey(); }
+ inline int leftColumn() const { return loadedColumns.firstKey(); }
+ inline int rightColumn() const { return loadedColumns.lastKey(); }
+
+ void relayoutTable();
+ void relayoutTableItems();
+
+ void layoutVerticalEdge(Qt::Edge tableEdge);
+ void layoutHorizontalEdge(Qt::Edge tableEdge);
+ void layoutTopLeftItem();
+ void layoutTableEdgeFromLoadRequest();
+
+ void updateContentWidth();
+ void updateContentHeight();
+ void updateAverageEdgeSize();
+ void forceLayout();
+
+ void enforceTableAtOrigin();
+ void syncLoadedTableRectFromLoadedTable();
+ void syncLoadedTableFromLoadRequest();
+
+ int nextVisibleEdgeIndex(Qt::Edge edge, int startIndex);
+ int nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge);
+ inline int edgeToArrayIndex(Qt::Edge edge);
+ void clearEdgeSizeCache();
+
+ bool canLoadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const;
+ bool canUnloadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const;
+ Qt::Edge nextEdgeToLoad(const QRectF rect);
+ Qt::Edge nextEdgeToUnload(const QRectF rect);
+
+ qreal cellWidth(const QPoint &cell);
+ qreal cellHeight(const QPoint &cell);
+
+ FxTableItem *loadedTableItem(const QPoint &cell) const;
+ FxTableItem *createFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode);
+ FxTableItem *loadFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode);
+
+ void releaseItem(FxTableItem *fxTableItem, QQmlTableInstanceModel::ReusableFlag reusableFlag);
+ 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();
+ void drainReusePoolAfterLoadRequest();
+ void processLoadRequest();
+
+ 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();
+
+ void initItemCallback(int modelIndex, QObject *item);
+ void itemCreatedCallback(int modelIndex, QObject *object);
+ void itemPooledCallback(int modelIndex, QObject *object);
+ void itemReusedCallback(int modelIndex, QObject *object);
+ void modelUpdated(const QQmlChangeSet &changeSet, bool reset);
+
+ inline void syncWithPendingChanges();
+ inline void syncDelegate();
+ inline void syncModel();
+ inline void syncRebuildOptions();
+
+ void connectToModel();
+ void disconnectFromModel();
+
+ void rowsMovedCallback(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row);
+ void columnsMovedCallback(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column);
+ void rowsInsertedCallback(const QModelIndex &parent, int begin, int end);
+ void rowsRemovedCallback(const QModelIndex &parent, int begin, int end);
+ void columnsInsertedCallback(const QModelIndex &parent, int begin, int end);
+ void columnsRemovedCallback(const QModelIndex &parent, int begin, int end);
+ void layoutChangedCallback(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
+ void modelResetCallback();
+
+ void _q_componentFinalized();
+ void registerCallbackWhenBindingsAreEvaluated();
+
+ inline QString tableLayoutToString() const;
+ void dumpTable() const;
+};
+
+class FxTableItem : public QQuickItemViewFxItem
+{
+public:
+ FxTableItem(QQuickItem *item, QQuickTableView *table, bool own)
+ : QQuickItemViewFxItem(item, own, QQuickTableViewPrivate::get(table))
+ {
+ }
+
+ qreal position() const override { return 0; }
+ qreal endPosition() const override { return 0; }
+ qreal size() const override { return 0; }
+ qreal sectionSize() const override { return 0; }
+ bool contains(qreal, qreal) const override { return false; }
+
+ QPoint cell;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 080cc9412e..73b151168e 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -74,17 +74,13 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
const QChar QQuickTextPrivate::elideChar = QChar(0x2026);
QQuickTextPrivate::QQuickTextPrivate()
- : fontInfo(font), elideLayout(0), textLine(0), lineWidth(0)
+ : fontInfo(font), elideLayout(nullptr), textLine(nullptr), lineWidth(0)
, color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000)
, lineCount(1), multilengthEos(-1)
, elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop)
, format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap)
, style(QQuickText::Normal)
-#if defined(QT_QUICK_DEFAULT_TEXT_RENDER_TYPE)
- , renderType(QQuickText::QT_QUICK_DEFAULT_TEXT_RENDER_TYPE)
-#else
- , renderType(QQuickText::QtRendering)
-#endif
+ , renderType(QQuickTextUtil::textRenderType<QQuickText>())
, updateType(UpdatePaintNode)
, maximumLineCountValid(false), updateOnComponentComplete(true), richText(false)
, styledText(false), widthExceeded(false), heightExceeded(false), internalWidthUpdate(false)
@@ -92,6 +88,7 @@ QQuickTextPrivate::QQuickTextPrivate()
, truncated(false), hAlignImplicit(true), rightToLeftText(false)
, layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false), formatModifiesFontSize(false)
, polishSize(false)
+ , updateSizeRecursionGuard(false)
{
implicitAntialiasing = true;
}
@@ -107,7 +104,7 @@ QQuickTextPrivate::ExtraData::ExtraData()
, explicitRightPadding(false)
, explicitBottomPadding(false)
, lineHeight(1.0)
- , doc(0)
+ , doc(nullptr)
, minimumPixelSize(12)
, minimumPointSize(12)
, nbActiveDownloads(0)
@@ -128,7 +125,7 @@ void QQuickTextPrivate::init()
QQuickTextPrivate::~QQuickTextPrivate()
{
delete elideLayout;
- delete textLine; textLine = 0;
+ delete textLine; textLine = nullptr;
if (extra.isAllocated()) {
qDeleteAll(extra->imgTags);
@@ -269,9 +266,6 @@ void QQuickTextPrivate::updateLayout()
formatModifiesFontSize = fontSizeModified;
multilengthEos = -1;
} else {
- layout.clearFormats();
- if (elideLayout)
- elideLayout->clearFormats();
QString tmp = text;
multilengthEos = tmp.indexOf(QLatin1Char('\x9c'));
if (multilengthEos != -1)
@@ -349,6 +343,19 @@ void QQuickTextPrivate::updateBaseline(qreal baseline, qreal dy)
q->setBaselineOffset(baseline + yoff + q->topPadding());
}
+void QQuickTextPrivate::signalSizeChange(const QSizeF &previousSize)
+{
+ Q_Q(QQuickText);
+
+ if (layedOutTextRect.size() != previousSize) {
+ emit q->contentSizeChanged();
+ if (layedOutTextRect.width() != previousSize.width())
+ emit q->contentWidthChanged(layedOutTextRect.width());
+ if (layedOutTextRect.height() != previousSize.height())
+ emit q->contentHeightChanged(layedOutTextRect.height());
+ }
+}
+
void QQuickTextPrivate::updateSize()
{
Q_Q(QQuickText);
@@ -369,6 +376,8 @@ void QQuickTextPrivate::updateSize()
qreal hPadding = q->leftPadding() + q->rightPadding();
qreal vPadding = q->topPadding() + q->bottomPadding();
+ const QSizeF previousSize = layedOutTextRect.size();
+
if (text.isEmpty() && !isLineLaidOutConnected() && fontSizeMode() == QQuickText::FixedSize) {
// How much more expensive is it to just do a full layout on an empty string here?
// There may be subtle differences in the height and baseline calculations between
@@ -385,14 +394,13 @@ void QQuickTextPrivate::updateSize()
q->setImplicitSize(hPadding, fontHeight + vPadding);
layedOutTextRect = QRectF(0, 0, 0, fontHeight);
advance = QSizeF();
- emit q->contentSizeChanged();
+ signalSizeChange(previousSize);
updateType = UpdatePaintNode;
q->update();
return;
}
QSizeF size(0, 0);
- QSizeF previousSize = layedOutTextRect.size();
//setup instance of QTextLayout for all cases other than richtext
if (!richText) {
@@ -434,7 +442,7 @@ void QQuickTextPrivate::updateSize()
if (internalWidthUpdate)
return;
- extra->doc->setPageSize(QSizeF());
+ extra->doc->setPageSize(QSizeF(q->width(), -1));
if (q->widthValid() && (wrapMode != QQuickText::NoWrap || extra->doc->idealWidth() < availableWidth()))
extra->doc->setTextWidth(availableWidth());
else
@@ -449,6 +457,7 @@ void QQuickTextPrivate::updateSize()
//### need to confirm cost of always setting these for richText
internalWidthUpdate = true;
+ qreal oldWidth = q->width();
qreal iWidth = -1;
if (!q->widthValid())
iWidth = size.width();
@@ -456,36 +465,45 @@ void QQuickTextPrivate::updateSize()
q->setImplicitSize(iWidth + hPadding, size.height() + vPadding);
internalWidthUpdate = false;
- if (iWidth == -1)
- q->setImplicitHeight(size.height() + vPadding);
-
- QTextBlock firstBlock = extra->doc->firstBlock();
- while (firstBlock.layout()->lineCount() == 0)
- firstBlock = firstBlock.next();
-
- QTextBlock lastBlock = extra->doc->lastBlock();
- while (lastBlock.layout()->lineCount() == 0)
- lastBlock = lastBlock.previous();
-
- if (firstBlock.lineCount() > 0 && lastBlock.lineCount() > 0) {
- QTextLine firstLine = firstBlock.layout()->lineAt(0);
- QTextLine lastLine = lastBlock.layout()->lineAt(lastBlock.layout()->lineCount() - 1);
- advance = QSizeF(lastLine.horizontalAdvance(),
- (lastLine.y() + lastBlock.layout()->position().y()) - (firstLine.y() + firstBlock.layout()->position().y()));
+ // If the implicit width update caused a recursive change of the width,
+ // we will have skipped integral parts of the layout due to the
+ // internalWidthUpdate recursion guard. To make sure everything is up
+ // to date, we need to run a second pass over the layout when updateSize()
+ // is done.
+ if (!qFuzzyCompare(q->width(), oldWidth) && !updateSizeRecursionGuard) {
+ updateSizeRecursionGuard = true;
+ updateSize();
+ updateSizeRecursionGuard = false;
} else {
- advance = QSizeF();
+ if (iWidth == -1)
+ q->setImplicitHeight(size.height() + vPadding);
+
+ QTextBlock firstBlock = extra->doc->firstBlock();
+ while (firstBlock.layout()->lineCount() == 0)
+ firstBlock = firstBlock.next();
+
+ QTextBlock lastBlock = extra->doc->lastBlock();
+ while (lastBlock.layout()->lineCount() == 0)
+ lastBlock = lastBlock.previous();
+
+ if (firstBlock.lineCount() > 0 && lastBlock.lineCount() > 0) {
+ QTextLine firstLine = firstBlock.layout()->lineAt(0);
+ QTextLine lastLine = lastBlock.layout()->lineAt(lastBlock.layout()->lineCount() - 1);
+ advance = QSizeF(lastLine.horizontalAdvance(),
+ (lastLine.y() + lastBlock.layout()->position().y()) - (firstLine.y() + firstBlock.layout()->position().y()));
+ } else {
+ advance = QSizeF();
+ }
}
}
-
- if (layedOutTextRect.size() != previousSize)
- emit q->contentSizeChanged();
+ signalSizeChange(previousSize);
updateType = UpdatePaintNode;
q->update();
}
QQuickTextLine::QQuickTextLine()
- : QObject(), m_line(0), m_height(0), m_lineOffset(0)
+ : QObject(), m_line(nullptr), m_height(0), m_lineOffset(0)
{
}
@@ -625,13 +643,20 @@ QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QT
// Appending the elide character may push the line over the maximum width
// in which case the elided text will need to be elided.
QFontMetricsF metrics(layout.font());
- if (metrics.width(elideChar) + line.naturalTextWidth() >= lineWidth)
+ if (metrics.horizontalAdvance(elideChar) + line.naturalTextWidth() >= lineWidth)
elideText = metrics.elidedText(elideText, Qt::TextElideMode(elideMode), lineWidth);
}
return elideText;
}
}
+void QQuickTextPrivate::clearFormats()
+{
+ layout.clearFormats();
+ if (elideLayout)
+ elideLayout->clearFormats();
+}
+
/*!
Lays out the QQuickTextPrivate::layout QTextLayout in the constraints of the QQuickText.
@@ -1055,12 +1080,15 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
if (eos != multilengthEos)
truncated = true;
+ assignedFont = QFontInfo(font).family();
+
if (elide) {
if (!elideLayout) {
elideLayout = new QTextLayout;
elideLayout->setCacheEnabled(true);
}
- if (styledText) {
+ QTextEngine *engine = layout.engine();
+ if (engine && engine->hasFormats()) {
QVector<QTextLayout::FormatRange> formats;
switch (elideMode) {
case QQuickText::ElideRight:
@@ -1107,7 +1135,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
layout.clearLayout();
} else {
delete elideLayout;
- elideLayout = 0;
+ elideLayout = nullptr;
}
QTextLine firstLine = visibleCount == 1 && elideLayout
@@ -1219,7 +1247,7 @@ void QQuickTextPrivate::ensureDoc()
if (!extra.isAllocated() || !extra->doc) {
Q_Q(QQuickText);
extra.value().doc = new QQuickTextDocumentWithImageResources(q);
- extra->doc->setPageSize(QSizeF(0, 0));
+ extra->doc->setPageSize(QSizeF(q->width(), -1));
extra->doc->setDocumentMargin(0);
extra->doc->setBaseUrl(q->baseUrl());
qmlobject_connect(extra->doc, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()),
@@ -1233,7 +1261,7 @@ void QQuickTextPrivate::ensureDoc()
\inqmlmodule QtQuick
\ingroup qtquick-visual
\inherits Item
- \brief Specifies how to add formatted text to a scene
+ \brief Specifies how to add formatted text to a scene.
Text items can display both plain and rich text. For example, red text with
a specific font and size can be defined like this:
@@ -1499,6 +1527,36 @@ QQuickText::~QQuickText()
Text { text: "Hello"; renderType: Text.NativeRendering; font.hintingPreference: Font.PreferVerticalHinting }
\endqml
*/
+
+/*!
+ \qmlproperty bool QtQuick::Text::font.kerning
+ \since 5.10
+
+ Enables or disables the kerning OpenType feature when shaping the text. Disabling this may
+ improve performance when creating or changing the text, at the expense of some cosmetic
+ features. The default value is true.
+
+ \qml
+ Text { text: "OATS FLAVOUR WAY"; font.kerning: false }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool QtQuick::Text::font.preferShaping
+ \since 5.10
+
+ Sometimes, a font will apply complex rules to a set of characters in order to
+ display them correctly. In some writing systems, such as Brahmic scripts, this is
+ required in order for the text to be legible, but in e.g. Latin script, it is merely
+ a cosmetic feature. Setting the \c preferShaping property to false will disable all
+ such features when they are not required, which will improve performance in most cases.
+
+ The default value is true.
+
+ \qml
+ Text { text: "Some text"; font.preferShaping: false }
+ \endqml
+*/
QFont QQuickText::font() const
{
Q_D(const QQuickText);
@@ -1599,6 +1657,7 @@ void QQuickText::setText(const QString &n)
d->extra->doc->setText(n);
d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
} else {
+ d->clearFormats();
d->rightToLeftText = d->text.isRightToLeft();
}
d->determineHorizontalAlignment();
@@ -2023,6 +2082,8 @@ void QQuickText::resetMaximumLineCount()
\code
<b></b> - bold
+ <del></del> - strike out (removed content)
+ <s></s> - strike out (no longer accurate or no longer relevant content)
<strong></strong> - bold
<i></i> - italic
<br> - new line
@@ -2089,6 +2150,7 @@ void QQuickText::setTextFormat(TextFormat format)
d->extra->doc->setText(d->text);
d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
} else {
+ d->clearFormats();
d->rightToLeftText = d->text.isRightToLeft();
d->textHasChanged = true;
}
@@ -2283,8 +2345,10 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed
if (newGeometry.height() > oldGeometry.height()) {
- if (!d->heightExceeded) // Height is adequate and growing.
+ if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) {
+ // Height is adequate and growing, and it wasn't 0 previously.
goto geomChangeDone;
+ }
if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
goto geomChangeDone;
} else if (newGeometry.height() < oldGeometry.height()) {
@@ -2328,10 +2392,10 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
if (d->text.isEmpty()) {
delete oldNode;
- return 0;
+ return nullptr;
}
- if (d->updateType != QQuickTextPrivate::UpdatePaintNode && oldNode != 0) {
+ if (d->updateType != QQuickTextPrivate::UpdatePaintNode && oldNode != nullptr) {
// Update done in preprocess() in the nodes
d->updateType = QQuickTextPrivate::UpdateNone;
return oldNode;
@@ -2341,7 +2405,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height() + d->lineHeightOffset(), d->availableHeight(), d->vAlign) + topPadding();
- QQuickTextNode *node = 0;
+ QQuickTextNode *node = nullptr;
if (!oldNode)
node = new QQuickTextNode(this);
else
@@ -2394,6 +2458,12 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
void QQuickText::updatePolish()
{
Q_D(QQuickText);
+ // If the fonts used for rendering are different from the ones used in the GUI thread,
+ // it means we will get warnings and corrupted text. If this case is detected, we need
+ // to update the text layout before creating the scenegraph nodes.
+ if (!d->assignedFont.isEmpty() && QFontInfo(d->font).family() != d->assignedFont)
+ d->polishSize = true;
+
if (d->polishSize) {
d->updateSize();
d->polishSize = false;
@@ -2799,7 +2869,7 @@ void QQuickText::hoverLeaveEvent(QHoverEvent *event)
Supported render types are:
\list
- \li Text.QtRendering - the default
+ \li Text.QtRendering
\li Text.NativeRendering
\endlist
@@ -2807,6 +2877,8 @@ void QQuickText::hoverLeaveEvent(QHoverEvent *event)
not require advanced features such as transformation of the text. Using such features in
combination with the NativeRendering render type will lend poor and sometimes pixelated
results.
+
+ The default rendering type is determined by \l QQuickWindow::textRenderType().
*/
QQuickText::RenderType QQuickText::renderType() const
{
@@ -2875,14 +2947,14 @@ void QQuickText::invalidateFontCaches()
{
Q_D(QQuickText);
- if (d->richText && d->extra.isAllocated() && d->extra->doc != 0) {
+ if (d->richText && d->extra.isAllocated() && d->extra->doc != nullptr) {
QTextBlock block;
for (block = d->extra->doc->firstBlock(); block.isValid(); block = block.next()) {
- if (block.layout() != 0 && block.layout()->engine() != 0)
+ if (block.layout() != nullptr && block.layout()->engine() != nullptr)
block.layout()->engine()->resetFontEngineCache();
}
} else {
- if (d->layout.engine() != 0)
+ if (d->layout.engine() != nullptr)
d->layout.engine()->resetFontEngineCache();
}
}
diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h
index a56bcdb87b..1af60051fb 100644
--- a/src/quick/items/qquicktext_p.h
+++ b/src/quick/items/qquicktext_p.h
@@ -79,10 +79,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickText : public QQuickImplicitSizeItem
Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat NOTIFY textFormatChanged)
Q_PROPERTY(TextElideMode elide READ elideMode WRITE setElideMode NOTIFY elideModeChanged) //### elideMode?
- Q_PROPERTY(qreal contentWidth READ contentWidth NOTIFY contentSizeChanged)
- Q_PROPERTY(qreal contentHeight READ contentHeight NOTIFY contentSizeChanged)
- Q_PROPERTY(qreal paintedWidth READ contentWidth NOTIFY contentSizeChanged) // Compatibility
- Q_PROPERTY(qreal paintedHeight READ contentHeight NOTIFY contentSizeChanged)
+ Q_PROPERTY(qreal contentWidth READ contentWidth NOTIFY contentWidthChanged)
+ Q_PROPERTY(qreal contentHeight READ contentHeight NOTIFY contentHeightChanged)
+ Q_PROPERTY(qreal paintedWidth READ contentWidth NOTIFY contentWidthChanged) // Compatibility
+ Q_PROPERTY(qreal paintedHeight READ contentHeight NOTIFY contentHeightChanged)
Q_PROPERTY(qreal lineHeight READ lineHeight WRITE setLineHeight NOTIFY lineHeightChanged)
Q_PROPERTY(LineHeightMode lineHeightMode READ lineHeightMode WRITE setLineHeightMode NOTIFY lineHeightModeChanged)
Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl RESET resetBaseUrl NOTIFY baseUrlChanged)
@@ -102,8 +102,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickText : public QQuickImplicitSizeItem
Q_PROPERTY(QSizeF advance READ advance NOTIFY contentSizeChanged REVISION 10)
public:
- QQuickText(QQuickItem *parent=0);
- ~QQuickText();
+ QQuickText(QQuickItem *parent=nullptr);
+ ~QQuickText() override;
enum HAlignment { AlignLeft = Qt::AlignLeft,
AlignRight = Qt::AlignRight,
@@ -212,15 +212,15 @@ public:
FontSizeMode fontSizeMode() const;
void setFontSizeMode(FontSizeMode mode);
- void componentComplete() Q_DECL_OVERRIDE;
+ void componentComplete() override;
int resourcesLoading() const; // mainly for testing
qreal contentWidth() const;
qreal contentHeight() const;
- QRectF boundingRect() const Q_DECL_OVERRIDE;
- QRectF clipRect() const Q_DECL_OVERRIDE;
+ QRectF boundingRect() const override;
+ QRectF clipRect() const override;
Q_INVOKABLE void doLayout(); // ### Qt 6: remove
Q_REVISION(9) Q_INVOKABLE void forceLayout();
@@ -272,6 +272,10 @@ Q_SIGNALS:
void textFormatChanged(QQuickText::TextFormat textFormat);
void elideModeChanged(QQuickText::TextElideMode mode);
void contentSizeChanged();
+ // The next two signals should be marked as Q_REVISION(12). See QTBUG-71247
+ void contentWidthChanged(qreal contentWidth);
+ void contentHeightChanged(qreal contentHeight);
+
void lineHeightChanged(qreal lineHeight);
void lineHeightModeChanged(LineHeightMode mode);
void fontSizeModeChanged();
@@ -289,20 +293,20 @@ Q_SIGNALS:
Q_REVISION(9) void fontInfoChanged();
protected:
- QQuickText(QQuickTextPrivate &dd, QQuickItem *parent = 0);
+ QQuickText(QQuickTextPrivate &dd, QQuickItem *parent = nullptr);
- void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
void geometryChanged(const QRectF &newGeometry,
- const QRectF &oldGeometry) Q_DECL_OVERRIDE;
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ const QRectF &oldGeometry) override;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
- void updatePolish() Q_DECL_OVERRIDE;
+ void updatePolish() override;
- void hoverEnterEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
- void hoverMoveEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
- void hoverLeaveEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverMoveEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
void invalidateFontCaches();
private Q_SLOTS:
diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h
index fde07eaf2e..efa45e0958 100644
--- a/src/quick/items/qquicktext_p_p.h
+++ b/src/quick/items/qquicktext_p_p.h
@@ -75,16 +75,18 @@ public:
void updateBaseline(qreal baseline, qreal dy);
void updateSize();
+ void signalSizeChange(const QSizeF &previousSize);
void updateLayout();
bool determineHorizontalAlignment();
bool setHAlign(QQuickText::HAlignment, bool forceAlign = false);
- void mirrorChange() Q_DECL_OVERRIDE;
+ void mirrorChange() override;
bool isLineLaidOutConnected();
void setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height);
int lineHeightOffset() const;
- QString elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine = 0) const;
+ QString elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine = nullptr) const;
void elideFormats(int start, int length, int offset, QVector<QTextLayout::FormatRange> *elidedFormats);
+ void clearFormats();
void processHoverEvent(QHoverEvent *event);
@@ -153,6 +155,8 @@ public:
QQuickText::RenderType renderType;
UpdateType updateType;
+ QString assignedFont;
+
bool maximumLineCountValid:1;
bool updateOnComponentComplete:1;
bool richText:1;
@@ -171,11 +175,12 @@ public:
bool needToUpdateLayout:1;
bool formatModifiesFontSize:1;
bool polishSize:1; // Workaround for problem with polish called after updateSize (QTBUG-42636)
+ bool updateSizeRecursionGuard:1;
static const QChar elideChar;
- qreal getImplicitWidth() const Q_DECL_OVERRIDE;
- qreal getImplicitHeight() const Q_DECL_OVERRIDE;
+ qreal getImplicitWidth() const override;
+ qreal getImplicitHeight() const override;
qreal availableWidth() const;
qreal availableHeight() const;
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 2e23d69e5b..a7a90c9134 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -47,7 +47,6 @@
#include <qfontmetrics.h>
#include <qevent.h>
#include <qdebug.h>
-#include <qdrag.h>
#include <qclipboard.h>
#include <qtimer.h>
#include <qinputmethod.h>
@@ -95,7 +94,7 @@ static QTextLine currentTextLine(const QTextCursor &cursor)
}
QQuickTextControlPrivate::QQuickTextControlPrivate()
- : doc(0),
+ : doc(nullptr),
#if QT_CONFIG(im)
preeditCursor(0),
#endif
@@ -432,6 +431,7 @@ void QQuickTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged /
#endif
emit q->selectionChanged();
}
+ q->updateCursorRectangle(true);
}
void QQuickTextControlPrivate::_q_updateCurrentCharFormatAndSelection()
@@ -998,7 +998,7 @@ QRectF QQuickTextControlPrivate::rectForPosition(int position) const
if (relativePos < line.textLength() - line.textStart())
w = line.cursorToX(relativePos + 1) - x;
else
- w = QFontMetrics(block.layout()->font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw()
+ w = QFontMetrics(block.layout()->font()).horizontalAdvance(QLatin1Char(' ')); // in sync with QTextLine::draw()
}
r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(), textCursorWidth + w, line.height());
} else {
@@ -1150,7 +1150,6 @@ void QQuickTextControlPrivate::mouseMoveEvent(QMouseEvent *e, const QPointF &mou
if (interactionFlags & Qt::TextEditable) {
if (cursor.position() != oldCursorPos) {
emit q->cursorPositionChanged();
- q->updateCursorRectangle(true);
}
_q_updateCurrentCharFormatAndSelection();
#if QT_CONFIG(im)
@@ -1159,7 +1158,6 @@ void QQuickTextControlPrivate::mouseMoveEvent(QMouseEvent *e, const QPointF &mou
#endif
} else if (cursor.position() != oldCursorPos) {
emit q->cursorPositionChanged();
- q->updateCursorRectangle(true);
}
selectionChanged(true);
repaintOldAndNewSelection(oldSelection);
@@ -1305,8 +1303,12 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
cursor.removeSelectedText();
}
+ QTextBlock block;
+
// insert commit string
if (!e->commitString().isEmpty() || e->replacementLength()) {
+ if (e->commitString().endsWith(QChar::LineFeed))
+ block = cursor.block(); // Remember the block where the preedit text is
QTextCursor c = cursor;
c.setPosition(c.position() + e->replacementStart());
c.setPosition(c.position() + e->replacementLength(), QTextCursor::KeepAnchor);
@@ -1325,7 +1327,9 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
}
}
- QTextBlock block = cursor.block();
+ if (!block.isValid())
+ block = cursor.block();
+
QTextLayout *layout = block.layout();
if (isGettingInput) {
layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index 70104a97e0..c99736a874 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -77,7 +77,7 @@ class Q_AUTOTEST_EXPORT QQuickTextControl : public QInputControl
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickTextControl)
public:
- explicit QQuickTextControl(QTextDocument *doc, QObject *parent = 0);
+ explicit QQuickTextControl(QTextDocument *doc, QObject *parent = nullptr);
virtual ~QQuickTextControl();
QTextDocument *document() const;
@@ -177,9 +177,9 @@ public:
bool cursorOn() const;
protected:
- void timerEvent(QTimerEvent *e) Q_DECL_OVERRIDE;
+ void timerEvent(QTimerEvent *e) override;
- bool event(QEvent *e) Q_DECL_OVERRIDE;
+ bool event(QEvent *e) override;
private:
Q_DISABLE_COPY(QQuickTextControl)
diff --git a/src/quick/items/qquicktextdocument.cpp b/src/quick/items/qquicktextdocument.cpp
index 5d2034defe..06ac5804c4 100644
--- a/src/quick/items/qquicktextdocument.cpp
+++ b/src/quick/items/qquicktextdocument.cpp
@@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QQuickTextDocument
\since 5.1
- \brief The QQuickTextDocument class provides access to the QTextDocument of QQuickTextEdit
+ \brief The QQuickTextDocument class provides access to the QTextDocument of QQuickTextEdit.
\inmodule QtQuick
This class provides access to the QTextDocument of QQuickTextEdit elements.
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 61d610520f..6b4b118eb7 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -45,7 +45,6 @@
#include "qquickwindow.h"
#include "qquicktextnode_p.h"
#include "qquicktextnodeengine_p.h"
-#include "qquicktextutil_p.h"
#include <QtCore/qmath.h>
#include <QtGui/qguiapplication.h>
@@ -74,7 +73,7 @@ QT_BEGIN_NAMESPACE
\ingroup qtquick-visual
\ingroup qtquick-input
\inherits Item
- \brief Displays multiple lines of editable formatted text
+ \brief Displays multiple lines of editable formatted text.
The TextEdit item displays a block of editable, formatted text.
@@ -140,7 +139,7 @@ namespace {
class RootNode : public QSGTransformNode
{
public:
- RootNode() : cursorNode(0), frameDecorationsNode(0)
+ RootNode() : cursorNode(nullptr), frameDecorationsNode(nullptr)
{ }
void resetFrameDecorations(QQuickTextNode* newNode)
@@ -356,6 +355,36 @@ QString QQuickTextEdit::text() const
*/
/*!
+ \qmlproperty bool QtQuick::TextEdit::font.kerning
+ \since 5.10
+
+ Enables or disables the kerning OpenType feature when shaping the text. Disabling this may
+ improve performance when creating or changing the text, at the expense of some cosmetic
+ features. The default value is true.
+
+ \qml
+ TextEdit { text: "OATS FLAVOUR WAY"; kerning: font.false }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool QtQuick::TextEdit::font.preferShaping
+ \since 5.10
+
+ Sometimes, a font will apply complex rules to a set of characters in order to
+ display them correctly. In some writing systems, such as Brahmic scripts, this is
+ required in order for the text to be legible, but in e.g. Latin script, it is merely
+ a cosmetic feature. Setting the \c preferShaping property to false will disable all
+ such features when they are not required, which will improve performance in most cases.
+
+ The default value is true.
+
+ \qml
+ TextEdit { text: "Some text"; font.preferShaping: false }
+ \endqml
+*/
+
+/*!
\qmlproperty string QtQuick::TextEdit::text
The text to display. If the text format is AutoText the text edit will
@@ -482,7 +511,7 @@ void QQuickTextEdit::setTextFormat(TextFormat format)
Supported render types are:
\list
- \li Text.QtRendering - the default
+ \li Text.QtRendering
\li Text.NativeRendering
\endlist
@@ -490,6 +519,8 @@ void QQuickTextEdit::setTextFormat(TextFormat format)
not require advanced features such as transformation of the text. Using such features in
combination with the NativeRendering render type will lend poor and sometimes pixelated
results.
+
+ The default rendering type is determined by \l QQuickWindow::textRenderType().
*/
QQuickTextEdit::RenderType QQuickTextEdit::renderType() const
{
@@ -1610,7 +1641,8 @@ bool QQuickTextEdit::event(QEvent *event)
Q_D(QQuickTextEdit);
if (event->type() == QEvent::ShortcutOverride) {
d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
- return event->isAccepted();
+ if (event->isAccepted())
+ return true;
}
return QQuickImplicitSizeItem::event(event);
}
@@ -1937,12 +1969,11 @@ void QQuickTextEdit::triggerPreprocess()
}
typedef QQuickTextEditPrivate::Node TextNode;
-typedef QList<TextNode*>::iterator TextNodeIterator;
+using TextNodeIterator = QQuickTextEditPrivate::TextNodeIterator;
-
-static bool comesBefore(TextNode* n1, TextNode* n2)
+static inline bool operator<(const TextNode &n1, const TextNode &n2)
{
- return n1->startPos() < n2->startPos();
+ return n1.startPos() < n2.startPos();
}
static inline void updateNodeTransform(QQuickTextNode* node, const QPointF &topLeft)
@@ -1961,12 +1992,12 @@ static inline void updateNodeTransform(QQuickTextNode* node, const QPointF &topL
void QQuickTextEdit::invalidateFontCaches()
{
Q_D(QQuickTextEdit);
- if (d->document == 0)
+ if (d->document == nullptr)
return;
QTextBlock block;
for (block = d->document->firstBlock(); block.isValid(); block = block.next()) {
- if (block.layout() != 0 && block.layout()->engine() != 0)
+ if (block.layout() != nullptr && block.layout()->engine() != nullptr)
block.layout()->engine()->resetFontEngineCache();
}
}
@@ -1984,7 +2015,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
Q_UNUSED(updatePaintNodeData);
Q_D(QQuickTextEdit);
- if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode && oldNode != 0) {
+ if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode && oldNode != nullptr) {
// Update done in preprocess() in the nodes
d->updateType = QQuickTextEditPrivate::UpdateNone;
return oldNode;
@@ -1995,13 +2026,12 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
if (!oldNode) {
// If we had any QQuickTextNode node references, they were deleted along with the root node
// But here we must delete the Node structures in textNodeMap
- qDeleteAll(d->textNodeMap);
d->textNodeMap.clear();
}
RootNode *rootNode = static_cast<RootNode *>(oldNode);
TextNodeIterator nodeIterator = d->textNodeMap.begin();
- while (nodeIterator != d->textNodeMap.end() && !(*nodeIterator)->dirty())
+ while (nodeIterator != d->textNodeMap.end() && !nodeIterator->dirty())
++nodeIterator;
QQuickTextNodeEngine engine;
@@ -2014,20 +2044,30 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
int firstDirtyPos = 0;
if (nodeIterator != d->textNodeMap.end()) {
- firstDirtyPos = (*nodeIterator)->startPos();
+ firstDirtyPos = nodeIterator->startPos();
+ // ### this could be optimized if the first and last dirty nodes are not connected
+ // as the intermediate text nodes would usually only need to be transformed differently.
+ int lastDirtyPos = firstDirtyPos;
+ auto it = d->textNodeMap.constEnd();
+ while (it != nodeIterator) {
+ --it;
+ if (it->dirty()) {
+ lastDirtyPos = it->startPos();
+ break;
+ }
+ }
do {
- rootNode->removeChildNode((*nodeIterator)->textNode());
- delete (*nodeIterator)->textNode();
- delete *nodeIterator;
+ rootNode->removeChildNode(nodeIterator->textNode());
+ delete nodeIterator->textNode();
nodeIterator = d->textNodeMap.erase(nodeIterator);
- } while (nodeIterator != d->textNodeMap.end() && (*nodeIterator)->dirty());
+ } while (nodeIterator != d->textNodeMap.constEnd() && nodeIterator->startPos() <= lastDirtyPos);
}
// FIXME: the text decorations could probably be handled separately (only updated for affected textFrames)
rootNode->resetFrameDecorations(d->createTextNode());
resetEngine(&frameDecorationsEngine, d->color, d->selectedTextColor, d->selectionColor);
- QQuickTextNode *node = 0;
+ QQuickTextNode *node = nullptr;
int currentNodeSize = 0;
int nodeStart = firstDirtyPos;
@@ -2037,7 +2077,8 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
rootNode->setMatrix(basePositionMatrix);
QPointF nodeOffset;
- TextNode *firstCleanNode = (nodeIterator != d->textNodeMap.end()) ? *nodeIterator : 0;
+ const TextNode firstCleanNode = (nodeIterator != d->textNodeMap.end()) ? *nodeIterator
+ : TextNode();
QList<QTextFrame *> frames;
frames.append(d->document->rootFrame());
@@ -2047,7 +2088,8 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
frames.append(textFrame->childFrames());
frameDecorationsEngine.addFrameDecorations(d->document, textFrame);
- if (textFrame->lastPosition() < firstDirtyPos || (firstCleanNode && textFrame->firstPosition() >= firstCleanNode->startPos()))
+ if (textFrame->lastPosition() < firstDirtyPos
+ || textFrame->firstPosition() >= firstCleanNode.startPos())
continue;
node = d->createTextNode();
resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor);
@@ -2060,7 +2102,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
QTextCharFormat format = a->formatAccessor(pos);
QTextBlock block = textFrame->firstCursorPosition().block();
engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position()));
- engine.addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document,
+ engine.addTextObject(block, QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document,
pos, textFrame->frameFormat().position());
nodeStart = pos;
} else {
@@ -2087,8 +2129,8 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
engine.addTextBlock(d->document, block, -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1);
currentNodeSize += block.length();
- if ((it.atEnd()) || (firstCleanNode && block.next().position() >= firstCleanNode->startPos())) // last node that needed replacing or last block of the frame
- break;
+ if ((it.atEnd()) || block.next().position() >= firstCleanNode.startPos())
+ break; // last node that needed replacing or last block of the frame
QList<int>::const_iterator lowerBound = std::lower_bound(frameBoundaries.constBegin(), frameBoundaries.constEnd(), block.next().position());
if (currentNodeSize > nodeBreakingSize || lowerBound == frameBoundaries.constEnd() || *lowerBound > nodeStart) {
@@ -2106,16 +2148,19 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
// Now prepend the frame decorations since we want them rendered first, with the text nodes and cursor in front.
rootNode->prependChildNode(rootNode->frameDecorationsNode);
- Q_ASSERT(nodeIterator == d->textNodeMap.end() || (*nodeIterator) == firstCleanNode);
+ Q_ASSERT(nodeIterator == d->textNodeMap.end()
+ || (nodeIterator->textNode() == firstCleanNode.textNode()
+ && nodeIterator->startPos() == firstCleanNode.startPos()));
// Update the position of the subsequent text blocks.
- if (firstCleanNode) {
- QPointF oldOffset = firstCleanNode->textNode()->matrix().map(QPointF(0,0));
- QPointF currentOffset = d->document->documentLayout()->blockBoundingRect(d->document->findBlock(firstCleanNode->startPos())).topLeft();
+ if (firstCleanNode.textNode() != nullptr) {
+ QPointF oldOffset = firstCleanNode.textNode()->matrix().map(QPointF(0,0));
+ QPointF currentOffset = d->document->documentLayout()->blockBoundingRect(
+ d->document->findBlock(firstCleanNode.startPos())).topLeft();
QPointF delta = currentOffset - oldOffset;
while (nodeIterator != d->textNodeMap.end()) {
- QMatrix4x4 transformMatrix = (*nodeIterator)->textNode()->matrix();
+ QMatrix4x4 transformMatrix = nodeIterator->textNode()->matrix();
transformMatrix.translate(delta.x(), delta.y());
- (*nodeIterator)->textNode()->setMatrix(transformMatrix);
+ nodeIterator->textNode()->setMatrix(transformMatrix);
++nodeIterator;
}
@@ -2123,11 +2168,11 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
// Since we iterate over blocks from different text frames that are potentially not sorted
// we need to ensure that our list of nodes is sorted again:
- std::sort(d->textNodeMap.begin(), d->textNodeMap.end(), &comesBefore);
+ std::sort(d->textNodeMap.begin(), d->textNodeMap.end());
}
- if (d->cursorComponent == 0) {
- QSGInternalRectangleNode* cursor = 0;
+ if (d->cursorComponent == nullptr) {
+ QSGInternalRectangleNode* cursor = nullptr;
if (!isReadOnly() && d->cursorVisible && d->control->cursorOn())
cursor = d->sceneGraphContext()->createInternalRectangleNode(d->control->cursorRect(), d->color);
rootNode->resetCursorNode(cursor);
@@ -2302,22 +2347,26 @@ void QQuickTextEdit::markDirtyNodesForRange(int start, int end, int charDelta)
if (start == end)
return;
- TextNode dummyNode(start, 0);
- TextNodeIterator it = std::lower_bound(d->textNodeMap.begin(), d->textNodeMap.end(), &dummyNode, &comesBefore);
+ TextNode dummyNode(start);
+
+ const TextNodeIterator textNodeMapBegin = d->textNodeMap.begin();
+ const TextNodeIterator textNodeMapEnd = d->textNodeMap.end();
+
+ TextNodeIterator it = std::lower_bound(textNodeMapBegin, textNodeMapEnd, dummyNode);
// qLowerBound gives us the first node past the start of the affected portion, rewind to the first node
// that starts at the last position before the edit position. (there might be several because of images)
- if (it != d->textNodeMap.begin()) {
+ if (it != textNodeMapBegin) {
--it;
- TextNode otherDummy((*it)->startPos(), 0);
- it = std::lower_bound(d->textNodeMap.begin(), d->textNodeMap.end(), &otherDummy, &comesBefore);
+ TextNode otherDummy(it->startPos());
+ it = std::lower_bound(textNodeMapBegin, textNodeMapEnd, otherDummy);
}
// mark the affected nodes as dirty
- while (it != d->textNodeMap.end()) {
- if ((*it)->startPos() <= end)
- (*it)->setDirty();
+ while (it != textNodeMapEnd) {
+ if (it->startPos() <= end)
+ it->setDirty();
else if (charDelta)
- (*it)->moveStartPos(charDelta);
+ it->moveStartPos(charDelta);
else
return;
++it;
@@ -2480,7 +2529,7 @@ void QQuickTextEdit::updateSize()
if (d->isImplicitResizeEnabled()) {
// ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
- if (!widthValid() && !d->requireImplicitWidth)
+ if (!widthValid())
setImplicitSize(newWidth + leftPadding() + rightPadding(), newHeight + topPadding() + bottomPadding());
else
setImplicitHeight(newHeight + topPadding() + bottomPadding());
@@ -2502,8 +2551,8 @@ void QQuickTextEdit::updateWholeDocument()
{
Q_D(QQuickTextEdit);
if (!d->textNodeMap.isEmpty()) {
- for (TextNode* node : qAsConst(d->textNodeMap))
- node->setDirty();
+ for (TextNode &node : d->textNodeMap)
+ node.setDirty();
}
polish();
@@ -2640,6 +2689,12 @@ void QQuickTextEditPrivate::handleFocusEvent(QFocusEvent *event)
q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
q, SLOT(q_updateAlignment()));
#endif
+ if (event->reason() != Qt::ActiveWindowFocusReason
+ && event->reason() != Qt::PopupFocusReason
+ && control->textCursor().hasSelection()
+ && !persistentSelection)
+ q->deselect();
+
emit q->editingFinished();
}
}
@@ -2647,7 +2702,7 @@ void QQuickTextEditPrivate::handleFocusEvent(QFocusEvent *event)
void QQuickTextEditPrivate::addCurrentTextNodeToRoot(QQuickTextNodeEngine *engine, QSGTransformNode *root, QQuickTextNode *node, TextNodeIterator &it, int startPos)
{
engine->addToSceneGraph(node, QQuickText::Normal, QColor());
- it = textNodeMap.insert(it, new TextNode(startPos, node));
+ it = textNodeMap.insert(it, TextNode(startPos, node));
++it;
root->appendChildNode(node);
}
@@ -3038,6 +3093,32 @@ void QQuickTextEdit::resetBottomPadding()
}
/*!
+ \qmlproperty real QtQuick::TextEdit::tabStopDistance
+ \since 5.10
+
+ The default distance, in device units, between tab stops.
+
+ \sa QTextOption::setTabStop()
+*/
+int QQuickTextEdit::tabStopDistance() const
+{
+ Q_D(const QQuickTextEdit);
+ return d->document->defaultTextOption().tabStopDistance();
+}
+
+void QQuickTextEdit::setTabStopDistance(qreal distance)
+{
+ Q_D(QQuickTextEdit);
+ QTextOption textOptions = d->document->defaultTextOption();
+ if (textOptions.tabStopDistance() == distance)
+ return;
+
+ textOptions.setTabStopDistance(distance);
+ d->document->setDefaultTextOption(textOptions);
+ emit tabStopDistanceChanged(distance);
+}
+
+/*!
\qmlmethod QtQuick::TextEdit::clear()
\since 5.7
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index c8d3515be1..7a847ffeae 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -111,9 +111,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem
Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6)
Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6)
Q_PROPERTY(QString preeditText READ preeditText NOTIFY preeditTextChanged REVISION 7)
+ Q_PROPERTY(qreal tabStopDistance READ tabStopDistance WRITE setTabStopDistance NOTIFY tabStopDistanceChanged REVISION 10)
public:
- QQuickTextEdit(QQuickItem *parent=0);
+ QQuickTextEdit(QQuickItem *parent=nullptr);
enum HAlignment {
AlignLeft = Qt::AlignLeft,
@@ -234,7 +235,7 @@ public:
bool canUndo() const;
bool canRedo() const;
- void componentComplete() Q_DECL_OVERRIDE;
+ void componentComplete() override;
/* FROM EDIT */
void setReadOnly(bool);
@@ -243,7 +244,7 @@ public:
QRectF cursorRectangle() const;
#if QT_CONFIG(im)
- QVariant inputMethodQuery(Qt::InputMethodQuery property) const Q_DECL_OVERRIDE;
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const override;
Q_REVISION(4) Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const;
#endif
@@ -259,8 +260,8 @@ public:
Q_INVOKABLE void moveCursorSelection(int pos);
Q_INVOKABLE void moveCursorSelection(int pos, SelectionMode mode);
- QRectF boundingRect() const Q_DECL_OVERRIDE;
- QRectF clipRect() const Q_DECL_OVERRIDE;
+ QRectF boundingRect() const override;
+ QRectF clipRect() const override;
bool isInputMethodComposing() const;
@@ -296,6 +297,9 @@ public:
void setBottomPadding(qreal padding);
void resetBottomPadding();
+ int tabStopDistance() const;
+ void setTabStopDistance(qreal distance);
+
Q_SIGNALS:
void textChanged();
Q_REVISION(7) void preeditTextChanged();
@@ -340,6 +344,7 @@ Q_SIGNALS:
Q_REVISION(6) void leftPaddingChanged();
Q_REVISION(6) void rightPaddingChanged();
Q_REVISION(6) void bottomPaddingChanged();
+ Q_REVISION(10) void tabStopDistanceChanged(qreal distance);
public Q_SLOTS:
void selectAll();
@@ -379,31 +384,31 @@ private:
void invalidateFontCaches();
protected:
- QQuickTextEdit(QQuickTextEditPrivate &dd, QQuickItem *parent = 0);
+ QQuickTextEdit(QQuickTextEditPrivate &dd, QQuickItem *parent = nullptr);
void geometryChanged(const QRectF &newGeometry,
- const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ const QRectF &oldGeometry) override;
- bool event(QEvent *) Q_DECL_OVERRIDE;
- void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE;
- void keyReleaseEvent(QKeyEvent *) Q_DECL_OVERRIDE;
- void focusInEvent(QFocusEvent *event) Q_DECL_OVERRIDE;
- void focusOutEvent(QFocusEvent *event) Q_DECL_OVERRIDE;
+ bool event(QEvent *) override;
+ void keyPressEvent(QKeyEvent *) override;
+ void keyReleaseEvent(QKeyEvent *) override;
+ void focusInEvent(QFocusEvent *event) override;
+ void focusOutEvent(QFocusEvent *event) override;
- void hoverEnterEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
- void hoverMoveEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
- void hoverLeaveEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverMoveEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
// mouse filter?
- void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseDoubleClickEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
#if QT_CONFIG(im)
- void inputMethodEvent(QInputMethodEvent *e) Q_DECL_OVERRIDE;
+ void inputMethodEvent(QInputMethodEvent *e) override;
#endif
- QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) Q_DECL_OVERRIDE;
- void updatePolish() Q_DECL_OVERRIDE;
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override;
+ void updatePolish() override;
friend class QQuickTextUtil;
friend class QQuickTextDocument;
diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h
index 03bce00cb0..46d3d5ff6b 100644
--- a/src/quick/items/qquicktextedit_p_p.h
+++ b/src/quick/items/qquicktextedit_p_p.h
@@ -53,11 +53,14 @@
#include "qquicktextedit_p.h"
#include "qquickimplicitsizeitem_p_p.h"
+#include "qquicktextutil_p.h"
#include <QtQml/qqml.h>
#include <QtCore/qlist.h>
#include <private/qlazilyallocated_p.h>
+#include <limits>
+
QT_BEGIN_NAMESPACE
class QTextLayout;
class QQuickTextDocumentWithImageResources;
@@ -73,7 +76,8 @@ public:
typedef QQuickTextEdit Public;
struct Node {
- explicit Node(int startPos, QQuickTextNode* node)
+ explicit Node(int startPos = std::numeric_limits<int>::max(),
+ QQuickTextNode *node = nullptr)
: m_startPos(startPos), m_node(node), m_dirty(false) { }
QQuickTextNode* textNode() const { return m_node; }
void moveStartPos(int delta) { Q_ASSERT(m_startPos + delta > 0); m_startPos += delta; }
@@ -86,7 +90,7 @@ public:
QQuickTextNode* m_node;
bool m_dirty;
};
- typedef QList<Node*>::iterator TextNodeIterator;
+ typedef QList<Node>::iterator TextNodeIterator;
struct ExtraData {
ExtraData();
@@ -108,15 +112,11 @@ public:
QQuickTextEditPrivate()
: color(QRgb(0xFF000000)), selectionColor(QRgb(0xFF000080)), selectedTextColor(QRgb(0xFFFFFFFF))
, textMargin(0.0), xoff(0), yoff(0)
- , font(sourceFont), cursorComponent(0), cursorItem(0), document(0), control(0)
- , quickDocument(0), lastSelectionStart(0), lastSelectionEnd(0), lineCount(0)
+ , font(sourceFont), cursorComponent(nullptr), cursorItem(nullptr), document(nullptr), control(nullptr)
+ , quickDocument(nullptr), lastSelectionStart(0), lastSelectionEnd(0), lineCount(0)
, hAlign(QQuickTextEdit::AlignLeft), vAlign(QQuickTextEdit::AlignTop)
, format(QQuickTextEdit::PlainText), wrapMode(QQuickTextEdit::NoWrap)
-#if defined(QT_QUICK_DEFAULT_TEXT_RENDER_TYPE)
- , renderType(QQuickTextEdit::QT_QUICK_DEFAULT_TEXT_RENDER_TYPE)
-#else
- , renderType(QQuickTextEdit::QtRendering)
-#endif
+ , renderType(QQuickTextUtil::textRenderType<QQuickTextEdit>())
, contentDirection(Qt::LayoutDirectionAuto)
, mouseSelectionMode(QQuickTextEdit::SelectCharacters)
#if QT_CONFIG(im)
@@ -131,11 +131,6 @@ public:
{
}
- ~QQuickTextEditPrivate()
- {
- qDeleteAll(textNodeMap);
- }
-
static QQuickTextEditPrivate *get(QQuickTextEdit *item) {
return static_cast<QQuickTextEditPrivate *>(QObjectPrivate::get(item)); }
@@ -146,8 +141,8 @@ public:
void relayoutDocument();
bool determineHorizontalAlignment();
bool setHAlign(QQuickTextEdit::HAlignment, bool forceAlign = false);
- void mirrorChange() Q_DECL_OVERRIDE;
- qreal getImplicitWidth() const Q_DECL_OVERRIDE;
+ void mirrorChange() override;
+ qreal getImplicitWidth() const override;
Qt::LayoutDirection textDirection(const QString &text) const;
bool isLinkHoveredConnected();
@@ -189,7 +184,7 @@ public:
QQuickTextDocumentWithImageResources *document;
QQuickTextControl *control;
QQuickTextDocument *quickDocument;
- QList<Node*> textNodeMap;
+ QList<Node> textNodeMap;
int lastSelectionStart;
int lastSelectionEnd;
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index a378359c95..5f6fd8f50f 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -40,7 +40,6 @@
#include "qquicktextinput_p.h"
#include "qquicktextinput_p_p.h"
#include "qquickwindow.h"
-#include "qquicktextutil_p.h"
#include <private/qqmlglobal_p.h>
#include <private/qv4scopedvalue_p.h>
@@ -76,7 +75,7 @@ DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
\ingroup qtquick-visual
\ingroup qtquick-input
\inherits Item
- \brief Displays an editable line of text
+ \brief Displays an editable line of text.
The TextInput type displays a single line of editable plain text.
@@ -157,7 +156,7 @@ void QQuickTextInput::setText(const QString &s)
Supported render types are:
\list
- \li Text.QtRendering - the default
+ \li Text.QtRendering
\li Text.NativeRendering
\endlist
@@ -165,6 +164,8 @@ void QQuickTextInput::setText(const QString &s)
not require advanced features such as transformation of the text. Using such features in
combination with the NativeRendering render type will lend poor and sometimes pixelated
results.
+
+ The default rendering type is determined by \l QQuickWindow::textRenderType().
*/
QQuickTextInput::RenderType QQuickTextInput::renderType() const
{
@@ -378,6 +379,36 @@ QString QQuickTextInputPrivate::realText() const
TextInput { text: "Hello"; renderType: TextInput.NativeRendering; font.hintingPreference: Font.PreferVerticalHinting }
\endqml
*/
+
+/*!
+ \qmlproperty bool QtQuick::TextInput::font.kerning
+ \since 5.10
+
+ Enables or disables the kerning OpenType feature when shaping the text. Disabling this may
+ improve performance when creating or changing the text, at the expense of some cosmetic
+ features. The default value is true.
+
+ \qml
+ TextInput { text: "OATS FLAVOUR WAY"; font.kerning: false }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool QtQuick::TextInput::font.preferShaping
+ \since 5.10
+
+ Sometimes, a font will apply complex rules to a set of characters in order to
+ display them correctly. In some writing systems, such as Brahmic scripts, this is
+ required in order for the text to be legible, but in e.g. Latin script, it is merely
+ a cosmetic feature. Setting the \c preferShaping property to false will disable all
+ such features when they are not required, which will improve performance in most cases.
+
+ The default value is true.
+
+ \qml
+ TextInput { text: "Some text"; font.preferShaping: false }
+ \endqml
+*/
QFont QQuickTextInput::font() const
{
Q_D(const QQuickTextInput);
@@ -846,7 +877,7 @@ QRectF QQuickTextInput::cursorRectangle() const
if (c < text().length())
w = l.cursorToX(c + 1) - x;
else
- w = QFontMetrics(font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw()
+ w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(' ')); // in sync with QTextLine::draw()
}
return QRectF(x, y, w, l.height());
}
@@ -1077,7 +1108,8 @@ void QQuickTextInputPrivate::checkIsValid()
Q_Q(QQuickTextInput);
ValidatorState state = hasAcceptableInput(m_text);
- m_validInput = state != InvalidInput;
+ if (!m_maskData)
+ m_validInput = state != InvalidInput;
if (state != AcceptableInput) {
if (m_acceptableInput) {
m_acceptableInput = false;
@@ -1210,6 +1242,12 @@ void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
d->updateDisplayText();
updateCursorRectangle();
+ // If this control is used for password input, we want to minimize
+ // the possibility of string reallocation not to leak (parts of)
+ // the password.
+ if (d->m_echoMode != QQuickTextInput::Normal)
+ d->m_text.reserve(30);
+
emit echoModeChanged(echoMode());
}
@@ -1345,7 +1383,7 @@ QRectF QQuickTextInput::positionToRectangle(int pos) const
if (pos < text().length())
w = l.cursorToX(pos + 1) - x;
else
- w = QFontMetrics(font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw()
+ w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(' ')); // in sync with QTextLine::draw()
}
return QRectF(x, y, w, l.height());
}
@@ -1831,7 +1869,7 @@ void QQuickTextInput::invalidateFontCaches()
{
Q_D(QQuickTextInput);
- if (d->m_textLayout.engine() != 0)
+ if (d->m_textLayout.engine() != nullptr)
d->m_textLayout.engine()->resetFontEngineCache();
}
@@ -1854,7 +1892,7 @@ QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
Q_UNUSED(data);
Q_D(QQuickTextInput);
- if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
+ if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != nullptr) {
// Update done in preprocess() in the nodes
d->updateType = QQuickTextInputPrivate::UpdateNone;
return oldNode;
@@ -1863,13 +1901,13 @@ QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
d->updateType = QQuickTextInputPrivate::UpdateNone;
QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
- if (node == 0)
+ if (node == nullptr)
node = new QQuickTextNode(this);
d->textNode = node;
- const bool showCursor = !isReadOnly() && d->cursorItem == 0 && d->cursorVisible && d->m_blinkStatus;
+ const bool showCursor = !isReadOnly() && d->cursorItem == nullptr && d->cursorVisible && d->m_blinkStatus;
- if (!d->textLayoutDirty && oldNode != 0) {
+ if (!d->textLayoutDirty && oldNode != nullptr) {
if (showCursor)
node->setCursor(cursorRectangle(), d->color);
else
@@ -3407,10 +3445,10 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
if (!event->commitString().isEmpty()) {
internalInsert(event->commitString());
cursorPositionChanged = true;
+ } else {
+ m_cursor = qBound(0, c, m_text.length());
}
- m_cursor = qBound(0, c, m_text.length());
-
for (int i = 0; i < event->attributes().size(); ++i) {
const QInputMethodEvent::Attribute &a = event->attributes().at(i);
if (a.type == QInputMethodEvent::Selection) {
@@ -3530,11 +3568,15 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
#if QT_CONFIG(validator)
if (m_validator) {
QString textCopy = m_text;
+ if (m_maskData)
+ textCopy = maskString(0, m_text, true);
int cursorCopy = m_cursor;
QValidator::State state = m_validator->validate(textCopy, cursorCopy);
+ if (m_maskData)
+ textCopy = m_text;
m_validInput = state != QValidator::Invalid;
m_acceptableInput = state == QValidator::Acceptable;
- if (m_validInput) {
+ if (m_validInput && !m_maskData) {
if (m_text != textCopy) {
internalSetText(textCopy, cursorCopy);
return true;
@@ -3543,26 +3585,8 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
}
}
#endif
-
- if (m_maskData) {
- if (m_text.length() != m_maxLength) {
- m_acceptableInput = false;
- } else {
- for (int i = 0; i < m_maxLength; ++i) {
- if (m_maskData[i].separator) {
- if (m_text.at(i) != m_maskData[i].maskChar) {
- m_acceptableInput = false;
- break;
- }
- } else {
- if (!isValidInput(m_text.at(i), m_maskData[i].maskChar)) {
- m_acceptableInput = false;
- break;
- }
- }
- }
- }
- }
+ if (m_maskData)
+ checkIsValid();
if (validateFromState >= 0 && wasValidInput && !m_validInput) {
if (m_transactions.count())
@@ -3810,7 +3834,7 @@ void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
if (maskFields.isEmpty() || delimiter == 0) {
if (m_maskData) {
delete [] m_maskData;
- m_maskData = 0;
+ m_maskData = nullptr;
m_maxLength = 32767;
internalSetText(QString());
}
diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h
index c4da807471..c46a2f8128 100644
--- a/src/quick/items/qquicktextinput_p.h
+++ b/src/quick/items/qquicktextinput_p.h
@@ -115,10 +115,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem
Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6)
public:
- QQuickTextInput(QQuickItem * parent=0);
+ QQuickTextInput(QQuickItem * parent=nullptr);
~QQuickTextInput();
- void componentComplete() Q_DECL_OVERRIDE;
+ void componentComplete() override;
enum EchoMode {//To match QLineEdit::EchoMode
Normal,
@@ -267,12 +267,12 @@ public:
bool hasAcceptableInput() const;
#if QT_CONFIG(im)
- QVariant inputMethodQuery(Qt::InputMethodQuery property) const Q_DECL_OVERRIDE;
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const override;
Q_REVISION(3) Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const;
#endif
- QRectF boundingRect() const Q_DECL_OVERRIDE;
- QRectF clipRect() const Q_DECL_OVERRIDE;
+ QRectF boundingRect() const override;
+ QRectF clipRect() const override;
bool canPaste() const;
@@ -363,26 +363,26 @@ private:
void ensureActiveFocus();
protected:
- QQuickTextInput(QQuickTextInputPrivate &dd, QQuickItem *parent = 0);
+ QQuickTextInput(QQuickTextInputPrivate &dd, QQuickItem *parent = nullptr);
void geometryChanged(const QRectF &newGeometry,
- const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ const QRectF &oldGeometry) override;
- void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
- void keyPressEvent(QKeyEvent* ev) Q_DECL_OVERRIDE;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseDoubleClickEvent(QMouseEvent *event) override;
+ void keyPressEvent(QKeyEvent* ev) override;
#if QT_CONFIG(im)
- void inputMethodEvent(QInputMethodEvent *) Q_DECL_OVERRIDE;
+ void inputMethodEvent(QInputMethodEvent *) override;
#endif
- void mouseUngrabEvent() Q_DECL_OVERRIDE;
- bool event(QEvent *e) Q_DECL_OVERRIDE;
- void focusOutEvent(QFocusEvent *event) Q_DECL_OVERRIDE;
- void focusInEvent(QFocusEvent *event) Q_DECL_OVERRIDE;
- void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE;
- QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) Q_DECL_OVERRIDE;
- void updatePolish() Q_DECL_OVERRIDE;
+ void mouseUngrabEvent() override;
+ bool event(QEvent *e) override;
+ void focusOutEvent(QFocusEvent *event) override;
+ void focusInEvent(QFocusEvent *event) override;
+ void timerEvent(QTimerEvent *event) override;
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) override;
+ void updatePolish() override;
public Q_SLOTS:
void selectAll();
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index 0bf5779a53..7965f3d3f4 100644
--- a/src/quick/items/qquicktextinput_p_p.h
+++ b/src/quick/items/qquicktextinput_p_p.h
@@ -43,6 +43,7 @@
#include "qquicktextinput_p.h"
#include "qquicktext_p.h"
#include "qquickimplicitsizeitem_p_p.h"
+#include "qquicktextutil_p.h"
#include <QtQml/qqml.h>
#include <QtCore/qelapsedtimer.h>
@@ -98,9 +99,9 @@ public:
QQuickTextInputPrivate()
: hscroll(0)
, vscroll(0)
- , cursorItem(0)
- , textNode(0)
- , m_maskData(0)
+ , cursorItem(nullptr)
+ , textNode(nullptr)
+ , m_maskData(nullptr)
, color(QRgb(0xFF000000))
, selectionColor(QRgb(0xFF000080))
, selectedTextColor(QRgb(0xFFFFFFFF))
@@ -122,11 +123,7 @@ public:
, vAlign(QQuickTextInput::AlignTop)
, wrapMode(QQuickTextInput::NoWrap)
, m_echoMode(QQuickTextInput::Normal)
-#if defined(QT_QUICK_DEFAULT_TEXT_RENDER_TYPE)
- , renderType(QQuickTextInput::QT_QUICK_DEFAULT_TEXT_RENDER_TYPE)
-#else
- , renderType(QQuickTextInput::QtRendering)
-#endif
+ , renderType(QQuickTextUtil::textRenderType<QQuickTextInput>())
, updateType(UpdatePaintNode)
, mouseSelectionMode(QQuickTextInput::SelectCharacters)
, m_layoutDirection(Qt::LayoutDirectionAuto)
@@ -165,6 +162,11 @@ public:
~QQuickTextInputPrivate()
{
+ // If this control is used for password input, we don't want the
+ // password data to stay in the process memory, therefore we need
+ // to zero it out
+ if (m_echoMode != QQuickTextInput::Normal)
+ m_text.fill(0);
}
void init();
@@ -175,7 +177,7 @@ public:
void updateVerticalScroll();
bool determineHorizontalAlignment();
bool setHAlign(QQuickTextInput::HAlignment, bool forceAlign = false);
- void mirrorChange() Q_DECL_OVERRIDE;
+ void mirrorChange() override;
bool sendMouseEventToInputContext(QMouseEvent *event);
#if QT_CONFIG(im)
Qt::InputMethodHints effectiveInputMethodHints() const;
@@ -454,7 +456,7 @@ public:
void updateLayout();
void updateBaselineOffset();
- qreal getImplicitWidth() const Q_DECL_OVERRIDE;
+ qreal getImplicitWidth() const override;
inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; }
void setTopPadding(qreal value, bool reset = false);
diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp
index cf4e71adf5..0dd12207b7 100644
--- a/src/quick/items/qquicktextnode.cpp
+++ b/src/quick/items/qquicktextnode.cpp
@@ -78,7 +78,7 @@ namespace {
Creates an empty QQuickTextNode
*/
QQuickTextNode::QQuickTextNode(QQuickItem *ownerElement)
- : m_cursorNode(0), m_ownerElement(ownerElement), m_useNativeRenderer(false)
+ : m_cursorNode(nullptr), m_ownerElement(ownerElement), m_useNativeRenderer(false)
{
#ifdef QSG_RUNTIME_DESCRIPTION
qsgnode_set_description(this, QLatin1String("text"));
@@ -125,7 +125,7 @@ QSGGlyphNode *QQuickTextNode::addGlyphs(const QPointF &position, const QGlyphRun
node->geometry()->setIndexDataPattern(QSGGeometry::StaticPattern);
node->geometry()->setVertexDataPattern(QSGGeometry::StaticPattern);
- if (parentNode == 0)
+ if (parentNode == nullptr)
parentNode = this;
parentNode->appendChildNode(node);
@@ -134,7 +134,7 @@ QSGGlyphNode *QQuickTextNode::addGlyphs(const QPointF &position, const QGlyphRun
void QQuickTextNode::setCursor(const QRectF &rect, const QColor &color)
{
- if (m_cursorNode != 0)
+ if (m_cursorNode != nullptr)
delete m_cursorNode;
QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext();
@@ -147,7 +147,7 @@ void QQuickTextNode::clearCursor()
if (m_cursorNode)
removeChildNode(m_cursorNode);
delete m_cursorNode;
- m_cursorNode = 0;
+ m_cursorNode = nullptr;
}
void QQuickTextNode::addRectangleNode(const QRectF &rect, const QColor &color)
@@ -205,7 +205,7 @@ void QQuickTextNode::addTextDocument(const QPointF &position, QTextDocument *tex
QTextBlock block = textFrame->firstCursorPosition().block();
engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position()));
- engine.addTextObject(rect.topLeft(), format, QQuickTextNodeEngine::Unselected, textDocument,
+ engine.addTextObject(block, rect.topLeft(), format, QQuickTextNodeEngine::Unselected, textDocument,
pos, textFrame->frameFormat().position());
} else {
QTextFrame::iterator it = textFrame->begin();
@@ -273,9 +273,9 @@ void QQuickTextNode::addTextLayout(const QPointF &position, QTextLayout *textLay
void QQuickTextNode::deleteContent()
{
- while (firstChild() != 0)
+ while (firstChild() != nullptr)
delete firstChild();
- m_cursorNode = 0;
+ m_cursorNode = nullptr;
qDeleteAll(m_textures);
m_textures.clear();
}
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index c179ab7163..a1b5eb1faf 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -75,7 +75,7 @@ QQuickTextNodeEngine::BinaryTreeNode::BinaryTreeNode(const QGlyphRun &g,
: glyphRun(g)
, boundingRect(brect)
, selectionState(selState)
- , clipNode(0)
+ , clipNode(nullptr)
, decorations(decs)
, color(c)
, backgroundColor(bc)
@@ -256,10 +256,10 @@ void QQuickTextNodeEngine::processCurrentLine()
QVarLengthArray<TextDecoration> pendingOverlines;
QVarLengthArray<TextDecoration> pendingStrikeOuts;
if (!sortedIndexes.isEmpty()) {
- QQuickDefaultClipNode *currentClipNode = m_hasSelection ? new QQuickDefaultClipNode(QRectF()) : 0;
+ QQuickDefaultClipNode *currentClipNode = m_hasSelection ? new QQuickDefaultClipNode(QRectF()) : nullptr;
bool currentClipNodeUsed = false;
for (int i=0; i<=sortedIndexes.size(); ++i) {
- BinaryTreeNode *node = 0;
+ BinaryTreeNode *node = nullptr;
if (i < sortedIndexes.size()) {
int sortedIndex = sortedIndexes.at(i);
Q_ASSERT(sortedIndex < m_currentLineTree.size());
@@ -275,7 +275,7 @@ void QQuickTextNodeEngine::processCurrentLine()
decorationRect.setY(m_position.y() + m_currentLine.y());
decorationRect.setHeight(m_currentLine.height());
- if (node != 0)
+ if (node != nullptr)
decorationRect.setRight(node->boundingRect.left());
TextDecoration textDecoration(currentSelectionState, decorationRect, lastColor);
@@ -295,14 +295,14 @@ void QQuickTextNodeEngine::processCurrentLine()
// If we've reached an unselected node from a selected node, we add the
// selection rect to the graph, and we add decoration every time the
// selection state changes, because that means the text color changes
- if (node == 0 || node->selectionState != currentSelectionState) {
+ if (node == nullptr || node->selectionState != currentSelectionState) {
currentRect.setY(m_position.y() + m_currentLine.y());
currentRect.setHeight(m_currentLine.height());
if (currentSelectionState == Selected)
m_selectionRects.append(currentRect);
- if (currentClipNode != 0) {
+ if (currentClipNode != nullptr) {
if (!currentClipNodeUsed) {
delete currentClipNode;
} else {
@@ -312,13 +312,13 @@ void QQuickTextNodeEngine::processCurrentLine()
}
}
- if (node != 0 && m_hasSelection)
+ if (node != nullptr && m_hasSelection)
currentClipNode = new QQuickDefaultClipNode(QRectF());
else
- currentClipNode = 0;
+ currentClipNode = nullptr;
currentClipNodeUsed = false;
- if (node != 0) {
+ if (node != nullptr) {
currentSelectionState = node->selectionState;
currentRect = node->boundingRect;
@@ -333,7 +333,7 @@ void QQuickTextNodeEngine::processCurrentLine()
currentRect = currentRect.united(node->boundingRect);
}
- if (node != 0) {
+ if (node != nullptr) {
if (node->selectionState == Selected) {
node->clipNode = currentClipNode;
currentClipNodeUsed = true;
@@ -423,10 +423,11 @@ void QQuickTextNodeEngine::addImage(const QRectF &rect, const QImage &image, qre
QRectF searchRect = rect;
if (layoutPosition == QTextFrameFormat::InFlow) {
if (m_currentLineTree.isEmpty()) {
+ qreal y = m_currentLine.ascent() - ascent;
if (m_currentTextDirection == Qt::RightToLeft)
- searchRect.moveTopRight(m_position + m_currentLine.rect().topRight() + QPointF(0, 1));
+ searchRect.moveTopRight(m_position + m_currentLine.rect().topRight() + QPointF(0, y));
else
- searchRect.moveTopLeft(m_position + m_currentLine.position() + QPointF(0,1));
+ searchRect.moveTopLeft(m_position + m_currentLine.position() + QPointF(0, y));
} else {
const BinaryTreeNode *lastNode = m_currentLineTree.data() + m_currentLineTree.size() - 1;
if (lastNode->glyphRun.isRightToLeft()) {
@@ -443,13 +444,13 @@ void QQuickTextNodeEngine::addImage(const QRectF &rect, const QImage &image, qre
m_hasContents = true;
}
-void QQuickTextNodeEngine::addTextObject(const QPointF &position, const QTextCharFormat &format,
+void QQuickTextNodeEngine::addTextObject(const QTextBlock &block, const QPointF &position, const QTextCharFormat &format,
SelectionState selectionState,
QTextDocument *textDocument, int pos,
QTextFrameFormat::Position layoutPosition)
{
QTextObjectInterface *handler = textDocument->documentLayout()->handlerForObject(format.objectType());
- if (handler != 0) {
+ if (handler != nullptr) {
QImage image;
QSizeF size = handler->intrinsicSize(textDocument, pos, format);
@@ -476,17 +477,23 @@ void QQuickTextNodeEngine::addTextObject(const QPointF &position, const QTextCha
}
qreal ascent;
- QFontMetrics m(format.font());
+ QTextLine line = block.layout()->lineForTextPosition(pos);
switch (format.verticalAlignment())
{
- case QTextCharFormat::AlignMiddle:
- ascent = size.height() / 2 - 1;
+ case QTextCharFormat::AlignTop:
+ ascent = line.ascent();
break;
- case QTextCharFormat::AlignBaseline:
- ascent = size.height() - m.descent() - 1;
+ case QTextCharFormat::AlignMiddle: {
+ QFontMetrics m(format.font());
+ ascent = (size.height() - m.xHeight()) / 2;
+ break;
+ }
+ case QTextCharFormat::AlignBottom:
+ ascent = size.height() - line.descent();
break;
+ case QTextCharFormat::AlignBaseline:
default:
- ascent = size.height() - 1;
+ ascent = size.height();
}
addImage(QRectF(position, size), image, ascent, selectionState, layoutPosition);
@@ -651,7 +658,7 @@ void QQuickTextNodeEngine::addFrameDecorations(QTextDocument *document, QTextFra
QTextFrameFormat frameFormat = frame->format().toFrameFormat();
QTextTable *table = qobject_cast<QTextTable *>(frame);
- QRectF boundingRect = table == 0
+ QRectF boundingRect = table == nullptr
? documentLayout->frameBoundingRect(frame)
: documentLayout->tableBoundingRect(table);
@@ -674,7 +681,7 @@ void QQuickTextNodeEngine::addFrameDecorations(QTextDocument *document, QTextFra
addBorder(boundingRect.adjusted(frameFormat.leftMargin(), frameFormat.topMargin(),
-frameFormat.rightMargin(), -frameFormat.bottomMargin()),
borderWidth, borderStyle, borderBrush);
- if (table != 0) {
+ if (table != nullptr) {
int rows = table->rows();
int columns = table->columns();
@@ -781,7 +788,7 @@ void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode,
// Add all text with unselected color first
for (int i = 0; i < nodes.size(); ++i) {
const BinaryTreeNode *node = nodes.at(i);
- parentNode->addGlyphs(node->position, node->glyphRun, node->color, style, styleColor, 0);
+ parentNode->addGlyphs(node->position, node->glyphRun, node->color, style, styleColor, nullptr);
}
for (int i = 0; i < imageNodes.size(); ++i) {
@@ -812,7 +819,7 @@ void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode,
for (int i = 0; i < nodes.size(); ++i) {
const BinaryTreeNode *node = nodes.at(i);
QQuickDefaultClipNode *clipNode = node->clipNode;
- if (clipNode != 0 && clipNode->parent() == 0)
+ if (clipNode != nullptr && clipNode->parent() == nullptr)
parentNode->appendChildNode(clipNode);
if (node->selectionState == Selected) {
@@ -820,26 +827,26 @@ void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode,
int previousNodeIndex = i - 1;
int nextNodeIndex = i + 1;
const BinaryTreeNode *previousNode = previousNodeIndex < 0 ? 0 : nodes.at(previousNodeIndex);
- while (previousNode != 0 && qFuzzyCompare(previousNode->boundingRect.left(), node->boundingRect.left()))
+ while (previousNode != nullptr && qFuzzyCompare(previousNode->boundingRect.left(), node->boundingRect.left()))
previousNode = --previousNodeIndex < 0 ? 0 : nodes.at(previousNodeIndex);
const BinaryTreeNode *nextNode = nextNodeIndex == nodes.size() ? 0 : nodes.at(nextNodeIndex);
- if (previousNode != 0 && previousNode->selectionState == Unselected)
+ if (previousNode != nullptr && previousNode->selectionState == Unselected)
parentNode->addGlyphs(previousNode->position, previousNode->glyphRun, color, style, styleColor, clipNode);
- if (nextNode != 0 && nextNode->selectionState == Unselected)
+ if (nextNode != nullptr && nextNode->selectionState == Unselected)
parentNode->addGlyphs(nextNode->position, nextNode->glyphRun, color, style, styleColor, clipNode);
// If the previous or next node completely overlaps this one, then we have already drawn the glyphs of
// this node
bool drawCurrent = false;
- if (previousNode != 0 || nextNode != 0) {
+ if (previousNode != nullptr || nextNode != nullptr) {
for (int i = 0; i < node->ranges.size(); ++i) {
const QPair<int, int> &range = node->ranges.at(i);
int rangeLength = range.second - range.first + 1;
- if (previousNode != 0) {
+ if (previousNode != nullptr) {
for (int j = 0; j < previousNode->ranges.size(); ++j) {
const QPair<int, int> &otherRange = previousNode->ranges.at(j);
@@ -853,7 +860,7 @@ void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode,
}
}
- if (nextNode != 0 && rangeLength > 0) {
+ if (nextNode != nullptr && rangeLength > 0) {
for (int j = 0; j < nextNode->ranges.size(); ++j) {
const QPair<int, int> &otherRange = nextNode->ranges.at(j);
@@ -896,8 +903,8 @@ void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode,
void QQuickTextNodeEngine::mergeFormats(QTextLayout *textLayout, QVarLengthArray<QTextLayout::FormatRange> *mergedFormats)
{
- Q_ASSERT(mergedFormats != 0);
- if (textLayout == 0)
+ Q_ASSERT(mergedFormats != nullptr);
+ if (textLayout == nullptr)
return;
QVector<QTextLayout::FormatRange> additionalFormats = textLayout->formats();
@@ -911,7 +918,7 @@ void QQuickTextNodeEngine::mergeFormats(QTextLayout *textLayout, QVarLengthArray
QTextLayout::FormatRange *lastFormat = mergedFormats->data() + mergedFormats->size() - 1;
if (additionalFormat.start < lastFormat->start + lastFormat->length) {
- QTextLayout::FormatRange *mergedRange = 0;
+ QTextLayout::FormatRange *mergedRange = nullptr;
int length = additionalFormat.length;
if (additionalFormat.start > lastFormat->start) {
@@ -960,9 +967,14 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
QVarLengthArray<QTextLayout::FormatRange> colorChanges;
mergeFormats(block.layout(), &colorChanges);
- QPointF blockPosition = textDocument->documentLayout()->blockBoundingRect(block).topLeft() + position;
+ const QTextCharFormat charFormat = block.charFormat();
+ const QRectF blockBoundingRect = textDocument->documentLayout()->blockBoundingRect(block).translated(position);
+
+ if (charFormat.background().style() != Qt::NoBrush)
+ m_backgrounds.append(qMakePair(blockBoundingRect, charFormat.background().color()));
+
if (QTextList *textList = block.textList()) {
- QPointF pos = blockPosition;
+ QPointF pos = blockBoundingRect.topLeft();
QTextLayout *layout = block.layout();
if (layout->lineCount() > 0) {
QTextLine firstLine = layout->lineAt(0);
@@ -975,7 +987,6 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
if (block.textDirection() == Qt::RightToLeft)
pos.rx() += textRect.width();
- const QTextCharFormat charFormat = block.charFormat();
QFont font(charFormat.font());
QFontMetricsF fontMetrics(font);
QTextListFormat listFormat = textList->format();
@@ -1000,8 +1011,8 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
break;
};
- QSizeF size(fontMetrics.width(listItemBullet), fontMetrics.height());
- qreal xoff = fontMetrics.width(QLatin1Char(' '));
+ QSizeF size(fontMetrics.horizontalAdvance(listItemBullet), fontMetrics.height());
+ qreal xoff = fontMetrics.horizontalAdvance(QLatin1Char(' '));
if (block.textDirection() == Qt::LeftToRight)
xoff = -xoff - size.width();
setPosition(pos + QPointF(xoff, 0));
@@ -1036,15 +1047,15 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
int fontHeight = fontMetrics.descent() + fontMetrics.ascent();
int valign = charFormat.verticalAlignment();
if (valign == QTextCharFormat::AlignSuperScript)
- setPosition(QPointF(blockPosition.x(), blockPosition.y() - fontHeight / 2));
+ setPosition(QPointF(blockBoundingRect.x(), blockBoundingRect.y() - fontHeight / 2));
else if (valign == QTextCharFormat::AlignSubScript)
- setPosition(QPointF(blockPosition.x(), blockPosition.y() + fontHeight / 6));
+ setPosition(QPointF(blockBoundingRect.x(), blockBoundingRect.y() + fontHeight / 6));
else
- setPosition(blockPosition);
+ setPosition(blockBoundingRect.topLeft());
if (text.contains(QChar::ObjectReplacementCharacter)) {
QTextFrame *frame = qobject_cast<QTextFrame *>(textDocument->objectForFormat(charFormat));
- if (frame && frame->frameFormat().position() == QTextFrameFormat::InFlow) {
+ if (!frame || frame->frameFormat().position() == QTextFrameFormat::InFlow) {
int blockRelativePosition = textPos - block.position();
QTextLine line = block.layout()->lineForTextPosition(blockRelativePosition);
if (!currentLine().isValid()
@@ -1058,7 +1069,7 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
? QQuickTextNodeEngine::Selected
: QQuickTextNodeEngine::Unselected;
- addTextObject(QPointF(), charFormat, selectionState, textDocument, textPos);
+ addTextObject(block, QPointF(), charFormat, selectionState, textDocument, textPos);
}
textPos += text.length();
} else {
@@ -1094,7 +1105,7 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
#if QT_CONFIG(im)
if (preeditLength >= 0 && textPos <= block.position() + preeditPosition) {
- setPosition(blockPosition);
+ setPosition(blockBoundingRect.topLeft());
textPos = block.position() + preeditPosition;
QTextLine line = block.layout()->lineForTextPosition(preeditPosition);
if (!currentLine().isValid()
diff --git a/src/quick/items/qquicktextnodeengine_p.h b/src/quick/items/qquicktextnodeengine_p.h
index 18c624513a..49c1766045 100644
--- a/src/quick/items/qquicktextnodeengine_p.h
+++ b/src/quick/items/qquicktextnodeengine_p.h
@@ -179,7 +179,7 @@ public:
const QVarLengthArray<QTextLayout::FormatRange> &colorChanges,
int textPos, int fragmentEnd,
int selectionStart, int selectionEnd);
- void addTextObject(const QPointF &position, const QTextCharFormat &format,
+ void addTextObject(const QTextBlock &block, const QPointF &position, const QTextCharFormat &format,
SelectionState selectionState,
QTextDocument *textDocument, int pos,
QTextFrameFormat::Position layoutPosition = QTextFrameFormat::InFlow);
diff --git a/src/quick/items/qquicktextutil.cpp b/src/quick/items/qquicktextutil.cpp
index 6aa6c5cb4b..eb356a9c48 100644
--- a/src/quick/items/qquicktextutil.cpp
+++ b/src/quick/items/qquicktextutil.cpp
@@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE
QQuickItem *QQuickTextUtil::createCursor(
QQmlComponent *component, QQuickItem *parent, const QRectF &rectangle, const char *className)
{
- QQuickItem *item = 0;
+ QQuickItem *item = nullptr;
if (component->isReady()) {
QQmlContext *creationContext = component->creationContext();
diff --git a/src/quick/items/qquicktextutil_p.h b/src/quick/items/qquicktextutil_p.h
index 01055c95ec..bad5e738a8 100644
--- a/src/quick/items/qquicktextutil_p.h
+++ b/src/quick/items/qquicktextutil_p.h
@@ -54,6 +54,7 @@
#include <QtQml/qqml.h>
#include <QtQml/qqmlincubator.h>
#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickwindow.h>
QT_BEGIN_NAMESPACE
@@ -64,6 +65,7 @@ public:
template <typename Private> static void setCursorDelegate(Private *d, QQmlComponent *delegate);
template <typename Private> static void createCursor(Private *d);
+ template <typename T> static typename T::RenderType textRenderType();
static qreal alignedX(qreal textWidth, qreal itemWidth, int alignment);
static qreal alignedY(qreal textHeight, qreal itemHeight, int alignment);
@@ -124,6 +126,20 @@ void QQuickTextUtil::createCursor(Private *d)
parent->update();
}
+template <typename T>
+typename T::RenderType QQuickTextUtil::textRenderType()
+{
+ switch (QQuickWindow::textRenderType()) {
+ case QQuickWindow::QtTextRendering:
+ return T::QtRendering;
+ case QQuickWindow::NativeTextRendering:
+ return T::NativeRendering;
+ }
+
+ Q_UNREACHABLE();
+ return T::QtRendering;
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/quick/items/qquicktranslate.cpp b/src/quick/items/qquicktranslate.cpp
index 9937c692a5..872fe25a18 100644
--- a/src/quick/items/qquicktranslate.cpp
+++ b/src/quick/items/qquicktranslate.cpp
@@ -58,7 +58,7 @@ public:
\instantiates QQuickTranslate
\inqmlmodule QtQuick
\ingroup qtquick-visual-transforms
- \brief Provides a way to move an Item without changing its x or y properties
+ \brief Provides a way to move an Item without changing its x or y properties.
The Translate type provides independent control over position in addition
to the Item's x and y properties.
@@ -162,7 +162,7 @@ public:
\instantiates QQuickScale
\inqmlmodule QtQuick
\ingroup qtquick-visual-transforms
- \brief Provides a way to scale an Item
+ \brief Provides a way to scale an Item.
The Scale type provides a way to scale an \l Item through a scale-type
transform.
@@ -304,7 +304,7 @@ public:
\instantiates QQuickRotation
\inqmlmodule QtQuick
\ingroup qtquick-visual-transforms
- \brief Provides a way to rotate an Item
+ \brief Provides a way to rotate an Item.
The Rotation type provides a way to rotate an \l Item through a
rotation-type transform.
@@ -467,7 +467,8 @@ public:
\instantiates QQuickMatrix4x4
\inqmlmodule QtQuick
\ingroup qtquick-visual-transforms
- \brief Provides a way to apply a 4x4 tranformation matrix to an \l Item
+ \since 5.3
+ \brief Provides a way to apply a 4x4 tranformation matrix to an \l Item.
The Matrix4x4 type provides a way to apply a transformation to an
\l Item through a 4x4 matrix.
diff --git a/src/quick/items/qquicktranslate_p.h b/src/quick/items/qquicktranslate_p.h
index 1bceba20cf..b6ea43342c 100644
--- a/src/quick/items/qquicktranslate_p.h
+++ b/src/quick/items/qquicktranslate_p.h
@@ -66,7 +66,7 @@ class Q_AUTOTEST_EXPORT QQuickTranslate : public QQuickTransform
Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
public:
- QQuickTranslate(QObject *parent = 0);
+ QQuickTranslate(QObject *parent = nullptr);
~QQuickTranslate();
qreal x() const;
@@ -75,7 +75,7 @@ public:
qreal y() const;
void setY(qreal);
- void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE;
+ void applyTo(QMatrix4x4 *matrix) const override;
Q_SIGNALS:
void xChanged();
@@ -96,7 +96,7 @@ class Q_AUTOTEST_EXPORT QQuickScale : public QQuickTransform
Q_PROPERTY(qreal yScale READ yScale WRITE setYScale NOTIFY yScaleChanged)
Q_PROPERTY(qreal zScale READ zScale WRITE setZScale NOTIFY zScaleChanged)
public:
- QQuickScale(QObject *parent = 0);
+ QQuickScale(QObject *parent = nullptr);
~QQuickScale();
QVector3D origin() const;
@@ -111,7 +111,7 @@ public:
qreal zScale() const;
void setZScale(qreal);
- void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE;
+ void applyTo(QMatrix4x4 *matrix) const override;
Q_SIGNALS:
void originChanged();
@@ -133,7 +133,7 @@ class Q_AUTOTEST_EXPORT QQuickRotation : public QQuickTransform
Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
Q_PROPERTY(QVector3D axis READ axis WRITE setAxis NOTIFY axisChanged)
public:
- QQuickRotation(QObject *parent = 0);
+ QQuickRotation(QObject *parent = nullptr);
~QQuickRotation();
QVector3D origin() const;
@@ -146,7 +146,7 @@ public:
void setAxis(const QVector3D &axis);
void setAxis(Qt::Axis axis);
- void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE;
+ void applyTo(QMatrix4x4 *matrix) const override;
Q_SIGNALS:
void originChanged();
@@ -164,13 +164,13 @@ class Q_AUTOTEST_EXPORT QQuickMatrix4x4 : public QQuickTransform
Q_PROPERTY(QMatrix4x4 matrix READ matrix WRITE setMatrix NOTIFY matrixChanged)
public:
- QQuickMatrix4x4(QObject *parent = 0);
+ QQuickMatrix4x4(QObject *parent = nullptr);
~QQuickMatrix4x4();
QMatrix4x4 matrix() const;
void setMatrix(const QMatrix4x4& matrix);
- void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE;
+ void applyTo(QMatrix4x4 *matrix) const override;
Q_SIGNALS:
void matrixChanged();
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index fca1805fc9..c411da9519 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -70,13 +70,13 @@ void QQuickViewPrivate::init(QQmlEngine* e)
{
// The content item has CppOwnership policy (set in QQuickWindow). Ensure the presence of a JS
// wrapper so that the garbage collector can see the policy.
- QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine.data());
+ QV4::ExecutionEngine *v4 = engine.data()->handle();
QV4::QObjectWrapper::wrap(v4, contentItem);
}
}
QQuickViewPrivate::QQuickViewPrivate()
- : root(0), component(0), resizeMode(QQuickView::SizeViewToRootObject), initialSize(0,0)
+ : root(nullptr), component(nullptr), resizeMode(QQuickView::SizeViewToRootObject), initialSize(0,0)
{
}
@@ -94,11 +94,11 @@ void QQuickViewPrivate::execute()
if (root) {
delete root;
- root = 0;
+ root = nullptr;
}
if (component) {
delete component;
- component = 0;
+ component = nullptr;
}
if (!source.isEmpty()) {
QML_MEMORY_SCOPE_URL(engine.data()->baseUrl().resolved(source));
@@ -136,11 +136,7 @@ void QQuickViewPrivate::itemGeometryChanged(QQuickItem *resizeItem, QQuickGeomet
Typical usage:
- \code
- QQuickView *view = new QQuickView;
- view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
- view->show();
- \endcode
+ \snippet qquickview-ex.cpp 0
To receive errors related to loading and executing QML with QQuickView,
you can connect to the statusChanged() signal and monitor for QQuickView::Error.
@@ -198,6 +194,16 @@ QQuickView::QQuickView(QQmlEngine* engine, QWindow *parent)
}
/*!
+ \internal
+*/
+QQuickView::QQuickView(const QUrl &source, QQuickRenderControl *control)
+ : QQuickWindow(*(new QQuickViewPrivate), control)
+{
+ d_func()->init();
+ setSource(source);
+}
+
+/*!
Destroys the QQuickView.
*/
QQuickView::~QQuickView()
@@ -206,7 +212,7 @@ QQuickView::~QQuickView()
// be a child of the QQuickViewPrivate, and will be destroyed by its dtor
Q_D(QQuickView);
delete d->root;
- d->root = 0;
+ d->root = nullptr;
}
/*!
@@ -250,7 +256,7 @@ void QQuickView::setContent(const QUrl& url, QQmlComponent *component, QObject*
if (d->component && d->component->isError()) {
const QList<QQmlError> errorList = d->component->errors();
for (const QQmlError &error : errorList) {
- QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
+ QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), nullptr).warning()
<< error;
}
emit statusChanged(status());
@@ -279,7 +285,7 @@ QUrl QQuickView::source() const
QQmlEngine* QQuickView::engine() const
{
Q_D(const QQuickView);
- return d->engine ? const_cast<QQmlEngine *>(d->engine.data()) : 0;
+ return d->engine ? const_cast<QQmlEngine *>(d->engine.data()) : nullptr;
}
/*!
@@ -292,7 +298,7 @@ QQmlEngine* QQuickView::engine() const
QQmlContext* QQuickView::rootContext() const
{
Q_D(const QQuickView);
- return d->engine ? d->engine.data()->rootContext() : 0;
+ return d->engine ? d->engine.data()->rootContext() : nullptr;
}
/*!
@@ -461,7 +467,7 @@ void QQuickView::continueExecute()
if (d->component->isError()) {
const QList<QQmlError> errorList = d->component->errors();
for (const QQmlError &error : errorList) {
- QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
+ QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), nullptr).warning()
<< error;
}
emit statusChanged(status());
@@ -473,7 +479,7 @@ void QQuickView::continueExecute()
if (d->component->isError()) {
const QList<QQmlError> errorList = d->component->errors();
for (const QQmlError &error : errorList) {
- QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
+ QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), nullptr).warning()
<< error;
}
emit statusChanged(status());
@@ -507,7 +513,7 @@ void QQuickViewPrivate::setRootObject(QObject *obj)
<< "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << endl
<< "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << endl;
delete obj;
- root = 0;
+ root = nullptr;
}
if (root) {
initialSize = rootObjectSize();
diff --git a/src/quick/items/qquickview.h b/src/quick/items/qquickview.h
index 6d3b30e4c4..ecae25e90b 100644
--- a/src/quick/items/qquickview.h
+++ b/src/quick/items/qquickview.h
@@ -42,7 +42,6 @@
#include <QtQuick/qquickwindow.h>
#include <QtCore/qurl.h>
-#include <QtQml/qqmldebug.h>
QT_BEGIN_NAMESPACE
@@ -60,10 +59,11 @@ class Q_QUICK_EXPORT QQuickView : public QQuickWindow
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(QUrl source READ source WRITE setSource DESIGNABLE true)
public:
- explicit QQuickView(QWindow *parent = Q_NULLPTR);
+ explicit QQuickView(QWindow *parent = nullptr);
QQuickView(QQmlEngine* engine, QWindow *parent);
- explicit QQuickView(const QUrl &source, QWindow *parent = Q_NULLPTR);
- virtual ~QQuickView();
+ explicit QQuickView(const QUrl &source, QWindow *parent = nullptr);
+ QQuickView(const QUrl &source, QQuickRenderControl *renderControl);
+ ~QQuickView() override;
QUrl source() const;
diff --git a/src/quick/items/qquickview_p.h b/src/quick/items/qquickview_p.h
index f92d4b95d6..3f284c0519 100644
--- a/src/quick/items/qquickview_p.h
+++ b/src/quick/items/qquickview_p.h
@@ -93,7 +93,7 @@ public:
void updateSize();
void setRootObject(QObject *);
- void init(QQmlEngine* e = 0);
+ void init(QQmlEngine* e = nullptr);
QSize rootObjectSize() const;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 2cb518d691..d448d74b99 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -46,6 +46,8 @@
#include "qquickevents_p_p.h"
#include <private/qquickdrag_p.h>
+#include <private/qquickhoverhandler_p.h>
+#include <private/qquickpointerhandler_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qsgtexture_p.h>
@@ -77,6 +79,9 @@
# include <private/qopenglvertexarrayobject_p.h>
# include <private/qsgdefaultrendercontext_p.h>
#endif
+#ifndef QT_NO_DEBUG_STREAM
+#include <private/qdebug_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -84,14 +89,23 @@ Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch")
Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target")
Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse")
Q_LOGGING_CATEGORY(DBG_MOUSE_TARGET, "qt.quick.mouse.target")
+Q_LOGGING_CATEGORY(lcWheelTarget, "qt.quick.wheel.target")
+Q_LOGGING_CATEGORY(lcGestureTarget, "qt.quick.gesture.target")
Q_LOGGING_CATEGORY(DBG_HOVER_TRACE, "qt.quick.hover.trace")
Q_LOGGING_CATEGORY(DBG_FOCUS, "qt.quick.focus")
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);
bool QQuickWindowPrivate::defaultAlphaBuffer = false;
+#if defined(QT_QUICK_DEFAULT_TEXT_RENDER_TYPE)
+QQuickWindow::TextRenderType QQuickWindowPrivate::textRenderType = QQuickWindow::QT_QUICK_DEFAULT_TEXT_RENDER_TYPE;
+#else
+QQuickWindow::TextRenderType QQuickWindowPrivate::textRenderType = QQuickWindow::QtTextRendering;
+#endif
+
void QQuickWindowPrivate::updateFocusItemTransform()
{
#if QT_CONFIG(im)
@@ -125,7 +139,7 @@ public:
}
protected:
- void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE
+ void timerEvent(QTimerEvent *) override
{
killTimer(m_timer);
m_timer = 0;
@@ -156,7 +170,7 @@ public slots:
void animationStopped() { incubate(); }
protected:
- void incubatingObjectCountChanged(int count) Q_DECL_OVERRIDE
+ void incubatingObjectCountChanged(int count) override
{
if (count && !m_renderLoop->interleaveIncubation())
incubateAgain();
@@ -245,14 +259,16 @@ void QQuickWindow::hideEvent(QHideEvent *)
void QQuickWindow::focusOutEvent(QFocusEvent *ev)
{
Q_D(QQuickWindow);
- d->contentItem->setFocus(false, ev->reason());
+ if (d->contentItem)
+ d->contentItem->setFocus(false, ev->reason());
}
/*! \reimp */
void QQuickWindow::focusInEvent(QFocusEvent *ev)
{
Q_D(QQuickWindow);
- d->contentItem->setFocus(true, ev->reason());
+ if (d->contentItem)
+ d->contentItem->setFocus(true, ev->reason());
d->updateFocusItemTransform();
}
@@ -432,10 +448,8 @@ void QQuickWindowPrivate::syncSceneGraph()
emit q->afterSynchronizing();
runAndClearJobs(&afterSynchronizingJobs);
- context->endSync();
}
-
void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
{
QML_MEMORY_SCOPE_STRING("SceneGraph");
@@ -476,36 +490,38 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
}
QQuickWindowPrivate::QQuickWindowPrivate()
- : contentItem(0)
- , activeFocusItem(0)
+ : contentItem(nullptr)
+ , activeFocusItem(nullptr)
#if QT_CONFIG(cursor)
- , cursorItem(0)
+ , cursorItem(nullptr)
#endif
#if QT_CONFIG(draganddrop)
- , dragGrabber(0)
+ , dragGrabber(nullptr)
#endif
, touchMouseId(-1)
, touchMouseDevice(nullptr)
, touchMousePressTimestamp(0)
- , dirtyItemList(0)
+ , dirtyItemList(nullptr)
, devicePixelRatio(0)
- , context(0)
- , renderer(0)
- , windowManager(0)
- , renderControl(0)
+ , context(nullptr)
+ , renderer(nullptr)
+ , windowManager(nullptr)
+ , renderControl(nullptr)
, pointerEventRecursionGuard(0)
- , customRenderStage(0)
+ , customRenderStage(nullptr)
, clearColor(Qt::white)
, clearBeforeRendering(true)
, persistentGLContext(true)
, persistentSceneGraph(true)
, lastWheelEventAccepted(false)
, componentCompleted(true)
+ , allowChildEventFiltering(true)
+ , allowDoubleClick(true)
, lastFocusReason(Qt::OtherFocusReason)
- , renderTarget(0)
+ , renderTarget(nullptr)
, renderTargetId(0)
- , vaoHelper(0)
- , incubationController(0)
+ , vaoHelper(nullptr)
+ , incubationController(nullptr)
{
#if QT_CONFIG(draganddrop)
dragGrabber = new QQuickDragGrabber;
@@ -569,13 +585,21 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
QObject::connect(q, SIGNAL(focusObjectChanged(QObject*)), q, SIGNAL(activeFocusItemChanged()));
QObject::connect(q, SIGNAL(screenChanged(QScreen*)), q, SLOT(handleScreenChanged(QScreen*)));
-
+ QObject::connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
+ q, SLOT(handleApplicationStateChanged(Qt::ApplicationState)));
QObject::connect(q, SIGNAL(frameSwapped()), q, SLOT(runJobsAfterSwap()), Qt::DirectConnection);
if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
service->addWindow(q);
}
+void QQuickWindow::handleApplicationStateChanged(Qt::ApplicationState state)
+{
+ Q_D(QQuickWindow);
+ if (state != Qt::ApplicationActive && d->contentItem)
+ d->contentItem->windowDeactivateEvent();
+}
+
/*!
\property QQuickWindow::data
\internal
@@ -583,7 +607,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
QQmlListProperty<QObject> QQuickWindowPrivate::data()
{
- return QQmlListProperty<QObject>(q_func(), 0, QQuickWindowPrivate::data_append,
+ return QQmlListProperty<QObject>(q_func(), nullptr, QQuickWindowPrivate::data_append,
QQuickWindowPrivate::data_count,
QQuickWindowPrivate::data_at,
QQuickWindowPrivate::data_clear);
@@ -591,6 +615,7 @@ QQmlListProperty<QObject> QQuickWindowPrivate::data()
static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::TouchPoint &p, QTouchEvent *event, QQuickItem *item, bool transformNeeded = true)
{
+ Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
// The touch point local position and velocity are not yet transformed.
QMouseEvent *me = new QMouseEvent(type, transformNeeded ? item->mapFromScene(p.scenePos()) : p.pos(), p.scenePos(), p.screenPos(),
Qt::LeftButton, (type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton), event->modifiers());
@@ -630,11 +655,25 @@ bool QQuickWindowPrivate::checkIfDoubleClicked(ulong newPressEventTimestamp)
return doubleClicked;
}
+void QQuickWindowPrivate::cancelTouchMouseSynthesis()
+{
+ qCDebug(DBG_TOUCH_TARGET);
+ touchMouseId = -1;
+ touchMouseDevice = nullptr;
+}
+
bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEvent *pointerEvent)
{
+ Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
Q_Q(QQuickWindow);
auto device = pointerEvent->device();
+ // A touch event from a trackpad is likely to be followed by a mouse or gesture event, so mouse event synth is redundant
+ if (device->type() == QQuickPointerDevice::TouchPad && device->capabilities().testFlag(QQuickPointerDevice::MouseEmulation)) {
+ qCDebug(DBG_TOUCH_TARGET) << "skipping delivery of synth-mouse event from" << device;
+ return false;
+ }
+
// FIXME: make this work for mouse events too and get rid of the asTouchEvent in here.
Q_ASSERT(pointerEvent->asPointerTouchEvent());
QScopedPointer<QTouchEvent> event(pointerEvent->asPointerTouchEvent()->touchEventForItem(item));
@@ -654,7 +693,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
if (!item->contains(pos))
break;
- qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << p.id() << "->" << item;
+ qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << p.id() << "->" << item;
QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event.data(), item, false));
// Send a single press and see if that's accepted
@@ -665,17 +704,15 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
touchMouseId = p.id();
if (!q->mouseGrabberItem())
item->grabMouse();
- auto pointerEventPoint = pointerEvent->pointById(p.id());
- pointerEventPoint->setGrabber(item);
+ if (auto pointerEventPoint = pointerEvent->pointById(p.id()))
+ pointerEventPoint->setGrabberItem(item);
if (checkIfDoubleClicked(event->timestamp())) {
QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event.data(), item, false));
QCoreApplication::sendEvent(item, mouseDoubleClick.data());
event->setAccepted(mouseDoubleClick->isAccepted());
- if (!mouseDoubleClick->isAccepted()) {
- touchMouseId = -1;
- touchMouseDevice = nullptr;
- }
+ if (!mouseDoubleClick->isAccepted())
+ cancelTouchMouseSynthesis();
}
return true;
@@ -690,7 +727,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
QCoreApplication::sendEvent(item, me.data());
event->setAccepted(me->isAccepted());
if (me->isAccepted()) {
- qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << p.id() << "->" << mouseGrabberItem;
+ qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << p.id() << "->" << mouseGrabberItem;
}
return event->isAccepted();
} else {
@@ -729,8 +766,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
if (q->mouseGrabberItem()) // might have ungrabbed due to event
q->mouseGrabberItem()->ungrabMouse();
- touchMouseId = -1;
- touchMouseDevice = nullptr;
+ cancelTouchMouseSynthesis();
return me->isAccepted();
}
}
@@ -740,45 +776,10 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
return false;
}
-void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
-{
- Q_Q(QQuickWindow);
- if (q->mouseGrabberItem() == grabber)
- return;
-
- qCDebug(DBG_MOUSE_TARGET) << "grabber" << q->mouseGrabberItem() << "->" << grabber;
- QQuickItem *oldGrabber = q->mouseGrabberItem();
- bool fromTouch = false;
-
- if (grabber && touchMouseId != -1 && touchMouseDevice) {
- // update the touch item for mouse touch id to the new grabber
- qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << touchMouseId << "->" << q->mouseGrabberItem();
- auto point = pointerEventInstance(touchMouseDevice)->pointById(touchMouseId);
- if (point)
- point->setGrabber(grabber);
- fromTouch = true;
- } else {
- QQuickPointerEvent *event = pointerEventInstance(QQuickPointerDevice::genericMouseDevice());
- Q_ASSERT(event->pointCount() == 1);
- event->point(0)->setGrabber(grabber);
- }
-
- if (oldGrabber) {
- QEvent e(QEvent::UngrabMouse);
- QSet<QQuickItem *> hasFiltered;
- if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered)) {
- oldGrabber->mouseUngrabEvent();
- if (fromTouch)
- oldGrabber->touchUngrabEvent();
- }
- }
-}
-
-void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVector<int> &ids)
+void QQuickWindowPrivate::grabTouchPoints(QObject *grabber, const QVector<int> &ids)
{
- QSet<QQuickItem*> ungrab;
+ QQuickPointerEvent *ev = nullptr;
for (int i = 0; i < ids.count(); ++i) {
- // FIXME: deprecate this function, we need a device
int id = ids.at(i);
if (Q_UNLIKELY(id < 0)) {
qWarning("ignoring grab of touchpoint %d", id);
@@ -786,54 +787,90 @@ void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVector<int
}
if (id == touchMouseId) {
auto point = pointerEventInstance(touchMouseDevice)->pointById(id);
- auto touchMouseGrabber = point->grabber();
+ auto touchMouseGrabber = point->grabberItem();
if (touchMouseGrabber) {
- point->setGrabber(nullptr);
+ point->setExclusiveGrabber(nullptr);
touchMouseGrabber->mouseUngrabEvent();
- ungrab.insert(touchMouseGrabber);
- touchMouseDevice = nullptr;
- touchMouseId = -1;
+ touchMouseGrabber->touchUngrabEvent();
+ cancelTouchMouseSynthesis();
}
qCDebug(DBG_MOUSE_TARGET) << "grabTouchPoints: mouse grabber changed due to grabTouchPoints:" << touchMouseGrabber << "-> null";
}
+ // optimization to avoid the loop over devices below:
+ // all ids are probably from the same event, so we don't have to search
+ if (ev) {
+ auto point = ev->pointById(id);
+ if (point && point->exclusiveGrabber() != grabber) {
+ point->setExclusiveGrabber(grabber);
+ continue; // next id in the ids loop
+ }
+ }
+ // search all devices for a QQuickPointerEvent instance that is delivering the point with id
const auto touchDevices = QQuickPointerDevice::touchDevices();
for (auto device : touchDevices) {
- auto point = pointerEventInstance(device)->pointById(id);
- if (!point)
- continue;
- QQuickItem *oldGrabber = point->grabber();
- if (oldGrabber == grabber)
- continue;
-
- point->setGrabber(grabber);
- if (oldGrabber)
- ungrab.insert(oldGrabber);
+ QQuickPointerEvent *pev = pointerEventInstance(device);
+ auto point = pev->pointById(id);
+ if (point) {
+ ev = pev;
+ if (point->exclusiveGrabber() != grabber)
+ point->setExclusiveGrabber(grabber);
+ break; // out of touchDevices loop
+ }
}
}
- for (QQuickItem *oldGrabber : qAsConst(ungrab))
- oldGrabber->touchUngrabEvent();
}
+/*!
+ Ungrabs all touchpoint grabs and/or the mouse grab from the given item \a grabber.
+ This should not be called when processing a release event - that's redundant.
+ It is called in other cases, when the points may not be released, but the item
+ nevertheless must lose its grab due to becoming disabled, invisible, etc.
+ QQuickEventPoint::setGrabberItem() calls touchUngrabEvent() when all points are released,
+ but if not all points are released, it cannot be sure whether to call touchUngrabEvent()
+ or not; so we have to do it here.
+*/
void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool touch)
{
Q_Q(QQuickWindow);
if (Q_LIKELY(mouse) && q->mouseGrabberItem() == grabber) {
- qCDebug(DBG_MOUSE_TARGET) << "removeGrabber" << q->mouseGrabberItem() << "-> null";
- setMouseGrabber(nullptr);
+ bool fromTouch = isDeliveringTouchAsMouse();
+ auto point = fromTouch ?
+ pointerEventInstance(touchMouseDevice)->pointById(touchMouseId) :
+ pointerEventInstance(QQuickPointerDevice::genericMouseDevice())->point(0);
+ QQuickItem *oldGrabber = point->grabberItem();
+ qCDebug(DBG_MOUSE_TARGET) << "removeGrabber" << oldGrabber << "-> null";
+ point->setGrabberItem(nullptr);
+ sendUngrabEvent(oldGrabber, fromTouch);
}
if (Q_LIKELY(touch)) {
+ bool ungrab = false;
const auto touchDevices = QQuickPointerDevice::touchDevices();
for (auto device : touchDevices) {
- auto pointerEvent = pointerEventInstance(device);
- for (int i = 0; i < pointerEvent->pointCount(); ++i) {
- if (pointerEvent->point(i)->grabber() == grabber) {
- pointerEvent->point(i)->setGrabber(nullptr);
- // FIXME send ungrab event only once
- grabber->touchUngrabEvent();
+ if (auto pointerEvent = queryPointerEventInstance(device)) {
+ for (int i = 0; i < pointerEvent->pointCount(); ++i) {
+ if (pointerEvent->point(i)->exclusiveGrabber() == grabber) {
+ pointerEvent->point(i)->setGrabberItem(nullptr);
+ ungrab = true;
+ }
}
}
}
+ if (ungrab)
+ grabber->touchUngrabEvent();
+ }
+}
+
+void QQuickWindowPrivate::sendUngrabEvent(QQuickItem *grabber, bool touch)
+{
+ if (!grabber)
+ return;
+ QEvent e(QEvent::UngrabMouse);
+ hasFiltered.clear();
+ if (!sendFilteredMouseEvent(&e, grabber, grabber->parentItem())) {
+ grabber->mouseUngrabEvent();
+ if (touch)
+ grabber->touchUngrabEvent();
}
}
@@ -880,12 +917,12 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
qCDebug(DBG_FOCUS) << " item:" << (QObject *)item;
qCDebug(DBG_FOCUS) << " activeFocusItem:" << (QObject *)activeFocusItem;
- QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
+ QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : nullptr;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- QQuickItem *oldActiveFocusItem = 0;
+ QQuickItem *oldActiveFocusItem = nullptr;
QQuickItem *currentActiveFocusItem = activeFocusItem;
- QQuickItem *newActiveFocusItem = 0;
+ QQuickItem *newActiveFocusItem = nullptr;
bool sendFocusIn = false;
lastFocusReason = reason;
@@ -911,7 +948,7 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
QGuiApplication::inputMethod()->commit();
#endif
- activeFocusItem = 0;
+ activeFocusItem = nullptr;
QQuickItem *afi = oldActiveFocusItem;
while (afi && afi != scope) {
@@ -991,7 +1028,7 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
qCDebug(DBG_FOCUS) << " item:" << (QObject *)item;
qCDebug(DBG_FOCUS) << " activeFocusItem:" << (QObject *)activeFocusItem;
- QQuickItemPrivate *scopePrivate = 0;
+ QQuickItemPrivate *scopePrivate = nullptr;
if (scope) {
scopePrivate = QQuickItemPrivate::get(scope);
if ( !scopePrivate->subFocusItem )
@@ -999,8 +1036,8 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
}
QQuickItem *currentActiveFocusItem = activeFocusItem;
- QQuickItem *oldActiveFocusItem = 0;
- QQuickItem *newActiveFocusItem = 0;
+ QQuickItem *oldActiveFocusItem = nullptr;
+ QQuickItem *newActiveFocusItem = nullptr;
lastFocusReason = reason;
@@ -1017,7 +1054,7 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
QGuiApplication::inputMethod()->commit();
#endif
- activeFocusItem = 0;
+ activeFocusItem = nullptr;
if (oldActiveFocusItem) {
QQuickItem *afi = oldActiveFocusItem;
@@ -1123,7 +1160,7 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
\instantiates QQuickWindow
\inqmlmodule QtQuick.Window
\ingroup qtquick-visual
- \brief Creates a new top-level window
+ \brief Creates a new top-level window.
The Window object creates a new top-level window for a Qt Quick scene. It automatically sets up the
window for use with \c {QtQuick 2.x} graphical types.
@@ -1160,7 +1197,7 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
\inmodule QtQuick
- \brief The QQuickWindow class provides the window for displaying a graphical QML scene
+ \brief The QQuickWindow class provides the window for displaying a graphical QML scene.
QQuickWindow provides the graphical scene management needed to interact with and display
a scene of QQuickItems.
@@ -1228,7 +1265,7 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
\note All classes with QSG prefix should be used solely on the scene graph's
rendering thread. See \l {Scene Graph and Rendering} for more information.
- \section2 Context and surface formats
+ \section2 Context and Surface Formats
While it is possible to specify a QSurfaceFormat for every QQuickWindow by
calling the member function setFormat(), windows may also be created from
@@ -1266,13 +1303,21 @@ QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent)
\internal
*/
QQuickWindow::QQuickWindow(QQuickRenderControl *control)
- : QWindow(*(new QQuickWindowPrivate), 0)
+ : QWindow(*(new QQuickWindowPrivate), nullptr)
{
Q_D(QQuickWindow);
d->init(this, control);
}
-
+/*!
+ \internal
+*/
+QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control)
+ : QWindow(dd, nullptr)
+{
+ Q_D(QQuickWindow);
+ d->init(this, control);
+}
/*!
Destroys the window.
@@ -1288,11 +1333,15 @@ QQuickWindow::~QQuickWindow()
d->windowManager->windowDestroyed(this);
}
- delete d->incubationController; d->incubationController = 0;
+ delete d->incubationController; d->incubationController = nullptr;
#if QT_CONFIG(draganddrop)
- delete d->dragGrabber; d->dragGrabber = 0;
+ delete d->dragGrabber; d->dragGrabber = nullptr;
#endif
- delete d->contentItem; d->contentItem = 0;
+ QQuickRootItem *root = d->contentItem;
+ d->contentItem = nullptr;
+ delete root;
+ qDeleteAll(d->pointerEventInstances);
+ d->pointerEventInstances.clear();
d->renderJobMutex.lock();
qDeleteAll(d->beforeSynchronizingJobs);
@@ -1493,16 +1542,16 @@ QQuickItem *QQuickWindow::mouseGrabberItem() const
{
Q_D(const QQuickWindow);
- if (d->touchMouseId != -1 && d->touchMouseDevice) {
- QQuickPointerEvent *event = d->pointerEventInstance(d->touchMouseDevice);
- auto point = event->pointById(d->touchMouseId);
- Q_ASSERT(point);
- return point->grabber();
+ if (d->isDeliveringTouchAsMouse()) {
+ if (QQuickPointerEvent *event = d->queryPointerEventInstance(d->touchMouseDevice)) {
+ auto point = event->pointById(d->touchMouseId);
+ return point ? point->grabberItem() : nullptr;
+ }
+ } else if (QQuickPointerEvent *event = d->queryPointerEventInstance(QQuickPointerDevice::genericMouseDevice())) {
+ Q_ASSERT(event->pointCount());
+ return event->point(0)->grabberItem();
}
-
- QQuickPointerEvent *event = d->pointerEventInstance(QQuickPointerDevice::genericMouseDevice());
- Q_ASSERT(event->pointCount());
- return event->point(0)->grabber();
+ return nullptr;
}
@@ -1515,8 +1564,20 @@ bool QQuickWindowPrivate::clearHover(ulong timestamp)
QPointF pos = q->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
bool accepted = false;
- for (QQuickItem* item : qAsConst(hoverItems))
+ for (QQuickItem* item : qAsConst(hoverItems)) {
accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), timestamp, true) || accepted;
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ if (itemPrivate->hasPointerHandlers()) {
+ pos = q->mapFromGlobal(QCursor::pos());
+ QQuickPointerEvent *pointerEvent = pointerEventInstance(QQuickPointerDevice::genericMouseDevice(), QEvent::MouseMove);
+ pointerEvent->point(0)->reset(Qt::TouchPointMoved, pos, quint64(1) << 24 /* mouse has device ID 1 */, timestamp, QVector2D());
+ pointerEvent->point(0)->setAccepted(true);
+ pointerEvent->localize(item);
+ for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers)
+ if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h))
+ hh->handlePointerEvent(pointerEvent);
+ }
+ }
hoverItems.clear();
return accepted;
}
@@ -1546,11 +1607,15 @@ bool QQuickWindow::event(QEvent *e)
return d->deliverTouchCancelEvent(static_cast<QTouchEvent*>(e));
break;
case QEvent::Enter: {
+ if (!d->contentItem)
+ return false;
QEnterEvent *enter = static_cast<QEnterEvent*>(e);
bool accepted = enter->isAccepted();
bool delivered = d->deliverHoverEvent(d->contentItem, enter->windowPos(), d->lastMousePosition,
QGuiApplication::keyboardModifiers(), 0L, accepted);
+ d->lastMousePosition = enter->windowPos();
enter->setAccepted(accepted);
+ d->updateCursor(mapFromGlobal(QCursor::pos()));
return delivered;
}
break;
@@ -1567,7 +1632,8 @@ bool QQuickWindow::event(QEvent *e)
break;
#endif
case QEvent::WindowDeactivate:
- contentItem()->windowDeactivateEvent();
+ if (d->contentItem)
+ d->contentItem->windowDeactivateEvent();
break;
case QEvent::Close: {
// TOOD Qt 6 (binary incompatible)
@@ -1577,6 +1643,14 @@ bool QQuickWindow::event(QEvent *e)
emit closing(&qev);
e->setAccepted(qev.isAccepted());
} break;
+ case QEvent::PlatformSurface:
+ if ((static_cast<QPlatformSurfaceEvent *>(e))->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
+ // Ensure that the rendering thread is notified before
+ // the QPlatformWindow is destroyed.
+ if (d->windowManager)
+ d->windowManager->hide(this);
+ }
+ break;
case QEvent::FocusAboutToChange:
#if QT_CONFIG(im)
if (d->activeFocusItem)
@@ -1592,7 +1666,7 @@ bool QQuickWindow::event(QEvent *e)
}
#if QT_CONFIG(gestures)
case QEvent::NativeGesture:
- d->deliverNativeGestureEvent(d->contentItem, static_cast<QNativeGestureEvent*>(e));
+ d->deliverSinglePointEventUntilAccepted(d->pointerEventInstance(e));
break;
#endif
case QEvent::ShortcutOverride:
@@ -1629,10 +1703,15 @@ void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
void QQuickWindowPrivate::deliverKeyEvent(QKeyEvent *e)
{
- Q_Q(QQuickWindow);
-
- if (activeFocusItem)
- q->sendEvent(activeFocusItem, e);
+ if (activeFocusItem) {
+ QQuickItem *item = activeFocusItem;
+ e->accept();
+ QCoreApplication::sendEvent(item, e);
+ while (!e->isAccepted() && (item = item->parentItem())) {
+ e->accept();
+ QCoreApplication::sendEvent(item, e);
+ }
+ }
}
QMouseEvent *QQuickWindowPrivate::cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos)
@@ -1649,38 +1728,113 @@ QMouseEvent *QQuickWindowPrivate::cloneMouseEvent(QMouseEvent *event, QPointF *t
return me;
}
+void QQuickWindowPrivate::deliverToPassiveGrabbers(const QVector<QPointer <QQuickPointerHandler> > &passiveGrabbers,
+ QQuickPointerEvent *pointerEvent)
+{
+ const QVector<QQuickPointerHandler *> &eventDeliveryTargets = pointerEvent->device()->eventDeliveryTargets();
+ QVarLengthArray<QPair<QQuickItem *, bool>, 4> sendFilteredPointerEventResult;
+ hasFiltered.clear();
+ for (auto handler : passiveGrabbers) {
+ // a null pointer in passiveGrabbers is unlikely, unless the grabbing handler was deleted dynamically
+ if (Q_LIKELY(handler) && !eventDeliveryTargets.contains(handler)) {
+ bool alreadyFiltered = false;
+ QQuickItem *par = handler->parentItem();
+
+ // see if we already have sent a filter event to the parent
+ auto it = std::find_if(sendFilteredPointerEventResult.begin(), sendFilteredPointerEventResult.end(),
+ [par](const QPair<QQuickItem *, bool> &pair) { return pair.first == par; });
+ if (it != sendFilteredPointerEventResult.end()) {
+ // Yes, the event was already filtered to that parent, do not call it again but use
+ // the result of the previous call to determine if we should call the handler.
+ alreadyFiltered = it->second;
+ } else {
+ alreadyFiltered = sendFilteredPointerEvent(pointerEvent, par);
+ sendFilteredPointerEventResult << qMakePair<QQuickItem*, bool>(par, alreadyFiltered);
+ }
+ if (!alreadyFiltered) {
+ pointerEvent->localize(handler->parentItem());
+ handler->handlePointerEvent(pointerEvent);
+ }
+ }
+ }
+}
+
+
+
void QQuickWindowPrivate::deliverMouseEvent(QQuickPointerMouseEvent *pointerEvent)
{
Q_Q(QQuickWindow);
auto point = pointerEvent->point(0);
- lastMousePosition = point->scenePos();
- QQuickItem *grabber = point->grabber();
- if (grabber) {
- // if the update consists of changing button state, then don't accept it
- // unless the button is one in which the item is interested
- if (pointerEvent->button() != Qt::NoButton
- && grabber->acceptedMouseButtons()
- && !(grabber->acceptedMouseButtons() & pointerEvent->button())) {
+ lastMousePosition = point->scenePosition();
+ const bool mouseIsReleased = (point->state() == QQuickEventPoint::Released && pointerEvent->buttons() == Qt::NoButton);
+ QQuickItem *grabberItem = point->grabberItem();
+ if (!grabberItem && isDeliveringTouchAsMouse())
+ grabberItem = q->mouseGrabberItem();
+
+ if (grabberItem) {
+ bool handled = false;
+ hasFiltered.clear();
+ if (sendFilteredPointerEvent(pointerEvent, grabberItem))
+ handled = true;
+ // if the grabber is an Item:
+ // if the update consists of changing button state, don't accept it unless
+ // the button is one in which the grabber is interested
+ Qt::MouseButtons acceptedButtons = grabberItem->acceptedMouseButtons();
+ if (!handled && pointerEvent->button() != Qt::NoButton && acceptedButtons
+ && !(acceptedButtons & pointerEvent->button())) {
pointerEvent->setAccepted(false);
- return;
+ handled = true;
}
// send update
- QPointF localPos = grabber->mapFromScene(lastMousePosition);
- auto me = pointerEvent->asMouseEvent(localPos);
- me->accept();
- q->sendEvent(grabber, me);
- point->setAccepted(me->isAccepted());
-
- // release event, make sure to ungrab if there still is a grabber
- if (me->type() == QEvent::MouseButtonRelease && !me->buttons() && q->mouseGrabberItem())
- q->mouseGrabberItem()->ungrabMouse();
+ if (!handled) {
+ QPointF localPos = grabberItem->mapFromScene(lastMousePosition);
+ auto me = pointerEvent->asMouseEvent(localPos);
+ me->accept();
+ QCoreApplication::sendEvent(grabberItem, me);
+ point->setAccepted(me->isAccepted());
+ }
+
+ // release event: ungrab if no buttons are pressed anymore
+ if (mouseIsReleased)
+ removeGrabber(grabberItem, true, isDeliveringTouchAsMouse());
+ deliverToPassiveGrabbers(point->passiveGrabbers(), pointerEvent);
+ } else if (auto handler = point->grabberPointerHandler()) {
+ pointerEvent->localize(handler->parentItem());
+ hasFiltered.clear();
+ if (!sendFilteredPointerEvent(pointerEvent, handler->parentItem()))
+ handler->handlePointerEvent(pointerEvent);
+ if (mouseIsReleased)
+ point->setGrabberPointerHandler(nullptr, true);
+ deliverToPassiveGrabbers(point->passiveGrabbers(), pointerEvent);
} else {
- // send initial press
bool delivered = false;
if (pointerEvent->isPressEvent()) {
- QSet<QQuickItem*> hasFiltered;
- delivered = deliverPressEvent(pointerEvent, &hasFiltered);
+ // send initial press
+ delivered = deliverPressOrReleaseEvent(pointerEvent);
+ } else if (pointerEvent->device()->type() == QQuickPointerDevice::Mouse) {
+ // if this is an update or release from an actual mouse,
+ // and the point wasn't grabbed, deliver only to PointerHandlers:
+ // passive grabbers first, then the rest
+ deliverToPassiveGrabbers(point->passiveGrabbers(), pointerEvent);
+
+ // If some points weren't grabbed, deliver to non-grabber PointerHandlers in reverse paint order
+ if (!pointerEvent->allPointsGrabbed() && pointerEvent->buttons()) {
+ QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point, false, false);
+ for (QQuickItem *item : targetItems) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ if (!itemPrivate->extra.isAllocated() || itemPrivate->extra->pointerHandlers.isEmpty())
+ continue;
+ pointerEvent->localize(item);
+ hasFiltered.clear();
+ if (!sendFilteredPointerEvent(pointerEvent, item)) {
+ if (itemPrivate->handlePointerEvent(pointerEvent, true)) // avoid re-delivering to grabbers
+ delivered = true;
+ }
+ if (point->exclusiveGrabber())
+ break;
+ }
+ }
}
if (!delivered)
@@ -1701,10 +1855,9 @@ bool QQuickWindowPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
hoverEvent.setTimestamp(timestamp);
hoverEvent.setAccepted(accepted);
- QSet<QQuickItem *> hasFiltered;
- if (sendFilteredMouseEvent(item->parentItem(), item, &hoverEvent, &hasFiltered)) {
+ hasFiltered.clear();
+ if (sendFilteredMouseEvent(&hoverEvent, item, item->parentItem()))
return true;
- }
QCoreApplication::sendEvent(item, &hoverEvent);
@@ -1735,6 +1888,16 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
}
}
+ if (itemPrivate->hasPointerHandlers()) {
+ QQuickPointerEvent *pointerEvent = pointerEventInstance(QQuickPointerDevice::genericMouseDevice(), QEvent::MouseMove);
+ pointerEvent->point(0)->reset(Qt::TouchPointMoved, scenePos, quint64(1) << 24 /* mouse has device ID 1 */, timestamp, QVector2D());
+ pointerEvent->point(0)->setAccepted(true);
+ pointerEvent->localize(item);
+ for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers)
+ if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h))
+ hh->handlePointerEvent(pointerEvent);
+ }
+
if (itemPrivate->hoverEnabled) {
QPointF p = item->mapFromScene(scenePos);
if (item->contains(p)) {
@@ -1787,43 +1950,57 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
return false;
}
-#if QT_CONFIG(wheelevent)
-bool QQuickWindowPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
+// Simple delivery of non-mouse, non-touch Pointer Events: visit the items and handlers
+// in the usual reverse-paint-order until propagation is stopped
+bool QQuickWindowPrivate::deliverSinglePointEventUntilAccepted(QQuickPointerEvent *event)
{
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QPointF p = item->mapFromScene(event->posF());
- if (!item->contains(p))
- return false;
- }
-
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
- continue;
- if (deliverWheelEvent(child, event))
- return true;
- }
+ Q_ASSERT(event->pointCount() == 1);
+ QQuickEventPoint *point = event->point(0);
+ QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point, false, false);
- QPointF p = item->mapFromScene(event->posF());
-
- if (item->contains(p)) {
- QWheelEvent wheel(p, event->globalPosF(), event->pixelDelta(), event->angleDelta(), event->delta(),
- event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted());
- wheel.setTimestamp(event->timestamp());
- wheel.accept();
- QCoreApplication::sendEvent(item, &wheel);
- if (wheel.isAccepted()) {
- event->accept();
+ for (QQuickItem *item : targetItems) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ event->localize(item);
+ // Let Pointer Handlers have the first shot
+ itemPrivate->handlePointerEvent(event);
+ if (point->isAccepted())
return true;
+ QPointF g = item->window()->mapToGlobal(point->scenePosition().toPoint());
+#if QT_CONFIG(wheelevent)
+ // Let the Item have a chance to handle it
+ if (QQuickPointerScrollEvent *pse = event->asPointerScrollEvent()) {
+ QWheelEvent wheel(point->position(), g, pse->pixelDelta().toPoint(), pse->angleDelta().toPoint(),
+ pse->buttons(), pse->modifiers(), pse->phase(),
+ pse->isInverted(), pse->synthSource());
+ wheel.setTimestamp(pse->timestamp());
+ wheel.accept();
+ QCoreApplication::sendEvent(item, &wheel);
+ if (wheel.isAccepted()) {
+ qCDebug(lcWheelTarget) << &wheel << "->" << item;
+ event->setAccepted(true);
+ return true;
+ }
}
+#endif
+#if QT_CONFIG(gestures)
+ if (QQuickPointerNativeGestureEvent *pnge = event->asPointerNativeGestureEvent()) {
+ QNativeGestureEvent nge(pnge->type(), pnge->device()->qTouchDevice(), point->position(), point->scenePosition(), g,
+ pnge->value(), 0L, 0L); // TODO can't copy things I can't access
+ nge.accept();
+ QCoreApplication::sendEvent(item, &nge);
+ if (nge.isAccepted()) {
+ qCDebug(lcGestureTarget) << &nge << "->" << item;
+ event->setAccepted(true);
+ return true;
+ }
+ }
+#endif // gestures
}
- return false;
+ return false; // it wasn't handled
}
+#if QT_CONFIG(wheelevent)
/*! \reimp */
void QQuickWindow::wheelEvent(QWheelEvent *event)
{
@@ -1838,64 +2015,27 @@ void QQuickWindow::wheelEvent(QWheelEvent *event)
return;
event->ignore();
- d->deliverWheelEvent(d->contentItem, event);
+ d->deliverPointerEvent(d->pointerEventInstance(event));
d->lastWheelEventAccepted = event->isAccepted();
}
#endif // wheelevent
-#if QT_CONFIG(gestures)
-bool QQuickWindowPrivate::deliverNativeGestureEvent(QQuickItem *item, QNativeGestureEvent *event)
-{
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- if ((itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) && !item->contains(event->localPos()))
- return false;
-
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
- continue;
- if (deliverNativeGestureEvent(child, event))
- return true;
- }
-
- QPointF p = item->mapFromScene(event->localPos());
-
- if (item->contains(p)) {
- QNativeGestureEvent copy(event->gestureType(), p, event->windowPos(), event->screenPos(),
- event->value(), 0L, 0L); // TODO can't copy things I can't access
- event->accept();
- item->event(&copy);
- if (copy.isAccepted()) {
- event->accept();
- return true;
- }
- }
-
- return false;
-}
-#endif // gestures
-
bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event)
{
qCDebug(DBG_TOUCH) << event;
Q_Q(QQuickWindow);
- // A TouchCancel event will typically not contain any points.
- // Deliver it to all items that have active touches.
- QQuickPointerEvent *pointerEvent = pointerEventInstance(QQuickPointerDevice::touchDevice(event->device()));
- QVector<QQuickItem *> grabbers = pointerEvent->grabbers();
-
- for (QQuickItem *grabber: qAsConst(grabbers)) {
- q->sendEvent(grabber, event);
- }
- touchMouseId = -1;
- touchMouseDevice = nullptr;
if (q->mouseGrabberItem())
q->mouseGrabberItem()->ungrabMouse();
+ cancelTouchMouseSynthesis();
+
+ // A TouchCancel event will typically not contain any points.
+ // Deliver it to all items and handlers that have active touches.
+ QQuickPointerEvent *pointerEvent = pointerEventInstance(QQuickPointerDevice::touchDevice(event->device()));
+ for (int i = 0; i < pointerEvent->pointCount(); ++i)
+ pointerEvent->point(i)->cancelExclusiveGrabImpl(event);
- // The next touch event can only be a TouchBegin so clean up.
+ // The next touch event can only be a TouchBegin, so clean up.
pointerEvent->clearGrabbers();
return true;
}
@@ -2032,8 +2172,6 @@ void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event)
{
- Q_Q(QQuickWindow);
-
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
event->accept();
return;
@@ -2054,7 +2192,8 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event)
case QEvent::MouseButtonDblClick:
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
event->button(), event->buttons());
- deliverPointerEvent(pointerEventInstance(event));
+ if (allowDoubleClick)
+ deliverPointerEvent(pointerEventInstance(event));
break;
case QEvent::MouseMove:
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove,
@@ -2066,7 +2205,7 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event)
updateCursor(event->windowPos());
#endif
- if (!q->mouseGrabberItem()) {
+ if (!pointerEventInstance(QQuickPointerDevice::genericMouseDevice())->point(0)->exclusiveGrabber()) {
QPointF last = lastMousePosition.isNull() ? event->windowPos() : lastMousePosition;
lastMousePosition = event->windowPos();
@@ -2077,7 +2216,6 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event)
accepted = clearHover(event->timestamp());
}
event->setAccepted(accepted);
- return;
}
deliverPointerEvent(pointerEventInstance(event));
break;
@@ -2114,23 +2252,51 @@ void QQuickWindowPrivate::flushFrameSynchronousEvents()
}
}
-QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevice *device) const
+QQuickPointerEvent *QQuickWindowPrivate::queryPointerEventInstance(QQuickPointerDevice *device, QEvent::Type eventType) const
{
- // the list of devices should be very small so a linear search should be ok
- for (QQuickPointerEvent *e: pointerEventInstances) {
+ // Search for a matching reusable event object.
+ for (QQuickPointerEvent *e : pointerEventInstances) {
+ // If device can generate native gestures (e.g. a trackpad), there might be multiple QQuickPointerEvents:
+ // QQuickPointerNativeGestureEvent, QQuickPointerScrollEvent, and QQuickPointerTouchEvent.
+ // Use eventType to disambiguate.
+#if QT_CONFIG(gestures)
+ if ((eventType == QEvent::NativeGesture) != bool(e->asPointerNativeGestureEvent()))
+ continue;
+#endif
+ if ((eventType == QEvent::Wheel) != bool(e->asPointerScrollEvent()))
+ continue;
+ // Otherwise we assume there's only one event type per device.
+ // More disambiguation tests might need to be added above if that changes later.
if (e->device() == device)
return e;
}
+ return nullptr;
+}
- QQuickPointerEvent *ev = nullptr;
+QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevice *device, QEvent::Type eventType) const
+{
+ QQuickPointerEvent *ev = queryPointerEventInstance(device, eventType);
+ if (ev)
+ return ev;
QQuickWindow *q = const_cast<QQuickWindow*>(q_func());
switch (device->type()) {
case QQuickPointerDevice::Mouse:
- ev = new QQuickPointerMouseEvent(q, device);
+ // QWindowSystemInterface::handleMouseEvent() does not take a device parameter:
+ // we assume all mouse events come from one mouse (the "core pointer").
+ // So when the event is a mouse event, device == QQuickPointerDevice::genericMouseDevice()
+ if (eventType == QEvent::Wheel)
+ ev = new QQuickPointerScrollEvent(q, device);
+ else
+ ev = new QQuickPointerMouseEvent(q, device);
break;
case QQuickPointerDevice::TouchPad:
case QQuickPointerDevice::TouchScreen:
- ev = new QQuickPointerTouchEvent(q, device);
+#if QT_CONFIG(gestures)
+ if (eventType == QEvent::NativeGesture)
+ ev = new QQuickPointerNativeGestureEvent(q, device);
+ else // assume QEvent::Type is one of TouchBegin/Update/End
+#endif
+ ev = new QQuickPointerTouchEvent(q, device);
break;
default:
// TODO tablet event types
@@ -2150,44 +2316,55 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevic
QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) const
{
QQuickPointerDevice *dev = nullptr;
- QQuickPointerEvent *ev = nullptr;
switch (event->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
+ case QEvent::Wheel:
dev = QQuickPointerDevice::genericMouseDevice();
- ev = pointerEventInstance(dev);
break;
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
case QEvent::TouchCancel:
dev = QQuickPointerDevice::touchDevice(static_cast<QTouchEvent *>(event)->device());
- ev = pointerEventInstance(dev);
break;
// TODO tablet event types
+#if QT_CONFIG(gestures)
+ case QEvent::NativeGesture:
+ dev = QQuickPointerDevice::touchDevice(static_cast<QNativeGestureEvent *>(event)->device());
+ break;
+#endif
default:
break;
}
- Q_ASSERT(ev);
- return ev->reset(event);
+ Q_ASSERT(dev);
+ return pointerEventInstance(dev, event->type())->reset(event);
}
void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event)
{
+ Q_Q(QQuickWindow);
// If users spin the eventloop as a result of event delivery, we disable
// event compression and send events directly. This is because we consider
// the usecase a bit evil, but we at least don't want to lose events.
++pointerEventRecursionGuard;
+ skipDelivery.clear();
if (event->asPointerMouseEvent()) {
deliverMouseEvent(event->asPointerMouseEvent());
+ // failsafe: never allow any kind of grab to persist after release
+ if (event->isReleaseEvent() && event->buttons() == Qt::NoButton) {
+ QQuickItem *oldGrabber = q->mouseGrabberItem();
+ event->clearGrabbers();
+ sendUngrabEvent(oldGrabber, false);
+ }
} else if (event->asPointerTouchEvent()) {
deliverTouchEvent(event->asPointerTouchEvent());
} else {
- Q_ASSERT(false);
+ deliverSinglePointEventUntilAccepted(event);
}
event->reset(nullptr);
@@ -2195,13 +2372,16 @@ void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event)
--pointerEventRecursionGuard;
}
-// check if item or any of its child items contain the point
+// check if item or any of its child items contain the point, or if any pointer handler "wants" the point
// FIXME: should this be iterative instead of recursive?
-QVector<QQuickItem *> QQuickWindowPrivate::pointerTargets(QQuickItem *item, const QPointF &scenePos, bool checkMouseButtons) const
+// If checkMouseButtons is true, it means we are finding targets for a mouse event, so no item for which acceptedMouseButtons() is NoButton will be added.
+// If checkAcceptsTouch is true, it means we are finding targets for a touch event, so either acceptTouchEvents() must return true OR
+// it must accept a synth. mouse event, thus if acceptTouchEvents() returns false but acceptedMouseButtons() is true, gets added; if not, it doesn't.
+QVector<QQuickItem *> QQuickWindowPrivate::pointerTargets(QQuickItem *item, QQuickEventPoint *point, bool checkMouseButtons, bool checkAcceptsTouch) const
{
QVector<QQuickItem *> targets;
auto itemPrivate = QQuickItemPrivate::get(item);
- QPointF itemPos = item->mapFromScene(scenePos);
+ QPointF itemPos = item->mapFromScene(point->scenePosition());
// if the item clips, we can potentially return early
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
if (!item->contains(itemPos))
@@ -2215,13 +2395,22 @@ QVector<QQuickItem *> QQuickWindowPrivate::pointerTargets(QQuickItem *item, cons
auto childPrivate = QQuickItemPrivate::get(child);
if (!child->isVisible() || !child->isEnabled() || childPrivate->culled)
continue;
- targets << pointerTargets(child, scenePos, false);
+ targets << pointerTargets(child, point, checkMouseButtons, checkAcceptsTouch);
}
- if (item->contains(itemPos) && (!checkMouseButtons || itemPrivate->acceptedMouseButtons())) {
- // add this item last - children take precedence
- targets << item;
+ bool relevant = item->contains(itemPos);
+ if (itemPrivate->hasPointerHandlers()) {
+ if (!relevant)
+ if (itemPrivate->anyPointerHandlerWants(point))
+ relevant = true;
+ } else {
+ if (relevant && checkMouseButtons && item->acceptedMouseButtons() == Qt::NoButton)
+ relevant = false;
+ if (relevant && checkAcceptsTouch && !(item->acceptTouchEvents() || item->acceptedMouseButtons()))
+ relevant = false;
}
+ if (relevant)
+ targets << item; // add this item last: children take precedence
return targets;
}
@@ -2251,11 +2440,12 @@ void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerTouchEvent *event)
{
qCDebug(DBG_TOUCH) << " - delivering" << event->asTouchEvent();
- QSet<QQuickItem *> hasFiltered;
if (event->isPressEvent())
- deliverPressEvent(event, &hasFiltered);
- if (!event->allPointsAccepted())
- deliverUpdatedTouchPoints(event, &hasFiltered);
+ deliverPressOrReleaseEvent(event);
+ if (!event->allUpdatedPointsAccepted())
+ deliverUpdatedTouchPoints(event);
+ if (event->isReleaseEvent())
+ deliverPressOrReleaseEvent(event, true);
// Remove released points from itemForTouchPointId
bool allReleased = true;
@@ -2265,39 +2455,113 @@ void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerTouchEvent *event)
if (point->state() == QQuickEventPoint::Released) {
int id = point->pointId();
qCDebug(DBG_TOUCH_TARGET) << "TP" << hex << id << "released";
- point->setGrabber(nullptr);
- if (id == touchMouseId) {
- touchMouseId = -1;
- touchMouseDevice = nullptr;
- }
+ point->setGrabberItem(nullptr);
+ if (id == touchMouseId)
+ cancelTouchMouseSynthesis();
} else {
allReleased = false;
}
}
- if (allReleased && !event->grabbers().isEmpty()) {
- qWarning() << "No release received for some grabbers" << event->grabbers();
+ if (allReleased) {
+ if (Q_UNLIKELY(!event->exclusiveGrabbers().isEmpty()))
+ qWarning() << "No release received for some grabbers" << event->exclusiveGrabbers();
event->clearGrabbers();
}
}
// Deliver touch points to existing grabbers
-bool QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *event, QSet<QQuickItem *> *hasFiltered)
-{
- const auto grabbers = event->grabbers();
- for (auto grabber : grabbers)
- deliverMatchingPointsToItem(grabber, event, hasFiltered);
+void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *event)
+{
+ bool done = false;
+ const auto grabbers = event->exclusiveGrabbers();
+ for (auto grabber : grabbers) {
+ // The grabber is guaranteed to be either an item or a handler.
+ QQuickItem *receiver = qmlobject_cast<QQuickItem *>(grabber);
+ if (!receiver) {
+ // The grabber is not an item? It's a handler then. Let it have the event first.
+ QQuickPointerHandler *handler = static_cast<QQuickPointerHandler *>(grabber);
+ receiver = static_cast<QQuickPointerHandler *>(grabber)->parentItem();
+ hasFiltered.clear();
+ if (sendFilteredPointerEvent(event, receiver))
+ done = true;
+ event->localize(receiver);
+ handler->handlePointerEvent(event);
+ }
+ if (done)
+ break;
+ // If the grabber is an item or the grabbing handler didn't handle it,
+ // then deliver the event to the item (which may have multiple handlers).
+ deliverMatchingPointsToItem(receiver, event);
+ }
- return false;
+ // Deliver to each eventpoint's passive grabbers (but don't visit any handler more than once)
+ int pointCount = event->pointCount();
+ for (int i = 0; i < pointCount; ++i) {
+ QQuickEventPoint *point = event->point(i);
+ deliverToPassiveGrabbers(point->passiveGrabbers(), event);
+ }
+
+ if (done)
+ return;
+
+ // If some points weren't grabbed, deliver only to non-grabber PointerHandlers in reverse paint order
+ if (!event->allPointsGrabbed()) {
+ QVector<QQuickItem *> targetItems;
+ for (int i = 0; i < pointCount; ++i) {
+ QQuickEventPoint *point = event->point(i);
+ if (point->state() == QQuickEventPoint::Pressed)
+ continue; // presses were delivered earlier; not the responsibility of deliverUpdatedTouchPoints
+ QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point, false, false);
+ if (targetItems.count()) {
+ targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
+ } else {
+ targetItems = targetItemsForPoint;
+ }
+ }
+ for (QQuickItem *item : targetItems) {
+ if (grabbers.contains(item))
+ continue;
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ event->localize(item);
+ itemPrivate->handlePointerEvent(event, true); // avoid re-delivering to grabbers
+ if (event->allPointsGrabbed())
+ break;
+ }
+ }
}
-// Deliver newly pressed touch points
-bool QQuickWindowPrivate::deliverPressEvent(QQuickPointerEvent *event, QSet<QQuickItem *> *hasFiltered)
+// Deliver an event containing newly pressed or released touch points
+bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event, bool handlersOnly)
{
- const QVector<QPointF> points = event->unacceptedPressedPointScenePositions();
+ int pointCount = event->pointCount();
QVector<QQuickItem *> targetItems;
- for (QPointF point: points) {
- QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point, false);
+ bool isTouchEvent = (event->asPointerTouchEvent() != nullptr);
+ if (isTouchEvent && event->isPressEvent() && isDeliveringTouchAsMouse()) {
+ if (const QQuickEventPoint *point = pointerEventInstance(touchMouseDevice)->pointById(touchMouseId)) {
+ // When a second point is pressed, if the first point's existing
+ // grabber was a pointer handler while a filtering parent is filtering
+ // the same first point _as mouse_: we're starting over with delivery,
+ // so we need to allow the second point to now be sent as a synth-mouse
+ // instead of the first one, so that filtering parents (maybe even the
+ // same one) can get a chance to see the second touchpoint as a
+ // synth-mouse and perhaps grab it. Ideally we would always do this
+ // when a new touchpoint is pressed, but this compromise fixes
+ // QTBUG-70998 and avoids breaking tst_FlickableInterop::touchDragSliderAndFlickable
+ if (point->grabberPointerHandler())
+ cancelTouchMouseSynthesis();
+ } else {
+ qCWarning(DBG_TOUCH_TARGET) << "during delivery of touch press, synth-mouse ID" << touchMouseId << "is missing from" << event;
+ }
+ }
+ for (int i = 0; i < pointCount; ++i) {
+ auto point = event->point(i);
+ if (point->state() == QQuickEventPoint::Pressed && !event->isDoubleClickEvent())
+ point->clearPassiveGrabbers();
+ point->setAccepted(false); // because otherwise touchEventForItem will ignore it
+ if (point->grabberPointerHandler() && point->state() == QQuickEventPoint::Released)
+ point->setGrabberPointerHandler(nullptr, true);
+ QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point, !isTouchEvent, isTouchEvent);
if (targetItems.count()) {
targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
} else {
@@ -2305,70 +2569,97 @@ bool QQuickWindowPrivate::deliverPressEvent(QQuickPointerEvent *event, QSet<QQui
}
}
- for (QQuickItem *item: targetItems) {
- deliverMatchingPointsToItem(item, event, hasFiltered);
- if (event->allPointsAccepted())
+ for (QQuickItem *item : targetItems) {
+ if (!event->m_event) {
+ qWarning("event went missing during delivery! (nested sendEvent() is not allowed)");
+ break;
+ }
+ hasFiltered.clear();
+ if (!handlersOnly && sendFilteredPointerEvent(event, item)) {
+ if (event->isAccepted()) {
+ for (int i = 0; i < event->pointCount(); ++i)
+ event->point(i)->setAccepted();
+ return true;
+ }
+ skipDelivery.append(item);
+ }
+
+ // Do not deliverMatchingPointsTo any item for which the filtering parent already intercepted the event,
+ // nor to any item which already had a chance to filter.
+ if (skipDelivery.contains(item))
+ continue;
+ if (!event->m_event) {
+ qWarning("event went missing during delivery! (nested sendEvent() is not allowed)");
break;
+ }
+ deliverMatchingPointsToItem(item, event, handlersOnly);
+ if (event->allPointsAccepted())
+ handlersOnly = true;
}
return event->allPointsAccepted();
}
-bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPointerEvent *pointerEvent, QSet<QQuickItem *> *hasFiltered)
+void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPointerEvent *pointerEvent, bool handlersOnly)
{
Q_Q(QQuickWindow);
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ pointerEvent->localize(item);
+
+ // Let the Item's handlers (if any) have the event first.
+ // However, double click should never be delivered to handlers.
+ if (!pointerEvent->isDoubleClickEvent()) {
+ bool wasAccepted = pointerEvent->allPointsAccepted();
+ itemPrivate->handlePointerEvent(pointerEvent);
+ allowDoubleClick = wasAccepted || !(pointerEvent->asPointerMouseEvent() && pointerEvent->isPressEvent() && pointerEvent->allPointsAccepted());
+ }
+ if (handlersOnly)
+ return;
+
+ // If all points are released and the item is not the grabber, it doesn't get the event.
+ // But if at least one point is still pressed, we might be in a potential gesture-takeover scenario.
+ if (pointerEvent->isReleaseEvent() && !pointerEvent->isUpdateEvent()
+ && !pointerEvent->exclusiveGrabbers().contains(item))
+ return;
// TODO: unite this mouse point delivery with the synthetic mouse event below
- if (auto event = pointerEvent->asPointerMouseEvent()) {
- if (item->acceptedMouseButtons() & event->button()) {
+ auto event = pointerEvent->asPointerMouseEvent();
+ if (event && item->acceptedMouseButtons() & event->button()) {
auto point = event->point(0);
- if (point->isAccepted())
- return false;
-
// The only reason to already have a mouse grabber here is
// synthetic events - flickable sends one when setPressDelay is used.
auto oldMouseGrabber = q->mouseGrabberItem();
- QPointF localPos = item->mapFromScene(point->scenePos());
- Q_ASSERT(item->contains(localPos)); // transform is checked already
+ QPointF localPos = item->mapFromScene(point->scenePosition());
QMouseEvent *me = event->asMouseEvent(localPos);
me->accept();
- q->sendEvent(item, me);
+ QCoreApplication::sendEvent(item, me);
if (me->isAccepted()) {
auto mouseGrabber = q->mouseGrabberItem();
if (mouseGrabber && mouseGrabber != item && mouseGrabber != oldMouseGrabber) {
item->mouseUngrabEvent();
- } else {
+ } else if (item->isEnabled() && item->isVisible()) {
item->grabMouse();
}
point->setAccepted(true);
}
- return me->isAccepted();
- }
- return false;
+ return;
}
- QQuickPointerTouchEvent *event = pointerEvent->asPointerTouchEvent();
- if (!event)
- return false;
+ QQuickPointerTouchEvent *ptEvent = pointerEvent->asPointerTouchEvent();
+ if (!ptEvent)
+ return;
- QScopedPointer<QTouchEvent> touchEvent(event->touchEventForItem(item));
+ QScopedPointer<QTouchEvent> touchEvent(ptEvent->touchEventForItem(item));
if (!touchEvent)
- return false;
+ return;
- qCDebug(DBG_TOUCH) << " - considering delivering " << touchEvent.data() << " to " << item;
+ qCDebug(DBG_TOUCH) << "considering delivering " << touchEvent.data() << " to " << item;
bool eventAccepted = false;
- // First check whether the parent wants to be a filter,
- // and if the parent accepts the event we are done.
- if (sendFilteredTouchEvent(item->parentItem(), item, event, hasFiltered)) {
- // If the touch was accepted (regardless by whom or in what form),
- // update acceptedNewPoints
- qCDebug(DBG_TOUCH) << " - can't. intercepted " << touchEvent.data() << " to " << item->parentItem() << " instead of " << item;
- for (auto point: qAsConst(touchEvent->touchPoints())) {
- event->pointById(point.id())->setAccepted();
- }
- return true;
- }
+ // If any parent filters the event, we're done.
+ hasFiltered.clear();
+ if (sendFilteredPointerEvent(pointerEvent, item))
+ return;
// Deliver the touch event to the given item
qCDebug(DBG_TOUCH) << " - actually delivering " << touchEvent.data() << " to " << item;
@@ -2376,36 +2667,39 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo
eventAccepted = touchEvent->isAccepted();
// If the touch event wasn't accepted, synthesize a mouse event and see if the item wants it.
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- if (!eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
- // send mouse event
- if (deliverTouchAsMouse(item, event))
- eventAccepted = true;
+ if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) {
+ if (!eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
+ // send mouse event
+ if (deliverTouchAsMouse(item, ptEvent))
+ eventAccepted = true;
+ }
}
if (eventAccepted) {
// 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())) {
- auto pointerEventPoint = event->pointById(point.id());
- pointerEventPoint->setAccepted();
- if (point.state() == Qt::TouchPointPressed)
- pointerEventPoint->setGrabber(item);
+ if (auto pointerEventPoint = ptEvent->pointById(point.id())) {
+ pointerEventPoint->setAccepted();
+ if (isPressOrRelease)
+ pointerEventPoint->setGrabberItem(item);
+ }
}
} 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())) {
if (point.state() == Qt::TouchPointPressed) {
- if (event->pointById(point.id())->grabber() == item) {
- qCDebug(DBG_TOUCH_TARGET) << "TP" << point.id() << "disassociated";
- event->pointById(point.id())->setGrabber(nullptr);
+ if (auto *tp = ptEvent->pointById(point.id())) {
+ if (tp->exclusiveGrabber() == item) {
+ qCDebug(DBG_TOUCH_TARGET) << "TP" << hex << point.id() << "disassociated";
+ tp->setGrabberItem(nullptr);
+ }
}
}
}
}
-
- return eventAccepted;
}
#if QT_CONFIG(draganddrop)
@@ -2557,7 +2851,7 @@ QQuickItem *QQuickWindowPrivate::findCursorItem(QQuickItem *item, const QPointF
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
QPointF p = item->mapFromScene(scenePos);
if (!item->contains(p))
- return 0;
+ return nullptr;
}
if (itemPrivate->subtreeCursorEnabled) {
@@ -2576,119 +2870,154 @@ QQuickItem *QQuickWindowPrivate::findCursorItem(QQuickItem *item, const QPointF
if (item->contains(p))
return item;
}
- return 0;
+ return nullptr;
}
#endif
-bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QQuickPointerTouchEvent *event, QSet<QQuickItem *> *hasFiltered)
+bool QQuickWindowPrivate::sendFilteredPointerEvent(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
{
- Q_Q(QQuickWindow);
+ return sendFilteredPointerEventImpl(event, receiver, filteringParent ? filteringParent : receiver->parentItem());
+}
- if (!target)
+bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
+{
+ if (!allowChildEventFiltering)
+ return false;
+ if (!filteringParent)
return false;
-
bool filtered = false;
-
- QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
- if (targetPrivate->filtersChildMouseEvents && !hasFiltered->contains(target)) {
- hasFiltered->insert(target);
- QScopedPointer<QTouchEvent> targetEvent(event->touchEventForItem(target, true));
- if (targetEvent) {
- if (target->childMouseEventFilter(item, targetEvent.data())) {
- qCDebug(DBG_TOUCH) << " - first chance intercepted on childMouseEventFilter by " << target;
- QVector<int> touchIds;
- const int touchPointCount = targetEvent->touchPoints().size();
- touchIds.reserve(touchPointCount);
- for (int i = 0; i < touchPointCount; ++i)
- touchIds.append(targetEvent->touchPoints().at(i).id());
- target->grabTouchPoints(touchIds);
- if (q->mouseGrabberItem()) {
- q->mouseGrabberItem()->ungrabMouse();
- touchMouseId = -1;
- touchMouseDevice = nullptr;
+ if (filteringParent->filtersChildMouseEvents() && !hasFiltered.contains(filteringParent)) {
+ hasFiltered.append(filteringParent);
+ if (QQuickPointerMouseEvent *pme = event->asPointerMouseEvent()) {
+ if (receiver->acceptedMouseButtons()) {
+ QPointF localPos = receiver->mapFromScene(pme->point(0)->scenePosition());
+ QMouseEvent *me = pme->asMouseEvent(localPos);
+ const bool wasAccepted = me->isAccepted();
+ me->setAccepted(true);
+ auto oldMouseGrabber = pme->point(0)->grabberItem();
+ if (filteringParent->childMouseEventFilter(receiver, me)) {
+ qCDebug(DBG_MOUSE) << "mouse event intercepted by childMouseEventFilter of " << filteringParent;
+ skipDelivery.append(filteringParent);
+ filtered = true;
+ if (me->isAccepted() && pme->isPressEvent()) {
+ auto mouseGrabber = pme->point(0)->grabberItem();
+ if (mouseGrabber && mouseGrabber != receiver && mouseGrabber != oldMouseGrabber) {
+ receiver->mouseUngrabEvent();
+ } else {
+ pme->point(0)->setGrabberItem(receiver);
+ }
+ }
+ } else {
+ // Restore accepted state if the event was not filtered.
+ me->setAccepted(wasAccepted);
}
- filtered = true;
}
+ } else if (QQuickPointerTouchEvent *pte = event->asPointerTouchEvent()) {
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ bool acceptsTouchEvents = receiver->acceptTouchEvents();
+#else
+ // In versions prior to Qt 6, we can't trust item->acceptTouchEvents() here, because it defaults to true.
+ bool acceptsTouchEvents = false;
+#endif
+ auto device = pte->device();
+ if (device->type() == QQuickPointerDevice::TouchPad &&
+ device->capabilities().testFlag(QQuickPointerDevice::MouseEmulation)) {
+ qCDebug(DBG_TOUCH_TARGET) << "skipping filtering of synth-mouse event from" << device;
+ } else if (acceptsTouchEvents || receiver->acceptedMouseButtons()) {
+ // get a touch event customized for delivery to filteringParent
+ QScopedPointer<QTouchEvent> filteringParentTouchEvent(pte->touchEventForItem(receiver, true));
+ if (filteringParentTouchEvent) {
+ 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())) {
+ QQuickEventPoint *pt = event->pointById(point.id());
+ pt->setAccepted();
+ pt->setGrabberItem(filteringParent);
+ }
+ return true;
+ } else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) {
+ // filteringParent didn't filter the touch event. Give it a chance to filter a synthetic mouse event.
+ for (int i = 0; i < filteringParentTouchEvent->touchPoints().size(); ++i) {
+ const QTouchEvent::TouchPoint &tp = filteringParentTouchEvent->touchPoints().at(i);
+
+ QEvent::Type t;
+ switch (tp.state()) {
+ case Qt::TouchPointPressed:
+ t = QEvent::MouseButtonPress;
+ break;
+ case Qt::TouchPointReleased:
+ t = QEvent::MouseButtonRelease;
+ break;
+ case Qt::TouchPointStationary:
+ continue;
+ default:
+ t = QEvent::MouseMove;
+ break;
+ }
- for (int i = 0; i < targetEvent->touchPoints().size(); ++i) {
- const QTouchEvent::TouchPoint &tp = targetEvent->touchPoints().at(i);
-
- QEvent::Type t;
- switch (tp.state()) {
- case Qt::TouchPointPressed:
- t = QEvent::MouseButtonPress;
- break;
- case Qt::TouchPointReleased:
- t = QEvent::MouseButtonRelease;
- break;
- case Qt::TouchPointStationary:
- continue;
- default:
- t = QEvent::MouseMove;
- break;
- }
-
- bool touchMouseUnset = (touchMouseId == -1);
- // Only deliver mouse event if it is the touchMouseId or it could become the touchMouseId
- if (touchMouseUnset || touchMouseId == tp.id()) {
- // targetEvent is already transformed wrt local position, velocity, etc.
-
- // FIXME: remove asTouchEvent!!!
- QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, event->asTouchEvent(), item, false));
- // If a filtering item calls QQuickWindow::mouseGrabberItem(), it should
- // report the touchpoint's grabber. Whenever we send a synthetic mouse event,
- // touchMouseId and touchMouseDevice must be set, even if it's only temporarily and isn't grabbed.
- touchMouseId = tp.id();
- touchMouseDevice = event->device();
- if (target->childMouseEventFilter(item, mouseEvent.data())) {
- qCDebug(DBG_TOUCH) << " - second chance intercepted on childMouseEventFilter by " << target;
- if (t != QEvent::MouseButtonRelease) {
- qCDebug(DBG_TOUCH_TARGET) << "TP" << tp.id() << "->" << target;
- if (touchMouseUnset) {
- // the point was grabbed as a pure touch point before, now it will be treated as mouse
- // but the old receiver still needs to be informed
- if (auto oldGrabber = pointerEventInstance(touchMouseDevice)->pointById(tp.id())->grabber())
- oldGrabber->touchUngrabEvent();
+ bool touchMouseUnset = (touchMouseId == -1);
+ // Only deliver mouse event if it is the touchMouseId or it could become the touchMouseId
+ if (touchMouseUnset || touchMouseId == tp.id()) {
+ // convert filteringParentTouchEvent (which is already transformed wrt local position, velocity, etc.)
+ // into a synthetic mouse event, and let childMouseEventFilter() have another chance with that
+ QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, filteringParentTouchEvent.data(), receiver, false));
+ // If a filtering item calls QQuickWindow::mouseGrabberItem(), it should
+ // report the touchpoint's grabber. Whenever we send a synthetic mouse event,
+ // touchMouseId and touchMouseDevice must be set, even if it's only temporarily and isn't grabbed.
+ touchMouseId = tp.id();
+ touchMouseDevice = event->device();
+ QQuickPointerDevice *dev = touchMouseDevice;
+ if (filteringParent->childMouseEventFilter(receiver, mouseEvent.data())) {
+ qCDebug(DBG_TOUCH) << "touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent;
+ skipDelivery.append(filteringParent);
+ if (t != QEvent::MouseButtonRelease) {
+ qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << tp.id() << "->" << filteringParent;
+ pointerEventInstance(dev)->pointById(tp.id())->setGrabberItem(filteringParent);
+ touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set
+ if (mouseEvent->isAccepted())
+ filteringParent->grabMouse();
+ }
+ filtered = true;
+ }
+ if (touchMouseUnset) {
+ // Now that we're done sending a synth mouse event, and it wasn't grabbed,
+ // the touchpoint is no longer acting as a synthetic mouse. Restore previous state.
+ cancelTouchMouseSynthesis();
+ }
+ // Only one touchpoint can be treated as a synthetic mouse, so after childMouseEventFilter
+ // has been called once, we're done with this loop over the touchpoints.
+ break;
}
- touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set
- target->grabMouse();
}
- filtered = true;
- }
- if (touchMouseUnset) {
- // Now that we're done sending a synth mouse event, and it wasn't grabbed,
- // the touchpoint is no longer acting as a synthetic mouse. Restore previous state.
- touchMouseId = -1;
- touchMouseDevice = nullptr;
}
- // Only one event can be filtered as a mouse event.
- break;
}
}
}
}
-
- return sendFilteredTouchEvent(target->parentItem(), item, event, hasFiltered) || filtered;
+ return sendFilteredPointerEventImpl(event, receiver, filteringParent->parentItem()) || filtered;
}
-bool QQuickWindowPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event, QSet<QQuickItem *> *hasFiltered)
+bool QQuickWindowPrivate::sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
{
- if (!target)
+ if (!filteringParent)
return false;
- QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
- if (targetPrivate->replayingPressEvent)
+ QQuickItemPrivate *filteringParentPrivate = QQuickItemPrivate::get(filteringParent);
+ if (filteringParentPrivate->replayingPressEvent)
return false;
bool filtered = false;
- if (targetPrivate->filtersChildMouseEvents && !hasFiltered->contains(target)) {
- hasFiltered->insert(target);
- if (target->childMouseEventFilter(item, event))
+ if (filteringParentPrivate->filtersChildMouseEvents && !hasFiltered.contains(filteringParent)) {
+ hasFiltered.append(filteringParent);
+ if (filteringParent->childMouseEventFilter(receiver, event)) {
filtered = true;
- qCDebug(DBG_MOUSE_TARGET) << target << "childMouseEventFilter ->" << filtered;
+ skipDelivery.append(filteringParent);
+ }
+ qCDebug(DBG_MOUSE_TARGET) << "for" << receiver << filteringParent << "childMouseEventFilter ->" << filtered;
}
- return sendFilteredMouseEvent(target->parentItem(), item, event, hasFiltered) || filtered;
+ return sendFilteredMouseEvent(event, receiver, filteringParent->parentItem()) || filtered;
}
bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int startDragThreshold)
@@ -2706,6 +3035,12 @@ bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent
return overThreshold;
}
+bool QQuickWindowPrivate::dragOverThreshold(QVector2D delta)
+{
+ int threshold = qApp->styleHints()->startDragDistance();
+ return qAbs(delta.x()) > threshold || qAbs(delta.y()) > threshold;
+}
+
/*!
\qmlproperty list<Object> Window::data
\default
@@ -2735,8 +3070,10 @@ void QQuickWindowPrivate::data_append(QQmlListProperty<QObject> *property, QObje
if (!o)
return;
QQuickWindow *that = static_cast<QQuickWindow *>(property->object);
- if (QQuickWindow *window = qmlobject_cast<QQuickWindow *>(o))
+ if (QQuickWindow *window = qmlobject_cast<QQuickWindow *>(o)) {
+ qCDebug(lcTransient) << window << "is transient for" << that;
window->setTransientParent(that);
+ }
QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(that->contentItem())->data();
itemProperty.append(&itemProperty, o);
}
@@ -2802,6 +3139,7 @@ void QQuickWindowPrivate::contextCreationFailureMessage(const QSurfaceFormat &fo
#if QT_DEPRECATED_SINCE(5, 8)
+// ### Qt6: remove
/*!
Propagates an event \a e to a QQuickItem \a item on the window.
@@ -2811,7 +3149,6 @@ void QQuickWindowPrivate::contextCreationFailureMessage(const QSurfaceFormat &fo
\deprecated
*/
-// ### Qt6: remove
bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e)
{
Q_D(QQuickWindow);
@@ -2838,8 +3175,8 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e)
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove: {
// XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
- QSet<QQuickItem *> hasFiltered;
- if (!d->sendFilteredMouseEvent(item->parentItem(), item, e, &hasFiltered)) {
+ d->hasFiltered.clear();
+ if (!d->sendFilteredMouseEvent(e, item, item->parentItem())) {
// accept because qml items by default accept and have to explicitly opt out of accepting
e->accept();
QCoreApplication::sendEvent(item, e);
@@ -2868,15 +3205,15 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
if (p->itemNodeInstance) {
delete p->itemNodeInstance;
- p->itemNodeInstance = 0;
+ p->itemNodeInstance = nullptr;
if (p->extra.isAllocated()) {
- p->extra->opacityNode = 0;
- p->extra->clipNode = 0;
- p->extra->rootNode = 0;
+ p->extra->opacityNode = nullptr;
+ p->extra->clipNode = nullptr;
+ p->extra->rootNode = nullptr;
}
- p->paintNode = 0;
+ p->paintNode = nullptr;
p->dirty(QQuickItemPrivate::Window);
}
@@ -2888,7 +3225,7 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
if (index >= 0) {
const QMetaMethod &method = mo->method(index);
// Skip functions named invalidateSceneGraph() in QML items.
- if (strstr(method.enclosingMetaObject()->className(), "_QML_") == 0)
+ if (strstr(method.enclosingMetaObject()->className(), "_QML_") == nullptr)
method.invoke(item, Qt::DirectConnection);
}
}
@@ -2916,7 +3253,7 @@ void QQuickWindowPrivate::updateDirtyNodes()
cleanupNodes();
QQuickItem *updateList = dirtyItemList;
- dirtyItemList = 0;
+ dirtyItemList = nullptr;
if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
while (updateList) {
@@ -2932,7 +3269,7 @@ void QQuickWindowPrivate::updateDirtyNodes()
static inline QSGNode *qquickitem_before_paintNode(QQuickItemPrivate *d)
{
const QList<QQuickItem *> childItems = d->paintOrderChildItems();
- QQuickItem *before = 0;
+ QQuickItem *before = nullptr;
for (int i=0; i<childItems.size(); ++i) {
QQuickItemPrivate *dd = QQuickItemPrivate::get(childItems.at(i));
// Perform the same check as the in fetchNextNode below.
@@ -2941,7 +3278,7 @@ static inline QSGNode *qquickitem_before_paintNode(QQuickItemPrivate *d)
else
break;
}
- return Q_UNLIKELY(before) ? QQuickItemPrivate::get(before)->itemNode() : 0;
+ return Q_UNLIKELY(before) ? QQuickItemPrivate::get(before)->itemNode() : nullptr;
}
static QSGNode *fetchNextNode(QQuickItemPrivate *itemPriv, int &ii, bool &returnedPaintNode)
@@ -2973,7 +3310,7 @@ static QSGNode *fetchNextNode(QQuickItemPrivate *itemPriv, int &ii, bool &return
return childPrivate->itemNode();
}
- return 0;
+ return nullptr;
}
void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
@@ -3008,10 +3345,10 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
}
bool clipEffectivelyChanged = (dirty & (QQuickItemPrivate::Clip | QQuickItemPrivate::Window)) &&
- ((item->clip() == false) != (itemPriv->clipNode() == 0));
+ ((item->clip() == false) != (itemPriv->clipNode() == nullptr));
int effectRefCount = itemPriv->extra.isAllocated()?itemPriv->extra->effectRefCount:0;
bool effectRefEffectivelyChanged = (dirty & (QQuickItemPrivate::EffectReference | QQuickItemPrivate::Window)) &&
- ((effectRefCount == 0) != (itemPriv->rootNode() == 0));
+ ((effectRefCount == 0) != (itemPriv->rootNode() == nullptr));
if (clipEffectivelyChanged) {
QSGNode *parent = itemPriv->opacityNode() ? (QSGNode *) itemPriv->opacityNode() :
@@ -3019,7 +3356,7 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
QSGNode *child = itemPriv->rootNode();
if (item->clip()) {
- Q_ASSERT(itemPriv->clipNode() == 0);
+ Q_ASSERT(itemPriv->clipNode() == nullptr);
QQuickDefaultClipNode *clip = new QQuickDefaultClipNode(item->clipRect());
itemPriv->extra.value().clipNode = clip;
clip->update();
@@ -3045,7 +3382,7 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
}
delete itemPriv->clipNode();
- itemPriv->extra->clipNode = 0;
+ itemPriv->extra->clipNode = nullptr;
}
}
@@ -3060,18 +3397,18 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
parent = itemPriv->itemNode();
if (itemPriv->extra.isAllocated() && itemPriv->extra->effectRefCount) {
- Q_ASSERT(itemPriv->rootNode() == 0);
+ Q_ASSERT(itemPriv->rootNode() == nullptr);
QSGRootNode *root = new QSGRootNode();
itemPriv->extra->rootNode = root;
parent->reparentChildNodesTo(root);
parent->appendChildNode(root);
} else {
- Q_ASSERT(itemPriv->rootNode() != 0);
+ Q_ASSERT(itemPriv->rootNode() != nullptr);
QSGRootNode *root = itemPriv->rootNode();
parent->removeChildNode(root);
root->reparentChildNodesTo(parent);
delete itemPriv->rootNode();
- itemPriv->extra->rootNode = 0;
+ itemPriv->extra->rootNode = nullptr;
}
}
@@ -3097,7 +3434,7 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
int added = 0;
int removed = 0;
int replaced = 0;
- QSGNode *desiredNode = 0;
+ QSGNode *desiredNode = nullptr;
while (currentNode && (desiredNode = fetchNextNode(itemPriv, ii, fetchedPaintNode))) {
// uh oh... reality and our utopic paradise are diverging!
@@ -3182,11 +3519,11 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
updatePaintNodeData.transformNode = itemPriv->itemNode();
itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
- Q_ASSERT(itemPriv->paintNode == 0 ||
- itemPriv->paintNode->parent() == 0 ||
+ Q_ASSERT(itemPriv->paintNode == nullptr ||
+ itemPriv->paintNode->parent() == nullptr ||
itemPriv->paintNode->parent() == itemPriv->childContainerNode());
- if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
+ if (itemPriv->paintNode && itemPriv->paintNode->parent() == nullptr) {
QSGNode *before = qquickitem_before_paintNode(itemPriv);
if (before && before->parent()) {
Q_ASSERT(before->parent() == itemPriv->childContainerNode());
@@ -3197,7 +3534,7 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
}
} else if (itemPriv->paintNode) {
delete itemPriv->paintNode;
- itemPriv->paintNode = 0;
+ itemPriv->paintNode = nullptr;
}
}
@@ -3249,14 +3586,14 @@ void QQuickWindow::cleanupSceneGraph()
Q_D(QQuickWindow);
#if QT_CONFIG(opengl)
delete d->vaoHelper;
- d->vaoHelper = 0;
+ d->vaoHelper = nullptr;
#endif
if (!d->renderer)
return;
delete d->renderer->rootNode();
delete d->renderer;
- d->renderer = 0;
+ d->renderer = nullptr;
d->runAndClearJobs(&d->beforeSynchronizingJobs);
d->runAndClearJobs(&d->afterSynchronizingJobs);
@@ -3267,6 +3604,7 @@ void QQuickWindow::cleanupSceneGraph()
void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
{
+ qCDebug(lcTransient) << this << "is transient for" << window;
setTransientParent(window);
disconnect(sender(), SIGNAL(windowChanged(QQuickWindow*)),
this, SLOT(setTransientParent_helper(QQuickWindow*)));
@@ -3305,7 +3643,7 @@ QOpenGLContext *QQuickWindow::openglContext() const
bool QQuickWindow::isSceneGraphInitialized() const
{
Q_D(const QQuickWindow);
- return d->context != 0 && d->context->isValid();
+ return d->context != nullptr && d->context->isValid();
}
/*!
@@ -3375,7 +3713,7 @@ bool QQuickWindow::isSceneGraphInitialized() const
\instantiates QQuickCloseEvent
\inqmlmodule QtQuick.Window
\ingroup qtquick-visual
- \brief Notification that a \l Window is about to be closed
+ \brief Notification that a \l Window is about to be closed.
\since 5.1
Notification that a window is about to be closed by the windowing system
@@ -3434,7 +3772,7 @@ void QQuickWindow::setRenderTarget(QOpenGLFramebufferObject *fbo)
{
Q_D(QQuickWindow);
if (d->context && QThread::currentThread() != d->context->thread()) {
- qWarning("QQuickWindow::setRenderThread: Cannot set render target from outside the rendering thread");
+ qWarning("QQuickWindow::setRenderTarget: Cannot set render target from outside the rendering thread");
return;
}
@@ -3483,7 +3821,7 @@ void QQuickWindow::setRenderTarget(uint fboId, const QSize &size)
d->renderTargetSize = size;
// Unset any previously set instance...
- d->renderTarget = 0;
+ d->renderTarget = nullptr;
}
@@ -3597,7 +3935,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
Q_D(const QQuickWindow);
if (!d->windowManager)
- return 0; // TODO: make sure that this is safe
+ return nullptr; // TODO: make sure that this is safe
if (!d->incubationController)
d->incubationController = new QQuickWindowIncubationController(d->windowManager);
@@ -3643,6 +3981,23 @@ QQmlIncubationController *QQuickWindow::incubationController() const
*/
/*!
+ \enum QQuickWindow::TextRenderType
+ \since 5.10
+
+ This enum describes the default render type of text-like elements in Qt
+ Quick (\l Text, \l TextInput, etc.).
+
+ Select NativeTextRendering if you prefer text to look native on the target
+ platform and do not require advanced features such as transformation of the
+ text. Using such features in combination with the NativeTextRendering
+ render type will lend poor and sometimes pixelated results.
+
+ \value QtTextRendering Use Qt's own rasterization algorithm.
+
+ \value NativeTextRendering Use the operating system's native rasterizer for text.
+*/
+
+/*!
\fn void QQuickWindow::beforeSynchronizing()
This signal is emitted before the scene graph is synchronized with the QML state.
@@ -3824,7 +4179,7 @@ bool QQuickWindow::clearBeforeRendering() const
QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
{
- return createTextureFromImage(image, 0);
+ return createTextureFromImage(image, nullptr);
}
@@ -3873,7 +4228,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText
{
Q_D(const QQuickWindow);
if (!isSceneGraphInitialized()) // check both for d->context and d->context->isValid()
- return 0;
+ return nullptr;
uint flags = 0;
if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas;
if (options & TextureHasMipmaps) flags |= QSGRenderContext::CreateTexture_Mipmap;
@@ -3919,7 +4274,7 @@ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, Create
Q_UNUSED(size)
Q_UNUSED(options)
#endif
- return 0;
+ return nullptr;
}
/*!
@@ -4033,7 +4388,7 @@ void QQuickWindow::resetOpenGLState()
int maxAttribs;
gl->glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
for (int i=0; i<maxAttribs; ++i) {
- gl->glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0);
+ gl->glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
gl->glDisableVertexAttribArray(i);
}
}
@@ -4096,6 +4451,8 @@ void QQuickWindow::resetOpenGLState()
The flags which you read from this property might differ from the ones
that you set if the requested flags could not be fulfilled.
+
+ \sa Qt::WindowFlags
*/
/*!
@@ -4265,6 +4622,62 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
+ \qmlproperty QWindow Window::transientParent
+ \since 5.13
+
+ The window for which this window is a transient pop-up.
+
+ This is a hint to the window manager that this window is a dialog or pop-up
+ on behalf of the transient parent. It usually means that the transient
+ window will be centered over its transient parent when it is initially
+ shown, that minimizing the parent window will also minimize the transient
+ window, and so on; however results vary somewhat from platform to platform.
+
+ Normally if you declare a Window inside an Item or inside another Window,
+ this relationship is deduced automatically. In that case, if you declare
+ this window's \l visible property \c true, it will not actually be shown
+ until the \c transientParent window is shown.
+
+ However if you set this property, then Qt Quick will no longer wait until
+ the \c transientParent window is shown before showing this window. If you
+ want to to be able to show a transient window independently of the "parent"
+ Item or Window within which it was declared, you can remove that
+ relationship by setting \c transientParent to \c null:
+
+ \qml
+ import QtQuick.Window 2.13
+
+ Window {
+ // visible is false by default
+ Window {
+ transientParent: null
+ visible: true
+ }
+ }
+ \endqml
+
+ In order to cause the window to be centered above its transient parent by
+ default, depending on the window manager, it may also be necessary to set
+ the \l Window::flags property with a suitable \l Qt::WindowType (such as
+ \c Qt::Dialog).
+*/
+
+/*!
+ \property QQuickWindow::transientParent
+ \brief The window for which this window is a transient pop-up.
+ \since 5.13
+
+ This is a hint to the window manager that this window is a dialog or pop-up
+ on behalf of the transient parent, which may be any kind of \l QWindow.
+
+ In order to cause the window to be centered above its transient parent by
+ default, depending on the window manager, it may also be necessary to set
+ the \l flags property with a suitable \l Qt::WindowType (such as \c Qt::Dialog).
+
+ \sa parent()
+ */
+
+/*!
\qmlproperty Item Window::activeFocusItem
\since 5.1
@@ -4610,7 +5023,7 @@ void QQuickWindow::setSceneGraphBackend(const QString &backend)
}
/*!
- Returns the requested Qt Quick scenegraph \a backend.
+ Returns the requested Qt Quick scenegraph backend.
\note The return value of this function may still be outdated by
subsequent calls to setSceneGraphBackend() until the first QQuickWindow in the
@@ -4662,6 +5075,65 @@ QSGNinePatchNode *QQuickWindow::createNinePatchNode() const
return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createNinePatchNode() : nullptr;
}
+/*!
+ \since 5.10
+
+ Returns the render type of text-like elements in Qt Quick.
+ The default is QQuickWindow::QtTextRendering.
+
+ \sa setTextRenderType()
+*/
+QQuickWindow::TextRenderType QQuickWindow::textRenderType()
+{
+ return QQuickWindowPrivate::textRenderType;
+}
+
+/*!
+ \since 5.10
+
+ Sets the default render type of text-like elements in Qt Quick to \a renderType.
+
+ \note setting the render type will only affect elements created afterwards;
+ the render type of existing elements will not be modified.
+
+ \sa textRenderType()
+*/
+void QQuickWindow::setTextRenderType(QQuickWindow::TextRenderType renderType)
+{
+ QQuickWindowPrivate::textRenderType = renderType;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QQuickWindow *win)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ if (!win) {
+ debug << "QQuickWindow(0)";
+ return debug;
+ }
+
+ debug << win->metaObject()->className() << '(' << static_cast<const void *>(win);
+ if (win->isActive())
+ debug << " active";
+ if (win->isExposed())
+ debug << " exposed";
+ debug << ", visibility=" << win->visibility() << ", flags=" << win->flags();
+ if (!win->title().isEmpty())
+ debug << ", title=" << win->title();
+ if (!win->objectName().isEmpty())
+ debug << ", name=" << win->objectName();
+ if (win->parent())
+ debug << ", parent=" << static_cast<const void *>(win->parent());
+ if (win->transientParent())
+ debug << ", transientParent=" << static_cast<const void *>(win->transientParent());
+ debug << ", geometry=";
+ QtDebugUtils::formatQRect(debug, win->geometry());
+ debug << ')';
+ return debug;
+}
+#endif
+
#include "moc_qquickwindow.cpp"
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index d1a16fbeb6..79e8a11aa8 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -47,6 +47,7 @@
#include <QtGui/qwindow.h>
#include <QtGui/qevent.h>
#include <QtQml/qqml.h>
+#include <QtQml/qqmldebug.h>
QT_BEGIN_NAMESPACE
@@ -94,21 +95,28 @@ public:
};
Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption)
+ Q_FLAG(CreateTextureOptions)
enum SceneGraphError {
ContextNotAvailable = 1
};
Q_ENUM(SceneGraphError)
- explicit QQuickWindow(QWindow *parent = Q_NULLPTR);
+ enum TextRenderType {
+ QtTextRendering,
+ NativeTextRendering
+ };
+ Q_ENUM(TextRenderType)
+
+ explicit QQuickWindow(QWindow *parent = nullptr);
explicit QQuickWindow(QQuickRenderControl *renderControl);
- virtual ~QQuickWindow();
+ ~QQuickWindow() override;
QQuickItem *contentItem() const;
QQuickItem *activeFocusItem() const;
- QObject *focusObject() const Q_DECL_OVERRIDE;
+ QObject *focusObject() const override;
QQuickItem *mouseGrabberItem() const;
@@ -130,7 +138,7 @@ public:
QQmlIncubationController *incubationController() const;
#if QT_CONFIG(accessibility)
- QAccessibleInterface *accessibleRoot() const Q_DECL_OVERRIDE;
+ QAccessibleInterface *accessibleRoot() const override;
#endif
// Scene graph specific functions
@@ -170,6 +178,9 @@ public:
QSGImageNode *createImageNode() const;
QSGNinePatchNode *createNinePatchNode() const;
+ static TextRenderType textRenderType();
+ static void setTextRenderType(TextRenderType renderType);
+
Q_SIGNALS:
void frameSwapped();
Q_REVISION(2) void openglContextCreated(QOpenGLContext *context);
@@ -193,27 +204,28 @@ public Q_SLOTS:
void releaseResources();
protected:
- QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent = Q_NULLPTR);
+ QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent = nullptr);
+ QQuickWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control);
- void exposeEvent(QExposeEvent *) Q_DECL_OVERRIDE;
- void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE;
+ void exposeEvent(QExposeEvent *) override;
+ void resizeEvent(QResizeEvent *) override;
- void showEvent(QShowEvent *) Q_DECL_OVERRIDE;
- void hideEvent(QHideEvent *) Q_DECL_OVERRIDE;
+ void showEvent(QShowEvent *) override;
+ void hideEvent(QHideEvent *) override;
// TODO Qt 6: reimplement QWindow::closeEvent to emit closing
- void focusInEvent(QFocusEvent *) Q_DECL_OVERRIDE;
- void focusOutEvent(QFocusEvent *) Q_DECL_OVERRIDE;
+ void focusInEvent(QFocusEvent *) override;
+ void focusOutEvent(QFocusEvent *) override;
- bool event(QEvent *) Q_DECL_OVERRIDE;
- void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE;
- void keyReleaseEvent(QKeyEvent *) Q_DECL_OVERRIDE;
- void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE;
- void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE;
- void mouseDoubleClickEvent(QMouseEvent *) Q_DECL_OVERRIDE;
- void mouseMoveEvent(QMouseEvent *) Q_DECL_OVERRIDE;
+ bool event(QEvent *) override;
+ void keyPressEvent(QKeyEvent *) override;
+ void keyReleaseEvent(QKeyEvent *) override;
+ void mousePressEvent(QMouseEvent *) override;
+ void mouseReleaseEvent(QMouseEvent *) override;
+ void mouseDoubleClickEvent(QMouseEvent *) override;
+ void mouseMoveEvent(QMouseEvent *) override;
#if QT_CONFIG(wheelevent)
- void wheelEvent(QWheelEvent *) Q_DECL_OVERRIDE;
+ void wheelEvent(QWheelEvent *) override;
#endif
private Q_SLOTS:
@@ -223,7 +235,7 @@ private Q_SLOTS:
void handleScreenChanged(QScreen *screen);
void setTransientParent_helper(QQuickWindow *window);
void runJobsAfterSwap();
-
+ void handleApplicationStateChanged(Qt::ApplicationState state);
private:
friend class QQuickItem;
friend class QQuickWidget;
@@ -232,6 +244,10 @@ private:
Q_DISABLE_COPY(QQuickWindow)
};
+#ifndef QT_NO_DEBUG_STREAM
+QDebug Q_QUICK_EXPORT operator<<(QDebug debug, const QQuickWindow *item);
+#endif
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQuickWindow *)
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index b3ff5a2b35..5a3807b24f 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -114,9 +114,9 @@ public:
static inline QQuickWindowPrivate *get(QQuickWindow *c) { return c->d_func(); }
QQuickWindowPrivate();
- virtual ~QQuickWindowPrivate();
+ ~QQuickWindowPrivate() override;
- void init(QQuickWindow *, QQuickRenderControl *control = 0);
+ void init(QQuickWindow *, QQuickRenderControl *control = nullptr);
QQuickRootItem *contentItem;
QSet<QQuickItem *> parentlessItems;
@@ -137,23 +137,23 @@ public:
QQuickPointerDevice *touchMouseDevice;
bool checkIfDoubleClicked(ulong newPressEventTimestamp);
ulong touchMousePressTimestamp;
+ void cancelTouchMouseSynthesis();
// Mouse positions are saved in widget coordinates
QPointF lastMousePosition;
bool deliverTouchAsMouse(QQuickItem *item, QQuickPointerEvent *pointerEvent);
+ bool isDeliveringTouchAsMouse() const { return touchMouseId != -1 && touchMouseDevice; }
void translateTouchEvent(QTouchEvent *touchEvent);
- void setMouseGrabber(QQuickItem *grabber);
- void grabTouchPoints(QQuickItem *grabber, const QVector<int> &ids);
+ void grabTouchPoints(QObject *grabber, const QVector<int> &ids);
void removeGrabber(QQuickItem *grabber, bool mouse = true, bool touch = true);
- static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = 0);
+ void sendUngrabEvent(QQuickItem *grabber, bool touch);
+ static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = nullptr);
+ void deliverToPassiveGrabbers(const QVector<QPointer <QQuickPointerHandler> > &passiveGrabbers, QQuickPointerEvent *pointerEvent);
void deliverMouseEvent(QQuickPointerMouseEvent *pointerEvent);
- bool sendFilteredMouseEvent(QQuickItem *, QQuickItem *, QEvent *, QSet<QQuickItem *> *);
-#if QT_CONFIG(wheelevent)
- bool deliverWheelEvent(QQuickItem *, QWheelEvent *);
-#endif
-#if QT_CONFIG(gestures)
- bool deliverNativeGestureEvent(QQuickItem *, QNativeGestureEvent *);
-#endif
+ bool sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent);
+ bool sendFilteredPointerEvent(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent = nullptr);
+ bool sendFilteredPointerEventImpl(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent);
+ bool deliverSinglePointEventUntilAccepted(QQuickPointerEvent *);
// entry point of events to the window
void handleTouchEvent(QTouchEvent *);
@@ -164,19 +164,19 @@ public:
// the device-specific event instances which are reused during event delivery
mutable QVector<QQuickPointerEvent *> pointerEventInstances;
- QQuickPointerEvent *pointerEventInstance(QQuickPointerDevice *device) const;
+ QQuickPointerEvent *queryPointerEventInstance(QQuickPointerDevice *device, QEvent::Type eventType = QEvent::None) const;
+ QQuickPointerEvent *pointerEventInstance(QQuickPointerDevice *device, QEvent::Type eventType = QEvent::None) const;
// delivery of pointer events:
QQuickPointerEvent *pointerEventInstance(QEvent *ev) const;
void deliverPointerEvent(QQuickPointerEvent *);
void deliverTouchEvent(QQuickPointerTouchEvent *);
bool deliverTouchCancelEvent(QTouchEvent *);
- bool deliverPressEvent(QQuickPointerEvent *, QSet<QQuickItem *> *);
- bool deliverUpdatedTouchPoints(QQuickPointerTouchEvent *event, QSet<QQuickItem *> *hasFiltered);
- bool deliverMatchingPointsToItem(QQuickItem *item, QQuickPointerEvent *pointerEvent, QSet<QQuickItem*> *filtered);
- bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QQuickPointerTouchEvent *event, QSet<QQuickItem*> *filtered);
+ bool deliverPressOrReleaseEvent(QQuickPointerEvent *, bool handlersOnly = false);
+ void deliverUpdatedTouchPoints(QQuickPointerTouchEvent *event);
+ void deliverMatchingPointsToItem(QQuickItem *item, QQuickPointerEvent *pointerEvent, bool handlersOnly = false);
- QVector<QQuickItem *> pointerTargets(QQuickItem *, const QPointF &, bool checkMouseButtons) const;
+ QVector<QQuickItem *> pointerTargets(QQuickItem *, QQuickEventPoint *point, bool checkMouseButtons, bool checkAcceptsTouch) const;
QVector<QQuickItem *> mergePointerTargets(const QVector<QQuickItem *> &list1, const QVector<QQuickItem *> &list2) const;
// hover delivery
@@ -201,8 +201,8 @@ public:
};
Q_DECLARE_FLAGS(FocusOptions, FocusOption)
- void setFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = 0);
- void clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = 0);
+ void setFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = nullptr);
+ void clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = nullptr);
static void notifyFocusChangesRecur(QQuickItem **item, int remaining);
void clearFocusObject() override;
@@ -226,6 +226,8 @@ public:
QList<QSGNode *> cleanupNodeList;
QVector<QQuickItem *> itemsToPolish;
+ QVector<QQuickItem *> hasFiltered; // during event delivery to a single receiver, the filtering parents for which childMouseEventFilter was already called
+ QVector<QQuickItem *> skipDelivery; // during delivery of one event to all receivers, Items to which we know delivery is no longer necessary
qreal devicePixelRatio;
QMetaObject::Connection physicalDpiChangedConnection;
@@ -263,6 +265,9 @@ public:
uint lastWheelEventAccepted : 1;
bool componentCompleted : 1;
+ bool allowChildEventFiltering : 1;
+ bool allowDoubleClick : 1;
+
Qt::FocusReason lastFocusReason;
QOpenGLFramebufferObject *renderTarget;
@@ -274,6 +279,7 @@ public:
mutable QQuickWindowIncubationController *incubationController;
static bool defaultAlphaBuffer;
+ static QQuickWindow::TextRenderType textRenderType;
static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int startDragThreshold = -1);
@@ -290,6 +296,15 @@ public:
return overThreshold;
}
+ static bool dragOverThreshold(const QQuickEventPoint *point)
+ {
+ QPointF delta = point->scenePosition() - point->scenePressPosition();
+ return (QQuickWindowPrivate::dragOverThreshold(delta.x(), Qt::XAxis, point) ||
+ QQuickWindowPrivate::dragOverThreshold(delta.y(), Qt::YAxis, point));
+ }
+
+ static bool dragOverThreshold(QVector2D delta);
+
// data property
static void data_append(QQmlListProperty<QObject> *, QObject *);
static int data_count(QQmlListProperty<QObject> *);
@@ -318,7 +333,7 @@ class QQuickWindowQObjectCleanupJob : public QRunnable
{
public:
QQuickWindowQObjectCleanupJob(QObject *o) : object(o) { }
- void run() Q_DECL_OVERRIDE { delete object; }
+ void run() override { delete object; }
QObject *object;
static void schedule(QQuickWindow *window, QObject *object) {
Q_ASSERT(window);
diff --git a/src/quick/items/qquickwindowattached.cpp b/src/quick/items/qquickwindowattached.cpp
index c8d71139ca..481366222d 100644
--- a/src/quick/items/qquickwindowattached.cpp
+++ b/src/quick/items/qquickwindowattached.cpp
@@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE
QQuickWindowAttached::QQuickWindowAttached(QObject* attachee)
: QObject(attachee)
- , m_window(NULL)
+ , m_window(nullptr)
{
m_attachee = qobject_cast<QQuickItem*>(attachee);
if (m_attachee && m_attachee->window()) // It might not be in a window yet
@@ -68,12 +68,12 @@ bool QQuickWindowAttached::isActive() const
QQuickItem *QQuickWindowAttached::activeFocusItem() const
{
- return (m_window ? m_window->activeFocusItem() : Q_NULLPTR);
+ return (m_window ? m_window->activeFocusItem() : nullptr);
}
QQuickItem *QQuickWindowAttached::contentItem() const
{
- return (m_window ? m_window->contentItem() : Q_NULLPTR);
+ return (m_window ? m_window->contentItem() : nullptr);
}
int QQuickWindowAttached::width() const
diff --git a/src/quick/items/qquickwindowattached_p.h b/src/quick/items/qquickwindowattached_p.h
index 3212508fd8..191f22137c 100644
--- a/src/quick/items/qquickwindowattached_p.h
+++ b/src/quick/items/qquickwindowattached_p.h
@@ -51,6 +51,7 @@
// We mean it.
//
+#include <private/qtquickglobal_p.h>
#include <qqml.h>
#include <QWindow>
@@ -59,7 +60,7 @@ QT_BEGIN_NAMESPACE
class QQuickItem;
class QQuickWindow;
-class Q_AUTOTEST_EXPORT QQuickWindowAttached : public QObject
+class Q_QUICK_PRIVATE_EXPORT QQuickWindowAttached : public QObject
{
Q_OBJECT
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index a7f45534c4..2b109c0897 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -52,6 +52,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcTransient)
+
class QQuickWindowQmlImplPrivate : public QQuickWindowPrivate
{
public:
@@ -112,7 +114,7 @@ void QQuickWindowQmlImpl::classBegin()
{
// The content item has CppOwnership policy (set in QQuickWindow). Ensure the presence of a JS
// wrapper so that the garbage collector can see the policy.
- QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(e);
+ QV4::ExecutionEngine *v4 = e->handle();
QV4::QObjectWrapper::wrap(v4, d->contentItem);
}
}
@@ -121,7 +123,14 @@ void QQuickWindowQmlImpl::componentComplete()
{
Q_D(QQuickWindowQmlImpl);
d->complete = true;
- if (transientParent() && !transientParent()->isVisible()) {
+ QQuickItem *itemParent = qmlobject_cast<QQuickItem *>(QObject::parent());
+ const bool transientParentAlreadySet = QQuickWindowPrivate::get(this)->transientParentPropertySet;
+ if (!transientParentAlreadySet && itemParent && !itemParent->window()) {
+ qCDebug(lcTransient) << "window" << title() << "has invisible Item parent" << itemParent << "transientParent"
+ << transientParent() << "declared visibility" << d->visibility << "; delaying show";
+ connect(itemParent, &QQuickItem::windowChanged, this,
+ &QQuickWindowQmlImpl::setWindowVisibility, Qt::QueuedConnection);
+ } else if (transientParent() && !transientParent()->isVisible()) {
connect(transientParent(), &QQuickWindow::visibleChanged, this,
&QQuickWindowQmlImpl::setWindowVisibility, Qt::QueuedConnection);
} else {
@@ -135,9 +144,10 @@ void QQuickWindowQmlImpl::setWindowVisibility()
if (transientParent() && !transientParent()->isVisible())
return;
- if (sender()) {
- disconnect(transientParent(), &QWindow::visibleChanged, this,
- &QQuickWindowQmlImpl::setWindowVisibility);
+ if (QQuickItem *senderItem = qmlobject_cast<QQuickItem *>(sender())) {
+ disconnect(senderItem, &QQuickItem::windowChanged, this, &QQuickWindowQmlImpl::setWindowVisibility);
+ } else if (sender()) {
+ disconnect(transientParent(), &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::setWindowVisibility);
}
// We have deferred window creation until we have the full picture of what
@@ -201,10 +211,11 @@ void QQuickWindowModule::defineModule()
qmlRegisterUncreatableType<QQuickScreen,1>(uri, 2, 3, "Screen", QStringLiteral("Screen can only be used via the attached property."));
qmlRegisterUncreatableType<QQuickScreenInfo,2>(uri, 2, 3, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property."));
qmlRegisterUncreatableType<QQuickScreenInfo,10>(uri, 2, 10, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property."));
+ qmlRegisterRevision<QWindow,13>(uri, 2, 13);
+ qmlRegisterRevision<QQuickWindow,13>(uri, 2, 13);
+ qmlRegisterType<QQuickWindowQmlImpl,13>(uri, 2, 13, "Window");
}
QT_END_NAMESPACE
-QML_DECLARE_TYPEINFO(QQuickWindowQmlImpl, QML_HAS_ATTACHED_PROPERTIES)
-
#include "moc_qquickwindowmodule_p.cpp"
diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h
index 16130bc8a0..e7033e9b8d 100644
--- a/src/quick/items/qquickwindowmodule_p.h
+++ b/src/quick/items/qquickwindowmodule_p.h
@@ -54,10 +54,10 @@
#include <private/qtquickglobal_p.h>
#include <qquickwindow.h>
#include <qqmlparserstatus.h>
+#include <private/qquickwindowattached_p.h>
QT_BEGIN_NAMESPACE
-class QQuickWindowAttached;
class QQuickWindowQmlImplPrivate;
class Q_QUICK_PRIVATE_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public QQmlParserStatus
@@ -70,7 +70,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public Q
Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION 2)
public:
- QQuickWindowQmlImpl(QWindow *parent = Q_NULLPTR);
+ QQuickWindowQmlImpl(QWindow *parent = nullptr);
void setVisible(bool visible);
void setVisibility(Visibility visibility);
@@ -86,8 +86,8 @@ Q_SIGNALS:
Q_REVISION(2) void screenChanged();
protected:
- void classBegin() Q_DECL_OVERRIDE;
- void componentComplete() Q_DECL_OVERRIDE;
+ void classBegin() override;
+ void componentComplete() override;
private Q_SLOTS:
void setWindowVisibility();
@@ -105,4 +105,7 @@ public:
QT_END_NAMESPACE
+QML_DECLARE_TYPE(QQuickWindowQmlImpl)
+QML_DECLARE_TYPEINFO(QQuickWindowQmlImpl, QML_HAS_ATTACHED_PROPERTIES)
+
#endif
diff --git a/src/quick/items/shaders/lineargradient.frag b/src/quick/items/shaders/lineargradient.frag
deleted file mode 100644
index 7f4a739109..0000000000
--- a/src/quick/items/shaders/lineargradient.frag
+++ /dev/null
@@ -1,9 +0,0 @@
-uniform sampler2D gradTabTexture;
-uniform highp float opacity;
-
-varying highp float gradTabIndex;
-
-void main()
-{
- gl_FragColor = texture2D(gradTabTexture, vec2(gradTabIndex, 0.5)) * opacity;
-}
diff --git a/src/quick/items/shaders/lineargradient.vert b/src/quick/items/shaders/lineargradient.vert
deleted file mode 100644
index eb21b8886b..0000000000
--- a/src/quick/items/shaders/lineargradient.vert
+++ /dev/null
@@ -1,15 +0,0 @@
-attribute vec4 vertexCoord;
-attribute vec4 vertexColor;
-
-uniform mat4 matrix;
-uniform vec2 gradStart;
-uniform vec2 gradEnd;
-
-varying float gradTabIndex;
-
-void main()
-{
- vec2 gradVec = gradEnd - gradStart;
- gradTabIndex = dot(gradVec, vertexCoord.xy - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);
- gl_Position = matrix * vertexCoord;
-}
diff --git a/src/quick/items/shaders/lineargradient_core.frag b/src/quick/items/shaders/lineargradient_core.frag
deleted file mode 100644
index 5908acfa67..0000000000
--- a/src/quick/items/shaders/lineargradient_core.frag
+++ /dev/null
@@ -1,12 +0,0 @@
-#version 150 core
-
-uniform sampler2D gradTabTexture;
-uniform float opacity;
-
-in float gradTabIndex;
-out vec4 fragColor;
-
-void main()
-{
- fragColor = texture(gradTabTexture, vec2(gradTabIndex, 0.5)) * opacity;
-}
diff --git a/src/quick/items/shaders/lineargradient_core.vert b/src/quick/items/shaders/lineargradient_core.vert
deleted file mode 100644
index 60b56f38e3..0000000000
--- a/src/quick/items/shaders/lineargradient_core.vert
+++ /dev/null
@@ -1,17 +0,0 @@
-#version 150 core
-
-in vec4 vertexCoord;
-in vec4 vertexColor;
-
-uniform mat4 matrix;
-uniform vec2 gradStart;
-uniform vec2 gradEnd;
-
-out float gradTabIndex;
-
-void main()
-{
- vec2 gradVec = gradEnd - gradStart;
- gradTabIndex = dot(gradVec, vertexCoord.xy - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);
- gl_Position = matrix * vertexCoord;
-}