aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp6
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp31
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h2
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp11
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp7
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h2
-rw-r--r--src/quick/items/qquickanchors.cpp2
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp14
-rw-r--r--src/quick/items/qquickcolorgroup.cpp4
-rw-r--r--src/quick/items/qquickdrag.cpp12
-rw-r--r--src/quick/items/qquickdrag_p.h3
-rw-r--r--src/quick/items/qquickdroparea.cpp38
-rw-r--r--src/quick/items/qquickdroparea_p.h14
-rw-r--r--src/quick/items/qquickevents.cpp53
-rw-r--r--src/quick/items/qquickflickable.cpp197
-rw-r--r--src/quick/items/qquickflickable_p_p.h41
-rw-r--r--src/quick/items/qquickflipable.cpp54
-rw-r--r--src/quick/items/qquickgridview.cpp32
-rw-r--r--src/quick/items/qquickimage.cpp6
-rw-r--r--src/quick/items/qquickimagebase.cpp30
-rw-r--r--src/quick/items/qquickimplicitsizeitem_p.h2
-rw-r--r--src/quick/items/qquickitem.cpp338
-rw-r--r--src/quick/items/qquickitem.h1
-rw-r--r--src/quick/items/qquickitem_p.h28
-rw-r--r--src/quick/items/qquickitemchangelistener_p.h1
-rw-r--r--src/quick/items/qquickitemgrabresult.h2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp136
-rw-r--r--src/quick/items/qquickitemview.cpp26
-rw-r--r--src/quick/items/qquickitemview_p_p.h5
-rw-r--r--src/quick/items/qquickitemviewtransition.cpp35
-rw-r--r--src/quick/items/qquickitemviewtransition_p.h3
-rw-r--r--src/quick/items/qquicklistview.cpp21
-rw-r--r--src/quick/items/qquickloader.cpp19
-rw-r--r--src/quick/items/qquickmousearea.cpp36
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp12
-rw-r--r--src/quick/items/qquickmultipointtoucharea_p.h3
-rw-r--r--src/quick/items/qquickpainteditem.cpp2
-rw-r--r--src/quick/items/qquickpalette.cpp2
-rw-r--r--src/quick/items/qquickpathview.cpp13
-rw-r--r--src/quick/items/qquickpathview_p_p.h6
-rw-r--r--src/quick/items/qquickpincharea.cpp28
-rw-r--r--src/quick/items/qquickpositioners.cpp6
-rw-r--r--src/quick/items/qquickrectangle.cpp9
-rw-r--r--src/quick/items/qquickrendercontrol.cpp23
-rw-r--r--src/quick/items/qquickrendercontrol.h3
-rw-r--r--src/quick/items/qquickrendercontrol_p.h3
-rw-r--r--src/quick/items/qquickscalegrid.cpp2
-rw-r--r--src/quick/items/qquickshadereffect.cpp23
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp8
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h1
-rw-r--r--src/quick/items/qquickspriteengine.cpp1
-rw-r--r--src/quick/items/qquickstateoperations.cpp92
-rw-r--r--src/quick/items/qquicktableview.cpp152
-rw-r--r--src/quick/items/qquicktableview_p_p.h16
-rw-r--r--src/quick/items/qquicktext.cpp92
-rw-r--r--src/quick/items/qquicktext_p.h2
-rw-r--r--src/quick/items/qquicktextedit.cpp13
-rw-r--r--src/quick/items/qquicktextedit_p.h2
-rw-r--r--src/quick/items/qquicktextinput.cpp60
-rw-r--r--src/quick/items/qquicktextinput_p_p.h2
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp5
-rw-r--r--src/quick/items/qquickwindow.cpp132
-rw-r--r--src/quick/items/qquickwindow_p.h18
-rw-r--r--src/quick/items/qquickwindowmodule_p.h5
64 files changed, 1345 insertions, 603 deletions
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index e13c0f6dae..89fafbe44d 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -288,7 +288,7 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
QPainter instead of the more expensive and likely less performing
JavaScript and Context2D approach.
- \sa Context2D QQuickPaintedItem
+ \sa Context2D, QQuickPaintedItem, {Pointer Handlers Example}
*/
QQuickCanvasItem::QQuickCanvasItem(QQuickItem *parent)
@@ -652,6 +652,10 @@ void QQuickCanvasItem::invalidateSceneGraph()
d->textureProvider = nullptr;
delete d->nodeTexture;
d->nodeTexture = nullptr;
+
+ // As we can expect(/hope) that the SG will be "good again", we can requestPaint ( which does 'markDirty(canvasWindow);' )
+ // Otherwise this Canvas will be "blank" when SG comes back
+ requestPaint();
}
void QQuickCanvasItem::schedulePolish()
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 64b8b80f8b..32546c5299 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -2459,7 +2459,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_beginPath(const QV4::Funct
\image qml-item-canvas-bezierCurveTo.png
\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}
+ \sa {https://web.archive.org/web/20130505222636if_/http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
@@ -3884,16 +3884,16 @@ void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
m_path.cubicTo(QPointF(cp1x, cp1y), QPointF(cp2x, cp2y), pt);
}
-void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
+void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, qreal radius)
{
QPointF p0(m_path.currentPosition());
QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
- float p1p0_length = std::sqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
- float p1p2_length = std::sqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
+ qreal p1p0_length = std::hypot(p1p0.x(), p1p0.y());
+ qreal p1p2_length = std::hypot(p1p2.x(), p1p2.y());
- double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
+ qreal cos_phi = QPointF::dotProduct(p1p0, p1p2) / (p1p0_length * p1p2_length);
// The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
// We could have used areCollinear() here, but since we're reusing
@@ -3903,16 +3903,16 @@ void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radiu
return;
}
- float tangent = radius / std::tan(std::acos(cos_phi) / 2);
- float factor_p1p0 = tangent / p1p0_length;
+ qreal tangent = radius / std::tan(std::acos(cos_phi) / 2);
+ qreal factor_p1p0 = tangent / p1p0_length;
QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
QPointF orth_p1p0(p1p0.y(), -p1p0.x());
- float orth_p1p0_length = std::sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
- float factor_ra = radius / orth_p1p0_length;
+ qreal orth_p1p0_length = std::hypot(orth_p1p0.x(), orth_p1p0.y());
+ qreal factor_ra = radius / orth_p1p0_length;
// angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
- double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
+ qreal cos_alpha = QPointF::dotProduct(orth_p1p0, p1p2) / (orth_p1p0_length * p1p2_length);
if (cos_alpha < 0.f)
orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
@@ -3920,20 +3920,15 @@ void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radiu
// calculate angles for addArc
orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
- float sa = std::acos(orth_p1p0.x() / orth_p1p0_length);
- if (orth_p1p0.y() < 0.f)
- sa = 2 * M_PI - sa;
+ qreal sa = std::atan2(orth_p1p0.y(), orth_p1p0.x());
// anticlockwise logic
bool anticlockwise = false;
- float factor_p1p2 = tangent / p1p2_length;
+ qreal factor_p1p2 = tangent / p1p2_length;
QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
- float orth_p1p2_length = std::sqrt(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
- float ea = std::acos(orth_p1p2.x() / orth_p1p2_length);
- if (orth_p1p2.y() < 0)
- ea = 2 * M_PI - ea;
+ qreal ea = std::atan2(orth_p1p2.y(), orth_p1p2.x());
if ((sa > ea) && ((sa - ea) < M_PI))
anticlockwise = true;
if ((sa < ea) && ((ea - sa) > M_PI))
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 92ec1e6470..ea1354725f 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -240,7 +240,7 @@ public:
void arc(qreal x, qreal y, qreal radius,
qreal startAngle, qreal endAngle,
bool anticlockwise);
- void addArcTo(const QPointF& p1, const QPointF& p2, float radius);
+ void addArcTo(const QPointF& p1, const QPointF& p2, qreal radius);
bool isPointInPath(qreal x, qreal y) const;
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index e111f908d0..71a5e414f6 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -120,8 +120,15 @@ void QQuickContext2DTexture::setItem(QQuickCanvasItem* item)
bool QQuickContext2DTexture::setCanvasWindow(const QRect& r)
{
- qreal canvasDevicePixelRatio = (m_item && m_item->window()) ?
- m_item->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio();
+ bool ok = false;
+ static qreal overriddenDevicePixelRatio =
+ !qEnvironmentVariableIsEmpty("QT_CANVAS_OVERRIDE_DEVICEPIXELRATIO") ?
+ qgetenv("QT_CANVAS_OVERRIDE_DEVICEPIXELRATIO").toFloat(&ok) : 0.0;
+ qreal canvasDevicePixelRatio = overriddenDevicePixelRatio;
+ if (overriddenDevicePixelRatio == 0.0) {
+ 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())),
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 0b593c0089..f63ab764f1 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -109,7 +109,7 @@ QT_BEGIN_NAMESPACE
This property sets an accessible description.
Similar to the name it describes the item. The description
can be a little more verbose and tell what the item does,
- for example the functionallity of the button it describes.
+ for example the functionality of the button it describes.
*/
/*!
@@ -406,9 +406,10 @@ void QQuickAccessibleAttached::setRole(QAccessible::Role role)
m_state.focusable = true;
break;
case QAccessible::StaticText:
- if (!m_stateExplicitlySet.readOnly) {
+ if (!m_stateExplicitlySet.readOnly)
m_state.readOnly = true;
- }
+ if (!m_stateExplicitlySet.focusable)
+ m_state.focusable = true;
break;
default:
break;
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 6d7d46bfd4..13f4b1f52f 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -189,7 +189,7 @@ public:
bool doAction(const QString &actionName);
void availableActions(QStringList *actions) const;
- Q_INVOKABLE static QString stripHtml(const QString &html);
+ Q_REVISION(6, 2) Q_INVOKABLE static QString stripHtml(const QString &html);
public Q_SLOTS:
void valueChanged() {
diff --git a/src/quick/items/qquickanchors.cpp b/src/quick/items/qquickanchors.cpp
index 8ee4229013..a2657c19f4 100644
--- a/src/quick/items/qquickanchors.cpp
+++ b/src/quick/items/qquickanchors.cpp
@@ -1409,5 +1409,7 @@ bool QQuickAnchorsPrivate::checkVAnchorValid(QQuickAnchorLine anchor) const
QT_END_NAMESPACE
+#include "moc_qquickanchors_p_p.cpp"
+
#include <moc_qquickanchors_p.cpp>
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index 5b3d9db091..a3f2494fba 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -894,7 +894,7 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
maybeUpdate();
}
- qreal frameCount = d->m_spriteEngine->spriteFrames();
+ int frameCount = d->m_spriteEngine->spriteFrames();
bool reverse = d->m_spriteEngine->sprite()->reverse();
if (reverse)
frameAt = (frameCount - 1) - frameAt;
@@ -931,15 +931,15 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
x2 = x1 - w;
y2 = y1;
} else {
- x2 = 1.0 - w;
+ x2 = d->m_sheetSize.width() - w;
y2 = y1 - h;
- if (y2 < 0.0) {
+ if (y2 < 0) {
//the last row may not fill the entire width
int maxRowFrames = d->m_sheetSize.width() / d->m_spriteEngine->spriteWidth();
if (d->m_spriteEngine->maxFrames() % maxRowFrames)
x2 = ((d->m_spriteEngine->maxFrames() % maxRowFrames) - 1) * w;
- y2 = 1.0 - h;
+ y2 = d->m_sheetSize.height() - h;
}
}
} else {
@@ -947,10 +947,10 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
x2 = x1 + w;
y2 = y1;
} else {
- x2 = 0.0;
+ x2 = 0;
y2 = y1 + h;
- if (y2 >= 1.0)
- y2 = 0.0;
+ if (y2 >= d->m_sheetSize.height())
+ y2 = 0;
}
}
diff --git a/src/quick/items/qquickcolorgroup.cpp b/src/quick/items/qquickcolorgroup.cpp
index ebbbf07499..2a039ec1b4 100644
--- a/src/quick/items/qquickcolorgroup.cpp
+++ b/src/quick/items/qquickcolorgroup.cpp
@@ -47,6 +47,8 @@
QT_BEGIN_NAMESPACE
/*!
+ \internal
+
\class QQuickColorGroup
\brief The QQuickColorGroup class represents a set of colors.
\inmodule QtQuick
@@ -592,3 +594,5 @@ void QQuickColorGroup::resetColor(QPalette::ColorRole role, Notifier notifier)
}
QT_END_NAMESPACE
+
+#include "moc_qquickcolorgroup_p.cpp"
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index e6ffcee2aa..ba81028822 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -482,7 +482,9 @@ void QQuickDragAttached::setKeys(const QStringList &keys)
\qmlattachedproperty stringlist QtQuick::Drag::mimeData
\since 5.2
- This property holds a map of mimeData that is used during startDrag.
+ This property holds a map from mime type to data that is used during startDrag.
+ The mime data needs to be a \c string, or an \c ArrayBuffer with the data encoded
+ according to the mime type.
*/
QVariantMap QQuickDragAttached::mimeData() const
@@ -767,8 +769,12 @@ Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedAct
QDrag *drag = new QDrag(source ? source : q);
QMimeData *mimeData = new QMimeData();
- for (auto it = externalMimeData.cbegin(), end = externalMimeData.cend(); it != end; ++it)
- mimeData->setData(it.key(), it.value().toString().toUtf8());
+ for (auto it = externalMimeData.cbegin(), end = externalMimeData.cend(); it != end; ++it) {
+ if (it.value().typeId() == QMetaType::QByteArray)
+ mimeData->setData(it.key(), it.value().toByteArray());
+ else
+ mimeData->setData(it.key(), it.value().toString().toUtf8());
+ }
drag->setMimeData(mimeData);
if (pixmapLoader.isReady()) {
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index b02a0ea2e1..38ec278adb 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -109,9 +109,12 @@ public:
void grab(QQuickItem *item) { m_items.insert(new Item(item)); }
iterator release(iterator at) { Item *item = *at; at = at.erase(); delete item; return at; }
+ auto& ignoreList() { return m_ignoreDragItems; }
+
private:
ItemList m_items;
+ QVarLengthArray<QQuickItem *, 4> m_ignoreDragItems;
QObject *m_target;
};
diff --git a/src/quick/items/qquickdroparea.cpp b/src/quick/items/qquickdroparea.cpp
index 21dc0979a9..077574cbd1 100644
--- a/src/quick/items/qquickdroparea.cpp
+++ b/src/quick/items/qquickdroparea.cpp
@@ -226,7 +226,7 @@ void QQuickDropArea::dragMoveEvent(QDragMoveEvent *event)
emit d->drag->positionChanged();
event->accept();
- QQuickDropEvent dragTargetEvent(d, event);
+ QQuickDragEvent dragTargetEvent(d, event);
emit positionChanged(&dragTargetEvent);
}
@@ -276,7 +276,7 @@ void QQuickDropArea::dragEnterEvent(QDragEnterEvent *event)
event->accept();
- QQuickDropEvent dragTargetEvent(d, event);
+ QQuickDragEvent dragTargetEvent(d, event);
emit entered(&dragTargetEvent);
if (!event->isAccepted())
return;
@@ -325,7 +325,7 @@ void QQuickDropArea::dropEvent(QDropEvent *event)
if (!d->containsDrag)
return;
- QQuickDropEvent dragTargetEvent(d, event);
+ QQuickDragEvent dragTargetEvent(d, event);
emit dropped(&dragTargetEvent);
d->containsDrag = false;
@@ -337,7 +337,7 @@ void QQuickDropArea::dropEvent(QDropEvent *event)
/*!
\qmltype DragEvent
- \instantiates QQuickDropEvent
+ \instantiates QQuickDragEvent
\inqmlmodule QtQuick
\ingroup qtquick-input-events
\brief Provides information about a drag event.
@@ -514,7 +514,7 @@ void QQuickDropArea::dropEvent(QDropEvent *event)
easily be translated into a QByteArray. \a format should be one contained in the \l formats property.
*/
-QObject *QQuickDropEvent::source() const
+QObject *QQuickDragEvent::source() const
{
if (const QQuickDragMimeData *dragMime = qobject_cast<const QQuickDragMimeData *>(event->mimeData()))
return dragMime->source();
@@ -522,57 +522,57 @@ QObject *QQuickDropEvent::source() const
return event->source();
}
-QStringList QQuickDropEvent::keys() const
+QStringList QQuickDragEvent::keys() const
{
return d->getKeys(event->mimeData());
}
-bool QQuickDropEvent::hasColor() const
+bool QQuickDragEvent::hasColor() const
{
return event->mimeData()->hasColor();
}
-bool QQuickDropEvent::hasHtml() const
+bool QQuickDragEvent::hasHtml() const
{
return event->mimeData()->hasHtml();
}
-bool QQuickDropEvent::hasText() const
+bool QQuickDragEvent::hasText() const
{
return event->mimeData()->hasText();
}
-bool QQuickDropEvent::hasUrls() const
+bool QQuickDragEvent::hasUrls() const
{
return event->mimeData()->hasUrls();
}
-QVariant QQuickDropEvent::colorData() const
+QVariant QQuickDragEvent::colorData() const
{
return event->mimeData()->colorData();
}
-QString QQuickDropEvent::html() const
+QString QQuickDragEvent::html() const
{
return event->mimeData()->html();
}
-QString QQuickDropEvent::text() const
+QString QQuickDragEvent::text() const
{
return event->mimeData()->text();
}
-QList<QUrl> QQuickDropEvent::urls() const
+QList<QUrl> QQuickDragEvent::urls() const
{
return event->mimeData()->urls();
}
-QStringList QQuickDropEvent::formats() const
+QStringList QQuickDragEvent::formats() const
{
return event->mimeData()->formats();
}
-void QQuickDropEvent::getDataAsString(QQmlV4Function *args)
+void QQuickDragEvent::getDataAsString(QQmlV4Function *args)
{
if (args->length() != 0) {
QV4::ExecutionEngine *v4 = args->v4engine();
@@ -584,7 +584,7 @@ void QQuickDropEvent::getDataAsString(QQmlV4Function *args)
}
}
-void QQuickDropEvent::getDataAsArrayBuffer(QQmlV4Function *args)
+void QQuickDragEvent::getDataAsArrayBuffer(QQmlV4Function *args)
{
if (args->length() != 0) {
QV4::ExecutionEngine *v4 = args->v4engine();
@@ -595,12 +595,12 @@ void QQuickDropEvent::getDataAsArrayBuffer(QQmlV4Function *args)
}
}
-void QQuickDropEvent::acceptProposedAction(QQmlV4Function *)
+void QQuickDragEvent::acceptProposedAction(QQmlV4Function *)
{
event->acceptProposedAction();
}
-void QQuickDropEvent::accept(QQmlV4Function *args)
+void QQuickDragEvent::accept(QQmlV4Function *args)
{
Qt::DropAction action = event->dropAction();
diff --git a/src/quick/items/qquickdroparea_p.h b/src/quick/items/qquickdroparea_p.h
index 74f16df9cc..122029a18a 100644
--- a/src/quick/items/qquickdroparea_p.h
+++ b/src/quick/items/qquickdroparea_p.h
@@ -61,7 +61,7 @@ QT_REQUIRE_CONFIG(quick_draganddrop);
QT_BEGIN_NAMESPACE
class QQuickDropAreaPrivate;
-class QQuickDropEvent : public QObject
+class QQuickDragEvent : public QObject
{
Q_OBJECT
Q_PROPERTY(qreal x READ x)
@@ -81,10 +81,11 @@ class QQuickDropEvent : public QObject
Q_PROPERTY(QString text READ text)
Q_PROPERTY(QList<QUrl> urls READ urls)
Q_PROPERTY(QStringList formats READ formats)
- QML_ANONYMOUS
+ QML_NAMED_ELEMENT(DragEvent)
+ QML_UNCREATABLE("DragEvent is only meant to be created by DropArea")
QML_ADDED_IN_VERSION(2, 0)
public:
- QQuickDropEvent(QQuickDropAreaPrivate *d, QDropEvent *event) : d(d), event(event) {}
+ QQuickDragEvent(QQuickDropAreaPrivate *d, QDropEvent *event) : d(d), event(event) {}
qreal x() const { return event->position().x(); }
qreal y() const { return event->position().y(); }
@@ -176,10 +177,10 @@ Q_SIGNALS:
void keysChanged();
void sourceChanged();
- void entered(QQuickDropEvent *drag);
+ void entered(QQuickDragEvent *drag);
void exited();
- void positionChanged(QQuickDropEvent *drag);
- void dropped(QQuickDropEvent *drop);
+ void positionChanged(QQuickDragEvent *drag);
+ void dropped(QQuickDragEvent *drop);
protected:
void dragMoveEvent(QDragMoveEvent *event) override;
@@ -194,7 +195,6 @@ private:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQuickDropEvent)
QML_DECLARE_TYPE(QQuickDropArea)
#endif // QQUICKDROPAREA_P_H
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index ba9082cc2a..f9b5b80a92 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -289,6 +289,7 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
/*!
\qmlproperty int QtQuick::MouseEvent::source
\since 5.7
+ \deprecated [6.2] Use \l {Qt Quick Input Handlers}{input handlers} with \l {PointerDeviceHandler::acceptedDevices}{acceptedDevices} set.
This property holds the source of the mouse event.
@@ -364,10 +365,9 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
\ingroup qtquick-input-events
\brief Provides information about a mouse wheel event.
- The position of the mouse can be found via the
- \l {Item::x} {x} and \l {Item::y} {y} properties.
+ The position of the mouse can be found via the \l x and \l y properties.
- \sa MouseArea
+ \sa WheelHandler, MouseArea
*/
/*!
@@ -380,16 +380,20 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
\qmlproperty real QtQuick::WheelEvent::y
These properties hold the coordinates of the position supplied by the wheel event.
+
+ \sa QWheelEvent::position()
*/
/*!
\qmlproperty bool QtQuick::WheelEvent::accepted
- Setting \a accepted to true prevents the wheel event from being
- propagated to items below this item.
+ Setting \a accepted to \c true prevents the wheel event from being
+ propagated to items below the receiving item or handler.
- Generally, if the item acts on the wheel event then it should be accepted
+ Generally, if the item acts on the wheel event, it should be accepted
so that items lower in the stacking order do not also respond to the same event.
+
+ \sa QWheelEvent::accepted
*/
/*!
@@ -403,32 +407,39 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
\li \l {Qt::RightButton} {Qt.RightButton}
\li \l {Qt::MiddleButton} {Qt.MiddleButton}
\endlist
+
+ \sa QWheelEvent::buttons()
*/
/*!
\qmlproperty point QtQuick::WheelEvent::angleDelta
- This property holds the distance that the wheel is rotated in wheel degrees.
- The x and y cordinate of this property holds the delta in horizontal and
- vertical orientation.
+ This property holds the relative amount that the wheel was rotated, in
+ eighths of a degree. The \c x and \c y coordinates of this property hold
+ the delta in horizontal and vertical orientations, respectively.
A positive value indicates that the wheel was rotated up/right;
a negative value indicates that the wheel was rotated down/left.
- Most mouse types work in steps of 15 degrees, in which case the delta value is a
- multiple of 120; i.e., 120 units * 1/8 = 15 degrees.
+ Most mouse types work in steps of \c 15 degrees, in which case the delta value is a
+ multiple of \c 120; i.e., \c {120 units * 1/8 = 15 degrees}.
+
+ \sa QWheelEvent::angleDelta()
*/
/*!
\qmlproperty point QtQuick::WheelEvent::pixelDelta
This property holds the delta in screen pixels and is available in platforms that
- have high-resolution trackpads, such as \macos.
- The x and y cordinate of this property holds the delta in horizontal and
- vertical orientation. The value should be used directly to scroll content on screen.
+ have high-resolution \l {QInputDevice::DeviceType::TouchPad}{trackpads}, such as \macos.
+ The \c x and \c y coordinates of this property hold the delta in horizontal
+ and vertical orientations, respectively. The values can be used directly to
+ scroll content on screen.
- For platforms without high-resolution trackpad support, pixelDelta will always be (0,0),
- and angleDelta should be used instead.
+ For platforms without \l {QInputDevice::Capability::PixelScroll}{high-resolution trackpad}
+ support, pixelDelta will always be \c {(0,0)}, and \l angleDelta should be used instead.
+
+ \sa QWheelEvent::pixelDelta()
*/
/*!
@@ -449,7 +460,7 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
For example, to react to a Control key pressed during the wheel event:
\qml
- MouseArea {
+ WheelHandler {
onWheel: (wheel)=> {
if (wheel.modifiers & Qt.ControlModifier) {
adjustZoom(wheel.angleDelta.y / 120);
@@ -457,6 +468,8 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
}
}
\endqml
+
+ \sa QWheelEvent::modifiers()
*/
/*!
@@ -478,7 +491,11 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
negate the angleDelta or pixelDelta values.
\note Many platforms provide no such information. On such platforms
- \l inverted always returns false.
+ \c inverted always returns \c false.
+
+ \sa QWheelEvent::inverted()
*/
QT_END_NAMESPACE
+
+#include "moc_qquickevents_p_p.cpp"
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 14bf190fe9..e050561ac5 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -43,6 +43,8 @@
#include "qquickwindow.h"
#include "qquickwindow_p.h"
#include "qquickevents_p_p.h"
+#include "qquickmousearea_p.h"
+#include "qquickdrag_p.h"
#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquicktransition_p.h>
@@ -52,6 +54,7 @@
#include <QtGui/qevent.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qeventpoint_p.h>
#include <QtGui/qstylehints.h>
#include <QtCore/qmath.h>
#include "qplatformdefs.h"
@@ -137,7 +140,8 @@ void QQuickFlickableVisibleArea::updateVisible()
qreal pagePos = 0;
qreal pageSize = 0;
if (!qFuzzyIsNull(maxYBounds)) {
- pagePos = (-p->vData.move.value() + flickable->minYExtent()) / maxYBounds;
+ qreal y = p->pixelAligned ? Round(p->vData.move.value()) : p->vData.move.value();
+ pagePos = (-y + flickable->minYExtent()) / maxYBounds;
pageSize = viewheight / maxYBounds;
}
@@ -155,7 +159,8 @@ void QQuickFlickableVisibleArea::updateVisible()
const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
const qreal maxXBounds = maxxextent + viewwidth;
if (!qFuzzyIsNull(maxXBounds)) {
- pagePos = (-p->hData.move.value() + flickable->minXExtent()) / maxXBounds;
+ qreal x = p->pixelAligned ? Round(p->hData.move.value()) : p->hData.move.value();
+ pagePos = (-x + flickable->minXExtent()) / maxXBounds;
pageSize = viewwidth / maxXBounds;
} else {
pagePos = 0;
@@ -253,9 +258,27 @@ QQuickFlickablePrivate::AxisData::~AxisData()
delete transitionToBounds;
}
+class QQuickFlickableContentItem : public QQuickItem
+{
+ /*!
+ \internal
+ The flickable area inside the viewport can be bigger than the bounds of the
+ content item itself, if the flickable is using non-zero extents (as returned
+ by e.g minXExtent()). Since the default implementation in QQuickItem::contains()
+ only checks if the point is inside the bounds of the item, we need to override it
+ to check the extents as well. The easist way to do this is to simply check if the
+ point is inside the bounds of the flickable rather than the content item.
+ */
+ bool contains(const QPointF &point) const override
+ {
+ const QQuickItem *flickable = parentItem();
+ const QPointF posInFlickable = flickable->mapFromItem(this, point);
+ return flickable->contains(posInFlickable);
+ }
+};
QQuickFlickablePrivate::QQuickFlickablePrivate()
- : contentItem(new QQuickItem)
+ : contentItem(new QQuickFlickableContentItem)
, hData(this, &QQuickFlickablePrivate::setViewportX)
, vData(this, &QQuickFlickablePrivate::setViewportY)
, hMoved(false), vMoved(false)
@@ -293,16 +316,17 @@ void QQuickFlickablePrivate::init()
viewportPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
}
-/*
- Returns the amount to overshoot by given a velocity.
- Will be roughly in range 0 - size/4
+/*!
+ \internal
+ Returns the distance to overshoot, given \a velocity.
+ Will be in range 0 - velocity / 3, but limited to a max of QML_FLICK_OVERSHOOT
*/
-qreal QQuickFlickablePrivate::overShootDistance(qreal size) const
+qreal QQuickFlickablePrivate::overShootDistance(qreal velocity) const
{
if (maxVelocity <= 0)
- return 0.0;
+ return 0;
- return qMin(qreal(QML_FLICK_OVERSHOOT), size/3);
+ return qMin(qreal(QML_FLICK_OVERSHOOT), velocity / 3);
}
void QQuickFlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity)
@@ -329,7 +353,7 @@ void QQuickFlickablePrivate::AxisData::updateVelocity()
}
}
-void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &)
+void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeom)
{
Q_Q(QQuickFlickable);
if (item == contentItem) {
@@ -338,8 +362,14 @@ void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometr
orient |= Qt::Horizontal;
if (change.yChange())
orient |= Qt::Vertical;
- if (orient)
+ if (orient) {
q->viewportMoved(orient);
+ const QPointF deltaMoved = item->position() - oldGeom.topLeft();
+ if (hData.contentPositionChangedExternallyDuringDrag)
+ hData.pressPos += deltaMoved.x();
+ if (vData.contentPositionChangedExternallyDuringDrag)
+ vData.pressPos += deltaMoved.y();
+ }
if (orient & Qt::Horizontal)
emit q->contentXChanged();
if (orient & Qt::Vertical)
@@ -531,8 +561,8 @@ void QQuickFlickablePrivate::updateBeginningEnd()
const qreal maxyextent = -q->maxYExtent();
const qreal minyextent = -q->minYExtent();
const qreal ypos = -vData.move.value();
- bool atBeginning = fuzzyLessThanOrEqualTo(ypos, minyextent);
- bool atEnd = fuzzyLessThanOrEqualTo(maxyextent, ypos);
+ bool atBeginning = fuzzyLessThanOrEqualTo(ypos, std::ceil(minyextent));
+ bool atEnd = fuzzyLessThanOrEqualTo(std::floor(maxyextent), ypos);
if (atBeginning != vData.atBeginning) {
vData.atBeginning = atBeginning;
@@ -551,8 +581,8 @@ void QQuickFlickablePrivate::updateBeginningEnd()
const qreal maxxextent = -q->maxXExtent();
const qreal minxextent = -q->minXExtent();
const qreal xpos = -hData.move.value();
- atBeginning = fuzzyLessThanOrEqualTo(xpos, minxextent);
- atEnd = fuzzyLessThanOrEqualTo(maxxextent, xpos);
+ atBeginning = fuzzyLessThanOrEqualTo(xpos, std::ceil(minxextent));
+ atEnd = fuzzyLessThanOrEqualTo(std::floor(maxxextent), xpos);
if (atBeginning != hData.atBeginning) {
hData.atBeginning = atBeginning;
@@ -722,7 +752,8 @@ void QQuickFlickablePrivate::updateBeginningEnd()
/*!
\qmlsignal QtQuick::Flickable::flickEnded()
- This signal is emitted when the view stops moving due to a flick.
+ This signal is emitted when the view stops moving after a flick
+ or a series of flicks.
*/
/*!
@@ -799,8 +830,11 @@ void QQuickFlickable::setContentX(qreal pos)
d->hData.vTime = d->timeline.time();
if (isMoving() || isFlicking())
movementEnding(true, false);
- if (!qFuzzyCompare(-pos, d->hData.move.value()))
+ if (!qFuzzyCompare(-pos, d->hData.move.value())) {
+ d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
d->hData.move.setValue(-pos);
+ d->hData.contentPositionChangedExternallyDuringDrag = false;
+ }
}
qreal QQuickFlickable::contentY() const
@@ -817,8 +851,11 @@ void QQuickFlickable::setContentY(qreal pos)
d->vData.vTime = d->timeline.time();
if (isMoving() || isFlicking())
movementEnding(false, true);
- if (!qFuzzyCompare(-pos, d->vData.move.value()))
+ if (!qFuzzyCompare(-pos, d->vData.move.value())) {
+ d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
d->vData.move.setValue(-pos);
+ d->vData.contentPositionChangedExternallyDuringDrag = false;
+ }
}
/*!
@@ -1032,6 +1069,17 @@ void QQuickFlickable::setSynchronousDrag(bool v)
}
}
+/*! \internal
+ Take the velocity of the first point from the given \a event and transform
+ it to the local coordinate system (taking scale and rotation into account).
+*/
+QVector2D QQuickFlickablePrivate::firstPointLocalVelocity(QPointerEvent *event)
+{
+ QTransform transform = windowToItemTransform();
+ // rotate and scale the velocity vector from scene to local
+ return QVector2D(transform.map(event->point(0).velocity().toPointF()) - transform.map(QPointF()));
+}
+
qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event) const
{
if (0 != event->timestamp())
@@ -1103,7 +1151,9 @@ void QQuickFlickablePrivate::maybeBeginDrag(qint64 currentTimestamp, const QPoin
pressPos = pressPosn;
hData.pressPos = hData.move.value();
vData.pressPos = vData.move.value();
- bool wasFlicking = hData.flicking || vData.flicking;
+ const bool wasFlicking = hData.flicking || vData.flicking;
+ hData.flickingWhenDragBegan = hData.flicking;
+ vData.flickingWhenDragBegan = vData.flicking;
if (hData.flicking) {
hData.flicking = false;
emit q->flickingHorizontallyChanged();
@@ -1333,15 +1383,15 @@ void QQuickFlickablePrivate::handleMoveEvent(QPointerEvent *event)
{
Q_Q(QQuickFlickable);
if (!interactive || lastPosTime == -1 ||
- (event->isSinglePointEvent() && static_cast<QSinglePointEvent *>(event)->buttons() == Qt::NoButton))
+ (event->isSinglePointEvent() && !static_cast<QSinglePointEvent *>(event)->buttons().testFlag(Qt::LeftButton)))
return;
qint64 currentTimestamp = computeCurrentTime(event);
const auto &firstPoint = event->points().first();
const auto &pos = firstPoint.position();
- QVector2D deltas = QVector2D(pos - q->mapFromGlobal(firstPoint.globalPressPosition()));
+ const QVector2D deltas = QVector2D(pos - q->mapFromGlobal(firstPoint.globalPressPosition()));
+ const QVector2D velocity = firstPointLocalVelocity(event);
bool overThreshold = false;
- QVector2D velocity = event->point(0).velocity();
if (q->yflick())
overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.y(), Qt::YAxis, firstPoint);
@@ -1373,12 +1423,14 @@ void QQuickFlickablePrivate::handleReleaseEvent(QPointerEvent *event)
bool canBoost = false;
const auto pos = event->points().first().position();
- const auto pressPos = event->points().first().pressPosition();
+ const auto pressPos = q->mapFromGlobal(event->points().first().globalPressPosition());
+ const QVector2D eventVelocity = firstPointLocalVelocity(event);
+ qCDebug(lcVel) << event->deviceType() << event->type() << "velocity" << event->points().first().velocity() << "transformed to local" << eventVelocity;
qreal vVelocity = 0;
if (elapsed < 100 && vData.velocity != 0.) {
vVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
- ? event->point(0).velocity().y() : vData.velocity);
+ ? eventVelocity.y() : vData.velocity);
}
if ((vData.atBeginning && vVelocity > 0.) || (vData.atEnd && vVelocity < 0.)) {
vVelocity /= 2;
@@ -1393,7 +1445,7 @@ void QQuickFlickablePrivate::handleReleaseEvent(QPointerEvent *event)
qreal hVelocity = 0;
if (elapsed < 100 && hData.velocity != 0.) {
hVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
- ? event->point(0).velocity().x() : hData.velocity);
+ ? eventVelocity.x() : hData.velocity);
}
if ((hData.atBeginning && hVelocity > 0.) || (hData.atEnd && hVelocity < 0.)) {
hVelocity /= 2;
@@ -1599,7 +1651,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
return;
}
- if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull()) {
+ if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull() || event->phase() == Qt::NoScrollPhase) {
// no pixel delta (physical mouse wheel, or "dumb" touchpad), so use angleDelta
int xDelta = event->angleDelta().x();
int yDelta = event->angleDelta().y();
@@ -1620,9 +1672,9 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
d->vData.addVelocitySample(instVelocity, d->maxVelocity);
d->vData.updateVelocity();
if ((yDelta > 0 && contentY() > -minYExtent()) || (yDelta < 0 && contentY() < -maxYExtent())) {
- d->flickY(d->vData.velocity);
- d->flickingStarted(false, true);
- if (d->vData.flicking) {
+ const bool newFlick = d->flickY(d->vData.velocity);
+ if (newFlick && (d->vData.atBeginning != (yDelta > 0) || d->vData.atEnd != (yDelta < 0))) {
+ d->flickingStarted(false, true);
d->vMoved = true;
movementStarting();
}
@@ -1637,9 +1689,9 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
d->hData.addVelocitySample(instVelocity, d->maxVelocity);
d->hData.updateVelocity();
if ((xDelta > 0 && contentX() > -minXExtent()) || (xDelta < 0 && contentX() < -maxXExtent())) {
- d->flickX(d->hData.velocity);
- d->flickingStarted(true, false);
- if (d->hData.flicking) {
+ const bool newFlick = d->flickX(d->hData.velocity);
+ if (newFlick && (d->hData.atBeginning != (xDelta > 0) || d->hData.atEnd != (xDelta < 0))) {
+ d->flickingStarted(true, false);
d->hMoved = true;
movementStarting();
}
@@ -1867,13 +1919,13 @@ void QQuickFlickable::viewportMoved(Qt::Orientations orient)
{
Q_D(QQuickFlickable);
if (orient & Qt::Vertical)
- d->viewportAxisMoved(d->vData, minYExtent(), maxYExtent(), height(), d->fixupY_callback);
+ d->viewportAxisMoved(d->vData, minYExtent(), maxYExtent(), d->fixupY_callback);
if (orient & Qt::Horizontal)
- d->viewportAxisMoved(d->hData, minXExtent(), maxXExtent(), width(), d->fixupX_callback);
+ d->viewportAxisMoved(d->hData, minXExtent(), maxXExtent(), d->fixupX_callback);
d->updateBeginningEnd();
}
-void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent,
QQuickTimeLineCallback::Callback fixupCallback)
{
if (!scrollingPhase && (pressed || calcVelocity)) {
@@ -1889,10 +1941,15 @@ void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent,
} else {
if (timeline.time() > data.vTime) {
velocityTimeline.reset(data.smoothVelocity);
- qreal velocity = (data.lastPos - data.move.value()) * 1000 / (timeline.time() - data.vTime);
- if (!qFuzzyCompare(data.smoothVelocity.value(), velocity))
- qCDebug(lcVel) << "velocity" << data.smoothVelocity.value() << "->" << velocity;
- data.smoothVelocity.setValue(velocity);
+ int dt = timeline.time() - data.vTime;
+ if (dt > 2) {
+ qreal velocity = (data.lastPos - data.move.value()) * 1000 / dt;
+ if (!qFuzzyCompare(data.smoothVelocity.value(), velocity))
+ qCDebug(lcVel) << "velocity" << data.smoothVelocity.value() << "->" << velocity
+ << "computed as (" << data.lastPos << "-" << data.move.value() << ") * 1000 / ("
+ << timeline.time() << "-" << data.vTime << ")";
+ data.smoothVelocity.setValue(velocity);
+ }
}
}
@@ -1904,7 +1961,7 @@ void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent,
? data.move.value() - minExtent
: maxExtent - data.move.value();
data.inOvershoot = true;
- qreal maxDistance = overShootDistance(vSize) - overBound;
+ qreal maxDistance = overShootDistance(qAbs(data.smoothVelocity.value())) - overBound;
resetTimeline(data);
if (maxDistance > 0)
timeline.accel(data.move, -data.smoothVelocity.value(), deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
@@ -2513,6 +2570,23 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
bool receiverDisabled = receiver && !receiver->isEnabled();
bool stealThisEvent = d->stealMouse;
bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab());
+ bool receiverRelinquishGrab = false;
+
+ // Special case for MouseArea, try to guess what it does with the event
+ if (auto *mouseArea = qmlobject_cast<QQuickMouseArea *>(receiver)) {
+ bool preventStealing = mouseArea->preventStealing();
+ if (mouseArea->drag() && mouseArea->drag()->target())
+ preventStealing = true;
+ if (!preventStealing && receiverKeepsGrab) {
+ receiverRelinquishGrab = !receiverDisabled
+ || (QQuickDeliveryAgentPrivate::isMouseEvent(event)
+ && firstPoint.state() == QEventPoint::State::Pressed
+ && (receiver->acceptedMouseButtons() & static_cast<QMouseEvent *>(event)->button()));
+ if (receiverRelinquishGrab)
+ receiverKeepsGrab = false;
+ }
+ }
+
if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) {
QScopedPointer<QPointerEvent> localizedEvent(QQuickDeliveryAgentPrivate::clonePointerEvent(event, localPos));
localizedEvent->setAccepted(false);
@@ -2523,7 +2597,9 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
case QEventPoint::State::Pressed:
d->handlePressEvent(localizedEvent.data());
d->captureDelayedPress(receiver, event);
- stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
+ // never grab the pointing device on press during filtering: do it later, during a move
+ d->stealMouse = false;
+ stealThisEvent = false;
break;
case QEventPoint::State::Released:
d->handleReleaseEvent(localizedEvent.data());
@@ -2540,7 +2616,7 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
event->setExclusiveGrabber(firstPoint, this);
}
- const bool filtered = stealThisEvent || d->delayedPressEvent || receiverDisabled;
+ const bool filtered = !receiverRelinquishGrab && (stealThisEvent || d->delayedPressEvent || receiverDisabled);
if (filtered) {
event->setAccepted(true);
}
@@ -2566,8 +2642,19 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
{
Q_D(QQuickFlickable);
+ QPointerEvent *pointerEvent = e->isPointerEvent() ? static_cast<QPointerEvent *>(e) : nullptr;
+
+ auto wantsPointerEvent_helper = [this, d, i, pointerEvent]() {
+ Q_ASSERT(pointerEvent);
+ QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, this);
+ const bool wants = d->wantsPointerEvent(pointerEvent);
+ // re-localize event back to \a i before returning
+ QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, i);
+ return wants;
+ };
+
if (!isVisible() || !isEnabled() || !isInteractive() ||
- (e->isPointerEvent() && !d->wantsPointerEvent(static_cast<QPointerEvent *>(e)))) {
+ (pointerEvent && !wantsPointerEvent_helper())) {
d->cancelInteraction();
return QQuickItem::childMouseEventFilter(i, e);
}
@@ -2579,8 +2666,8 @@ bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
qCDebug(lcFilter) << "filtering UngrabMouse" << spe->points().first() << "for" << i << "grabber is" << grabber;
if (grabber != this)
mouseUngrabEvent(); // A child has been ungrabbed
- } else if (e->isPointerEvent()) {
- return filterPointerEvent(i, static_cast<QPointerEvent *>(e));
+ } else if (pointerEvent) {
+ return filterPointerEvent(i, pointerEvent);
}
return QQuickItem::childMouseEventFilter(i, e);
@@ -2848,6 +2935,12 @@ void QQuickFlickable::movementStarting()
if (!wasMoving && (d->hData.moving || d->vData.moving)) {
emit movingChanged();
emit movementStarted();
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleEvent ev(this, QAccessible::ScrollingStart);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
}
}
@@ -2861,7 +2954,7 @@ void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding)
Q_D(QQuickFlickable);
// emit flicking signals
- bool wasFlicking = d->hData.flicking || d->vData.flicking;
+ const bool wasFlicking = d->hData.flicking || d->vData.flicking;
if (hMovementEnding && d->hData.flicking) {
d->hData.flicking = false;
emit flickingHorizontallyChanged();
@@ -2873,6 +2966,10 @@ void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding)
if (wasFlicking && (!d->hData.flicking || !d->vData.flicking)) {
emit flickingChanged();
emit flickEnded();
+ } else if (d->hData.flickingWhenDragBegan || d->vData.flickingWhenDragBegan) {
+ d->hData.flickingWhenDragBegan = !hMovementEnding;
+ d->vData.flickingWhenDragBegan = !vMovementEnding;
+ emit flickEnded();
}
// emit moving signals
@@ -2892,6 +2989,12 @@ void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding)
if (wasMoving && !isMoving()) {
emit movingChanged();
emit movementEnded();
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleEvent ev(this, QAccessible::ScrollingEnd);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
}
if (hMovementEnding) {
@@ -3019,4 +3122,6 @@ void QQuickFlickable::setBoundsMovement(BoundsMovement movement)
QT_END_NAMESPACE
+#include "moc_qquickflickable_p_p.cpp"
+
#include "moc_qquickflickable_p.cpp"
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index a003a69b9f..c748bb9f43 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -107,8 +107,9 @@ public:
, smoothVelocity(fp), atEnd(false), atBeginning(true)
, transitionToSet(false)
, fixingUp(false), inOvershoot(false), inRebound(false), moving(false), flicking(false)
- , dragging(false), extentsChanged(false)
+ , flickingWhenDragBegan(false), dragging(false), extentsChanged(false)
, explicitValue(false), minExtentDirty(true), maxExtentDirty(true)
+ , contentPositionChangedExternallyDuringDrag(false)
, unused(0)
{}
@@ -119,6 +120,7 @@ public:
dragStartOffset = 0;
fixingUp = false;
inOvershoot = false;
+ contentPositionChangedExternallyDuringDrag = false;
}
void markExtentsDirty() {
@@ -156,20 +158,22 @@ public:
int vTime;
QQuickFlickablePrivate::Velocity smoothVelocity;
QPODVector<qreal,10> velocityBuffer;
- bool atEnd : 1;
- bool atBeginning : 1;
- bool transitionToSet : 1;
- bool fixingUp : 1;
- bool inOvershoot : 1;
- bool inRebound : 1;
- bool moving : 1;
- bool flicking : 1;
- bool dragging : 1;
- bool extentsChanged : 1;
- bool explicitValue : 1;
- mutable bool minExtentDirty : 1;
- mutable bool maxExtentDirty : 1;
- uint unused : 19;
+ uint atEnd : 1;
+ uint atBeginning : 1;
+ uint transitionToSet : 1;
+ uint fixingUp : 1;
+ uint inOvershoot : 1;
+ uint inRebound : 1;
+ uint moving : 1;
+ uint flicking : 1;
+ uint flickingWhenDragBegan : 1;
+ uint dragging : 1;
+ uint extentsChanged : 1;
+ uint explicitValue : 1;
+ mutable uint minExtentDirty : 1;
+ mutable uint maxExtentDirty : 1;
+ uint contentPositionChangedExternallyDuringDrag : 1;
+ uint unused : 17;
};
bool flickX(qreal velocity);
@@ -195,7 +199,7 @@ public:
void setViewportX(qreal x);
void setViewportY(qreal y);
- qreal overShootDistance(qreal size) const;
+ qreal overShootDistance(qreal velocity) const;
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override;
@@ -256,7 +260,7 @@ public:
QQuickFlickable::BoundsMovement boundsMovement;
QQuickTransition *rebound;
- void viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ void viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent,
QQuickTimeLineCallback::Callback fixupCallback);
void handlePressEvent(QPointerEvent *);
@@ -268,6 +272,7 @@ public:
const QVector2D &deltas, bool overThreshold, bool momentum,
bool velocitySensitiveOverBounds, const QVector2D &velocity);
+ QVector2D firstPointLocalVelocity(QPointerEvent *event);
qint64 computeCurrentTime(QInputEvent *event) const;
qreal devicePixelRatio() const;
@@ -278,7 +283,7 @@ public:
static void data_clear(QQmlListProperty<QObject> *);
};
-class QQuickFlickableVisibleArea : public QObject
+class Q_QUICK_PRIVATE_EXPORT QQuickFlickableVisibleArea : public QObject
{
Q_OBJECT
diff --git a/src/quick/items/qquickflipable.cpp b/src/quick/items/qquickflipable.cpp
index a338985622..87112c8b93 100644
--- a/src/quick/items/qquickflipable.cpp
+++ b/src/quick/items/qquickflipable.cpp
@@ -39,7 +39,7 @@
#include "qquickflipable_p.h"
#include "qquickitem_p.h"
-
+#include "qquicktranslate_p.h"
#include <QtQml/qqmlinfo.h>
@@ -237,9 +237,20 @@ void QQuickFlipable::updatePolish()
d->updateSide();
}
-// determination on the currently visible side of the flipable
-// has to be done on the complete scene transform to give
-// correct results.
+/*! \internal
+ Flipable must use the complete scene transform to correctly determine the
+ currently visible side.
+
+ It must also be independent of camera distance, in case the contents are
+ too wide: for rotation transforms we simply call QMatrix4x4::rotate(),
+ whereas QQuickRotation::applyTo(QMatrix4x4*) calls
+ QMatrix4x4::projectedRotate() which by default assumes the camera distance
+ is 1024 virtual pixels. So for example if contents inside Flipable are to
+ be flipped around the y axis, and are wider than 1024*2, some of the
+ rendering goes behind the "camera". That's expected for rendering (since we
+ didn't provide API to change camera distance), but not ok for deciding when
+ to flip.
+*/
void QQuickFlipablePrivate::updateSide()
{
Q_Q(QQuickFlipable);
@@ -249,8 +260,39 @@ void QQuickFlipablePrivate::updateSide()
sideDirty = false;
- QTransform sceneTransform;
- itemToParentTransform(sceneTransform);
+ QMatrix4x4 sceneTransform;
+
+ const qreal tx = x.value();
+ const qreal ty = y.value();
+ if (!qFuzzyIsNull(tx) || !qFuzzyIsNull(ty))
+ sceneTransform.translate(tx, ty);
+
+ for (const auto *transform : std::as_const(transforms)) {
+ if (const auto *rot = qobject_cast<const QQuickRotation *>(transform)) {
+ // rotation is a special case: we want to call rotate() instead of projectedRotate()
+ const auto angle = rot->angle();
+ const auto axis = rot->axis();
+ if (!(qFuzzyIsNull(angle) || axis.isNull())) {
+ sceneTransform.translate(rot->origin());
+ sceneTransform.rotate(angle, axis.x(), axis.y(), axis.z());
+ sceneTransform.translate(-rot->origin());
+ }
+ } else {
+ transform->applyTo(&sceneTransform);
+ }
+ }
+
+ const bool hasRotation = !qFuzzyIsNull(rotation());
+ const bool hasScale = !qFuzzyCompare(scale(), 1);
+ if (hasScale || hasRotation) {
+ QPointF tp = computeTransformOrigin();
+ sceneTransform.translate(tp.x(), tp.y());
+ if (hasScale)
+ sceneTransform.scale(scale(), scale());
+ if (hasRotation)
+ sceneTransform.rotate(rotation(), 0, 0, 1);
+ sceneTransform.translate(-tp.x(), -tp.y());
+ }
QPointF p1(0, 0);
QPointF p2(1, 0);
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index 90fa05f492..73fe84fdef 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -208,6 +208,8 @@ public:
void updateHeader() override;
void updateFooter() override;
+ void initializeComponentItem(QQuickItem *item) const override;
+
void changedVisibleIndex(int newIndex) override;
void initializeCurrentItem() override;
@@ -349,9 +351,27 @@ qreal QQuickGridViewPrivate::rowPosAt(int modelIndex) const
return lastItem->rowPos() + rows * rowSize();
}
}
- return (modelIndex / columns) * rowSize();
-}
+ qreal rowPos = ((modelIndex / columns) * rowSize());
+
+ if (flow == QQuickGridView::FlowLeftToRight && verticalLayoutDirection == QQuickItemView::TopToBottom) {
+ // Add the effective startpos of row 0. Start by subtracting minExtent, which will contain the
+ // height of the rows outside the beginning of the content item. (Rows can end up outside if
+ // e.g flicking the viewport a long way down, changing cellSize, and then flick back).
+ // NOTE: It's not clearly understood why the flow == QQuickGridView::FlowLeftToRight guard is
+ // needed, since the flow shouldn't normally affect the y postition of an index. But without
+ // it, several auto tests start failing, so we keep it until this part is better understood.
+ rowPos -= minExtent;
+ // minExtent will also contain the size of the topMargin (vData.startMargin), the header, and
+ // the highlightRangeStart. Those should be added before the start of row 0. So we need to subtract
+ // them from the rowPos. But only the largest of topMargin and highlightRangeStart will need
+ // to be taken into account, since having a topMargin will also ensure that currentItem ends
+ // up within the requested highlight range when view is positioned at the beginning.
+ rowPos += qMax(vData.startMargin, highlightRangeStart) + headerSize();
+ }
+
+ return rowPos;
+}
qreal QQuickGridViewPrivate::snapPosAt(qreal pos) const
{
@@ -835,6 +855,14 @@ void QQuickGridViewPrivate::updateFooter()
emit q->footerItemChanged();
}
+void QQuickGridViewPrivate::initializeComponentItem(QQuickItem *item) const
+{
+ QQuickGridViewAttached *attached = static_cast<QQuickGridViewAttached *>(
+ qmlAttachedPropertiesObject<QQuickGridView>(item));
+ if (attached)
+ attached->setView(const_cast<QQuickGridView*>(q_func()));
+}
+
void QQuickGridViewPrivate::updateHeader()
{
Q_Q(QQuickGridView);
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 4226bb7a57..4426c26cab 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -494,6 +494,8 @@ qreal QQuickImage::paintedHeight() const
\note \e {Changing this property dynamically causes the image source to be reloaded,
potentially even from the network, if it is not in the disk cache.}
+
+ \sa {Pointer Handlers Example}
*/
/*!
@@ -970,3 +972,7 @@ void QQuickImage::setMipmap(bool use)
*/
QT_END_NAMESPACE
+
+#include "moc_qquickimage_p_p.cpp"
+
+#include "moc_qquickimage_p.cpp"
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 619b3c299b..596cd7d63a 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -51,6 +51,17 @@
QT_BEGIN_NAMESPACE
+bool isScalableImageFormat(const QUrl &url)
+{
+ if (url.scheme() == QLatin1String("image"))
+ return true;
+
+ const QString stringUrl = url.path(QUrl::PrettyDecoded);
+ return stringUrl.endsWith(QLatin1String("svg"))
+ || stringUrl.endsWith(QLatin1String("svgz"))
+ || stringUrl.endsWith(QLatin1String("pdf"));
+}
+
// This function gives derived classes the chance set the devicePixelRatio
// if they're not happy with our implementation of it.
bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio)
@@ -58,17 +69,7 @@ bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio
// QQuickImageProvider and SVG and PDF can generate a high resolution image when
// sourceSize is set. If sourceSize is not set then the provider default size will
// be used, as usual.
- bool setDevicePixelRatio = false;
- if (url.scheme() == QLatin1String("image")) {
- setDevicePixelRatio = true;
- } else {
- QString stringUrl = url.path(QUrl::PrettyDecoded);
- if (stringUrl.endsWith(QLatin1String("svg")) ||
- stringUrl.endsWith(QLatin1String("svgz")) ||
- stringUrl.endsWith(QLatin1String("pdf"))) {
- setDevicePixelRatio = true;
- }
- }
+ const bool setDevicePixelRatio = isScalableImageFormat(url);
if (setDevicePixelRatio)
devicePixelRatio = targetDevicePixelRatio;
@@ -326,8 +327,10 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
const qreal targetDevicePixelRatio = (window() ? window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
d->devicePixelRatio = 1.0;
bool updatedDevicePixelRatio = false;
- if (d->sourcesize.isValid())
+ if (d->sourcesize.isValid()
+ || (isScalableImageFormat(d->url) && d->url.scheme() != QLatin1String("image"))) {
updatedDevicePixelRatio = d->updateDevicePixelRatio(targetDevicePixelRatio);
+ }
if (!updatedDevicePixelRatio) {
// (possible) local file: loadUrl and d->devicePixelRatio will be modified if
@@ -343,7 +346,8 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
(loadOptions & HandleDPR) ? d->sourcesize * d->devicePixelRatio : QSize(),
options,
(loadOptions & UseProviderOptions) ? d->providerOptions : QQuickImageProviderOptions(),
- d->currentFrame, d->frameCount);
+ d->currentFrame, d->frameCount,
+ d->devicePixelRatio);
if (d->pix.isLoading()) {
if (d->progress != 0.0) {
diff --git a/src/quick/items/qquickimplicitsizeitem_p.h b/src/quick/items/qquickimplicitsizeitem_p.h
index 8ae8f9f447..41f682fe57 100644
--- a/src/quick/items/qquickimplicitsizeitem_p.h
+++ b/src/quick/items/qquickimplicitsizeitem_p.h
@@ -62,6 +62,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImplicitSizeItem : public QQuickItem
Q_OBJECT
Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged)
Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged)
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(6, 2)
protected:
QQuickImplicitSizeItem(QQuickImplicitSizeItemPrivate &dd, QQuickItem *parent);
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index cdaf4773f1..dfa88c0a04 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -53,6 +53,7 @@
#include <QtGui/qpen.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qstylehints.h>
+#include <QtGui/private/qeventpoint_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qpointingdevice_p.h>
#include <QtGui/qinputmethod.h>
@@ -60,6 +61,7 @@
#include <QtCore/private/qnumeric_p.h>
#include <QtGui/qpa/qplatformtheme.h>
#include <QtCore/qloggingcategory.h>
+#include <QtCore/private/qduplicatetracker_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmlengine_p.h>
@@ -403,42 +405,42 @@ void QQuickItemKeyFilter::componentComplete()
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::left
+ \qmlattachedproperty Item QtQuick::KeyNavigation::left
This property holds the item to assign focus to
when the left cursor key is pressed.
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::right
+ \qmlattachedproperty Item QtQuick::KeyNavigation::right
This property holds the item to assign focus to
when the right cursor key is pressed.
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::up
+ \qmlattachedproperty Item QtQuick::KeyNavigation::up
This property holds the item to assign focus to
when the up cursor key is pressed.
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::down
+ \qmlattachedproperty Item QtQuick::KeyNavigation::down
This property holds the item to assign focus to
when the down cursor key is pressed.
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::tab
+ \qmlattachedproperty Item QtQuick::KeyNavigation::tab
This property holds the item to assign focus to
when the Tab key is pressed.
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::backtab
+ \qmlattachedproperty Item QtQuick::KeyNavigation::backtab
This property holds the item to assign focus to
when the Shift+Tab key combination (Backtab) is pressed.
@@ -590,7 +592,7 @@ void QQuickKeyNavigationAttached::setBacktab(QQuickItem *i)
}
/*!
- \qmlproperty enumeration QtQuick::KeyNavigation::priority
+ \qmlattachedproperty enumeration QtQuick::KeyNavigation::priority
This property determines whether the keys are processed before
or after the attached item's own key handling.
@@ -908,7 +910,7 @@ bool QQuickKeysAttached::isConnected(const char *signalName) const
*/
/*!
- \qmlproperty list<Object> QtQuick::Keys::forwardTo
+ \qmlproperty list<Item> QtQuick::Keys::forwardTo
This property provides a way to forward key presses, key releases, and keyboard input
coming from input methods to other items. This can be useful when you want
@@ -2351,31 +2353,22 @@ QQuickItem::~QQuickItem()
while (!d->childItems.isEmpty())
d->childItems.constFirst()->setParentItem(nullptr);
- if (!d->changeListeners.isEmpty()) {
- const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
- if (anchor)
- anchor->clearItem(this);
- }
-
- /*
+ d->notifyChangeListeners(QQuickItemPrivate::AllChanges, [this](const QQuickItemPrivate::ChangeListener &change){
+ QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
+ if (anchor)
+ anchor->clearItem(this);
+ });
+ /*
update item anchors that depended on us unless they are our child (and will also be destroyed),
or our sibling, and our parent is also being destroyed.
*/
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
- if (anchor && anchor->item && anchor->item->parentItem() && anchor->item->parentItem() != this)
- anchor->update();
- }
-
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::Destroyed)
- change.listener->itemDestroyed(this);
- }
-
- d->changeListeners.clear();
- }
+ d->notifyChangeListeners(QQuickItemPrivate::AllChanges, [this](const QQuickItemPrivate::ChangeListener &change){
+ QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
+ if (anchor && anchor->item && anchor->item->parentItem() && anchor->item->parentItem() != this)
+ anchor->update();
+ });
+ d->notifyChangeListeners(QQuickItemPrivate::Destroyed, &QQuickItemChangeListener::itemDestroyed, this);
+ d->changeListeners.clear();
/*
Remove any references our transforms have to us, in case they try to
@@ -2539,6 +2532,7 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
QQuickItem *current = item;
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: startItem:" << startItem;
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: firstFromItem:" << firstFromItem;
+ QDuplicateTracker<QQuickItem *> cycleDetector;
do {
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: current:" << current;
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: from:" << from;
@@ -2605,7 +2599,10 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
// traversed all of the chain (by compare the [current] item with [startItem])
// Since the [startItem] might be promoted to its parent if it is invisible,
// we still have to check [current] item with original start item
- if ((current == startItem || current == originalStartItem) && from == firstFromItem) {
+ // We might also run into a cycle before we reach firstFromItem again
+ // but note that we have to ignore current if we are meant to skip it
+ if (((current == startItem || current == originalStartItem) && from == firstFromItem) ||
+ (!skip && cycleDetector.hasSeen(current))) {
// wrapped around, avoid endless loops
if (item == contentItem) {
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem";
@@ -3658,14 +3655,7 @@ QQuickAnchors *QQuickItemPrivate::anchors() const
void QQuickItemPrivate::siblingOrderChanged()
{
Q_Q(QQuickItem);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::SiblingOrder) {
- change.listener->itemSiblingOrderChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::SiblingOrder, &QQuickItemChangeListener::itemSiblingOrderChanged, q);
}
QQmlListProperty<QObject> QQuickItemPrivate::data()
@@ -3733,6 +3723,9 @@ QList<QQuickItem *> QQuickItem::childItems() const
If clipping is enabled, an item will clip its own painting, as well
as the painting of its children, to its bounding rectangle.
+
+ \note Clipping can affect rendering performance. See \l {Clipping} for more
+ information.
*/
/*!
\property QQuickItem::clip
@@ -3783,15 +3776,10 @@ void QQuickItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeom
change.setWidthChange(newGeometry.width() != oldGeometry.width());
change.setHeightChange(newGeometry.height() != oldGeometry.height());
- if (!d->changeListeners.isEmpty()) {
- const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &listener : listeners) {
- if (listener.types & QQuickItemPrivate::Geometry) {
- if (change.matches(listener.gTypes))
- listener.listener->itemGeometryChanged(this, change, oldGeometry);
- }
- }
- }
+ d->notifyChangeListeners(QQuickItemPrivate::Geometry, [&](const QQuickItemPrivate::ChangeListener &listener){
+ if (change.matches(listener.gTypes))
+ listener.listener->itemGeometryChanged(this, change, oldGeometry);
+ });
// The notify method takes care of emitting the signal, and also notifies any
// property observers.
@@ -4419,16 +4407,11 @@ void QQuickItem::setBaselineOffset(qreal offset)
d->baselineOffset = offset;
- if (!d->changeListeners.isEmpty()) {
- const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::Geometry) {
- QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
- if (anchor)
- anchor->updateVerticalAnchors();
- }
- }
- }
+ d->notifyChangeListeners(QQuickItemPrivate::Geometry, [](const QQuickItemPrivate::ChangeListener &change){
+ QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
+ if (anchor)
+ anchor->updateVerticalAnchors();
+ });
if (d->_anchors && (d->_anchors->usedAnchors() & QQuickAnchors::BaselineAnchor))
QQuickAnchorsPrivate::get(d->_anchors)->updateVerticalAnchors();
@@ -4564,10 +4547,10 @@ static bool unwrapMapFromToFromItemArgs(QQmlV4Function *args, const QQuickItem *
}
/*!
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, real x, real y)
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, point p)
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, real x, real y, real width, real height)
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, rect r)
+ \qmlmethod point QtQuick::Item::mapFromItem(Item item, real x, real y)
+ \qmlmethod point QtQuick::Item::mapFromItem(Item item, point p)
+ \qmlmethod rect QtQuick::Item::mapFromItem(Item item, real x, real y, real width, real height)
+ \qmlmethod rect QtQuick::Item::mapFromItem(Item item, rect r)
Maps the point (\a x, \a y) or rect (\a x, \a y, \a width, \a height), which is in \a
item's coordinate system, to this item's coordinate system, and returns a \l point or \l rect
@@ -4619,10 +4602,10 @@ QTransform QQuickItem::itemTransform(QQuickItem *other, bool *ok) const
}
/*!
- \qmlmethod object QtQuick::Item::mapToItem(Item item, real x, real y)
- \qmlmethod object QtQuick::Item::mapToItem(Item item, point p)
- \qmlmethod object QtQuick::Item::mapToItem(Item item, real x, real y, real width, real height)
- \qmlmethod object QtQuick::Item::mapToItem(Item item, rect r)
+ \qmlmethod point QtQuick::Item::mapToItem(Item item, real x, real y)
+ \qmlmethod point QtQuick::Item::mapToItem(Item item, point p)
+ \qmlmethod rect QtQuick::Item::mapToItem(Item item, real x, real y, real width, real height)
+ \qmlmethod rect QtQuick::Item::mapToItem(Item item, rect r)
Maps the point (\a x, \a y) or rect (\a x, \a y, \a width, \a height), which is in this
item's coordinate system, to \a item's coordinate system, and returns a \l point or \l rect
@@ -4704,7 +4687,7 @@ static bool unwrapMapFromToFromGlobalArgs(QQmlV4Function *args, const QQuickItem
/*!
\since 5.7
- \qmlmethod object QtQuick::Item::mapFromGlobal(real x, real y)
+ \qmlmethod point QtQuick::Item::mapFromGlobal(real x, real y)
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.
@@ -4731,7 +4714,7 @@ void QQuickItem::mapFromGlobal(QQmlV4Function *args) const
/*!
\since 5.7
- \qmlmethod object QtQuick::Item::mapToGlobal(real x, real y)
+ \qmlmethod point QtQuick::Item::mapToGlobal(real x, real y)
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.
@@ -6424,26 +6407,12 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
switch (change) {
case QQuickItem::ItemChildAddedChange: {
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::Children) {
- change.listener->itemChildAdded(q, data.item);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Children, &QQuickItemChangeListener::itemChildAdded, q, data.item);
break;
}
case QQuickItem::ItemChildRemovedChange: {
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::Children) {
- change.listener->itemChildRemoved(q, data.item);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Children, &QQuickItemChangeListener::itemChildRemoved, q, data.item);
break;
}
case QQuickItem::ItemSceneChange:
@@ -6451,50 +6420,22 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
break;
case QQuickItem::ItemVisibleHasChanged: {
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::Visibility) {
- change.listener->itemVisibilityChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Visibility, &QQuickItemChangeListener::itemVisibilityChanged, q);
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);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Enabled, &QQuickItemChangeListener::itemEnabledChanged, q);
break;
}
case QQuickItem::ItemParentHasChanged: {
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::Parent) {
- change.listener->itemParentChanged(q, data.item);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Parent, &QQuickItemChangeListener::itemParentChanged, q, data.item);
break;
}
case QQuickItem::ItemOpacityHasChanged: {
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::Opacity) {
- change.listener->itemOpacityChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Opacity, &QQuickItemChangeListener::itemOpacityChanged, q);
break;
}
case QQuickItem::ItemActiveFocusHasChanged:
@@ -6502,14 +6443,7 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
break;
case QQuickItem::ItemRotationHasChanged: {
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::Rotation) {
- change.listener->itemRotationChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Rotation, &QQuickItemChangeListener::itemRotationChanged, q);
break;
}
case QQuickItem::ItemAntialiasingHasChanged:
@@ -6787,16 +6721,17 @@ void QQuickItem::setX(qreal v)
d->x.removeBindingUnlessInWrapper();
if (qt_is_nan(v))
return;
- if (d->x == v)
+
+ const qreal oldx = d->x;
+ if (oldx == v)
return;
- qreal oldx = d->x;
d->x = v;
d->dirty(QQuickItemPrivate::Position);
- geometryChange(QRectF(v, d->y, d->width, d->height),
- QRectF(oldx, d->y, d->width, d->height));
+ const qreal y = d->y, w = d->width, h = d->height;
+ geometryChange(QRectF(v, y, w, h), QRectF(oldx, y, w, h));
}
void QQuickItem::setY(qreal v)
@@ -6805,18 +6740,19 @@ void QQuickItem::setY(qreal v)
d->y.removeBindingUnlessInWrapper();
if (qt_is_nan(v))
return;
- if (d->y == v)
+
+ const qreal oldy = d->y;
+ if (oldy == v)
return;
- qreal oldy = d->y;
d->y = v;
d->dirty(QQuickItemPrivate::Position);
// we use v instead of d->y, as that avoid a method call
// and we have v anyway in scope
- geometryChange(QRectF(d->x, v, d->width, d->height),
- QRectF(d->x, oldy, d->width, d->height));
+ const qreal x = d->x, w = d->width, h = d->height;
+ geometryChange(QRectF(x, v, w, h), QRectF(x, oldy, w, h));
}
/*!
@@ -6828,8 +6764,8 @@ void QQuickItem::setPosition(const QPointF &pos)
if (QPointF(d->x, d->y) == pos)
return;
- qreal oldx = d->x;
- qreal oldy = d->y;
+ const qreal oldx = d->x;
+ const qreal oldy = d->y;
/* This preserves the bindings, because that was what the code used to do
The effect of this is that you can have
@@ -6849,8 +6785,8 @@ void QQuickItem::setPosition(const QPointF &pos)
d->dirty(QQuickItemPrivate::Position);
- geometryChange(QRectF(d->x, d->y, d->width, d->height),
- QRectF(oldx, oldy, d->width, d->height));
+ const qreal w = d->width, h = d->height;
+ geometryChange(QRectF(pos.x(), pos.y(), w, h), QRectF(oldx, oldy, w, h));
}
/* The bindable methods return an object which supports inspection (hasBinding) and
@@ -6885,16 +6821,16 @@ void QQuickItem::setWidth(qreal w)
return;
d->widthValidFlag = true;
- if (d->width == w)
+ const qreal oldWidth = d->width;
+ if (oldWidth == w)
return;
- qreal oldWidth = d->width;
d->width = w;
d->dirty(QQuickItemPrivate::Size);
- geometryChange(QRectF(d->x, d->y, w, d->height),
- QRectF(d->x, d->y, oldWidth, d->height));
+ const qreal x = d->x, y = d->y, h = d->height;
+ geometryChange(QRectF(x, y, w, h), QRectF(x, y, oldWidth, h));
}
void QQuickItem::resetWidth()
@@ -6908,14 +6844,7 @@ void QQuickItem::resetWidth()
void QQuickItemPrivate::implicitWidthChanged()
{
Q_Q(QQuickItem);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::ImplicitWidth) {
- change.listener->itemImplicitWidthChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::ImplicitWidth, &QQuickItemChangeListener::itemImplicitWidthChanged, q);
emit q->implicitWidthChanged();
}
@@ -6941,7 +6870,14 @@ QBindable<qreal> QQuickItem::bindableWidth()
\qmlproperty real QtQuick::Item::implicitWidth
\qmlproperty real QtQuick::Item::implicitHeight
- Defines the natural width or height of the Item if no \l width or \l height is specified.
+ Defines the preferred width or height of the Item.
+
+ If \l width or \l height is not specified, an item's effective size will be
+ determined by its \l implicitWidth or \l implicitHeight.
+
+ However, if an item is the child of a \l {Qt Quick Layouts}{layout}, the
+ layout will determine the item's preferred size using its implicit size.
+ In such a scenario, the explicit \l width or \l height will be ignored.
The default implicit size for most items is 0x0, however some items have an inherent
implicit size which cannot be overridden, for example, \l [QML] Image and \l [QML] Text.
@@ -6975,7 +6911,14 @@ QBindable<qreal> QQuickItem::bindableWidth()
\property QQuickItem::implicitWidth
\property QQuickItem::implicitHeight
- Defines the natural width or height of the Item if no \l width or \l height is specified.
+ Defines the preferred width or height of the Item.
+
+ If \l width or \l height is not specified, an item's effective size will be
+ determined by its \l implicitWidth or \l implicitHeight.
+
+ However, if an item is the child of a \l {Qt Quick Layouts}{layout}, the
+ layout will determine the item's preferred size using its implicit size.
+ In such a scenario, the explicit \l width or \l height will be ignored.
The default implicit size for most items is 0x0, however some items have an inherent
implicit size which cannot be overridden, for example, \l [QML] Image and \l [QML] Text.
@@ -7019,19 +6962,18 @@ void QQuickItem::setImplicitWidth(qreal w)
changed = false;
}
- qreal oldWidth = d->width.valueBypassingBindings();
+ const qreal oldWidth = d->width.valueBypassingBindings();
Q_ASSERT(!d->width.hasBinding() || QQmlPropertyBinding::isUndefined(d->width.binding()));
// we need to keep the binding if its undefined (therefore we can't use operator=/setValue)
d->width.setValueBypassingBindings(w);
d->dirty(QQuickItemPrivate::Size);
- qreal x = d->x.valueBypassingBindings();
- qreal y = d->y.valueBypassingBindings();
- qreal width = w;
- qreal height = d->height.valueBypassingBindings();
- geometryChange(QRectF(x, y, width, height),
- QRectF(x, y, oldWidth, height));
+ const qreal x = d->x.valueBypassingBindings();
+ const qreal y = d->y.valueBypassingBindings();
+ const qreal width = w;
+ const qreal height = d->height.valueBypassingBindings();
+ geometryChange(QRectF(x, y, width, height), QRectF(x, y, oldWidth, height));
if (changed)
d->implicitWidthChanged();
@@ -7085,16 +7027,16 @@ void QQuickItem::setHeight(qreal h)
return;
d->heightValidFlag = true;
- if (d->height == h)
+ const qreal oldHeight = d->height;
+ if (oldHeight == h)
return;
- qreal oldHeight = d->height;
d->height = h;
d->dirty(QQuickItemPrivate::Size);
- geometryChange(QRectF(d->x, d->y, d->width, h),
- QRectF(d->x, d->y, d->width, oldHeight));
+ const qreal x = d->x, y = d->y, w = d->width;
+ geometryChange(QRectF(x, y, w, h), QRectF(x, y, w, oldHeight));
}
void QQuickItem::resetHeight()
@@ -7111,14 +7053,7 @@ void QQuickItem::resetHeight()
void QQuickItemPrivate::implicitHeightChanged()
{
Q_Q(QQuickItem);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::ImplicitHeight) {
- change.listener->itemImplicitHeightChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::ImplicitHeight, &QQuickItemChangeListener::itemImplicitHeightChanged, q);
emit q->implicitHeightChanged();
}
@@ -7151,17 +7086,17 @@ void QQuickItem::setImplicitHeight(qreal h)
changed = false;
}
- qreal oldHeight = d->height.valueBypassingBindings();
+ const qreal oldHeight = d->height.valueBypassingBindings();
Q_ASSERT(!d->height.hasBinding() || QQmlPropertyBinding::isUndefined(d->height.binding()));
// we need to keep the binding if its undefined (therefore we can't use operator=/setValue)
d->height.setValueBypassingBindings(h);
d->dirty(QQuickItemPrivate::Size);
- qreal x = d->x.valueBypassingBindings();
- qreal y = d->y.valueBypassingBindings();
- qreal width = d->width.valueBypassingBindings();
- qreal height = d->height.valueBypassingBindings();
+ const qreal x = d->x.valueBypassingBindings();
+ const qreal y = d->y.valueBypassingBindings();
+ const qreal width = d->width.valueBypassingBindings();
+ const qreal height = d->height.valueBypassingBindings();
geometryChange(QRectF(x, y, width, height),
QRectF(x, y, width, oldHeight));
@@ -7200,8 +7135,8 @@ void QQuickItem::setImplicitSize(qreal w, qreal h)
if (wDone && hDone)
return;
- qreal oldWidth = width;
- qreal oldHeight = height;
+ const qreal oldWidth = width;
+ const qreal oldHeight = height;
if (!wDone) {
width = w;
d->width = w;
@@ -7213,8 +7148,8 @@ void QQuickItem::setImplicitSize(qreal w, qreal h)
d->dirty(QQuickItemPrivate::Size);
- qreal x = d->x.valueBypassingBindings();
- qreal y = d->y.valueBypassingBindings();
+ const qreal x = d->x.valueBypassingBindings();
+ const qreal y = d->y.valueBypassingBindings();
geometryChange(QRectF(x, y, width, height),
QRectF(x, y, oldWidth, oldHeight));
@@ -7267,15 +7202,15 @@ void QQuickItem::setSize(const QSizeF &size)
if (d->width == size.width() && d->height == size.height())
return;
- qreal oldHeight = d->height;
- qreal oldWidth = d->width;
+ const qreal oldHeight = d->height;
+ const qreal oldWidth = d->width;
d->height.setValueBypassingBindings(size.height());
d->width.setValueBypassingBindings(size.width());
d->dirty(QQuickItemPrivate::Size);
- geometryChange(QRectF(d->x, d->y, d->width, d->height),
- QRectF(d->x, d->y, oldWidth, oldHeight));
+ const qreal x = d->x, y = d->y;
+ geometryChange(QRectF(x, y, size.width(), size.height()), QRectF(x, y, oldWidth, oldHeight));
}
/*!
@@ -7456,20 +7391,19 @@ void QQuickItem::setFocus(bool focus, Qt::FocusReason reason)
if (d->focus == focus)
return;
+ bool notifyListeners = false;
if (d->window || d->parentItem) {
// Need to find our nearest focus scope
QQuickItem *scope = parentItem();
while (scope && !scope->isFocusScope() && scope->parentItem())
scope = scope->parentItem();
if (d->window) {
- if (reason != Qt::PopupFocusReason) {
- auto da = d->deliveryAgentPrivate();
- Q_ASSERT(da);
- if (focus)
- da->setFocusInScope(scope, this, reason);
- else
- da->clearFocusInScope(scope, this, reason);
- }
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ if (focus)
+ da->setFocusInScope(scope, this, reason);
+ else
+ da->clearFocusInScope(scope, this, reason);
} else {
// do the focus changes from setFocusInScope/clearFocusInScope that are
// unrelated to a window
@@ -7487,9 +7421,10 @@ void QQuickItem::setFocus(bool focus, Qt::FocusReason reason)
d->focus = focus;
changed << this;
+ notifyListeners = true;
emit focusChanged(focus);
- QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(changed.data(), changed.count() - 1);
+ QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(changed.data(), changed.count() - 1, reason);
}
} else {
QVarLengthArray<QQuickItem *, 20> changed;
@@ -7502,10 +7437,13 @@ void QQuickItem::setFocus(bool focus, Qt::FocusReason reason)
d->focus = focus;
changed << this;
+ notifyListeners = true;
emit focusChanged(focus);
- QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(changed.data(), changed.count() - 1);
+ QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(changed.data(), changed.count() - 1, reason);
}
+ if (notifyListeners)
+ d->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, this, reason);
}
/*!
@@ -7635,7 +7573,7 @@ bool QQuickItem::isUnderMouse() const
return false;
QPointF cursorPos = QGuiApplicationPrivate::lastCursorPosition;
- return contains(mapFromScene(d->window->mapFromGlobal(cursorPos.toPoint())));
+ return contains(mapFromScene(d->window->mapFromGlobal(cursorPos)));
}
/*!
@@ -7802,7 +7740,7 @@ void QQuickItem::setCursor(const QCursor &cursor)
if (d->window) {
QWindow *renderWindow = QQuickRenderControl::renderWindowFor(d->window);
QWindow *window = renderWindow ? renderWindow : d->window;
- QPointF pos = window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
+ QPointF pos = window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition);
if (contains(mapFromScene(pos)))
updateCursorPos = pos;
}
@@ -7831,7 +7769,7 @@ void QQuickItem::unsetCursor()
if (d->window) {
QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(d->window);
if (windowPrivate->cursorItem == this) {
- QPointF pos = d->window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
+ QPointF pos = d->window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition);
windowPrivate->updateCursor(pos);
}
}
@@ -8065,7 +8003,7 @@ void QQuickItem::setKeepTouchGrab(bool keep)
Returns \c true if this item contains \a point, which is in local coordinates;
returns \c false otherwise. This is the same check that is used for
hit-testing a QEventPoint during event delivery, and is affected by
- containmentMask() if it is set.
+ \l containmentMask if it is set.
*/
/*!
Returns \c true if this item contains \a point, which is in local coordinates;
@@ -8073,7 +8011,7 @@ void QQuickItem::setKeepTouchGrab(bool keep)
This function can be overridden in order to handle point collisions in items
with custom shapes. The default implementation checks whether the point is inside
- containmentMask() if it is set, or inside the bounding box otherwise.
+ \l containmentMask() if it is set, or inside the bounding box otherwise.
\note This method is used for hit-testing each QEventPoint during event
delivery, so the implementation should be kept as lightweight as possible.
@@ -8102,10 +8040,10 @@ bool QQuickItem::contains(const QPointF &point) const
\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. Its main use is currently to determine
+ \l contains() method. Its main use is currently to determine
whether a \l {QPointerEvent}{pointer event} has landed into the item or not.
- By default the \l contains method will return true for any point
+ By default the \c contains() method will return true for any point
within the Item's bounding box. \c containmentMask allows for
more fine-grained control. For example, if a custom C++
QQuickItem subclass with a specialized contains() method
@@ -8670,7 +8608,7 @@ QSGTextureProvider *QQuickItem::textureProvider() const
}
\endcode
- \sa Window::palette, Popup::palette, ColorGroup, Palette
+ \sa Window::palette, Popup::palette, ColorGroup, Palette, SystemPalette
*/
/*!
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index 6a3a5db921..fcaedfb50d 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -472,6 +472,7 @@ private:
friend class QSGRenderer;
friend class QAccessibleQuickItem;
friend class QQuickAccessibleAttached;
+ friend class QQuickAnchorChanges;
Q_DISABLE_COPY(QQuickItem)
Q_DECLARE_PRIVATE(QQuickItem)
};
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index d8a7c1dfdc..4406e191cb 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -331,6 +331,8 @@ public:
ImplicitWidth = 0x100,
ImplicitHeight = 0x200,
Enabled = 0x400,
+ Focus = 0x800,
+ AllChanges = 0xFFFFFFFF
};
Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
@@ -358,6 +360,32 @@ public:
QQuickGeometryChange gTypes; //NOTE: not used for ==
};
+ // call QQuickItemChangeListener PMF
+ template <typename Fn, typename ...Args>
+ void notifyChangeListeners(QQuickItemPrivate::ChangeTypes changeTypes, Fn &&function, Args &&...args)
+ {
+ if (changeListeners.isEmpty())
+ return;
+
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
+ if (change.types & changeTypes)
+ (change.listener->*function)(args...);
+ }
+ }
+ // call functor
+ template <typename Fn>
+ void notifyChangeListeners(QQuickItemPrivate::ChangeTypes changeTypes, Fn &&function) {
+ if (changeListeners.isEmpty())
+ return;
+
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
+ if (change.types & changeTypes)
+ function(change);
+ }
+ }
+
struct ExtraData {
ExtraData();
diff --git a/src/quick/items/qquickitemchangelistener_p.h b/src/quick/items/qquickitemchangelistener_p.h
index 31d06c9983..91e2d69cc0 100644
--- a/src/quick/items/qquickitemchangelistener_p.h
+++ b/src/quick/items/qquickitemchangelistener_p.h
@@ -134,6 +134,7 @@ public:
virtual void itemRotationChanged(QQuickItem *) {}
virtual void itemImplicitWidthChanged(QQuickItem *) {}
virtual void itemImplicitHeightChanged(QQuickItem *) {}
+ virtual void itemFocusChanged(QQuickItem *, Qt::FocusReason /* reason */) {}
virtual QQuickAnchorsPrivate *anchorPrivate() { return nullptr; }
};
diff --git a/src/quick/items/qquickitemgrabresult.h b/src/quick/items/qquickitemgrabresult.h
index a055c0638b..e800c71377 100644
--- a/src/quick/items/qquickitemgrabresult.h
+++ b/src/quick/items/qquickitemgrabresult.h
@@ -75,7 +75,7 @@ public:
#endif
#endif
Q_INVOKABLE bool saveToFile(const QString &fileName) const;
- Q_INVOKABLE bool saveToFile(const QUrl &fileName) const;
+ Q_REVISION(6, 2) Q_INVOKABLE bool saveToFile(const QUrl &fileName) const;
protected:
bool event(QEvent *) override;
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 5201f6fd72..fbffde1c48 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -125,6 +125,8 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcTransient)
QT_END_NAMESPACE
+#include "moc_qquickitemsmodule_p.cpp"
+
static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject *parent)
{
// When setting a parent (especially during dynamic object creation) in QML,
@@ -194,4 +196,138 @@ void QQuickItemsModule::defineModule()
qt_quickitems_defineModule();
}
+/*!
+ \qmltype PointerEvent
+ \instantiates QPointerEvent
+ \inqmlmodule QtQuick
+ \brief QML equivalent for \l QPointerEvent.
+
+ PointerEvent is the QML name of the QPointerEvent class.
+*/
+
+/*!
+ \qmltype PointerDevice
+ \instantiates QPointingDevice
+ \inqmlmodule QtQuick
+ \brief QML equivalent for \l QPointingDevice.
+
+ PointerDevice is the QML name of the QPointingDevice class.
+ It has the same properties and enums as \l QPointingDevice.
+*/
+
+/*!
+ \qmlproperty enumeration PointerDevice::deviceType
+
+ This property tells the type of device that generated a PointerEvent.
+
+ Valid values are:
+
+ \value PointerDevice.Unknown The device cannot be identified.
+ \value PointerDevice.Mouse A mouse.
+ \value PointerDevice.TouchScreen A touchscreen.
+ \value PointerDevice.TouchPad A touchpad or trackpad.
+ \value PointerDevice.Stylus A stylus on a graphics tablet.
+ \value PointerDevice.Airbrush An airbrush on a graphics tablet.
+ \value PointerDevice.Puck A digitizer with crosshairs, on a graphics tablet.
+
+ \sa QInputDevice::DeviceType, PointerDeviceHandler::acceptedDevices
+*/
+
+/*!
+ \qmlproperty enumeration PointerDevice::pointerType
+
+ This property tells what is interacting with the PointerDevice.
+
+ There is some redundancy between this property and \l deviceType.
+ For example, if a touchscreen is used, then \c deviceType is
+ \c TouchScreen and \c pointerType is \c Finger. But on a graphics
+ tablet, it's often possible for both ends of the stylus to be used,
+ and programs need to distinguish them.
+ \l PointerDeviceHandler::acceptedDevices and
+ \l PointerDeviceHandler::acceptedPointerTypes can be used in combination
+ to filter the subset of events that a particular handler should react to.
+
+ Valid values are:
+
+ \value PointerDevice.Unknown The device cannot be identified.
+ \value PointerDevice.Generic A mouse or a device that emulates a mouse.
+ \value PointerDevice.Finger A finger on a touchscreen.
+ \value PointerDevice.Pen A stylus on a graphics tablet.
+ \value PointerDevice.Eraser An eraser on a graphics tablet.
+ \value PointerDevice.Cursor A digitizer with crosshairs, on a graphics tablet.
+
+ \sa QPointingDevice::PointerType, PointerDeviceHandler::acceptedPointerTypes
+*/
+
+/*!
+ \qmlproperty int PointerDevice::maximumPoints
+
+ This property tells the maximum number of simultaneous touch points
+ (fingers) that can be detected.
+*/
+
+/*!
+ \qmlproperty int PointerDevice::buttonCount
+
+ This property tells the maximum number of on-device buttons that can be
+ detected.
+*/
+
+/*!
+ \qmltype pointingDeviceUniqueId
+ \instantiates QPointingDeviceUniqueId
+ \inqmlmodule QtQuick
+ \brief QML equivalent for \l QPointingDeviceUniqueId.
+
+ pointingDeviceUniqueId is the QML name of the QPointingDeviceUniqueId class.
+*/
+
+/*!
+ \qmlproperty qint64 pointingDeviceUniqueId::numericId
+
+ This property gives the numeric ID of the \l PointerDevice, if available;
+ otherwise it is \c -1.
+*/
+
+/*!
+ \qmlproperty pointingDeviceUniqueId PointerDevice::uniqueId
+
+ This property may provide a unique ID for the device, if available. For
+ example, a graphics tablet stylus device may have a unique serial number.
+
+ \sa eventPoint, QEventPoint::uniqueId()
+*/
+
+/*!
+ \qmlsignal PointerDevice::grabChanged(QtObject grabber, enumeration transition, PointerEvent event, eventPoint point)
+
+ This signal is emitted when the \a grabber object gains or loses an
+ exclusive or passive grab of \a point during delivery of \a event.
+ The \a transition tells what happened, from the perspective of the
+ \c grabber object, which may be either an \l Item or an
+ \l {Qt Quick Input Handlers}{Input Handler}.
+
+ Valid values for \a transition are:
+
+ \value GrabExclusive
+ The \a grabber has taken primary responsibility for handling the \a point.
+ \value UngrabExclusive
+ The \a grabber has given up its previous exclusive grab.
+ \value CancelGrabExclusive
+ The exclusive grab of \a grabber has been taken over or cancelled.
+ \value GrabPassive
+ The \a grabber has acquired a passive grab, to monitor the \a point.
+ \value UngrabPassive
+ The \a grabber has given up its previous passive grab.
+ \value CancelGrabPassive
+ The previous passive grab has terminated abnormally.
+
+ \note A grab transition from one object to another results in two signals,
+ to notify that one object has lost its grab, and to notify that there is
+ another grabber. In other cases, when transitioning to or from a non-grabbing
+ state, only one signal is emitted.
+
+ \sa QPointerEvent::setExclusiveGrabber(), QPointerEvent::addPassiveGrabber(), QPointerEvent::removePassiveGrabber()
+*/
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index f1336a91f6..faa03fa9ae 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -57,8 +57,6 @@ FxViewItem::FxViewItem(QQuickItem *i, QQuickItemView *v, bool own, QQuickItemVie
, view(v)
, attached(attached)
{
- if (attached) // can be null for default components (see createComponentItem)
- attached->setView(view);
}
QQuickItemViewChangeSet::QQuickItemViewChangeSet()
@@ -290,8 +288,6 @@ void QQuickItemView::setDelegate(QQmlComponent *delegate)
if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) {
int oldCount = dataModel->count();
dataModel->setDelegate(delegate);
- if (isComponentComplete())
- d->applyDelegateChange();
if (oldCount != dataModel->count())
emit countChanged();
}
@@ -1785,7 +1781,7 @@ void QQuickItemViewPrivate::refill(qreal from, qreal to)
do {
bufferPause.stop();
- if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges()) {
+ if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges() || currentChanges.active) {
currentChanges.reset();
bufferedChanges.reset();
releaseVisibleItems(reusableFlag);
@@ -1972,6 +1968,9 @@ void QQuickItemViewPrivate::layout()
transitioner->resetTargetLists();
}
+ if (!currentItem)
+ updateCurrent(currentIndex);
+
runDelayedRemoveTransition = false;
inLayout = false;
}
@@ -2504,12 +2503,29 @@ QQuickItem *QQuickItemViewPrivate::createComponentItem(QQmlComponent *component,
item->setZ(zValue);
QQml_setParent_noEvent(item, q->contentItem());
item->setParentItem(q->contentItem());
+
+ initializeComponentItem(item);
}
if (component)
component->completeCreate();
return item;
}
+/*!
+ \internal
+
+ Allows derived classes to do any initialization required for \a item
+ before completeCreate() is called on it. For example, any attached
+ properties required by the item can be set.
+
+ This is similar to initItem(), but as that has logic specific to
+ delegate items, we use a separate function for non-delegates.
+*/
+void QQuickItemViewPrivate::initializeComponentItem(QQuickItem *item) const
+{
+ Q_UNUSED(item);
+}
+
void QQuickItemViewPrivate::updateTrackedItem()
{
Q_Q(QQuickItemView);
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index 0bc2a6b768..36c36f43e8 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -76,7 +76,7 @@ public:
};
-class QQuickItemViewChangeSet
+class Q_AUTOTEST_EXPORT QQuickItemViewChangeSet
{
public:
QQuickItemViewChangeSet();
@@ -100,7 +100,7 @@ public:
};
-class Q_AUTOTEST_EXPORT QQuickItemViewPrivate : public QQuickFlickablePrivate, public QQuickItemViewTransitionChangeListener, public QAnimationJobChangeListener
+class Q_QUICK_AUTOTEST_EXPORT QQuickItemViewPrivate : public QQuickFlickablePrivate, public QQuickItemViewTransitionChangeListener, public QAnimationJobChangeListener
{
Q_DECLARE_PUBLIC(QQuickItemView)
public:
@@ -178,6 +178,7 @@ public:
QQuickItem *createHighlightItem() const;
QQuickItem *createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault = false) const;
+ virtual void initializeComponentItem(QQuickItem *) const;
void updateCurrent(int modelIndex);
void updateTrackedItem();
diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp
index b7649c9952..6b03d6c16b 100644
--- a/src/quick/items/qquickitemviewtransition.cpp
+++ b/src/quick/items/qquickitemviewtransition.cpp
@@ -500,6 +500,37 @@ void QQuickItemViewTransitionableItem::startTransition(QQuickItemViewTransitione
clearCurrentScheduledTransition();
}
+void QQuickItemViewTransitionableItem::completeTransition(QQuickTransition *quickTransition)
+{
+ if (nextTransitionType == QQuickItemViewTransitioner::NoTransition)
+ return;
+
+ if (!prepared) {
+ qWarning("QQuickViewItem::prepareTransition() not called!");
+ return;
+ }
+
+ if (!item) {
+ qWarning("No target for transition!");
+ return;
+ }
+
+ if (!transition || transition->m_type != nextTransitionType || transition->m_isTarget != isTransitionTarget) {
+ if (transition)
+ RETURN_IF_DELETED(transition->cancel());
+ delete transition;
+ transition = new QQuickItemViewTransitionJob;
+ }
+
+ QQuickStateOperation::ActionList actions; // not used
+ QList<QQmlProperty> after; // not used
+ QScopedPointer<QQuickTransitionInstance> instance(
+ quickTransition->prepare(actions, after, transition, item));
+ RETURN_IF_DELETED(instance->complete());
+
+ clearCurrentScheduledTransition();
+}
+
void QQuickItemViewTransitionableItem::setNextTransition(QQuickItemViewTransitioner::TransitionType type, bool isTargetItem)
{
// Don't reset nextTransitionToSet - once it is set, it cannot be changed
@@ -549,13 +580,15 @@ void QQuickItemViewTransitionableItem::stopTransition()
{
if (transition)
RETURN_IF_DELETED(transition->cancel());
+ delete transition;
+ transition = nullptr;
clearCurrentScheduledTransition();
resetNextTransitionPos();
}
QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
- : QObject(parent), m_item(nullptr), m_index(-1)
+ : QObject(parent), m_index(-1)
{
}
/*!
diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h
index 43858db688..253f3c6c70 100644
--- a/src/quick/items/qquickitemviewtransition_p.h
+++ b/src/quick/items/qquickitemviewtransition_p.h
@@ -157,6 +157,7 @@ public:
bool prepareTransition(QQuickItemViewTransitioner *transitioner, int index, const QRectF &viewBounds);
void startTransition(QQuickItemViewTransitioner *transitioner, int index);
+ void completeTransition(QQuickTransition *quickTransition);
SelfDeletable m_selfDeletable;
QPointF nextTransitionTo;
@@ -225,7 +226,7 @@ private:
QList<int> m_targetIndexes;
QList<QObject *> m_targetItems;
- QQuickItem *m_item;
+ QPointer<QQuickItem> m_item;
int m_index;
};
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index b954f1b107..58f031a9eb 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -130,6 +130,8 @@ public:
bool hasStickyHeader() const override;
bool hasStickyFooter() const override;
+ void initializeComponentItem(QQuickItem *item) const override;
+
void changedVisibleIndex(int newIndex) override;
void initializeCurrentItem() override;
@@ -1573,6 +1575,14 @@ bool QQuickListViewPrivate::hasStickyFooter() const
return footer && footerPositioning != QQuickListView::InlineFooter;
}
+void QQuickListViewPrivate::initializeComponentItem(QQuickItem *item) const
+{
+ QQuickListViewAttached *attached = static_cast<QQuickListViewAttached *>(
+ qmlAttachedPropertiesObject<QQuickListView>(item));
+ if (attached) // can be null for default components (see createComponentItem)
+ attached->setView(const_cast<QQuickListView*>(q_func()));
+}
+
void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change,
const QRectF &oldGeometry)
{
@@ -1642,6 +1652,10 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
return;
}
+ // update footer if all visible items have been removed
+ if (visibleItems.count() == 0)
+ updateFooter();
+
correctFlick = false;
fixupMode = moveReason == Mouse ? fixupMode : Immediate;
bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
@@ -2727,7 +2741,8 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
\c section.delegate holds the delegate component for each section. The
default \l {QQuickItem::z}{stacking order} of section delegate instances
- is \c 2.
+ is \c 2. If you declare a \c required property named "section" in it,
+ that property will contain the section's title.
\c section.labelPositioning determines whether the current and/or
next section labels stick to the start/end of the view, and whether
@@ -3743,8 +3758,10 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
item = createItem(it.index, QQmlIncubator::Synchronous);
if (!item)
return false;
- if (it.removedAtIndex)
+ if (it.removedAtIndex) {
+ releaseItem(item, reusableFlag);
continue;
+ }
visibleItems.insert(index, item);
if (index == 0)
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 4cd93ca1f0..1f5c55cffe 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -736,6 +736,9 @@ void QQuickLoaderPrivate::_q_sourceLoaded()
return;
}
+ if (!active)
+ return;
+
QQmlContext *creationContext = component->creationContext();
if (!creationContext) creationContext = qmlContext(q);
itemContext = new QQmlContext(creationContext);
@@ -801,7 +804,7 @@ void QQuickLoader::componentComplete()
{
Q_D(QQuickLoader);
QQuickItem::componentComplete();
- if (active()) {
+ if (active() && (status() != Ready)) {
if (d->loadingFromSource)
d->createComponent();
d->load();
@@ -939,7 +942,7 @@ void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
}
/*!
- \qmlproperty object QtQuick::Loader::item
+ \qmlproperty QtObject QtQuick::Loader::item
This property holds the top-level object that is currently loaded.
Since \c {QtQuick 2.0}, Loader can load any object type.
@@ -1038,9 +1041,15 @@ void QQuickLoaderPrivate::createComponent()
const QQmlComponent::CompilationMode mode = asynchronous
? QQmlComponent::Asynchronous
: QQmlComponent::PreferSynchronous;
- QQmlContext *context = qmlContext(q);
- component.setObject(new QQmlComponent(
- context->engine(), context->resolvedUrl(source), mode, q), q);
+ if (QQmlContext *context = qmlContext(q)) {
+ if (QQmlEngine *engine = context->engine()) {
+ component.setObject(new QQmlComponent(
+ engine, context->resolvedUrl(source), mode, q), q);
+ return;
+ }
+ }
+
+ qmlWarning(q) << "createComponent: Cannot find a QML engine.";
}
#include <moc_qquickloader_p.cpp>
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 281860fa6e..4977ddf44f 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -808,7 +808,8 @@ void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
QQuickWindow *w = window();
if (w && w->mouseGrabberItem() == this)
ungrabMouse();
- setKeepMouseGrab(false);
+ if (!d->preventStealing)
+ setKeepMouseGrab(false);
}
}
d->doubleClick = false;
@@ -827,7 +828,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
emit this->doubleClicked(&me);
if (!me.isAccepted())
d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick);
- d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
+ if (d->pressed)
+ d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
}
QQuickItem::mouseDoubleClickEvent(event);
}
@@ -849,14 +851,8 @@ void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
me.setPosition(d->lastPos);
}
- if (auto parentMouseArea = qobject_cast<QQuickMouseArea *>(parentItem())) {
- if (parentMouseArea->acceptHoverEvents()) {
- // Special legacy case: if our parent is another MouseArea, and we're
- // hovered, the parent MouseArea should be hovered too. We achieve this
- // by simply ignoring the event to not block propagation.
- event->ignore();
- }
- }
+ // A MouseArea should not block hover events
+ event->ignore();
}
void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
@@ -876,14 +872,8 @@ void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
emit positionChanged(&me);
}
- if (auto parentMouseArea = qobject_cast<QQuickMouseArea *>(parentItem())) {
- if (parentMouseArea->acceptHoverEvents()) {
- // Special legacy case: if our parent is another MouseArea, and we're
- // hovered, the parent MouseArea should be hovered too. We achieve this
- // by simply ignoring the event to not block propagation.
- event->ignore();
- }
- }
+ // A MouseArea should not block hover events
+ event->ignore();
}
void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
@@ -894,14 +884,8 @@ void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
else
setHovered(false);
- if (auto parentMouseArea = qobject_cast<QQuickMouseArea *>(parentItem())) {
- if (parentMouseArea->acceptHoverEvents()) {
- // Special legacy case: if our parent is another MouseArea, and we're
- // hovered, the parent MouseArea should be hovered too. We achieve this
- // by simply ignoring the event to not block propagation.
- event->ignore();
- }
- }
+ // A MouseArea should not block hover events
+ event->ignore();
}
#if QT_CONFIG(wheelevent)
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 642b5ca047..8687de8f43 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -40,11 +40,11 @@
#include "qquickmultipointtoucharea_p.h"
#include <QtQuick/qquickwindow.h>
#include <private/qsgadaptationlayer_p.h>
-#include <private/qevent_p.h>
#include <private/qquickitem_p.h>
#include <private/qquickwindow_p.h>
#include <private/qguiapplication_p.h>
#include <QtGui/private/qevent_p.h>
+#include <QtGui/private/qeventpoint_p.h>
#include <QtGui/private/qpointingdevice_p.h>
#include <QEvent>
#include <QMouseEvent>
@@ -570,7 +570,7 @@ void QQuickMultiPointTouchArea::grabGesture(QPointingDevice *dev)
setKeepTouchGrab(true);
}
-void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
+void QQuickMultiPointTouchArea::updateTouchData(QEvent *event, RemapEventPoints remap)
{
bool ended = false;
bool moved = false;
@@ -578,6 +578,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
clearTouchLists();
QList<QEventPoint> touchPoints;
+ bool touchPointsFromEvent = false;
QPointingDevice *dev = nullptr;
switch (event->type()) {
@@ -586,6 +587,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
case QEvent::TouchEnd: {
QTouchEvent* te = static_cast<QTouchEvent*>(event);
touchPoints = te->points();
+ touchPointsFromEvent = true;
dev = const_cast<QPointingDevice *>(te->pointingDevice());
break;
}
@@ -630,6 +632,8 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
}
if (numTouchPoints >= _minimumTouchPoints && numTouchPoints <= _maximumTouchPoints) {
for (QEventPoint &p : touchPoints) {
+ if (touchPointsFromEvent && remap == RemapEventPoints::ToLocal)
+ QMutableEventPoint::from(p).setPosition(mapFromScene(p.scenePosition()));
QEventPoint::State touchPointState = p.state();
int id = p.id();
if (touchPointState & QEventPoint::State::Released) {
@@ -971,12 +975,12 @@ bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *receiver, QEve
}
if (!shouldFilter(event))
return false;
- updateTouchData(event);
+ updateTouchData(event, RemapEventPoints::ToLocal);
return _stealMouse;
case QEvent::TouchEnd: {
if (!shouldFilter(event))
return false;
- updateTouchData(event);
+ updateTouchData(event, RemapEventPoints::ToLocal);
ungrab(true);
}
break;
diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h
index 66626e8610..e1f2c559ce 100644
--- a/src/quick/items/qquickmultipointtoucharea_p.h
+++ b/src/quick/items/qquickmultipointtoucharea_p.h
@@ -278,7 +278,8 @@ protected:
void updateTouchPoint(QQuickTouchPoint*, const QEventPoint*);
void updateTouchPoint(QQuickTouchPoint *dtp, const QMouseEvent *e);
- void updateTouchData(QEvent*);
+ enum class RemapEventPoints { No, ToLocal };
+ void updateTouchData(QEvent*, RemapEventPoints remap = RemapEventPoints::No);
bool sendMouseEvent(QMouseEvent *event);
bool shouldFilter(QEvent *event);
diff --git a/src/quick/items/qquickpainteditem.cpp b/src/quick/items/qquickpainteditem.cpp
index 2cf26142c8..c24a6cbfdd 100644
--- a/src/quick/items/qquickpainteditem.cpp
+++ b/src/quick/items/qquickpainteditem.cpp
@@ -83,6 +83,8 @@ public:
\note It important to understand the performance implications such items
can incur. See QQuickPaintedItem::RenderTarget and
QQuickPaintedItem::renderTarget.
+
+ \sa {Scene Graph - Painted Item}, {Writing QML Extensions with C++}
*/
/*!
diff --git a/src/quick/items/qquickpalette.cpp b/src/quick/items/qquickpalette.cpp
index a64b309426..5e95a92238 100644
--- a/src/quick/items/qquickpalette.cpp
+++ b/src/quick/items/qquickpalette.cpp
@@ -334,3 +334,5 @@ bool QQuickPalette::isValidColorGroup(QPalette::ColorGroup groupTag,
}
QT_END_NAMESPACE
+
+#include "moc_qquickpalette_p.cpp"
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index d862eba25b..f714b98309 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -49,7 +49,8 @@
#include <private/qqmlchangeset_p.h>
#include <QtQml/qqmlinfo.h>
-#include <QtGui/qevent.h>
+
+#include <QtGui/private/qeventpoint_p.h>
#include <QtGui/qevent.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qstylehints.h>
@@ -145,7 +146,8 @@ QQuickItem *QQuickPathViewPrivate::getItem(int modelIndex, qreal z, bool async)
item->setParentItem(q);
requestedIndex = -1;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
+ itemPrivate->addItemChangeListener(
+ this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
}
inRequest = false;
return item;
@@ -198,11 +200,14 @@ void QQuickPathView::initItem(int index, QObject *object)
void QQuickPathViewPrivate::releaseItem(QQuickItem *item)
{
- if (!item || !model)
+ if (!item)
return;
qCDebug(lcItemViewDelegateLifecycle) << "release" << item;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
+ itemPrivate->removeItemChangeListener(
+ this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
+ if (!model)
+ return;
QQmlInstanceModel::ReleaseFlags flags = model->release(item);
if (!flags) {
// item was not destroyed, and we no longer reference it.
diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h
index 274086ea7c..b83cd95b95 100644
--- a/src/quick/items/qquickpathview_p_p.h
+++ b/src/quick/items/qquickpathview_p_p.h
@@ -88,6 +88,12 @@ public:
}
}
+ void itemDestroyed(QQuickItem *item) override
+ {
+ if (!items.removeOne(item))
+ itemCache.removeOne(item);
+ }
+
void scheduleLayout() {
Q_Q(QQuickPathView);
if (!layoutScheduled) {
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index ed8506b440..37458542d3 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -360,7 +360,7 @@ void QQuickPinchArea::touchEvent(QTouchEvent *event)
void QQuickPinchArea::clearPinch(QTouchEvent *event)
{
Q_D(QQuickPinchArea);
- qCDebug(lcPA, "clear: %lld touchpoints", d->touchPoints.count());
+ qCDebug(lcPA, "clear: %" PRIdQSIZETYPE " touchpoints", d->touchPoints.count());
d->touchPoints.clear();
if (d->inPinch) {
d->inPinch = false;
@@ -390,12 +390,13 @@ void QQuickPinchArea::clearPinch(QTouchEvent *event)
}
}
setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
}
void QQuickPinchArea::cancelPinch(QTouchEvent *event)
{
Q_D(QQuickPinchArea);
- qCDebug(lcPA, "cancel: %lld touchpoints", d->touchPoints.count());
+ qCDebug(lcPA, "cancel: %" PRIdQSIZETYPE " touchpoints", d->touchPoints.count());
d->touchPoints.clear();
if (d->inPinch) {
d->inPinch = false;
@@ -431,6 +432,7 @@ void QQuickPinchArea::cancelPinch(QTouchEvent *event)
event->setExclusiveGrabber(point, nullptr);
}
setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
}
void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
@@ -440,6 +442,7 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
if (d->touchPoints.count() < 2) {
// A pinch gesture is not occurring, so stealing the grab is permitted.
setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
// During filtering, there's no need to hold a grab for one point,
// because filtering happens for every event anyway.
// But if we receive the event via direct delivery, and give up the grab,
@@ -463,6 +466,8 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
pe.setPoint1(mapFromScene(d->lastPoint1));
pe.setPoint2(mapFromScene(d->lastPoint2));
+ setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
emit pinchFinished(&pe);
d->pinchStartDist = 0;
d->pinchActivated = false;
@@ -499,6 +504,8 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
d->initPinch = true;
event->setExclusiveGrabber(touchPoint1, this);
event->setExclusiveGrabber(touchPoint2, this);
+ setKeepTouchGrab(true);
+ setKeepMouseGrab(true);
}
if (d->pinchActivated && !d->pinchRejected) {
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
@@ -561,6 +568,9 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
event->setExclusiveGrabber(touchPoint1, this);
event->setExclusiveGrabber(touchPoint2, this);
setKeepTouchGrab(true);
+ // So that PinchArea works in PathView, grab mouse events too.
+ // We should be able to remove these setKeepMouseGrab calls when QTBUG-105567 is fixed.
+ setKeepMouseGrab(true);
d->inPinch = true;
if (d->pinch && d->pinch->target()) {
auto targetParent = pinch()->target()->parentItem();
@@ -727,6 +737,8 @@ bool QQuickPinchArea::event(QEvent *event)
clearPinch(nullptr);
break;
case Qt::ZoomNativeGesture: {
+ if (d->pinchRejected)
+ break;
qreal scale = d->pinchLastScale * (1.0 + gesture->value());
QQuickPinchEvent pe(d->pinchStartCenter, scale, d->pinchLastAngle, 0.0);
pe.setStartCenter(d->pinchStartCenter);
@@ -744,7 +756,10 @@ bool QQuickPinchArea::event(QEvent *event)
else
emit pinchStarted(&pe);
d->inPinch = true;
- updatePinchTarget();
+ if (pe.accepted())
+ updatePinchTarget();
+ else
+ d->pinchRejected = true;
} break;
case Qt::SmartZoomNativeGesture: {
if (gesture->value() > 0.0 && d->pinch && d->pinch->target()) {
@@ -768,6 +783,8 @@ bool QQuickPinchArea::event(QEvent *event)
emit smartZoom(&pe);
} break;
case Qt::RotateNativeGesture: {
+ if (d->pinchRejected)
+ break;
qreal angle = d->pinchLastAngle + gesture->value();
QQuickPinchEvent pe(d->pinchStartCenter, d->pinchLastScale, angle, 0.0);
pe.setStartCenter(d->pinchStartCenter);
@@ -786,7 +803,10 @@ bool QQuickPinchArea::event(QEvent *event)
emit pinchStarted(&pe);
d->inPinch = true;
d->pinchRotation = angle;
- updatePinchTarget();
+ if (pe.accepted())
+ updatePinchTarget();
+ else
+ d->pinchRejected = true;
} break;
default:
return QQuickItem::event(event);
diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp
index a8d050527b..313143e881 100644
--- a/src/quick/items/qquickpositioners.cpp
+++ b/src/quick/items/qquickpositioners.cpp
@@ -1697,7 +1697,7 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
int c = m_columns;
int r = m_rows;
- int numVisible = positionedItems.count();
+ const int numVisible = positionedItems.count();
if (m_columns <= 0 && m_rows <= 0) {
c = 4;
@@ -1714,6 +1714,10 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
return; //Nothing else to do
}
+ if (numVisible > r * c) {
+ qmlWarning(this) << "Grid contains more visible items (" << numVisible << ") than rows*columns (" << r * c << ")";
+ }
+
QList<qreal> maxColWidth;
QList<qreal> maxRowHeight;
int childIndex =0;
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index ce570a743c..52c830c14a 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -578,8 +578,13 @@ QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
if (d->pen && d->pen->isValid()) {
rectangle->setPenColor(d->pen->color());
- rectangle->setPenWidth(d->pen->width());
- rectangle->setAligned(d->pen->pixelAligned());
+ qreal penWidth = d->pen->width();
+ if (d->pen->pixelAligned()) {
+ qreal dpr = window() ? window()->effectiveDevicePixelRatio() : 1.0;
+ penWidth = qRound(penWidth * dpr) / dpr; // Ensures integer width after dpr scaling
+ }
+ rectangle->setPenWidth(penWidth);
+ rectangle->setAligned(false); // width rounding already done, so the Node should not do it
} else {
rectangle->setPenWidth(0);
}
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index a660bd0ca3..2d48a39be8 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -181,6 +181,14 @@ QQuickRenderControl::QQuickRenderControl(QObject *parent)
}
/*!
+ \internal
+*/
+QQuickRenderControl::QQuickRenderControl(QQuickRenderControlPrivate &dd, QObject * parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
Destroys the instance. Releases all scenegraph resources.
\sa invalidate()
@@ -214,7 +222,7 @@ void QQuickRenderControlPrivate::windowDestroyed()
QQuickWindowPrivate::get(window)->animationController.reset();
#if QT_CONFIG(quick_shadereffect)
- QSGRhiShaderEffectNode::cleanupMaterialTypeCache();
+ QSGRhiShaderEffectNode::cleanupMaterialTypeCache(window);
#endif
window = nullptr;
}
@@ -322,6 +330,7 @@ bool QQuickRenderControl::initialize()
params.initialSurfacePixelSize = d->window->size() * d->window->effectiveDevicePixelRatio();
params.maybeSurface = d->window;
renderContext->initialize(&params);
+ d->initialized = true;
} else {
qWarning("QRhi is only compatible with default adaptation");
return false;
@@ -528,7 +537,7 @@ void QQuickRenderControlPrivate::maybeUpdate()
Reimplemented in subclasses to return the real window this render control
is rendering into.
- If \a offset in non-null, it is set to the offset of the control
+ If \a offset is non-null, it is set to the offset of the control
inside the window.
\note While not mandatory, reimplementing this function becomes essential for
@@ -540,7 +549,7 @@ void QQuickRenderControlPrivate::maybeUpdate()
/*!
Returns the real window that \a win is being rendered to, if any.
- If \a offset in non-null, it is set to the offset of the rendering
+ If \a offset is non-null, it is set to the offset of the rendering
inside its window.
*/
@@ -554,6 +563,14 @@ QWindow *QQuickRenderControl::renderWindowFor(QQuickWindow *win, QPoint *offset)
return nullptr;
}
+bool QQuickRenderControlPrivate::isRenderWindowFor(QQuickWindow *quickWin, const QWindow *renderWin)
+{
+ QQuickRenderControl *rc = QQuickWindowPrivate::get(quickWin)->renderControl;
+ if (rc)
+ return QQuickRenderControlPrivate::get(rc)->isRenderWindow(renderWin);
+ return false;
+}
+
/*!
\return the QQuickWindow this QQuickRenderControl is associated with.
diff --git a/src/quick/items/qquickrendercontrol.h b/src/quick/items/qquickrendercontrol.h
index 160aad73ab..3b1646c3f6 100644
--- a/src/quick/items/qquickrendercontrol.h
+++ b/src/quick/items/qquickrendercontrol.h
@@ -80,6 +80,9 @@ public:
QQuickWindow *window() const;
+protected:
+ QQuickRenderControl(QQuickRenderControlPrivate &dd, QObject * parent);
+
Q_SIGNALS:
void renderRequested();
void sceneChanged();
diff --git a/src/quick/items/qquickrendercontrol_p.h b/src/quick/items/qquickrendercontrol_p.h
index 00d9c909d0..8349153df0 100644
--- a/src/quick/items/qquickrendercontrol_p.h
+++ b/src/quick/items/qquickrendercontrol_p.h
@@ -71,6 +71,9 @@ public:
return renderControl->d_func();
}
+ static bool isRenderWindowFor(QQuickWindow *quickWin, const QWindow *renderWin);
+ virtual bool isRenderWindow(const QWindow *w) { Q_UNUSED(w); return false; }
+
static void cleanup();
void windowDestroyed();
diff --git a/src/quick/items/qquickscalegrid.cpp b/src/quick/items/qquickscalegrid.cpp
index c2288cf220..13b249d50f 100644
--- a/src/quick/items/qquickscalegrid.cpp
+++ b/src/quick/items/qquickscalegrid.cpp
@@ -217,3 +217,5 @@ QString QQuickGridScaledImage::pixmapUrl() const
}
QT_END_NAMESPACE
+
+#include "moc_qquickscalegrid_p_p.cpp"
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index caabd541b6..5c2f113fdc 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -1165,6 +1165,8 @@ QSGNode *QQuickShaderEffectImpl::handleUpdatePaintNode(QSGNode *oldNode, QQuickI
sd.fragment.shader = &m_shaders[Fragment];
sd.fragment.dirtyConstants = &m_dirtyConstants[Fragment];
sd.fragment.dirtyTextures = &m_dirtyTextures[Fragment];
+ sd.materialTypeCacheKey = m_item->window();
+
node->syncMaterial(&sd);
if (m_dirty & QSGShaderEffectNode::DirtyShaderMesh) {
@@ -1243,6 +1245,7 @@ bool QQuickShaderEffectImpl::updateUniformValue(const QByteArray &name, const QV
sd.fragment.shader = &m_shaders[Fragment];
sd.fragment.dirtyConstants = &dirtyConstants[Fragment];
sd.fragment.dirtyTextures = {};
+ sd.materialTypeCacheKey = m_item->window();
node->syncMaterial(&sd);
@@ -1384,7 +1387,7 @@ bool QQuickShaderEffectImpl::updateShader(Shader shaderType, const QUrl &fileUrl
// provided and monitored like with an application-provided shader.
QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
v.name = QByteArrayLiteral("source");
- v.bindPoint = 0; // fake
+ v.bindPoint = 1; // fake, must match the default source bindPoint in qquickshadereffectnode.cpp
v.type = texturesSeparate ? QSGGuiThreadShaderEffectManager::ShaderInfo::Texture
: QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
m_shaders[shaderType].shaderInfo.variables.append(v);
@@ -1438,10 +1441,8 @@ void QQuickShaderEffectImpl::updateShaderVars(Shader shaderType)
const int varCount = m_shaders[shaderType].shaderInfo.variables.count();
m_shaders[shaderType].varData.resize(varCount);
- // Reuse signal mappers as much as possible since the mapping is based on
- // the index and shader type which are both constant.
- if (m_mappers[shaderType].count() < varCount)
- m_mappers[shaderType].resize(varCount);
+ // Recreate signal mappers when the shader has changed.
+ clearMappers(shaderType);
auto *engine = qmlEngine(m_item);
QQmlPropertyCache *propCache = engine ? QQmlData::ensurePropertyCache(engine, m_item) : nullptr;
@@ -1497,13 +1498,11 @@ void QQuickShaderEffectImpl::updateShaderVars(Shader shaderType)
if (pd->notifyIndex() == -1) {
qWarning("QQuickShaderEffect: property '%s' does not have notification method!", v.name.constData());
} else {
- auto *&mapper = m_mappers[shaderType][i];
- if (!mapper) {
- const int mappedId = indexToMappedId(shaderType, i);
- mapper = new QtPrivate::EffectSlotMapper([this, mappedId](){
- this->propertyChanged(mappedId);
- });
- }
+ const int mappedId = indexToMappedId(shaderType, i);
+ auto mapper = new QtPrivate::EffectSlotMapper([this, mappedId](){
+ this->propertyChanged(mappedId);
+ });
+ m_mappers[shaderType].append(mapper);
mapper->setSignalIndex(m_itemMetaObject->property(propIdx).notifySignal().methodIndex());
Q_ASSERT(m_item->metaObject() == m_itemMetaObject);
bool ok = QObjectPrivate::connectImpl(m_item, pd->notifyIndex(), m_item, nullptr, mapper,
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 4f61d61309..b298ed74da 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -344,7 +344,6 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
d->refFromEffectItem(m_hideSource);
d->addItemChangeListener(this, QQuickItemPrivate::Geometry);
connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
- connect(m_sourceItem, SIGNAL(parentChanged(QQuickItem*)), this, SLOT(sourceItemParentChanged(QQuickItem*)));
} else {
qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window.");
m_sourceItem = nullptr;
@@ -364,13 +363,6 @@ void QQuickShaderEffectSource::sourceItemDestroyed(QObject *item)
}
-void QQuickShaderEffectSource::sourceItemParentChanged(QQuickItem *parent)
-{
- if (!parent && m_texture)
- m_texture->setItem(0);
-}
-
-
/*!
\qmlproperty rect QtQuick::ShaderEffectSource::sourceRect
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 921038e49a..fe419e5959 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -174,7 +174,6 @@ Q_SIGNALS:
private Q_SLOTS:
void sourceItemDestroyed(QObject *item);
void invalidateSceneGraph();
- void sourceItemParentChanged(QQuickItem *parent);
protected:
void releaseResources() override;
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index e35c766ab6..ddc43c10ed 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -352,6 +352,7 @@ void QQuickSpriteEngine::startAssemblingImage()
return;
m_loaded = false;
m_errorsPrinted = false;
+ m_sprites.clear();
//This could also trigger the start of the image loading in Sprites, however that currently happens in Sprite::setSource
diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp
index bfec619f80..d16f0d0883 100644
--- a/src/quick/items/qquickstateoperations.cpp
+++ b/src/quick/items/qquickstateoperations.cpp
@@ -359,8 +359,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << xa;
} else {
QQmlProperty property(d->target, QLatin1String("x"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->xString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->xString.value, d->target, qmlContext(this));
QQuickStateAction xa;
xa.property = property;
xa.toBinding = newBinding;
@@ -378,8 +377,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << ya;
} else {
QQmlProperty property(d->target, QLatin1String("y"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->yString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->yString.value, d->target, qmlContext(this));
QQuickStateAction ya;
ya.property = property;
ya.toBinding = newBinding;
@@ -397,8 +395,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << sa;
} else {
QQmlProperty property(d->target, QLatin1String("scale"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->scaleString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->scaleString.value, d->target, qmlContext(this));
QQuickStateAction sa;
sa.property = property;
sa.toBinding = newBinding;
@@ -416,8 +413,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << ra;
} else {
QQmlProperty property(d->target, QLatin1String("rotation"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->rotationString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->rotationString.value, d->target, qmlContext(this));
QQuickStateAction ra;
ra.property = property;
ra.toBinding = newBinding;
@@ -435,8 +431,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << wa;
} else {
QQmlProperty property(d->target, QLatin1String("width"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->widthString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->widthString, d->target, qmlContext(this));
QQuickStateAction wa;
wa.property = property;
wa.toBinding = newBinding;
@@ -454,8 +449,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << ha;
} else {
QQmlProperty property(d->target, QLatin1String("height"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->heightString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->heightString, d->target, qmlContext(this));
QQuickStateAction ha;
ha.property = property;
ha.toBinding = newBinding;
@@ -492,11 +486,13 @@ void QQuickParentChangePrivate::reverseRewindHelper(const std::unique_ptr<QQuick
{
if (!target || !snapshot)
return;
- target->setX(snapshot->x);
- target->setY(snapshot->y);
+
+ // leave existing bindings alive; new bindings are applied in applyBindings
+ // setPosition and setSize update the geometry without invalidating bindings
+ target->setPosition(QPointF(snapshot->x, snapshot->y));
+ target->setSize(QSizeF(snapshot->width, snapshot->height));
+
target->setScale(snapshot->scale);
- target->setWidth(snapshot->width);
- target->setHeight(snapshot->height);
target->setRotation(snapshot->rotation);
target->setParentItem(snapshot->parent);
if (snapshot->stackBefore)
@@ -573,7 +569,7 @@ void QQuickParentChange::rewind()
The AnchorChanges type is used to modify the anchors of an item in a \l State.
AnchorChanges cannot be used to modify the margins on an item. For this, use
- PropertyChanges intead.
+ PropertyChanges instead.
In the following example we change the top and bottom anchors of an item
using AnchorChanges, and the top and bottom anchor margins using
@@ -1106,6 +1102,7 @@ void QQuickAnchorChanges::reverse()
QQuickAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QQuickAnchors::Horizontal_Mask;
QQuickAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QQuickAnchors::Horizontal_Mask;
+ const QRectF oldGeometry(d->target->position(), d->target->size());
bool stateSetWidth = (stateHAnchors &&
stateHAnchors != QQuickAnchors::LeftAnchor &&
stateHAnchors != QQuickAnchors::RightAnchor &&
@@ -1114,8 +1111,11 @@ void QQuickAnchorChanges::reverse()
origHAnchors != QQuickAnchors::LeftAnchor &&
origHAnchors != QQuickAnchors::RightAnchor &&
origHAnchors != QQuickAnchors::HCenterAnchor);
- if (d->origWidth.isValid() && stateSetWidth && !origSetWidth)
- d->target->setWidth(d->origWidth.value);
+ if (d->origWidth.isValid() && stateSetWidth && !origSetWidth && !qt_is_nan(d->origWidth)) {
+ targetPrivate->widthValidFlag = true;
+ if (targetPrivate->width != d->origWidth)
+ targetPrivate->width.setValueBypassingBindings(d->origWidth);
+ }
bool stateSetHeight = (stateVAnchors &&
stateVAnchors != QQuickAnchors::TopAnchor &&
@@ -1127,14 +1127,23 @@ void QQuickAnchorChanges::reverse()
origVAnchors != QQuickAnchors::BottomAnchor &&
origVAnchors != QQuickAnchors::VCenterAnchor &&
origVAnchors != QQuickAnchors::BaselineAnchor);
- if (d->origHeight.isValid() && stateSetHeight && !origSetHeight)
- d->target->setHeight(d->origHeight.value);
+ if (d->origHeight.isValid() && stateSetHeight && !origSetHeight && !!qt_is_nan(d->origHeight)) {
+ targetPrivate->heightValidFlag = true;
+ if (targetPrivate->height != d->origHeight)
+ targetPrivate->height.setValueBypassingBindings(d->origHeight);
+ }
+
+ if (stateHAnchors && !origHAnchors && !qt_is_nan(d->origX) && d->origX != targetPrivate->x)
+ targetPrivate->x.setValueBypassingBindings(d->origX);
- if (stateHAnchors && !origHAnchors)
- d->target->setX(d->origX);
+ if (stateVAnchors && !origVAnchors && !qt_is_nan(d->origY) && d->origY != targetPrivate->y)
+ targetPrivate->y.setValueBypassingBindings(d->origY);
- if (stateVAnchors && !origVAnchors)
- d->target->setY(d->origY);
+ const QRectF newGeometry(d->target->position(), d->target->size());
+ if (newGeometry != oldGeometry) {
+ targetPrivate->dirty(QQuickItemPrivate::Position);
+ d->target->geometryChange(newGeometry, oldGeometry);
+ }
}
QQuickStateActionEvent::EventType QQuickAnchorChanges::type() const
@@ -1328,15 +1337,31 @@ void QQuickAnchorChanges::rewind()
return;
QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(d->target);
+ const QRectF oldGeometry(d->target->position(), d->target->size());
+
+ // Restore previous values (but not previous bindings, i.e. anchors).
+ // Also, don't drop any new bindings.
+ if (!qt_is_nan(d->rewindX) && d->rewindX != targetPrivate->x)
+ targetPrivate->x.setValueBypassingBindings(d->rewindX);
+ if (!qt_is_nan(d->rewindY) && d->rewindY != targetPrivate->y)
+ targetPrivate->y.setValueBypassingBindings(d->rewindY);
+
+ if (targetPrivate->widthValid() && !qt_is_nan(d->rewindWidth)) {
+ targetPrivate->widthValidFlag = true;
+ if (d->rewindWidth != targetPrivate->width)
+ targetPrivate->width.setValueBypassingBindings(d->rewindWidth);
+ }
- //restore previous values (but not previous bindings, i.e. anchors)
- d->target->setX(d->rewindX);
- d->target->setY(d->rewindY);
- if (targetPrivate->widthValid()) {
- d->target->setWidth(d->rewindWidth);
+ if (targetPrivate->heightValid() && !qt_is_nan(d->rewindHeight)) {
+ targetPrivate->heightValidFlag = true;
+ if (d->rewindHeight != targetPrivate->height)
+ targetPrivate->height.setValueBypassingBindings(d->rewindHeight);
}
- if (targetPrivate->heightValid()) {
- d->target->setHeight(d->rewindHeight);
+
+ const QRectF newGeometry(d->target->position(), d->target->size());
+ if (newGeometry != oldGeometry) {
+ targetPrivate->dirty(QQuickItemPrivate::Position);
+ d->target->geometryChange(newGeometry, oldGeometry);
}
}
@@ -1373,7 +1398,6 @@ void QQuickAnchorChanges::saveTargetValues()
d->toHeight = d->target->height();
}
-#include <moc_qquickstateoperations_p.cpp>
-
QT_END_NAMESPACE
+#include <moc_qquickstateoperations_p.cpp>
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 540f2edfde..9f259166df 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -429,6 +429,7 @@
/*!
\qmlproperty ItemSelectionModel QtQuick::TableView::selectionModel
+ \since 6.2
This property can be set to control which delegate items should be shown as
selected. If the delegate has a \c {required property bool selected}
@@ -583,8 +584,8 @@
there is no setter function. This getter function is mostly
useful if the TableView doesn't have a columnWidthProvider set, since
otherwise you can call that function instead (which will work, even
- for columns that are not currently visible.
- If no columnWidthProvider is set, the height of a row will be
+ for columns that are not currently visible).
+ If no columnWidthProvider is set, the width of a column will be
equal to its \l implicitColumnWidth().
\sa columnWidthProvider, implicitColumnWidth(), isColumnLoaded(), {Row heights and column widths}
@@ -602,7 +603,7 @@
there is no setter function. This getter function is mostly
useful if the TableView doesn't have a rowHeightProvider set, since
otherwise you can call that function instead (which will work, even
- for rows that are not currently visible.
+ for rows that are not currently visible).
If no rowHeightProvider is set, the height of a row will be
equal to its \l implicitRowHeight().
@@ -687,8 +688,6 @@ Q_LOGGING_CATEGORY(lcTableViewDelegateLifecycle, "qt.quick.tableview.lifecycle")
#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;
static const char* kRequiredProperty = "_qt_isrequiredpropery_selected";
@@ -790,8 +789,12 @@ void QQuickTableViewPrivate::setSelectionStartPos(const QPointF &pos)
{
if (loadedItems.isEmpty())
return;
- if (!selectionModel)
+ if (!selectionModel) {
+ if (warnNoSelectionModel)
+ qmlWarning(q_func()) << "Cannot set selection: no SelectionModel assigned!";
+ warnNoSelectionModel = false;
return;
+ }
const QAbstractItemModel *qaim = selectionModel->model();
if (!qaim)
return;
@@ -816,8 +819,12 @@ void QQuickTableViewPrivate::setSelectionEndPos(const QPointF &pos)
{
if (loadedItems.isEmpty())
return;
- if (!selectionModel)
+ if (!selectionModel) {
+ if (warnNoSelectionModel)
+ qmlWarning(q_func()) << "Cannot set selection: no SelectionModel assigned!";
+ warnNoSelectionModel = false;
return;
+ }
const QAbstractItemModel *qaim = selectionModel->model();
if (!qaim)
return;
@@ -2331,16 +2338,31 @@ void QQuickTableViewPrivate::processRebuildTable()
if (rebuildState == RebuildState::LayoutTable) {
layoutAfterLoadingInitialTable();
+ loadAndUnloadVisibleEdges();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::CancelOvershootBottomRight) {
+ cancelOvershootBottomRight();
+ loadAndUnloadVisibleEdges();
if (!moveToNextRebuildState())
return;
}
- if (rebuildState == RebuildState::LoadAndUnloadAfterLayout) {
+ if (rebuildState == RebuildState::CancelOvershootTopLeft) {
+ cancelOvershootTopLeft();
loadAndUnloadVisibleEdges();
if (!moveToNextRebuildState())
return;
}
+ if (rebuildState == RebuildState::UpdateContentSize) {
+ updateContentSize();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
const bool preload = (rebuildOptions & RebuildOption::All
&& reusableFlag == QQmlTableInstanceModel::Reusable);
@@ -2584,23 +2606,31 @@ void QQuickTableViewPrivate::loadInitialTable()
loadAndUnloadVisibleEdges();
}
-void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
+void QQuickTableViewPrivate::updateContentSize()
{
- clearEdgeSizeCache();
- relayoutTableItems();
- syncLoadedTableRectFromLoadedTable();
-
- if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded()) {
+ const bool allColumnsLoaded = atTableEnd(Qt::LeftEdge) && atTableEnd(Qt::RightEdge);
+ if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded) {
updateAverageColumnWidth();
updateContentWidth();
}
- if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded()) {
+ const bool allRowsLoaded = atTableEnd(Qt::TopEdge) && atTableEnd(Qt::BottomEdge);
+ if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded) {
updateAverageRowHeight();
updateContentHeight();
}
updateExtents();
+}
+
+void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
+{
+ clearEdgeSizeCache();
+ relayoutTableItems();
+ syncLoadedTableRectFromLoadedTable();
+
+ updateContentSize();
+
adjustViewportXAccordingToAlignment();
adjustViewportYAccordingToAlignment();
}
@@ -2675,6 +2705,58 @@ void QQuickTableViewPrivate::adjustViewportYAccordingToAlignment()
syncViewportRect();
}
+void QQuickTableViewPrivate::cancelOvershootBottomRight()
+{
+ // After doing a layout with positioning specified, the table might end up in an
+ // overshooting state (meaning that the table is dragged beyond the bounds
+ // of the viewport, with the result that it will bounce back in once you touch it).
+ // This happens because the layouting might try to e.g position the last row in the
+ // model in the center of the viewport, which will leave a big blank space from the
+ // last row towards the bottom.
+ // This space will be detected by updateExtents(), which will adjust the extents so
+ // that the superfluous blank area ends up as an overshoot. But we shouldn't leave the
+ // table in an overshooting state after a rebuild, so we clamp it here so thatit's
+ // either aligned to the top/left or to the bottom/right of the viewport.
+ // An exception is if we're not rebuilding because of positionViewAtCell(), since
+ // the app is allowed to set contentX and contentY at start-up. A second exception is
+ // if this view is a sync child, since then we can end up with extra space at the end
+ // if our model has fewer rows/columns than the syncView.
+ const qreal blankSpaceRight = viewportRect.right() - loadedTableOuterRect.right();
+ const qreal blankSpaceBottom = viewportRect.bottom() - loadedTableOuterRect.bottom();
+ const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
+ const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
+
+ if (positionVertically && !syncVertically && viewportRect.top() > 0 && blankSpaceBottom > 0) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "cancelling overshoot at bottom:" << blankSpaceBottom;
+ setLocalViewportY(viewportRect.y() - blankSpaceBottom);
+ syncViewportRect();
+ }
+
+ if (positionHorizontally && !syncHorizontally && viewportRect.left() > 0 && blankSpaceRight > 0) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "cancelling overshoot at right:" << blankSpaceRight;
+ setLocalViewportX(viewportRect.x() - blankSpaceRight);
+ syncViewportRect();
+ }
+}
+
+void QQuickTableViewPrivate::cancelOvershootTopLeft()
+{
+ const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
+ const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
+
+ if (positionVertically && !syncVertically && viewportRect.top() < 0) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "cancelling overshoot at top:" << viewportRect.top();
+ setLocalViewportY(0);
+ syncViewportRect();
+ }
+
+ if (positionHorizontally && !syncHorizontally && viewportRect.left() < 0) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "cancelling overshoot at left:" << viewportRect.left();
+ setLocalViewportX(0);
+ syncViewportRect();
+ }
+}
+
void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
{
Q_Q(QQuickTableView);
@@ -2725,7 +2807,7 @@ void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
{
const int edgeIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
- qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex;
+ qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex << q_func();
const auto visibleCells = edge & (Qt::LeftEdge | Qt::RightEdge)
? loadedRows.keys() : loadedColumns.keys();
@@ -3226,11 +3308,25 @@ void QQuickTableViewPrivate::syncSyncView()
if (syncHorizontally) {
q->setColumnSpacing(syncView->columnSpacing());
updateContentWidth();
+
+ if (syncView->leftColumn() != q->leftColumn()) {
+ // The left column is no longer the same as the left
+ // column in syncView. This requires a rebuild.
+ scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
+ scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
+ }
}
if (syncVertically) {
q->setRowSpacing(syncView->rowSpacing());
updateContentHeight();
+
+ if (syncView->topRow() != q->topRow()) {
+ // The top row is no longer the same as the top
+ // row in syncView. This requires a rebuild.
+ scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
+ scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
+ }
}
if (syncView && loadedItems.isEmpty() && !tableSize.isEmpty()) {
@@ -3456,10 +3552,26 @@ void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
void QQuickTableViewPrivate::syncViewportRect()
{
- // Sync viewportRect so that it contains the actual geometry of the viewport
+ // Sync viewportRect so that it contains the actual geometry of the viewport.
+ // Since the column (and row) size of a sync child is decided by the column size
+ // of its sync view, the viewport width of a sync view needs to be the maximum of
+ // the sync views width, and its sync childrens width. This to ensure that no sync
+ // child loads a column which is not yet loaded by the sync view, since then the
+ // implicit column size cannot be resolved.
Q_Q(QQuickTableView);
- viewportRect = QRectF(q->contentX(), q->contentY(), q->width(), q->height());
- qCDebug(lcTableViewDelegateLifecycle) << viewportRect;
+
+ qreal w = q->width();
+ qreal h = q->height();
+
+ for (auto syncChild : std::as_const(syncChildren)) {
+ auto syncChild_d = syncChild->d_func();
+ if (syncChild_d->syncHorizontally)
+ w = qMax(w, syncChild->width());
+ if (syncChild_d->syncHorizontally)
+ h = qMax(h, syncChild->height());
+ }
+
+ viewportRect = QRectF(q->contentX(), q->contentY(), w, h);
}
void QQuickTableViewPrivate::syncViewportPosRecursive()
@@ -4154,3 +4266,5 @@ QQuickTableSectionSizeProviderPrivate::~QQuickTableSectionSizeProviderPrivate()
#include "moc_qquicktableview_p.cpp"
QT_END_NAMESPACE
+
+#include "moc_qquicktableview_p_p.cpp"
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 76d5c152da..9893cd97e7 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -71,6 +71,8 @@ Q_DECLARE_LOGGING_CATEGORY(lcTableViewDelegateLifecycle)
static const qreal kDefaultRowHeight = 50;
static const qreal kDefaultColumnWidth = 50;
+static const int kEdgeIndexNotSet = -2;
+static const int kEdgeIndexAtEnd = -3;
class FxTableItem;
class QQuickTableSectionSizeProviderPrivate;
@@ -201,7 +203,9 @@ public:
LoadInitalTable,
VerifyTable,
LayoutTable,
- LoadAndUnloadAfterLayout,
+ CancelOvershootBottomRight,
+ CancelOvershootTopLeft,
+ UpdateContentSize,
PreloadColumns,
PreloadRows,
MovePreloadedItemsToPool,
@@ -288,6 +292,8 @@ public:
// Consider making it public.
bool isTransposed = false;
+ bool warnNoSelectionModel = true;
+
QJSValue rowHeightProvider;
QJSValue columnWidthProvider;
QQuickTableSectionSizeProvider rowHeights;
@@ -396,6 +402,9 @@ public:
int nextVisibleEdgeIndex(Qt::Edge edge, int startIndex);
int nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge);
+ inline bool atTableEnd(Qt::Edge edge) {
+ return nextVisibleEdgeIndexAroundLoadedTable(edge) == kEdgeIndexAtEnd;
+ }
bool allColumnsLoaded();
bool allRowsLoaded();
inline int edgeToArrayIndex(Qt::Edge edge);
@@ -432,8 +441,13 @@ public:
void adjustViewportXAccordingToAlignment();
void adjustViewportYAccordingToAlignment();
+ void cancelOvershootBottomRight();
+ void cancelOvershootTopLeft();
+
void scheduleRebuildTable(QQuickTableViewPrivate::RebuildOptions options);
+ void updateContentSize();
+
QTypeRevision resolveImportVersion();
void createWrapperModel();
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 0f17af1975..ec1416768e 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -764,11 +764,15 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
const bool pixelSize = font.pixelSize() != -1;
QString layoutText = layout.text();
- int largeFont = pixelSize ? font.pixelSize() : font.pointSize();
- int smallFont = fontSizeMode() != QQuickText::FixedSize
- ? qMin(pixelSize ? minimumPixelSize() : minimumPointSize(), largeFont)
- : largeFont;
- int scaledFontSize = largeFont;
+ const qreal minimumSize = pixelSize
+ ? static_cast<qreal>(minimumPixelSize())
+ : minimumPointSize();
+ qreal largeFont = pixelSize ? font.pixelSize() : font.pointSizeF();
+ qreal smallFont = fontSizeMode() != QQuickText::FixedSize
+ ? qMin<qreal>(minimumSize, largeFont)
+ : largeFont;
+ qreal scaledFontSize = largeFont;
+ const qreal sizeFittingThreshold(0.01);
bool widthChanged = false;
widthExceeded = availableWidth() <= 0 && (singlelineElide || canWrap || horizontalFit);
@@ -797,7 +801,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
if (pixelSize)
scaledFont.setPixelSize(scaledFontSize);
else
- scaledFont.setPointSize(scaledFontSize);
+ scaledFont.setPointSizeF(scaledFontSize);
if (layout.font() != scaledFont)
layout.setFont(scaledFont);
}
@@ -967,7 +971,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
const qreal availWidth = availableWidth();
const qreal availHeight = availableHeight();
- lineWidth = q->widthValid() && availWidth > 0 ? availWidth : naturalWidth;
+ lineWidth = q->widthValid() && q->width() > 0 ? availWidth : naturalWidth;
maxHeight = q->heightValid() ? availHeight : FLT_MAX;
// If the width of the item has changed and it's possible the result of wrapping,
@@ -1061,40 +1065,45 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
if (!horizontalFit && !verticalFit)
break;
+ // Can't find a better fit
+ if (qFuzzyCompare(smallFont, largeFont))
+ break;
+
// Try and find a font size that better fits the dimensions of the element.
if (horizontalFit) {
if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
widthExceeded = true;
- largeFont = scaledFontSize - 1;
- if (smallFont > largeFont)
- break;
+ largeFont = scaledFontSize;
+
scaledFontSize = (smallFont + largeFont) / 2;
- if (pixelSize)
- scaledFont.setPixelSize(scaledFontSize);
- else
- scaledFont.setPointSize(scaledFontSize);
+
continue;
} else if (!verticalFit) {
smallFont = scaledFontSize;
- if (smallFont == largeFont)
+
+ // Check to see if the current scaledFontSize is acceptable
+ if ((largeFont - smallFont) < sizeFittingThreshold)
break;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
+
+ scaledFontSize = (smallFont + largeFont) / 2;
}
}
if (verticalFit) {
if (truncateHeight || unelidedRect.height() > maxHeight) {
heightExceeded = true;
- largeFont = scaledFontSize - 1;
- if (smallFont > largeFont)
- break;
+ largeFont = scaledFontSize;
+
scaledFontSize = (smallFont + largeFont) / 2;
} else {
smallFont = scaledFontSize;
- if (smallFont == largeFont)
+
+ // Check to see if the current scaledFontSize is acceptable
+ if ((largeFont - smallFont) < sizeFittingThreshold)
break;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
+
+ scaledFontSize = (smallFont + largeFont) / 2;
}
}
}
@@ -1153,12 +1162,6 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
elideLayout->setFont(layout.font());
elideLayout->setTextOption(layout.textOption());
-#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
- if (QQmlDebugTranslationService *service
- = QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
- elideText = service->foundElidedText(q, layoutText, elideText);
- }
-#endif //QT_CONFIG(translation)
elideLayout->setText(elideText);
elideLayout->beginLayout();
@@ -2416,21 +2419,23 @@ void QQuickText::geometryChange(const QRectF &newGeometry, const QRectF &oldGeom
goto geomChangeDone;
if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed
- if (newGeometry.height() > oldGeometry.height()) {
- 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()) {
- if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
- goto geomChangeDone;
-
- if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
- && d->elideMode != QQuickText::ElideRight
- && !(d->maximumLineCountValid && d->widthExceeded)) {
- goto geomChangeDone;
+ if (!verticalPositionChanged) {
+ if (newGeometry.height() > oldGeometry.height()) {
+ 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()) {
+ if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
+ goto geomChangeDone;
+
+ if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
+ && d->elideMode != QQuickText::ElideRight
+ && !(d->maximumLineCountValid && d->widthExceeded)) {
+ goto geomChangeDone;
+ }
}
}
} else if (!heightChanged && widthMaximum) {
@@ -2958,7 +2963,7 @@ void QQuickTextPrivate::processHoverEvent(QHoverEvent *event)
emit q->linkHovered(extra->hoveredLink);
}
}
- event->setAccepted(!link.isEmpty());
+ event->ignore();
}
void QQuickText::hoverEnterEvent(QHoverEvent *event)
@@ -2981,6 +2986,7 @@ void QQuickText::hoverLeaveEvent(QHoverEvent *event)
/*!
\qmlproperty int QtQuick::Text::renderTypeQuality
+ \since 6.0
Override the default rendering type quality for this component. This is a low-level
customization which can be ignored in most cases. It currently only has an effect
diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h
index 304b82b914..13d8579017 100644
--- a/src/quick/items/qquicktext_p.h
+++ b/src/quick/items/qquicktext_p.h
@@ -339,6 +339,8 @@ private:
Q_DECLARE_PRIVATE(QQuickText)
};
+Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, QQuickText::HAlignment, QQuickText::VAlignment)
+
class QTextLine;
class QQuickTextLine : public QObject
{
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 32a27661ea..1412b68ceb 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -1203,7 +1203,15 @@ void QQuickTextEdit::setCursorVisible(bool on)
/*!
\qmlproperty int QtQuick::TextEdit::cursorPosition
- The position of the cursor in the TextEdit.
+ The position of the cursor in the TextEdit. The cursor is positioned between
+ characters.
+
+ \note The \e characters in this case refer to the string of \l QChar objects,
+ therefore 16-bit Unicode characters, and the position is considered an index
+ into this string. This does not necessarily correspond to individual graphemes
+ in the writing system, as a single grapheme may be represented by multiple
+ Unicode characters, such as in the case of surrogate pairs, linguistic
+ ligatures or diacritics.
*/
int QQuickTextEdit::cursorPosition() const
{
@@ -2959,6 +2967,7 @@ void QQuickTextEdit::hoverEnterEvent(QHoverEvent *event)
Q_D(QQuickTextEdit);
if (d->isLinkHoveredConnected())
d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+ event->ignore();
}
void QQuickTextEdit::hoverMoveEvent(QHoverEvent *event)
@@ -2966,6 +2975,7 @@ void QQuickTextEdit::hoverMoveEvent(QHoverEvent *event)
Q_D(QQuickTextEdit);
if (d->isLinkHoveredConnected())
d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+ event->ignore();
}
void QQuickTextEdit::hoverLeaveEvent(QHoverEvent *event)
@@ -2973,6 +2983,7 @@ void QQuickTextEdit::hoverLeaveEvent(QHoverEvent *event)
Q_D(QQuickTextEdit);
if (d->isLinkHoveredConnected())
d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+ event->ignore();
}
/*!
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index 41245f904e..7b43a847c1 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -422,6 +422,8 @@ private:
Q_DECLARE_PRIVATE(QQuickTextEdit)
};
+Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, QQuickTextEdit::HAlignment, QQuickTextEdit::VAlignment)
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickTextEdit)
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index e5922df623..c08f357df8 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -517,8 +517,16 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color)
}
/*!
- \qmlproperty enumeration QtQuick::TextInput::horizontalAlignment
\qmlproperty enumeration QtQuick::TextInput::effectiveHorizontalAlignment
+ \readonly
+
+ When using the attached property LayoutMirroring::enabled to mirror application
+ layouts, the horizontal alignment of text will also be mirrored. However, the property
+ \l horizontalAlignment will remain unchanged. To query the effective horizontal alignment
+ of TextInput, use the read-only property \c effectiveHorizontalAlignment.
+*/
+/*!
+ \qmlproperty enumeration QtQuick::TextInput::horizontalAlignment
\qmlproperty enumeration QtQuick::TextInput::verticalAlignment
Sets the horizontal alignment of the text within the TextInput item's
@@ -541,7 +549,7 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color)
When using the attached property LayoutMirroring::enabled to mirror application
layouts, the horizontal alignment of text will also be mirrored. However, the property
\c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
- of TextInput, use the read-only property \c effectiveHorizontalAlignment.
+ of TextInput, use the read-only property \l effectiveHorizontalAlignment.
*/
QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
{
@@ -830,7 +838,20 @@ void QQuickTextInput::setCursorVisible(bool on)
/*!
\qmlproperty int QtQuick::TextInput::cursorPosition
- The position of the cursor in the TextInput.
+ The position of the cursor in the TextInput. The cursor is positioned between
+ characters.
+
+ \note The \e characters in this case refer to the string of \l QChar objects,
+ therefore 16-bit Unicode characters, and the position is considered an index
+ into this string. This does not necessarily correspond to individual graphemes
+ in the writing system, as a single grapheme may be represented by multiple
+ Unicode characters, such as in the case of surrogate pairs, linguistic
+ ligatures or diacritics.
+
+ \l displayText is different if echoMode is set to \l TextInput.Password: then
+ each passwordMaskCharacter is a "narrow" character
+ (the cursorPosition always moves by 1), even if the text in the TextInput is not.
+
*/
int QQuickTextInput::cursorPosition() const
{
@@ -848,6 +869,7 @@ void QQuickTextInput::setCursorPosition(int cp)
/*!
\qmlproperty rectangle QtQuick::TextInput::cursorRectangle
+ \readonly
The rectangle where the standard text cursor is rendered within the text input. Read only.
@@ -889,6 +911,7 @@ QRectF QQuickTextInput::cursorRectangle() const
This property is read-only. To change the selection, use select(start,end),
selectAll(), or selectWord().
+ \readonly
\sa selectionEnd, cursorPosition, selectedText
*/
int QQuickTextInput::selectionStart() const
@@ -904,6 +927,7 @@ int QQuickTextInput::selectionStart() const
This property is read-only. To change the selection, use select(start,end),
selectAll(), or selectWord().
+ \readonly
\sa selectionStart, cursorPosition, selectedText
*/
int QQuickTextInput::selectionEnd() const
@@ -934,6 +958,7 @@ void QQuickTextInput::select(int start, int end)
/*!
\qmlproperty string QtQuick::TextInput::selectedText
+ \readonly
This read-only property provides the text currently selected in the
text input.
@@ -1151,6 +1176,7 @@ void QQuickTextInput::setInputMask(const QString &im)
/*!
\qmlproperty bool QtQuick::TextInput::acceptableInput
+ \readonly
This property is always true unless a validator or input mask has been set.
If a validator or input mask has been set, this property will only be true
@@ -2001,6 +2027,8 @@ QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property, const
if (argument.isValid())
return QVariant(QStringView{d->m_text}.left(d->m_cursor).right(argument.toInt()).toString());
return QVariant(d->m_text.left(d->m_cursor));
+ case Qt::ImReadOnly:
+ return QVariant(d->m_readOnly);
default:
return QQuickItem::inputMethodQuery(property);
}
@@ -2104,7 +2132,7 @@ void QQuickTextInput::undo()
{
Q_D(QQuickTextInput);
if (!d->m_readOnly) {
- d->resetInputMethod();
+ d->cancelInput();
d->internalUndo();
d->finishChange(-1, true);
}
@@ -2120,7 +2148,7 @@ void QQuickTextInput::redo()
{
Q_D(QQuickTextInput);
if (!d->m_readOnly) {
- d->resetInputMethod();
+ d->cancelInput();
d->internalRedo();
d->finishChange();
}
@@ -2458,6 +2486,7 @@ void QQuickTextInput::setPersistentSelection(bool on)
/*!
\qmlproperty bool QtQuick::TextInput::canPaste
+ \readonly
Returns true if the TextInput is writable and the content of the clipboard is
suitable for pasting into the TextInput.
@@ -2479,6 +2508,7 @@ bool QQuickTextInput::canPaste() const
/*!
\qmlproperty bool QtQuick::TextInput::canUndo
+ \readonly
Returns true if the TextInput is writable and there are previous operations
that can be undone.
@@ -2492,6 +2522,7 @@ bool QQuickTextInput::canUndo() const
/*!
\qmlproperty bool QtQuick::TextInput::canRedo
+ \readonly
Returns true if the TextInput is writable and there are \l {undo}{undone}
operations that can be redone.
@@ -2505,6 +2536,7 @@ bool QQuickTextInput::canRedo() const
/*!
\qmlproperty real QtQuick::TextInput::contentWidth
+ \readonly
Returns the width of the text, including the width past the width
which is covered due to insufficient wrapping if \l wrapMode is set.
@@ -2518,6 +2550,7 @@ qreal QQuickTextInput::contentWidth() const
/*!
\qmlproperty real QtQuick::TextInput::contentHeight
+ \readonly
Returns the height of the text, including the height past the height
that is covered if the text does not fit within the set height.
@@ -2681,7 +2714,7 @@ void QQuickTextInput::focusOutEvent(QFocusEvent *event)
/*!
\qmlproperty bool QtQuick::TextInput::inputMethodComposing
-
+ \readonly
This property holds whether the TextInput has partial text input from an
input method.
@@ -2747,11 +2780,13 @@ void QQuickTextInputPrivate::init()
m_inputControl = new QInputControl(QInputControl::LineEdit, q);
}
-void QQuickTextInputPrivate::resetInputMethod()
+void QQuickTextInputPrivate::cancelInput()
{
+#if QT_CONFIG(im)
Q_Q(QQuickTextInput);
if (!m_readOnly && q->hasActiveFocus() && qGuiApp)
- QGuiApplication::inputMethod()->reset();
+ cancelPreedit();
+#endif // im
}
void QQuickTextInput::updateCursorRectangle(bool scroll)
@@ -3459,7 +3494,12 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
for (int i = 0; i < event->attributes().size(); ++i) {
const QInputMethodEvent::Attribute &a = event->attributes().at(i);
if (a.type == QInputMethodEvent::Selection) {
- m_cursor = qBound(0, a.start + a.length, m_text.length());
+ // If we already called internalInsert(), the cursor position will
+ // already be adjusted correctly. The attribute.start does
+ // not seem to take the mask into account, so it will reset cursor
+ // to an invalid position in such case.
+ if (!cursorPositionChanged)
+ m_cursor = qBound(0, a.start + a.length, m_text.length());
if (a.length) {
m_selstart = qMax(0, qMin(a.start, m_text.length()));
m_selend = m_cursor;
@@ -4696,7 +4736,7 @@ void QQuickTextInput::ensureVisible(int position)
void QQuickTextInput::clear()
{
Q_D(QQuickTextInput);
- d->resetInputMethod();
+ d->cancelInput();
d->clear();
}
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index b4561556aa..1fecd7f9df 100644
--- a/src/quick/items/qquicktextinput_p_p.h
+++ b/src/quick/items/qquicktextinput_p_p.h
@@ -173,7 +173,7 @@ public:
}
void init();
- void resetInputMethod();
+ void cancelInput();
void startCreatingCursor();
void ensureVisible(int position, int preeditCursor = 0, int preeditLength = 0);
void updateHorizontalScroll();
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index b3401200c8..763607f730 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -209,10 +209,7 @@ void QQuickTextNodeEngine::addTextDecorations(const QVarLengthArray<TextDecorati
{
QRectF &rect = textDecoration.rect;
- rect.setY(qRound(rect.y()
- + m_currentLine.ascent()
- + (m_currentLine.leadingIncluded() ? m_currentLine.leading() : qreal(0.0f))
- + offset));
+ rect.setY(qRound(rect.y() + m_currentLine.ascent() + offset));
rect.setHeight(thickness);
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 314223a838..19b508cecb 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -483,18 +483,14 @@ void forceUpdate(QQuickItem *item)
forceUpdate(items.at(i));
}
-void QQuickWindowRenderTarget::reset(QRhi *rhi, QSGRenderer *renderer)
+void QQuickWindowRenderTarget::reset(QRhi *rhi)
{
- if (rhi) {
- if (renderer)
- renderer->invalidatePipelineCacheDependency(rpDesc);
- if (owns) {
- delete renderTarget;
- delete rpDesc;
- delete texture;
- delete renderBuffer;
- delete depthStencil;
- }
+ if (rhi && owns) {
+ delete renderTarget;
+ delete rpDesc;
+ delete texture;
+ delete renderBuffer;
+ delete depthStencil;
}
renderTarget = nullptr;
@@ -514,7 +510,7 @@ void QQuickWindowPrivate::ensureCustomRenderTarget()
redirect.renderTargetDirty = false;
- redirect.rt.reset(rhi, renderer);
+ redirect.rt.reset(rhi);
// a default constructed QQuickRenderTarget means no redirection
if (customRenderTarget.isNull())
@@ -723,7 +719,7 @@ QQuickWindowPrivate::QQuickWindowPrivate()
QQuickWindowPrivate::~QQuickWindowPrivate()
{
inDestructor = true;
- redirect.rt.reset(rhi, renderer);
+ redirect.rt.reset(rhi);
if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
service->removeWindow(q_func());
deliveryAgent = nullptr;
@@ -884,14 +880,6 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
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} graphical types.
- To use this type, you will need to import the module with the following line:
- \code
- import QtQuick
- \endcode
-
- Omitting this import will allow you to have a QML environment without
- access to window system features.
-
A Window can be declared inside an Item or inside another Window; in that
case the inner Window will automatically become "transient for" the outer
Window: that is, most platforms will show it centered upon the outer window
@@ -907,9 +895,23 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
When the user attempts to close a window, the \l closing signal will be
emitted. You can force the window to stay open (for example to prompt the
- user to save changes) by writing an \c onClosing handler and setting
- \c {close.accepted = false}.
+ user to save changes) by writing an \c onClosing handler that sets
+ \c {close.accepted = false} unless it's safe to close the window (for example,
+ because there are no more unsaved changes).
+
+ \code
+ onClosing: (close) => {
+ if (document.changed) {
+ close.accepted = false
+ confirmExitPopup.open()
+ }
+ }
+
+ // The confirmExitPopup allows user to save or discard the document,
+ // or to cancel the closing.
+ \endcode
*/
+
/*!
\class QQuickWindow
\since 5.0
@@ -1094,7 +1096,11 @@ QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent)
}
/*!
- \internal
+ Constructs a window for displaying a QML scene, whose rendering will
+ be controlled by the \a control object.
+ Please refer to QQuickRenderControl's documentation for more information.
+
+ \since 5.4
*/
QQuickWindow::QQuickWindow(QQuickRenderControl *control)
: QWindow(*(new QQuickWindowPrivate), nullptr)
@@ -1318,6 +1324,8 @@ QQuickItem *QQuickWindow::contentItem() const
\brief The item which currently has active focus or \c null if there is
no item with active focus.
+
+ \sa QQuickItem::forceActiveFocus(), {Keyboard Focus in Qt Quick}
*/
QQuickItem *QQuickWindow::activeFocusItem() const
{
@@ -1350,6 +1358,38 @@ bool QQuickWindow::event(QEvent *e)
QQuickDeliveryAgent *da = d->deliveryAgent;
if (e->isPointerEvent()) {
/*
+ We can't bypass the virtual functions like mousePressEvent() tabletEvent() etc.,
+ for the sake of code that subclasses QQuickWindow and overrides them, even though
+ we no longer need them as entry points for Qt Quick event delivery.
+ So dispatch to them now, ahead of normal delivery, and stop them from calling
+ back into this function if they were called from here (avoid recursion).
+ It could also be that user code expects them to work as entry points, too;
+ in that case, windowEventDispatch _won't_ be set, so the event comes here and
+ we'll dispatch it further below.
+ */
+ if (d->windowEventDispatch)
+ return false;
+ {
+ const bool wasAccepted = e->isAccepted();
+ QBoolBlocker windowEventDispatchGuard(d->windowEventDispatch, true);
+ qCDebug(lcPtr) << "dispatching to window functions in case of override" << e;
+ QWindow::event(e);
+ if (e->isAccepted() && !wasAccepted)
+ return true;
+ }
+ /*
+ QQuickWindow does not override touchEvent(). If the application has a subclass
+ of QQuickWindow which allows the event to remain accepted, it means they want
+ to stop propagation here, so return early (below). But otherwise we will call
+ QWindow::touchEvent(), which will ignore(); in that case, we need to continue
+ with the usual delivery below, so we need to undo the ignore().
+ */
+ auto pe = static_cast<QPointerEvent *>(e);
+ if (QQuickDeliveryAgentPrivate::isTouchEvent(pe))
+ e->accept();
+ // end of dispatch to user-overridden virtual window functions
+
+ /*
When delivering update and release events to existing grabbers,
use the subscene delivery agent, if any. A possible scenario:
1) Two touchpoints pressed on the main window: QQuickWindowPrivate::deliveryAgent delivers to QQuick3DViewport,
@@ -1362,7 +1402,6 @@ bool QQuickWindow::event(QEvent *e)
With single-point events (mouse, or only one finger) it's simplified: there can only be one subscene of interest;
for (pt : pe->points()) would only iterate once, so we might as well skip that logic.
*/
- auto pe = static_cast<QPointerEvent *>(e);
if (pe->pointCount()) {
if (QQuickDeliveryAgentPrivate::subsceneAgentsExist) {
bool ret = false;
@@ -1533,13 +1572,18 @@ bool QQuickWindow::event(QEvent *e)
else if (e->type() == QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure))
d->windowManager->handleContextCreationFailure(this);
- return QWindow::event(e);
+ if (e->isPointerEvent())
+ return true;
+ else
+ return QWindow::event(e);
}
/*! \reimp */
void QQuickWindow::keyPressEvent(QKeyEvent *e)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverKeyEvent(e);
@@ -1549,6 +1593,8 @@ void QQuickWindow::keyPressEvent(QKeyEvent *e)
void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverKeyEvent(e);
@@ -1559,6 +1605,8 @@ void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
void QQuickWindow::wheelEvent(QWheelEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverSinglePointEventUntilAccepted(event);
@@ -1570,6 +1618,8 @@ void QQuickWindow::wheelEvent(QWheelEvent *event)
void QQuickWindow::tabletEvent(QTabletEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverPointerEvent(event);
@@ -1580,6 +1630,8 @@ void QQuickWindow::tabletEvent(QTabletEvent *event)
void QQuickWindow::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
@@ -1588,6 +1640,8 @@ void QQuickWindow::mousePressEvent(QMouseEvent *event)
void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
@@ -1596,6 +1650,8 @@ void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
@@ -1604,6 +1660,8 @@ void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
@@ -1672,6 +1730,12 @@ QPair<QQuickItem*, QQuickPointerHandler*> QQuickWindowPrivate::findCursorItemAnd
}
#endif
+void QQuickWindowPrivate::clearFocusObject()
+{
+ if (auto da = deliveryAgentPrivate())
+ da->clearFocusObject();
+}
+
/*!
\qmlproperty list<Object> Window::data
\qmldefault
@@ -1787,7 +1851,7 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
p->dirty(QQuickItemPrivate::Window);
}
- // Qt 6: Make invalidateSceneGraph a virtual member of QQuickItem
+ // Qt 7: Make invalidateSceneGraph a virtual member of QQuickItem
if (p->flags & QQuickItem::ItemHasContents) {
const QMetaObject *mo = item->metaObject();
int index = mo->indexOfSlot("invalidateSceneGraph()");
@@ -2000,9 +2064,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
// desired list is shorter.
QSGNode *groupNode = itemPriv->childContainerNode();
QSGNode *currentNode = groupNode->firstChild();
- int added = 0;
- int removed = 0;
- int replaced = 0;
QSGNode *desiredNode = nullptr;
while (currentNode && (desiredNode = fetchNextNode(itemPriv, ii, fetchedPaintNode))) {
@@ -2015,7 +2076,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
desiredNode->parent()->removeChildNode(desiredNode);
groupNode->insertChildNodeAfter(desiredNode, currentNode);
groupNode->removeChildNode(currentNode);
- replaced++;
// since we just replaced currentNode, we also need to reset
// the pointer.
@@ -2034,7 +2094,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
if (desiredNode->parent())
desiredNode->parent()->removeChildNode(desiredNode);
groupNode->appendChildNode(desiredNode);
- added++;
}
} else if (currentNode) {
// on the other hand, if we processed less than our current node
@@ -2044,7 +2103,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
QSGNode *node = currentNode->nextSibling();
groupNode->removeChildNode(currentNode);
currentNode = node;
- removed++;
}
}
}
@@ -2490,7 +2548,7 @@ QImage QQuickWindow::grabWindow()
{
Q_D(QQuickWindow);
- if (!isVisible() && !d->renderControl) {
+ if (!d->isRenderable() && !d->renderControl) {
// backends like software can grab regardless of the window state
if (d->windowManager && (d->windowManager->flags() & QSGRenderLoop::SupportsGrabWithoutExpose))
return d->windowManager->grab(this);
@@ -3780,7 +3838,7 @@ QSGRendererInterface *QQuickWindow::rendererInterface() const
graphics API based on the platform and other conditions, set \a api to
QSGRendererInterface::Unknown.
- \since 5.8
+ \since 6.0
*/
void QQuickWindow::setGraphicsApi(QSGRendererInterface::GraphicsApi api)
{
@@ -4082,7 +4140,7 @@ void QQuickWindow::setTextRenderType(QQuickWindow::TextRenderType renderType)
/*!
\since 6.0
- \qmlproperty QQuickPalette Window::palette
+ \qmlproperty Palette Window::palette
This property holds the palette currently set for the window.
@@ -4094,7 +4152,7 @@ void QQuickWindow::setTextRenderType(QQuickWindow::TextRenderType renderType)
property on the window's palette, that property propagates to all child controls in the window,
overriding any system defaults for that property.
- \sa Item::palette, Popup::palette, QQuickColorGroup
+ \sa Item::palette, Popup::palette, ColorGroup, SystemPalette
//! internal \sa QQuickAbstractPaletteProvider, QQuickPalette
*/
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 7342424251..3b442499bb 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -110,7 +110,7 @@ public Q_SLOTS:
class QQuickWindowRenderTarget
{
public:
- void reset(QRhi *rhi, QSGRenderer *renderer);
+ void reset(QRhi *rhi);
QRhiRenderTarget *renderTarget = nullptr;
QRhiRenderPassDescriptor *rpDesc = nullptr;
QRhiTexture *texture = nullptr;
@@ -161,6 +161,8 @@ public:
QPair<QQuickItem*, QQuickPointerHandler*> findCursorItemAndHandler(QQuickItem *item, const QPointF &scenePos) const;
#endif
+ void clearFocusObject() override;
+
void dirtyItem(QQuickItem *);
void cleanup(QSGNode *);
@@ -249,9 +251,18 @@ public:
void clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason)
{ deliveryAgentPrivate()->clearFocusInScope(scope, item, reason); }
void handleTouchEvent(QTouchEvent *e)
- { deliveryAgentPrivate()->handleTouchEvent(e); }
+ {
+ // setup currentEventDeliveryAgent like in QQuickDeliveryAgent::event
+ QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = deliveryAgentPrivate()->q_func();
+ deliveryAgentPrivate()->handleTouchEvent(e);
+ QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = nullptr;
+ }
void handleMouseEvent(QMouseEvent *e)
- { deliveryAgentPrivate()->handleMouseEvent(e); }
+ {
+ QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = deliveryAgentPrivate()->q_func();
+ deliveryAgentPrivate()->handleMouseEvent(e);
+ QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = nullptr;
+ }
// ^^^ currently in use in Controls 2; TODO remove
// data property
@@ -287,6 +298,7 @@ public:
uint hasActiveSwapchain : 1;
uint hasRenderableSwapchain : 1;
uint swapchainJustBecameRenderable : 1;
+ bool windowEventDispatch = false;
private:
static void cleanupNodesOnShutdown(QQuickItem *);
diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h
index 7177469b55..c1cd48f964 100644
--- a/src/quick/items/qquickwindowmodule_p.h
+++ b/src/quick/items/qquickwindowmodule_p.h
@@ -74,7 +74,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public Q
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
- Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
+ Q_PROPERTY(QWindow::Visibility visibility READ visibility WRITE setVisibility NOTIFY
+ visibilityChanged)
Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION(2, 3))
QML_ATTACHED(QQuickWindowAttached)
QML_NAMED_ELEMENT(Window)
@@ -84,7 +85,7 @@ public:
QQuickWindowQmlImpl(QWindow *parent = nullptr);
void setVisible(bool visible);
- void setVisibility(Visibility visibility);
+ void setVisibility(QWindow::Visibility visibility);
QObject *screen() const;
void setScreen(QObject *screen);