aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-02-17 01:01:00 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-02-17 10:21:59 +0100
commit3e758800b4daf8fbc870a2ff5d54fce9d4402ce8 (patch)
treeba237b9da1c7dfd08bf13e71c5dbd6b3c2e77633 /src/quick
parent925a0e499a5dbdb180fd9969a79abf96006ce4fd (diff)
parent55546991e24ca6799709cbe0171b9ab87216c35f (diff)
Merge remote-tracking branch 'origin/5.15' into dev
Conflicts: src/imports/qtqml/plugin.cpp src/qml/qml/qqml.h src/qml/qml/qqmlmetatype.cpp src/qml/qml/qqmlmetatype_p.h src/qml/qml/qqmltypeloader.cpp src/qml/types/qqmlbind.cpp src/quick/items/qquickitemsmodule.cpp tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp Change-Id: I52548938a582cb6510271ed4bc3a9aa0c3c11df6
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/accessible/qaccessiblequickview.cpp8
-rw-r--r--src/quick/designer/qquickdesignersupportproperties.cpp8
-rw-r--r--src/quick/doc/snippets/qml/qml-data-models/listmodel-listview-required.qml81
-rw-r--r--src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc20
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc1
-rw-r--r--src/quick/handlers/qquickhandlerpoint.cpp5
-rw-r--r--src/quick/handlers/qquickhoverhandler.cpp19
-rw-r--r--src/quick/handlers/qquickhoverhandler_p.h1
-rw-r--r--src/quick/items/qquickevents.cpp162
-rw-r--r--src/quick/items/qquickevents_p_p.h71
-rw-r--r--src/quick/items/qquickflickable.cpp19
-rw-r--r--src/quick/items/qquickflickable_p_p.h2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp7
-rw-r--r--src/quick/items/qquickitemsmodule_p.h12
-rw-r--r--src/quick/items/qquickitemview.cpp2
-rw-r--r--src/quick/items/qquicklistview.cpp168
-rw-r--r--src/quick/items/qquickloader.cpp93
-rw-r--r--src/quick/items/qquickloader_p_p.h7
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp28
-rw-r--r--src/quick/items/qquickmultipointtoucharea_p.h4
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp4
-rw-r--r--src/quick/items/qquickspriteengine_p.h12
-rw-r--r--src/quick/items/qquickspritesequence.cpp4
-rw-r--r--src/quick/items/qquicktableview.cpp20
-rw-r--r--src/quick/items/qquicktableview_p_p.h2
-rw-r--r--src/quick/items/qquicktext.cpp7
-rw-r--r--src/quick/items/qquickwindow.cpp60
-rw-r--r--src/quick/items/qquickwindow.h3
-rw-r--r--src/quick/items/qquickwindow_p.h2
-rw-r--r--src/quick/qtquickglobal_p.h2
-rw-r--r--src/quick/quick.pro5
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp16
-rw-r--r--src/quick/util/qquickpixmapcache.cpp12
-rw-r--r--src/quick/util/qquickstate.cpp10
-rw-r--r--src/quick/util/qquickstate_p_p.h17
-rw-r--r--src/quick/util/qquickstategroup.cpp36
-rw-r--r--src/quick/util/qquicktimeline_p_p.h3
37 files changed, 775 insertions, 158 deletions
diff --git a/src/quick/accessible/qaccessiblequickview.cpp b/src/quick/accessible/qaccessiblequickview.cpp
index 41a02fc09c..b23b0316f5 100644
--- a/src/quick/accessible/qaccessiblequickview.cpp
+++ b/src/quick/accessible/qaccessiblequickview.cpp
@@ -84,8 +84,12 @@ QAccessibleInterface *QAccessibleQuickWindow::child(int index) const
QAccessibleInterface *QAccessibleQuickWindow::focusChild() const
{
QObject *focusObject = window()->focusObject();
- if (focusObject)
- return QAccessible::queryAccessibleInterface(focusObject);
+ if (focusObject) {
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(focusObject);
+ if (!iface || iface == this || !iface->focusChild())
+ return iface;
+ return iface->focusChild();
+ }
return nullptr;
}
diff --git a/src/quick/designer/qquickdesignersupportproperties.cpp b/src/quick/designer/qquickdesignersupportproperties.cpp
index c746f55daa..335795acf1 100644
--- a/src/quick/designer/qquickdesignersupportproperties.cpp
+++ b/src/quick/designer/qquickdesignersupportproperties.cpp
@@ -155,8 +155,8 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::propert
baseName + QQuickDesignerSupport::PropertyName(metaProperty.name())
+ '.', inspectedObjects));
}
- } else if (QQmlValueTypeFactory::valueType(metaProperty.userType())) {
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(metaProperty.userType());
+ } else if (QQmlGadgetPtrWrapper *valueType
+ = QQmlGadgetPtrWrapper::instance(qmlEngine(object), metaProperty.userType())) {
valueType->setValue(metaProperty.read(object));
propertyNameList.append(propertyNameListForWritableProperties(valueType,
baseName + QQuickDesignerSupport::PropertyName(metaProperty.name())
@@ -223,8 +223,8 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allProp
+ QQuickDesignerSupport::PropertyName(metaProperty.name())
+ '.', inspectedObjects));
}
- } else if (QQmlValueTypeFactory::valueType(metaProperty.userType())) {
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(metaProperty.userType());
+ } else if (QQmlGadgetPtrWrapper *valueType
+ = QQmlGadgetPtrWrapper::instance(qmlEngine(object), metaProperty.userType())) {
valueType->setValue(metaProperty.read(object));
propertyNameList.append(baseName + QQuickDesignerSupport::PropertyName(metaProperty.name()));
propertyNameList.append(allPropertyNames(valueType,
diff --git a/src/quick/doc/snippets/qml/qml-data-models/listmodel-listview-required.qml b/src/quick/doc/snippets/qml/qml-data-models/listmodel-listview-required.qml
new file mode 100644
index 0000000000..e9a668ed8f
--- /dev/null
+++ b/src/quick/doc/snippets/qml/qml-data-models/listmodel-listview-required.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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$
+**
+****************************************************************************/
+
+//! [document]
+import QtQuick 2.0
+
+Item {
+ width: 200
+ height: 250
+
+ ListModel {
+ id: myModel
+ ListElement { type: "Dog"; age: 8; noise: "meow" }
+ ListElement { type: "Cat"; age: 5; noise: "woof" }
+ }
+
+ component MyDelegate : Text {
+ required property string type
+ required property int age
+ text: type + ", " + age
+ // WRONG: Component.onCompleted: () => console.log(noise)
+ // The above line would cause a ReferenceError
+ // as there is no required property noise,
+ // and the presence of the required properties prevents
+ // noise from being injected into the scope
+ }
+
+ ListView {
+ anchors.fill: parent
+ model: myModel
+ delegate: MyDelegate {}
+ }
+}
+//! [document]
diff --git a/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc b/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc
index 04dbf1cf20..555f730c9e 100644
--- a/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc
+++ b/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc
@@ -164,6 +164,16 @@ To visualize data, bind the view's \c model property to a model and the
\snippet qml/qml-data-models/listmodel-listview.qml document
+ To get finer control over which roles are accessible, and to make delegates
+ more self-contained and usable outside of views,
+ \li{Required Properties}{required properties} can be used. If a delegate
+ contains required properties, the named roles are not provided. Instead,
+ the QML engine will check if the name of a required property matches that of
+ a model role. If so, that property will be bound to the corresponding value
+ from the model.
+
+ \snippet qml/qml-data-models/listmodel-listview-required.qml document
+
If there is a naming clash between the model's properties and the delegate's
properties, the roles can be accessed with the qualified \e model name
instead. For example, if a \l Text type had \e type or \e age properties,
@@ -186,6 +196,10 @@ To visualize data, bind the view's \c model property to a model and the
modelData role is also provided for models that have only one role. In this
case the \e modelData role contains the same data as the named role.
+ \note \e model, \e index, and \e modelData roles are not accessible
+ if the delegate contains required properties, unless it has also required
+ properties with matching names.
+
QML provides several types of data models among the built-in set of QML
types. In addition, models can be created with Qt C++ and then made
available to \l{QQmlEngine} for use by
@@ -417,6 +431,12 @@ ListView {
\note The \c edit role is equal to \l Qt::EditRole. See \l{QAbstractItemModel::}{roleNames}()
for the built-in role names. However, real life models would usually register custom roles.
+\node If a model role is bound to a \li{Required Property}{required property}, assigning to
+that property will not modify the model. It will instead break the binding to the model (just
+like assigning to any other property breaks existing bindings). If you want to use
+required properties and change the model data, make model also a required property and assign to
+\e model.propertyName.
+
For more information, visit the \l{qtquick-modelviewsdata-cppmodels.html#changing-model-data}{Using C++ Models with Qt Quick Views}
article.
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index 418475f100..528444cad3 100644
--- a/src/quick/doc/src/qmltypereference.qdoc
+++ b/src/quick/doc/src/qmltypereference.qdoc
@@ -179,6 +179,7 @@ available when you import \c QtQuick.
\li \l bool \c font.kerning
\li \l bool \c font.preferShaping
\li \l enumeration \c font.hintingPreference
+ \li \l string \c font.styleName
\endlist
Example:
diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp
index f3d92cf200..e6148ca072 100644
--- a/src/quick/handlers/qquickhandlerpoint.cpp
+++ b/src/quick/handlers/qquickhandlerpoint.cpp
@@ -120,7 +120,10 @@ void QQuickHandlerPoint::reset(const QQuickEventPoint *point)
m_pressure = tp->pressure();
m_ellipseDiameters = tp->ellipseDiameters();
} else if (event->asPointerTabletEvent()) {
- // TODO
+ m_uniqueId = event->device()->uniqueId();
+ m_rotation = static_cast<const QQuickEventTabletPoint *>(point)->rotation();
+ m_pressure = static_cast<const QQuickEventTabletPoint *>(point)->pressure();
+ m_ellipseDiameters = QSizeF();
} else {
m_uniqueId = event->device()->uniqueId();
m_rotation = 0;
diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp
index 1216eda477..b12d85784a 100644
--- a/src/quick/handlers/qquickhoverhandler.cpp
+++ b/src/quick/handlers/qquickhoverhandler.cpp
@@ -93,11 +93,22 @@ bool QQuickHoverHandler::wantsPointerEvent(QQuickPointerEvent *event)
{
QQuickEventPoint *point = event->point(0);
if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(point) && parentContains(point)) {
- // assume this is a mouse event, so there's only one point
+ // assume this is a mouse or tablet event, so there's only one point
setPointId(point->pointId());
return true;
}
- setHovered(false);
+
+ // Some hover events come from QQuickWindow::tabletEvent(). In between,
+ // some hover events come from QQWindowPrivate::flushFrameSynchronousEvents(),
+ // but those look like mouse events. If a particular HoverHandler instance
+ // is filtering for tablet events only (e.g. by setting
+ // acceptedDevices:PointerDevice.Stylus), those events should not cause
+ // the hovered property to transition to false prematurely.
+ // If a QQuickPointerTabletEvent caused the hovered property to become true,
+ // then only another QQuickPointerTabletEvent can make it become false.
+ if (!(m_hoveredTablet && event->asPointerMouseEvent()))
+ setHovered(false);
+
return false;
}
@@ -107,6 +118,8 @@ void QQuickHoverHandler::handleEventPoint(QQuickEventPoint *point)
if (point->state() == QQuickEventPoint::Released &&
point->pointerEvent()->device()->pointerType() == QQuickPointerDevice::Finger)
hovered = false;
+ else if (point->pointerEvent()->asPointerTabletEvent())
+ m_hoveredTablet = true;
setHovered(hovered);
setPassiveGrab(point);
}
@@ -124,6 +137,8 @@ void QQuickHoverHandler::setHovered(bool hovered)
if (m_hovered != hovered) {
qCDebug(lcHoverHandler) << objectName() << "hovered" << m_hovered << "->" << hovered;
m_hovered = hovered;
+ if (!hovered)
+ m_hoveredTablet = false;
emit hoveredChanged();
}
}
diff --git a/src/quick/handlers/qquickhoverhandler_p.h b/src/quick/handlers/qquickhoverhandler_p.h
index e4786bfa53..313b87217c 100644
--- a/src/quick/handlers/qquickhoverhandler_p.h
+++ b/src/quick/handlers/qquickhoverhandler_p.h
@@ -84,6 +84,7 @@ private:
private:
bool m_hovered = false;
+ bool m_hoveredTablet = false;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 469dc3cb4d..3c01bd2cb1 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -658,14 +658,73 @@ QQuickPointerDevice *QQuickPointerDevice::genericMouseDevice()
return g_genericMouseDevice;
}
-QQuickPointerDevice *QQuickPointerDevice::tabletDevice(qint64 id)
-{
- auto it = g_tabletDevices->find(id);
+QQuickPointerDevice *QQuickPointerDevice::tabletDevice(const QTabletEvent *event)
+{
+ // QTabletEvent::uniqueId() is the same for the pointy end and the eraser end of the stylus.
+ // We need to make those unique. QTabletEvent::PointerType only needs 2 bits' worth of storage.
+ // The key into g_tabletDevices just needs to be unique; we don't need to extract uniqueId
+ // back out of it, because QQuickPointerDevice stores that separately anyway.
+ // So the shift-and-add can be thought of as a sort of hash function, even though
+ // most of the time the result will be recognizable because the uniqueId MSBs are often 0.
+ qint64 key = event->uniqueId() + (qint64(event->pointerType()) << 60);
+ auto it = g_tabletDevices->find(key);
if (it != g_tabletDevices->end())
return it.value();
- // ### Figure out how to populate the tablet devices
- return nullptr;
+ DeviceType type = UnknownDevice;
+ int buttonCount = 0;
+ Capabilities caps = Position | Pressure | Hover;
+ // TODO Qt 6: we can't know for sure about XTilt or YTilt until we have a
+ // QTabletDevice populated with capabilities provided by QPA plugins
+
+ switch (event->device()) {
+ case QTabletEvent::Stylus:
+ type = QQuickPointerDevice::Stylus;
+ buttonCount = 3;
+ break;
+ case QTabletEvent::RotationStylus:
+ type = QQuickPointerDevice::Stylus;
+ caps |= QQuickPointerDevice::Rotation;
+ buttonCount = 1;
+ break;
+ case QTabletEvent::Airbrush:
+ type = QQuickPointerDevice::Airbrush;
+ buttonCount = 2;
+ break;
+ case QTabletEvent::Puck:
+ type = QQuickPointerDevice::Puck;
+ buttonCount = 3;
+ break;
+ case QTabletEvent::FourDMouse:
+ type = QQuickPointerDevice::Mouse;
+ caps |= QQuickPointerDevice::Rotation;
+ buttonCount = 3;
+ break;
+ default:
+ type = QQuickPointerDevice::UnknownDevice;
+ break;
+ }
+
+ PointerType ptype = GenericPointer;
+ switch (event->pointerType()) {
+ case QTabletEvent::Pen:
+ ptype = Pen;
+ break;
+ case QTabletEvent::Eraser:
+ ptype = Eraser;
+ break;
+ case QTabletEvent::Cursor:
+ ptype = Cursor;
+ break;
+ case QTabletEvent::UnknownPointer:
+ break;
+ }
+
+ QQuickPointerDevice *device = new QQuickPointerDevice(type, ptype, caps, 1, buttonCount,
+ QLatin1String("tablet tool ") + QString::number(event->uniqueId()), event->uniqueId());
+
+ g_tabletDevices->insert(key, device);
+ return device;
}
/*!
@@ -1284,6 +1343,12 @@ QVector2D QQuickEventPoint::estimatedVelocity() const
QQuickPointerEvent::~QQuickPointerEvent()
{}
+QQuickPointerMouseEvent::QQuickPointerMouseEvent(QObject *parent, QQuickPointerDevice *device)
+ : QQuickSinglePointEvent(parent, device)
+{
+ m_point = new QQuickEventPoint(this);
+}
+
QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event)
{
auto ev = static_cast<QMouseEvent*>(event);
@@ -1398,6 +1463,12 @@ void QQuickPointerTouchEvent::localize(QQuickItem *target)
}
#if QT_CONFIG(gestures)
+QQuickPointerNativeGestureEvent::QQuickPointerNativeGestureEvent(QObject *parent, QQuickPointerDevice *device)
+ : QQuickSinglePointEvent(parent, device)
+{
+ m_point = new QQuickEventPoint(this);
+}
+
QQuickPointerEvent *QQuickPointerNativeGestureEvent::reset(QEvent *event)
{
auto ev = static_cast<QNativeGestureEvent*>(event);
@@ -1560,6 +1631,12 @@ QQuickEventPoint *QQuickSinglePointEvent::point(int i) const
\note Many platforms provide no such information. On such platforms,
\c inverted always returns false.
*/
+QQuickPointerScrollEvent::QQuickPointerScrollEvent(QObject *parent, QQuickPointerDevice *device)
+ : QQuickSinglePointEvent(parent, device)
+{
+ m_point = new QQuickEventPoint(this);
+}
+
QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event)
{
m_event = static_cast<QInputEvent*>(event);
@@ -1832,6 +1909,81 @@ QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickIte
return &m_synthMouseEvent;
}
+#if QT_CONFIG(tabletevent)
+QQuickPointerTabletEvent::QQuickPointerTabletEvent(QObject *parent, QQuickPointerDevice *device)
+ : QQuickSinglePointEvent(parent, device)
+{
+ m_point = new QQuickEventTabletPoint(this);
+}
+
+QQuickPointerEvent *QQuickPointerTabletEvent::reset(QEvent *event)
+{
+ auto ev = static_cast<QTabletEvent*>(event);
+ m_event = ev;
+ if (!event)
+ return this;
+
+ Q_ASSERT(m_device == QQuickPointerDevice::tabletDevice(ev));
+ m_device->eventDeliveryTargets().clear();
+ m_button = ev->button();
+ m_pressedButtons = ev->buttons();
+ static_cast<QQuickEventTabletPoint *>(m_point)->reset(ev);
+ return this;
+}
+
+QQuickEventTabletPoint::QQuickEventTabletPoint(QQuickPointerTabletEvent *parent)
+ : QQuickEventPoint(parent)
+{
+}
+
+void QQuickEventTabletPoint::reset(const QTabletEvent *ev)
+{
+ Qt::TouchPointState state = Qt::TouchPointStationary;
+ switch (ev->type()) {
+ case QEvent::TabletPress:
+ state = Qt::TouchPointPressed;
+ clearPassiveGrabbers();
+ break;
+ case QEvent::TabletRelease:
+ state = Qt::TouchPointReleased;
+ break;
+ case QEvent::TabletMove:
+ state = Qt::TouchPointMoved;
+ break;
+ default:
+ break;
+ }
+ QQuickEventPoint::reset(state, ev->posF(), 1, ev->timestamp());
+ m_rotation = ev->rotation();
+ m_pressure = ev->pressure();
+ m_tangentialPressure = ev->tangentialPressure();
+ m_tilt = QVector2D(ev->xTilt(), ev->yTilt());
+}
+
+bool QQuickPointerTabletEvent::isPressEvent() const
+{
+ auto me = static_cast<QTabletEvent *>(m_event);
+ return me->type() == QEvent::TabletPress;
+}
+
+bool QQuickPointerTabletEvent::isUpdateEvent() const
+{
+ auto me = static_cast<QTabletEvent *>(m_event);
+ return me->type() == QEvent::TabletMove;
+}
+
+bool QQuickPointerTabletEvent::isReleaseEvent() const
+{
+ auto me = static_cast<QTabletEvent *>(m_event);
+ return me->type() == QEvent::TabletRelease;
+}
+
+QTabletEvent *QQuickPointerTabletEvent::asTabletEvent() const
+{
+ return static_cast<QTabletEvent *>(m_event);
+}
+#endif // QT_CONFIG(tabletevent)
+
#if QT_CONFIG(gestures)
bool QQuickPointerNativeGestureEvent::isPressEvent() const
{
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index 94b61fd364..84450e060a 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -478,8 +478,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickSinglePointEvent : public QQuickPointerEvent
{
Q_OBJECT
public:
- QQuickSinglePointEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
- : QQuickPointerEvent(parent, device), m_point(new QQuickEventPoint(this)) { }
+ QQuickSinglePointEvent(QObject *parent, QQuickPointerDevice *device)
+ : QQuickPointerEvent(parent, device) { }
void localize(QQuickItem *target) override;
int pointCount() const override { return 1; }
@@ -493,7 +493,7 @@ public:
bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const override;
protected:
- QQuickEventPoint *m_point;
+ QQuickEventPoint *m_point = nullptr;
Q_DISABLE_COPY(QQuickSinglePointEvent)
};
@@ -507,8 +507,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickSinglePointE
QML_ADDED_IN_MINOR_VERSION(12)
public:
- QQuickPointerMouseEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
- : QQuickSinglePointEvent(parent, device) { }
+ QQuickPointerMouseEvent(QObject *parent, QQuickPointerDevice *device);
QQuickPointerEvent *reset(QEvent *) override;
bool isPressEvent() const override;
@@ -570,6 +569,60 @@ private:
Q_DISABLE_COPY(QQuickPointerTouchEvent)
};
+#if QT_CONFIG(tabletevent)
+class Q_QUICK_PRIVATE_EXPORT QQuickEventTabletPoint : public QQuickEventPoint
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal rotation READ rotation)
+ Q_PROPERTY(qreal pressure READ pressure)
+ Q_PROPERTY(qreal tangentialPressure READ tangentialPressure)
+ Q_PROPERTY(QVector2D tilt READ tilt)
+
+ QML_NAMED_ELEMENT(EventTabletPoint)
+ QML_UNCREATABLE("EventTouchPoint is only available as a member of PointerEvent.")
+ QML_ADDED_IN_MINOR_VERSION(15)
+
+public:
+ QQuickEventTabletPoint(QQuickPointerTabletEvent *parent);
+
+ void reset(const QTabletEvent *e);
+
+ qreal rotation() const { return m_rotation; }
+ qreal pressure() const { return m_pressure; }
+ qreal tangentialPressure() const { return m_tangentialPressure; }
+ QVector2D tilt() const { return m_tilt; }
+
+private:
+ qreal m_rotation;
+ qreal m_pressure;
+ qreal m_tangentialPressure;
+ QVector2D m_tilt;
+
+ friend class QQuickPointerTouchEvent;
+
+ Q_DISABLE_COPY(QQuickEventTabletPoint)
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerTabletEvent : public QQuickSinglePointEvent
+{
+ Q_OBJECT
+public:
+ QQuickPointerTabletEvent(QObject *parent, QQuickPointerDevice *device);
+
+ QQuickPointerEvent *reset(QEvent *) override;
+ bool isPressEvent() const override;
+ bool isUpdateEvent() const override;
+ bool isReleaseEvent() const override;
+ QQuickPointerTabletEvent *asPointerTabletEvent() override { return this; }
+ const QQuickPointerTabletEvent *asPointerTabletEvent() const override { return this; }
+ const QQuickEventTabletPoint *tabletPoint() const { return static_cast<QQuickEventTabletPoint *>(m_point); }
+
+ QTabletEvent *asTabletEvent() const;
+
+ Q_DISABLE_COPY(QQuickPointerTabletEvent)
+};
+#endif // QT_CONFIG(tabletevent)
+
#if QT_CONFIG(gestures)
class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickSinglePointEvent
{
@@ -578,8 +631,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickSing
Q_PROPERTY(qreal value READ value CONSTANT)
public:
- QQuickPointerNativeGestureEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
- : QQuickSinglePointEvent(parent, device) { }
+ QQuickPointerNativeGestureEvent(QObject *parent, QQuickPointerDevice *device);
QQuickPointerEvent *reset(QEvent *) override;
bool isPressEvent() const override;
@@ -608,8 +660,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerScrollEvent : public QQuickSinglePoint
QML_ADDED_IN_MINOR_VERSION(14)
public:
- QQuickPointerScrollEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
- : QQuickSinglePointEvent(parent, device) { }
+ QQuickPointerScrollEvent(QObject *parent, QQuickPointerDevice *device);
QQuickPointerEvent *reset(QEvent *) override;
void localize(QQuickItem *target) override;
@@ -714,7 +765,7 @@ public:
static QQuickPointerDevice *touchDevice(const QTouchDevice *d);
static QList<QQuickPointerDevice *> touchDevices();
static QQuickPointerDevice *genericMouseDevice();
- static QQuickPointerDevice *tabletDevice(qint64);
+ static QQuickPointerDevice *tabletDevice(const QTabletEvent *event);
QVector<QQuickPointerHandler *> &eventDeliveryTargets() { return m_eventDeliveryTargets; }
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 8ade5b7e37..27c57e147a 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -128,8 +128,13 @@ void QQuickFlickableVisibleArea::updateVisible()
// Vertical
const qreal viewheight = flickable->height();
const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent();
- qreal pagePos = (-p->vData.move.value() + flickable->minYExtent()) / (maxyextent + viewheight);
- qreal pageSize = viewheight / (maxyextent + viewheight);
+ const qreal maxYBounds = maxyextent + viewheight;
+ qreal pagePos = 0;
+ qreal pageSize = 0;
+ if (!qFuzzyIsNull(maxYBounds)) {
+ pagePos = (-p->vData.move.value() + flickable->minYExtent()) / maxYBounds;
+ pageSize = viewheight / maxYBounds;
+ }
if (pageSize != m_heightRatio) {
m_heightRatio = pageSize;
@@ -143,8 +148,14 @@ void QQuickFlickableVisibleArea::updateVisible()
// Horizontal
const qreal viewwidth = flickable->width();
const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
- pagePos = (-p->hData.move.value() + flickable->minXExtent()) / (maxxextent + viewwidth);
- pageSize = viewwidth / (maxxextent + viewwidth);
+ const qreal maxXBounds = maxxextent + viewwidth;
+ if (!qFuzzyIsNull(maxXBounds)) {
+ pagePos = (-p->hData.move.value() + flickable->minXExtent()) / maxXBounds;
+ pageSize = viewwidth / maxXBounds;
+ } else {
+ pagePos = 0;
+ pageSize = 0;
+ }
if (pageSize != m_widthRatio) {
m_widthRatio = pageSize;
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 1ff55dae90..3f5f11effd 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -73,7 +73,7 @@ class QQuickFlickableVisibleArea;
class QQuickTransition;
class QQuickFlickableReboundTransition;
-class Q_AUTOTEST_EXPORT QQuickFlickablePrivate : public QQuickItemPrivate, public QQuickItemChangeListener
+class Q_QUICK_PRIVATE_EXPORT QQuickFlickablePrivate : public QQuickItemPrivate, public QQuickItemChangeListener
{
Q_DECLARE_PUBLIC(QQuickFlickable)
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index bd6b9d741e..125518e51b 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -183,13 +183,6 @@ static void qt_quickitems_defineModule()
qRegisterMetaType<QQuickAnchorLine>("QQuickAnchorLine");
qRegisterMetaType<QPointingDeviceUniqueId>("QPointingDeviceUniqueId");
qRegisterMetaType<QQuickHandlerPoint>();
-
-#if !QT_CONFIG(quick_animatedimage)
- qmlRegisterTypeNotAvailable(
- "QtQuick", 2, 15, "AnimatedImage",
- QCoreApplication::translate("QQuickAnimatedImage",
- "Qt was built without support for QMovie"));
-#endif
}
static void initResources()
diff --git a/src/quick/items/qquickitemsmodule_p.h b/src/quick/items/qquickitemsmodule_p.h
index 6ceb0d56e6..28dff65dff 100644
--- a/src/quick/items/qquickitemsmodule_p.h
+++ b/src/quick/items/qquickitemsmodule_p.h
@@ -51,6 +51,7 @@
// We mean it.
//
+#include <private/qtquickglobal_p.h>
#include <QtGui/qevent.h>
#include <qqml.h>
@@ -71,6 +72,17 @@ struct QPointingDeviceUniqueIdForeign
QML_UNCREATABLE("PointingDeviceUniqueId is only available via read-only properties.")
};
+#if !QT_CONFIG(quick_animatedimage)
+struct QQuickAnimatedImageNotAvailable
+{
+ Q_GADGET
+ QML_UNAVAILABLE
+ QML_NAMED_ELEMENT(AnimatedImage)
+ QML_ADDED_IN_VERSION(2, 0)
+ QML_UNCREATABLE("Qt was built without support for QMovie.")
+};
+#endif
+
QT_END_NAMESPACE
#endif // QQUICKITEMSMODULE_P_H
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 7fb392233e..3e3a2c262b 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -2419,7 +2419,7 @@ void QQuickItemView::destroyingItem(QObject *object)
Q_D(QQuickItemView);
QQuickItem* item = qmlobject_cast<QQuickItem*>(object);
if (item) {
- item->setParentItem(nullptr);
+ QQuickItemPrivate::get(item)->setCulled(true);
d->unrequestedItems.remove(item);
}
}
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index badd2efe29..b91e705ad0 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -141,6 +141,8 @@ public:
QQuickItemViewAttached *getAttachedObject(const QObject *object) const override;
+ void fixupHeader();
+ void fixupHeaderCompleted();
QQuickListView::Orientation orient;
qreal visiblePos;
qreal averageSize;
@@ -169,6 +171,12 @@ public:
QString nextSection;
qreal overshootDist;
+
+ qreal desiredViewportPosition;
+ qreal fixupHeaderPosition;
+ bool headerNeedsSeparateFixup : 1;
+ bool desiredHeaderVisible : 1;
+
bool correctFlick : 1;
bool inFlickCorrection : 1;
@@ -182,7 +190,9 @@ public:
, highlightPosAnimator(nullptr), highlightWidthAnimator(nullptr), highlightHeightAnimator(nullptr)
, highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
, sectionCriteria(nullptr), currentSectionItem(nullptr), nextSectionItem(nullptr)
- , overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
+ , overshootDist(0.0), desiredViewportPosition(0.0), fixupHeaderPosition(0.0)
+ , headerNeedsSeparateFixup(false), desiredHeaderVisible(false)
+ , correctFlick(false), inFlickCorrection(false)
{
highlightMoveDuration = -1; //override default value set in base class
}
@@ -1402,6 +1412,31 @@ void QQuickListViewPrivate::updateFooter()
emit q->footerItemChanged();
}
+void QQuickListViewPrivate::fixupHeaderCompleted()
+{
+ headerNeedsSeparateFixup = false;
+ QObjectPrivate::disconnect(&timeline, &QQuickTimeLine::updated, this, &QQuickListViewPrivate::fixupHeader);
+}
+
+void QQuickListViewPrivate::fixupHeader()
+{
+ FxListItemSG *listItem = static_cast<FxListItemSG*>(header);
+ const bool fixingUp = (orient == QQuickListView::Vertical ? vData : hData).fixingUp;
+ if (fixingUp && headerPositioning == QQuickListView::PullBackHeader && visibleItems.count()) {
+ int fixupDura = timeline.duration();
+ if (fixupDura < 0)
+ fixupDura = fixupDuration/2;
+ const int t = timeline.time();
+
+ const qreal progress = qreal(t)/fixupDura;
+ const qreal ultimateHeaderPosition = desiredHeaderVisible ? desiredViewportPosition : desiredViewportPosition - headerSize();
+ const qreal headerPosition = fixupHeaderPosition * (1 - progress) + ultimateHeaderPosition * progress;
+ const qreal viewPos = isContentFlowReversed() ? -position() - size() : position();
+ const qreal clampedPos = qBound(originPosition() - headerSize(), headerPosition, lastPosition() - size());
+ listItem->setPosition(qBound(viewPos - headerSize(), clampedPos, viewPos));
+ }
+}
+
void QQuickListViewPrivate::updateHeader()
{
Q_Q(QQuickListView);
@@ -1419,9 +1454,14 @@ void QQuickListViewPrivate::updateHeader()
if (headerPositioning == QQuickListView::OverlayHeader) {
listItem->setPosition(isContentFlowReversed() ? -position() - size() : position());
} else if (visibleItems.count()) {
+ const bool fixingUp = (orient == QQuickListView::Vertical ? vData : hData).fixingUp;
if (headerPositioning == QQuickListView::PullBackHeader) {
- qreal viewPos = isContentFlowReversed() ? -position() - size() : position();
- qreal clampedPos = qBound(originPosition() - headerSize(), listItem->position(), lastPosition() - headerSize() - size());
+ qreal headerPosition = listItem->position();
+ const qreal viewPos = isContentFlowReversed() ? -position() - size() : position();
+ // Make sure the header is not shown if we absolutely do not have any plans to show it
+ if (fixingUp && !headerNeedsSeparateFixup)
+ headerPosition = viewPos - headerSize();
+ qreal clampedPos = qBound(originPosition() - headerSize(), headerPosition, lastPosition() - size());
listItem->setPosition(qBound(viewPos - headerSize(), clampedPos, viewPos));
} else {
qreal startPos = originPosition();
@@ -1539,13 +1579,46 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
bias = -bias;
tempPosition -= bias;
}
- FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
+
+ qreal snapOffset = 0;
+ qreal overlayHeaderOffset = 0;
+ bool isHeaderWithinBounds = false;
+ if (header) {
+ qreal visiblePartOfHeader = header->position() + header->size() - tempPosition;
+ isHeaderWithinBounds = visiblePartOfHeader > 0;
+ switch (headerPositioning) {
+ case QQuickListView::OverlayHeader:
+ snapOffset = header->size();
+ overlayHeaderOffset = header->size();
+ break;
+ case QQuickListView::InlineHeader:
+ if (isHeaderWithinBounds && tempPosition < originPosition())
+ // For the inline header, we want to snap to the first item
+ // if we're more than halfway down the inline header.
+ // So if we look for an item halfway down of the header
+ snapOffset = header->size() / 2;
+ break;
+ case QQuickListView::PullBackHeader:
+ desiredHeaderVisible = visiblePartOfHeader > header->size()/2;
+ if (qFuzzyCompare(header->position(), tempPosition)) {
+ // header was pulled down; make sure it remains visible and snap items to bottom of header
+ snapOffset = header->size();
+ } else if (desiredHeaderVisible) {
+ // More than 50% of the header is shown. Show it fully.
+ // Scroll the view so the next item snaps to the header.
+ snapOffset = header->size();
+ overlayHeaderOffset = header->size();
+ }
+ break;
+ }
+ }
+ FxViewItem *topItem = snapItemAt(tempPosition + snapOffset + highlightRangeStart);
if (strictHighlightRange && currentItem && (!topItem || (topItem->index != currentIndex && fixupMode == Immediate))) {
// StrictlyEnforceRange always keeps an item in range
updateHighlight();
topItem = currentItem;
}
- FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
+ FxViewItem *bottomItem = snapItemAt(tempPosition + snapOffset + highlightRangeEnd);
if (strictHighlightRange && currentItem && (!bottomItem || (bottomItem->index != currentIndex && fixupMode == Immediate))) {
// StrictlyEnforceRange always keeps an item in range
updateHighlight();
@@ -1553,27 +1626,92 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
}
qreal pos;
bool isInBounds = -position() > maxExtent && -position() <= minExtent;
- if (topItem && (isInBounds || strictHighlightRange)) {
- if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
- pos = isContentFlowReversed() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart;
+
+ if (header && !topItem && isInBounds) {
+ // We are trying to pull back further than needed
+ switch (headerPositioning) {
+ case QQuickListView::OverlayHeader:
+ pos = startPosition() - overlayHeaderOffset;
+ break;
+ case QQuickListView::InlineHeader:
+ pos = isContentFlowReversed() ? header->size() - size() : header->position();
+ break;
+ case QQuickListView::PullBackHeader:
+ pos = isContentFlowReversed() ? -size() : startPosition();
+ break;
+ }
+ } else if (topItem && (isInBounds || strictHighlightRange)) {
+ if (topItem->index == 0 && header && !hasStickyHeader() && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
+ pos = isContentFlowReversed() ? -header->position() + highlightRangeStart - size() : (header->position() - highlightRangeStart + header->size());
} else {
- if (isContentFlowReversed())
- pos = qMax(qMin(-static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size(), -maxExtent), -minExtent);
- else
- pos = qMax(qMin(static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart, -maxExtent), -minExtent);
+ if (header && headerPositioning == QQuickListView::PullBackHeader) {
+ // We pulled down the header. If it isn't pulled all way down, we need to snap
+ // the header.
+ if (qFuzzyCompare(tempPosition, header->position())) {
+ // It is pulled all way down. Scroll-snap the content, but not the header.
+ if (isContentFlowReversed())
+ pos = -static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + snapOffset;
+ else
+ pos = static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - snapOffset;
+ } else {
+ // Header is not pulled all way down, make it completely visible or hide it.
+ // Depends on how much of the header is visible.
+ if (desiredHeaderVisible) {
+ // More than half of the header is visible - show it.
+ // Scroll so that the topItem is aligned to a fully visible header
+ if (isContentFlowReversed())
+ pos = -static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + headerSize();
+ else
+ pos = static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - headerSize();
+ } else {
+ // Less than half is visible - hide the header. Scroll so
+ // that the topItem is aligned to the top of the view
+ if (isContentFlowReversed())
+ pos = -static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size();
+ else
+ pos = static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart;
+ }
+ }
+
+ headerNeedsSeparateFixup = isHeaderWithinBounds || desiredHeaderVisible;
+ if (headerNeedsSeparateFixup) {
+ // We need to animate the header independently if it starts visible or should end as visible,
+ // since the header should not necessarily follow the content.
+ // Store the desired viewport position.
+ // Also store the header position so we know where to animate the header from (fixupHeaderPosition).
+ // We deduce the desired header position from the desiredViewportPosition variable.
+ pos = qBound(-minExtent, pos, -maxExtent);
+ desiredViewportPosition = isContentFlowReversed() ? -pos - size() : pos;
+
+ FxListItemSG *headerItem = static_cast<FxListItemSG*>(header);
+ fixupHeaderPosition = headerItem->position();
+
+ // follow the same fixup timeline
+ QObjectPrivate::connect(&timeline, &QQuickTimeLine::updated, this, &QQuickListViewPrivate::fixupHeader);
+ QObjectPrivate::connect(&timeline, &QQuickTimeLine::completed, this, &QQuickListViewPrivate::fixupHeaderCompleted);
+ }
+ } else if (isContentFlowReversed()) {
+ pos = -static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + overlayHeaderOffset;
+ } else {
+ pos = static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - overlayHeaderOffset;
+ }
}
} else if (bottomItem && isInBounds) {
if (isContentFlowReversed())
- pos = qMax(qMin(-static_cast<FxListItemSG*>(bottomItem)->itemPosition() + highlightRangeEnd - size(), -maxExtent), -minExtent);
+ pos = -static_cast<FxListItemSG*>(bottomItem)->itemPosition() + highlightRangeEnd - size() + overlayHeaderOffset;
else
- pos = qMax(qMin(static_cast<FxListItemSG*>(bottomItem)->itemPosition() - highlightRangeEnd, -maxExtent), -minExtent);
+ pos = static_cast<FxListItemSG*>(bottomItem)->itemPosition() - highlightRangeEnd - overlayHeaderOffset;
} else {
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
return;
}
+ pos = qBound(-minExtent, pos, -maxExtent);
qreal dist = qAbs(data.move + pos);
- if (dist > 0) {
+ if (dist >= 0) {
+ // Even if dist == 0 we still start the timeline, because we use the same timeline for
+ // moving the header. And we might need to move the header while the content does not
+ // need moving
timeline.reset(data.move);
if (fixupMode != Immediate) {
timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 8722a45373..1fb71272b1 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -56,7 +56,7 @@ static const QQuickItemPrivate::ChangeTypes watchedChanges
QQuickLoaderPrivate::QQuickLoaderPrivate()
: item(nullptr), object(nullptr), itemContext(nullptr), incubator(nullptr), updatingSize(false),
- active(true), loadingFromSource(false), asynchronous(false)
+ active(true), loadingFromSource(false), asynchronous(false), status(computeStatus())
{
}
@@ -379,7 +379,7 @@ void QQuickLoader::setActive(bool newVal)
d->object = nullptr;
emit itemChanged();
}
- emit statusChanged();
+ d->updateStatus();
}
emit activeChanged();
}
@@ -432,7 +432,7 @@ void QQuickLoader::loadFromSource()
Q_D(QQuickLoader);
if (d->source.isEmpty()) {
emit sourceChanged();
- emit statusChanged();
+ d->updateStatus();
emit progressChanged();
emit itemChanged();
return;
@@ -503,7 +503,7 @@ void QQuickLoader::loadFromSourceComponent()
Q_D(QQuickLoader);
if (!d->component) {
emit sourceComponentChanged();
- emit statusChanged();
+ d->updateStatus();
emit progressChanged();
emit itemChanged();
return;
@@ -619,7 +619,7 @@ void QQuickLoaderPrivate::load()
q, SLOT(_q_sourceLoaded()));
QObject::connect(component, SIGNAL(progressChanged(qreal)),
q, SIGNAL(progressChanged()));
- emit q->statusChanged();
+ updateStatus();
emit q->progressChanged();
if (loadingFromSource)
emit q->sourceChanged();
@@ -707,7 +707,7 @@ void QQuickLoaderPrivate::incubatorStateChanged(QQmlIncubator::Status status)
emit q->sourceChanged();
else
emit q->sourceComponentChanged();
- emit q->statusChanged();
+ updateStatus();
emit q->progressChanged();
if (status == QQmlIncubator::Ready)
emit q->loaded();
@@ -724,7 +724,7 @@ void QQuickLoaderPrivate::_q_sourceLoaded()
emit q->sourceChanged();
else
emit q->sourceComponentChanged();
- emit q->statusChanged();
+ updateStatus();
emit q->progressChanged();
emit q->itemChanged(); //Like clearing source, emit itemChanged even if previous item was also null
disposeInitialPropertyValues(); // cleanup
@@ -742,7 +742,7 @@ void QQuickLoaderPrivate::_q_sourceLoaded()
component->create(*incubator, itemContext);
if (incubator && incubator->status() == QQmlIncubator::Loading)
- emit q->statusChanged();
+ updateStatus();
}
/*!
@@ -789,37 +789,7 @@ QQuickLoader::Status QQuickLoader::status() const
{
Q_D(const QQuickLoader);
- if (!d->active)
- return Null;
-
- if (d->component) {
- switch (d->component->status()) {
- case QQmlComponent::Loading:
- return Loading;
- case QQmlComponent::Error:
- return Error;
- case QQmlComponent::Null:
- return Null;
- default:
- break;
- }
- }
-
- if (d->incubator) {
- switch (d->incubator->status()) {
- case QQmlIncubator::Loading:
- return Loading;
- case QQmlIncubator::Error:
- return Error;
- default:
- break;
- }
- }
-
- if (d->object)
- return Ready;
-
- return d->source.isEmpty() ? Null : Error;
+ return static_cast<Status>(d->status);
}
void QQuickLoader::componentComplete()
@@ -1020,6 +990,51 @@ QV4::ReturnedValue QQuickLoaderPrivate::extractInitialPropertyValues(QQmlV4Funct
return valuemap->asReturnedValue();
}
+QQuickLoader::Status QQuickLoaderPrivate::computeStatus() const
+{
+ if (!active)
+ return QQuickLoader::Status::Null;
+
+ if (component) {
+ switch (component->status()) {
+ case QQmlComponent::Loading:
+ return QQuickLoader::Status::Loading;
+ case QQmlComponent::Error:
+ return QQuickLoader::Status::Error;
+ case QQmlComponent::Null:
+ return QQuickLoader::Status::Null;
+ default:
+ break;
+ }
+ }
+
+ if (incubator) {
+ switch (incubator->status()) {
+ case QQmlIncubator::Loading:
+ return QQuickLoader::Status::Loading;
+ case QQmlIncubator::Error:
+ return QQuickLoader::Status::Error;
+ default:
+ break;
+ }
+ }
+
+ if (object)
+ return QQuickLoader::Status::Ready;
+
+ return source.isEmpty() ? QQuickLoader::Status::Null : QQuickLoader::Status::Error;
+}
+
+void QQuickLoaderPrivate::updateStatus()
+{
+ Q_Q(QQuickLoader);
+ auto newStatus = computeStatus();
+ if (status != newStatus) {
+ status = newStatus;
+ emit q->statusChanged();
+ }
+}
+
#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 349b5c6c06..39d50280c5 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -96,6 +96,8 @@ public:
void disposeInitialPropertyValues();
static QUrl resolveSourceUrl(QQmlV4Function *args);
QV4::ReturnedValue extractInitialPropertyValues(QQmlV4Function *args, QObject *loader, bool *error);
+ QQuickLoader::Status computeStatus() const;
+ void updateStatus();
qreal getImplicitWidth() const override;
qreal getImplicitHeight() const override;
@@ -112,6 +114,11 @@ public:
bool active : 1;
bool loadingFromSource : 1;
bool asynchronous : 1;
+ // We need to use char instead of QQuickLoader::Status
+ // as otherwise the size of the class would increase
+ // on 32-bit systems, as sizeof(Status) == sizeof(int)
+ // and sizeof(int) > remaining padding on 32 bit
+ char status;
void _q_sourceLoaded();
void _q_updateSize(bool loaderGeometryChanged = true);
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 9a371207ce..3a807d3c66 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -88,20 +88,18 @@ void QQuickTouchPoint::setPointId(int id)
These properties hold the current position of the touch point.
*/
-void QQuickTouchPoint::setX(qreal x)
+void QQuickTouchPoint::setPosition(QPointF p)
{
- if (_x == x)
+ bool xch = (_x != p.x());
+ bool ych = (_y != p.y());
+ if (!xch && !ych)
return;
- _x = x;
- emit xChanged();
-}
-
-void QQuickTouchPoint::setY(qreal y)
-{
- if (_y == y)
- return;
- _y = y;
- emit yChanged();
+ _x = p.x();
+ _y = p.y();
+ if (xch)
+ emit xChanged();
+ if (ych)
+ emit yChanged();
}
/*!
@@ -798,8 +796,7 @@ void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QT
//TODO: if !qmlDefined, could bypass setters.
// also, should only emit signals after all values have been set
dtp->setUniqueId(p->uniqueId());
- dtp->setX(p->pos().x());
- dtp->setY(p->pos().y());
+ dtp->setPosition(p->pos());
dtp->setEllipseDiameters(p->ellipseDiameters());
dtp->setPressure(p->pressure());
dtp->setRotation(p->rotation());
@@ -817,8 +814,7 @@ void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QM
{
dtp->setPreviousX(dtp->x());
dtp->setPreviousY(dtp->y());
- dtp->setX(e->localPos().x());
- dtp->setY(e->localPos().y());
+ dtp->setPosition(e->localPos());
if (e->type() == QEvent::MouseButtonPress) {
dtp->setStartX(e->localPos().x());
dtp->setStartY(e->localPos().y());
diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h
index 363e62593b..e34a3faad6 100644
--- a/src/quick/items/qquickmultipointtoucharea_p.h
+++ b/src/quick/items/qquickmultipointtoucharea_p.h
@@ -97,10 +97,8 @@ public:
void setUniqueId(const QPointingDeviceUniqueId &id);
qreal x() const { return _x; }
- void setX(qreal x);
-
qreal y() const { return _y; }
- void setY(qreal y);
+ void setPosition(QPointF pos);
QSizeF ellipseDiameters() const { return _ellipseDiameters; }
void setEllipseDiameters(const QSizeF &d);
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index f9f3e5cfa3..b298ed74da 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -161,10 +161,6 @@ public:
\l sourceItem while still handling input. For this, you can use
the \l hideSource property.
- \note If \l sourceItem is a \l Rectangle with border, by default half the
- border width falls outside the texture. To get the whole border, you can
- extend the \l sourceRect.
-
\note The ShaderEffectSource relies on FBO multisampling support
to antialias edges. If the underlying hardware does not support this,
which is the case for most embedded graphics chips, edges rendered
diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h
index d76055c831..5ad33389de 100644
--- a/src/quick/items/qquickspriteengine_p.h
+++ b/src/quick/items/qquickspriteengine_p.h
@@ -330,6 +330,18 @@ inline int spriteCount(QQmlListProperty<QQuickSprite> *p)
return reinterpret_cast<QList<QQuickSprite *> *>(p->data)->count();
}
+inline void spriteReplace(QQmlListProperty<QQuickSprite> *p, int idx, QQuickSprite *s)
+{
+ reinterpret_cast<QList<QQuickSprite *> *>(p->data)->replace(idx, s);
+ p->object->metaObject()->invokeMethod(p->object, "createEngine");
+}
+
+inline void spriteRemoveLast(QQmlListProperty<QQuickSprite> *p)
+{
+ reinterpret_cast<QList<QQuickSprite *> *>(p->data)->removeLast();
+ p->object->metaObject()->invokeMethod(p->object, "createEngine");
+}
+
QT_END_NAMESPACE
#endif // QQUICKSPRITEENGINE_P_H
diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp
index eb4b5335e7..c29938a1bb 100644
--- a/src/quick/items/qquickspritesequence.cpp
+++ b/src/quick/items/qquickspritesequence.cpp
@@ -162,7 +162,9 @@ void QQuickSpriteSequence::setInterpolate(bool arg)
QQmlListProperty<QQuickSprite> QQuickSpriteSequence::sprites()
{
Q_D(QQuickSpriteSequence);
- return QQmlListProperty<QQuickSprite>(this, &d->m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
+ return QQmlListProperty<QQuickSprite>(this, &d->m_sprites,
+ spriteAppend, spriteCount, spriteAt,
+ spriteClear, spriteReplace, spriteRemoveLast);
}
bool QQuickSpriteSequence::running() const
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 496aea73d1..56c5bedd4d 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -2352,14 +2352,11 @@ void QQuickTableViewPrivate::connectToModel()
QObjectPrivate::connect(model, &QQmlInstanceModel::createdItem, this, &QQuickTableViewPrivate::itemCreatedCallback);
QObjectPrivate::connect(model, &QQmlInstanceModel::initItem, this, &QQuickTableViewPrivate::initItemCallback);
+ QObjectPrivate::connect(model, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback);
+ QObjectPrivate::connect(model, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback);
- if (tableModel) {
- const auto tm = tableModel.data();
- QObjectPrivate::connect(tm, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback);
- QObjectPrivate::connect(tm, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback);
- // Connect atYEndChanged to a function that fetches data if more is available
- QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged, this, &QQuickTableViewPrivate::fetchMoreData);
- }
+ // Connect atYEndChanged to a function that fetches data if more is available
+ QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged, this, &QQuickTableViewPrivate::fetchMoreData);
if (auto const aim = model->abstractItemModel()) {
// When the model exposes a QAIM, we connect to it directly. This means that if the current model is
@@ -2387,13 +2384,10 @@ void QQuickTableViewPrivate::disconnectFromModel()
QObjectPrivate::disconnect(model, &QQmlInstanceModel::createdItem, this, &QQuickTableViewPrivate::itemCreatedCallback);
QObjectPrivate::disconnect(model, &QQmlInstanceModel::initItem, this, &QQuickTableViewPrivate::initItemCallback);
+ QObjectPrivate::disconnect(model, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback);
+ QObjectPrivate::disconnect(model, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback);
- if (tableModel) {
- const auto tm = tableModel.data();
- QObjectPrivate::disconnect(tm, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback);
- QObjectPrivate::disconnect(tm, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback);
- QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged, this, &QQuickTableViewPrivate::fetchMoreData);
- }
+ QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged, this, &QQuickTableViewPrivate::fetchMoreData);
if (auto const aim = model->abstractItemModel()) {
disconnect(aim, &QAbstractItemModel::rowsMoved, this, &QQuickTableViewPrivate::rowsMovedCallback);
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 03fe019916..a3cc39419f 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -91,7 +91,7 @@ private:
Q_DECLARE_PRIVATE(QQuickTableSectionSizeProvider)
};
-class Q_QML_AUTOTEST_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate
+class Q_QUICK_PRIVATE_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate
{
Q_DECLARE_PUBLIC(QQuickTableView)
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index f89e7d970f..816b48b190 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -40,6 +40,9 @@
#include "qquicktext_p.h"
#include "qquicktext_p_p.h"
+#include <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qqmldebugconnector_p.h>
+
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qsgadaptationlayer_p.h>
@@ -1146,6 +1149,10 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
elideLayout->setFont(layout.font());
elideLayout->setTextOption(layout.textOption());
+ if (QQmlDebugTranslationService *service
+ = QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
+ elideText = service->foundElidedText(q, layoutText, elideText);
+ }
elideLayout->setText(elideText);
elideLayout->beginLayout();
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 491334f439..5832242961 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -93,6 +93,7 @@ Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch")
Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target")
Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse")
Q_LOGGING_CATEGORY(DBG_MOUSE_TARGET, "qt.quick.mouse.target")
+Q_LOGGING_CATEGORY(lcTablet, "qt.quick.tablet")
Q_LOGGING_CATEGORY(lcWheelTarget, "qt.quick.wheel.target")
Q_LOGGING_CATEGORY(lcGestureTarget, "qt.quick.gesture.target")
Q_LOGGING_CATEGORY(DBG_HOVER_TRACE, "qt.quick.hover.trace")
@@ -547,7 +548,7 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa
else
context->endNextFrame(renderer);
- if (renderer->hasCustomRenderModeWithContinuousUpdate()) {
+ if (renderer && renderer->hasCustomRenderModeWithContinuousUpdate()) {
// For the overdraw visualizer. This update is not urgent so avoid a
// direct update() call, this is only here to keep the overdraw
// visualization box rotating even when the scene is static.
@@ -682,10 +683,13 @@ void QQuickWindow::handleApplicationStateChanged(Qt::ApplicationState state)
QQmlListProperty<QObject> QQuickWindowPrivate::data()
{
- return QQmlListProperty<QObject>(q_func(), nullptr, QQuickWindowPrivate::data_append,
- QQuickWindowPrivate::data_count,
- QQuickWindowPrivate::data_at,
- QQuickWindowPrivate::data_clear);
+ return QQmlListProperty<QObject>(q_func(), nullptr,
+ QQuickWindowPrivate::data_append,
+ QQuickWindowPrivate::data_count,
+ QQuickWindowPrivate::data_at,
+ QQuickWindowPrivate::data_clear,
+ QQuickWindowPrivate::data_replace,
+ QQuickWindowPrivate::data_removeLast);
}
static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::TouchPoint &p, QTouchEvent *event, QQuickItem *item, bool transformNeeded = true)
@@ -2119,6 +2123,17 @@ void QQuickWindow::wheelEvent(QWheelEvent *event)
}
#endif // wheelevent
+#if QT_CONFIG(tabletevent)
+/*! \reimp */
+void QQuickWindow::tabletEvent(QTabletEvent *event)
+{
+ Q_D(QQuickWindow);
+ qCDebug(lcTablet) << event;
+ // TODO Qt 6: make sure TabletEnterProximity and TabletLeaveProximity are delivered here
+ d->deliverPointerEvent(d->pointerEventInstance(event));
+}
+#endif // tabletevent
+
bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event)
{
qCDebug(DBG_TOUCH) << event;
@@ -2397,8 +2412,12 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevic
#endif
ev = new QQuickPointerTouchEvent(q, device);
break;
+ case QQuickPointerDevice::Stylus:
+ case QQuickPointerDevice::Airbrush:
+ case QQuickPointerDevice::Puck:
+ ev = new QQuickPointerTabletEvent(q, device);
+ break;
default:
- // TODO tablet event types
break;
}
pointerEventInstances << ev;
@@ -2429,7 +2448,15 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) con
case QEvent::TouchCancel:
dev = QQuickPointerDevice::touchDevice(static_cast<QTouchEvent *>(event)->device());
break;
- // TODO tablet event types
+#if QT_CONFIG(tabletevent)
+ case QEvent::TabletPress:
+ case QEvent::TabletMove:
+ case QEvent::TabletRelease:
+ case QEvent::TabletEnterProximity:
+ case QEvent::TabletLeaveProximity:
+ dev = QQuickPointerDevice::tabletDevice(static_cast<QTabletEvent *>(event));
+ break;
+#endif
#if QT_CONFIG(gestures)
case QEvent::NativeGesture:
dev = QQuickPointerDevice::touchDevice(static_cast<QNativeGestureEvent *>(event)->device());
@@ -2464,6 +2491,11 @@ void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event)
deliverTouchEvent(event->asPointerTouchEvent());
} else {
deliverSinglePointEventUntilAccepted(event);
+ // If any handler got interested in the tablet event, we don't want to receive a synth-mouse event from QtGui
+ // TODO Qt 6: QTabletEvent will be accepted by default, like other events
+ if (event->asPointerTabletEvent() &&
+ (!event->point(0)->passiveGrabbers().isEmpty() || event->point(0)->exclusiveGrabber()))
+ event->setAccepted(true);
}
event->reset(nullptr);
@@ -3257,6 +3289,20 @@ void QQuickWindowPrivate::data_clear(QQmlListProperty<QObject> *property)
itemProperty.clear(&itemProperty);
}
+void QQuickWindowPrivate::data_replace(QQmlListProperty<QObject> *property, int i, QObject *o)
+{
+ QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
+ QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
+ itemProperty.replace(&itemProperty, i, o);
+}
+
+void QQuickWindowPrivate::data_removeLast(QQmlListProperty<QObject> *property)
+{
+ QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
+ QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
+ itemProperty.removeLast(&itemProperty);
+}
+
bool QQuickWindowPrivate::isRenderable() const
{
Q_Q(const QQuickWindow);
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index d22bba4512..097627374c 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -252,6 +252,9 @@ protected:
#if QT_CONFIG(wheelevent)
void wheelEvent(QWheelEvent *) override;
#endif
+#if QT_CONFIG(tabletevent)
+ void tabletEvent(QTabletEvent *) override;
+#endif
private Q_SLOTS:
void maybeUpdate();
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 6e6dc7a400..86bdaf6396 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -299,6 +299,8 @@ public:
static int data_count(QQmlListProperty<QObject> *);
static QObject *data_at(QQmlListProperty<QObject> *, int);
static void data_clear(QQmlListProperty<QObject> *);
+ static void data_replace(QQmlListProperty<QObject> *, int, QObject *);
+ static void data_removeLast(QQmlListProperty<QObject> *);
static void contextCreationFailureMessage(const QSurfaceFormat &format,
QString *translatedMessage,
diff --git a/src/quick/qtquickglobal_p.h b/src/quick/qtquickglobal_p.h
index f6376a6d17..80e59563c7 100644
--- a/src/quick/qtquickglobal_p.h
+++ b/src/quick/qtquickglobal_p.h
@@ -61,6 +61,8 @@
#define Q_QUICK_PRIVATE_EXPORT Q_QUICK_EXPORT
+void Q_QUICK_PRIVATE_EXPORT qml_register_types_QtQuick();
+
QT_BEGIN_NAMESPACE
void QQuick_initializeProviders();
diff --git a/src/quick/quick.pro b/src/quick/quick.pro
index 6db2ae884e..9ddd67c33d 100644
--- a/src/quick/quick.pro
+++ b/src/quick/quick.pro
@@ -23,13 +23,10 @@ exists("qqml_enable_gcov") {
QMAKE_DOCS = $$PWD/doc/qtquick.qdocconf
-ANDROID_LIB_DEPENDENCIES = \
- lib/libQt5QuickParticles.so
MODULE_PLUGIN_TYPES += \
scenegraph
ANDROID_BUNDLED_FILES += \
- qml \
- lib/libQt5QuickParticles.so
+ qml
include(util/util.pri)
include(scenegraph/scenegraph.pri)
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 4777f46f0a..9b288029b4 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -660,6 +660,11 @@ void QSGRenderThread::sync(bool inExpose, bool inGrab)
qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- window has bad size, sync aborted");
}
+ // Two special cases: For grabs we do not care about blocking the gui
+ // (main) thread. When this is from an expose, we will keep locked until
+ // the frame is rendered (submitted), so in that case waking happens later
+ // in syncAndRender(). Otherwise, wake now and let the main thread go on
+ // while we render.
if (!inExpose && !inGrab) {
qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- sync complete, waking Gui");
waitCondition.wakeOne();
@@ -756,13 +761,11 @@ void QSGRenderThread::syncAndRender(QImage *grabImage)
QCoreApplication::postEvent(window, new QEvent(QEvent::Type(QQuickWindowPrivate::FullUpdateRequest)));
// Before returning we need to ensure the same wake up logic that
// would have happened if beginFrame() had suceeded.
- if (exposeRequested) {
+ if (syncRequested && !grabRequested) {
+ // Lock like sync() would do. Note that exposeRequested always includes syncRequested.
qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- bailing out due to failed beginFrame, wake Gui");
- waitCondition.wakeOne();
- mutex.unlock();
- } else if (syncRequested && !grabRequested) {
- qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- bailing out due to failed beginFrame, wake Gui like sync would do");
mutex.lock();
+ // Go ahead with waking because we will return right after this.
waitCondition.wakeOne();
mutex.unlock();
}
@@ -885,7 +888,8 @@ void QSGRenderThread::syncAndRender(QImage *grabImage)
// has started rendering with a bad window, causing makeCurrent to
// fail or if the window has a bad size.
if (exposeRequested) {
- qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- wake Gui after initial expose");
+ // With expose sync() did not wake gui, do it now.
+ qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- wake Gui after expose");
waitCondition.wakeOne();
mutex.unlock();
}
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 2ae9debbc9..8846edcd44 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -427,11 +427,12 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e
imgio.setScaledSize(scSize);
if (!requestRegion.isNull())
imgio.setScaledClipRect(requestRegion);
+ const QSize originalSize = imgio.size();
qCDebug(lcImg) << url << "frame" << frame << "of" << imgio.imageCount()
- << "requestRegion" << requestRegion << "QImageReader size" << imgio.size() << "-> scSize" << scSize;
+ << "requestRegion" << requestRegion << "QImageReader size" << originalSize << "-> scSize" << scSize;
if (impsize)
- *impsize = imgio.size();
+ *impsize = originalSize;
if (imgio.read(image)) {
maybeRemoveAlpha(image);
@@ -1025,8 +1026,11 @@ public:
inline bool operator==(const QQuickPixmapKey &lhs, const QQuickPixmapKey &rhs)
{
- return *lhs.region == *rhs.region && *lhs.size == *rhs.size && *lhs.url == *rhs.url &&
- lhs.options == rhs.options && lhs.frame == rhs.frame;
+ return *lhs.url == *rhs.url &&
+ *lhs.region == *rhs.region &&
+ *lhs.size == *rhs.size &&
+ lhs.frame == rhs.frame &&
+ lhs.options == rhs.options;
}
inline uint qHash(const QQuickPixmapKey &key)
diff --git a/src/quick/util/qquickstate.cpp b/src/quick/util/qquickstate.cpp
index c106528f45..71ab1f4d62 100644
--- a/src/quick/util/qquickstate.cpp
+++ b/src/quick/util/qquickstate.cpp
@@ -267,9 +267,13 @@ void QQuickState::setExtends(const QString &extends)
QQmlListProperty<QQuickStateOperation> QQuickState::changes()
{
Q_D(QQuickState);
- return QQmlListProperty<QQuickStateOperation>(this, &d->operations, QQuickStatePrivate::operations_append,
- QQuickStatePrivate::operations_count, QQuickStatePrivate::operations_at,
- QQuickStatePrivate::operations_clear);
+ return QQmlListProperty<QQuickStateOperation>(this, &d->operations,
+ QQuickStatePrivate::operations_append,
+ QQuickStatePrivate::operations_count,
+ QQuickStatePrivate::operations_at,
+ QQuickStatePrivate::operations_clear,
+ QQuickStatePrivate::operations_replace,
+ QQuickStatePrivate::operations_removeLast);
}
int QQuickState::operationCount() const
diff --git a/src/quick/util/qquickstate_p_p.h b/src/quick/util/qquickstate_p_p.h
index 2fa5321165..ae4ed291b5 100644
--- a/src/quick/util/qquickstate_p_p.h
+++ b/src/quick/util/qquickstate_p_p.h
@@ -244,6 +244,23 @@ public:
QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
return list->at(index);
}
+ static void operations_replace(QQmlListProperty<QQuickStateOperation> *prop, int index,
+ QQuickStateOperation *op) {
+ QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ auto &guard = list->at(index);
+ if (guard.object() == op) {
+ op->setState(qobject_cast<QQuickState*>(prop->object));
+ } else {
+ list->at(index)->setState(nullptr);
+ op->setState(qobject_cast<QQuickState*>(prop->object));
+ list->replace(index, OperationGuard(op, list));
+ }
+ }
+ static void operations_removeLast(QQmlListProperty<QQuickStateOperation> *prop) {
+ QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ list->last()->setState(nullptr);
+ list->removeLast();
+ }
QQuickTransitionManager transitionManager;
diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp
index 46e7d62fc1..2109aafc10 100644
--- a/src/quick/util/qquickstategroup.cpp
+++ b/src/quick/util/qquickstategroup.cpp
@@ -70,6 +70,8 @@ public:
static int count_state(QQmlListProperty<QQuickState> *list);
static QQuickState *at_state(QQmlListProperty<QQuickState> *list, int index);
static void clear_states(QQmlListProperty<QQuickState> *list);
+ static void replace_states(QQmlListProperty<QQuickState> *list, int index, QQuickState *state);
+ static void removeLast_states(QQmlListProperty<QQuickState> *list);
static void append_transition(QQmlListProperty<QQuickTransition> *list, QQuickTransition *state);
static int count_transitions(QQmlListProperty<QQuickTransition> *list);
@@ -163,10 +165,13 @@ QList<QQuickState *> QQuickStateGroup::states() const
QQmlListProperty<QQuickState> QQuickStateGroup::statesProperty()
{
Q_D(QQuickStateGroup);
- return QQmlListProperty<QQuickState>(this, &d->states, &QQuickStateGroupPrivate::append_state,
- &QQuickStateGroupPrivate::count_state,
- &QQuickStateGroupPrivate::at_state,
- &QQuickStateGroupPrivate::clear_states);
+ return QQmlListProperty<QQuickState>(this, &d->states,
+ &QQuickStateGroupPrivate::append_state,
+ &QQuickStateGroupPrivate::count_state,
+ &QQuickStateGroupPrivate::at_state,
+ &QQuickStateGroupPrivate::clear_states,
+ &QQuickStateGroupPrivate::replace_states,
+ &QQuickStateGroupPrivate::removeLast_states);
}
void QQuickStateGroupPrivate::append_state(QQmlListProperty<QQuickState> *list, QQuickState *state)
@@ -201,6 +206,29 @@ void QQuickStateGroupPrivate::clear_states(QQmlListProperty<QQuickState> *list)
_this->d_func()->states.clear();
}
+void QQuickStateGroupPrivate::replace_states(QQmlListProperty<QQuickState> *list, int index, QQuickState *state)
+{
+ auto *self = qobject_cast<QQuickStateGroup *>(list->object);
+ auto *d = self->d_func();
+ auto *oldState = d->states.at(index);
+ if (oldState != state) {
+ oldState->setStateGroup(nullptr);
+ state->setStateGroup(self);
+ d->states.replace(index, state);
+ if (d->currentState == oldState->name())
+ d->setCurrentStateInternal(state->name(), true);
+ }
+}
+
+void QQuickStateGroupPrivate::removeLast_states(QQmlListProperty<QQuickState> *list)
+{
+ auto *d = qobject_cast<QQuickStateGroup *>(list->object)->d_func();
+ if (d->currentState == d->states.last()->name())
+ d->setCurrentStateInternal(d->states.length() > 1 ? d->states.first()->name() : QString(), true);
+ d->states.last()->setStateGroup(nullptr);
+ d->states.removeLast();
+}
+
/*!
\qmlproperty list<Transition> QtQuick::StateGroup::transitions
This property holds a list of transitions defined by the state group.
diff --git a/src/quick/util/qquicktimeline_p_p.h b/src/quick/util/qquicktimeline_p_p.h
index abb5369b7b..fc5bd15ed1 100644
--- a/src/quick/util/qquicktimeline_p_p.h
+++ b/src/quick/util/qquicktimeline_p_p.h
@@ -52,6 +52,7 @@
//
#include <QtCore/QObject>
+#include <private/qtquickglobal_p.h>
#include "private/qabstractanimationjob_p.h"
QT_BEGIN_NAMESPACE
@@ -61,7 +62,7 @@ class QQuickTimeLineValue;
class QQuickTimeLineCallback;
struct QQuickTimeLinePrivate;
class QQuickTimeLineObject;
-class Q_AUTOTEST_EXPORT QQuickTimeLine : public QObject, QAbstractAnimationJob
+class Q_QUICK_PRIVATE_EXPORT QQuickTimeLine : public QObject, QAbstractAnimationJob
{
Q_OBJECT
public: