aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp10
-rw-r--r--src/quick/designer/qquickdesignersupportproperties.cpp35
-rw-r--r--src/quick/designer/qquickdesignersupportproperties_p.h7
-rw-r--r--src/quick/doc/images/containmentMask-circle.gifbin0 -> 9926 bytes
-rw-r--r--src/quick/doc/images/containmentMask-shape.gifbin0 -> 11261 bytes
-rw-r--r--src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml69
-rw-r--r--src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml69
-rw-r--r--src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml76
-rw-r--r--src/quick/doc/snippets/pointerHandlers/hoverTapKeyButton.qml73
-rw-r--r--src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.pngbin0 -> 1454 bytes
-rw-r--r--src/quick/doc/snippets/qml/externaldrag.qml20
-rw-r--r--src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml71
-rw-r--r--src/quick/doc/snippets/qml/item/containmentMask-shape.qml80
-rw-r--r--src/quick/doc/src/concepts/input/focus.qdoc2
-rw-r--r--src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc64
-rw-r--r--src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc27
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc67
-rw-r--r--src/quick/handlers/qquickdragaxis.cpp2
-rw-r--r--src/quick/handlers/qquickdraghandler.cpp2
-rw-r--r--src/quick/handlers/qquickhandlerpoint.cpp2
-rw-r--r--src/quick/handlers/qquickhoverhandler.cpp108
-rw-r--r--src/quick/handlers/qquickhoverhandler_p.h1
-rw-r--r--src/quick/handlers/qquickmultipointhandler.cpp18
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp29
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler.cpp2
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp60
-rw-r--r--src/quick/handlers/qquickpointhandler.cpp2
-rw-r--r--src/quick/handlers/qquicksinglepointhandler.cpp2
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp15
-rw-r--r--src/quick/handlers/qquickwheelhandler.cpp2
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp29
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h2
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp5
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp11
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp5
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp14
-rw-r--r--src/quick/items/qquickdroparea.cpp1
-rw-r--r--src/quick/items/qquickevents.cpp14
-rw-r--r--src/quick/items/qquickflickable.cpp146
-rw-r--r--src/quick/items/qquickflickable_p_p.h6
-rw-r--r--src/quick/items/qquickgridview.cpp2
-rw-r--r--src/quick/items/qquickimage.cpp10
-rw-r--r--src/quick/items/qquickimagebase.cpp8
-rw-r--r--src/quick/items/qquickitem.cpp111
-rw-r--r--src/quick/items/qquickitemanimation.cpp27
-rw-r--r--src/quick/items/qquickitemanimation_p_p.h8
-rw-r--r--src/quick/items/qquickitemsmodule.cpp2
-rw-r--r--src/quick/items/qquickitemview.cpp8
-rw-r--r--src/quick/items/qquickitemviewtransition.cpp10
-rw-r--r--src/quick/items/qquickitemviewtransition_p.h4
-rw-r--r--src/quick/items/qquickloader.cpp31
-rw-r--r--src/quick/items/qquickloader_p_p.h1
-rw-r--r--src/quick/items/qquickmousearea.cpp6
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp33
-rw-r--r--src/quick/items/qquickmultipointtoucharea_p.h7
-rw-r--r--src/quick/items/qquickopenglshadereffectnode.cpp5
-rw-r--r--src/quick/items/qquickpincharea.cpp22
-rw-r--r--src/quick/items/qquickscalegrid.cpp2
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp8
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h1
-rw-r--r--src/quick/items/qquickstateoperations.cpp2
-rw-r--r--src/quick/items/qquicktableview.cpp80
-rw-r--r--src/quick/items/qquicktext.cpp36
-rw-r--r--src/quick/items/qquicktext_p.h2
-rw-r--r--src/quick/items/qquicktextedit.cpp18
-rw-r--r--src/quick/items/qquicktextedit_p.h2
-rw-r--r--src/quick/items/qquicktextinput.cpp66
-rw-r--r--src/quick/items/qquicktextinput_p.h2
-rw-r--r--src/quick/items/qquicktextinput_p_p.h2
-rw-r--r--src/quick/items/qquickwindow.cpp40
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h4
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp2
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp86
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.h1
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp2
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h4
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp78
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext.cpp15
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext_p.h1
-rw-r--r--src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp10
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp15
-rw-r--r--src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp16
-rw-r--r--src/quick/scenegraph/qsgrhishadereffectnode.cpp4
-rw-r--r--src/quick/scenegraph/qsgrhishadereffectnode_p.h1
-rw-r--r--src/quick/scenegraph/qsgrhitextureglyphcache.cpp5
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp13
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp3
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext.vert9
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext_core.vert9
-rw-r--r--src/quick/scenegraph/shaders/styledtext.vert7
-rw-r--r--src/quick/scenegraph/shaders/styledtext_core.vert7
-rw-r--r--src/quick/scenegraph/shaders/textmask.vert7
-rw-r--r--src/quick/scenegraph/shaders/textmask_core.vert7
-rw-r--r--src/quick/scenegraph/shaders_ng/24bittextmask.frag5
-rw-r--r--src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsbbin1469 -> 1579 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/32bitcolortext.frag5
-rw-r--r--src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsbbin1344 -> 1436 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask.frag3
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsbbin1351 -> 1433 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask_a.frag3
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsbbin845 -> 926 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.frag5
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsbbin2174 -> 2266 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.vert9
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsbbin2623 -> 2743 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext_a.frag5
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsbbin1437 -> 1528 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.frag3
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.frag.qsbbin1740 -> 1834 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.vert7
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.vert.qsbbin2175 -> 2294 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext_a.frag3
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsbbin1158 -> 1236 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.frag3
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.frag.qsbbin1469 -> 1561 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.vert7
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.vert.qsbbin1933 -> 2047 bytes
-rw-r--r--src/quick/scenegraph/util/qsgplaintexture.cpp2
-rw-r--r--src/quick/util/qquickanimation.cpp16
-rw-r--r--src/quick/util/qquickanimation_p_p.h10
-rw-r--r--src/quick/util/qquickanimator.cpp8
-rw-r--r--src/quick/util/qquickanimator_p_p.h8
-rw-r--r--src/quick/util/qquickanimatorjob.cpp11
-rw-r--r--src/quick/util/qquickanimatorjob_p.h11
-rw-r--r--src/quick/util/qquickpath.cpp7
-rw-r--r--src/quick/util/qquickpropertychanges.cpp35
-rw-r--r--src/quick/util/qquicksmoothedanimation.cpp2
-rw-r--r--src/quick/util/qquickstategroup.cpp9
-rw-r--r--src/quick/util/qquickstyledtext.cpp6
-rw-r--r--src/quick/util/qquicktimeline.cpp5
132 files changed, 1681 insertions, 521 deletions
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index 5e1ae25c38..ae1954ae8d 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -177,6 +177,11 @@ QList<QQuickItem *> QAccessibleQuickItem::childItems() const
return accessibleUnignoredChildren(item());
}
+static bool isTextRole(QAccessible::Role role)
+{
+ return role == QAccessible::EditableText || role == QAccessible::StaticText;
+}
+
QAccessible::State QAccessibleQuickItem::state() const
{
QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(item());
@@ -194,7 +199,7 @@ QAccessible::State QAccessibleQuickItem::state() const
state.offscreen = true;
if ((role() == QAccessible::CheckBox || role() == QAccessible::RadioButton) && object()->property("checked").toBool())
state.checked = true;
- if (item()->activeFocusOnTab() || role() == QAccessible::EditableText)
+ if (item()->activeFocusOnTab() || isTextRole(role()))
state.focusable = true;
if (item()->hasActiveFocus())
state.focused = true;
@@ -216,6 +221,8 @@ QAccessible::Role QAccessibleQuickItem::role() const
if (role == QAccessible::NoRole) {
if (qobject_cast<QQuickText*>(const_cast<QQuickItem *>(item())))
role = QAccessible::StaticText;
+ else if (qobject_cast<QQuickTextInput*>(const_cast<QQuickItem *>(item())))
+ role = QAccessible::EditableText;
else
role = QAccessible::Client;
}
@@ -232,6 +239,7 @@ QStringList QAccessibleQuickItem::actionNames() const
{
QStringList actions;
switch (role()) {
+ case QAccessible::Link:
case QAccessible::PushButton:
actions << QAccessibleActionInterface::pressAction();
break;
diff --git a/src/quick/designer/qquickdesignersupportproperties.cpp b/src/quick/designer/qquickdesignersupportproperties.cpp
index fb6a5fb324..479e77bf68 100644
--- a/src/quick/designer/qquickdesignersupportproperties.cpp
+++ b/src/quick/designer/qquickdesignersupportproperties.cpp
@@ -126,16 +126,15 @@ void QQuickDesignerSupportProperties::getPropertyCache(QObject *object, QQmlEngi
QQmlEnginePrivate::get(engine)->cache(object->metaObject());
}
-QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::propertyNameListForWritableProperties(QObject *object,
+static QQuickDesignerSupport::PropertyNameList propertyNameListForWritableProperties(QObject *object,
const QQuickDesignerSupport::PropertyName &baseName,
- QObjectList *inspectedObjects)
+ QObjectList *inspectedObjects,
+ int depth = 0)
{
QQuickDesignerSupport::PropertyNameList propertyNameList;
- QObjectList localObjectList;
-
- if (inspectedObjects == nullptr)
- inspectedObjects = &localObjectList;
+ if (depth > 2)
+ return propertyNameList;
if (!inspectedObjects->contains(object))
inspectedObjects->append(object);
@@ -150,14 +149,16 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::propert
if (childObject)
propertyNameList.append(propertyNameListForWritableProperties(childObject,
baseName + QQuickDesignerSupport::PropertyName(metaProperty.name())
- + '.', inspectedObjects));
+ + '.', inspectedObjects,
+ depth + 1));
}
} else if (QQmlGadgetPtrWrapper *valueType
= QQmlGadgetPtrWrapper::instance(qmlEngine(object), metaProperty.userType())) {
valueType->setValue(metaProperty.read(object));
propertyNameList.append(propertyNameListForWritableProperties(valueType,
baseName + QQuickDesignerSupport::PropertyName(metaProperty.name())
- + '.', inspectedObjects));
+ + '.', inspectedObjects,
+ depth + 1));
}
if (metaProperty.isReadable() && metaProperty.isWritable()) {
@@ -169,6 +170,12 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::propert
return propertyNameList;
}
+QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::propertyNameListForWritableProperties(QObject *object)
+{
+ QObjectList localObjectList;
+ return ::propertyNameListForWritableProperties(object, {}, &localObjectList);
+}
+
bool QQuickDesignerSupportProperties::isPropertyBlackListed(const QQuickDesignerSupport::PropertyName &propertyName)
{
if (propertyName.contains(".") && propertyName.contains("__"))
@@ -182,7 +189,8 @@ bool QQuickDesignerSupportProperties::isPropertyBlackListed(const QQuickDesigner
QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allPropertyNames(QObject *object,
const QQuickDesignerSupport::PropertyName &baseName,
- QObjectList *inspectedObjects)
+ QObjectList *inspectedObjects,
+ int depth)
{
QQuickDesignerSupport::PropertyNameList propertyNameList;
@@ -191,6 +199,9 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allProp
if (inspectedObjects == nullptr)
inspectedObjects = &localObjectList;
+ if (depth > 2)
+ return propertyNameList;
+
if (!inspectedObjects->contains(object))
inspectedObjects->append(object);
@@ -214,7 +225,8 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allProp
propertyNameList.append(allPropertyNames(childObject,
baseName
+ QQuickDesignerSupport::PropertyName(metaProperty.name())
- + '.', inspectedObjects));
+ + '.', inspectedObjects,
+ depth + 1));
}
} else if (QQmlGadgetPtrWrapper *valueType
= QQmlGadgetPtrWrapper::instance(qmlEngine(object), metaProperty.userType())) {
@@ -223,7 +235,8 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allProp
propertyNameList.append(allPropertyNames(valueType,
baseName
+ QQuickDesignerSupport::PropertyName(metaProperty.name())
- + '.', inspectedObjects));
+ + '.', inspectedObjects,
+ depth + 1));
} else {
addToPropertyNameListIfNotBlackListed(&propertyNameList,
baseName + QQuickDesignerSupport::PropertyName(metaProperty.name()));
diff --git a/src/quick/designer/qquickdesignersupportproperties_p.h b/src/quick/designer/qquickdesignersupportproperties_p.h
index 02e75ea886..5970eca9f1 100644
--- a/src/quick/designer/qquickdesignersupportproperties_p.h
+++ b/src/quick/designer/qquickdesignersupportproperties_p.h
@@ -90,12 +90,11 @@ public:
static void getPropertyCache(QObject *object, QQmlEngine *engine);
static bool isPropertyBlackListed(const QQuickDesignerSupport::PropertyName &propertyName);
- static QQuickDesignerSupport::PropertyNameList propertyNameListForWritableProperties(QObject *object,
- const QQuickDesignerSupport::PropertyName &baseName = QQuickDesignerSupport::PropertyName(),
- QObjectList *inspectedObjects = nullptr);
+ static QQuickDesignerSupport::PropertyNameList propertyNameListForWritableProperties(QObject *object);
static QQuickDesignerSupport::PropertyNameList allPropertyNames(QObject *object,
const QQuickDesignerSupport::PropertyName &baseName = QQuickDesignerSupport::PropertyName(),
- QObjectList *inspectedObjects = nullptr);
+ QObjectList *inspectedObjects = nullptr,
+ int depth = 0);
static bool hasFullImplementedListInterface(const QQmlListReference &list);
};
diff --git a/src/quick/doc/images/containmentMask-circle.gif b/src/quick/doc/images/containmentMask-circle.gif
new file mode 100644
index 0000000000..80abce625f
--- /dev/null
+++ b/src/quick/doc/images/containmentMask-circle.gif
Binary files differ
diff --git a/src/quick/doc/images/containmentMask-shape.gif b/src/quick/doc/images/containmentMask-shape.gif
new file mode 100644
index 0000000000..e7989352eb
--- /dev/null
+++ b/src/quick/doc/images/containmentMask-shape.gif
Binary files differ
diff --git a/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml b/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml
new file mode 100644
index 0000000000..b8a378ddcf
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Rectangle {
+ width: 150; height: 50; radius: 3
+ color: control.hovered ? "goldenrod" : shift.hovered ? "wheat" : "beige"
+
+ HoverHandler {
+ id: control
+ acceptedModifiers: Qt.ControlModifier
+ cursorShape: Qt.PointingHandCursor
+ }
+
+ HoverHandler {
+ id: shift
+ acceptedModifiers: Qt.ShiftModifier
+ cursorShape: Qt.CrossCursor
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml b/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml
new file mode 100644
index 0000000000..6bd6a40b1a
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Rectangle {
+ width: 150; height: 50; radius: 3
+ color: mouse.hovered ? "goldenrod" : stylus.hovered ? "tomato" : "wheat"
+
+ HoverHandler {
+ id: stylus
+ acceptedDevices: PointerDevice.Stylus
+ cursorShape: Qt.CrossCursor
+ }
+
+ HoverHandler {
+ id: mouse
+ acceptedDevices: PointerDevice.Mouse
+ cursorShape: Qt.PointingHandCursor
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml b/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml
new file mode 100644
index 0000000000..5d82158baf
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Rectangle {
+ id: rect
+ width: 150; height: 150
+
+ HoverHandler {
+ id: stylus
+ acceptedPointerTypes: PointerDevice.Pen
+ cursorShape: Qt.CrossCursor
+ }
+
+ HoverHandler {
+ id: eraser
+ acceptedPointerTypes: PointerDevice.Eraser
+ cursorShape: Qt.BlankCursor
+ target: Image {
+ parent: rect
+ source: "images/cursor-eraser.png"
+ visible: eraser.hovered
+ x: eraser.point.position.x
+ y: eraser.point.position.y - 32
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/hoverTapKeyButton.qml b/src/quick/doc/snippets/pointerHandlers/hoverTapKeyButton.qml
new file mode 100644
index 0000000000..1564aa16b5
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/hoverTapKeyButton.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.12
+
+Rectangle {
+ id: button
+ signal clicked
+
+ width: 150; height: 50; radius: 3
+ color: tapHandler.pressed ? "goldenrod" : hoverHandler.hovered ? "wheat" : "beige"
+ border.color: activeFocus ? "brown" : "transparent"
+ focus: true
+
+ HoverHandler {
+ id: hoverHandler
+ }
+
+ TapHandler {
+ id: tapHandler
+ onTapped: button.clicked()
+ }
+
+ Keys.onEnterPressed: button.clicked()
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png b/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png
new file mode 100644
index 0000000000..e5488a89f2
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png
Binary files differ
diff --git a/src/quick/doc/snippets/qml/externaldrag.qml b/src/quick/doc/snippets/qml/externaldrag.qml
index 97a23293ca..5a88be2d4b 100644
--- a/src/quick/doc/snippets/qml/externaldrag.qml
+++ b/src/quick/doc/snippets/qml/externaldrag.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
//![0]
-import QtQuick 2.8
+import QtQuick 2.12
Item {
width: 200; height: 200
@@ -59,7 +59,7 @@ Item {
color: "green"
radius: 5
- Drag.active: dragArea.drag.active
+ Drag.active: dragHandler.active
Drag.dragType: Drag.Automatic
Drag.supportedActions: Qt.CopyAction
Drag.mimeData: {
@@ -72,14 +72,14 @@ Item {
text: "Drag me"
}
- MouseArea {
- id: dragArea
- anchors.fill: parent
-
- drag.target: parent
- onPressed: parent.grabToImage(function(result) {
- parent.Drag.imageSource = result.url
- })
+ DragHandler {
+ id: dragHandler
+ onActiveChanged:
+ if (active) {
+ parent.grabToImage(function(result) {
+ parent.Drag.imageSource = result.url;
+ })
+ }
}
}
}
diff --git a/src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml b/src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml
new file mode 100644
index 0000000000..2d97bcdafa
--- /dev/null
+++ b/src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQml 2.12
+import QtQuick 2.12
+
+//![0]
+Rectangle {
+ id: circle
+ width: 100; height: width
+ radius: width / 2
+ color: tapHandler.pressed ? "tomato" : hoverHandler.hovered ? "darkgray" : "lightgray"
+
+ TapHandler { id: tapHandler }
+ HoverHandler { id: hoverHandler }
+
+ containmentMask: QtObject {
+ property alias radius: circle.radius
+ function contains(point: point) : bool {
+ return (Math.pow(point.x - radius, 2) + Math.pow(point.y - radius, 2)) < Math.pow(radius, 2)
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/qml/item/containmentMask-shape.qml b/src/quick/doc/snippets/qml/item/containmentMask-shape.qml
new file mode 100644
index 0000000000..a3da217e73
--- /dev/null
+++ b/src/quick/doc/snippets/qml/item/containmentMask-shape.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Shapes 1.12
+
+//![0]
+Rectangle {
+ width: 90; height: 100
+ color: hoverHandler.hovered ? "wheat" : "lightgray"
+ containmentMask: shape
+
+ HoverHandler { id: hoverHandler }
+
+ Shape {
+ id: shape
+ containsMode: Shape.FillContains
+
+ ShapePath {
+ fillColor: "lightsteelblue"
+ startX: 10; startY: 20
+ PathArc {
+ x: 10; y: 80
+ radiusX: 40; radiusY: 40
+ useLargeArc: true
+ }
+ PathLine {
+ x: 10; y: 20
+ }
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/src/concepts/input/focus.qdoc b/src/quick/doc/src/concepts/input/focus.qdoc
index 9862489f42..21f5f0e225 100644
--- a/src/quick/doc/src/concepts/input/focus.qdoc
+++ b/src/quick/doc/src/concepts/input/focus.qdoc
@@ -196,7 +196,7 @@ property. As the \l ListView is a focus scope, this doesn't affect the
rest of the application. However, if the \l ListView itself has
active focus this causes the delegate itself to receive active focus.
In this example, the root type of the delegate is also a focus scope,
-which in turn gives active focus to the \c {Text} type that actually performs
+which in turn gives active focus to the \l {TextInput} type that actually performs
the work of handling the \c {Return} key.
All of the QML view classes, such as \l PathView and \l GridView, behave
diff --git a/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc b/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc
index 2ac9860e6f..bf889a9066 100644
--- a/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc
+++ b/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -30,20 +30,21 @@
\title Qt Quick Input Handlers
\brief A module with a set of QML elements that handle events from input devices in a user interface.
- Qt Quick Input Handlers are a set of QML types used to handle events from
- keyboard, touch, mouse, and stylus devices in a UI. In contrast to event-handling
- items, such as \l MouseArea and \l Flickable, input handlers are explicitly non-visual,
- require less memory and are intended to be used in greater numbers: one
- handler instance per aspect of interaction. Each input handler instance
- handles certain events on behalf of its \c parent Item. Thus the visual and
+ Qt Quick Input Handlers are a set of QML types used to handle
+ \l {QInputEvent}{events} from keyboard, touch, mouse, and stylus
+ \l {QInputDevice}{devices} in a UI. In contrast to event-handling
+ items, such as \l MouseArea and \l Flickable, input handlers are explicitly
+ non-visual, require less memory and are intended to be used in greater
+ numbers: one handler instance per aspect of interaction. Each input handler
+ instance handles certain events on behalf of its
+ \l {QQuickPointerHandler::parent()}{parent} Item. Thus the visual and
behavioral concerns are better separated, and the behavior is built up by
finer-grained composition.
- In Qt 5.10, these handlers were introduced in a separate Qt.labs.handlers module.
- Now they are included with Qt Quick since 5.12. The pre-existing
- \l Keys attached property is similar in concept, so we refer to the
- pointing-device-oriented handlers plus \c Keys together as the set of Input Handlers.
- We expect to offer more attached-property use cases in future versions of Qt.
+ The pre-existing \l Keys attached property is similar in concept, so we
+ refer to the pointing-device-oriented handlers plus \c Keys together as the
+ set of Input Handlers. We expect to offer more attached-property use cases
+ in future versions of Qt.
\section1 Input Handlers
@@ -60,7 +61,44 @@
\li Each Item can have unlimited Handlers
\endlist
- \omit TODO actual overview with snippets and stuff \endomit
+ \section1 Handlers Manipulating Items
+
+ Some Handlers add interactivity simply by being declared inside an Item:
+
+ \snippet pointerHandlers/dragHandler.qml 0
+
+ \section1 Handler Properties and Signals
+
+ All Handlers have properties that can be used in bindings, and signals that
+ can be handled to react to input:
+
+ \snippet pointerHandlers/hoverTapKeyButton.qml 0
+
+ \section1 Pointer Grab
+
+ An important concept with Pointer Handlers is the type of grabs that they
+ perform. The only kind of grab an Item can take is the exclusive grab: for
+ example if you call \l QPointerEvent::setExclusiveGrabber(), the following
+ mouse moves and mouse release event will be sent only to that object. (As a
+ workaround to this exclusivity, see \l QQuickItem::setFiltersChildMouseEvents()
+ and \l QQuickItem::childMouseEventFilter().) However Pointer Handlers have
+ an additional mechanism available: the
+ \l {QPointerEvent::addPassiveGrabber()} {passive grab}. Mouse and touch
+ \l {QEventPoint::state()}{press} events are delivered by visiting all the
+ Items in top-down Z order: first each Item's child Handlers, and then the
+ \l {QQuickItem::event()}{Item} itself. At the time a press event is
+ delivered, a Handler can take either a passive or an exclusive grab
+ depending on its needs. If it takes a passive grab, it is guaranteed to
+ receive the updates and the release, even if other Items or Handlers in the
+ scene take any kind of grab, passive or exclusve. Some Handlers (such as
+ PointHandler) can work only with passive grabs; others require exclusive
+ grabs; and others can "lurk" with passive grabs until they detect that a
+ gesture is being performed, and then make the transition from passive to
+ exclusive grab.
+
+ When a grab transition is requested, \l PointerHandler::grabPermissions,
+ \l QQuickItem::keepMouseGrab() and \l QQuickItem::keepTouchGrab() control
+ whether the transition will be allowed.
\section1 Related Information
diff --git a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
index abfff7cc11..8cd51a50c6 100644
--- a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
@@ -52,11 +52,16 @@ options that align with the latest UI design trends. If these UI controls do not
satisfy your application's needs, only then it is recommended to create a
custom control.
+You can use the controls when you design UIs in Qt Design Studio. In addition,
+it provides timeline-based animations, visual effects, layouts, and a
+live-preview for prototyping applications.
\section2 Related Information
\list
\li \l{Qt Quick Controls}
+\li \l{Customizing Qt Quick Controls}
\li \l{Qt Quick}
+\li \l{Qt Design Studio Manual}
\endlist
\omit
@@ -146,7 +151,7 @@ specific file managed by the resource system. For example, if we wanted to give
\li \l{The Qt Resource System}
\endlist
-\section1 Separate UI from Logic
+\section1 Separate UI from Business Logic
One of the key goals that most application developers want to achieve is to
create a maintainable application. One of the ways to achieve this goal is
@@ -162,8 +167,8 @@ reasons why an application's UI should be written in QML:
\li JavaScript can easily be used in QML to respond to events.
\endlist
-Being a strongly typed language, C++ is best suited for an application's logic.
-Typically, such code performs tasks such as complex calculations
+Being a strongly typed language, C++ is best suited for an application's
+business logic. Typically, such code performs tasks such as complex calculations
or data processing, which are faster in C++ than QML.
Qt offers various approaches to integrate QML and C++ code in an application.
@@ -326,6 +331,22 @@ see \l {Choosing the Correct Integration Method Between C++ and QML}.
\li \l{Qt Quick Controls - Chat Tutorial}{Chat application tutorial}
\endlist
+\section1 Using Qt Design Studio
+
+Qt Design Studio uses UI files that have the filename extension \e {.ui.qml}
+to separate the visual parts of the UI from the UI logic you implement in
+\e {.qml} files. You should edit UI files only in the \uicontrol {2D} view in
+Qt Design Studio. If you use some other tool to add code that Qt Design Studio
+does not support, it displays error messages. Fix the errors to enable visual
+editing of the UI files again. Typically, you should move the unsupported code
+to a \e {.qml} file.
+
+\section2 Related Information
+
+\list
+ \li \l{Qt Design Studio: UI Files}
+\endlist
+
\section1 Using Qt Quick Layouts
Qt offers Qt Quick Layouts to arrange Qt Quick items visually in a layout.
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index 528444cad3..65de1284a4 100644
--- a/src/quick/doc/src/qmltypereference.qdoc
+++ b/src/quick/doc/src/qmltypereference.qdoc
@@ -740,6 +740,73 @@ console.log(c + " " + d); // false true
\li Example
\row
+ \li translate(vector3d vector)
+ \li Multiplies \c this matrix4x4 by another that translates coordinates by the components
+ of \c vector
+ \li \code
+var m = Qt.matrix4x4();
+m.translate(Qt.vector3d(1,2,3));
+console.log(m.toString());
+// QMatrix4x4(1, 0, 0, 1, 0, 1, 0, 2, 0, 0, 1, 3, 0, 0, 0, 1)
+ \endcode
+
+ \row
+ \li rotate(real angle, vector3d axis)
+ \li Multiples \c this matrix4x4 by another that rotates coordinates through
+ \c angle degrees about \c axis
+ \li \code
+var m = Qt.matrix4x4();
+m.rotate(180,vector3d(1,0,0));
+console.log(m.toString());
+// QMatrix4x4(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1)
+ \endcode
+
+ \row
+ \li scale(real factor)
+ \li Multiplies \c this matrix4x4 by another that scales coordinates by the given \c factor
+ \li \code
+var m = Qt.matrix4x4();
+m.scale(2);
+console.log(m.toString());
+// QMatrix4x4(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1)
+ \endcode
+
+ \row
+ \li scale(real x, real y, real z)
+ \li Multiplies \c this matrix4x4 by another that scales coordinates by the components
+ \c x, \c y, and \c z
+ \li \code
+var m = Qt.matrix4x4();
+m.scale(1,2,3);
+console.log(m.toString());
+// QMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1)
+ \endcode
+
+ \row
+ \li scale(vector3d vector)
+ \li Multiplies \c this matrix4x4 by another that scales coordinates by the components
+ of \c vector
+ \li \code
+var m = Qt.matrix4x4();
+m.scale(Qt.vector3d(1,2,3));
+console.log(m.toString());
+// QMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1)
+ \endcode
+
+ \row
+ \li lookAt(vector3d eye, vector3d center, vector3d up)
+ \li Multiplies \c this matrix4x4 by a viewing matrix derived from an \c eye point.
+ The \c center vector3d indicates the center of the view that the \c eye is looking at.
+ The \c up vector3d indicates which direction should be considered up with respect to
+ the \c eye.
+ \li \code
+var m = Qt.matrix4x4();
+m.lookAt(Qt.vector3d(1,2,3),Qt.vector3d(1,2,0),Qt.vector3d(0,1,0));
+console.log(m.toString());
+// QMatrix4x4(1, 0, 0, -1, 0, 1, 0, -2, 0, 0, 1, -3, 0, 0, 0, 1)
+ \endcode
+
+ \row
\li matrix4x4 times(matrix4x4 other)
\li Returns the matrix4x4 result of multiplying \c this matrix4x4 with
the \c other matrix4x4
diff --git a/src/quick/handlers/qquickdragaxis.cpp b/src/quick/handlers/qquickdragaxis.cpp
index 88470c8a7d..806b5d705a 100644
--- a/src/quick/handlers/qquickdragaxis.cpp
+++ b/src/quick/handlers/qquickdragaxis.cpp
@@ -76,3 +76,5 @@ void QQuickDragAxis::setEnabled(bool enabled)
}
QT_END_NAMESPACE
+
+#include "moc_qquickdragaxis_p.cpp"
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp
index 492897b68b..b9a2c183c2 100644
--- a/src/quick/handlers/qquickdraghandler.cpp
+++ b/src/quick/handlers/qquickdraghandler.cpp
@@ -343,3 +343,5 @@ void QQuickDragHandler::setTranslation(const QVector2D &trans)
*/
QT_END_NAMESPACE
+
+#include "moc_qquickdraghandler_p.cpp"
diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp
index 72efdfd0f4..7103206470 100644
--- a/src/quick/handlers/qquickhandlerpoint.cpp
+++ b/src/quick/handlers/qquickhandlerpoint.cpp
@@ -348,3 +348,5 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
*/
QT_END_NAMESPACE
+
+#include "moc_qquickhandlerpoint_p.cpp"
diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp
index b12d85784a..a65730607a 100644
--- a/src/quick/handlers/qquickhoverhandler.cpp
+++ b/src/quick/handlers/qquickhoverhandler.cpp
@@ -85,8 +85,11 @@ QQuickHoverHandler::~QQuickHoverHandler()
void QQuickHoverHandler::componentComplete()
{
- parentItem()->setAcceptHoverEvents(true);
- QQuickItemPrivate::get(parentItem())->setHasHoverInChild(true);
+ QQuickSinglePointHandler::componentComplete();
+ if (auto par = parentItem()) {
+ par->setAcceptHoverEvents(true);
+ QQuickItemPrivate::get(par)->setHasHoverInChild(true);
+ }
}
bool QQuickHoverHandler::wantsPointerEvent(QQuickPointerEvent *event)
@@ -124,6 +127,13 @@ void QQuickHoverHandler::handleEventPoint(QQuickEventPoint *point)
setPassiveGrab(point);
}
+void QQuickHoverHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point)
+{
+ QQuickSinglePointHandler::onGrabChanged(grabber, transition, point);
+ if (grabber == this && transition == QQuickEventPoint::CancelGrabPassive)
+ setHovered(false);
+}
+
/*!
\qmlproperty bool QtQuick::HoverHandler::hovered
\readonly
@@ -144,6 +154,98 @@ void QQuickHoverHandler::setHovered(bool hovered)
}
/*!
+ \internal
+ \qmlproperty flags QtQuick::HoverHandler::acceptedButtons
+
+ This property is not used in HoverHandler.
+*/
+
+/*!
+ \qmlproperty flags QtQuick::HoverHandler::acceptedDevices
+
+ The types of pointing devices that can activate the pointer handler.
+
+ By default, this property is set to
+ \l{QInputDevice::DeviceType}{PointerDevice.AllDevices}.
+ If you set it to an OR combination of device types, it will ignore pointer
+ events from the non-matching devices.
+
+ For example, an item could be made to respond to mouse hover in one way,
+ and stylus hover in another way, with two handlers:
+
+ \snippet pointerHandlers/hoverMouseOrStylus.qml 0
+
+ The available device types are as follows:
+
+ \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.
+ \value PointerDevice.AllDevices Any type of pointing device.
+
+ \sa QInputDevice::DeviceType
+*/
+
+/*!
+ \qmlproperty flags QtQuick::HoverHandler::acceptedPointerTypes
+
+ The types of pointing instruments (generic, stylus, eraser, and so on)
+ that can activate the pointer handler.
+
+ By default, this property is set to
+ \l {QPointingDevice::PointerType} {PointerDevice.AllPointerTypes}.
+ If you set it to an OR combination of device types, it will ignore events
+ from non-matching events.
+
+ For example, you could provide feedback by changing the cursor depending on
+ whether a stylus or eraser is hovering over a graphics tablet:
+
+ \snippet pointerHandlers/hoverStylusOrEraser.qml 0
+
+ The available pointer types are as follows:
+
+ \value PointerDevice.Generic A mouse or a device that emulates a mouse.
+ \value PointerDevice.Finger A finger on a touchscreen (hover detection is unlikely).
+ \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.
+ \value PointerDevice.AllPointerTypes Any type of pointing device.
+
+ \sa QPointingDevice::PointerType
+*/
+
+/*!
+ \qmlproperty flags QtQuick::HoverHandler::acceptedModifiers
+
+ If this property is set, a hover event is handled only if the given keyboard
+ modifiers are pressed. The event is ignored without the modifiers.
+
+ This property is set to \c Qt.KeyboardModifierMask by default, resulting
+ in handling hover events regardless of any modifier keys.
+
+ For example, an \l[QML]{Item} could have two handlers of the same type, one
+ of which is enabled only if the required keyboard modifiers are pressed:
+
+ \snippet pointerHandlers/hoverModifiers.qml 0
+
+ The available modifiers are as follows:
+
+ \value Qt.NoModifier No modifier key is allowed.
+ \value Qt.ShiftModifier A Shift key on the keyboard must be pressed.
+ \value Qt.ControlModifier A Ctrl key on the keyboard must be pressed.
+ \value Qt.AltModifier An Alt key on the keyboard must be pressed.
+ \value Qt.MetaModifier A Meta key on the keyboard must be pressed.
+ \value Qt.KeypadModifier A keypad button must be pressed.
+ \value Qt.GroupSwitchModifier A Mode_switch key on the keyboard must be pressed.
+ X11 only (unless activated on Windows by a command line argument).
+ \value Qt.KeyboardModifierMask The handler ignores modifier keys.
+
+ \sa Qt::KeyboardModifier
+*/
+
+/*!
\since 5.15
\qmlproperty Qt::CursorShape QtQuick::HoverHandler::cursorShape
This property holds the cursor shape that will appear whenever
@@ -192,3 +294,5 @@ void QQuickHoverHandler::setHovered(bool hovered)
*/
QT_END_NAMESPACE
+
+#include "moc_qquickhoverhandler_p.cpp"
diff --git a/src/quick/handlers/qquickhoverhandler_p.h b/src/quick/handlers/qquickhoverhandler_p.h
index 313b87217c..426372d162 100644
--- a/src/quick/handlers/qquickhoverhandler_p.h
+++ b/src/quick/handlers/qquickhoverhandler_p.h
@@ -78,6 +78,7 @@ protected:
void componentComplete() override;
bool wantsPointerEvent(QQuickPointerEvent *event) override;
void handleEventPoint(QQuickEventPoint *point) override;
+ void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) override;
private:
void setHovered(bool hovered);
diff --git a/src/quick/handlers/qquickmultipointhandler.cpp b/src/quick/handlers/qquickmultipointhandler.cpp
index f404788de4..443cf4ffbc 100644
--- a/src/quick/handlers/qquickmultipointhandler.cpp
+++ b/src/quick/handlers/qquickmultipointhandler.cpp
@@ -146,7 +146,7 @@ void QQuickMultiPointHandler::onActiveChanged()
}
}
-void QQuickMultiPointHandler::onGrabChanged(QQuickPointerHandler *, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *)
+void QQuickMultiPointHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point)
{
Q_D(QQuickMultiPointHandler);
// If another handler or item takes over this set of points, assume it has
@@ -155,6 +155,20 @@ void QQuickMultiPointHandler::onGrabChanged(QQuickPointerHandler *, QQuickEventP
// (e.g. between DragHandler and PinchHandler).
if (transition == QQuickEventPoint::UngrabExclusive || transition == QQuickEventPoint::CancelGrabExclusive)
d->currentPoints.clear();
+ if (grabber != this)
+ return;
+ switch (transition) {
+ case QQuickEventPoint::GrabExclusive:
+ case QQuickEventPoint::GrabPassive:
+ case QQuickEventPoint::UngrabPassive:
+ case QQuickEventPoint::UngrabExclusive:
+ case QQuickEventPoint::CancelGrabPassive:
+ case QQuickEventPoint::CancelGrabExclusive:
+ QQuickPointerHandler::onGrabChanged(grabber, transition, point);
+ break;
+ case QQuickEventPoint::OverrideGrabPassive:
+ return; // don't emit
+ }
}
QVector<QQuickEventPoint *> QQuickMultiPointHandler::eligiblePoints(QQuickPointerEvent *event)
@@ -422,3 +436,5 @@ QMetaProperty &QQuickMultiPointHandlerPrivate::yMetaProperty() const
}
QT_END_NAMESPACE
+
+#include "moc_qquickmultipointhandler_p.cpp"
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index 5b30d08557..16cf2c8100 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -85,7 +85,14 @@ Q_LOGGING_CATEGORY(lcPinchHandler, "qt.quick.handler.pinch")
\image touchpoints-pinchhandler.png
- \sa PinchArea
+ \note The pinch begins when the number of fingers pressed is between
+ \l {MultiPointHandler::minimumPointCount}{minimumPointCount} and
+ \l {MultiPointHandler::maximumPointCount}{maximumPointCount}, inclusive.
+ Until then, PinchHandler tracks the positions of any pressed fingers,
+ but if it's a disallowed number, it does not scale or rotate
+ its \l target, and the \l active property remains \c false.
+
+ \sa PinchArea, QPointerEvent::pointCount()
*/
QQuickPinchHandler::QQuickPinchHandler(QQuickItem *parent)
@@ -249,19 +256,12 @@ bool QQuickPinchHandler::wantsPointerEvent(QQuickPointerEvent *event)
*/
/*!
- \qmlproperty int QtQuick::PinchHandler::minimumTouchPoints
-
- The pinch begins when this number of fingers are pressed.
- Until then, PinchHandler tracks the positions of any pressed fingers,
- but if it's an insufficient number, it does not scale or rotate
- its \l target, and the \l active property will remain false.
-*/
-
-/*!
\qmlproperty bool QtQuick::PinchHandler::active
- This property is true when all the constraints (epecially \l minimumTouchPoints)
- are satisfied and the \l target, if any, is being manipulated.
+ This property is \c true when all the constraints (epecially
+ \l {MultiPointHandler::minimumPointCount}{minimumPointCount} and
+ \l {MultiPointHandler::maximumPointCount}{maximumPointCount}) are satisfied
+ and the \l target, if any, is being manipulated.
*/
void QQuickPinchHandler::onActiveChanged()
@@ -543,6 +543,11 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
The translation of the gesture \l centroid. It is \c (0, 0) when the
gesture begins.
+
+ \note On some touchpads, such as on a \macos trackpad, native gestures do
+ not generate any translation values, and this property stays at \c (0, 0).
*/
QT_END_NAMESPACE
+
+#include "moc_qquickpinchhandler_p.cpp"
diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp
index 90f31bf9fd..b7f0580648 100644
--- a/src/quick/handlers/qquickpointerdevicehandler.cpp
+++ b/src/quick/handlers/qquickpointerdevicehandler.cpp
@@ -314,3 +314,5 @@ bool QQuickPointerDeviceHandler::wantsPointerEvent(QQuickPointerEvent *event)
}
QT_END_NAMESPACE
+
+#include "moc_qquickpointerdevicehandler_p.cpp"
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
index adb753e000..67700e04fa 100644
--- a/src/quick/handlers/qquickpointerhandler.cpp
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -207,9 +207,11 @@ void QQuickPointerHandler::setCursorShape(Qt::CursorShape shape)
return;
d->cursorShape = shape;
d->cursorSet = true;
- QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parentItem());
- itemPriv->hasCursorHandler = true;
- itemPriv->setHasCursorInChild(true);
+ if (auto *par = qmlobject_cast<QQuickItem *>(parent())) {
+ QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(par);
+ itemPriv->hasCursorHandler = true;
+ itemPriv->setHasCursorInChild(true);
+ }
emit cursorShapeChanged();
}
@@ -220,9 +222,11 @@ void QQuickPointerHandler::resetCursorShape()
return;
d->cursorShape = Qt::ArrowCursor;
d->cursorSet = false;
- QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parentItem());
- itemPriv->hasCursorHandler = false;
- itemPriv->setHasCursorInChild(itemPriv->hasCursor);
+ if (auto *parent = parentItem()) {
+ QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent);
+ itemPriv->hasCursorHandler = false;
+ itemPriv->setHasCursorInChild(itemPriv->hasCursor);
+ }
emit cursorShapeChanged();
}
@@ -346,10 +350,16 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec
existingPhGrabber->metaObject()->className() == metaObject()->className())
allowed = true;
} else if ((d->grabPermissions & CanTakeOverFromItems)) {
+ allowed = true;
QQuickItem * existingItemGrabber = point->grabberItem();
- if (existingItemGrabber && !((existingItemGrabber->keepMouseGrab() && point->pointerEvent()->asPointerMouseEvent()) ||
- (existingItemGrabber->keepTouchGrab() && point->pointerEvent()->asPointerTouchEvent()))) {
- allowed = true;
+ QQuickWindowPrivate *winPriv = QQuickWindowPrivate::get(parentItem()->window());
+ const bool isMouse = point->pointerEvent()->asPointerMouseEvent();
+ const bool isTouch = point->pointerEvent()->asPointerTouchEvent();
+ if (existingItemGrabber &&
+ ((existingItemGrabber->keepMouseGrab() &&
+ (isMouse || winPriv->isDeliveringTouchAsMouse())) ||
+ (existingItemGrabber->keepTouchGrab() && isTouch))) {
+ allowed = false;
// If the handler wants to steal the exclusive grab from an Item, the Item can usually veto
// by having its keepMouseGrab flag set. But an exception is if that Item is a parent that
// normally filters events (such as a Flickable): it needs to be possible for e.g. a
@@ -358,14 +368,19 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec
// at first and then expects to be able to steal the grab later on. It cannot respect
// Flickable's wishes in that case, because then it would never have a chance.
if (existingItemGrabber->keepMouseGrab() &&
- !(existingItemGrabber->filtersChildMouseEvents() && existingItemGrabber->isAncestorOf(parentItem()))) {
- QQuickWindowPrivate *winPriv = QQuickWindowPrivate::get(parentItem()->window());
+ existingItemGrabber->filtersChildMouseEvents() && existingItemGrabber->isAncestorOf(parentItem())) {
if (winPriv->isDeliveringTouchAsMouse() && point->pointId() == winPriv->touchMouseId) {
- qCDebug(lcPointerHandlerGrab) << this << "wants to grab touchpoint" << point->pointId()
- << "but declines to steal grab from touch-mouse grabber with keepMouseGrab=true" << existingItemGrabber;
- allowed = false;
+ qCDebug(lcPointerHandlerGrab) << this << "steals touchpoint" << point->pointId()
+ << "despite parent touch-mouse grabber with keepMouseGrab=true" << existingItemGrabber;
+ allowed = true;
}
}
+ if (!allowed) {
+ qCDebug(lcPointerHandlerGrab) << this << "wants to grab point" << point->pointId()
+ << "but declines to steal from grabber" << existingItemGrabber
+ << "with keepMouseGrab=" << existingItemGrabber->keepMouseGrab()
+ << "keepTouchGrab=" << existingItemGrabber->keepTouchGrab();
+ }
}
}
}
@@ -406,6 +421,8 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec
This handler can take the exclusive grab from another handler of the same class.
\value PointerHandler.CanTakeOverFromHandlersOfDifferentType
This handler can take the exclusive grab from any kind of handler.
+ \value PointerHandler.CanTakeOverFromItems
+ This handler can take the exclusive grab from any type of Item.
\value PointerHandler.CanTakeOverFromAnything
This handler can take the exclusive grab from any type of Item or Handler.
\value PointerHandler.ApprovesTakeOverByHandlersOfSameType
@@ -446,6 +463,14 @@ void QQuickPointerHandler::classBegin()
void QQuickPointerHandler::componentComplete()
{
+ Q_D(const QQuickPointerHandler);
+ if (d->cursorSet) {
+ if (auto *parent = parentItem()) {
+ QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent);
+ itemPriv->hasCursorHandler = true;
+ itemPriv->setHasCursorInChild(true);
+ }
+ }
}
QQuickPointerEvent *QQuickPointerHandler::currentEvent()
@@ -503,8 +528,11 @@ bool QQuickPointerHandler::parentContains(const QQuickEventPoint *point) const
return false;
if (QQuickItem *par = parentItem()) {
if (par->window()) {
+ QRect windowGeometry = par->window()->geometry();
+ if (!par->window()->isTopLevel())
+ windowGeometry = QRect(QWindowPrivate::get(par->window())->globalPosition(), par->window()->size());
QPoint screenPosition = par->window()->mapToGlobal(point->scenePosition().toPoint());
- if (!par->window()->geometry().contains(screenPosition))
+ if (!windowGeometry.contains(screenPosition))
return false;
}
QPointF p = par->mapFromScene(point->scenePosition());
@@ -716,3 +744,5 @@ bool QQuickPointerHandlerPrivate::dragOverThreshold(const QQuickEventPoint *poin
}
QT_END_NAMESPACE
+
+#include "moc_qquickpointerhandler_p.cpp"
diff --git a/src/quick/handlers/qquickpointhandler.cpp b/src/quick/handlers/qquickpointhandler.cpp
index 30f62332ba..6b7b70f17a 100644
--- a/src/quick/handlers/qquickpointhandler.cpp
+++ b/src/quick/handlers/qquickpointhandler.cpp
@@ -163,3 +163,5 @@ QVector2D QQuickPointHandler::translation() const
}
QT_END_NAMESPACE
+
+#include "moc_qquickpointhandler_p.cpp"
diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp
index b51f53b74f..d785d8c0ca 100644
--- a/src/quick/handlers/qquicksinglepointhandler.cpp
+++ b/src/quick/handlers/qquicksinglepointhandler.cpp
@@ -218,3 +218,5 @@ void QQuickSinglePointHandlerPrivate::reset()
}
QT_END_NAMESPACE
+
+#include "moc_qquicksinglepointhandler_p.cpp"
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index f3674d6fa9..b722cf7538 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -209,6 +209,8 @@ void QQuickTapHandler::timerEvent(QTimerEvent *event)
If the spatial constraint is violated, \l pressed transitions immediately
from true to false, regardless of the time held.
+ The \c gesturePolicy also affects grab behavior as described below.
+
\value TapHandler.DragThreshold
(the default value) The event point must not move significantly.
If the mouse, finger or stylus moves past the system-wide drag
@@ -217,11 +219,13 @@ void QQuickTapHandler::timerEvent(QTimerEvent *event)
can be useful whenever TapHandler needs to cooperate with other
input handlers (for example \l DragHandler) or event-handling Items
(for example QtQuick Controls), because in this case TapHandler
- will not take the exclusive grab, but merely a passive grab.
+ will not take the exclusive grab, but merely a
+ \l {QPointerEvent::addPassiveGrabber()}{passive grab}.
\value TapHandler.WithinBounds
If the event point leaves the bounds of the \c parent Item, the tap
- gesture is canceled. The TapHandler will take the exclusive grab on
+ gesture is canceled. The TapHandler will take the
+ \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on
press, but will release the grab as soon as the boundary constraint
is no longer satisfied.
@@ -232,8 +236,9 @@ void QQuickTapHandler::timerEvent(QTimerEvent *event)
typical behavior for button widgets: you can cancel a click by
dragging outside the button, and you can also change your mind by
dragging back inside the button before release. Note that it's
- necessary for TapHandler take the exclusive grab on press and retain
- it until release in order to detect this gesture.
+ necessary for TapHandler to take the
+ \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on press
+ and retain it until release in order to detect this gesture.
*/
void QQuickTapHandler::setGesturePolicy(QQuickTapHandler::GesturePolicy gesturePolicy)
{
@@ -426,3 +431,5 @@ void QQuickTapHandler::updateTimeHeld()
from the previous \c tapCount.
*/
QT_END_NAMESPACE
+
+#include "moc_qquicktaphandler_p.cpp"
diff --git a/src/quick/handlers/qquickwheelhandler.cpp b/src/quick/handlers/qquickwheelhandler.cpp
index 16f38af962..7e48d67b8b 100644
--- a/src/quick/handlers/qquickwheelhandler.cpp
+++ b/src/quick/handlers/qquickwheelhandler.cpp
@@ -527,3 +527,5 @@ QMetaProperty &QQuickWheelHandlerPrivate::targetMetaProperty() const
}
QT_END_NAMESPACE
+
+#include "moc_qquickwheelhandler_p.cpp"
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 14fa07099f..28c62bd4f2 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -3892,16 +3892,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
@@ -3911,16 +3911,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());
@@ -3928,20 +3928,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 b5626dec0c..a00689f694 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -241,7 +241,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/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index 55ebbe907c..1d047e3c2f 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -375,7 +375,10 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
}
state.lineDash = pattern;
QPen nPen = p->pen();
- nPen.setDashPattern(pattern);
+ if (count > 0)
+ nPen.setDashPattern(pattern);
+ else
+ nPen.setStyle(Qt::SolidLine);
p->setPen(nPen);
break;
}
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index 0ebd1a66c9..3f28620d90 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -165,8 +165,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 67d17c98e5..70dcaa2acf 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -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/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index f239f24367..8818bc5608 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/qquickdroparea.cpp b/src/quick/items/qquickdroparea.cpp
index d90ee209d6..e503cd7815 100644
--- a/src/quick/items/qquickdroparea.cpp
+++ b/src/quick/items/qquickdroparea.cpp
@@ -91,6 +91,7 @@ QQuickDropAreaPrivate::~QQuickDropAreaPrivate()
/*!
\qmltype DropArea
\instantiates QQuickDropArea
+ \inherits Item
\inqmlmodule QtQuick
\ingroup qtquick-input
\brief For specifying drag and drop handling in an area.
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 950afaed52..ac962f6f61 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -712,6 +712,8 @@ QQuickPointerDevice *QQuickPointerDevice::tabletDevice(const QTabletEvent *event
switch (event->pointerType()) {
case QTabletEvent::Pen:
ptype = Pen;
+ if (type == QQuickPointerDevice::UnknownDevice)
+ type = QQuickPointerDevice::Stylus;
break;
case QTabletEvent::Eraser:
ptype = Eraser;
@@ -813,7 +815,7 @@ QQuickPointerDevice *QQuickPointerDevice::tabletDevice(const QTabletEvent *event
\readonly
\qmlproperty int QtQuick::EventPoint::pointId
- This property holds the ID of the event, if any.
+ This property holds the ID of the point, if any.
Touchpoints have automatically-incrementing IDs: each time the user
presses a finger against the touchscreen, it will be a larger number.
@@ -826,12 +828,8 @@ QQuickPointerDevice *QQuickPointerDevice::tabletDevice(const QTabletEvent *event
\readonly
\qmlproperty bool QtQuick::EventPoint::accepted
- Setting \a accepted to true prevents the event from being propagated to
- Items below the PointerHandler's Item.
-
- Generally, if the handler acts on the mouse event, then it should be
- accepted so that items lower in the stacking order do not also respond to
- the same event.
+ Indicates whether this point has been accepted during delivery thus far.
+ This flag cannot be usefully set from QML.
*/
/*!
@@ -2276,3 +2274,5 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *eve
#endif
QT_END_NAMESPACE
+
+#include "moc_qquickevents_p_p.cpp"
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 9a68be4c49..2634b68248 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -62,6 +62,8 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcHandlerParent)
+Q_LOGGING_CATEGORY(lcVel, "qt.quick.flickable.velocity")
+Q_LOGGING_CATEGORY(lcWheel, "qt.quick.flickable.wheel")
// FlickThreshold determines how far the "mouse" must have moved
// before we perform a flick.
@@ -263,7 +265,8 @@ QQuickFlickablePrivate::QQuickFlickablePrivate()
, deceleration(QML_FLICK_DEFAULTDECELERATION)
, maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100)
, delayedPressEvent(nullptr), pressDelay(0), fixupDuration(400)
- , flickBoost(1.0), fixupMode(Normal), vTime(0), visibleArea(nullptr)
+ , flickBoost(1.0), initialWheelFlickDistance(qApp->styleHints()->wheelScrollLines() * 24)
+ , fixupMode(Normal), vTime(0), visibleArea(nullptr)
, flickableDirection(QQuickFlickable::AutoFlickDirection)
, boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
, boundsMovement(QQuickFlickable::FollowBoundsBehavior)
@@ -323,7 +326,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) {
@@ -332,8 +335,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,10 +540,14 @@ void QQuickFlickablePrivate::updateBeginningEnd()
if (atBeginning != vData.atBeginning) {
vData.atBeginning = atBeginning;
atYBeginningChange = true;
+ if (!vData.moving && atBeginning)
+ vData.smoothVelocity.setValue(0);
}
if (atEnd != vData.atEnd) {
vData.atEnd = atEnd;
atYEndChange = true;
+ if (!vData.moving && atEnd)
+ vData.smoothVelocity.setValue(0);
}
// Horizontal
@@ -547,10 +560,14 @@ void QQuickFlickablePrivate::updateBeginningEnd()
if (atBeginning != hData.atBeginning) {
hData.atBeginning = atBeginning;
atXBeginningChange = true;
+ if (!hData.moving && atBeginning)
+ hData.smoothVelocity.setValue(0);
}
if (atEnd != hData.atEnd) {
hData.atEnd = atEnd;
atXEndChange = true;
+ if (!hData.moving && atEnd)
+ hData.smoothVelocity.setValue(0);
}
if (vData.extentsChanged) {
@@ -785,8 +802,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
@@ -803,8 +823,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;
+ }
}
/*!
@@ -1489,6 +1512,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
d->hData.velocity = 0;
d->timer.start();
d->maybeBeginDrag(currentTimestamp, event->position());
+ d->lastPosTime = -1;
break;
case Qt::NoScrollPhase: // default phase with an ordinary wheel mouse
case Qt::ScrollUpdate:
@@ -1515,20 +1539,34 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
return;
}
+ qreal elapsed = qreal(currentTimestamp - d->lastPosTime) / qreal(1000);
+ if (elapsed <= 0) {
+ d->lastPosTime = currentTimestamp;
+ qCDebug(lcWheel) << "insufficient elapsed time: can't calculate velocity" << elapsed;
+ return;
+ }
+
if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull()) {
- // physical mouse wheel, so use angleDelta
+ // no pixel delta (physical mouse wheel, or "dumb" touchpad), so use angleDelta
int xDelta = event->angleDelta().x();
int yDelta = event->angleDelta().y();
+ // For a single "clicky" wheel event (angleDelta +/- 120),
+ // we want flick() to end up moving a distance proportional to QStyleHints::wheelScrollLines().
+ // The decel algo from there is
+ // qreal dist = v2 / (accel * 2.0);
+ // i.e. initialWheelFlickDistance = (120 / dt)^2 / (deceleration * 2)
+ // now solve for dt:
+ // dt = 120 / sqrt(deceleration * 2 * initialWheelFlickDistance)
+ if (!isMoving())
+ elapsed = 120 / qSqrt(d->deceleration * 2 * d->initialWheelFlickDistance);
if (yflick() && yDelta != 0) {
- bool valid = false;
- if (yDelta > 0 && contentY() > -minYExtent()) {
- d->vData.velocity = qMax(yDelta*2 - d->vData.smoothVelocity.value(), qreal(d->maxVelocity/4));
- valid = true;
- } else if (yDelta < 0 && contentY() < -maxYExtent()) {
- d->vData.velocity = qMin(yDelta*2 - d->vData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
- valid = true;
- }
- if (valid) {
+ qreal instVelocity = yDelta / elapsed;
+ // if the direction has changed, start over with filtering, to allow instant movement in the opposite direction
+ if ((instVelocity < 0 && d->vData.velocity > 0) || (instVelocity > 0 && d->vData.velocity < 0))
+ d->vData.velocityBuffer.clear();
+ 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) {
@@ -1539,15 +1577,13 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
}
}
if (xflick() && xDelta != 0) {
- bool valid = false;
- if (xDelta > 0 && contentX() > -minXExtent()) {
- d->hData.velocity = qMax(xDelta*2 - d->hData.smoothVelocity.value(), qreal(d->maxVelocity/4));
- valid = true;
- } else if (xDelta < 0 && contentX() < -maxXExtent()) {
- d->hData.velocity = qMin(xDelta*2 - d->hData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
- valid = true;
- }
- if (valid) {
+ qreal instVelocity = xDelta / elapsed;
+ // if the direction has changed, start over with filtering, to allow instant movement in the opposite direction
+ if ((instVelocity < 0 && d->hData.velocity > 0) || (instVelocity > 0 && d->hData.velocity < 0))
+ d->hData.velocityBuffer.clear();
+ 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) {
@@ -1562,18 +1598,13 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
int xDelta = event->pixelDelta().x();
int yDelta = event->pixelDelta().y();
- qreal elapsed = qreal(currentTimestamp - d->lastPosTime) / 1000.;
- if (elapsed <= 0) {
- d->lastPosTime = currentTimestamp;
- return;
- }
QVector2D velocity(xDelta / elapsed, yDelta / elapsed);
- d->lastPosTime = currentTimestamp;
d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta());
d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta,
true, !d->scrollingPhase, true, velocity);
event->accept();
}
+ d->lastPosTime = currentTimestamp;
if (!event->isAccepted())
QQuickItem::wheelEvent(event);
@@ -1744,6 +1775,10 @@ void QQuickFlickable::componentComplete()
setContentX(-minXExtent());
if (!d->vData.explicitValue && d->vData.startMargin != 0.)
setContentY(-minYExtent());
+ if (lcWheel().isDebugEnabled() || lcVel().isDebugEnabled()) {
+ d->timeline.setObjectName(QLatin1String("timeline for Flickable ") + objectName());
+ d->velocityTimeline.setObjectName(QLatin1String("velocity timeline for Flickable ") + objectName());
+ }
}
void QQuickFlickable::viewportMoved(Qt::Orientations orient)
@@ -2445,7 +2480,20 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event)
bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
{
Q_D(QQuickFlickable);
- if (!isVisible() || !isEnabled() || !isInteractive() || !d->wantsPointerEvent(e)) {
+ auto wantsPointerEvent_helper = [=]() {
+ bool wants = true;
+ if (e->type() >= QEvent::MouseButtonPress && e->type() <= QEvent::MouseMove) {
+ QMouseEvent *me = static_cast<QMouseEvent*>(e);
+ QPointF itemLocalPos = me->localPos();
+ me->setLocalPos(mapFromItem(i, itemLocalPos));
+ wants = d->wantsPointerEvent(e);
+ // re-localize event back to \a i before returning
+ me->setLocalPos(itemLocalPos);
+ }
+ return wants;
+ };
+
+ if (!isVisible() || !isEnabled() || !isInteractive() || !wantsPointerEvent_helper()) {
d->cancelInteraction();
return QQuickItem::childMouseEventFilter(i, e);
}
@@ -2491,9 +2539,23 @@ void QQuickFlickable::setMaximumFlickVelocity(qreal v)
/*!
\qmlproperty real QtQuick::Flickable::flickDeceleration
- This property holds the rate at which a flick will decelerate.
-
- The default value is platform dependent.
+ This property holds the rate at which a flick will decelerate:
+ the higher the number, the faster it slows down when the user stops
+ flicking via touch, touchpad or mouse wheel. For example 0.0001 is nearly
+ "frictionless", and 10000 feels quite "sticky".
+
+ The default value is platform dependent. Values of zero or less are not allowed.
+
+ \note For touchpad flicking, some platforms drive Flickable directly by
+ sending QWheelEvents with QWheelEvent::phase() being \c Qt::ScrollMomentum,
+ after the user has released all fingers from the touchpad. In that case,
+ the operating system is controlling the deceleration, and this property has
+ no effect.
+
+ \note For mouse wheel scrolling, and for gesture scrolling on touchpads
+ that do not have a momentum phase, extremely large values of
+ flickDeceleration can make Flickable very resistant to scrolling,
+ especially if \l maximumFlickVelocity is too small.
*/
qreal QQuickFlickable::flickDeceleration() const
{
@@ -2506,7 +2568,7 @@ void QQuickFlickable::setFlickDeceleration(qreal deceleration)
Q_D(QQuickFlickable);
if (deceleration == d->deceleration)
return;
- d->deceleration = deceleration;
+ d->deceleration = qMax(0.001, deceleration);
emit flickDecelerationChanged();
}
@@ -2716,6 +2778,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
}
}
@@ -2760,6 +2828,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) {
@@ -2887,4 +2961,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 414c9c33d6..aef15e150a 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -109,6 +109,7 @@ public:
, fixingUp(false), inOvershoot(false), inRebound(false), moving(false), flicking(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() {
@@ -169,7 +171,8 @@ public:
bool explicitValue : 1;
mutable bool minExtentDirty : 1;
mutable bool maxExtentDirty : 1;
- uint unused : 19;
+ bool contentPositionChangedExternallyDuringDrag : 1;
+ uint unused : 18;
};
bool flickX(qreal velocity);
@@ -241,6 +244,7 @@ public:
int pressDelay;
int fixupDuration;
qreal flickBoost;
+ qreal initialWheelFlickDistance;
enum FixupMode { Normal, Immediate, ExtentChanged };
FixupMode fixupMode;
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index 7ca5b0c34c..0a1f7681d6 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -1653,6 +1653,7 @@ void QQuickGridView::setCellWidth(qreal cellWidth)
d->updateViewport();
emit cellWidthChanged();
d->forceLayoutPolish();
+ QQuickFlickable::setContentX(d->contentXForPosition(d->position()));
}
}
@@ -1670,6 +1671,7 @@ void QQuickGridView::setCellHeight(qreal cellHeight)
d->updateViewport();
emit cellHeightChanged();
d->forceLayoutPolish();
+ QQuickFlickable::setContentY(d->contentYForPosition(d->position()));
}
}
/*!
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 1882ec8997..bf6e17a5d7 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -343,9 +343,9 @@ void QQuickImage::setFillMode(FillMode mode)
}
/*!
-
\qmlproperty real QtQuick::Image::paintedWidth
\qmlproperty real QtQuick::Image::paintedHeight
+ \readonly
These properties hold the size of the image that is actually painted.
In most cases it is the same as \c width and \c height, but when using an
@@ -367,6 +367,7 @@ qreal QQuickImage::paintedHeight() const
/*!
\qmlproperty enumeration QtQuick::Image::status
+ \readonly
This property holds the status of image loading. It can be one of:
\list
@@ -404,6 +405,7 @@ qreal QQuickImage::paintedHeight() const
/*!
\qmlproperty real QtQuick::Image::progress
+ \readonly
This property holds the progress of image loading, from 0.0 (nothing loaded)
to 1.0 (finished).
@@ -425,7 +427,7 @@ qreal QQuickImage::paintedHeight() const
*/
/*!
- \qmlproperty QSize QtQuick::Image::sourceSize
+ \qmlproperty size QtQuick::Image::sourceSize
This property holds the scaled width and height of the full-frame image.
@@ -943,3 +945,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 8849c2005c..d7b5709bb0 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -56,8 +56,8 @@ QT_BEGIN_NAMESPACE
bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio)
{
// QQuickImageProvider and SVG and PDF can generate a high resolution image when
- // sourceSize is set (this function is only called if it's set).
- // If sourceSize is not set then the provider default size will be used, as usual.
+ // 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;
@@ -418,10 +418,14 @@ void QQuickImageBase::itemChange(ItemChange change, const ItemChangeData &value)
Q_D(QQuickImageBase);
// If the screen DPI changed, reload image.
if (change == ItemDevicePixelRatioHasChanged && value.realValue != d->devicePixelRatio) {
+ const auto oldDpr = d->devicePixelRatio;
// ### how can we get here with !qmlEngine(this)? that implies
// itemChange() on an item pending deletion, which seems strange.
if (qmlEngine(this) && isComponentComplete() && d->url.isValid()) {
load();
+ // not changed when loading (sourceSize might not be set)
+ if (d->devicePixelRatio == oldDpr)
+ d->updateDevicePixelRatio(value.realValue);
}
}
QQuickItem::itemChange(change, value);
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 497672b497..33da9762d3 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -905,7 +905,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
@@ -2095,7 +2095,7 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
/*!
\class QQuickItem::ItemChangeData
\inmodule QtQuick
- \brief Adds supplimentary information to the QQuickItem::itemChange()
+ \brief Adds supplementary information to the QQuickItem::itemChange()
function.
The meaning of each member of this class is defined by the change type.
@@ -2125,25 +2125,31 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
/*!
\variable QQuickItem::ItemChangeData::realValue
- Contains supplimentary information to the QQuickItem::itemChange() function.
+ The numeric value that has changed: \l {QQuickItem::opacity()}{opacity},
+ \l {QQuickItem::rotation()}{rotation} or
+ \l {QScreen::devicePixelRatio}{device pixel ratio}.
\sa QQuickItem::ItemChange
*/
/*!
\variable QQuickItem::ItemChangeData::boolValue
- Contains supplimentary information to the QQuickItem::itemChange() function.
+ The boolean value that has changed: \l {QQuickItem::visible()}{visible},
+ \l {QQuickItem::enabled()}{enabled}, \l {QQuickItem::activeFocus()}{activeFocus}
+ or \l {QQuickItem::antialiasing()}{antialiasing}.
\sa QQuickItem::ItemChange
*/
/*!
\variable QQuickItem::ItemChangeData::item
- Contains supplimentary information to the QQuickItem::itemChange() function.
+ The item that has been added or removed as a \l{QQuickItem::childItems()}{child},
+ or the new \l{QQuickItem::parentItem()}{parent}.
\sa QQuickItem::ItemChange
*/
/*!
\variable QQuickItem::ItemChangeData::window
- Contains supplimentary information to the QQuickItem::itemChange() function.
+ The \l{QQuickWindow}{window} in which the item has been shown, or \c nullptr
+ if the item has been removed from a window.
\sa QQuickItem::ItemChange
*/
@@ -3711,6 +3717,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
@@ -4534,10 +4543,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
@@ -4589,10 +4598,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
@@ -4674,7 +4683,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.
@@ -4701,7 +4710,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.
@@ -4784,14 +4793,24 @@ void QQuickItem::forceActiveFocus()
void QQuickItem::forceActiveFocus(Qt::FocusReason reason)
{
+ Q_D(QQuickItem);
setFocus(true, reason);
QQuickItem *parent = parentItem();
+ QQuickItem *scope = nullptr;
while (parent) {
if (parent->flags() & QQuickItem::ItemIsFocusScope) {
parent->setFocus(true, reason);
+ if (!scope)
+ scope = parent;
}
parent = parent->parentItem();
}
+ // In certain reparenting scenarios, d->focus might be true and the scope
+ // might also have focus, so that setFocus() returns early without actually
+ // acquiring active focus, because it thinks it already has it. In that
+ // case, try to set the DeliveryAgent's active focus. (QTBUG-89736).
+ if (scope && !d->activeFocus && d->window)
+ QQuickWindowPrivate::get(d->window)->setFocusInScope(scope, this, Qt::OtherFocusReason);
}
/*!
@@ -7852,22 +7871,64 @@ 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.
- QtQuick::Item::contains main use is currently to determine whether
- an input event has landed into the item or not.
+ QtQuick::Item::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
- within the Item's bounding box. \c containmentMask allows for a
- more fine-grained control. For example, the developer could
- define and use an AnotherItem element as containmentMask,
- which has a specialized contains method, like:
+ 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
+ is used as containmentMask:
\code
Item { id: item; containmentMask: AnotherItem { id: anotherItem } }
\endcode
- \e{item}'s contains method would then return true only if
- \e{anotherItem}'s contains implementation returns true.
+ \e{item}'s contains method would then return \c true only if
+ \e{anotherItem}'s contains() implementation returns \c true.
+
+ A \l Shape can be used as a mask, to make an item react to
+ \l {QPointerEvent}{pointer events} only within a non-rectangular region:
+
+ \table
+ \row
+ \li \image containmentMask-shape.gif
+ \li \snippet qml/item/containmentMask-shape.qml 0
+ \endtable
+
+ It is also possible to define the contains method in QML. For example,
+ to create a circular item that only responds to events within its
+ actual bounds:
+
+ \table
+ \row
+ \li \image containmentMask-circle.gif
+ \li \snippet qml/item/containmentMask-circle-js.qml 0
+ \endtable
+
+ \sa {Qt Quick Examples - Shapes}
+*/
+/*!
+ \property QQuickItem::containmentMask
+ \since 5.11
+ This property holds an optional mask to be used in the contains() method,
+ which is mainly used for hit-testing each \l QPointerEvent.
+
+ By default, \l contains() will return \c true for any point
+ within the Item's bounding box. But any QQuickItem, or any QObject
+ that implements a function of the form
+ \code
+ Q_INVOKABLE bool contains(const QPointF &point) const;
+ \endcode
+ can be used as a mask, to defer hit-testing to that object.
+
+ \note contains() is called frequently during event delivery.
+ Deferring hit-testing to another object slows it down somewhat.
+ containmentMask() can cause performance problems if that object's
+ contains() method is not efficient. If you implement a custom
+ QQuickItem subclass, you can alternatively override contains().
+
+ \sa contains()
*/
QObject *QQuickItem::containmentMask() const
{
diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp
index dfb56ccc00..63359a7683 100644
--- a/src/quick/items/qquickitemanimation.cpp
+++ b/src/quick/items/qquickitemanimation.cpp
@@ -529,8 +529,8 @@ QAbstractAnimationJob* QQuickAnchorAnimation::transition(QQuickStateActions &act
data->interpolatorType = QMetaType::QReal;
data->interpolator = d->interpolator;
data->reverse = direction == Backward ? true : false;
- data->fromSourced = false;
- data->fromDefined = false;
+ data->fromIsSourced = false;
+ data->fromIsDefined = false;
for (int ii = 0; ii < actions.count(); ++ii) {
QQuickStateAction &action = actions[ii];
@@ -543,7 +543,7 @@ QAbstractAnimationJob* QQuickAnchorAnimation::transition(QQuickStateActions &act
QQuickBulkValueAnimator *animator = new QQuickBulkValueAnimator;
if (data->actions.count()) {
animator->setAnimValue(data);
- animator->setFromSourcedValue(&data->fromSourced);
+ animator->setFromIsSourcedValue(&data->fromIsSourced);
} else {
delete data;
}
@@ -864,9 +864,9 @@ QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actio
data->exitInterval = d->duration ? qreal(d->exitDuration) / d->duration : qreal(0);
data->endRotation = d->endRotation;
data->reverse = direction == Backward ? true : false;
- data->fromSourced = false;
- data->fromDefined = (d->path && d->path->hasStartX() && d->path->hasStartY()) ? true : false;
- data->toDefined = d->path ? true : false;
+ data->fromIsSourced = false;
+ data->fromIsDefined = (d->path && d->path->hasStartX() && d->path->hasStartY()) ? true : false;
+ data->toIsDefined = d->path ? true : false;
int origModifiedSize = modified.count();
for (int i = 0; i < actions.count(); ++i) {
@@ -885,8 +885,7 @@ QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actio
}
}
- if (target && d->path &&
- (modified.count() > origModifiedSize || data->toDefined)) {
+ if (target && d->path && (modified.count() > origModifiedSize || data->toIsDefined)) {
data->target = target;
data->path = d->path;
data->path->invalidateSequentialHistory();
@@ -897,13 +896,13 @@ QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actio
// treat interruptions specially, otherwise we end up with strange paths
if ((data->reverse || prevData.reverse) && prevData.currentV > 0 && prevData.currentV < 1) {
- if (!data->fromDefined && !data->toDefined && !prevData.painterPath.isEmpty()) {
+ if (!data->fromIsDefined && !data->toIsDefined && !prevData.painterPath.isEmpty()) {
QPointF pathPos = QQuickPath::sequentialPointAt(prevData.painterPath, prevData.pathLength, prevData.attributePoints, prevData.prevBez, prevData.currentV);
if (!prevData.anchorPoint.isNull())
pathPos -= prevData.anchorPoint;
if (pathPos == data->target->position()) { //only treat as interruption if we interrupted ourself
data->painterPath = prevData.painterPath;
- data->toDefined = data->fromDefined = data->fromSourced = true;
+ data->toIsDefined = data->fromIsDefined = data->fromIsSourced = true;
data->prevBez.isValid = false;
data->interruptStart = prevData.currentV;
data->startRotation = prevData.startRotation;
@@ -913,13 +912,13 @@ QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actio
}
}
}
- pa->setFromSourcedValue(&data->fromSourced);
+ pa->setFromIsSourcedValue(&data->fromIsSourced);
pa->setAnimValue(data);
pa->setDuration(d->duration);
pa->setEasingCurve(d->easingCurve);
return initInstance(pa);
} else {
- pa->setFromSourcedValue(nullptr);
+ pa->setFromIsSourcedValue(nullptr);
pa->setAnimValue(nullptr);
delete pa;
delete data;
@@ -939,7 +938,7 @@ void QQuickPathAnimationUpdater::setValue(qreal v)
}
currentV = v;
bool atStart = ((reverse && v == 1.0) || (!reverse && v == 0.0));
- if (!fromSourced && (!fromDefined || !toDefined)) {
+ if (!fromIsSourced && (!fromIsDefined || !toIsDefined)) {
qreal startX = reverse ? toX + anchorPoint.x() : target->x() + anchorPoint.x();
qreal startY = reverse ? toY + anchorPoint.y() : target->y() + anchorPoint.y();
qreal endX = reverse ? target->x() + anchorPoint.x() : toX + anchorPoint.x();
@@ -947,7 +946,7 @@ void QQuickPathAnimationUpdater::setValue(qreal v)
prevBez.isValid = false;
painterPath = path->createPath(QPointF(startX, startY), QPointF(endX, endY), QStringList(), pathLength, attributePoints);
- fromSourced = true;
+ fromIsSourced = true;
}
qreal angle;
diff --git a/src/quick/items/qquickitemanimation_p_p.h b/src/quick/items/qquickitemanimation_p_p.h
index 83b9899197..351a0cb2bc 100644
--- a/src/quick/items/qquickitemanimation_p_p.h
+++ b/src/quick/items/qquickitemanimation_p_p.h
@@ -92,7 +92,7 @@ class QQuickPathAnimationUpdater : public QQuickBulkValueUpdater
{
public:
QQuickPathAnimationUpdater() : path(nullptr), pathLength(0), target(nullptr), reverse(false),
- fromSourced(false), fromDefined(false), toDefined(false),
+ fromIsSourced(false), fromIsDefined(false), toIsDefined(false),
toX(0), toY(0), currentV(0), orientation(QQuickPathAnimation::Fixed),
entryInterval(0), exitInterval(0) {}
~QQuickPathAnimationUpdater() {}
@@ -108,9 +108,9 @@ public:
QQuickItem *target;
bool reverse;
- bool fromSourced;
- bool fromDefined;
- bool toDefined;
+ bool fromIsSourced;
+ bool fromIsDefined;
+ bool toIsDefined;
qreal toX;
qreal toY;
qreal currentV;
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 125518e51b..f14b29b1b8 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -128,6 +128,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,
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 2b4ca9e256..29afaae93b 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -290,8 +290,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 +1783,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);
@@ -2346,7 +2344,9 @@ FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, QQmlIncubator::Inc
inRequest = true;
- QObject* object = model->object(modelIndex, incubationMode);
+ // The model will run this same range check internally but produce a warning and return nullptr.
+ // Since we handle this result graciously in our code, we preempt this warning by checking the range ourselves.
+ QObject* object = modelIndex < model->count() ? model->object(modelIndex, incubationMode) : nullptr;
QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
if (!item) {
diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp
index b7649c9952..78b379d5a2 100644
--- a/src/quick/items/qquickitemviewtransition.cpp
+++ b/src/quick/items/qquickitemviewtransition.cpp
@@ -125,6 +125,8 @@ void QQuickItemViewTransitionJob::startTransition(QQuickItemViewTransitionableIt
actions << QQuickStateAction(item->item, QLatin1String("x"), QVariant(to.x()));
actions << QQuickStateAction(item->item, QLatin1String("y"), QVariant(to.y()));
+ actions[0].fromValue = item->itemX();
+ actions[1].fromValue = item->itemY();
m_transitioner->runningJobs << this;
QQuickTransitionManager::transition(actions, trans, item->item);
}
@@ -555,9 +557,15 @@ void QQuickItemViewTransitionableItem::stopTransition()
QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
- : QObject(parent), m_item(nullptr), m_index(-1)
+ : QObject(parent), m_index(-1)
{
}
+
+QQuickItem *QQuickViewTransitionAttached::item() const
+{
+ return m_item.data();
+}
+
/*!
\qmltype ViewTransition
\instantiates QQuickViewTransitionAttached
diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h
index 5f4e74171e..bedef93d0b 100644
--- a/src/quick/items/qquickitemviewtransition_p.h
+++ b/src/quick/items/qquickitemviewtransition_p.h
@@ -202,7 +202,7 @@ public:
QQuickViewTransitionAttached(QObject *parent);
int index() const { return m_index; }
- QQuickItem *item() const { return m_item; }
+ QQuickItem *item() const;
QPointF destination() const { return m_destination; }
QList<int> targetIndexes() const { return m_targetIndexes; }
@@ -224,7 +224,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/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index cb4f79a3c2..0a5514d5f9 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -439,9 +439,8 @@ void QQuickLoader::loadFromSource()
}
if (isComponentComplete()) {
- QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
if (!d->component)
- d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this);
+ d->createComponent();
d->load();
}
}
@@ -737,6 +736,9 @@ void QQuickLoaderPrivate::_q_sourceLoaded()
return;
}
+ if (!active)
+ return;
+
QQmlContext *creationContext = component->creationContext();
if (!creationContext) creationContext = qmlContext(q);
itemContext = new QQmlContext(creationContext);
@@ -803,11 +805,8 @@ void QQuickLoader::componentComplete()
Q_D(QQuickLoader);
QQuickItem::componentComplete();
if (active()) {
- if (d->loadingFromSource) {
- QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
- if (!d->component)
- d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this);
- }
+ if (d->loadingFromSource && !d->component)
+ d->createComponent();
d->load();
}
}
@@ -943,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.
@@ -1041,6 +1040,22 @@ void QQuickLoaderPrivate::updateStatus()
}
}
+void QQuickLoaderPrivate::createComponent()
+{
+ Q_Q(QQuickLoader);
+ const QQmlComponent::CompilationMode mode = asynchronous
+ ? QQmlComponent::Asynchronous
+ : QQmlComponent::PreferSynchronous;
+ if (QQmlContext *context = qmlContext(q)) {
+ if (QQmlEngine *engine = context->engine()) {
+ component.setObject(new QQmlComponent(engine, source, mode, q), q);
+ return;
+ }
+ }
+
+ qmlWarning(q) << "createComponent: Cannot find a QML engine.";
+}
+
#include <moc_qquickloader_p.cpp>
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 39d50280c5..b178803c7d 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -98,6 +98,7 @@ public:
QV4::ReturnedValue extractInitialPropertyValues(QQmlV4Function *args, QObject *loader, bool *error);
QQuickLoader::Status computeStatus() const;
void updateStatus();
+ void createComponent();
qreal getImplicitWidth() const override;
qreal getImplicitHeight() const override;
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 982d089b5f..3e2e4fc1cf 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -806,7 +806,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;
@@ -825,7 +826,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);
}
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 383718c979..4d420969cf 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -569,7 +569,7 @@ void QQuickMultiPointTouchArea::grabGesture()
setKeepTouchGrab(true);
}
-void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
+void QQuickMultiPointTouchArea::updateTouchData(QEvent *event, RemapEventPoints remap)
{
bool ended = false;
bool moved = false;
@@ -578,12 +578,14 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
clearTouchLists();
QList<QTouchEvent::TouchPoint> touchPoints;
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window());
+ bool touchPointsFromEvent = false;
switch (event->type()) {
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
touchPoints = static_cast<QTouchEvent*>(event)->touchPoints();
+ touchPointsFromEvent = true;
break;
case QEvent::MouseButtonPress:
_mouseQpaTouchPoint = QTouchEvent::TouchPoint(windowPriv->touchMouseId);
@@ -614,6 +616,8 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
qWarning("updateTouchData: unhandled event type %d", event->type());
break;
}
+ if (!touchPointsFromEvent)
+ remap = RemapEventPoints::No;
int numTouchPoints = touchPoints.count();
//always remove released touches, and make sure we handle all releases before adds.
@@ -624,7 +628,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
if (!dtp)
continue;
- updateTouchPoint(dtp, &p);
+ updateTouchPoint(dtp, &p, RemapEventPoints::No);
dtp->setPressed(false);
_releasedTouchPoints.append(dtp);
_touchPoints.remove(id);
@@ -639,19 +643,19 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
//handled above
} else if (!_touchPoints.contains(id)) { //could be pressed, moved, or stationary
// (we may have just obtained enough points to start tracking them -- in that case moved or stationary count as newly pressed)
- addTouchPoint(&p);
+ addTouchPoint(&p, remap);
started = true;
} else if ((touchPointState & Qt::TouchPointMoved) || p.d->stationaryWithModifiedProperty) {
// React to a stationary point with a property change (velocity, pressure) as if the point moved. (QTBUG-77142)
QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
Q_ASSERT(dtp);
_movedTouchPoints.append(dtp);
- updateTouchPoint(dtp,&p);
+ updateTouchPoint(dtp, &p, remap);
moved = true;
} else {
QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
Q_ASSERT(dtp);
- updateTouchPoint(dtp,&p);
+ updateTouchPoint(dtp, &p, remap);
}
}
@@ -685,7 +689,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
emit released(_releasedTouchPoints);
if (moved)
emit updated(_movedTouchPoints);
- if (started)
+ if (started && !_pressedTouchPoints.isEmpty())
emit pressed(_pressedTouchPoints);
if (ended || moved || started) emit touchUpdated(_touchPoints.values());
}
@@ -707,7 +711,7 @@ void QQuickMultiPointTouchArea::clearTouchLists()
_movedTouchPoints.clear();
}
-void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
+void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p, RemapEventPoints remap)
{
QQuickTouchPoint *dtp = nullptr;
for (QQuickTouchPoint* tp : qAsConst(_touchPrototypes)) {
@@ -721,7 +725,7 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
if (dtp == nullptr)
dtp = new QQuickTouchPoint(false);
dtp->setPointId(p->id());
- updateTouchPoint(dtp,p);
+ updateTouchPoint(dtp, p, remap);
dtp->setPressed(true);
_touchPoints.insert(p->id(),dtp);
_pressedTouchPoints.append(dtp);
@@ -730,12 +734,15 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
void QQuickMultiPointTouchArea::addTouchPoint(const QMouseEvent *e)
{
QQuickTouchPoint *dtp = nullptr;
- for (QQuickTouchPoint *tp : qAsConst(_touchPrototypes))
+ for (QQuickTouchPoint *tp : qAsConst(_touchPrototypes)) {
if (!tp->inUse()) {
tp->setInUse(true);
dtp = tp;
break;
+ } else if (_mouseTouchPoint == tp) {
+ return; // do not allow more than one touchpoint to react to the mouse (QTBUG-83662)
}
+ }
if (dtp == nullptr)
dtp = new QQuickTouchPoint(false);
@@ -779,12 +786,12 @@ void QQuickMultiPointTouchArea::addTouchPrototype(QQuickTouchPoint *prototype)
_touchPrototypes.insert(id, prototype);
}
-void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QTouchEvent::TouchPoint *p)
+void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QTouchEvent::TouchPoint *p, RemapEventPoints remap)
{
//TODO: if !qmlDefined, could bypass setters.
// also, should only emit signals after all values have been set
dtp->setUniqueId(p->uniqueId());
- dtp->setPosition(p->pos());
+ dtp->setPosition(remap == RemapEventPoints::ToLocal ? mapFromScene(p->scenePos()) : p->pos());
dtp->setEllipseDiameters(p->ellipseDiameters());
dtp->setPressure(p->pressure());
dtp->setRotation(p->rotation());
@@ -972,12 +979,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 e34a3faad6..85c1e2258e 100644
--- a/src/quick/items/qquickmultipointtoucharea_p.h
+++ b/src/quick/items/qquickmultipointtoucharea_p.h
@@ -267,14 +267,15 @@ protected:
void mouseUngrabEvent() override;
void touchUngrabEvent() override;
+ enum class RemapEventPoints { No, ToLocal };
void addTouchPrototype(QQuickTouchPoint* prototype);
- void addTouchPoint(const QTouchEvent::TouchPoint *p);
+ void addTouchPoint(const QTouchEvent::TouchPoint *p, RemapEventPoints remap);
void addTouchPoint(const QMouseEvent *e);
void clearTouchLists();
- void updateTouchPoint(QQuickTouchPoint*, const QTouchEvent::TouchPoint*);
+ void updateTouchPoint(QQuickTouchPoint*, const QTouchEvent::TouchPoint*, RemapEventPoints remap);
void updateTouchPoint(QQuickTouchPoint *dtp, const QMouseEvent *e);
- void updateTouchData(QEvent*);
+ void updateTouchData(QEvent*, RemapEventPoints remap = RemapEventPoints::No);
bool sendMouseEvent(QMouseEvent *event);
bool shouldFilter(QEvent *event);
diff --git a/src/quick/items/qquickopenglshadereffectnode.cpp b/src/quick/items/qquickopenglshadereffectnode.cpp
index 5721f116e8..bc50099903 100644
--- a/src/quick/items/qquickopenglshadereffectnode.cpp
+++ b/src/quick/items/qquickopenglshadereffectnode.cpp
@@ -120,10 +120,13 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
: QQuickShaderEffect::Error);
}
+ if (newEffect != oldEffect)
+ m_initialized = false;
+
int textureProviderIndex = 0;
if (!m_initialized) {
for (int shaderType = 0; shaderType < QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
- Q_ASSERT(m_uniformLocs[shaderType].isEmpty());
+ m_uniformLocs[shaderType].clear();
m_uniformLocs[shaderType].reserve(material->uniforms[shaderType].size());
for (int i = 0; i < material->uniforms[shaderType].size(); ++i) {
const UniformData &d = material->uniforms[shaderType].at(i);
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index 0692a1da42..df6f271b0d 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -556,7 +556,10 @@ void QQuickPinchArea::updatePinch()
d->inPinch = true;
d->stealMouse = true;
if (d->pinch && d->pinch->target()) {
- d->pinchStartPos = pinch()->target()->position();
+ auto targetParent = pinch()->target()->parentItem();
+ d->pinchStartPos = targetParent ?
+ targetParent->mapToScene(pinch()->target()->position()) :
+ pinch()->target()->position();
d->pinchStartScale = d->pinch->target()->scale();
d->pinchStartRotation = d->pinch->target()->rotation();
d->pinch->setActive(true);
@@ -604,6 +607,9 @@ void QQuickPinchArea::updatePinchTarget()
s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale());
pinch()->target()->setScale(s);
QPointF pos = d->sceneLastCenter - d->sceneStartCenter + d->pinchStartPos;
+ if (auto targetParent = pinch()->target()->parentItem())
+ pos = targetParent->mapFromScene(pos);
+
if (pinch()->axis() & QQuickPinch::XAxis) {
qreal x = pos.x();
if (x < pinch()->xmin())
@@ -704,6 +710,8 @@ bool QQuickPinchArea::event(QEvent *event)
clearPinch();
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);
@@ -721,7 +729,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()) {
@@ -745,6 +756,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);
@@ -763,7 +776,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/qquickscalegrid.cpp b/src/quick/items/qquickscalegrid.cpp
index 23f179be1d..82875c9e52 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/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 4deb6c70a3..c0a1ccab78 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -173,7 +173,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/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp
index ddaa1979b6..a832f53e39 100644
--- a/src/quick/items/qquickstateoperations.cpp
+++ b/src/quick/items/qquickstateoperations.cpp
@@ -573,7 +573,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
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index f9454fc5cb..3c10a65450 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -958,43 +958,61 @@ QQuickTableViewPrivate::RebuildOptions QQuickTableViewPrivate::checkForVisibilit
return RebuildOption::None;
}
- // Go through all columns from first to last, find the columns that used
- // to be hidden and not loaded, and check if they should become visible
- // (and vice versa). If there is a change, we need to rebuild.
RebuildOptions rebuildOptions = RebuildOption::None;
- for (int column = leftColumn(); column <= rightColumn(); ++column) {
- const bool wasVisibleFromBefore = loadedColumns.contains(column);
- const bool isVisibleNow = !qFuzzyIsNull(getColumnWidth(column));
- if (wasVisibleFromBefore == isVisibleNow)
- continue;
-
- // A column changed visibility. This means that it should
- // either be loaded or unloaded. So we need a rebuild.
- qCDebug(lcTableViewDelegateLifecycle) << "Column" << column << "changed visibility to" << isVisibleNow;
+ if (loadedTableOuterRect.x() == origin.x() && leftColumn() != 0) {
+ // Since the left column is at the origin of the viewport, but still not the first
+ // column in the model, we need to calculate a new left column since there might be
+ // columns in front of it that used to be hidden, but should now be visible (QTBUG-93264).
rebuildOptions.setFlag(RebuildOption::ViewportOnly);
- if (column == leftColumn()) {
- // The first loaded column should now be hidden. This means that we
- // need to calculate which column should now be first instead.
- rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
+ rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
+ } else {
+ // Go through all loaded columns from first to last, find the columns that used
+ // to be hidden and not loaded, and check if they should become visible
+ // (and vice versa). If there is a change, we need to rebuild.
+ for (int column = leftColumn(); column <= rightColumn(); ++column) {
+ const bool wasVisibleFromBefore = loadedColumns.contains(column);
+ const bool isVisibleNow = !qFuzzyIsNull(getColumnWidth(column));
+ if (wasVisibleFromBefore == isVisibleNow)
+ continue;
+
+ // A column changed visibility. This means that it should
+ // either be loaded or unloaded. So we need a rebuild.
+ qCDebug(lcTableViewDelegateLifecycle) << "Column" << column << "changed visibility to" << isVisibleNow;
+ rebuildOptions.setFlag(RebuildOption::ViewportOnly);
+ if (column == leftColumn()) {
+ // The first loaded column should now be hidden. This means that we
+ // need to calculate which column should now be first instead.
+ rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
+ }
+ break;
}
- break;
}
- // Go through all rows from first to last, and do the same as above
- for (int row = topRow(); row <= bottomRow(); ++row) {
- const bool wasVisibleFromBefore = loadedRows.contains(row);
- const bool isVisibleNow = !qFuzzyIsNull(getRowHeight(row));
- if (wasVisibleFromBefore == isVisibleNow)
- continue;
-
- // A row changed visibility. This means that it should
- // either be loaded or unloaded. So we need a rebuild.
- qCDebug(lcTableViewDelegateLifecycle) << "Row" << row << "changed visibility to" << isVisibleNow;
+ if (loadedTableOuterRect.y() == origin.y() && topRow() != 0) {
+ // Since the top row is at the origin of the viewport, but still not the first
+ // row in the model, we need to calculate a new top row since there might be
+ // rows in front of it that used to be hidden, but should now be visible (QTBUG-93264).
rebuildOptions.setFlag(RebuildOption::ViewportOnly);
- if (row == topRow())
- rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
- break;
+ rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
+ } else {
+ // Go through all loaded rows from first to last, find the rows that used
+ // to be hidden and not loaded, and check if they should become visible
+ // (and vice versa). If there is a change, we need to rebuild.
+ for (int row = topRow(); row <= bottomRow(); ++row) {
+ const bool wasVisibleFromBefore = loadedRows.contains(row);
+ const bool isVisibleNow = !qFuzzyIsNull(getRowHeight(row));
+ if (wasVisibleFromBefore == isVisibleNow)
+ continue;
+
+ // A row changed visibility. This means that it should
+ // either be loaded or unloaded. So we need a rebuild.
+ qCDebug(lcTableViewDelegateLifecycle) << "Row" << row << "changed visibility to" << isVisibleNow;
+ rebuildOptions.setFlag(RebuildOption::ViewportOnly);
+ if (row == topRow())
+ rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
+ break;
+ }
}
return rebuildOptions;
@@ -3078,3 +3096,5 @@ QQuickTableSectionSizeProviderPrivate::~QQuickTableSectionSizeProviderPrivate()
#include "moc_qquicktableview_p.cpp"
QT_END_NAMESPACE
+
+#include "moc_qquicktableview_p_p.cpp"
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 6230186933..d8fd2017e3 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -965,7 +965,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,
@@ -2168,7 +2168,7 @@ void QQuickText::resetMaximumLineCount()
<img src="" align="top,middle,bottom" width="" height=""> - inline images
<ol type="">, <ul type=""> and <li> - ordered and unordered lists
<pre></pre> - preformatted
- &gt; &lt; &amp;
+ &gt; &lt; &amp; &quot; &nbsp; &apos;
\endcode
\c Text.StyledText parser is strict, requiring tags to be correctly nested.
@@ -2409,21 +2409,23 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
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) {
diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h
index 0fffc1fb9a..698f9649dd 100644
--- a/src/quick/items/qquicktext_p.h
+++ b/src/quick/items/qquicktext_p.h
@@ -326,6 +326,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 5df5e5adcf..5dad4d4d42 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -1204,7 +1204,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
{
@@ -2359,6 +2367,14 @@ void QQuickTextEdit::q_textChanged()
d->determineHorizontalAlignment();
d->updateDefaultTextOption();
updateSize();
+
+ markDirtyNodesForRange(0, d->document->characterCount(), 0);
+ polish();
+ if (isComponentComplete()) {
+ d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
+ update();
+ }
+
emit textChanged();
}
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index 227d8cbf51..88ba2f9d0d 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 0e7f52e816..9db18d1683 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -518,8 +518,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
@@ -542,7 +550,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
{
@@ -831,7 +839,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
{
@@ -849,6 +870,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.
@@ -890,6 +912,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
@@ -905,6 +928,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
@@ -935,6 +959,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.
@@ -1152,6 +1177,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
@@ -1585,7 +1611,7 @@ void QQuickTextInput::mousePressEvent(QMouseEvent *event)
d->moveCursor(cursor, mark);
if (d->focusOnPress && !qGuiApp->styleHints()->setFocusOnTouchRelease())
- ensureActiveFocus();
+ ensureActiveFocus(Qt::MouseFocusReason);
event->setAccepted(true);
}
@@ -1637,7 +1663,7 @@ void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
#endif
if (d->focusOnPress && qGuiApp->styleHints()->setFocusOnTouchRelease())
- ensureActiveFocus();
+ ensureActiveFocus(Qt::MouseFocusReason);
if (!event->isAccepted())
QQuickImplicitSizeItem::mouseReleaseEvent(event);
@@ -1872,10 +1898,10 @@ void QQuickTextInput::invalidateFontCaches()
d->m_textLayout.engine()->resetFontEngineCache();
}
-void QQuickTextInput::ensureActiveFocus()
+void QQuickTextInput::ensureActiveFocus(Qt::FocusReason reason)
{
bool hadActiveFocus = hasActiveFocus();
- forceActiveFocus();
+ forceActiveFocus(reason);
#if QT_CONFIG(im)
Q_D(QQuickTextInput);
// re-open input panel on press if already focused
@@ -2105,7 +2131,7 @@ void QQuickTextInput::undo()
{
Q_D(QQuickTextInput);
if (!d->m_readOnly) {
- d->resetInputMethod();
+ d->cancelInput();
d->internalUndo();
d->finishChange(-1, true);
}
@@ -2121,7 +2147,7 @@ void QQuickTextInput::redo()
{
Q_D(QQuickTextInput);
if (!d->m_readOnly) {
- d->resetInputMethod();
+ d->cancelInput();
d->internalRedo();
d->finishChange();
}
@@ -2459,6 +2485,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.
@@ -2480,6 +2507,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.
@@ -2493,6 +2521,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.
@@ -2506,6 +2535,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.
@@ -2519,6 +2549,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.
@@ -2682,7 +2713,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.
@@ -2748,11 +2779,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)
@@ -3456,7 +3489,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;
@@ -4695,7 +4733,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.h b/src/quick/items/qquicktextinput_p.h
index 9f7b82b168..8e97393d10 100644
--- a/src/quick/items/qquicktextinput_p.h
+++ b/src/quick/items/qquicktextinput_p.h
@@ -361,7 +361,7 @@ Q_SIGNALS:
private:
void invalidateFontCaches();
- void ensureActiveFocus();
+ void ensureActiveFocus(Qt::FocusReason reason);
protected:
QQuickTextInput(QQuickTextInputPrivate &dd, QQuickItem *parent = nullptr);
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index fa92e608b7..6c11ca0a0b 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/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index c956c85091..8ab69603ad 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -450,12 +450,13 @@ void QQuickWindow::physicalDpiChanged()
void QQuickWindow::handleScreenChanged(QScreen *screen)
{
Q_D(QQuickWindow);
+ // we connected to the initial screen in QQuickWindowPrivate::init, but the screen changed
disconnect(d->physicalDpiChangedConnection);
if (screen) {
physicalDpiChanged();
// When physical DPI changes on the same screen, either the resolution or the device pixel
// ratio changed. We must check what it is. Device pixel ratio does not have its own
- // ...Changed() signal.
+ // ...Changed() signal. Reconnect, same as in QQuickWindowPrivate::init.
d->physicalDpiChangedConnection = connect(screen, &QScreen::physicalDotsPerInchChanged,
this, &QQuickWindow::physicalDpiChanged);
}
@@ -707,8 +708,13 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
Q_ASSERT(windowManager || renderControl);
- if (QScreen *screen = q->screen())
- devicePixelRatio = screen->devicePixelRatio();
+ if (QScreen *screen = q->screen()) {
+ devicePixelRatio = screen->devicePixelRatio();
+ // if the screen changes, then QQuickWindow::handleScreenChanged disconnects
+ // and connects to the new screen
+ physicalDpiChangedConnection = QObject::connect(screen, &QScreen::physicalDotsPerInchChanged,
+ q, &QQuickWindow::physicalDpiChanged);
+ }
QSGContext *sg;
if (renderControl) {
@@ -1488,7 +1494,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)
@@ -1702,6 +1712,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
{
@@ -2140,6 +2152,15 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems.at(0))) {
QQuickItem *hoverLeaveItem = hoverItems.takeFirst();
sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, timestamp, accepted);
+ QQuickItemPrivate *hoverLeaveItemPrivate = QQuickItemPrivate::get(hoverLeaveItem);
+ if (hoverLeaveItemPrivate->hasPointerHandlers()) {
+ for (QQuickPointerHandler *handler : hoverLeaveItemPrivate->extra->pointerHandlers) {
+ if (auto *hh = qmlobject_cast<QQuickHoverHandler *>(handler)) {
+ QQuickPointerEvent *pointerEvent = pointerEventInstance(QQuickPointerDevice::genericMouseDevice(), QEvent::MouseMove);
+ pointerEvent->point(0)->cancelPassiveGrab(hh);
+ }
+ }
+ }
}
if (!hoverItems.isEmpty() && hoverItems.at(0) == item) {//Not entering a new Item
@@ -2184,12 +2205,16 @@ bool QQuickWindowPrivate::deliverSinglePointEventUntilAccepted(QQuickPointerEven
QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point, false, false);
for (QQuickItem *item : targetItems) {
+ if (!item->window())
+ continue;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
event->localize(item);
// Let Pointer Handlers have the first shot
itemPrivate->handlePointerEvent(event);
if (point->isAccepted())
return true;
+ if (!item->window())
+ continue;
QPointF g = item->window()->mapToGlobal(point->scenePosition().toPoint());
#if QT_CONFIG(wheelevent)
// Let the Item have a chance to handle it
@@ -2424,6 +2449,9 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event)
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(),
event->buttons());
deliverPointerEvent(pointerEventInstance(event));
+#if QT_CONFIG(cursor)
+ updateCursor(event->windowPos());
+#endif
break;
case QEvent::MouseButtonDblClick:
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
@@ -2595,7 +2623,9 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) con
}
Q_ASSERT(dev);
- return pointerEventInstance(dev, event->type())->reset(event);
+ auto pev = pointerEventInstance(dev, event->type());
+ Q_ASSERT(pev);
+ return pev->reset(event);
}
void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event)
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h
index b80bacbaa0..af912e1a3f 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h
@@ -54,6 +54,8 @@
#include <private/qsgadaptationlayer_p.h>
#include <private/qsgtexturematerial_p.h>
+#include <QtCore/QPointer>
+
QT_BEGIN_NAMESPACE
namespace QSGSoftwareHelpers {
@@ -132,7 +134,7 @@ private:
QRectF m_innerSourceRect;
QRectF m_subSourceRect;
- QSGTexture *m_texture;
+ QPointer<QSGTexture> m_texture;
QPixmap m_cachedMirroredPixmap;
bool m_mirror;
diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp
index 7c98e2c1e1..13b4c63c3c 100644
--- a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp
+++ b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp
@@ -180,3 +180,5 @@ QSGTexture *Texture::removedFromAtlas() const
}
QT_END_NAMESPACE
+
+#include "moc_qsgcompressedatlastexture_p.cpp"
diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
index 65abb2a1af..ce433a0411 100644
--- a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
+++ b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
@@ -382,3 +382,5 @@ QSize QSGCompressedTextureFactory::textureSize() const
}
QT_END_NAMESPACE
+
+#include "moc_qsgcompressedtexture_p.cpp"
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 31671c8639..8f24617b24 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -1068,11 +1068,10 @@ static void qsg_wipeBuffer(Buffer *buffer, QOpenGLFunctions *funcs)
free(buffer->data);
}
-static void qsg_wipeBatch(Batch *batch, QOpenGLFunctions *funcs, bool separateIndexBuffer)
+static void qsg_wipeBatch(Batch *batch, QOpenGLFunctions *funcs)
{
qsg_wipeBuffer(&batch->vbo, funcs);
- if (separateIndexBuffer)
- qsg_wipeBuffer(&batch->ibo, funcs);
+ qsg_wipeBuffer(&batch->ibo, funcs);
delete batch->ubuf;
batch->stencilClipState.reset();
delete batch;
@@ -1082,13 +1081,12 @@ Renderer::~Renderer()
{
if (m_rhi || QOpenGLContext::currentContext()) {
// Clean up batches and buffers
- const bool separateIndexBuffer = m_context->separateIndexBuffer();
for (int i = 0; i < m_opaqueBatches.size(); ++i)
- qsg_wipeBatch(m_opaqueBatches.at(i), this, separateIndexBuffer);
+ qsg_wipeBatch(m_opaqueBatches.at(i), this);
for (int i = 0; i < m_alphaBatches.size(); ++i)
- qsg_wipeBatch(m_alphaBatches.at(i), this, separateIndexBuffer);
+ qsg_wipeBatch(m_alphaBatches.at(i), this);
for (int i = 0; i < m_batchPool.size(); ++i)
- qsg_wipeBatch(m_batchPool.at(i), this, separateIndexBuffer);
+ qsg_wipeBatch(m_batchPool.at(i), this);
}
for (Node *n : qAsConst(m_nodes))
@@ -1133,6 +1131,9 @@ void Renderer::releaseCachedResources()
if (m_rhi)
m_rhi->releaseCachedResources();
+
+ m_vertexUploadPool.resize(0);
+ m_indexUploadPool.resize(0);
}
void Renderer::invalidateAndRecycleBatch(Batch *b)
@@ -1159,8 +1160,7 @@ void Renderer::map(Buffer *buffer, int byteSize, bool isIndexBuf)
if (!m_context->hasBrokenIndexBufferObjects() && m_visualizer->mode() == Visualizer::VisualizeNothing) {
// Common case, use a shared memory pool for uploading vertex data to avoid
// excessive reevaluation
- QDataBuffer<char> &pool = m_context->separateIndexBuffer() && isIndexBuf
- ? m_indexUploadPool : m_vertexUploadPool;
+ QDataBuffer<char> &pool = isIndexBuf ? m_indexUploadPool : m_vertexUploadPool;
if (byteSize > pool.size())
pool.resize(byteSize);
buffer->data = pool.data();
@@ -1878,7 +1878,7 @@ bool Renderer::checkOverlap(int first, int last, const Rect &bounds)
{
for (int i=first; i<=last; ++i) {
Element *e = m_alphaRenderList.at(i);
- if (!e || e->batch)
+ if (!e)
continue;
Q_ASSERT(e->boundsComputed);
if (e->bounds.intersects(bounds))
@@ -1949,8 +1949,10 @@ void Renderer::prepareAlphaBatches()
continue;
if (ej->root != ei->root || ej->isRenderNode)
break;
- if (ej->batch)
+ if (ej->batch) {
+ overlapBounds |= ej->bounds;
continue;
+ }
QSGGeometryNode *gnj = ej->node;
if (gnj->geometry()->vertexCount() == 0)
@@ -2218,11 +2220,7 @@ void Renderer::uploadBatch(Batch *b)
ibufferSize = unmergedIndexSize;
}
- const bool separateIndexBuffer = m_context->separateIndexBuffer();
- if (separateIndexBuffer)
- map(&b->ibo, ibufferSize, true);
- else
- bufferSize += ibufferSize;
+ map(&b->ibo, ibufferSize, true);
map(&b->vbo, bufferSize);
if (Q_UNLIKELY(debug_upload())) qDebug() << " - batch" << b << " first:" << b->first << " root:"
@@ -2232,9 +2230,7 @@ void Renderer::uploadBatch(Batch *b)
if (b->merged) {
char *vertexData = b->vbo.data;
char *zData = vertexData + b->vertexCount * g->sizeOfVertex();
- char *indexData = separateIndexBuffer
- ? b->ibo.data
- : zData + (int(m_useDepthBuffer) * b->vertexCount * sizeof(float));
+ char *indexData = b->ibo.data;
quint16 iOffset16 = 0;
quint32 iOffset32 = 0;
@@ -2246,8 +2242,8 @@ void Renderer::uploadBatch(Batch *b)
const uint verticesInSetLimit = m_uint32IndexForRhi ? 0xfffffffe : 0xfffe;
int indicesInSet = 0;
b->drawSets.reset();
- int drawSetIndices = separateIndexBuffer ? 0 : indexData - vertexData;
- const char *indexBase = separateIndexBuffer ? b->ibo.data : b->vbo.data;
+ int drawSetIndices = 0;
+ const char *indexBase = b->ibo.data;
b->drawSets << DrawSet(0, zData - vertexData, drawSetIndices);
while (e) {
verticesInSet += e->node->geometry()->vertexCount();
@@ -2281,8 +2277,7 @@ void Renderer::uploadBatch(Batch *b)
}
} else {
char *vboData = b->vbo.data;
- char *iboData = separateIndexBuffer ? b->ibo.data
- : vboData + b->vertexCount * g->sizeOfVertex();
+ char *iboData = b->ibo.data;
Element *e = b->first;
while (e) {
QSGGeometry *g = e->node->geometry();
@@ -2350,9 +2345,7 @@ void Renderer::uploadBatch(Batch *b)
if (!b->drawSets.isEmpty()) {
if (m_uint32IndexForRhi) {
- const quint32 *id = (const quint32 *)(separateIndexBuffer
- ? b->ibo.data
- : b->vbo.data + b->drawSets.at(0).indices);
+ const quint32 *id = (const quint32 *) b->ibo.data;
{
QDebug iDump = qDebug();
iDump << " -- Index Data, count:" << b->indexCount;
@@ -2363,9 +2356,7 @@ void Renderer::uploadBatch(Batch *b)
}
}
} else {
- const quint16 *id = (const quint16 *)(separateIndexBuffer
- ? b->ibo.data
- : b->vbo.data + b->drawSets.at(0).indices);
+ const quint16 *id = (const quint16 *) b->ibo.data;
{
QDebug iDump = qDebug();
iDump << " -- Index Data, count:" << b->indexCount;
@@ -2386,8 +2377,7 @@ void Renderer::uploadBatch(Batch *b)
#endif // QT_NO_DEBUG_OUTPUT
unmap(&b->vbo);
- if (separateIndexBuffer)
- unmap(&b->ibo, true);
+ unmap(&b->ibo, true);
if (Q_UNLIKELY(debug_upload())) qDebug() << " --- vertex/index buffers unmapped, batch upload completed...";
@@ -3047,7 +3037,7 @@ void Renderer::renderMergedBatch(const Batch *batch) // legacy (GL-only)
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id);
char *indexBase = nullptr;
- const Buffer *indexBuf = m_context->separateIndexBuffer() ? &batch->ibo : &batch->vbo;
+ const Buffer *indexBuf = &batch->ibo;
if (m_context->hasBrokenIndexBufferObjects()) {
indexBase = indexBuf->data;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -3140,8 +3130,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch) // legacy (GL-only)
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id);
char *indexBase = nullptr;
- const bool separateIndexBuffer = m_context->separateIndexBuffer();
- const Buffer *indexBuf = separateIndexBuffer ? &batch->ibo : &batch->vbo;
+ const Buffer *indexBuf = &batch->ibo;
if (batch->indexCount) {
if (m_context->hasBrokenIndexBufferObjects()) {
indexBase = indexBuf->data;
@@ -3171,9 +3160,6 @@ void Renderer::renderUnmergedBatch(const Batch *batch) // legacy (GL-only)
int vOffset = 0;
char *iOffset = indexBase;
- if (!separateIndexBuffer)
- iOffset += batch->vertexCount * gn->geometry()->sizeOfVertex();
-
QMatrix4x4 rootMatrix = batch->root ? qsg_matrixForRoot(batch->root) : QMatrix4x4();
while (e) {
@@ -4004,6 +3990,17 @@ void Renderer::renderBatches()
if (m_useDepthBuffer) {
glClearDepthf(1); // calls glClearDepth() under the hood for desktop OpenGL
+ glDepthMask(true);
+ }
+ glColorMask(true, true, true, true);
+ glDisable(GL_SCISSOR_TEST);
+
+ bindable()->clear(clearMode());
+
+ if (m_renderPassRecordingCallbacks.start)
+ m_renderPassRecordingCallbacks.start(m_renderPassRecordingCallbacks.userData);
+
+ if (m_useDepthBuffer) {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(true);
@@ -4017,11 +4014,6 @@ void Renderer::renderBatches()
glDisable(GL_SCISSOR_TEST);
glDisable(GL_STENCIL_TEST);
- bindable()->clear(clearMode());
-
- if (m_renderPassRecordingCallbacks.start)
- m_renderPassRecordingCallbacks.start(m_renderPassRecordingCallbacks.userData);
-
if (Q_LIKELY(renderOpaque)) {
for (int i=0; i<m_opaqueBatches.size(); ++i) {
Batch *b = m_opaqueBatches.at(i);
@@ -4040,12 +4032,14 @@ void Renderer::renderBatches()
if (Q_LIKELY(renderAlpha)) {
for (int i=0; i<m_alphaBatches.size(); ++i) {
Batch *b = m_alphaBatches.at(i);
- if (b->merged)
+ if (b->merged) {
renderMergedBatch(b);
- else if (b->isRenderNode)
+ } else if (b->isRenderNode) {
+ m_current_projection_matrix = projectionMatrix();
renderRenderNode(b);
- else
+ } else {
renderUnmergedBatch(b);
+ }
}
}
@@ -4335,7 +4329,7 @@ void Renderer::render()
if (largestVBO * 2 < m_vertexUploadPool.size())
m_vertexUploadPool.resize(largestVBO * 2);
- if (m_context->separateIndexBuffer() && largestIBO * 2 < m_indexUploadPool.size())
+ if (largestIBO * 2 < m_indexUploadPool.size())
m_indexUploadPool.resize(largestIBO * 2);
renderBatches();
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.h b/src/quick/scenegraph/coreapi/qsggeometry.h
index d17915a842..685ac1cd95 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.h
+++ b/src/quick/scenegraph/coreapi/qsggeometry.h
@@ -202,6 +202,7 @@ public:
void setLineWidth(float w);
private:
+ Q_DISABLE_COPY_MOVE(QSGGeometry)
friend class QSGGeometryData;
int m_drawing_mode;
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp b/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp
index c5cbd0c979..d2eb22f45a 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp
@@ -105,7 +105,7 @@ void QSGMaterialRhiShaderPrivate::prepare(QShader::Variant vertexShaderVariant)
ubufBinding = -1;
ubufSize = 0;
ubufStages = { };
- memset(combinedImageSamplerBindings, 0, sizeof(combinedImageSamplerBindings));
+ memset(static_cast<void *>(combinedImageSamplerBindings), 0, sizeof(combinedImageSamplerBindings));
vertexShader = fragmentShader = nullptr;
masterUniformData.clear();
diff --git a/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp b/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
index 9282b6c308..c7af996a30 100644
--- a/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
@@ -130,7 +130,7 @@ void OpenGLVisualizer::visualizeBatch(Batch *b)
if (b->merged) {
shader->setUniformValue(shader->matrix, matrix);
- const char *dataStart = m_renderer->m_context->separateIndexBuffer() ? b->ibo.data : b->vbo.data;
+ const char *dataStart = b->ibo.data;
for (int ds=0; ds<b->drawSets.size(); ++ds) {
const DrawSet &set = b->drawSets.at(ds);
m_funcs->glVertexAttribPointer(a.position, 2, a.type, false, g->sizeOfVertex(),
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 742a4d03b2..04f1f2732c 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -465,9 +465,9 @@ public:
{
return pixelSize / QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution);
}
- int distanceFieldRadius() const
+ qreal distanceFieldRadius() const
{
- return QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
+ return QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
}
int glyphCount() const { return m_glyphCount; }
bool doubleGlyphResolution() const { return m_doubleGlyphResolution; }
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 3c60f830de..d6834b554e 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -119,7 +119,8 @@ public:
protected:
void initialize() override;
- int m_matrix_id;
+ int m_projectionMatrix_id;
+ int m_modelViewMatrix_id;
int m_color_id;
int m_textureScale_id;
float m_devicePixelRatio;
@@ -135,7 +136,8 @@ char const *const *QSGTextMaskShader::attributeNames() const
QSGTextMaskShader::QSGTextMaskShader(QFontEngine::GlyphFormat glyphFormat)
: QSGMaterialShader(*new QSGMaterialShaderPrivate)
- , m_matrix_id(-1)
+ , m_projectionMatrix_id(-1)
+ , m_modelViewMatrix_id(-1)
, m_color_id(-1)
, m_textureScale_id(-1)
, m_glyphFormat(glyphFormat)
@@ -146,7 +148,8 @@ QSGTextMaskShader::QSGTextMaskShader(QFontEngine::GlyphFormat glyphFormat)
void QSGTextMaskShader::initialize()
{
- m_matrix_id = program()->uniformLocation("matrix");
+ m_projectionMatrix_id = program()->uniformLocation("projectionMatrix");
+ m_modelViewMatrix_id = program()->uniformLocation("modelViewMatrix");
m_color_id = program()->uniformLocation("color");
m_textureScale_id = program()->uniformLocation("textureScale");
m_devicePixelRatio = (float) qsg_device_pixel_ratio(QOpenGLContext::currentContext());
@@ -184,8 +187,10 @@ void QSGTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEf
program()->setUniformValue("dpr", m_devicePixelRatio);
}
- if (state.isMatrixDirty())
- program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ if (state.isMatrixDirty()) {
+ program()->setUniformValue(m_projectionMatrix_id, state.projectionMatrix());
+ program()->setUniformValue(m_modelViewMatrix_id, state.modelViewMatrix());
+ }
}
class QSG8BitTextMaskShader : public QSGTextMaskShader
@@ -387,8 +392,10 @@ void QSGStyledTextShader::updateState(const RenderState &state,
}
}
- if (state.isMatrixDirty())
- program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ if (state.isMatrixDirty()) {
+ program()->setUniformValue(m_projectionMatrix_id, state.projectionMatrix());
+ program()->setUniformValue(m_modelViewMatrix_id, state.modelViewMatrix());
+ }
}
class QSGOutlinedTextShader : public QSGStyledTextShader
@@ -428,6 +435,18 @@ QSGTextMaskRhiShader::QSGTextMaskRhiShader(QFontEngine::GlyphFormat glyphFormat)
QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/textmask.frag.qsb"));
}
+enum UbufOffset {
+ ModelViewMatrixOffset = 0,
+ ProjectionMatrixOffset = ModelViewMatrixOffset + 64,
+ ColorOffset = ProjectionMatrixOffset + 64,
+ TextureScaleOffset = ColorOffset + 16,
+ DprOffset = TextureScaleOffset + 8,
+
+ // + 1 float padding (vec4 must be aligned to 16)
+ StyleColorOffset = DprOffset + 4 + 4,
+ ShiftOffset = StyleColorOffset + 16
+};
+
bool QSGTextMaskRhiShader::updateUniformData(RenderState &state,
QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
{
@@ -443,11 +462,14 @@ bool QSGTextMaskRhiShader::updateUniformData(RenderState &state,
bool changed = false;
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 92);
+ Q_ASSERT(buf->size() >= DprOffset + 4);
if (state.isMatrixDirty()) {
- const QMatrix4x4 m = state.combinedMatrix();
- memcpy(buf->data(), m.constData(), 64);
+ const QMatrix4x4 mv = state.modelViewMatrix();
+ memcpy(buf->data() + ModelViewMatrixOffset, mv.constData(), 64);
+ const QMatrix4x4 p = state.projectionMatrix();
+ memcpy(buf->data() + ProjectionMatrixOffset, p.constData(), 64);
+
changed = true;
}
@@ -456,13 +478,13 @@ bool QSGTextMaskRhiShader::updateUniformData(RenderState &state,
if (updated || !oldMat || oldRtex != newRtex) {
const QVector2D textureScale = QVector2D(1.0f / mat->rhiGlyphCache()->width(),
1.0f / mat->rhiGlyphCache()->height());
- memcpy(buf->data() + 64 + 16, &textureScale, 8);
+ memcpy(buf->data() + TextureScaleOffset, &textureScale, 8);
changed = true;
}
if (!oldMat) {
float dpr = state.devicePixelRatio();
- memcpy(buf->data() + 64 + 16 + 8, &dpr, 4);
+ memcpy(buf->data() + DprOffset, &dpr, 4);
}
// move texture uploads/copies onto the renderer's soon-to-be-committed list
@@ -510,11 +532,11 @@ bool QSG8BitTextMaskRhiShader::updateUniformData(RenderState &state,
QSGTextMaskMaterial *oldMat = static_cast<QSGTextMaskMaterial *>(oldMaterial);
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 80);
+ Q_ASSERT(buf->size() >= ColorOffset + 16);
if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) {
const QVector4D color = qsg_premultiply(mat->color(), state.opacity());
- memcpy(buf->data() + 64, &color, 16);
+ memcpy(buf->data() + ColorOffset, &color, 16);
changed = true;
}
@@ -553,12 +575,12 @@ bool QSG24BitTextMaskRhiShader::updateUniformData(RenderState &state,
QSGTextMaskMaterial *oldMat = static_cast<QSGTextMaskMaterial *>(oldMaterial);
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 92);
+ Q_ASSERT(buf->size() >= ColorOffset + 16);
if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) {
// shader takes vec4 but uses alpha only; coloring happens via the blend constant
const QVector4D color = qsg_premultiply(mat->color(), state.opacity());
- memcpy(buf->data() + 64, &color, 16);
+ memcpy(buf->data() + ColorOffset, &color, 16);
changed = true;
}
@@ -608,12 +630,12 @@ bool QSG32BitColorTextRhiShader::updateUniformData(RenderState &state,
QSGTextMaskMaterial *oldMat = static_cast<QSGTextMaskMaterial *>(oldMaterial);
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 92);
+ Q_ASSERT(buf->size() >= ColorOffset + 16);
if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) {
// shader takes vec4 but uses alpha only
const QVector4D color(0, 0, 0, mat->color().w() * state.opacity());
- memcpy(buf->data() + 64, &color, 16);
+ memcpy(buf->data() + ColorOffset, &color, 16);
changed = true;
}
@@ -649,20 +671,17 @@ bool QSGStyledTextRhiShader::updateUniformData(RenderState &state,
QSGStyledTextMaterial *oldMat = static_cast<QSGStyledTextMaterial *>(oldMaterial);
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 120);
-
- // matrix..dpr + 1 float padding (vec4 must be aligned to 16)
- const int startOffset = 64 + 16 + 8 + 4 + 4;
+ Q_ASSERT(buf->size() >= ShiftOffset + 8);
if (oldMat == nullptr || mat->styleColor() != oldMat->styleColor() || state.isOpacityDirty()) {
const QVector4D styleColor = qsg_premultiply(mat->styleColor(), state.opacity());
- memcpy(buf->data() + startOffset, &styleColor, 16);
+ memcpy(buf->data() + StyleColorOffset, &styleColor, 16);
changed = true;
}
if (oldMat == nullptr || oldMat->styleShift() != mat->styleShift()) {
const QVector2D v = mat->styleShift();
- memcpy(buf->data() + startOffset + 16, &v, 8);
+ memcpy(buf->data() + ShiftOffset, &v, 8);
changed = true;
}
@@ -799,8 +818,11 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
QTextureGlyphCache *cache = glyphCache();
QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
- cache->populate(fontD->fontEngine, glyphIndexes.size(), glyphIndexes.constData(),
- fixedPointPositions.data());
+ cache->populate(fontD->fontEngine,
+ glyphIndexes.size(),
+ glyphIndexes.constData(),
+ fixedPointPositions.data(),
+ true);
cache->fillInPendingGlyphs();
int margin = fontD->fontEngine->glyphMargin(cache->glyphFormat());
@@ -820,9 +842,11 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
for (int i=0; i<glyphIndexes.size(); ++i) {
QPointF glyphPosition = glyphPositions.at(i) + position;
+ QFixedPoint fixedPointPosition = fixedPointPositions.at(i);
+
QFixed subPixelPosition;
if (supportsSubPixelPositions)
- subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPosition.x()));
+ subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(fixedPointPosition.x.toReal() * glyphCacheScaleX));
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
index bf7bb052bb..0e11a062de 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
@@ -415,21 +415,6 @@ QSGDefaultRenderContext *QSGDefaultRenderContext::from(QOpenGLContext *context)
return qobject_cast<QSGDefaultRenderContext *>(context->property(QSG_RENDERCONTEXT_PROPERTY).value<QObject *>());
}
-bool QSGDefaultRenderContext::separateIndexBuffer() const
-{
- if (m_rhi)
- return true;
-
- // WebGL: A given WebGLBuffer object may only be bound to one of
- // the ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER target in its
- // lifetime. An attempt to bind a buffer object to the other
- // target will generate an INVALID_OPERATION error, and the
- // current binding will remain untouched.
- static const bool isWebGL = (qGuiApp->platformName().compare(QLatin1String("webgl")) == 0
- || qGuiApp->platformName().compare(QLatin1String("wasm")) == 0);
- return isWebGL;
-}
-
void QSGDefaultRenderContext::preprocess()
{
for (auto it = m_glyphCaches.begin(); it != m_glyphCaches.end(); ++it) {
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
index e90a11eda6..6da67264d1 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext_p.h
+++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
@@ -140,7 +140,6 @@ public:
bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; }
int maxTextureSize() const override { return m_maxTextureSize; }
- bool separateIndexBuffer() const;
int msaaSampleCount() const { return m_initParams.sampleCount; }
diff --git a/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp
index b6b6f3b057..6e9894b10b 100644
--- a/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp
@@ -122,7 +122,7 @@ void QSGOpenGLDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs
// We need to add a buffer to avoid glyphs that overlap the border between two
// textures causing the height of the textures to extend beyond the limit.
- m_maxTextureHeight = m_maxTextureWidth - (qCeil(m_referenceFont.pixelSize() * scaleFactor) + distanceFieldRadius() * 2 + padding * 2);
+ m_maxTextureHeight = m_maxTextureWidth - (qCeil(m_referenceFont.pixelSize() * scaleFactor + distanceFieldRadius() * 2) + padding * 2);
}
if (m_areaAllocator == nullptr)
@@ -132,8 +132,8 @@ void QSGOpenGLDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs
glyph_t glyphIndex = *it;
QRectF boundingRect = glyphData(glyphIndex).boundingRect;
- int glyphWidth = qCeil(boundingRect.width()) + distanceFieldRadius() * 2;
- int glyphHeight = qCeil(boundingRect.height()) + distanceFieldRadius() * 2;
+ int glyphWidth = qCeil(boundingRect.width() + distanceFieldRadius()) * 2;
+ int glyphHeight = qCeil(boundingRect.height() + distanceFieldRadius()) * 2;
QSize glyphSize(glyphWidth + padding * 2, glyphHeight + padding * 2);
QRect alloc = m_areaAllocator->allocate(glyphSize);
@@ -144,8 +144,8 @@ void QSGOpenGLDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs
TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
QRectF unusedGlyphBoundingRect = glyphData(unusedGlyph).boundingRect;
- int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width()) + distanceFieldRadius() * 2;
- int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height()) + distanceFieldRadius() * 2;
+ int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width() + distanceFieldRadius()) * 2;
+ int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height() + distanceFieldRadius()) * 2;
m_areaAllocator->deallocate(QRect(unusedCoord.x - padding,
unusedCoord.y - padding,
padding * 2 + unusedGlyphWidth,
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index c96129e660..ee01211545 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -413,13 +413,6 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
qCDebug(QSG_LOG_RENDERLOOP, "cleanup without an OpenGL context");
}
-#if QT_CONFIG(quick_shadereffect)
- QSGRhiShaderEffectNode::cleanupMaterialTypeCache();
-#if QT_CONFIG(opengl)
- QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
-#endif
-#endif
-
if (d->swapchain) {
if (window->handle()) {
// We get here when exiting via QCoreApplication::quit() instead of
@@ -432,6 +425,14 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
}
d->cleanupNodesOnShutdown();
+
+#if QT_CONFIG(quick_shadereffect)
+ QSGRhiShaderEffectNode::cleanupMaterialTypeCache();
+#if QT_CONFIG(opengl)
+ QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
+#endif
+#endif
+
if (m_windows.size() == 0) {
rc->invalidate();
d->rhi = nullptr;
diff --git a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
index 53b6fe117f..2325a2665b 100644
--- a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
@@ -86,8 +86,8 @@ void QSGRhiDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs)
int padding = QSG_RHI_DISTANCEFIELD_GLYPH_CACHE_PADDING;
QRectF boundingRect = glyphData(glyphIndex).boundingRect;
- int glyphWidth = qCeil(boundingRect.width()) + distanceFieldRadius() * 2;
- int glyphHeight = qCeil(boundingRect.height()) + distanceFieldRadius() * 2;
+ int glyphWidth = qCeil(boundingRect.width() + distanceFieldRadius() * 2);
+ int glyphHeight = qCeil(boundingRect.height() + distanceFieldRadius() * 2);
QSize glyphSize(glyphWidth + padding * 2, glyphHeight + padding * 2);
QRect alloc = m_areaAllocator->allocate(glyphSize);
@@ -98,8 +98,8 @@ void QSGRhiDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs)
TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
QRectF unusedGlyphBoundingRect = glyphData(unusedGlyph).boundingRect;
- int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width()) + distanceFieldRadius() * 2;
- int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height()) + distanceFieldRadius() * 2;
+ int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width() + distanceFieldRadius() * 2);
+ int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height() + distanceFieldRadius() * 2);
m_areaAllocator->deallocate(QRect(unusedCoord.x - padding,
unusedCoord.y - padding,
padding * 2 + unusedGlyphWidth,
@@ -446,7 +446,7 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
const char *textureRecord = allocatorData;
for (int i = 0; i < textureCount; ++i, textureRecord += Qtdf::TextureRecordSize) {
- if (textureRecord + Qtdf::TextureRecordSize > qtdfTableEnd) {
+ if (qtdfTableEnd - textureRecord < Qtdf::TextureRecordSize) {
qWarning("qtdf table too small in font '%s'.",
qPrintable(font.familyName()));
return false;
@@ -462,7 +462,7 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
const char *glyphRecord = textureRecord;
for (quint32 i = 0; i < glyphCount; ++i, glyphRecord += Qtdf::GlyphRecordSize) {
- if (glyphRecord + Qtdf::GlyphRecordSize > qtdfTableEnd) {
+ if (qtdfTableEnd - glyphRecord < Qtdf:: GlyphRecordSize) {
qWarning("qtdf table too small in font '%s'.",
qPrintable(font.familyName()));
return false;
@@ -512,8 +512,8 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
int width = texInfo->allocatedArea.width();
int height = texInfo->allocatedArea.height();
- qint64 size = width * height;
- if (reinterpret_cast<const char *>(textureData + size) > qtdfTableEnd) {
+ qint64 size = qint64(width) * height;
+ if (qtdfTableEnd - reinterpret_cast<const char *>(textureData) < size) {
qWarning("qtdf table too small in font '%s'.",
qPrintable(font.familyName()));
return false;
diff --git a/src/quick/scenegraph/qsgrhishadereffectnode.cpp b/src/quick/scenegraph/qsgrhishadereffectnode.cpp
index e86dae7c09..b0d3ca78f5 100644
--- a/src/quick/scenegraph/qsgrhishadereffectnode.cpp
+++ b/src/quick/scenegraph/qsgrhishadereffectnode.cpp
@@ -572,10 +572,10 @@ void QSGRhiShaderEffectMaterial::updateTextureProviders(bool layoutChange)
QSGRhiShaderEffectNode::QSGRhiShaderEffectNode(QSGDefaultRenderContext *rc, QSGRhiGuiThreadShaderEffectManager *mgr)
: QSGShaderEffectNode(mgr),
- m_rc(rc),
m_mgr(mgr),
m_material(this)
{
+ Q_UNUSED(rc);
setFlag(UsePreprocess, true);
setMaterial(&m_material);
}
@@ -884,3 +884,5 @@ bool QSGRhiGuiThreadShaderEffectManager::reflect(ShaderInfo *result)
}
QT_END_NAMESPACE
+
+#include "moc_qsgrhishadereffectnode_p.cpp"
diff --git a/src/quick/scenegraph/qsgrhishadereffectnode_p.h b/src/quick/scenegraph/qsgrhishadereffectnode_p.h
index 26460d24b2..3c382743ee 100644
--- a/src/quick/scenegraph/qsgrhishadereffectnode_p.h
+++ b/src/quick/scenegraph/qsgrhishadereffectnode_p.h
@@ -139,7 +139,6 @@ private Q_SLOTS:
void handleTextureProviderDestroyed(QObject *object);
private:
- QSGDefaultRenderContext *m_rc;
QSGRhiGuiThreadShaderEffectManager *m_mgr;
QSGRhiShaderEffectMaterial m_material;
};
diff --git a/src/quick/scenegraph/qsgrhitextureglyphcache.cpp b/src/quick/scenegraph/qsgrhitextureglyphcache.cpp
index 89c9ea4d5b..c35d5b0705 100644
--- a/src/quick/scenegraph/qsgrhitextureglyphcache.cpp
+++ b/src/quick/scenegraph/qsgrhitextureglyphcache.cpp
@@ -233,7 +233,10 @@ void QSGRhiTextureGlyphCache::endFillTexture()
int QSGRhiTextureGlyphCache::glyphPadding() const
{
- return 1;
+ if (m_format == QFontEngine::Format_Mono)
+ return 8;
+ else
+ return 1;
}
int QSGRhiTextureGlyphCache::maxTextureWidth() const
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 1c72c4dba6..d47b0d72a5 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -547,17 +547,16 @@ void QSGRenderThread::invalidateGraphics(QQuickWindow *window, bool inDestructor
QQuickWindowPrivate *dd = QQuickWindowPrivate::get(window);
+ // The canvas nodes must be cleaned up regardless if we are in the destructor..
+ if (wipeSG) {
+ dd->cleanupNodesOnShutdown();
#if QT_CONFIG(quick_shadereffect)
- QSGRhiShaderEffectNode::cleanupMaterialTypeCache();
+ QSGRhiShaderEffectNode::cleanupMaterialTypeCache();
#if QT_CONFIG(opengl)
- if (current)
- QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
+ if (current)
+ QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
#endif
#endif
-
- // The canvas nodes must be cleaned up regardless if we are in the destructor..
- if (wipeSG) {
- dd->cleanupNodesOnShutdown();
} else {
qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- persistent SG, avoiding cleanup");
if (current && gl)
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 20d7c4557f..20e127c49f 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -256,12 +256,13 @@ void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window)
if (Q_UNLIKELY(!current))
RLDEBUG("cleanup without an OpenGL context");
+ d->cleanupNodesOnShutdown();
+
#if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl)
if (current)
QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
#endif
- d->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
d->context->invalidate();
delete m_gl;
diff --git a/src/quick/scenegraph/shaders/outlinedtext.vert b/src/quick/scenegraph/shaders/outlinedtext.vert
index 9df832de3c..42fa577063 100644
--- a/src/quick/scenegraph/shaders/outlinedtext.vert
+++ b/src/quick/scenegraph/shaders/outlinedtext.vert
@@ -1,4 +1,5 @@
-uniform highp mat4 matrix;
+uniform highp mat4 modelViewMatrix;
+uniform highp mat4 projectionMatrix;
uniform highp vec2 textureScale;
uniform highp vec2 shift;
uniform highp float dpr;
@@ -19,6 +20,6 @@ void main()
sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale;
sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale;
sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
-} \ No newline at end of file
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
+}
diff --git a/src/quick/scenegraph/shaders/outlinedtext_core.vert b/src/quick/scenegraph/shaders/outlinedtext_core.vert
index a854355460..50a1371e89 100644
--- a/src/quick/scenegraph/shaders/outlinedtext_core.vert
+++ b/src/quick/scenegraph/shaders/outlinedtext_core.vert
@@ -9,7 +9,8 @@ out vec2 sCoordDown;
out vec2 sCoordLeft;
out vec2 sCoordRight;
-uniform mat4 matrix;
+uniform mat4 modelViewMatrix;
+uniform mat4 projectionMatrix;
uniform vec2 textureScale;
uniform vec2 shift;
uniform float dpr;
@@ -21,6 +22,6 @@ void main()
sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale;
sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale;
sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
-} \ No newline at end of file
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
+}
diff --git a/src/quick/scenegraph/shaders/styledtext.vert b/src/quick/scenegraph/shaders/styledtext.vert
index 29c9902609..dc87dadd5f 100644
--- a/src/quick/scenegraph/shaders/styledtext.vert
+++ b/src/quick/scenegraph/shaders/styledtext.vert
@@ -1,4 +1,5 @@
-uniform highp mat4 matrix;
+uniform highp mat4 modelViewMatrix;
+uniform highp mat4 projectionMatrix;
uniform highp vec2 textureScale;
uniform highp vec2 shift;
uniform highp float dpr;
@@ -13,6 +14,6 @@ void main()
{
sampleCoord = tCoord * textureScale;
shiftedSampleCoord = (tCoord - shift) * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders/styledtext_core.vert b/src/quick/scenegraph/shaders/styledtext_core.vert
index 04a0e88da8..d9a81bf06f 100644
--- a/src/quick/scenegraph/shaders/styledtext_core.vert
+++ b/src/quick/scenegraph/shaders/styledtext_core.vert
@@ -6,7 +6,8 @@ in vec2 tCoord;
out vec2 sampleCoord;
out vec2 shiftedSampleCoord;
-uniform mat4 matrix;
+uniform mat4 modelViewMatrix;
+uniform mat4 projectionMatrix;
uniform vec2 textureScale;
uniform vec2 shift;
uniform float dpr;
@@ -15,6 +16,6 @@ void main()
{
sampleCoord = tCoord * textureScale;
shiftedSampleCoord = (tCoord - shift) * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders/textmask.vert b/src/quick/scenegraph/shaders/textmask.vert
index 1692159d2c..7f418b0895 100644
--- a/src/quick/scenegraph/shaders/textmask.vert
+++ b/src/quick/scenegraph/shaders/textmask.vert
@@ -1,4 +1,5 @@
-uniform highp mat4 matrix;
+uniform highp mat4 modelViewMatrix;
+uniform highp mat4 projectionMatrix;
uniform highp vec2 textureScale;
uniform highp float dpr;
@@ -10,6 +11,6 @@ varying highp vec2 sampleCoord;
void main()
{
sampleCoord = tCoord * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders/textmask_core.vert b/src/quick/scenegraph/shaders/textmask_core.vert
index b0efc1e731..1f88974aed 100644
--- a/src/quick/scenegraph/shaders/textmask_core.vert
+++ b/src/quick/scenegraph/shaders/textmask_core.vert
@@ -5,13 +5,14 @@ in vec2 tCoord;
out vec2 sampleCoord;
-uniform mat4 matrix;
+uniform mat4 modelViewMatrix;
+uniform mat4 projectionMatrix;
uniform vec2 textureScale;
uniform float dpr;
void main()
{
sampleCoord = tCoord * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders_ng/24bittextmask.frag b/src/quick/scenegraph/shaders_ng/24bittextmask.frag
index bc3826a924..ed8da4cd30 100644
--- a/src/quick/scenegraph/shaders_ng/24bittextmask.frag
+++ b/src/quick/scenegraph/shaders_ng/24bittextmask.frag
@@ -6,8 +6,9 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- vec4 color; // only alpha is used, but must be vec4 due to layout compat
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
+ vec4 color;
vec2 textureScale;
float dpr;
} ubuf;
diff --git a/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb b/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
index c493996375..6eee3f01d6 100644
--- a/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag
index 63e445f90b..4198a4d339 100644
--- a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag
+++ b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag
@@ -6,8 +6,9 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- vec4 color; // only alpha is used, but must be vec4 due to layout compat
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
+ vec4 color;
vec2 textureScale;
float dpr;
} ubuf;
diff --git a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
index 3f8489bfe6..d81bb2f26d 100644
--- a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask.frag b/src/quick/scenegraph/shaders_ng/8bittextmask.frag
index 6304e821ff..a06743876d 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask.frag
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask.frag
@@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb b/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
index f721207325..6ebb3342ac 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag
index 0d0fa1cd3a..f725cbc5e7 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag
@@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
index 93ac0124be..e29f734c33 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.frag b/src/quick/scenegraph/shaders_ng/outlinedtext.frag
index 947d161a50..e2f82d3845 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.frag
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.frag
@@ -11,11 +11,12 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- // must match styledtext
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
+ // the above must stay compatible with textmask/8bittextmask
vec4 styleColor;
vec2 shift;
} ubuf;
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
index 1756ee9d4b..071abd2f88 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.vert b/src/quick/scenegraph/shaders_ng/outlinedtext.vert
index 023f9dfdc2..4068e42f28 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.vert
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.vert
@@ -10,11 +10,12 @@ layout(location = 3) out vec2 sCoordLeft;
layout(location = 4) out vec2 sCoordRight;
layout(std140, binding = 0) uniform buf {
- // must match styledtext
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
+ // the above must stay compatible with textmask/8bittextmask
vec4 styleColor;
vec2 shift;
} ubuf;
@@ -28,6 +29,6 @@ void main()
sCoordDown = (tCoord - vec2(0.0, 1.0)) * ubuf.textureScale;
sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * ubuf.textureScale;
sCoordRight = (tCoord - vec2(1.0, 0.0)) * ubuf.textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr;
- gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = ubuf.modelViewMatrix * vCoord;
+ gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
index b8d38bdff4..dd159d008d 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag
index 5b7bd9ca82..274d891a3c 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag
@@ -11,11 +11,12 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- // must match styledtext
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
+ // the above must stay compatible with textmask/8bittextmask
vec4 styleColor;
vec2 shift;
} ubuf;
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
index f44b92dc28..393b1608e9 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.frag b/src/quick/scenegraph/shaders_ng/styledtext.frag
index 0b16396037..2e380dfeae 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.frag
+++ b/src/quick/scenegraph/shaders_ng/styledtext.frag
@@ -8,7 +8,8 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb b/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
index b0461a686c..5b45142201 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.vert b/src/quick/scenegraph/shaders_ng/styledtext.vert
index beadf07c79..271dae8d8a 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.vert
+++ b/src/quick/scenegraph/shaders_ng/styledtext.vert
@@ -7,7 +7,8 @@ layout(location = 0) out vec2 sampleCoord;
layout(location = 1) out vec2 shiftedSampleCoord;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
@@ -22,6 +23,6 @@ void main()
{
sampleCoord = tCoord * ubuf.textureScale;
shiftedSampleCoord = (tCoord - ubuf.shift) * ubuf.textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr;
- gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = ubuf.modelViewMatrix * vCoord;
+ gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb b/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
index 18e4685d21..e2a5859bfc 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext_a.frag b/src/quick/scenegraph/shaders_ng/styledtext_a.frag
index b673137895..62e162c851 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext_a.frag
+++ b/src/quick/scenegraph/shaders_ng/styledtext_a.frag
@@ -8,7 +8,8 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
diff --git a/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
index 3d9b5a0bdd..c3aa6c068a 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/textmask.frag b/src/quick/scenegraph/shaders_ng/textmask.frag
index 518d5c965f..ed8da4cd30 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.frag
+++ b/src/quick/scenegraph/shaders_ng/textmask.frag
@@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
diff --git a/src/quick/scenegraph/shaders_ng/textmask.frag.qsb b/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
index cfae9575da..a4341d8915 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/textmask.vert b/src/quick/scenegraph/shaders_ng/textmask.vert
index 9d80d5dadb..e0b3c01bce 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.vert
+++ b/src/quick/scenegraph/shaders_ng/textmask.vert
@@ -6,7 +6,8 @@ layout(location = 1) in vec2 tCoord;
layout(location = 0) out vec2 sampleCoord;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
@@ -17,6 +18,6 @@ out gl_PerVertex { vec4 gl_Position; };
void main()
{
sampleCoord = tCoord * ubuf.textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr;
- gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = ubuf.modelViewMatrix * vCoord;
+ gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders_ng/textmask.vert.qsb b/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
index 2ea425e1c0..4ca3b874d0 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/util/qsgplaintexture.cpp b/src/quick/scenegraph/util/qsgplaintexture.cpp
index f00918bb4e..7c3cf90325 100644
--- a/src/quick/scenegraph/util/qsgplaintexture.cpp
+++ b/src/quick/scenegraph/util/qsgplaintexture.cpp
@@ -466,3 +466,5 @@ void QSGPlainTexturePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch
}
QT_END_NAMESPACE
+
+#include "moc_qsgplaintexture_p.cpp"
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index e5e25d141b..4cf019c7f0 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -1996,7 +1996,7 @@ void QQuickPropertyAnimationPrivate::convertVariant(QVariant &variant, int type)
}
QQuickBulkValueAnimator::QQuickBulkValueAnimator()
- : QAbstractAnimationJob(), animValue(nullptr), fromSourced(nullptr), m_duration(250)
+ : QAbstractAnimationJob(), animValue(nullptr), fromIsSourced(nullptr), m_duration(250)
{
}
@@ -2026,8 +2026,8 @@ void QQuickBulkValueAnimator::updateCurrentTime(int currentTime)
void QQuickBulkValueAnimator::topLevelAnimationLoopChanged()
{
//check for new from every top-level loop (when the top level animation is started and all subsequent loops)
- if (fromSourced)
- *fromSourced = false;
+ if (fromIsSourced)
+ *fromIsSourced = false;
QAbstractAnimationJob::topLevelAnimationLoopChanged();
}
@@ -2596,7 +2596,7 @@ void QQuickAnimationPropertyUpdater::setValue(qreal v)
if (v == 1.) {
QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
} else {
- if (!fromSourced && !fromDefined) {
+ if (!fromIsSourced && !fromIsDefined) {
action.fromValue = action.property.read();
if (interpolatorType) {
QQuickPropertyAnimationPrivate::convertVariant(action.fromValue, interpolatorType);
@@ -2616,7 +2616,7 @@ void QQuickAnimationPropertyUpdater::setValue(qreal v)
return;
}
wasDeleted = nullptr;
- fromSourced = true;
+ fromIsSourced = true;
}
void QQuickAnimationPropertyUpdater::debugUpdater(QDebug d, int indentLevel) const
@@ -2760,11 +2760,11 @@ QAbstractAnimationJob* QQuickPropertyAnimation::transition(QQuickStateActions &a
data->interpolatorType = d->interpolatorType;
data->interpolator = d->interpolator;
data->reverse = direction == Backward ? true : false;
- data->fromSourced = false;
- data->fromDefined = d->fromIsDefined;
+ data->fromIsSourced = false;
+ data->fromIsDefined = d->fromIsDefined;
data->actions = dataActions;
animator->setAnimValue(data);
- animator->setFromSourcedValue(&data->fromSourced);
+ animator->setFromIsSourcedValue(&data->fromIsSourced);
d->actions = &data->actions; //remove this?
}
diff --git a/src/quick/util/qquickanimation_p_p.h b/src/quick/util/qquickanimation_p_p.h
index 8d23242b68..f785bf6623 100644
--- a/src/quick/util/qquickanimation_p_p.h
+++ b/src/quick/util/qquickanimation_p_p.h
@@ -135,7 +135,7 @@ public:
void setAnimValue(QQuickBulkValueUpdater *value);
QQuickBulkValueUpdater *getAnimValue() const { return animValue; }
- void setFromSourcedValue(bool *value) { fromSourced = value; }
+ void setFromIsSourcedValue(bool *value) { fromIsSourced = value; }
int duration() const override { return m_duration; }
void setDuration(int msecs) { m_duration = msecs; }
@@ -150,7 +150,7 @@ protected:
private:
QQuickBulkValueUpdater *animValue;
- bool *fromSourced;
+ bool *fromIsSourced;
int m_duration;
QEasingCurve easing;
};
@@ -311,7 +311,7 @@ public:
class Q_AUTOTEST_EXPORT QQuickAnimationPropertyUpdater : public QQuickBulkValueUpdater
{
public:
- QQuickAnimationPropertyUpdater() : interpolatorType(0), interpolator(nullptr), prevInterpolatorType(0), reverse(false), fromSourced(false), fromDefined(false), wasDeleted(nullptr) {}
+ QQuickAnimationPropertyUpdater() : interpolatorType(0), interpolator(nullptr), prevInterpolatorType(0), reverse(false), fromIsSourced(false), fromIsDefined(false), wasDeleted(nullptr) {}
~QQuickAnimationPropertyUpdater() override;
void setValue(qreal v) override;
@@ -323,8 +323,8 @@ public:
QVariantAnimation::Interpolator interpolator;
int prevInterpolatorType; //for generic
bool reverse;
- bool fromSourced;
- bool fromDefined;
+ bool fromIsSourced;
+ bool fromIsDefined;
bool *wasDeleted;
};
diff --git a/src/quick/util/qquickanimator.cpp b/src/quick/util/qquickanimator.cpp
index d1ff78f8bc..e2a9c33adf 100644
--- a/src/quick/util/qquickanimator.cpp
+++ b/src/quick/util/qquickanimator.cpp
@@ -176,7 +176,7 @@ void QQuickAnimator::setTo(qreal to)
Q_D(QQuickAnimator);
if (to == d->to)
return;
- d->isToDefined = true;
+ d->toIsDefined = true;
d->to = to;
Q_EMIT toChanged(d->to);
}
@@ -204,7 +204,7 @@ void QQuickAnimator::setFrom(qreal from)
Q_D(QQuickAnimator);
if (from == d->from)
return;
- d->isFromDefined = true;
+ d->fromIsDefined = true;
d->from = from;
Q_EMIT fromChanged(d->from);
}
@@ -231,14 +231,14 @@ void QQuickAnimatorPrivate::apply(QQuickAnimatorJob *job,
job->setTarget(qobject_cast<QQuickItem *>(action.property.object()));
- if (isFromDefined)
+ if (fromIsDefined)
job->setFrom(from);
else if (action.fromValue.isValid())
job->setFrom(action.fromValue.toReal());
else
job->setFrom(action.property.read().toReal());
- if (isToDefined)
+ if (toIsDefined)
job->setTo(to);
else if (action.toValue.isValid())
job->setTo(action.toValue.toReal());
diff --git a/src/quick/util/qquickanimator_p_p.h b/src/quick/util/qquickanimator_p_p.h
index b176119c70..33e202c522 100644
--- a/src/quick/util/qquickanimator_p_p.h
+++ b/src/quick/util/qquickanimator_p_p.h
@@ -68,8 +68,8 @@ public:
, duration(250)
, from(0)
, to(0)
- , isFromDefined(false)
- , isToDefined(false)
+ , fromIsDefined(false)
+ , toIsDefined(false)
{
}
@@ -79,8 +79,8 @@ public:
qreal from;
qreal to;
- uint isFromDefined : 1;
- uint isToDefined : 1;
+ uint fromIsDefined : 1;
+ uint toIsDefined : 1;
void apply(QQuickAnimatorJob *job, const QString &propertyName, QQuickStateActions &actions, QQmlProperties &modified, QObject *defaultTarget);
};
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 2ae8a5a2aa..f027e9fafe 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -285,6 +285,17 @@ qreal QQuickAnimatorJob::progress(int time) const
return m_easing.valueForProgress((m_duration == 0) ? qreal(1) : qreal(time) / qreal(m_duration));
}
+void QQuickAnimatorJob::boundValue()
+{
+ qreal rangeMin = m_from;
+ qreal rangeMax = m_to;
+ if (m_from > m_to) {
+ rangeMax = m_from;
+ rangeMin = m_to;
+ }
+ m_value = qBound(rangeMin, m_value, rangeMax);
+}
+
qreal QQuickAnimatorJob::value() const
{
qreal value = m_to;
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index 522540bcbc..a31cd08032 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -122,10 +122,16 @@ public:
virtual void setTarget(QQuickItem *target);
QQuickItem *target() const { return m_target; }
- void setFrom(qreal from) { m_from = from; }
+ void setFrom(qreal from) {
+ m_from = from;
+ boundValue();
+ }
qreal from() const { return m_from; }
- void setTo(qreal to) { m_to = to; }
+ void setTo(qreal to) {
+ m_to = to;
+ boundValue();
+ }
qreal to() const { return m_to; }
void setDuration(int duration) { m_duration = duration; }
@@ -171,6 +177,7 @@ protected:
void debugAnimation(QDebug d) const override;
qreal progress(int time) const;
+ void boundValue();
QPointer<QQuickItem> m_target;
QQuickAnimatorController *m_controller;
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index 74ee52b1d3..c39e1f5b8b 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -107,12 +107,13 @@ QT_BEGIN_NAMESPACE
\li PathPolyline
\li Yes
\li Yes
+ \li No
\li Yes
- \li Yes
- \li PathMultiLine
- \li Yes
+ \row
+ \li PathMultiLine
\li Yes
\li Yes
+ \li No
\li Yes
\row
\li PathQuad
diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp
index 1cb30f5a8d..7a47f132fe 100644
--- a/src/quick/util/qquickpropertychanges.cpp
+++ b/src/quick/util/qquickpropertychanges.cpp
@@ -239,18 +239,22 @@ public:
void QQuickPropertyChangesParser::verifyList(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
{
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- error(compilationUnit->objectAt(binding->value.objectIndex), QQuickPropertyChanges::tr("PropertyChanges does not support creating state-specific objects."));
- return;
- }
-
- if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
- || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Object:
+ error(compilationUnit->objectAt(binding->value.objectIndex),
+ QQuickPropertyChanges::tr(
+ "PropertyChanges does not support creating state-specific objects."));
+ break;
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ case QV4::CompiledData::Binding::Type_AttachedProperty: {
const QV4::CompiledData::Object *subObj = compilationUnit->objectAt(binding->value.objectIndex);
const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
- for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) {
+ for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding)
verifyList(compilationUnit, subBinding);
- }
+ break;
+ }
+ default:
+ break;
}
}
@@ -273,8 +277,9 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
QString propertyName = propertyPrefix + compilationUnit->stringAt(binding->propertyNameIndex);
- if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
- || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ case QV4::CompiledData::Binding::Type_AttachedProperty: {
QString pre = propertyName + QLatin1Char('.');
const QV4::CompiledData::Object *subObj = compilationUnit->objectAt(binding->value.objectIndex);
const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
@@ -283,6 +288,9 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
}
return;
}
+ default:
+ break;
+ }
if (propertyName.count() >= 3 &&
propertyName.at(0) == QLatin1Char('o') &&
@@ -299,7 +307,8 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
}
}
- if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Script
+ || binding->isTranslationBinding()) {
QUrl url = QUrl();
int line = -1;
int column = -1;
@@ -323,7 +332,7 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
}
QVariant var;
- switch (binding->type) {
+ switch (binding->type()) {
case QV4::CompiledData::Binding::Type_Script:
case QV4::CompiledData::Binding::Type_Translation:
case QV4::CompiledData::Binding::Type_TranslationById:
diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp
index 254b1af0a2..d511dc0562 100644
--- a/src/quick/util/qquicksmoothedanimation.cpp
+++ b/src/quick/util/qquicksmoothedanimation.cpp
@@ -569,4 +569,6 @@ void QQuickSmoothedAnimation::setMaximumEasingTime(int v)
QT_END_NAMESPACE
+#include "moc_qquicksmoothedanimation_p_p.cpp"
+
#include "moc_qquicksmoothedanimation_p.cpp"
diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp
index 2109aafc10..7cb3138618 100644
--- a/src/quick/util/qquickstategroup.cpp
+++ b/src/quick/util/qquickstategroup.cpp
@@ -376,7 +376,14 @@ bool QQuickStateGroupPrivate::updateAutoState()
QQuickState *state = states.at(ii);
if (state->isWhenKnown()) {
if (state->isNamed()) {
- if (state->when()) {
+ bool whenValue = state->when();
+ const QQmlProperty whenProp(state, QLatin1String("when"));
+ const auto potentialWhenBinding = QQmlPropertyPrivate::binding(whenProp);
+ // if there is a binding, the value in when might not be up-to-date at this point
+ // so we manually reevaluate the binding
+ if (auto abstractBinding = dynamic_cast<QQmlBinding *>(potentialWhenBinding))
+ whenValue = abstractBinding->evaluate().toBool();
+ if (whenValue) {
if (stateChangeDebug())
qWarning() << "Setting auto state due to expression";
if (currentState != state->name()) {
diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
index 660852ba83..a25af90414 100644
--- a/src/quick/util/qquickstyledtext.cpp
+++ b/src/quick/util/qquickstyledtext.cpp
@@ -46,6 +46,8 @@
#include "qquickstyledtext_p.h"
#include <QQmlContext>
+Q_LOGGING_CATEGORY(lcStyledText, "qt.quick.styledtext")
+
/*
QQuickStyledText supports few tags:
@@ -562,10 +564,14 @@ void QQuickStyledTextPrivate::parseEntity(const QChar *&ch, const QString &textI
textOut += QChar(60);
else if (entity == QLatin1String("amp"))
textOut += QChar(38);
+ else if (entity == QLatin1String("apos"))
+ textOut += QChar(39);
else if (entity == QLatin1String("quot"))
textOut += QChar(34);
else if (entity == QLatin1String("nbsp"))
textOut += QChar(QChar::Nbsp);
+ else
+ qCWarning(lcStyledText) << "StyledText doesn't support entity" << entity;
return;
} else if (*ch == QLatin1Char(' ')) {
QStringRef entity(&textIn, entityStart - 1, entityLength + 1);
diff --git a/src/quick/util/qquicktimeline.cpp b/src/quick/util/qquicktimeline.cpp
index 7ec7c827eb..949724e87c 100644
--- a/src/quick/util/qquicktimeline.cpp
+++ b/src/quick/util/qquicktimeline.cpp
@@ -53,6 +53,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcTl, "qt.quick.timeline")
+
struct Update {
Update(QQuickTimeLineValue *_g, qreal _v)
: g(_g), v(_v) {}
@@ -513,6 +515,7 @@ void QQuickTimeLine::reset(QQuickTimeLineValue &timeLineValue)
qWarning() << "QQuickTimeLine: Cannot reset a QQuickTimeLineValue owned by another timeline.";
return;
}
+ qCDebug(lcTl) << static_cast<QObject*>(this) << timeLineValue.value();
remove(&timeLineValue);
timeLineValue._t = nullptr;
}
@@ -954,3 +957,5 @@ QQuickTimeLineObject *QQuickTimeLineCallback::callbackObject() const
}
QT_END_NAMESPACE
+
+#include "moc_qquicktimeline_p_p.cpp"