aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/configure.json12
-rw-r--r--src/quick/designer/qqmldesignermetaobject.cpp4
-rw-r--r--src/quick/doc/snippets/qml/pathview/pathview.qml4
-rw-r--r--src/quick/handlers/handlers.pri5
-rw-r--r--src/quick/handlers/qquickhandlerpoint.cpp351
-rw-r--r--src/quick/handlers/qquickhandlerpoint_p.h120
-rw-r--r--src/quick/handlers/qquickmultipointhandler.cpp35
-rw-r--r--src/quick/handlers/qquickmultipointhandler_p.h10
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp37
-rw-r--r--src/quick/handlers/qquickpinchhandler_p.h8
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler.cpp58
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler_p.h22
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler_p_p.h74
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp131
-rw-r--r--src/quick/handlers/qquickpointerhandler_p.h30
-rw-r--r--src/quick/handlers/qquickpointerhandler_p_p.h84
-rw-r--r--src/quick/handlers/qquicksinglepointhandler.cpp258
-rw-r--r--src/quick/handlers/qquicksinglepointhandler_p.h55
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp2
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp16
-rw-r--r--src/quick/items/items.pri10
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp11
-rw-r--r--src/quick/items/qquickanimatedsprite_p.h2
-rw-r--r--src/quick/items/qquickevents.cpp214
-rw-r--r--src/quick/items/qquickevents_p_p.h108
-rw-r--r--src/quick/items/qquickitem.cpp2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp3
-rw-r--r--src/quick/items/qquickitemview.cpp106
-rw-r--r--src/quick/items/qquickitemview_p_p.h37
-rw-r--r--src/quick/items/qquickitemviewfxitem.cpp165
-rw-r--r--src/quick/items/qquickitemviewfxitem_p_p.h108
-rw-r--r--src/quick/items/qquickloader.cpp15
-rw-r--r--src/quick/items/qquickloader_p_p.h3
-rw-r--r--src/quick/items/qquickrectangle.cpp36
-rw-r--r--src/quick/items/qquickrectangle_p.h10
-rw-r--r--src/quick/items/qquickrendercontrol.cpp1
-rw-r--r--src/quick/items/qquickscalegrid.cpp4
-rw-r--r--src/quick/items/qquickscalegrid_p_p.h12
-rw-r--r--src/quick/items/qquicktableview.cpp1474
-rw-r--r--src/quick/items/qquicktableview_p.h216
-rw-r--r--src/quick/items/qquicktableview_p_p.h342
-rw-r--r--src/quick/items/qquicktext.cpp47
-rw-r--r--src/quick/items/qquicktext_p_p.h1
-rw-r--r--src/quick/items/qquickwindow.cpp147
-rw-r--r--src/quick/items/qquickwindow_p.h7
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp5
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h1
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp12
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h4
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h1
-rw-r--r--src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp225
-rw-r--r--src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h2
-rw-r--r--src/quick/util/qquickanimation.cpp22
-rw-r--r--src/quick/util/qquickanimation_p.h1
-rw-r--r--src/quick/util/qquickimageprovider.cpp5
-rw-r--r--src/quick/util/qquickimageprovider.h6
-rw-r--r--src/quick/util/qquickimageprovider_p.h72
-rw-r--r--src/quick/util/qquickpixmapcache.cpp19
-rw-r--r--src/quick/util/qquickprofiler.cpp3
-rw-r--r--src/quick/util/qquickprofiler_p.h2
-rw-r--r--src/quick/util/qquickstate.cpp2
-rw-r--r--src/quick/util/qquickstate_p_p.h4
-rw-r--r--src/quick/util/qquicksvgparser.cpp3
-rw-r--r--src/quick/util/qquickutilmodule.cpp3
-rw-r--r--src/quick/util/util.pri1
66 files changed, 3834 insertions, 958 deletions
diff --git a/src/quick/configure.json b/src/quick/configure.json
index ea1d49baad..ab356be557 100644
--- a/src/quick/configure.json
+++ b/src/quick/configure.json
@@ -15,6 +15,7 @@
"quick-flipable": "boolean",
"quick-gridview": "boolean",
"quick-listview": "boolean",
+ "quick-tableview": "boolean",
"quick-path": "boolean",
"quick-pathview": "boolean",
"quick-positioners": "boolean",
@@ -86,7 +87,7 @@
},
"quick-itemview": {
"label": "ItemView item",
- "condition": "features.quick-gridview || features.quick-listview",
+ "condition": "features.quick-gridview || features.quick-listview || features.quick-tableview",
"output": [
"privateFeature"
]
@@ -107,6 +108,14 @@
"privateFeature"
]
},
+ "quick-tableview": {
+ "label": "TableView item",
+ "purpose": "Provides the TableView item.",
+ "section": "Qt Quick",
+ "output": [
+ "privateFeature"
+ ]
+ },
"quick-particles": {
"label": "Particle support",
"purpose": "Provides a particle system.",
@@ -183,6 +192,7 @@
"quick-flipable",
"quick-gridview",
"quick-listview",
+ "quick-tableview",
"quick-path",
"quick-pathview",
"quick-positioners",
diff --git a/src/quick/designer/qqmldesignermetaobject.cpp b/src/quick/designer/qqmldesignermetaobject.cpp
index 09493c30d6..2efcdada8b 100644
--- a/src/quick/designer/qqmldesignermetaobject.cpp
+++ b/src/quick/designer/qqmldesignermetaobject.cpp
@@ -83,7 +83,7 @@ static QQmlPropertyCache *cacheForObject(QObject *object, QQmlEngine *engine)
{
QQmlVMEMetaObject *metaObject = QQmlVMEMetaObject::get(object);
if (metaObject)
- return metaObject->cache;
+ return metaObject->cache.data();
return QQmlEnginePrivate::get(engine)->cache(object);
}
@@ -139,7 +139,7 @@ QQmlDesignerMetaObject::QQmlDesignerMetaObject(QObject *object, QQmlEngine *engi
cache->setParent(ddata->propertyCache);
cache->invalidate(engine, this);
ddata->propertyCache->release();
- ddata->propertyCache = cache;
+ ddata->propertyCache = cache.data();
ddata->propertyCache->addref();
}
diff --git a/src/quick/doc/snippets/qml/pathview/pathview.qml b/src/quick/doc/snippets/qml/pathview/pathview.qml
index 1a31f1372b..58d19b1a0c 100644
--- a/src/quick/doc/snippets/qml/pathview/pathview.qml
+++ b/src/quick/doc/snippets/qml/pathview/pathview.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -59,6 +59,7 @@ Rectangle {
id: delegate
Column {
id: wrapper
+ opacity: PathView.isCurrentItem ? 1 : 0.5
Image {
anchors.horizontalCenter: nameText.horizontalCenter
width: 64; height: 64
@@ -68,7 +69,6 @@ Rectangle {
id: nameText
text: name
font.pointSize: 16
- color: wrapper.PathView.isCurrentItem ? "red" : "black"
}
}
}
diff --git a/src/quick/handlers/handlers.pri b/src/quick/handlers/handlers.pri
index 8bd74d95da..a096643403 100644
--- a/src/quick/handlers/handlers.pri
+++ b/src/quick/handlers/handlers.pri
@@ -1,16 +1,20 @@
HEADERS += \
$$PWD/qquickdraghandler_p.h \
+ $$PWD/qquickhandlerpoint_p.h \
$$PWD/qquickhandlersmodule_p.h \
$$PWD/qquickmultipointhandler_p.h \
$$PWD/qquickpinchhandler_p.h \
$$PWD/qquickpointerdevicehandler_p.h \
+ $$PWD/qquickpointerdevicehandler_p_p.h \
$$PWD/qquickpointerhandler_p.h \
+ $$PWD/qquickpointerhandler_p_p.h \
$$PWD/qquickpointhandler_p.h \
$$PWD/qquicksinglepointhandler_p.h \
$$PWD/qquicktaphandler_p.h \
SOURCES += \
$$PWD/qquickdraghandler.cpp \
+ $$PWD/qquickhandlerpoint.cpp \
$$PWD/qquickhandlersmodule.cpp \
$$PWD/qquickmultipointhandler.cpp \
$$PWD/qquickpinchhandler.cpp \
@@ -19,4 +23,3 @@ SOURCES += \
$$PWD/qquickpointhandler.cpp \
$$PWD/qquicksinglepointhandler.cpp \
$$PWD/qquicktaphandler.cpp \
-
diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp
new file mode 100644
index 0000000000..4bd5d2cbfb
--- /dev/null
+++ b/src/quick/handlers/qquickhandlerpoint.cpp
@@ -0,0 +1,351 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickhandlerpoint_p.h"
+#include "private/qquickevents_p_p.h"
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH_TARGET)
+
+/*!
+ \qmltype HandlerPoint
+ \instantiates QQuickHandlerPoint
+ \inqmlmodule Qt.labs.handlers
+ \ingroup qtquick-handlers
+ \brief An event point.
+
+ A QML representation of a QQuickEventPoint.
+
+ It's possible to make bindings to properties of a \l SinglePointHandler's
+ current point. For example:
+
+ \snippet pointerHandlers/dragHandlerNullTarget.qml 0
+
+ The point is kept up-to-date when the DragHandler is actively responding to
+ an EventPoint; but when the point is released, or the current point is
+ being handled by a different handler, \c position.x and \c position.y are 0.
+
+ \note This is practically identical to QtQuick::EventPoint; however an
+ EventPoint is a long-lived QObject which is invalidated between gestures
+ and reused for subsequent event deliveries. Continuous bindings to its
+ properties are not possible, and an individual handler cannot rely on it
+ outside the period when that point is part of an active gesture which that
+ handler is handling. HandlerPoint is a Q_GADGET that the handler owns.
+ This allows you to make lifetime bindings to its properties.
+
+ \sa SinglePointHandler::point
+*/
+
+QQuickHandlerPoint::QQuickHandlerPoint()
+ : m_id(0)
+ , m_rotation(0)
+ , m_pressure(0)
+{}
+
+void QQuickHandlerPoint::reset()
+{
+ m_id = 0;
+ m_uniqueId = QPointingDeviceUniqueId();
+ m_position = QPointF();
+ m_scenePosition = QPointF();
+ m_pressPosition = QPointF();
+ m_scenePressPosition = QPointF();
+ m_sceneGrabPosition = QPointF();
+ m_velocity = QVector2D();
+ m_rotation = 0;
+ m_pressure = 0;
+ m_ellipseDiameters = QSizeF();
+ m_pressedButtons = Qt::NoButton;
+ m_pressedModifiers = Qt::NoModifier;
+}
+
+void QQuickHandlerPoint::reset(const QQuickEventPoint *point)
+{
+ m_id = point->pointId();
+ const QQuickPointerEvent *event = point->pointerEvent();
+ switch (point->state()) {
+ case QQuickEventPoint::Pressed:
+ m_pressPosition = point->position();
+ m_scenePressPosition = point->scenePosition();
+ m_pressedButtons = event->buttons();
+ break;
+ case QQuickEventPoint::Released:
+ reset();
+ return;
+ default:
+ m_pressedButtons = event->buttons();
+ break;
+ }
+ m_pressedModifiers = event->modifiers();
+ if (event->asPointerTouchEvent()) {
+ const QQuickEventTouchPoint *tp = static_cast<const QQuickEventTouchPoint *>(point);
+ m_uniqueId = tp->uniqueId();
+ m_rotation = tp->rotation();
+ m_pressure = tp->pressure();
+ m_ellipseDiameters = tp->ellipseDiameters();
+ } else if (event->asPointerTabletEvent()) {
+ // TODO
+ } else {
+ m_uniqueId = event->device()->uniqueId();
+ m_rotation = 0;
+ m_pressure = event->buttons() ? 1 : 0;
+ m_ellipseDiameters = QSizeF();
+ }
+ m_position = point->position();
+ m_scenePosition = point->scenePosition();
+ if (point->state() == QQuickEventPoint::Updated)
+ m_velocity = point->velocity();
+}
+
+void QQuickHandlerPoint::reset(const QVector<QQuickEventPoint *> &points)
+{
+ if (points.isEmpty()) {
+ qWarning("reset: no points");
+ return;
+ }
+ if (points.count() == 1) {
+ reset(points.first());
+ return;
+ }
+ // all points are required to be from the same event
+ const QQuickPointerEvent *event = points.first()->pointerEvent();
+ QPointF posSum;
+ QPointF scenePosSum;
+ QVector2D velocitySum;
+ qreal pressureSum = 0;
+ QSizeF ellipseDiameterSum;
+ bool press = false;
+ const QQuickPointerTouchEvent *touchEvent = event->asPointerTouchEvent();
+ for (const QQuickEventPoint *point : qAsConst(points)) {
+ posSum += point->position();
+ scenePosSum += point->scenePosition();
+ velocitySum += point->velocity();
+ if (touchEvent) {
+ pressureSum += static_cast<const QQuickEventTouchPoint *>(point)->pressure();
+ ellipseDiameterSum += static_cast<const QQuickEventTouchPoint *>(point)->ellipseDiameters();
+ }
+ if (point->state() == QQuickEventPoint::Pressed)
+ press = true;
+ }
+ m_id = 0;
+ m_uniqueId = QPointingDeviceUniqueId();
+ m_pressedButtons = event->buttons();
+ m_pressedModifiers = event->modifiers();
+ m_position = posSum / points.size();
+ m_scenePosition = scenePosSum / points.size();
+ if (press) {
+ m_pressPosition = m_position;
+ m_scenePressPosition = m_scenePosition;
+ }
+ m_velocity = velocitySum / points.size();
+ m_rotation = 0; // averaging the rotations of all the points isn't very sensible
+ m_pressure = pressureSum / points.size();
+ m_ellipseDiameters = ellipseDiameterSum / points.size();
+}
+
+/*!
+ \readonly
+ \qmlproperty int QtQuick::HandlerPoint::id
+ \brief The ID number of the point
+
+ During a touch gesture, from the time that the first finger is pressed
+ until the last finger is released, each touchpoint will have a unique ID
+ number. Likewise, if input from multiple devices occurs (for example
+ simultaneous mouse and touch presses), all the current event points from
+ all the devices will have unique IDs.
+
+ \note Do not assume that id numbers start at zero or that they are
+ sequential. Such an assumption is often false due to the way the underlying
+ drivers work.
+
+ \sa QTouchEvent::TouchPoint::id
+*/
+
+/*!
+ \readonly
+ \qmlproperty PointingDeviceUniqueId QtQuick::HandlerPoint::uniqueId
+ \brief The unique ID of the point, if any
+
+ This is normally empty, because touchscreens cannot uniquely identify fingers.
+
+ On some types of touchscreens, especially those using TUIO drivers,
+ it's possible to use recognizable physical tokens (fiducial objects)
+ in addition to fingers. So if this point is a touch point, and
+ uniqueId is set, it is the identifier for such an object.
+
+ On a graphics tablet, each type of stylus or other tool often has a unique
+ ID or serial number, which can be useful to respond in different ways to
+ different tools.
+
+ Interpreting the contents of this ID requires knowledge of the hardware and
+ drivers in use.
+
+ \sa QTabletEvent::uniqueId, QtQuick::TouchPoint::uniqueId, QtQuick::EventTouchPoint::uniqueId
+*/
+
+/*!
+ \readonly
+ \qmlproperty QPointF QtQuick::HandlerPoint::position
+ \brief The position within the \c parent Item
+
+ This is the position of the event point relative to the bounds of
+ the \l {PointerHandler::parent} {parent}.
+*/
+
+/*!
+ \readonly
+ \qmlproperty QPointF QtQuick::HandlerPoint::scenePosition
+ \brief The position within the scene
+
+ This is the position of the event point relative to the bounds of the Qt
+ Quick scene (typically the whole window).
+*/
+
+/*!
+ \readonly
+ \qmlproperty QPointF QtQuick::HandlerPoint::pressPosition
+ \brief The pressed position within the \c parent Item
+
+ This is the position at which this point was pressed, relative to the
+ bounds of the \l {PointerHandler::parent} {parent}.
+*/
+
+/*!
+ \readonly
+ \qmlproperty QPointF QtQuick::HandlerPoint::scenePressPosition
+ \brief The pressed position within the scene
+
+ This is the position at which this point was pressed, in the coordinate
+ system of the \l {Qt Quick Scene Graph}{scene graph}.
+*/
+
+/*!
+ \readonly
+ \qmlproperty QPointF QtQuick::HandlerPoint::sceneGrabPosition
+ \brief The grabbed position within the scene
+
+ If this point has been grabbed by a Pointer Handler or an Item, it means
+ that object has taken sole responsibility for handling the movement and the
+ release if this point. In that case, this is the position at which the grab
+ occurred, in the coordinate system of the \l {Qt Quick Scene Graph}{scene graph}.
+*/
+
+/*!
+ \readonly
+ \qmlproperty enum QtQuick::HandlerPoint::pressedButtons
+ \brief Which mouse or stylus buttons are currently pressed
+
+ \sa MouseArea::pressedButtons
+*/
+
+/*!
+ \readonly
+ \qmlproperty enum QtQuick::HandlerPoint::modifiers
+ \brief Which modifier keys are currently pressed
+
+ This property holds the keyboard modifiers that were pressed at the time
+ the event occurred.
+
+ \sa MouseArea::modifiers
+*/
+
+/*!
+ \readonly
+ \qmlproperty QVector2D QtQuick::HandlerPoint::velocity
+ \brief A vector representing the average speed and direction of movement
+
+ This is a velocity vector pointing in the direction of movement, in logical
+ pixels per second. It has x and y components, at least one of which will be
+ nonzero when this point is in motion. It holds the average recent velocity:
+ how fast and in which direction the event point has been moving recently.
+
+ \sa QtQuick::EventPoint::velocity, QtQuick::TouchPoint::velocity, QTouchEvent::TouchPoint::velocity
+*/
+
+/*!
+ \readonly
+ \qmlproperty qreal QtQuick::HandlerPoint::rotation
+
+ This property holds the rotation angle of the stylus on a graphics tablet
+ or the contact patch of a touchpoint on a touchscreen.
+
+ It is valid only with certain tablet stylus devices and touchscreens that
+ can measure the rotation angle. Otherwise, it will be zero.
+*/
+
+/*!
+ \readonly
+ \qmlproperty qreal QtQuick::HandlerPoint::pressure
+
+ This property tells how hard the user is pressing the stylus on a graphics
+ tablet or the finger against a touchscreen, in the range from \c 0 (no
+ measurable pressure) to \c 1.0 (maximum pressure which the device can
+ measure).
+
+ It is valid only with certain tablets and touchscreens that can measure
+ pressure. Otherwise, it will be zero.
+*/
+
+/*!
+ \readonly
+ \qmlproperty size QtQuick::HandlerPoint::ellipseDiameters
+
+ This property holds the diameters of the contact patch, if the event
+ comes from a touchpoint and the device provides this information.
+
+ A touchpoint is modeled as an elliptical area where the finger is pressed
+ against the touchscreen. (In fact, it could also be modeled as a bitmap;
+ but in that case we expect an elliptical bounding estimate to be fitted to
+ the contact patch before the event is sent.) The harder the user presses,
+ the larger the contact patch; so, these diameters provide an alternate way
+ of detecting pressure, in case the device does not include a separate
+ pressure sensor. The ellipse is centered on \l scenePosition (\l position
+ in the PointerHandler's Item's local coordinates). The \l rotation property
+ provides the rotation of the ellipse, if known. It is expected that if the
+ \l rotation is zero, the \l {QSize::height}{height} is the larger dimension
+ (the major axis), because of the usual hand position, reaching upward or
+ outward across the surface.
+
+ If the contact patch is unknown, or the device is not a touchscreen,
+ these values will be zero.
+
+ \sa QtQuick::EventTouchPoint::ellipseDiameters, QtQuick::TouchPoint::ellipseDiameters, QTouchEvent::TouchPoint::ellipseDiameters
+*/
+
+QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickhandlerpoint_p.h b/src/quick/handlers/qquickhandlerpoint_p.h
new file mode 100644
index 0000000000..1dff52942a
--- /dev/null
+++ b/src/quick/handlers/qquickhandlerpoint_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKHANDLERPOINT_H
+#define QQUICKHANDLERPOINT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickpointerdevicehandler_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMultiPointHandler;
+class QQuickSinglePointHandler;
+
+class Q_QUICK_PRIVATE_EXPORT QQuickHandlerPoint {
+ Q_GADGET
+ Q_PROPERTY(int id READ id)
+ Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId)
+ Q_PROPERTY(QPointF position READ position)
+ Q_PROPERTY(QPointF scenePosition READ scenePosition)
+ Q_PROPERTY(QPointF pressPosition READ pressPosition)
+ Q_PROPERTY(QPointF scenePressPosition READ scenePressPosition)
+ Q_PROPERTY(QPointF sceneGrabPosition READ sceneGrabPosition)
+ Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons)
+ Q_PROPERTY(Qt::KeyboardModifiers modifiers READ modifiers)
+ Q_PROPERTY(QVector2D velocity READ velocity)
+ Q_PROPERTY(qreal rotation READ rotation)
+ Q_PROPERTY(qreal pressure READ pressure)
+ Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters)
+
+public:
+ QQuickHandlerPoint();
+
+ int id() const { return m_id; }
+ Qt::MouseButtons pressedButtons() const { return m_pressedButtons; }
+ Qt::KeyboardModifiers modifiers() const { return m_pressedModifiers; }
+ QPointF pressPosition() const { return m_pressPosition; }
+ QPointF scenePressPosition() const { return m_scenePressPosition; }
+ QPointF sceneGrabPosition() const { return m_sceneGrabPosition; }
+ QPointF position() const { return m_position; }
+ QPointF scenePosition() const { return m_scenePosition; }
+ QVector2D velocity() const { return m_velocity; }
+ qreal rotation() const { return m_rotation; }
+ qreal pressure() const { return m_pressure; }
+ QSizeF ellipseDiameters() const { return m_ellipseDiameters; }
+ QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; }
+
+ void reset();
+ void reset(const QQuickEventPoint *point);
+ void reset(const QVector<QQuickEventPoint *> &points);
+
+private:
+ int m_id;
+ QPointingDeviceUniqueId m_uniqueId;
+ Qt::MouseButtons m_pressedButtons;
+ Qt::KeyboardModifiers m_pressedModifiers;
+ QPointF m_position;
+ QPointF m_scenePosition;
+ QPointF m_pressPosition;
+ QPointF m_scenePressPosition;
+ QPointF m_sceneGrabPosition;
+ QVector2D m_velocity;
+ qreal m_rotation;
+ qreal m_pressure;
+ QSizeF m_ellipseDiameters;
+ friend class QQuickMultiPointHandler;
+ friend class QQuickSinglePointHandler;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickHandlerPoint)
+
+#endif // QQUICKHANDLERPOINT_H
diff --git a/src/quick/handlers/qquickmultipointhandler.cpp b/src/quick/handlers/qquickmultipointhandler.cpp
index d595b4c9b4..89733a4260 100644
--- a/src/quick/handlers/qquickmultipointhandler.cpp
+++ b/src/quick/handlers/qquickmultipointhandler.cpp
@@ -91,6 +91,20 @@ bool QQuickMultiPointHandler::wantsPointerEvent(QQuickPointerEvent *event)
return ret;
}
+void QQuickMultiPointHandler::handlePointerEventImpl(QQuickPointerEvent *event)
+{
+ QQuickPointerHandler::handlePointerEventImpl(event);
+ m_centroid.reset(m_currentPoints);
+ emit centroidChanged();
+}
+
+void QQuickMultiPointHandler::onActiveChanged()
+{
+ if (active()) {
+ m_centroid.m_sceneGrabPosition = m_centroid.m_scenePosition;
+ }
+}
+
QVector<QQuickEventPoint *> QQuickMultiPointHandler::eligiblePoints(QQuickPointerEvent *event)
{
QVector<QQuickEventPoint *> ret;
@@ -207,27 +221,6 @@ bool QQuickMultiPointHandler::sameAsCurrentPoints(QQuickPointerEvent *event)
return ret;
}
-// TODO make templates for these functions somehow?
-QPointF QQuickMultiPointHandler::touchPointCentroid()
-{
- QPointF ret;
- if (Q_UNLIKELY(m_currentPoints.size() == 0))
- return ret;
- for (QQuickEventPoint *point : qAsConst(m_currentPoints))
- ret += point->scenePosition();
- return ret / m_currentPoints.size();
-}
-
-QVector2D QQuickMultiPointHandler::touchPointCentroidVelocity()
-{
- QVector2D ret;
- if (Q_UNLIKELY(m_currentPoints.size() == 0))
- return ret;
- for (QQuickEventPoint *point : qAsConst(m_currentPoints))
- ret += point->velocity();
- return ret / m_currentPoints.size();
-}
-
qreal QQuickMultiPointHandler::averageTouchPointDistance(const QPointF &ref)
{
qreal ret = 0;
diff --git a/src/quick/handlers/qquickmultipointhandler_p.h b/src/quick/handlers/qquickmultipointhandler_p.h
index 67e550d387..5a44866e67 100644
--- a/src/quick/handlers/qquickmultipointhandler_p.h
+++ b/src/quick/handlers/qquickmultipointhandler_p.h
@@ -53,6 +53,7 @@
#include "qquickitem.h"
#include "qevent.h"
+#include "qquickhandlerpoint_p.h"
#include "qquickpointerdevicehandler_p.h"
QT_BEGIN_NAMESPACE
@@ -63,6 +64,7 @@ class Q_AUTOTEST_EXPORT QQuickMultiPointHandler : public QQuickPointerDeviceHand
Q_PROPERTY(int minimumPointCount READ minimumPointCount WRITE setMinimumPointCount NOTIFY minimumPointCountChanged)
Q_PROPERTY(int maximumPointCount READ maximumPointCount WRITE setMaximumPointCount NOTIFY maximumPointCountChanged)
Q_PROPERTY(qreal pointDistanceThreshold READ pointDistanceThreshold WRITE setPointDistanceThreshold NOTIFY pointDistanceThresholdChanged)
+ Q_PROPERTY(QQuickHandlerPoint centroid READ centroid NOTIFY centroidChanged)
public:
explicit QQuickMultiPointHandler(QObject *parent = nullptr, int minimumPointCount = 2);
@@ -77,10 +79,13 @@ public:
qreal pointDistanceThreshold() const { return m_pointDistanceThreshold; }
void setPointDistanceThreshold(qreal pointDistanceThreshold);
+ QQuickHandlerPoint centroid() const { return m_centroid; }
+
signals:
void minimumPointCountChanged();
void maximumPointCountChanged();
void pointDistanceThresholdChanged();
+ void centroidChanged();
protected:
struct PointData {
@@ -91,10 +96,10 @@ protected:
};
bool wantsPointerEvent(QQuickPointerEvent *event) override;
+ void handlePointerEventImpl(QQuickPointerEvent *event) override;
+ void onActiveChanged() override;
bool sameAsCurrentPoints(QQuickPointerEvent *event);
QVector<QQuickEventPoint *> eligiblePoints(QQuickPointerEvent *event);
- QPointF touchPointCentroid();
- QVector2D touchPointCentroidVelocity();
qreal averageTouchPointDistance(const QPointF &ref);
qreal averageStartingDistance(const QPointF &ref);
qreal averageTouchPointAngle(const QPointF &ref);
@@ -106,6 +111,7 @@ protected:
protected:
QVector<QQuickEventPoint *> m_currentPoints;
+ QQuickHandlerPoint m_centroid;
int m_minimumPointCount;
int m_maximumPointCount;
qreal m_pointDistanceThreshold;
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index 57d851ed59..412ad6227d 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -287,11 +287,11 @@ bool QQuickPinchHandler::wantsPointerEvent(QQuickPointerEvent *event)
void QQuickPinchHandler::onActiveChanged()
{
+ QQuickMultiPointHandler::onActiveChanged();
if (active()) {
m_startMatrix = QMatrix4x4();
- m_startCentroid = touchPointCentroid();
- m_startAngles = angles(m_startCentroid);
- m_startDistance = averageTouchPointDistance(m_startCentroid);
+ m_startAngles = angles(m_centroid.sceneGrabPosition());
+ m_startDistance = averageTouchPointDistance(m_centroid.sceneGrabPosition());
m_activeRotation = 0;
m_activeTranslation = QVector2D();
if (const QQuickItem *t = target()) {
@@ -319,6 +319,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
for (QQuickEventPoint *point : qAsConst(m_currentPoints))
qCDebug(lcPinchHandler) << point->state() << point->sceneGrabPosition() << "->" << point->scenePosition();
}
+ QQuickMultiPointHandler::handlePointerEventImpl(event);
qreal dist = 0;
#if QT_CONFIG(gestures)
@@ -328,8 +329,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
m_activeScale = 1;
m_activeRotation = 0;
m_activeTranslation = QVector2D();
- m_centroid = QPointF();
- m_centroidVelocity = QVector2D();
+ m_centroid.reset();
setActive(false);
emit updated();
return;
@@ -344,12 +344,9 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
return;
}
if (!active()) {
- m_centroid = gesture->point(0)->scenePosition();
setActive(true);
- m_startCentroid = m_centroid;
// Native gestures for 2-finger pinch do not allow dragging, so
// the centroid won't move during the gesture, and translation stays at zero
- m_centroidVelocity = QVector2D();
m_activeTranslation = QVector2D();
}
} else
@@ -374,17 +371,15 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
return;
}
// TODO check m_pinchOrigin: right now it acts like it's set to PinchCenter
- m_centroid = touchPointCentroid();
- m_centroidVelocity = touchPointCentroidVelocity();
// avoid mapping the minima and maxima, as they might have unmappable values
// such as -inf/+inf. Because of this we perform the bounding to min/max in local coords.
// 1. scale
- dist = averageTouchPointDistance(m_centroid);
+ dist = averageTouchPointDistance(m_centroid.scenePosition());
m_activeScale = dist / m_startDistance;
m_activeScale = qBound(m_minimumScale/m_startScale, m_activeScale, m_maximumScale/m_startScale);
// 2. rotate
- QVector<PointData> newAngles = angles(m_centroid);
+ QVector<PointData> newAngles = angles(m_centroid.scenePosition());
const qreal angleDelta = averageAngleDelta(m_startAngles, newAngles);
m_activeRotation += angleDelta;
m_startAngles = std::move(newAngles);
@@ -396,7 +391,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
QPointF centroidParentPos;
QRectF bounds(m_minimumX, m_minimumY, m_maximumX - m_minimumX, m_maximumY - m_minimumY);
if (target() && target()->parentItem()) {
- centroidParentPos = target()->parentItem()->mapFromScene(m_centroid);
+ centroidParentPos = target()->parentItem()->mapFromScene(m_centroid.scenePosition());
centroidParentPos = QPointF(qBound(bounds.left(), centroidParentPos.x(), bounds.right()),
qBound(bounds.top(), centroidParentPos.y(), bounds.bottom()));
}
@@ -407,9 +402,8 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
if (target() && target()->parentItem()) {
// 3. Drag/translate
- const QPointF centroidStartParentPos = target()->parentItem()->mapFromScene(m_startCentroid);
+ const QPointF centroidStartParentPos = target()->parentItem()->mapFromScene(m_centroid.sceneGrabPosition());
m_activeTranslation = QVector2D(centroidParentPos - centroidStartParentPos);
-
// apply rotation + scaling around the centroid - then apply translation.
QMatrix4x4 mat;
@@ -432,10 +426,10 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
// TODO some translation inadvertently happens; try to hold the chosen pinch origin in place
} else {
- m_activeTranslation = QVector2D(m_centroid - m_startCentroid);
+ m_activeTranslation = QVector2D(m_centroid.scenePosition() - m_centroid.scenePressPosition());
}
- qCDebug(lcPinchHandler) << "centroid" << m_startCentroid << "->" << m_centroid
+ qCDebug(lcPinchHandler) << "centroid" << m_centroid.scenePressPosition() << "->" << m_centroid.scenePosition()
<< ", distance" << m_startDistance << "->" << dist
<< ", startScale" << m_startScale << "->" << scale
<< ", activeRotation" << m_activeRotation
@@ -456,15 +450,6 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
/*!
\readonly
- \qmlproperty QVector2D QtQuick::PinchHandler::centroidVelocity
-
- The average velocity of the \l centroid: a vector representing the speed
- and direction of movement of the whole group of touchpoints, in logical
- pixels per second.
-*/
-
-/*!
- \readonly
\qmlproperty real QtQuick::PinchHandler::scale
The scale factor. It is 1.0 when the gesture begins, increases as the
diff --git a/src/quick/handlers/qquickpinchhandler_p.h b/src/quick/handlers/qquickpinchhandler_p.h
index 9a17971416..c2eedeb9e0 100644
--- a/src/quick/handlers/qquickpinchhandler_p.h
+++ b/src/quick/handlers/qquickpinchhandler_p.h
@@ -66,8 +66,6 @@ class Q_AUTOTEST_EXPORT QQuickPinchHandler : public QQuickMultiPointHandler
Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged)
Q_PROPERTY(qreal maximumRotation READ maximumRotation WRITE setMaximumRotation NOTIFY maximumRotationChanged)
Q_PROPERTY(PinchOrigin pinchOrigin READ pinchOrigin WRITE setPinchOrigin NOTIFY pinchOriginChanged)
- Q_PROPERTY(QPointF centroid READ centroid NOTIFY updated)
- Q_PROPERTY(QVector2D centroidVelocity READ centroidVelocity NOTIFY updated)
Q_PROPERTY(qreal scale READ scale NOTIFY updated)
Q_PROPERTY(qreal rotation READ rotation NOTIFY updated)
Q_PROPERTY(QVector2D translation READ translation NOTIFY updated)
@@ -103,9 +101,6 @@ public:
QVector2D translation() const { return m_activeTranslation; }
qreal scale() const { return m_activeScale; }
qreal rotation() const { return m_activeRotation; }
- QPointF centroid() const { return m_centroid; }
- QVector2D centroidVelocity() const { return m_centroidVelocity; }
-
qreal minimumX() const { return m_minimumX; }
void setMinimumX(qreal minX);
qreal maximumX() const { return m_maximumX; }
@@ -137,8 +132,6 @@ private:
qreal m_activeScale;
qreal m_activeRotation;
QVector2D m_activeTranslation;
- QPointF m_centroid;
- QVector2D m_centroidVelocity;
qreal m_minimumScale;
qreal m_maximumScale;
@@ -156,7 +149,6 @@ private:
// internal
qreal m_startScale;
qreal m_startRotation;
- QPointF m_startCentroid;
qreal m_startDistance;
QPointF m_startPos;
diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp
index 06831613b6..add6513c1a 100644
--- a/src/quick/handlers/qquickpointerdevicehandler.cpp
+++ b/src/quick/handlers/qquickpointerdevicehandler.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "qquickpointerdevicehandler_p.h"
+#include "qquickpointerdevicehandler_p_p.h"
#include <private/qquickitem_p.h>
#include <QMouseEvent>
#include <QDebug>
@@ -59,10 +59,12 @@ QT_BEGIN_NAMESPACE
allow filtering based on device type, pointer type, or keyboard modifiers.
*/
QQuickPointerDeviceHandler::QQuickPointerDeviceHandler(QObject *parent)
- : QQuickPointerHandler(parent)
- , m_acceptedDevices(QQuickPointerDevice::AllDevices)
- , m_acceptedPointerTypes(QQuickPointerDevice::AllPointerTypes)
- , m_acceptedModifiers(Qt::KeyboardModifierMask)
+ : QQuickPointerHandler(*(new QQuickPointerDeviceHandlerPrivate), parent)
+{
+}
+
+QQuickPointerDeviceHandler::QQuickPointerDeviceHandler(QQuickPointerDeviceHandlerPrivate &dd, QObject *parent)
+ : QQuickPointerHandler(dd, parent)
{
}
@@ -70,6 +72,24 @@ QQuickPointerDeviceHandler::~QQuickPointerDeviceHandler()
{
}
+QQuickPointerDevice::DeviceTypes QQuickPointerDeviceHandler::acceptedDevices() const
+{
+ Q_D(const QQuickPointerDeviceHandler);
+ return d->acceptedDevices;
+}
+
+QQuickPointerDevice::PointerTypes QQuickPointerDeviceHandler::acceptedPointerTypes() const
+{
+ Q_D(const QQuickPointerDeviceHandler);
+ return d->acceptedPointerTypes;
+}
+
+Qt::KeyboardModifiers QQuickPointerDeviceHandler::acceptedModifiers() const
+{
+ Q_D(const QQuickPointerDeviceHandler);
+ return d->acceptedModifiers;
+}
+
/*!
\qmlproperty int PointerDeviceHandler::acceptedDevices
@@ -98,10 +118,11 @@ QQuickPointerDeviceHandler::~QQuickPointerDeviceHandler()
*/
void QQuickPointerDeviceHandler::setAcceptedDevices(QQuickPointerDevice::DeviceTypes acceptedDevices)
{
- if (m_acceptedDevices == acceptedDevices)
+ Q_D(QQuickPointerDeviceHandler);
+ if (d->acceptedDevices == acceptedDevices)
return;
- m_acceptedDevices = acceptedDevices;
+ d->acceptedDevices = acceptedDevices;
emit acceptedDevicesChanged();
}
@@ -136,10 +157,11 @@ void QQuickPointerDeviceHandler::setAcceptedDevices(QQuickPointerDevice::DeviceT
*/
void QQuickPointerDeviceHandler::setAcceptedPointerTypes(QQuickPointerDevice::PointerTypes acceptedPointerTypes)
{
- if (m_acceptedPointerTypes == acceptedPointerTypes)
+ Q_D(QQuickPointerDeviceHandler);
+ if (d->acceptedPointerTypes == acceptedPointerTypes)
return;
- m_acceptedPointerTypes = acceptedPointerTypes;
+ d->acceptedPointerTypes = acceptedPointerTypes;
emit acceptedPointerTypesChanged();
}
@@ -171,26 +193,28 @@ void QQuickPointerDeviceHandler::setAcceptedPointerTypes(QQuickPointerDevice::Po
*/
void QQuickPointerDeviceHandler::setAcceptedModifiers(Qt::KeyboardModifiers acceptedModifiers)
{
- if (m_acceptedModifiers == acceptedModifiers)
+ Q_D(QQuickPointerDeviceHandler);
+ if (d->acceptedModifiers == acceptedModifiers)
return;
- m_acceptedModifiers = acceptedModifiers;
+ d->acceptedModifiers = acceptedModifiers;
emit acceptedModifiersChanged();
}
bool QQuickPointerDeviceHandler::wantsPointerEvent(QQuickPointerEvent *event)
{
+ Q_D(QQuickPointerDeviceHandler);
if (!QQuickPointerHandler::wantsPointerEvent(event))
return false;
qCDebug(lcPointerHandlerDispatch) << objectName()
- << "checking device type" << m_acceptedDevices
- << "pointer type" << m_acceptedPointerTypes
- << "modifiers" << m_acceptedModifiers;
- if ((event->device()->type() & m_acceptedDevices) == 0)
+ << "checking device type" << d->acceptedDevices
+ << "pointer type" << d->acceptedPointerTypes
+ << "modifiers" << d->acceptedModifiers;
+ if ((event->device()->type() & d->acceptedDevices) == 0)
return false;
- if ((event->device()->pointerType() & m_acceptedPointerTypes) == 0)
+ if ((event->device()->pointerType() & d->acceptedPointerTypes) == 0)
return false;
- if (m_acceptedModifiers != Qt::KeyboardModifierMask && event->modifiers() != m_acceptedModifiers)
+ if (d->acceptedModifiers != Qt::KeyboardModifierMask && event->modifiers() != d->acceptedModifiers)
return false;
return true;
}
diff --git a/src/quick/handlers/qquickpointerdevicehandler_p.h b/src/quick/handlers/qquickpointerdevicehandler_p.h
index 1638604ea7..cd861b2bf1 100644
--- a/src/quick/handlers/qquickpointerdevicehandler_p.h
+++ b/src/quick/handlers/qquickpointerdevicehandler_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -36,6 +36,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+#include "qquickpointerhandler_p.h"
#ifndef QQUICKPOINTERDEVICEHANDLER_H
#define QQUICKPOINTERDEVICEHANDLER_H
@@ -51,10 +52,10 @@
// We mean it.
//
-#include "qquickpointerhandler_p.h"
-
QT_BEGIN_NAMESPACE
+class QQuickPointerDeviceHandlerPrivate;
+
class Q_AUTOTEST_EXPORT QQuickPointerDeviceHandler : public QQuickPointerHandler
{
Q_OBJECT
@@ -66,11 +67,11 @@ public:
explicit QQuickPointerDeviceHandler(QObject *parent = nullptr);
~QQuickPointerDeviceHandler();
- QQuickPointerDevice::DeviceTypes acceptedDevices() const { return m_acceptedDevices; }
- QQuickPointerDevice::PointerTypes acceptedPointerTypes() const { return m_acceptedPointerTypes; }
- Qt::KeyboardModifiers acceptedModifiers() const { return m_acceptedModifiers; }
+ QQuickPointerDevice::DeviceTypes acceptedDevices() const;
+ QQuickPointerDevice::PointerTypes acceptedPointerTypes() const;
+ Qt::KeyboardModifiers acceptedModifiers() const;
-public slots:
+public Q_SLOTS:
void setAcceptedDevices(QQuickPointerDevice::DeviceTypes acceptedDevices);
void setAcceptedPointerTypes(QQuickPointerDevice::PointerTypes acceptedPointerTypes);
void setAcceptedModifiers(Qt::KeyboardModifiers acceptedModifiers);
@@ -81,12 +82,11 @@ Q_SIGNALS:
void acceptedModifiersChanged();
protected:
+ QQuickPointerDeviceHandler(QQuickPointerDeviceHandlerPrivate &dd, QObject *parent = nullptr);
+
bool wantsPointerEvent(QQuickPointerEvent *event) override;
-protected:
- QQuickPointerDevice::DeviceTypes m_acceptedDevices;
- QQuickPointerDevice::PointerTypes m_acceptedPointerTypes;
- Qt::KeyboardModifiers m_acceptedModifiers;
+ Q_DECLARE_PRIVATE(QQuickPointerDeviceHandler)
};
QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickpointerdevicehandler_p_p.h b/src/quick/handlers/qquickpointerdevicehandler_p_p.h
new file mode 100644
index 0000000000..ee6bd060d6
--- /dev/null
+++ b/src/quick/handlers/qquickpointerdevicehandler_p_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOINTERDEVICEHANDLER_P_H
+#define QQUICKPOINTERDEVICEHANDLER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickpointerdevicehandler_p.h"
+#include "qquickpointerhandler_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQuickPointerDeviceHandlerPrivate : public QQuickPointerHandlerPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPointerDeviceHandler)
+
+public:
+ static QQuickPointerDeviceHandlerPrivate* get(QQuickPointerDeviceHandler *q) { return q->d_func(); }
+ static const QQuickPointerDeviceHandlerPrivate* get(const QQuickPointerDeviceHandler *q) { return q->d_func(); }
+
+ QQuickPointerDevice::DeviceTypes acceptedDevices = QQuickPointerDevice::AllDevices;
+ QQuickPointerDevice::PointerTypes acceptedPointerTypes = QQuickPointerDevice::AllPointerTypes;
+ Qt::KeyboardModifiers acceptedModifiers = Qt::KeyboardModifierMask;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPOINTERDEVICEHANDLER_P_H
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
index e5b1dc8985..a0325dd0c6 100644
--- a/src/quick/handlers/qquickpointerhandler.cpp
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -38,6 +38,8 @@
****************************************************************************/
#include "qquickpointerhandler_p.h"
+#include "qquickpointerhandler_p_p.h"
+#include <QtQuick/private/qquickitem_p.h>
QT_BEGIN_NAMESPACE
@@ -60,15 +62,12 @@ Q_LOGGING_CATEGORY(lcPointerHandlerActive, "qt.quick.handler.active")
*/
QQuickPointerHandler::QQuickPointerHandler(QObject *parent)
- : QObject(parent)
- , m_currentEvent(nullptr)
- , m_target(nullptr)
- , m_enabled(true)
- , m_active(false)
- , m_targetExplicitlySet(false)
- , m_hadKeepMouseGrab(false)
- , m_hadKeepTouchGrab(false)
- , m_grabPermissions(CanTakeOverFromItems | CanTakeOverFromHandlersOfDifferentType | ApprovesTakeOverByAnything)
+ : QObject(*(new QQuickPointerHandlerPrivate), parent)
+{
+}
+
+QQuickPointerHandler::QQuickPointerHandler(QQuickPointerHandlerPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
{
}
@@ -113,8 +112,9 @@ void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEv
setActive(false);
point->setAccepted(false);
if (auto par = parentItem()) {
- par->setKeepMouseGrab(m_hadKeepMouseGrab);
- par->setKeepTouchGrab(m_hadKeepTouchGrab);
+ Q_D(const QQuickPointerHandler);
+ par->setKeepMouseGrab(d->hadKeepMouseGrab);
+ par->setKeepTouchGrab(d->hadKeepTouchGrab);
}
break;
case QQuickEventPoint::OverrideGrabPassive:
@@ -130,7 +130,6 @@ void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEv
}
/*!
- \internal
Acquire or give up a passive grab of the given \a point, according to the \a grab state.
Unlike the exclusive grab, multiple PointerHandlers can have passive grabs
@@ -181,19 +180,20 @@ bool QQuickPointerHandler::canGrab(QQuickEventPoint *point)
*/
bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObject *proposedGrabber)
{
+ Q_D(const QQuickPointerHandler);
bool allowed = false;
if (proposedGrabber == this) {
QObject* existingGrabber = point->exclusiveGrabber();
- allowed = (existingGrabber == nullptr) || ((m_grabPermissions & CanTakeOverFromAnything) == CanTakeOverFromAnything);
+ allowed = (existingGrabber == nullptr) || ((d->grabPermissions & CanTakeOverFromAnything) == CanTakeOverFromAnything);
if (existingGrabber) {
if (QQuickPointerHandler *existingPhGrabber = point->grabberPointerHandler()) {
- if (!allowed && (m_grabPermissions & CanTakeOverFromHandlersOfDifferentType) &&
+ if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfDifferentType) &&
existingPhGrabber->metaObject()->className() != metaObject()->className())
allowed = true;
- if (!allowed && (m_grabPermissions & CanTakeOverFromHandlersOfSameType) &&
+ if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfSameType) &&
existingPhGrabber->metaObject()->className() == metaObject()->className())
allowed = true;
- } else if ((m_grabPermissions & CanTakeOverFromItems)) {
+ } else if ((d->grabPermissions & CanTakeOverFromItems)) {
QQuickItem * existingItemGrabber = point->grabberItem();
if (existingItemGrabber && !((existingItemGrabber->keepMouseGrab() && point->pointerEvent()->asPointerMouseEvent()) ||
(existingItemGrabber->keepTouchGrab() && point->pointerEvent()->asPointerTouchEvent())))
@@ -203,18 +203,18 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec
} else {
// proposedGrabber is different: that means this instance will lose its grab
if (proposedGrabber) {
- if ((m_grabPermissions & ApprovesTakeOverByAnything) == ApprovesTakeOverByAnything)
+ if ((d->grabPermissions & ApprovesTakeOverByAnything) == ApprovesTakeOverByAnything)
allowed = true;
- if (!allowed && (m_grabPermissions & ApprovesTakeOverByHandlersOfDifferentType) &&
+ if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfDifferentType) &&
proposedGrabber->metaObject()->className() != metaObject()->className())
allowed = true;
- if (!allowed && (m_grabPermissions & ApprovesTakeOverByHandlersOfSameType) &&
+ if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfSameType) &&
proposedGrabber->metaObject()->className() == metaObject()->className())
allowed = true;
- if (!allowed && (m_grabPermissions & ApprovesTakeOverByItems) && proposedGrabber->inherits("QQuickItem"))
+ if (!allowed && (d->grabPermissions & ApprovesTakeOverByItems) && proposedGrabber->inherits("QQuickItem"))
allowed = true;
} else {
- if (!allowed && (m_grabPermissions & ApprovesCancellation))
+ if (!allowed && (d->grabPermissions & ApprovesCancellation))
allowed = true;
}
}
@@ -236,12 +236,19 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec
which allows most takeover scenarios but avoids e.g. two PinchHandlers fighting
over the same touchpoints.
*/
+QQuickPointerHandler::GrabPermissions QQuickPointerHandler::grabPermissions() const
+{
+ Q_D(const QQuickPointerHandler);
+ return static_cast<QQuickPointerHandler::GrabPermissions>(d->grabPermissions);
+}
+
void QQuickPointerHandler::setGrabPermissions(GrabPermissions grabPermission)
{
- if (m_grabPermissions == grabPermission)
+ Q_D(QQuickPointerHandler);
+ if (d->grabPermissions == grabPermission)
return;
- m_grabPermissions = grabPermission;
+ d->grabPermissions = grabPermission;
emit grabPermissionChanged();
}
@@ -253,8 +260,13 @@ void QQuickPointerHandler::componentComplete()
{
}
+QQuickPointerEvent *QQuickPointerHandler::currentEvent()
+{
+ Q_D(const QQuickPointerHandler);
+ return d->currentEvent;
+}
+
/*!
- \internal
Acquire or give up the exclusive grab of the given \a point, according to
the \a grab state, and subject to the rules: canGrab(), and the rule not to
relinquish another handler's grab. Returns true if permission is granted,
@@ -284,7 +296,6 @@ bool QQuickPointerHandler::setExclusiveGrab(QQuickEventPoint *point, bool grab)
}
/*!
- \internal
Cancel any existing grab of the given \a point.
*/
void QQuickPointerHandler::cancelAllGrabs(QQuickEventPoint *point)
@@ -313,15 +324,28 @@ bool QQuickPointerHandler::parentContains(const QQuickEventPoint *point) const
If a PointerHandler is disabled, it will reject all events
and no signals will be emitted.
*/
+bool QQuickPointerHandler::enabled() const
+{
+ Q_D(const QQuickPointerHandler);
+ return d->enabled;
+}
+
void QQuickPointerHandler::setEnabled(bool enabled)
{
- if (m_enabled == enabled)
+ Q_D(QQuickPointerHandler);
+ if (d->enabled == enabled)
return;
- m_enabled = enabled;
+ d->enabled = enabled;
emit enabledChanged();
}
+bool QQuickPointerHandler::active() const
+{
+ Q_D(const QQuickPointerHandler);
+ return d->active;
+}
+
/*!
\qmlproperty Item QtQuick::PointerHandler::target
@@ -335,21 +359,28 @@ void QQuickPointerHandler::setEnabled(bool enabled)
*/
void QQuickPointerHandler::setTarget(QQuickItem *target)
{
- m_targetExplicitlySet = true;
- if (m_target == target)
+ Q_D(QQuickPointerHandler);
+ d->targetExplicitlySet = true;
+ if (d->target == target)
return;
- QQuickItem *oldTarget = m_target;
- m_target = target;
+ QQuickItem *oldTarget = d->target;
+ d->target = target;
onTargetChanged(oldTarget);
emit targetChanged();
}
+QQuickItem *QQuickPointerHandler::parentItem() const
+{
+ return static_cast<QQuickItem *>(QObject::parent());
+}
+
QQuickItem *QQuickPointerHandler::target() const
{
- if (!m_targetExplicitlySet)
+ Q_D(const QQuickPointerHandler);
+ if (!d->targetExplicitlySet)
return parentItem();
- return m_target;
+ return d->target;
}
void QQuickPointerHandler::handlePointerEvent(QQuickPointerEvent *event)
@@ -374,8 +405,14 @@ void QQuickPointerHandler::handlePointerEvent(QQuickPointerEvent *event)
bool QQuickPointerHandler::wantsPointerEvent(QQuickPointerEvent *event)
{
+ Q_D(const QQuickPointerHandler);
Q_UNUSED(event)
- return m_enabled;
+ return d->enabled;
+}
+
+bool QQuickPointerHandler::wantsEventPoint(QQuickEventPoint *point)
+{
+ return parentContains(point);
}
/*!
@@ -390,9 +427,10 @@ bool QQuickPointerHandler::wantsPointerEvent(QQuickPointerEvent *event)
*/
void QQuickPointerHandler::setActive(bool active)
{
- if (m_active != active) {
- qCDebug(lcPointerHandlerActive) << this << m_active << "->" << active;
- m_active = active;
+ Q_D(QQuickPointerHandler);
+ if (d->active != active) {
+ qCDebug(lcPointerHandlerActive) << this << d->active << "->" << active;
+ d->active = active;
onActiveChanged();
emit activeChanged();
}
@@ -400,7 +438,8 @@ void QQuickPointerHandler::setActive(bool active)
void QQuickPointerHandler::handlePointerEventImpl(QQuickPointerEvent *event)
{
- m_currentEvent = event;
+ Q_D(QQuickPointerHandler);
+ d->currentEvent = event;
}
/*!
@@ -430,4 +469,20 @@ void QQuickPointerHandler::handlePointerEventImpl(QQuickPointerEvent *event)
emitted when the grab is stolen by a different Pointer Handler or Item.
*/
+QQuickPointerHandlerPrivate::QQuickPointerHandlerPrivate()
+ : grabPermissions(QQuickPointerHandler::CanTakeOverFromItems |
+ QQuickPointerHandler::CanTakeOverFromHandlersOfDifferentType |
+ QQuickPointerHandler::ApprovesTakeOverByAnything)
+ , enabled(true)
+ , active(false)
+ , targetExplicitlySet(false)
+ , hadKeepMouseGrab(false)
+ , hadKeepTouchGrab(false)
+{
+}
+
+QQuickPointerHandlerPrivate::~QQuickPointerHandlerPrivate()
+{
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickpointerhandler_p.h b/src/quick/handlers/qquickpointerhandler_p.h
index e2bcce8fc9..1327e6be4e 100644
--- a/src/quick/handlers/qquickpointerhandler_p.h
+++ b/src/quick/handlers/qquickpointerhandler_p.h
@@ -51,8 +51,6 @@
// We mean it.
//
-#include "qevent.h"
-
#include <QtQuick/private/qquickevents_p_p.h>
#include <QtQuick/private/qquickitem_p.h>
@@ -60,6 +58,8 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcPointerHandlerDispatch)
+class QQuickPointerHandlerPrivate;
+
class Q_QUICK_PRIVATE_EXPORT QQuickPointerHandler : public QObject, public QQmlParserStatus
{
Q_OBJECT
@@ -91,19 +91,19 @@ public:
Q_FLAG(GrabPermissions)
public:
- bool enabled() const { return m_enabled; }
+ bool enabled() const;
void setEnabled(bool enabled);
- bool active() const { return m_active; }
+ bool active() const;
QQuickItem *target() const;
void setTarget(QQuickItem *target);
- QQuickItem * parentItem() const { return static_cast<QQuickItem *>(QObject::parent()); }
+ QQuickItem * parentItem() const;
void handlePointerEvent(QQuickPointerEvent *event);
- GrabPermissions grabPermissions() const { return static_cast<GrabPermissions>(m_grabPermissions); }
+ GrabPermissions grabPermissions() const;
void setGrabPermissions(GrabPermissions grabPermissions);
Q_SIGNALS:
@@ -115,11 +115,14 @@ Q_SIGNALS:
void canceled(QQuickEventPoint *point);
protected:
+ QQuickPointerHandler(QQuickPointerHandlerPrivate &dd, QObject *parent);
+
void classBegin() override;
void componentComplete() override;
- QQuickPointerEvent *currentEvent() { return m_currentEvent; }
+ QQuickPointerEvent *currentEvent();
virtual bool wantsPointerEvent(QQuickPointerEvent *event);
+ virtual bool wantsEventPoint(QQuickEventPoint *point);
virtual void handlePointerEventImpl(QQuickPointerEvent *event);
void setActive(bool active);
virtual void onTargetChanged(QQuickItem *oldTarget) { Q_UNUSED(oldTarget); }
@@ -133,19 +136,10 @@ protected:
QPointF eventPos(const QQuickEventPoint *point) const;
bool parentContains(const QQuickEventPoint *point) const;
-private:
- QQuickPointerEvent *m_currentEvent;
- QQuickItem *m_target;
- bool m_enabled : 1;
- bool m_active : 1;
- bool m_targetExplicitlySet : 1;
- bool m_hadKeepMouseGrab : 1; // some handlers override target()->setKeepMouseGrab(); this remembers previous state
- bool m_hadKeepTouchGrab : 1; // some handlers override target()->setKeepTouchGrab(); this remembers previous state
- uint m_reserved : 19;
- uint8_t m_grabPermissions : 8;
-
friend class QQuickEventPoint;
friend class QQuickWindowPrivate;
+
+ Q_DECLARE_PRIVATE(QQuickPointerHandler)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickPointerHandler::GrabPermissions)
diff --git a/src/quick/handlers/qquickpointerhandler_p_p.h b/src/quick/handlers/qquickpointerhandler_p_p.h
new file mode 100644
index 0000000000..ce50b98c57
--- /dev/null
+++ b/src/quick/handlers/qquickpointerhandler_p_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOINTERHANDLER_P_H
+#define QQUICKPOINTERHANDLER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qevent.h"
+
+#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuick/private/qquickpointerhandler_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerHandlerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPointerHandler)
+
+public:
+ static QQuickPointerHandlerPrivate* get(QQuickPointerHandler *q) { return q->d_func(); }
+ static const QQuickPointerHandlerPrivate* get(const QQuickPointerHandler *q) { return q->d_func(); }
+
+ QQuickPointerHandlerPrivate();
+ virtual ~QQuickPointerHandlerPrivate() override;
+
+ QQuickPointerEvent *currentEvent = nullptr;
+ QQuickItem *target = nullptr;
+ uint8_t grabPermissions : 8;
+ bool enabled : 1;
+ bool active : 1;
+ bool targetExplicitlySet : 1;
+ bool hadKeepMouseGrab : 1; // some handlers override target()->setKeepMouseGrab(); this remembers previous state
+ bool hadKeepTouchGrab : 1; // some handlers override target()->setKeepTouchGrab(); this remembers previous state
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPOINTERHANDLER_P_H
diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp
index 9df20390e4..04b4214bab 100644
--- a/src/quick/handlers/qquicksinglepointhandler.cpp
+++ b/src/quick/handlers/qquicksinglepointhandler.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -79,16 +79,23 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event)
// It's expected to be an update or a release.
// If we no longer want it, cancel the grab.
int candidatePointCount = 0;
+ bool missing = true;
QQuickEventPoint *point = nullptr;
int c = event->pointCount();
for (int i = 0; i < c; ++i) {
QQuickEventPoint *p = event->point(i);
+ const bool found = (p->pointId() == m_pointInfo.m_id);
+ if (found)
+ missing = false;
if (wantsEventPoint(p)) {
++candidatePointCount;
- if (p->pointId() == m_pointInfo.m_id)
+ if (found)
point = p;
}
}
+ if (missing)
+ qCWarning(DBG_TOUCH_TARGET) << this << "pointId" << hex << m_pointInfo.m_id
+ << "is missing from current event, but was neither canceled nor released";
if (point) {
if (candidatePointCount == 1 || (candidatePointCount > 1 && m_ignoreAdditionalPoints)) {
point->setAccepted();
@@ -97,8 +104,6 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event)
point->cancelAllGrabs(this);
}
} else {
- qCWarning(DBG_TOUCH_TARGET) << this << "pointId" << hex << m_pointInfo.m_id
- << "is missing from current event, but was neither canceled nor released";
return false;
}
} else {
@@ -130,48 +135,16 @@ void QQuickSinglePointHandler::handlePointerEventImpl(QQuickPointerEvent *event)
if (!m_pointInfo.m_id || !currentPoint->isAccepted()) {
reset();
} else {
- if (event->asPointerTouchEvent()) {
- QQuickEventTouchPoint *tp = static_cast<QQuickEventTouchPoint *>(currentPoint);
- m_pointInfo.m_uniqueId = tp->uniqueId();
- m_pointInfo.m_rotation = tp->rotation();
- m_pointInfo.m_pressure = tp->pressure();
- m_pointInfo.m_ellipseDiameters = tp->ellipseDiameters();
- } else if (event->asPointerTabletEvent()) {
- // TODO
- } else {
- m_pointInfo.m_uniqueId = event->device()->uniqueId();
- m_pointInfo.m_rotation = 0;
- m_pointInfo.m_pressure = event->buttons() ? 1 : 0;
- m_pointInfo.m_ellipseDiameters = QSizeF();
- }
- m_pointInfo.m_position = currentPoint->position();
- m_pointInfo.m_scenePosition = currentPoint->scenePosition();
- if (currentPoint->state() == QQuickEventPoint::Updated)
- m_pointInfo.m_velocity = currentPoint->velocity();
+ m_pointInfo.reset(currentPoint);
handleEventPoint(currentPoint);
- switch (currentPoint->state()) {
- case QQuickEventPoint::Pressed:
- m_pointInfo.m_pressPosition = currentPoint->position();
- m_pointInfo.m_scenePressPosition = currentPoint->scenePosition();
- m_pointInfo.m_pressedButtons = event->buttons();
- break;
- case QQuickEventPoint::Released:
+ if (currentPoint->state() == QQuickEventPoint::Released) {
setExclusiveGrab(currentPoint, false);
reset();
- break;
- default:
- m_pointInfo.m_pressedButtons = event->buttons();
- break;
}
emit pointChanged();
}
}
-bool QQuickSinglePointHandler::wantsEventPoint(QQuickEventPoint *point)
-{
- return parentContains(point);
-}
-
void QQuickSinglePointHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point)
{
if (grabber != this)
@@ -264,213 +237,4 @@ void QQuickSinglePointHandler::reset()
handled, this object is reset to default values (all coordinates are 0).
*/
-/*!
- \qmltype HandlerPoint
- \instantiates QQuickHandlerPoint
- \inqmlmodule Qt.labs.handlers
- \ingroup qtquick-handlers
- \brief An event point.
-
- A QML representation of a QQuickEventPoint.
-
- It's possible to make bindings to properties of a \l SinglePointHandler's
- current point. For example:
-
- \snippet pointerHandlers/dragHandlerNullTarget.qml 0
-
- The point is kept up-to-date when the DragHandler is actively responding to
- an EventPoint; but when the point is released, or the current point is
- being handled by a different handler, \c position.x and \c position.y are 0.
-
- \note This is practically identical to QtQuick::EventPoint; however an
- EventPoint is a long-lived QObject which is invalidated between gestures
- and reused for subsequent event deliveries. Continuous bindings to its
- properties are not possible, and an individual handler cannot rely on it
- outside the period when that point is part of an active gesture which that
- handler is handling. HandlerPoint is a Q_GADGET that the handler owns.
- This allows you to make lifetime bindings to its properties.
-
- \sa SinglePointHandler::point
-*/
-
-QQuickHandlerPoint::QQuickHandlerPoint()
- : m_id(0)
- , m_rotation(0)
- , m_pressure(0)
-{}
-
-void QQuickHandlerPoint::reset()
-{
- m_id = 0;
- m_uniqueId = QPointingDeviceUniqueId();
- m_position = QPointF();
- m_scenePosition = QPointF();
- m_pressPosition = QPointF();
- m_scenePressPosition = QPointF();
- m_sceneGrabPosition = QPointF();
- m_velocity = QVector2D();
- m_rotation = 0;
- m_pressure = 0;
- m_ellipseDiameters = QSizeF();
- m_pressedButtons = Qt::NoButton;
-}
-
-/*!
- \readonly
- \qmlproperty int QtQuick::HandlerPoint::id
- \brief The ID number of the point
-
- During a touch gesture, from the time that the first finger is pressed
- until the last finger is released, each touchpoint will have a unique ID
- number. Likewise, if input from multiple devices occurs (for example
- simultaneous mouse and touch presses), all the current event points from
- all the devices will have unique IDs.
-
- \note Do not assume that id numbers start at zero or that they are
- sequential. Such an assumption is often false due to the way the underlying
- drivers work.
-
- \sa QTouchEvent::TouchPoint::id
-*/
-
-/*!
- \readonly
- \qmlproperty PointingDeviceUniqueId QtQuick::HandlerPoint::uniqueId
- \brief The unique ID of the point, if any
-
- This is normally empty, because touchscreens cannot uniquely identify fingers.
-
- On some types of touchscreens, especially those using TUIO drivers,
- it's possible to use recognizable physical tokens (fiducial objects)
- in addition to fingers. So if this point is a touch point, and
- uniqueId is set, it is the identifier for such an object.
-
- On a graphics tablet, each type of stylus or other tool often has a unique
- ID or serial number, which can be useful to respond in different ways to
- different tools.
-
- Interpreting the contents of this ID requires knowledge of the hardware and
- drivers in use.
-
- \sa QTabletEvent::uniqueId, QtQuick::TouchPoint::uniqueId, QtQuick::EventTouchPoint::uniqueId
-*/
-
-/*!
- \readonly
- \qmlproperty QPointF QtQuick::HandlerPoint::position
- \brief The position within the \c parent Item
-
- This is the position of the event point relative to the bounds of
- the \l {PointerHandler::parent} {parent}.
-*/
-
-/*!
- \readonly
- \qmlproperty QPointF QtQuick::HandlerPoint::scenePosition
- \brief The position within the scene
-
- This is the position of the event point relative to the bounds of the Qt
- Quick scene (typically the whole window).
-*/
-
-/*!
- \readonly
- \qmlproperty QPointF QtQuick::HandlerPoint::pressPosition
- \brief The pressed position within the \c parent Item
-
- This is the position at which this point was pressed, relative to the
- bounds of the \l {PointerHandler::parent} {parent}.
-*/
-
-/*!
- \readonly
- \qmlproperty QPointF QtQuick::HandlerPoint::scenePressPosition
- \brief The pressed position within the scene
-
- This is the position at which this point was pressed, in the coordinate
- system of the \l {Qt Quick Scene Graph}{scene graph}.
-*/
-
-/*!
- \readonly
- \qmlproperty QPointF QtQuick::HandlerPoint::sceneGrabPosition
- \brief The grabbed position within the scene
-
- If this point has been grabbed by a Pointer Handler or an Item, it means
- that object has taken sole responsibility for handling the movement and the
- release if this point. In that case, this is the position at which the grab
- occurred, in the coordinate system of the \l {Qt Quick Scene Graph}{scene graph}.
-*/
-
-/*!
- \readonly
- \qmlproperty enum QtQuick::HandlerPoint::pressedButtons
- \brief Which mouse or stylus buttons are currently pressed
-
- \sa MouseArea::pressedButtons
-*/
-
-/*!
- \readonly
- \qmlproperty QVector2D QtQuick::HandlerPoint::velocity
- \brief A vector representing the average speed and direction of movement
-
- This is a velocity vector pointing in the direction of movement, in logical
- pixels per second. It has x and y components, at least one of which will be
- nonzero when this point is in motion. It holds the average recent velocity:
- how fast and in which direction the event point has been moving recently.
-
- \sa QtQuick::EventPoint::velocity, QtQuick::TouchPoint::velocity, QTouchEvent::TouchPoint::velocity
-*/
-
-/*!
- \readonly
- \qmlproperty qreal QtQuick::HandlerPoint::rotation
-
- This property holds the rotation angle of the stylus on a graphics tablet
- or the contact patch of a touchpoint on a touchscreen.
-
- It is valid only with certain tablet stylus devices and touchscreens that
- can measure the rotation angle. Otherwise, it will be zero.
-*/
-
-/*!
- \readonly
- \qmlproperty qreal QtQuick::HandlerPoint::pressure
-
- This property tells how hard the user is pressing the stylus on a graphics
- tablet or the finger against a touchscreen, in the range from \c 0 (no
- measurable pressure) to \c 1.0 (maximum pressure which the device can
- measure).
-
- It is valid only with certain tablets and touchscreens that can measure
- pressure. Otherwise, it will be zero.
-*/
-
-/*!
- \readonly
- \qmlproperty size QtQuick::HandlerPoint::ellipseDiameters
-
- This property holds the diameters of the contact patch, if the event
- comes from a touchpoint and the device provides this information.
-
- A touchpoint is modeled as an elliptical area where the finger is pressed
- against the touchscreen. (In fact, it could also be modeled as a bitmap;
- but in that case we expect an elliptical bounding estimate to be fitted to
- the contact patch before the event is sent.) The harder the user presses,
- the larger the contact patch; so, these diameters provide an alternate way
- of detecting pressure, in case the device does not include a separate
- pressure sensor. The ellipse is centered on \l scenePosition (\l position
- in the PointerHandler's Item's local coordinates). The \l rotation property
- provides the rotation of the ellipse, if known. It is expected that if the
- \l rotation is zero, the \l {QSize::height}{height} is the larger dimension
- (the major axis), because of the usual hand position, reaching upward or
- outward across the surface.
-
- If the contact patch is unknown, or the device is not a touchscreen,
- these values will be zero.
-
- \sa QtQuick::EventTouchPoint::ellipseDiameters, QtQuick::TouchPoint::ellipseDiameters, QTouchEvent::TouchPoint::ellipseDiameters
-*/
-
QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquicksinglepointhandler_p.h b/src/quick/handlers/qquicksinglepointhandler_p.h
index 7606b4f7ba..66ef1dbeb2 100644
--- a/src/quick/handlers/qquicksinglepointhandler_p.h
+++ b/src/quick/handlers/qquicksinglepointhandler_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -51,60 +51,11 @@
// We mean it.
//
+#include "qquickhandlerpoint_p.h"
#include "qquickpointerdevicehandler_p.h"
QT_BEGIN_NAMESPACE
-class QQuickSinglePointHandler;
-
-class Q_QUICK_PRIVATE_EXPORT QQuickHandlerPoint {
- Q_GADGET
- Q_PROPERTY(int id READ id)
- Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId)
- Q_PROPERTY(QPointF position READ position)
- Q_PROPERTY(QPointF scenePosition READ scenePosition)
- Q_PROPERTY(QPointF pressPosition READ pressPosition)
- Q_PROPERTY(QPointF scenePressPosition READ scenePressPosition)
- Q_PROPERTY(QPointF sceneGrabPosition READ sceneGrabPosition)
- Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons)
- Q_PROPERTY(QVector2D velocity READ velocity)
- Q_PROPERTY(qreal rotation READ rotation)
- Q_PROPERTY(qreal pressure READ pressure)
- Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters)
-
-public:
- QQuickHandlerPoint();
-
- int id() const { return m_id; }
- Qt::MouseButtons pressedButtons() const { return m_pressedButtons; }
- QPointF pressPosition() const { return m_pressPosition; }
- QPointF scenePressPosition() const { return m_scenePressPosition; }
- QPointF sceneGrabPosition() const { return m_sceneGrabPosition; }
- QPointF position() const { return m_position; }
- QPointF scenePosition() const { return m_scenePosition; }
- QVector2D velocity() const { return m_velocity; }
- qreal rotation() const { return m_rotation; }
- qreal pressure() const { return m_pressure; }
- QSizeF ellipseDiameters() const { return m_ellipseDiameters; }
- QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; }
-
-private:
- void reset();
- int m_id;
- QPointingDeviceUniqueId m_uniqueId;
- Qt::MouseButtons m_pressedButtons;
- QPointF m_position;
- QPointF m_scenePosition;
- QPointF m_pressPosition;
- QPointF m_scenePressPosition;
- QPointF m_sceneGrabPosition;
- QVector2D m_velocity;
- qreal m_rotation;
- qreal m_pressure;
- QSizeF m_ellipseDiameters;
- friend class QQuickSinglePointHandler;
-};
-
class Q_QUICK_PRIVATE_EXPORT QQuickSinglePointHandler : public QQuickPointerDeviceHandler
{
Q_OBJECT
@@ -126,7 +77,6 @@ Q_SIGNALS:
protected:
bool wantsPointerEvent(QQuickPointerEvent *event) override;
- virtual bool wantsEventPoint(QQuickEventPoint *point);
void handlePointerEventImpl(QQuickPointerEvent *event) override;
virtual void handleEventPoint(QQuickEventPoint *point) = 0;
@@ -148,7 +98,6 @@ private:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQuickHandlerPoint)
QML_DECLARE_TYPE(QQuickSinglePointHandler)
#endif // QQUICKPOINTERSINGLEHANDLER_H
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index 902ff0df10..b12894e23f 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -107,7 +107,7 @@ QQuickTapHandler::~QQuickTapHandler()
{
}
-static bool dragOverThreshold(QQuickEventPoint *point)
+static bool dragOverThreshold(const QQuickEventPoint *point)
{
QPointF delta = point->scenePosition() - point->scenePressPosition();
return (QQuickWindowPrivate::dragOverThreshold(delta.x(), Qt::XAxis, point) ||
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 2c115f4d3c..ef6f5fa716 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -596,7 +596,7 @@ public:
static QV4::Heap::QQuickJSContext2DPrototype *create(QV4::ExecutionEngine *engine)
{
QV4::Scope scope(engine);
- QV4::Scoped<QQuickJSContext2DPrototype> o(scope, engine->memoryManager->allocObject<QQuickJSContext2DPrototype>());
+ QV4::Scoped<QQuickJSContext2DPrototype> o(scope, engine->memoryManager->allocate<QQuickJSContext2DPrototype>());
o->defineDefaultProperty(QStringLiteral("quadraticCurveTo"), method_quadraticCurveTo, 0);
o->defineDefaultProperty(QStringLiteral("restore"), method_restore, 0);
@@ -954,7 +954,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE
{
QV4::Scope scope(v4);
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, scope.engine->memoryManager->allocObject<QQuickJSContext2DPixelData>());
+ QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, scope.engine->memoryManager->allocate<QQuickJSContext2DPixelData>());
QV4::ScopedObject p(scope, ed->pixelArrayProto.value());
pixelData->setPrototype(p);
@@ -966,7 +966,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE
*pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
}
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, scope.engine->memoryManager->allocObject<QQuickJSContext2DImageData>());
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, scope.engine->memoryManager->allocate<QQuickJSContext2DImageData>());
imageData->d()->pixelData = pixelData.asReturnedValue();
return imageData.asReturnedValue();
}
@@ -1582,7 +1582,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(const
}
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p);
*gradient->d()->brush = QLinearGradient(x0, y0, x1, y1);
@@ -1634,7 +1634,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(const
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p);
*gradient->d()->brush = QRadialGradient(QPointF(x1, y1), r1, QPointF(x0, y0), r0);
@@ -1678,7 +1678,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(cons
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p);
*gradient->d()->brush = QConicalGradient(x, y, angle);
@@ -1738,7 +1738,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(const QV4::F
CHECK_CONTEXT(r)
if (argc >= 2) {
- QV4::Scoped<QQuickContext2DStyle> pattern(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> pattern(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QColor color = scope.engine->toVariant(argv[0], qMetaTypeId<QColor>()).value<QColor>();
if (color.isValid()) {
@@ -4399,7 +4399,7 @@ void QQuickContext2D::setV4Engine(QV4::ExecutionEngine *engine)
QQuickContext2DEngineData *ed = engineData(engine);
QV4::Scope scope(engine);
- QV4::Scoped<QQuickJSContext2D> wrapper(scope, engine->memoryManager->allocObject<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> wrapper(scope, engine->memoryManager->allocate<QQuickJSContext2D>());
QV4::ScopedObject p(scope, ed->contextPrototype.value());
wrapper->setPrototype(p);
wrapper->d()->context = this;
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index 1acb3b5265..e649b5429d 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -122,9 +122,11 @@ qtConfig(quick-gridview) {
qtConfig(quick-itemview) {
HEADERS += \
+ $$PWD/qquickitemviewfxitem_p_p.h \
$$PWD/qquickitemview_p.h \
$$PWD/qquickitemview_p_p.h
SOURCES += \
+ $$PWD/qquickitemviewfxitem.cpp \
$$PWD/qquickitemview.cpp
}
@@ -142,6 +144,14 @@ qtConfig(quick-listview) {
$$PWD/qquicklistview.cpp
}
+qtConfig(quick-tableview) {
+ HEADERS += \
+ $$PWD/qquicktableview_p.h \
+ $$PWD/qquicktableview_p_p.h
+ SOURCES += \
+ $$PWD/qquicktableview.cpp
+}
+
qtConfig(quick-pathview) {
HEADERS += \
$$PWD/qquickpathview_p.h \
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index 603d5a3120..18adb4e992 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -268,6 +268,16 @@ QT_BEGIN_NAMESPACE
Stops, then starts the sprite animation.
*/
+/*!
+ \qmlsignal QtQuick::AnimatedSprite::finished()
+ \since 5.12
+
+ This signal is emitted when the sprite has finished animating.
+
+ It is not emitted when running is set to \c false, nor for sprites whose
+ \l loops property is set to \c AnimatedSprite.Infinite.
+*/
+
QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) :
QQuickItem(*(new QQuickAnimatedSpritePrivate), parent)
{
@@ -806,6 +816,7 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
frameAt = 0;
d->m_running = false;
emit runningChanged(false);
+ emit finished();
maybeUpdate();
}
} else {
diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h
index d7e60b909c..ff59591c9f 100644
--- a/src/quick/items/qquickanimatedsprite_p.h
+++ b/src/quick/items/qquickanimatedsprite_p.h
@@ -135,6 +135,8 @@ Q_SIGNALS:
void loopsChanged(int arg);
void currentFrameChanged(int arg);
+ Q_REVISION(12) void finished();
+
public Q_SLOTS:
void start();
void stop();
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index d4aba31e28..31c56b7cb7 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -642,6 +642,11 @@ QQuickPointerDevice *QQuickPointerDevice::touchDevice(const QTouchDevice *d)
return dev;
}
+const QTouchDevice *QQuickPointerDevice::qTouchDevice() const
+{
+ return g_touchDevices->key(const_cast<QQuickPointerDevice *>(this));
+}
+
QList<QQuickPointerDevice*> QQuickPointerDevice::touchDevices()
{
return g_touchDevices->values();
@@ -901,7 +906,7 @@ void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, b
if (grabber) {
grabber->onGrabChanged(grabber, GrabExclusive, this);
for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers) {
- if (passiveGrabber != grabber)
+ if (!passiveGrabber.isNull() && passiveGrabber != grabber)
passiveGrabber->onGrabChanged(grabber, OverrideGrabPassive, this);
}
}
@@ -1291,7 +1296,7 @@ QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event)
Qt::TouchPointState state = Qt::TouchPointStationary;
switch (ev->type()) {
case QEvent::MouseButtonPress:
- m_mousePoint->clearPassiveGrabbers();
+ m_point->clearPassiveGrabbers();
Q_FALLTHROUGH();
case QEvent::MouseButtonDblClick:
state = Qt::TouchPointPressed;
@@ -1305,13 +1310,13 @@ QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event)
default:
break;
}
- m_mousePoint->reset(state, ev->windowPos(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
+ m_point->reset(state, ev->windowPos(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
return this;
}
-void QQuickPointerMouseEvent::localize(QQuickItem *target)
+void QQuickSinglePointEvent::localize(QQuickItem *target)
{
- m_mousePoint->localizePosition(target);
+ m_point->localizePosition(target);
}
QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event)
@@ -1412,35 +1417,54 @@ QQuickPointerEvent *QQuickPointerNativeGestureEvent::reset(QEvent *event)
break;
}
quint64 deviceId = QTouchDevicePrivate::get(const_cast<QTouchDevice *>(ev->device()))->id; // a bit roundabout since QTouchDevice::mTouchDeviceId is protected
- m_gesturePoint->reset(state, ev->windowPos(), deviceId << 24, ev->timestamp());
+ m_point->reset(state, ev->windowPos(), deviceId << 24, ev->timestamp());
return this;
}
-
-void QQuickPointerNativeGestureEvent::localize(QQuickItem *target)
-{
- m_gesturePoint->localizePosition(target);
-}
#endif // QT_CONFIG(gestures)
-QQuickEventPoint *QQuickPointerMouseEvent::point(int i) const {
+QQuickEventPoint *QQuickSinglePointEvent::point(int i) const
+{
if (i == 0)
- return m_mousePoint;
+ return m_point;
return nullptr;
}
-QQuickEventPoint *QQuickPointerTouchEvent::point(int i) const {
- if (i >= 0 && i < m_pointCount)
- return m_touchPoints.at(i);
- return nullptr;
+QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event)
+{
+ m_event = static_cast<QInputEvent*>(event);
+ if (!event)
+ return this;
+#if QT_CONFIG(wheelevent)
+ if (event->type() == QEvent::Wheel) {
+ auto ev = static_cast<QWheelEvent*>(event);
+ m_device = QQuickPointerDevice::genericMouseDevice();
+ m_device->eventDeliveryTargets().clear();
+ // m_button = Qt::NoButton;
+ m_pressedButtons = ev->buttons();
+ m_angleDelta = QVector2D(ev->angleDelta());
+ m_pixelDelta = QVector2D(ev->pixelDelta());
+ m_phase = ev->phase();
+ m_synthSource = ev->source();
+ m_inverted = ev->inverted();
+
+ m_point->reset(Qt::TouchPointMoved, ev->posF(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
+ }
+#endif
+ // TODO else if (event->type() == QEvent::Scroll) ...
+ return this;
}
-#if QT_CONFIG(gestures)
-QQuickEventPoint *QQuickPointerNativeGestureEvent::point(int i) const {
- if (i == 0)
- return m_gesturePoint;
+void QQuickPointerScrollEvent::localize(QQuickItem *target)
+{
+ m_point->localizePosition(target);
+}
+
+QQuickEventPoint *QQuickPointerTouchEvent::point(int i) const
+{
+ if (i >= 0 && i < m_pointCount)
+ return m_touchPoints.at(i);
return nullptr;
}
-#endif // QT_CONFIG(gestures)
QQuickEventPoint::QQuickEventPoint(QQuickPointerEvent *parent)
: QObject(parent), m_pointId(0), m_exclusiveGrabber(nullptr), m_timestamp(0), m_pressTimestamp(0),
@@ -1454,17 +1478,19 @@ QQuickPointerEvent *QQuickEventPoint::pointerEvent() const
return static_cast<QQuickPointerEvent *>(parent());
}
-bool QQuickPointerMouseEvent::allPointsAccepted() const {
- return m_mousePoint->isAccepted();
+bool QQuickSinglePointEvent::allPointsAccepted() const
+{
+ return m_point->isAccepted();
}
-bool QQuickPointerMouseEvent::allUpdatedPointsAccepted() const {
- return m_mousePoint->state() == QQuickEventPoint::Pressed || m_mousePoint->isAccepted();
+bool QQuickSinglePointEvent::allUpdatedPointsAccepted() const
+{
+ return m_point->state() == QQuickEventPoint::Pressed || m_point->isAccepted();
}
-bool QQuickPointerMouseEvent::allPointsGrabbed() const
+bool QQuickSinglePointEvent::allPointsGrabbed() const
{
- return m_mousePoint->exclusiveGrabber() != nullptr;
+ return m_point->exclusiveGrabber() != nullptr;
}
QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) const
@@ -1477,10 +1503,10 @@ QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) cons
/*!
Returns the exclusive grabber of this event, if any, in a vector.
*/
-QVector<QObject *> QQuickPointerMouseEvent::exclusiveGrabbers() const
+QVector<QObject *> QQuickSinglePointEvent::exclusiveGrabbers() const
{
QVector<QObject *> result;
- if (QObject *grabber = m_mousePoint->exclusiveGrabber())
+ if (QObject *grabber = m_point->exclusiveGrabber())
result << grabber;
return result;
}
@@ -1488,17 +1514,18 @@ QVector<QObject *> QQuickPointerMouseEvent::exclusiveGrabbers() const
/*!
Remove all passive and exclusive grabbers of this event, without notifying.
*/
-void QQuickPointerMouseEvent::clearGrabbers() const {
- m_mousePoint->setGrabberItem(nullptr);
- m_mousePoint->clearPassiveGrabbers();
+void QQuickSinglePointEvent::clearGrabbers() const
+{
+ m_point->setGrabberItem(nullptr);
+ m_point->clearPassiveGrabbers();
}
/*!
Returns whether the given \a handler is the exclusive grabber of this event.
*/
-bool QQuickPointerMouseEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const
+bool QQuickSinglePointEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const
{
- return m_mousePoint->exclusiveGrabber() == handler;
+ return handler && (m_point->exclusiveGrabber() == handler);
}
bool QQuickPointerMouseEvent::isPressEvent() const
@@ -1526,7 +1553,8 @@ bool QQuickPointerMouseEvent::isReleaseEvent() const
return me && me->type() == QEvent::MouseButtonRelease;
}
-bool QQuickPointerTouchEvent::allPointsAccepted() const {
+bool QQuickPointerTouchEvent::allPointsAccepted() const
+{
for (int i = 0; i < m_pointCount; ++i) {
if (!m_touchPoints.at(i)->isAccepted())
return false;
@@ -1534,7 +1562,8 @@ bool QQuickPointerTouchEvent::allPointsAccepted() const {
return true;
}
-bool QQuickPointerTouchEvent::allUpdatedPointsAccepted() const {
+bool QQuickPointerTouchEvent::allUpdatedPointsAccepted() const
+{
for (int i = 0; i < m_pointCount; ++i) {
auto point = m_touchPoints.at(i);
if (point->state() != QQuickEventPoint::Pressed && !point->isAccepted())
@@ -1571,7 +1600,8 @@ QVector<QObject *> QQuickPointerTouchEvent::exclusiveGrabbers() const
Remove all passive and exclusive grabbers of all touchpoints in this event,
without notifying.
*/
-void QQuickPointerTouchEvent::clearGrabbers() const {
+void QQuickPointerTouchEvent::clearGrabbers() const
+{
for (auto point: m_touchPoints) {
point->setGrabberItem(nullptr);
point->clearPassiveGrabbers();
@@ -1629,7 +1659,8 @@ QVector<QPointF> QQuickPointerEvent::unacceptedPressedPointScenePositions() cons
If the touchpoint cannot be found, this returns nullptr.
Ownership of the event is NOT transferred to the caller.
*/
-QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const {
+QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const
+{
const QTouchEvent::TouchPoint *p = touchPointById(pointID);
if (!p)
return nullptr;
@@ -1669,33 +1700,6 @@ QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickIte
}
#if QT_CONFIG(gestures)
-/*!
- Returns the exclusive grabber of this event, if any, in a vector.
-*/
-QVector<QObject *> QQuickPointerNativeGestureEvent::exclusiveGrabbers() const
-{
- QVector<QObject *> result;
- if (QObject *grabber = m_gesturePoint->exclusiveGrabber())
- result << grabber;
- return result;
-}
-
-/*!
- Remove all passive and exclusive grabbers of this event, without notifying.
-*/
-void QQuickPointerNativeGestureEvent::clearGrabbers() const {
- m_gesturePoint->setGrabberItem(nullptr);
- m_gesturePoint->clearPassiveGrabbers();
-}
-
-/*!
- Returns whether the given \a handler is the exclusive grabber of this event.
-*/
-bool QQuickPointerNativeGestureEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const
-{
- return m_gesturePoint->exclusiveGrabber() == handler;
-}
-
bool QQuickPointerNativeGestureEvent::isPressEvent() const
{
return type() == Qt::BeginNativeGesture;
@@ -1729,6 +1733,39 @@ qreal QQuickPointerNativeGestureEvent::value() const
#endif // QT_CONFIG(gestures)
/*!
+ Returns whether the scroll event has Qt::ScrollBegin phase. On touchpads
+ which provide phase information, this is true when the fingers are placed
+ on the touchpad and scrolling begins. On other devices where this
+ information is not available, it remains false.
+*/
+bool QQuickPointerScrollEvent::isPressEvent() const
+{
+ return phase() == Qt::ScrollBegin;
+}
+
+/*!
+ Returns true when the scroll event has Qt::ScrollUpdate phase, or when the
+ phase is unknown. Some multi-touch-capable touchpads and trackpads provide
+ phase information; whereas ordinary mouse wheels and other types of
+ trackpads do not, and in such cases this is always true.
+*/
+bool QQuickPointerScrollEvent::isUpdateEvent() const
+{
+ return phase() == Qt::ScrollUpdate || phase() == Qt::NoScrollPhase;
+}
+
+/*!
+ Returns whether the scroll event has Qt::ScrollBegin phase. On touchpads
+ which provide phase information, this is true when the fingers are lifted
+ from the touchpad. On other devices where this information is not
+ available, it remains false.
+*/
+bool QQuickPointerScrollEvent::isReleaseEvent() const
+{
+ return phase() == Qt::ScrollEnd;
+}
+
+/*!
\internal
Returns a pointer to the QQuickEventPoint which has the \a pointId as
\l {QQuickEventPoint::pointId}{pointId}.
@@ -1736,13 +1773,15 @@ qreal QQuickPointerNativeGestureEvent::value() const
\fn QQuickPointerEvent::pointById(int pointId) const
*/
-QQuickEventPoint *QQuickPointerMouseEvent::pointById(int pointId) const {
- if (m_mousePoint && pointId == m_mousePoint->pointId())
- return m_mousePoint;
+QQuickEventPoint *QQuickSinglePointEvent::pointById(int pointId) const
+{
+ if (m_point && pointId == m_point->pointId())
+ return m_point;
return nullptr;
}
-QQuickEventPoint *QQuickPointerTouchEvent::pointById(int pointId) const {
+QQuickEventPoint *QQuickPointerTouchEvent::pointById(int pointId) const
+{
auto it = std::find_if(m_touchPoints.constBegin(), m_touchPoints.constEnd(),
[pointId](const QQuickEventTouchPoint *tp) { return tp->pointId() == pointId; } );
if (it != m_touchPoints.constEnd())
@@ -1750,21 +1789,14 @@ QQuickEventPoint *QQuickPointerTouchEvent::pointById(int pointId) const {
return nullptr;
}
-#if QT_CONFIG(gestures)
-QQuickEventPoint *QQuickPointerNativeGestureEvent::pointById(int pointId) const {
- if (m_gesturePoint && pointId == m_gesturePoint->pointId())
- return m_gesturePoint;
- return nullptr;
-}
-#endif
-
/*!
\internal
Returns a pointer to the original TouchPoint which has the same
\l {QTouchEvent::TouchPoint::id}{id} as \a pointId, if the original event is a
QTouchEvent, and if that point is found. Otherwise, returns nullptr.
*/
-const QTouchEvent::TouchPoint *QQuickPointerTouchEvent::touchPointById(int pointId) const {
+const QTouchEvent::TouchPoint *QQuickPointerTouchEvent::touchPointById(int pointId) const
+{
const QTouchEvent *ev = asTouchEvent();
if (!ev)
return nullptr;
@@ -1875,24 +1907,10 @@ QTouchEvent *QQuickPointerTouchEvent::asTouchEvent() const
return static_cast<QTouchEvent *>(m_event);
}
-#if QT_CONFIG(gestures)
-bool QQuickPointerNativeGestureEvent::allPointsAccepted() const {
- return m_gesturePoint->isAccepted();
-}
-
-bool QQuickPointerNativeGestureEvent::allUpdatedPointsAccepted() const {
- return m_gesturePoint->state() == QQuickEventPoint::Pressed || m_gesturePoint->isAccepted();
-}
-
-bool QQuickPointerNativeGestureEvent::allPointsGrabbed() const
-{
- return m_gesturePoint->exclusiveGrabber() != nullptr;
-}
-#endif // QT_CONFIG(gestures)
-
#ifndef QT_NO_DEBUG_STREAM
-Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerDevice *dev) {
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerDevice *dev)
+{
QDebugStateSaver saver(dbg);
dbg.nospace();
if (!dev) {
@@ -1914,7 +1932,8 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerDevice *
return dbg;
}
-Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *event) {
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *event)
+{
QDebugStateSaver saver(dbg);
dbg.nospace();
dbg << "QQuickPointerEvent(";
@@ -1933,7 +1952,8 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *e
return dbg;
}
-Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *event) {
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *event)
+{
QDebugStateSaver saver(dbg);
dbg.nospace();
dbg << "QQuickEventPoint(accepted:" << event->isAccepted()
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index bb6726706d..c67c386676 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -69,6 +69,7 @@ class QQuickPointerMouseEvent;
#if QT_CONFIG(gestures)
class QQuickPointerNativeGestureEvent;
#endif
+class QQuickPointerScrollEvent;
class QQuickPointerTabletEvent;
class QQuickPointerTouchEvent;
class QQuickPointerHandler;
@@ -419,17 +420,19 @@ public: // helpers for C++ only (during event delivery)
#if QT_CONFIG(gestures)
virtual QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() { return nullptr; }
#endif
+ virtual QQuickPointerScrollEvent *asPointerScrollEvent() { return nullptr; }
virtual const QQuickPointerMouseEvent *asPointerMouseEvent() const { return nullptr; }
virtual const QQuickPointerTouchEvent *asPointerTouchEvent() const { return nullptr; }
virtual const QQuickPointerTabletEvent *asPointerTabletEvent() const { return nullptr; }
#if QT_CONFIG(gestures)
virtual const QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() const { return nullptr; }
#endif
+ virtual const QQuickPointerScrollEvent *asPointerScrollEvent() const { return nullptr; }
virtual bool allPointsAccepted() const = 0;
virtual bool allUpdatedPointsAccepted() const = 0;
virtual bool allPointsGrabbed() const = 0;
- bool isAccepted() { return m_event->isAccepted(); }
- void setAccepted(bool accepted) { m_event->setAccepted(accepted); }
+ bool isAccepted() { return m_event ? m_event->isAccepted() : false; }
+ void setAccepted(bool accepted) { if (m_event) m_event->setAccepted(accepted); }
QVector<QPointF> unacceptedPressedPointScenePositions() const;
virtual int pointCount() const = 0;
@@ -439,7 +442,7 @@ public: // helpers for C++ only (during event delivery)
virtual void clearGrabbers() const = 0;
virtual bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const = 0;
- ulong timestamp() const { return m_event->timestamp(); }
+ ulong timestamp() const { return m_event ? m_event->timestamp() : 0; }
protected:
QQuickPointerDevice *m_device;
@@ -450,21 +453,14 @@ protected:
Q_DISABLE_COPY(QQuickPointerEvent)
};
-class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickPointerEvent
+class Q_QUICK_PRIVATE_EXPORT QQuickSinglePointEvent : public QQuickPointerEvent
{
Q_OBJECT
public:
- QQuickPointerMouseEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
- : QQuickPointerEvent(parent, device), m_mousePoint(new QQuickEventPoint(this)) { }
+ QQuickSinglePointEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
+ : QQuickPointerEvent(parent, device), m_point(new QQuickEventPoint(this)) { }
- QQuickPointerEvent *reset(QEvent *) override;
void localize(QQuickItem *target) override;
- bool isPressEvent() const override;
- bool isDoubleClickEvent() const override;
- bool isUpdateEvent() const override;
- bool isReleaseEvent() const override;
- QQuickPointerMouseEvent *asPointerMouseEvent() override { return this; }
- const QQuickPointerMouseEvent *asPointerMouseEvent() const override { return this; }
int pointCount() const override { return 1; }
QQuickEventPoint *point(int i) const override;
QQuickEventPoint *pointById(int pointId) const override;
@@ -475,10 +471,28 @@ public:
void clearGrabbers() const override;
bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const override;
- QMouseEvent *asMouseEvent(const QPointF& localPos) const;
+protected:
+ QQuickEventPoint *m_point;
-private:
- QQuickEventPoint *m_mousePoint;
+ Q_DISABLE_COPY(QQuickSinglePointEvent)
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickSinglePointEvent
+{
+ Q_OBJECT
+public:
+ QQuickPointerMouseEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
+ : QQuickSinglePointEvent(parent, device) { }
+
+ QQuickPointerEvent *reset(QEvent *) override;
+ bool isPressEvent() const override;
+ bool isDoubleClickEvent() const override;
+ bool isUpdateEvent() const override;
+ bool isReleaseEvent() const override;
+ QQuickPointerMouseEvent *asPointerMouseEvent() override { return this; }
+ const QQuickPointerMouseEvent *asPointerMouseEvent() const override { return this; }
+
+ QMouseEvent *asMouseEvent(const QPointF& localPos) const;
Q_DISABLE_COPY(QQuickPointerMouseEvent)
};
@@ -526,7 +540,7 @@ private:
};
#if QT_CONFIG(gestures)
-class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickPointerEvent
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickSinglePointEvent
{
Q_OBJECT
Q_PROPERTY(Qt::NativeGestureType type READ type CONSTANT)
@@ -534,34 +548,65 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickPoin
public:
QQuickPointerNativeGestureEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
- : QQuickPointerEvent(parent, device), m_gesturePoint(new QQuickEventPoint(this)) { }
+ : QQuickSinglePointEvent(parent, device) { }
QQuickPointerEvent *reset(QEvent *) override;
- void localize(QQuickItem *target) override;
bool isPressEvent() const override;
bool isUpdateEvent() const override;
bool isReleaseEvent() const override;
QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() override { return this; }
const QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() const override { return this; }
- int pointCount() const override { return 1; }
- QQuickEventPoint *point(int i) const override;
- QQuickEventPoint *pointById(int pointId) const override;
- bool allPointsAccepted() const override;
- bool allUpdatedPointsAccepted() const override;
- bool allPointsGrabbed() const override;
- QVector<QObject *> exclusiveGrabbers() const override;
- void clearGrabbers() const override;
- bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const override;
Qt::NativeGestureType type() const;
qreal value() const;
-private:
- QQuickEventPoint *m_gesturePoint;
-
Q_DISABLE_COPY(QQuickPointerNativeGestureEvent)
};
#endif // QT_CONFIG(gestures)
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerScrollEvent : public QQuickSinglePointEvent
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector2D angleDelta READ angleDelta CONSTANT)
+ Q_PROPERTY(QVector2D pixelDelta READ pixelDelta CONSTANT)
+ Q_PROPERTY(bool hasAngleDelta READ hasAngleDelta CONSTANT)
+ Q_PROPERTY(bool hasPixelDelta READ hasPixelDelta CONSTANT)
+ Q_PROPERTY(bool inverted READ isInverted CONSTANT)
+
+public:
+ QQuickPointerScrollEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
+ : QQuickSinglePointEvent(parent, device) { }
+
+ QQuickPointerEvent *reset(QEvent *) override;
+ void localize(QQuickItem *target) override;
+ bool isPressEvent() const override;
+ bool isUpdateEvent() const override;
+ bool isReleaseEvent() const override;
+ QQuickPointerScrollEvent *asPointerScrollEvent() override { return this; }
+ const QQuickPointerScrollEvent *asPointerScrollEvent() const override { return this; }
+ QVector2D angleDelta() const { return m_angleDelta; }
+ QVector2D pixelDelta() const { return m_pixelDelta; }
+ bool hasAngleDelta() const { return !angleDelta().isNull(); }
+ bool hasPixelDelta() const { return !pixelDelta().isNull(); }
+ bool isInverted() const { return m_inverted; }
+ Qt::ScrollPhase phase() const { return m_phase; }
+
+private:
+ // TODO add QQuickPointerDevice source() whenever QInputEvent is extended to have a source device
+ // then maybe Qt::MouseEventSource synthSource() will be obsolete... that's why it's not public now
+ Qt::MouseEventSource synthSource() const { return m_synthSource; }
+
+private:
+ QVector2D m_angleDelta;
+ QVector2D m_pixelDelta;
+ Qt::ScrollPhase m_phase = Qt::NoScrollPhase;
+ Qt::MouseEventSource m_synthSource = Qt::MouseEventNotSynthesized;
+ bool m_inverted = false;
+
+ friend class QQuickWindowPrivate;
+
+ Q_DISABLE_COPY(QQuickPointerScrollEvent)
+};
+
// ### Qt 6: move this to qtbase, replace QTouchDevice and the enums in QTabletEvent
class Q_QUICK_PRIVATE_EXPORT QQuickPointerDevice : public QObject
@@ -627,6 +672,7 @@ public:
int buttonCount() const { return m_buttonCount; }
QString name() const { return m_name; }
QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; }
+ const QTouchDevice *qTouchDevice() const;
static QQuickPointerDevice *touchDevice(const QTouchDevice *d);
static QList<QQuickPointerDevice *> touchDevices();
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 9be8b7f2b9..01413385d9 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -8680,7 +8680,7 @@ void QV4::Heap::QQuickItemWrapper::markObjects(QV4::Heap::Base *that, QV4::MarkS
quint64 QQuickItemPrivate::_q_createJSWrapper(QV4::ExecutionEngine *engine)
{
- return (engine->memoryManager->allocObject<QQuickItemWrapper>(q_func()))->asReturnedValue();
+ return (engine->memoryManager->allocate<QQuickItemWrapper>(q_func()))->asReturnedValue();
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 51a91e1f7a..96927dd37a 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -422,6 +422,9 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickAnimatedImage, 11>(uri, 2, 11,"AnimatedImage");
#endif
qmlRegisterType<QQuickItem, 11>(uri, 2, 11,"Item");
+
+ qmlRegisterType<QQuickAnimatedSprite, 12>("QtQuick", 2, 12, "AnimatedSprite");
+ qmlRegisterType<QQuickGradient, 12>(uri, 2, 12, "Gradient");
}
static void initResources()
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index f2e055e874..4e4881ce19 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qquickitemview_p_p.h"
+#include "qquickitemviewfxitem_p_p.h"
#include <QtQuick/private/qquicktransition_p.h>
#include <QtQml/QQmlInfo>
#include "qplatformdefs.h"
@@ -52,117 +53,14 @@ Q_LOGGING_CATEGORY(lcItemViewDelegateLifecycle, "qt.quick.itemview.lifecycle")
#endif
FxViewItem::FxViewItem(QQuickItem *i, QQuickItemView *v, bool own, QQuickItemViewAttached *attached)
- : item(i)
+ : QQuickItemViewFxItem(i, own, QQuickItemViewPrivate::get(v))
, view(v)
- , transitionableItem(nullptr)
, attached(attached)
- , ownItem(own)
- , releaseAfterTransition(false)
- , trackGeom(false)
{
if (attached) // can be null for default components (see createComponentItem)
attached->setView(view);
}
-FxViewItem::~FxViewItem()
-{
- delete transitionableItem;
- if (ownItem && item) {
- trackGeometry(false);
- item->setParentItem(nullptr);
- item->deleteLater();
- item = nullptr;
- }
-}
-
-qreal FxViewItem::itemX() const
-{
- return transitionableItem ? transitionableItem->itemX() : (item ? item->x() : 0);
-}
-
-qreal FxViewItem::itemY() const
-{
- return transitionableItem ? transitionableItem->itemY() : (item ? item->y() : 0);
-}
-
-void FxViewItem::moveTo(const QPointF &pos, bool immediate)
-{
- if (transitionableItem)
- transitionableItem->moveTo(pos, immediate);
- else if (item)
- item->setPosition(pos);
-}
-
-void FxViewItem::setVisible(bool visible)
-{
- if (!visible && transitionableItem && transitionableItem->transitionScheduledOrRunning())
- return;
- if (item)
- QQuickItemPrivate::get(item)->setCulled(!visible);
-}
-
-void FxViewItem::trackGeometry(bool track)
-{
- if (track) {
- if (!trackGeom) {
- if (item) {
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
- }
- trackGeom = true;
- }
- } else {
- if (trackGeom) {
- if (item) {
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
- }
- trackGeom = false;
- }
- }
-}
-
-QQuickItemViewTransitioner::TransitionType FxViewItem::scheduledTransitionType() const
-{
- return transitionableItem ? transitionableItem->nextTransitionType : QQuickItemViewTransitioner::NoTransition;
-}
-
-bool FxViewItem::transitionScheduledOrRunning() const
-{
- return transitionableItem ? transitionableItem->transitionScheduledOrRunning() : false;
-}
-
-bool FxViewItem::transitionRunning() const
-{
- return transitionableItem ? transitionableItem->transitionRunning() : false;
-}
-
-bool FxViewItem::isPendingRemoval() const
-{
- return transitionableItem ? transitionableItem->isPendingRemoval() : false;
-}
-
-void FxViewItem::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
-{
- if (!transitioner)
- return;
- if (!transitionableItem)
- transitionableItem = new QQuickItemViewTransitionableItem(item);
- transitioner->transitionNextReposition(transitionableItem, type, asTarget);
-}
-
-bool FxViewItem::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds)
-{
- return transitionableItem ? transitionableItem->prepareTransition(transitioner, index, viewBounds) : false;
-}
-
-void FxViewItem::startTransition(QQuickItemViewTransitioner *transitioner)
-{
- if (transitionableItem)
- transitionableItem->startTransition(transitioner, index);
-}
-
-
QQuickItemViewChangeSet::QQuickItemViewChangeSet()
: active(false)
{
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index e250cf0ccb..ea5b5df9c6 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -56,6 +56,7 @@
QT_REQUIRE_CONFIG(quick_itemview);
#include "qquickitemview_p.h"
+#include "qquickitemviewfxitem_p_p.h"
#include "qquickitemviewtransition_p.h"
#include "qquickflickable_p_p.h"
#include <QtQml/private/qqmlobjectmodel_p.h>
@@ -65,47 +66,13 @@ QT_REQUIRE_CONFIG(quick_itemview);
QT_BEGIN_NAMESPACE
-
-class Q_AUTOTEST_EXPORT FxViewItem
+class Q_AUTOTEST_EXPORT FxViewItem : public QQuickItemViewFxItem
{
public:
FxViewItem(QQuickItem *, QQuickItemView *, bool own, QQuickItemViewAttached *attached);
- virtual ~FxViewItem();
-
- qreal itemX() const;
- qreal itemY() const;
- inline qreal itemWidth() const { return item ? item->width() : 0; }
- inline qreal itemHeight() const { return item ? item->height() : 0; }
-
- void moveTo(const QPointF &pos, bool immediate);
- void setVisible(bool visible);
- void trackGeometry(bool track);
-
- QQuickItemViewTransitioner::TransitionType scheduledTransitionType() const;
- bool transitionScheduledOrRunning() const;
- bool transitionRunning() const;
- bool isPendingRemoval() const;
-
- void transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget);
- bool prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds);
- void startTransition(QQuickItemViewTransitioner *transitioner);
-
- // these are positions and sizes along the current direction of scrolling/flicking
- virtual qreal position() const = 0;
- virtual qreal endPosition() const = 0;
- virtual qreal size() const = 0;
- virtual qreal sectionSize() const = 0;
-
- virtual bool contains(qreal x, qreal y) const = 0;
- QPointer<QQuickItem> item;
QQuickItemView *view;
- QQuickItemViewTransitionableItem *transitionableItem;
QQuickItemViewAttached *attached;
- int index;
- bool ownItem;
- bool releaseAfterTransition;
- bool trackGeom;
};
diff --git a/src/quick/items/qquickitemviewfxitem.cpp b/src/quick/items/qquickitemviewfxitem.cpp
new file mode 100644
index 0000000000..f9c65967ea
--- /dev/null
+++ b/src/quick/items/qquickitemviewfxitem.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickitemviewfxitem_p_p.h"
+#include "qquickitem_p.h"
+#include "qquickitemview_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQuickItemViewFxItem::QQuickItemViewFxItem(QQuickItem *item, bool ownItem, QQuickItemChangeListener* changeListener)
+ : item(item)
+ , ownItem(ownItem)
+ , changeListener(changeListener)
+ , transitionableItem(nullptr)
+ , releaseAfterTransition(false)
+ , trackGeom(false)
+{
+}
+
+QQuickItemViewFxItem::~QQuickItemViewFxItem()
+{
+ delete transitionableItem;
+ if (ownItem && item) {
+ trackGeometry(false);
+ item->setParentItem(0);
+ item->deleteLater();
+ }
+}
+
+qreal QQuickItemViewFxItem::itemX() const
+{
+ return transitionableItem ? transitionableItem->itemX() : (item ? item->x() : 0);
+}
+
+qreal QQuickItemViewFxItem::itemY() const
+{
+ return transitionableItem ? transitionableItem->itemY() : (item ? item->y() : 0);
+}
+
+void QQuickItemViewFxItem::moveTo(const QPointF &pos, bool immediate)
+{
+ if (transitionableItem)
+ transitionableItem->moveTo(pos, immediate);
+ else if (item)
+ item->setPosition(pos);
+}
+
+void QQuickItemViewFxItem::setVisible(bool visible)
+{
+ if (!visible && transitionableItem && transitionableItem->transitionScheduledOrRunning())
+ return;
+ if (item)
+ QQuickItemPrivate::get(item)->setCulled(!visible);
+}
+
+void QQuickItemViewFxItem::trackGeometry(bool track)
+{
+ if (track) {
+ if (!trackGeom) {
+ if (item) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(changeListener, QQuickItemPrivate::Geometry);
+ }
+ trackGeom = true;
+ }
+ } else {
+ if (trackGeom) {
+ if (item) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->removeItemChangeListener(changeListener, QQuickItemPrivate::Geometry);
+ }
+ trackGeom = false;
+ }
+ }
+}
+
+QRectF QQuickItemViewFxItem::geometry() const
+{
+ return QRectF(item->position(), item->size());
+}
+
+void QQuickItemViewFxItem::setGeometry(const QRectF &geometry)
+{
+ item->setPosition(geometry.topLeft());
+ item->setSize(geometry.size());
+}
+
+QQuickItemViewTransitioner::TransitionType QQuickItemViewFxItem::scheduledTransitionType() const
+{
+ return transitionableItem ? transitionableItem->nextTransitionType : QQuickItemViewTransitioner::NoTransition;
+}
+
+bool QQuickItemViewFxItem::transitionScheduledOrRunning() const
+{
+ return transitionableItem ? transitionableItem->transitionScheduledOrRunning() : false;
+}
+
+bool QQuickItemViewFxItem::transitionRunning() const
+{
+ return transitionableItem ? transitionableItem->transitionRunning() : false;
+}
+
+bool QQuickItemViewFxItem::isPendingRemoval() const
+{
+ return transitionableItem ? transitionableItem->isPendingRemoval() : false;
+}
+
+void QQuickItemViewFxItem::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
+{
+ if (!transitioner)
+ return;
+ if (!transitionableItem)
+ transitionableItem = new QQuickItemViewTransitionableItem(item);
+ transitioner->transitionNextReposition(transitionableItem, type, asTarget);
+}
+
+bool QQuickItemViewFxItem::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds)
+{
+ return transitionableItem ? transitionableItem->prepareTransition(transitioner, index, viewBounds) : false;
+}
+
+void QQuickItemViewFxItem::startTransition(QQuickItemViewTransitioner *transitioner)
+{
+ if (transitionableItem)
+ transitionableItem->startTransition(transitioner, index);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/quick/items/qquickitemviewfxitem_p_p.h b/src/quick/items/qquickitemviewfxitem_p_p.h
new file mode 100644
index 0000000000..48ffe248bc
--- /dev/null
+++ b/src/quick/items/qquickitemviewfxitem_p_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFXVIEWITEM_P_P_H
+#define QQUICKFXVIEWITEM_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qtquickglobal_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickitemviewtransition_p.h>
+
+QT_REQUIRE_CONFIG(quick_itemview);
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQuickItemViewFxItem
+{
+public:
+ QQuickItemViewFxItem(QQuickItem *item, bool ownItem, QQuickItemChangeListener *changeListener);
+ virtual ~QQuickItemViewFxItem();
+
+ qreal itemX() const;
+ qreal itemY() const;
+ inline qreal itemWidth() const { return item ? item->width() : 0; }
+ inline qreal itemHeight() const { return item ? item->height() : 0; }
+
+ void moveTo(const QPointF &pos, bool immediate);
+ void setVisible(bool visible);
+ void trackGeometry(bool track);
+
+ QRectF geometry() const;
+ void setGeometry(const QRectF &geometry);
+
+ QQuickItemViewTransitioner::TransitionType scheduledTransitionType() const;
+ bool transitionScheduledOrRunning() const;
+ bool transitionRunning() const;
+ bool isPendingRemoval() const;
+
+ void transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget);
+ bool prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds);
+ void startTransition(QQuickItemViewTransitioner *transitioner);
+
+ // these are positions and sizes along the current direction of scrolling/flicking
+ virtual qreal position() const = 0;
+ virtual qreal endPosition() const = 0;
+ virtual qreal size() const = 0;
+ virtual qreal sectionSize() const = 0;
+
+ virtual bool contains(qreal x, qreal y) const = 0;
+
+ int index = -1;
+ QPointer<QQuickItem> item;
+ bool ownItem;
+ QQuickItemChangeListener *changeListener;
+ QQuickItemViewTransitionableItem *transitionableItem;
+ bool releaseAfterTransition;
+ bool trackGeom;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFXVIEWITEM_P_P_H
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index ea6a63559a..0de9d6c49a 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -54,7 +54,7 @@ static const QQuickItemPrivate::ChangeTypes watchedChanges
= QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
QQuickLoaderPrivate::QQuickLoaderPrivate()
- : item(nullptr), object(nullptr), component(nullptr), itemContext(nullptr), incubator(nullptr), updatingSize(false),
+ : item(nullptr), object(nullptr), itemContext(nullptr), incubator(nullptr), updatingSize(false),
active(true), loadingFromSource(false), asynchronous(false)
{
}
@@ -111,9 +111,8 @@ void QQuickLoaderPrivate::clear()
QObject::disconnect(component, SIGNAL(progressChanged(qreal)),
q, SIGNAL(progressChanged()));
component->deleteLater();
- component = nullptr;
+ component.setObject(nullptr, q);
}
- componentStrongReference.clear();
source = QUrl();
if (item) {
@@ -438,7 +437,7 @@ void QQuickLoader::loadFromSource()
if (isComponentComplete()) {
QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
- d->component = new QQmlComponent(qmlEngine(this), d->source, mode, this);
+ d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this);
d->load();
}
}
@@ -481,11 +480,7 @@ void QQuickLoader::setSourceComponent(QQmlComponent *comp)
d->clear();
- d->component = comp;
- if (comp) {
- if (QQmlData *ddata = QQmlData::get(comp))
- d->componentStrongReference = ddata->jsWrapper;
- }
+ d->component.setObject(comp, this);
d->loadingFromSource = false;
if (d->active)
@@ -828,7 +823,7 @@ void QQuickLoader::componentComplete()
if (active()) {
if (d->loadingFromSource) {
QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
- d->component = new QQmlComponent(qmlEngine(this), d->source, mode, this);
+ d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this);
}
d->load();
}
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 7492527401..349b5c6c06 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -103,8 +103,7 @@ public:
QUrl source;
QQuickItem *item;
QObject *object;
- QQmlComponent *component;
- QV4::PersistentValue componentStrongReference; // To ensure GC doesn't delete components created by Qt.createComponent
+ QQmlStrongJSQObjectReference<QQmlComponent> component;
QQmlContext *itemContext;
QQuickLoaderIncubator *incubator;
QV4::PersistentValue initialPropertyValues;
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index bf030b9d80..ab8203d0a8 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -219,10 +219,11 @@ void QQuickGradientStop::updateGradient()
of solid color fills or images. Consider using gradients for static items
in a user interface.
- In Qt 5.0, only vertical, linear gradients can be applied to items. If you
- need to apply different orientations of gradients, a combination of rotation
- and clipping will need to be applied to the relevant items. This can
- introduce additional performance requirements for your application.
+ Since Qt 5.12, vertical and horizontal linear gradients can be applied to items.
+ If you need to apply angled gradients, a combination of rotation and clipping
+ can be applied to the relevant items. Alternatively, consider using
+ QtQuick.Shapes::LinearGradient or QtGraphicalEffects::LinearGradient. These
+ approaches can all introduce additional performance requirements for your application.
The use of animations involving gradient stops may not give the desired
result. An alternative way to animate gradients is to use pre-generated
@@ -255,6 +256,28 @@ QQmlListProperty<QQuickGradientStop> QQuickGradient::stops()
return QQmlListProperty<QQuickGradientStop>(this, m_stops);
}
+/*!
+ \qmlproperty enumeration QtQuick::Gradient::orientation
+ \since 5.12
+
+ Set this property to define the direction of the gradient.
+ \list
+ \li Gradient.Vertical - a vertical gradient
+ \li Gradient.Horizontal - a horizontal gradient
+ \endlist
+
+ The default is Gradient.Vertical.
+*/
+void QQuickGradient::setOrientation(Orientation orientation)
+{
+ if (m_orientation == orientation)
+ return;
+
+ m_orientation = orientation;
+ emit orientationChanged();
+ emit updated();
+}
+
QGradientStops QQuickGradient::gradientStops() const
{
QGradientStops stops;
@@ -374,7 +397,7 @@ QQuickPen *QQuickRectangle::border()
The gradient to use to fill the rectangle.
- This property allows for the construction of simple vertical gradients.
+ This property allows for the construction of simple vertical or horizontal gradients.
Other gradients may be formed by adding rotation to the rectangle.
\div {class="float-left"}
@@ -510,10 +533,13 @@ QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
rectangle->setAntialiasing(antialiasing());
QGradientStops stops;
+ bool vertical = true;
if (d->gradient) {
stops = d->gradient->gradientStops();
+ vertical = d->gradient->orientation() == QQuickGradient::Vertical;
}
rectangle->setGradientStops(stops);
+ rectangle->setGradientVertical(vertical);
rectangle->update();
diff --git a/src/quick/items/qquickrectangle_p.h b/src/quick/items/qquickrectangle_p.h
index c07ad835fb..ddafaafb28 100644
--- a/src/quick/items/qquickrectangle_p.h
+++ b/src/quick/items/qquickrectangle_p.h
@@ -119,24 +119,34 @@ class Q_QUICK_PRIVATE_EXPORT QQuickGradient : public QObject
Q_OBJECT
Q_PROPERTY(QQmlListProperty<QQuickGradientStop> stops READ stops)
+ Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged REVISION 12)
Q_CLASSINFO("DefaultProperty", "stops")
public:
QQuickGradient(QObject *parent=nullptr);
~QQuickGradient() override;
+ enum Orientation { Vertical = Qt::Vertical,
+ Horizontal = Qt::Horizontal };
+ Q_ENUM(Orientation)
+
QQmlListProperty<QQuickGradientStop> stops();
+ Orientation orientation() const { return m_orientation; }
+ void setOrientation(Orientation orientation);
+
QGradientStops gradientStops() const;
Q_SIGNALS:
void updated();
+ void orientationChanged();
private:
void doUpdate();
private:
QList<QQuickGradientStop *> m_stops;
+ Orientation m_orientation = Vertical;
friend class QQuickRectangle;
friend class QQuickGradientStop;
};
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index 49568db552..b06b0821d2 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -187,7 +187,6 @@ void QQuickRenderControlPrivate::windowDestroyed()
{
if (window) {
rc->invalidate();
- QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
delete QQuickWindowPrivate::get(window)->animationController;
QQuickWindowPrivate::get(window)->animationController = nullptr;
diff --git a/src/quick/items/qquickscalegrid.cpp b/src/quick/items/qquickscalegrid.cpp
index d7a0f1b681..23f179be1d 100644
--- a/src/quick/items/qquickscalegrid.cpp
+++ b/src/quick/items/qquickscalegrid.cpp
@@ -66,6 +66,7 @@ void QQuickScaleGrid::setLeft(int pos)
{
if (_left != pos) {
_left = pos;
+ emit leftBorderChanged();
emit borderChanged();
}
}
@@ -74,6 +75,7 @@ void QQuickScaleGrid::setTop(int pos)
{
if (_top != pos) {
_top = pos;
+ emit topBorderChanged();
emit borderChanged();
}
}
@@ -82,6 +84,7 @@ void QQuickScaleGrid::setRight(int pos)
{
if (_right != pos) {
_right = pos;
+ emit rightBorderChanged();
emit borderChanged();
}
}
@@ -90,6 +93,7 @@ void QQuickScaleGrid::setBottom(int pos)
{
if (_bottom != pos) {
_bottom = pos;
+ emit bottomBorderChanged();
emit borderChanged();
}
}
diff --git a/src/quick/items/qquickscalegrid_p_p.h b/src/quick/items/qquickscalegrid_p_p.h
index 5752f61e3f..f5187a8eea 100644
--- a/src/quick/items/qquickscalegrid_p_p.h
+++ b/src/quick/items/qquickscalegrid_p_p.h
@@ -65,10 +65,10 @@ class Q_AUTOTEST_EXPORT QQuickScaleGrid : public QObject
{
Q_OBJECT
- Q_PROPERTY(int left READ left WRITE setLeft NOTIFY borderChanged)
- Q_PROPERTY(int top READ top WRITE setTop NOTIFY borderChanged)
- Q_PROPERTY(int right READ right WRITE setRight NOTIFY borderChanged)
- Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY borderChanged)
+ Q_PROPERTY(int left READ left WRITE setLeft NOTIFY leftBorderChanged)
+ Q_PROPERTY(int top READ top WRITE setTop NOTIFY topBorderChanged)
+ Q_PROPERTY(int right READ right WRITE setRight NOTIFY rightBorderChanged)
+ Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY bottomBorderChanged)
public:
QQuickScaleGrid(QObject *parent=nullptr);
@@ -90,6 +90,10 @@ public:
Q_SIGNALS:
void borderChanged();
+ void leftBorderChanged();
+ void topBorderChanged();
+ void rightBorderChanged();
+ void bottomBorderChanged();
private:
int _left;
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
new file mode 100644
index 0000000000..bcdc06a783
--- /dev/null
+++ b/src/quick/items/qquicktableview.cpp
@@ -0,0 +1,1474 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktableview_p.h"
+#include "qquicktableview_p_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtQml/private/qqmldelegatemodel_p.h>
+#include <QtQml/private/qqmldelegatemodel_p_p.h>
+#include <QtQml/private/qqmlincubator_p.h>
+#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQml/qqmlinfo.h>
+
+#include <QtQuick/private/qquickflickable_p_p.h>
+#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcTableViewDelegateLifecycle, "qt.quick.tableview.lifecycle")
+
+#define Q_TABLEVIEW_UNREACHABLE(output) { dumpTable(); qWarning() << "output:" << output; Q_UNREACHABLE(); }
+#define Q_TABLEVIEW_ASSERT(cond, output) Q_ASSERT(cond || [&](){ dumpTable(); qWarning() << "output:" << output; return false;}())
+
+static const Qt::Edge allTableEdges[] = { Qt::LeftEdge, Qt::RightEdge, Qt::TopEdge, Qt::BottomEdge };
+static const int kBufferTimerInterval = 300;
+
+static QLine rectangleEdge(const QRect &rect, Qt::Edge tableEdge)
+{
+ switch (tableEdge) {
+ case Qt::LeftEdge:
+ return QLine(rect.topLeft(), rect.bottomLeft());
+ case Qt::RightEdge:
+ return QLine(rect.topRight(), rect.bottomRight());
+ case Qt::TopEdge:
+ return QLine(rect.topLeft(), rect.topRight());
+ case Qt::BottomEdge:
+ return QLine(rect.bottomLeft(), rect.bottomRight());
+ }
+ return QLine();
+}
+
+static QRect expandedRect(const QRect &rect, Qt::Edge edge, int increment)
+{
+ switch (edge) {
+ case Qt::LeftEdge:
+ return rect.adjusted(-increment, 0, 0, 0);
+ case Qt::RightEdge:
+ return rect.adjusted(0, 0, increment, 0);
+ case Qt::TopEdge:
+ return rect.adjusted(0, -increment, 0, 0);
+ case Qt::BottomEdge:
+ return rect.adjusted(0, 0, 0, increment);
+ }
+ return QRect();
+}
+
+const QPoint QQuickTableViewPrivate::kLeft = QPoint(-1, 0);
+const QPoint QQuickTableViewPrivate::kRight = QPoint(1, 0);
+const QPoint QQuickTableViewPrivate::kUp = QPoint(0, -1);
+const QPoint QQuickTableViewPrivate::kDown = QPoint(0, 1);
+
+QQuickTableViewPrivate::QQuickTableViewPrivate()
+ : QQuickFlickablePrivate()
+{
+ cacheBufferDelayTimer.setSingleShot(true);
+ QObject::connect(&cacheBufferDelayTimer, &QTimer::timeout, [=]{ loadBuffer(); });
+}
+
+QQuickTableViewPrivate::~QQuickTableViewPrivate()
+{
+ clear();
+}
+
+QString QQuickTableViewPrivate::tableLayoutToString() const
+{
+ return QString(QLatin1String("table cells: (%1,%2) -> (%3,%4), item count: %5, table rect: %6,%7 x %8,%9"))
+ .arg(loadedTable.topLeft().x()).arg(loadedTable.topLeft().y())
+ .arg(loadedTable.bottomRight().x()).arg(loadedTable.bottomRight().y())
+ .arg(loadedItems.count())
+ .arg(loadedTableOuterRect.x())
+ .arg(loadedTableOuterRect.y())
+ .arg(loadedTableOuterRect.width())
+ .arg(loadedTableOuterRect.height());
+}
+
+void QQuickTableViewPrivate::dumpTable() const
+{
+ auto listCopy = loadedItems;
+ std::stable_sort(listCopy.begin(), listCopy.end(),
+ [](const FxTableItem *lhs, const FxTableItem *rhs)
+ { return lhs->index < rhs->index; });
+
+ qWarning() << QStringLiteral("******* TABLE DUMP *******");
+ for (int i = 0; i < listCopy.count(); ++i)
+ qWarning() << static_cast<FxTableItem *>(listCopy.at(i))->cell;
+ qWarning() << tableLayoutToString();
+
+ QString filename = QStringLiteral("QQuickTableView_dumptable_capture.png");
+ if (q_func()->window()->grabWindow().save(filename))
+ qWarning() << "Window capture saved to:" << filename;
+}
+
+QQuickTableViewAttached *QQuickTableViewPrivate::getAttachedObject(const QObject *object) const
+{
+ QObject *attachedObject = qmlAttachedPropertiesObject<QQuickTableView>(object);
+ return static_cast<QQuickTableViewAttached *>(attachedObject);
+}
+
+int QQuickTableViewPrivate::modelIndexAtCell(const QPoint &cell)
+{
+ int availableRows = tableSize.height();
+ int modelIndex = cell.y() + (cell.x() * availableRows);
+ Q_TABLEVIEW_ASSERT(modelIndex < model->count(), modelIndex << cell);
+ return modelIndex;
+}
+
+QPoint QQuickTableViewPrivate::cellAtModelIndex(int modelIndex)
+{
+ int availableRows = tableSize.height();
+ Q_TABLEVIEW_ASSERT(availableRows > 0, availableRows);
+ int column = int(modelIndex / availableRows);
+ int row = modelIndex % availableRows;
+ return QPoint(column, row);
+}
+
+void QQuickTableViewPrivate::updateContentWidth()
+{
+ Q_Q(QQuickTableView);
+
+ const qreal thresholdBeforeAdjust = 0.1;
+ int currentRightColumn = loadedTable.right();
+
+ if (currentRightColumn > contentSizeBenchMarkPoint.x()) {
+ contentSizeBenchMarkPoint.setX(currentRightColumn);
+
+ qreal currentWidth = loadedTableOuterRect.right();
+ qreal averageCellSize = currentWidth / (currentRightColumn + 1);
+ qreal averageSize = averageCellSize + cellSpacing.width();
+ qreal estimatedWith = (tableSize.width() * averageSize) - cellSpacing.width();
+
+ // loadedTableOuterRect has already been adjusted for left margin
+ currentWidth += tableMargins.right();
+ estimatedWith += tableMargins.right();
+
+ if (currentRightColumn >= tableSize.width() - 1) {
+ // We are at the last column, and can set the exact width
+ if (currentWidth != q->implicitWidth())
+ q->setContentWidth(currentWidth);
+ } else if (currentWidth >= q->implicitWidth()) {
+ // We are at the estimated width, but there are still more columns
+ q->setContentWidth(estimatedWith);
+ } else {
+ // Only set a new width if the new estimate is substantially different
+ qreal diff = 1 - (estimatedWith / q->implicitWidth());
+ if (qAbs(diff) > thresholdBeforeAdjust)
+ q->setContentWidth(estimatedWith);
+ }
+ }
+}
+
+void QQuickTableViewPrivate::updateContentHeight()
+{
+ Q_Q(QQuickTableView);
+
+ const qreal thresholdBeforeAdjust = 0.1;
+ int currentBottomRow = loadedTable.bottom();
+
+ if (currentBottomRow > contentSizeBenchMarkPoint.y()) {
+ contentSizeBenchMarkPoint.setY(currentBottomRow);
+
+ qreal currentHeight = loadedTableOuterRect.bottom();
+ qreal averageCellSize = currentHeight / (currentBottomRow + 1);
+ qreal averageSize = averageCellSize + cellSpacing.height();
+ qreal estimatedHeight = (tableSize.height() * averageSize) - cellSpacing.height();
+
+ // loadedTableOuterRect has already been adjusted for top margin
+ currentHeight += tableMargins.bottom();
+ estimatedHeight += tableMargins.bottom();
+
+ if (currentBottomRow >= tableSize.height() - 1) {
+ // We are at the last row, and can set the exact height
+ if (currentHeight != q->implicitHeight())
+ q->setContentHeight(currentHeight);
+ } else if (currentHeight >= q->implicitHeight()) {
+ // We are at the estimated height, but there are still more rows
+ q->setContentHeight(estimatedHeight);
+ } else {
+ // Only set a new height if the new estimate is substantially different
+ qreal diff = 1 - (estimatedHeight / q->implicitHeight());
+ if (qAbs(diff) > thresholdBeforeAdjust)
+ q->setContentHeight(estimatedHeight);
+ }
+ }
+}
+
+void QQuickTableViewPrivate::enforceFirstRowColumnAtOrigo()
+{
+ // Gaps before the first row/column can happen if rows/columns
+ // changes size while flicking e.g because of spacing changes or
+ // changes to a column maxWidth/row maxHeight. Check for this, and
+ // move the whole table rect accordingly.
+ bool layoutNeeded = false;
+ const qreal flickMargin = 50;
+
+ if (loadedTable.x() == 0 && loadedTableOuterRect.x() != tableMargins.left()) {
+ // The table is at the beginning, but not at the edge of the
+ // content view. So move the table to origo.
+ loadedTableOuterRect.moveLeft(tableMargins.left());
+ layoutNeeded = true;
+ } else if (loadedTableOuterRect.x() < 0) {
+ // The table is outside the beginning of the content view. Move
+ // the whole table inside, and make some room for flicking.
+ loadedTableOuterRect.moveLeft(tableMargins.left() + loadedTable.x() == 0 ? 0 : flickMargin);
+ layoutNeeded = true;
+ }
+
+ if (loadedTable.y() == 0 && loadedTableOuterRect.y() != tableMargins.top()) {
+ loadedTableOuterRect.moveTop(tableMargins.top());
+ layoutNeeded = true;
+ } else if (loadedTableOuterRect.y() < 0) {
+ loadedTableOuterRect.moveTop(tableMargins.top() + loadedTable.y() == 0 ? 0 : flickMargin);
+ layoutNeeded = true;
+ }
+
+ if (layoutNeeded)
+ relayoutTableItems();
+}
+
+void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
+{
+ QRectF topLeftRect = loadedTableItem(loadedTable.topLeft())->geometry();
+ QRectF bottomRightRect = loadedTableItem(loadedTable.bottomRight())->geometry();
+ loadedTableOuterRect = topLeftRect.united(bottomRightRect);
+ loadedTableInnerRect = QRectF(topLeftRect.bottomRight(), bottomRightRect.topLeft());
+}
+
+void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest()
+{
+ switch (loadRequest.edge()) {
+ case Qt::LeftEdge:
+ case Qt::TopEdge:
+ loadedTable.setTopLeft(loadRequest.firstCell());
+ break;
+ case Qt::RightEdge:
+ case Qt::BottomEdge:
+ loadedTable.setBottomRight(loadRequest.lastCell());
+ break;
+ default:
+ loadedTable = QRect(loadRequest.firstCell(), loadRequest.lastCell());
+ }
+}
+
+FxTableItem *QQuickTableViewPrivate::itemNextTo(const FxTableItem *fxTableItem, const QPoint &direction) const
+{
+ return loadedTableItem(fxTableItem->cell + direction);
+}
+
+FxTableItem *QQuickTableViewPrivate::loadedTableItem(const QPoint &cell) const
+{
+ for (int i = 0; i < loadedItems.count(); ++i) {
+ FxTableItem *item = loadedItems.at(i);
+ if (item->cell == cell)
+ return item;
+ }
+
+ Q_TABLEVIEW_UNREACHABLE(cell);
+ return nullptr;
+}
+
+FxTableItem *QQuickTableViewPrivate::createFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
+{
+ Q_Q(QQuickTableView);
+
+ bool ownItem = false;
+ int modelIndex = modelIndexAtCell(cell);
+
+ QObject* object = model->object(modelIndex, incubationMode);
+ if (!object) {
+ if (model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
+ // Item is incubating. Return nullptr for now, and let the table call this
+ // function again once we get a callback to itemCreatedCallback().
+ return nullptr;
+ }
+
+ qWarning() << "TableView: failed loading index:" << modelIndex;
+ object = new QQuickItem();
+ ownItem = true;
+ }
+
+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
+ if (!item) {
+ // The model could not provide an QQuickItem for the
+ // given index, so we create a placeholder instead.
+ qWarning() << "TableView: delegate is not an item:" << modelIndex;
+ model->release(object);
+ item = new QQuickItem();
+ ownItem = true;
+ }
+
+ item->setParentItem(q->contentItem());
+
+ FxTableItem *fxTableItem = new FxTableItem(item, q, ownItem);
+ fxTableItem->setVisible(false);
+ fxTableItem->cell = cell;
+ fxTableItem->index = modelIndex;
+ return fxTableItem;
+}
+
+FxTableItem *QQuickTableViewPrivate::loadFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
+{
+#ifdef QT_DEBUG
+ // Since TableView needs to work flawlessly when e.g incubating inside an async
+ // loader, being able to override all loading to async while debugging can be helpful.
+ static const bool forcedAsync = forcedIncubationMode == QLatin1String("async");
+ if (forcedAsync)
+ incubationMode = QQmlIncubator::Asynchronous;
+#endif
+
+ // Note that even if incubation mode is asynchronous, the item might
+ // be ready immediately since the model has a cache of items.
+ QBoolBlocker guard(blockItemCreatedCallback);
+ auto item = createFxTableItem(cell, incubationMode);
+ qCDebug(lcTableViewDelegateLifecycle) << cell << "ready?" << bool(item);
+ return item;
+}
+
+void QQuickTableViewPrivate::releaseLoadedItems() {
+ // Make a copy and clear the list of items first to avoid destroyed
+ // items being accessed during the loop (QTBUG-61294)
+ auto const tmpList = loadedItems;
+ loadedItems.clear();
+ for (FxTableItem *item : tmpList)
+ releaseItem(item);
+}
+
+void QQuickTableViewPrivate::releaseItem(FxTableItem *fxTableItem)
+{
+ if (fxTableItem->item) {
+ if (fxTableItem->ownItem)
+ delete fxTableItem->item;
+ else if (model->release(fxTableItem->item) != QQmlInstanceModel::Destroyed)
+ fxTableItem->item->setParentItem(nullptr);
+ }
+
+ delete fxTableItem;
+}
+
+void QQuickTableViewPrivate::clear()
+{
+ tableInvalid = true;
+ tableRebuilding = false;
+ if (loadRequest.isActive())
+ cancelLoadRequest();
+
+ releaseLoadedItems();
+ loadedTable = QRect();
+ loadedTableOuterRect = QRect();
+ loadedTableInnerRect = QRect();
+ columnWidths.clear();
+ rowHeights.clear();
+ contentSizeBenchMarkPoint = QPoint(-1, -1);
+
+ updateContentWidth();
+ updateContentHeight();
+}
+
+void QQuickTableViewPrivate::unloadItem(const QPoint &cell)
+{
+ FxTableItem *item = loadedTableItem(cell);
+ loadedItems.removeOne(item);
+ releaseItem(item);
+}
+
+void QQuickTableViewPrivate::unloadItems(const QLine &items)
+{
+ qCDebug(lcTableViewDelegateLifecycle) << items;
+
+ if (items.dx()) {
+ int y = items.p1().y();
+ for (int x = items.p1().x(); x <= items.p2().x(); ++x)
+ unloadItem(QPoint(x, y));
+ } else {
+ int x = items.p1().x();
+ for (int y = items.p1().y(); y <= items.p2().y(); ++y)
+ unloadItem(QPoint(x, y));
+ }
+}
+
+bool QQuickTableViewPrivate::canLoadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const
+{
+ switch (tableEdge) {
+ case Qt::LeftEdge:
+ if (loadedTable.topLeft().x() == 0)
+ return false;
+ return loadedTableOuterRect.left() > fillRect.left() + cellSpacing.width();
+ case Qt::RightEdge:
+ if (loadedTable.bottomRight().x() >= tableSize.width() - 1)
+ return false;
+ return loadedTableOuterRect.right() < fillRect.right() - cellSpacing.width();
+ case Qt::TopEdge:
+ if (loadedTable.topLeft().y() == 0)
+ return false;
+ return loadedTableOuterRect.top() > fillRect.top() + cellSpacing.height();
+ case Qt::BottomEdge:
+ if (loadedTable.bottomRight().y() >= tableSize.height() - 1)
+ return false;
+ return loadedTableOuterRect.bottom() < fillRect.bottom() - cellSpacing.height();
+ }
+
+ return false;
+}
+
+bool QQuickTableViewPrivate::canUnloadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const
+{
+ // Note: if there is only one row or column left, we cannot unload, since
+ // they are needed as anchor point for further layouting.
+ switch (tableEdge) {
+ case Qt::LeftEdge:
+ if (loadedTable.width() <= 1)
+ return false;
+ return loadedTableInnerRect.left() < fillRect.left();
+ case Qt::RightEdge:
+ if (loadedTable.width() <= 1)
+ return false;
+ return loadedTableInnerRect.right() > fillRect.right();
+ case Qt::TopEdge:
+ if (loadedTable.height() <= 1)
+ return false;
+ return loadedTableInnerRect.top() < fillRect.top();
+ case Qt::BottomEdge:
+ if (loadedTable.height() <= 1)
+ return false;
+ return loadedTableInnerRect.bottom() > fillRect.bottom();
+ }
+ Q_TABLEVIEW_UNREACHABLE(tableEdge);
+ return false;
+}
+
+Qt::Edge QQuickTableViewPrivate::nextEdgeToLoad(const QRectF rect)
+{
+ for (Qt::Edge edge : allTableEdges) {
+ if (canLoadTableEdge(edge, rect))
+ return edge;
+ }
+ return Qt::Edge(0);
+}
+
+Qt::Edge QQuickTableViewPrivate::nextEdgeToUnload(const QRectF rect)
+{
+ for (Qt::Edge edge : allTableEdges) {
+ if (canUnloadTableEdge(edge, rect))
+ return edge;
+ }
+ return Qt::Edge(0);
+}
+
+qreal QQuickTableViewPrivate::cellWidth(const QPoint& cell)
+{
+ // If a delegate item has TableView.cellWidth set, then
+ // we prefer that. Otherwise we fall back to use implicitWidth.
+ // Using an items width directly is not an option, since we change
+ // it during layout (which would also cause problems when recycling items).
+ auto const cellItem = loadedTableItem(cell)->item;
+ if (auto const attached = getAttachedObject(cellItem)) {
+ if (!attached->m_cellWidth.isNull)
+ return attached->m_cellWidth;
+ }
+ return cellItem->implicitWidth();
+}
+
+qreal QQuickTableViewPrivate::cellHeight(const QPoint& cell)
+{
+ // If a delegate item has TableView.cellHeight set, then
+ // we prefer that. Otherwise we fall back to use implicitHeight.
+ // Using an items height directly is not an option, since we change
+ // it during layout (which would also cause problems when recycling items).
+ auto const cellItem = loadedTableItem(cell)->item;
+ if (auto const attached = getAttachedObject(cellItem)) {
+ if (!attached->m_cellHeight.isNull)
+ return attached->m_cellHeight;
+ }
+ return cellItem->implicitHeight();
+}
+
+void QQuickTableViewPrivate::calculateColumnWidthsAfterRebuilding()
+{
+ qreal prevColumnWidth = 0;
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) {
+ qreal columnWidth = 0;
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row)
+ columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
+
+ if (columnWidth <= 0)
+ columnWidth = kDefaultColumnWidth;
+
+ if (columnWidth == prevColumnWidth)
+ continue;
+
+ columnWidths.append({column, columnWidth});
+ prevColumnWidth = columnWidth;
+ }
+
+ if (columnWidths.isEmpty()) {
+ // Add at least one column, wo we don't need
+ // to check if the vector is empty elsewhere.
+ columnWidths.append({0, 0});
+ }
+}
+
+void QQuickTableViewPrivate::calculateRowHeightsAfterRebuilding()
+{
+ qreal prevRowHeight = 0;
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) {
+ qreal rowHeight = 0;
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column)
+ rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
+
+ if (rowHeight <= 0)
+ rowHeight = kDefaultRowHeight;
+
+ if (rowHeight == prevRowHeight)
+ continue;
+
+ rowHeights.append({row, rowHeight});
+ prevRowHeight = rowHeight;
+ }
+
+ if (rowHeights.isEmpty()) {
+ // Add at least one row, wo we don't need
+ // to check if the vector is empty elsewhere.
+ rowHeights.append({0, 0});
+ }
+}
+
+void QQuickTableViewPrivate::calculateColumnWidth(int column)
+{
+ if (column < columnWidths.last().index) {
+ // We only do the calculation once, and then stick with the size.
+ // See comments inside ColumnRowSize struct.
+ return;
+ }
+
+ qreal columnWidth = 0;
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row)
+ columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
+
+ if (columnWidth <= 0)
+ columnWidth = kDefaultColumnWidth;
+
+ if (columnWidth == columnWidths.last().size)
+ return;
+
+ columnWidths.append({column, columnWidth});
+}
+
+void QQuickTableViewPrivate::calculateRowHeight(int row)
+{
+ if (row < rowHeights.last().index) {
+ // We only do the calculation once, and then stick with the size.
+ // See comments inside ColumnRowSize struct.
+ return;
+ }
+
+ qreal rowHeight = 0;
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column)
+ rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
+
+ if (rowHeight <= 0)
+ rowHeight = kDefaultRowHeight;
+
+ if (rowHeight == rowHeights.last().size)
+ return;
+
+ rowHeights.append({row, rowHeight});
+}
+
+void QQuickTableViewPrivate::calculateEdgeSizeFromLoadRequest()
+{
+ if (tableRebuilding)
+ return;
+
+ switch (loadRequest.edge()) {
+ case Qt::LeftEdge:
+ case Qt::TopEdge:
+ // Flicking left or up through "never loaded" rows/columns is currently
+ // not supported. You always need to start loading the table from the beginning.
+ return;
+ case Qt::RightEdge:
+ if (tableSize.height() > 1)
+ calculateColumnWidth(loadedTable.right());
+ break;
+ case Qt::BottomEdge:
+ if (tableSize.width() > 1)
+ calculateRowHeight(loadedTable.bottom());
+ break;
+ default:
+ Q_TABLEVIEW_UNREACHABLE("This function should not be called when loading top-left item");
+ }
+}
+
+void QQuickTableViewPrivate::calculateTableSize()
+{
+ // tableSize is the same as row and column count, and will always
+ // be the same as the number of rows and columns in the model.
+ Q_Q(QQuickTableView);
+ QSize prevTableSize = tableSize;
+
+ if (delegateModel)
+ tableSize = QSize(delegateModel->columns(), delegateModel->rows());
+ else if (model)
+ tableSize = QSize(1, model->count());
+ else
+ tableSize = QSize(0, 0);
+
+ if (prevTableSize.width() != tableSize.width())
+ emit q->columnsChanged();
+ if (prevTableSize.height() != tableSize.height())
+ emit q->rowsChanged();
+}
+
+qreal QQuickTableViewPrivate::columnWidth(int column)
+{
+ if (!columnWidths.isEmpty()) {
+ // Find the first ColumnRowSize with a column before, or at, the given column
+ auto iter = std::upper_bound(columnWidths.constBegin(), columnWidths.constEnd(),
+ ColumnRowSize{column, -1}, ColumnRowSize::lessThan);
+
+ if (iter == columnWidths.constEnd()) {
+ // If the table is not a list, return the size
+ // of the last recorded ColumnRowSize.
+ if (tableSize.height() > 1)
+ return columnWidths.last().size;
+ } else {
+ // Check if we got an explicit assignment for this column
+ if (iter->index == column)
+ return iter->size;
+
+ // If the table is not a list, return the size of
+ // ColumnRowSize element found before column. Since there
+ // is always an element stored for column 0, this is safe.
+ // Otherwise we continue, and return the size of the delegate
+ // item at the given column instead.
+ if (tableSize.height() > 1)
+ return (iter - 1)->size;
+ }
+ }
+
+ // If we have an item loaded at column, return the width of the item.
+ if (column >= loadedTable.left() && column <= loadedTable.right())
+ return cellWidth(QPoint(column, loadedTable.top()));
+
+ return -1;
+}
+
+qreal QQuickTableViewPrivate::rowHeight(int row)
+{
+ if (!rowHeights.isEmpty()) {
+ // Find the ColumnRowSize assignment before, or at, row
+ auto iter = std::lower_bound(rowHeights.constBegin(), rowHeights.constEnd(),
+ ColumnRowSize{row, -1}, ColumnRowSize::lessThan);
+
+ if (iter == rowHeights.constEnd()) {
+ // If the table is not a list, return the size
+ // of the last recorded ColumnRowSize.
+ if (tableSize.width() > 1)
+ return rowHeights.last().size;
+ } else {
+ // Check if we got an explicit assignment for this row
+ if (iter->index == row)
+ return iter->size;
+
+ // If the table is not a list, return the size of
+ // ColumnRowSize element found before row. Since there
+ // is always an element stored for row 0, this is safe.
+ // Otherwise we continue, and return the size of the delegate
+ // item at the given row instead.
+ if (tableSize.width() > 1)
+ return (iter - 1)->size;
+ }
+ }
+
+ // If we have an item loaded at row, return the height of the item.
+ if (row >= loadedTable.top() && row <= loadedTable.bottom())
+ return cellHeight(QPoint(loadedTable.left(), row));
+
+ return -1;
+}
+
+void QQuickTableViewPrivate::relayoutTable()
+{
+ relayoutTableItems();
+ columnRowPositionsInvalid = false;
+
+ syncLoadedTableRectFromLoadedTable();
+ contentSizeBenchMarkPoint = QPoint(-1, -1);
+ updateContentWidth();
+ updateContentHeight();
+}
+
+void QQuickTableViewPrivate::relayoutTableItems()
+{
+ qCDebug(lcTableViewDelegateLifecycle);
+ columnRowPositionsInvalid = false;
+
+ qreal nextColumnX = loadedTableOuterRect.x();
+ qreal nextRowY = loadedTableOuterRect.y();
+
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) {
+ // Adjust the geometry of all cells in the current column
+ qreal width = columnWidth(column);
+ if (width <= 0)
+ width = kDefaultColumnWidth;
+
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) {
+ auto item = loadedTableItem(QPoint(column, row));
+ QRectF geometry = item->geometry();
+ geometry.moveLeft(nextColumnX);
+ geometry.setWidth(width);
+ item->setGeometry(geometry);
+ }
+
+ nextColumnX += width + cellSpacing.width();
+ }
+
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) {
+ // Adjust the geometry of all cells in the current row
+ qreal height = rowHeight(row);
+ if (height <= 0)
+ height = kDefaultRowHeight;
+
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) {
+ auto item = loadedTableItem(QPoint(column, row));
+ QRectF geometry = item->geometry();
+ geometry.moveTop(nextRowY);
+ geometry.setHeight(height);
+ item->setGeometry(geometry);
+ }
+
+ nextRowY += height + cellSpacing.height();
+ }
+
+ if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) {
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) {
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) {
+ QPoint cell = QPoint(column, row);
+ qCDebug(lcTableViewDelegateLifecycle()) << "relayout item:" << cell << loadedTableItem(cell)->geometry();
+ }
+ }
+ }
+}
+
+void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge)
+{
+ int column = (tableEdge == Qt::LeftEdge) ? loadedTable.left() : loadedTable.right();
+ QPoint neighbourDirection = (tableEdge == Qt::LeftEdge) ? kRight : kLeft;
+ qreal left = -1;
+
+ qreal width = columnWidth(column);
+ if (width <= 0)
+ width = kDefaultColumnWidth;
+
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) {
+ auto fxTableItem = loadedTableItem(QPoint(column, row));
+ auto const neighbourItem = itemNextTo(fxTableItem, neighbourDirection);
+
+ QRectF geometry = fxTableItem->geometry();
+ geometry.setWidth(width);
+ geometry.setHeight(neighbourItem->geometry().height());
+
+ if (left == -1) {
+ // left will be the same for all items in the
+ // column, so do the calculation once.
+ left = tableEdge == Qt::LeftEdge ?
+ neighbourItem->geometry().left() - cellSpacing.width() - geometry.width() :
+ neighbourItem->geometry().right() + cellSpacing.width();
+ }
+
+ geometry.moveLeft(left);
+ geometry.moveTop(neighbourItem->geometry().top());
+
+ fxTableItem->setGeometry(geometry);
+ fxTableItem->setVisible(true);
+
+ qCDebug(lcTableViewDelegateLifecycle()) << "layout item:" << QPoint(column, row) << fxTableItem->geometry();
+ }
+}
+
+void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge)
+{
+ int row = (tableEdge == Qt::TopEdge) ? loadedTable.top() : loadedTable.bottom();
+ QPoint neighbourDirection = (tableEdge == Qt::TopEdge) ? kDown : kUp;
+ qreal top = -1;
+
+ qreal height = rowHeight(row);
+ if (height <= 0)
+ height = kDefaultRowHeight;
+
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) {
+ auto fxTableItem = loadedTableItem(QPoint(column, row));
+ auto const neighbourItem = itemNextTo(fxTableItem, neighbourDirection);
+
+ QRectF geometry = fxTableItem->geometry();
+ geometry.setWidth(neighbourItem->geometry().width());
+ geometry.setHeight(height);
+
+ if (top == -1) {
+ // top will be the same for all items in the
+ // row, so do the calculation once.
+ top = tableEdge == Qt::TopEdge ?
+ neighbourItem->geometry().top() - cellSpacing.height() - geometry.height() :
+ neighbourItem->geometry().bottom() + cellSpacing.height();
+ }
+
+ geometry.moveTop(top);
+ geometry.moveLeft(neighbourItem->geometry().left());
+
+ fxTableItem->setGeometry(geometry);
+ fxTableItem->setVisible(true);
+
+ qCDebug(lcTableViewDelegateLifecycle()) << "layout item:" << QPoint(column, row) << fxTableItem->geometry();
+ }
+}
+
+void QQuickTableViewPrivate::layoutTopLeftItem()
+{
+ // ###todo: support starting with other top-left items than 0,0
+ const QPoint cell = loadRequest.firstCell();
+ Q_TABLEVIEW_ASSERT(cell == QPoint(0, 0), loadRequest.toString());
+ auto topLeftItem = loadedTableItem(cell);
+ auto item = topLeftItem->item;
+
+ qreal width = cellWidth(cell);
+ qreal height = cellHeight(cell);
+ if (width <= 0)
+ width = kDefaultColumnWidth;
+ if (height <= 0)
+ height = kDefaultRowHeight;
+
+ item->setPosition(QPoint(tableMargins.left(), tableMargins.top()));
+ item->setSize(QSizeF(width, height));
+ topLeftItem->setVisible(true);
+ qCDebug(lcTableViewDelegateLifecycle) << "geometry:" << topLeftItem->geometry();
+}
+
+void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
+{
+ switch (loadRequest.edge()) {
+ case Qt::LeftEdge:
+ case Qt::RightEdge:
+ layoutVerticalEdge(loadRequest.edge());
+ break;
+ case Qt::TopEdge:
+ case Qt::BottomEdge:
+ layoutHorizontalEdge(loadRequest.edge());
+ break;
+ default:
+ layoutTopLeftItem();
+ break;
+ }
+}
+
+void QQuickTableViewPrivate::cancelLoadRequest()
+{
+ loadRequest.markAsDone();
+ model->cancel(modelIndexAtCell(loadRequest.currentCell()));
+
+ if (tableInvalid) {
+ // No reason to rollback already loaded edge items
+ // since we anyway are about to reload all items.
+ return;
+ }
+
+ if (loadRequest.atBeginning()) {
+ // No items have yet been loaded, so nothing to unload
+ return;
+ }
+
+ QLine rollbackItems;
+ rollbackItems.setP1(loadRequest.firstCell());
+ rollbackItems.setP2(loadRequest.previousCell());
+ qCDebug(lcTableViewDelegateLifecycle()) << "rollback:" << rollbackItems << tableLayoutToString();
+ unloadItems(rollbackItems);
+}
+
+void QQuickTableViewPrivate::processLoadRequest()
+{
+ Q_TABLEVIEW_ASSERT(loadRequest.isActive(), "");
+
+ while (loadRequest.hasCurrentCell()) {
+ QPoint cell = loadRequest.currentCell();
+ FxTableItem *fxTableItem = loadFxTableItem(cell, loadRequest.incubationMode());
+
+ if (!fxTableItem) {
+ // Requested item is not yet ready. Just leave, and wait for this
+ // function to be called again when the item is ready.
+ return;
+ }
+
+ loadedItems.append(fxTableItem);
+ loadRequest.moveToNextCell();
+ }
+
+ qCDebug(lcTableViewDelegateLifecycle()) << "all items loaded!";
+
+ syncLoadedTableFromLoadRequest();
+ calculateEdgeSizeFromLoadRequest();
+ layoutTableEdgeFromLoadRequest();
+
+ syncLoadedTableRectFromLoadedTable();
+ enforceFirstRowColumnAtOrigo();
+ updateContentWidth();
+ updateContentHeight();
+
+ loadRequest.markAsDone();
+ qCDebug(lcTableViewDelegateLifecycle()) << "request completed! Table:" << tableLayoutToString();
+}
+
+void QQuickTableViewPrivate::beginRebuildTable()
+{
+ qCDebug(lcTableViewDelegateLifecycle());
+ clear();
+ tableInvalid = false;
+ tableRebuilding = true;
+ calculateTableSize();
+ loadInitialTopLeftItem();
+ loadAndUnloadVisibleEdges();
+}
+
+void QQuickTableViewPrivate::endRebuildTable()
+{
+ tableRebuilding = false;
+
+ if (loadedItems.isEmpty())
+ return;
+
+ // We don't calculate row/column sizes for lists.
+ // Instead we we use the sizes of the items directly
+ // unless for explicit row/column size assignments.
+ columnWidths.clear();
+ rowHeights.clear();
+ if (tableSize.height() > 1)
+ calculateColumnWidthsAfterRebuilding();
+ if (tableSize.width() > 1)
+ calculateRowHeightsAfterRebuilding();
+
+ relayoutTable();
+ qCDebug(lcTableViewDelegateLifecycle()) << tableLayoutToString();
+}
+
+void QQuickTableViewPrivate::loadInitialTopLeftItem()
+{
+ Q_TABLEVIEW_ASSERT(loadedItems.isEmpty(), "");
+
+ if (tableSize.isEmpty())
+ return;
+
+ if (model->count() == 0)
+ return;
+
+ // Load top-left item. After loaded, loadItemsInsideRect() will take
+ // care of filling out the rest of the table.
+ loadRequest.begin(QPoint(0, 0), QQmlIncubator::AsynchronousIfNested);
+ processLoadRequest();
+}
+
+void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
+{
+ unloadItems(rectangleEdge(loadedTable, edge));
+ loadedTable = expandedRect(loadedTable, edge, -1);
+ syncLoadedTableRectFromLoadedTable();
+ qCDebug(lcTableViewDelegateLifecycle) << tableLayoutToString();
+}
+
+void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
+{
+ QLine cellsToLoad = rectangleEdge(expandedRect(loadedTable, edge, 1), edge);
+ loadRequest.begin(cellsToLoad, edge, incubationMode);
+ processLoadRequest();
+}
+
+void QQuickTableViewPrivate::loadAndUnloadVisibleEdges()
+{
+ // Unload table edges that have been moved outside the visible part of the
+ // table (including buffer area), and load new edges that has been moved inside.
+ // Note: an important point is that we always keep the table rectangular
+ // and without holes to reduce complexity (we never leave the table in
+ // a half-loaded state, or keep track of multiple patches).
+ // We load only one edge (row or column) at a time. This is especially
+ // important when loading into the buffer, since we need to be able to
+ // cancel the buffering quickly if the user starts to flick, and then
+ // focus all further loading on the edges that are flicked into view.
+
+ if (loadRequest.isActive()) {
+ // Don't start loading more edges while we're
+ // already waiting for another one to load.
+ return;
+ }
+
+ if (loadedItems.isEmpty()) {
+ // We need at least the top-left item to be loaded before we can
+ // start loading edges around it. Not having a top-left item at
+ // this point means that the model is empty (or no delegate).
+ return;
+ }
+
+ const QRectF unloadRect = hasBufferedItems ? bufferRect() : viewportRect;
+ bool tableModified;
+
+ do {
+ tableModified = false;
+
+ if (Qt::Edge edge = nextEdgeToUnload(unloadRect)) {
+ tableModified = true;
+ unloadEdge(edge);
+ }
+
+ if (Qt::Edge edge = nextEdgeToLoad(viewportRect)) {
+ tableModified = true;
+ loadEdge(edge, QQmlIncubator::AsynchronousIfNested);
+ if (loadRequest.isActive())
+ return;
+ }
+ } while (tableModified);
+
+}
+
+void QQuickTableViewPrivate::loadBuffer()
+{
+ // Rather than making sure to stop the timer from all locations that can
+ // violate the "buffering allowed" state, we just check that we're in the
+ // right state here before we start buffering.
+ if (cacheBuffer <= 0 || loadRequest.isActive() || loadedItems.isEmpty())
+ return;
+
+ qCDebug(lcTableViewDelegateLifecycle());
+ const QRectF loadRect = bufferRect();
+ while (Qt::Edge edge = nextEdgeToLoad(loadRect)) {
+ loadEdge(edge, QQmlIncubator::Asynchronous);
+ if (loadRequest.isActive())
+ break;
+ }
+
+ hasBufferedItems = true;
+}
+
+void QQuickTableViewPrivate::unloadBuffer()
+{
+ if (!hasBufferedItems)
+ return;
+
+ qCDebug(lcTableViewDelegateLifecycle());
+ hasBufferedItems = false;
+ cacheBufferDelayTimer.stop();
+ if (loadRequest.isActive())
+ cancelLoadRequest();
+ while (Qt::Edge edge = nextEdgeToUnload(viewportRect))
+ unloadEdge(edge);
+}
+
+QRectF QQuickTableViewPrivate::bufferRect()
+{
+ return viewportRect.adjusted(-cacheBuffer, -cacheBuffer, cacheBuffer, cacheBuffer);
+}
+
+void QQuickTableViewPrivate::invalidateTable() {
+ tableInvalid = true;
+ if (loadRequest.isActive())
+ cancelLoadRequest();
+ q_func()->polish();
+}
+
+void QQuickTableViewPrivate::invalidateColumnRowPositions() {
+ columnRowPositionsInvalid = true;
+ q_func()->polish();
+}
+
+void QQuickTableViewPrivate::updatePolish()
+{
+ // Whenever something changes, e.g viewport moves, spacing is set to a
+ // new value, model changes etc, this function will end up being called. Here
+ // we check what needs to be done, and load/unload cells accordingly.
+ Q_Q(QQuickTableView);
+
+ if (loadRequest.isActive()) {
+ // We're currently loading items async to build a new edge in the table. We see the loading
+ // as an atomic operation, which means that we don't continue doing anything else until all
+ // items have been received and laid out. Note that updatePolish is then called once more
+ // after the loadRequest has completed to handle anything that might have occurred in-between.
+ return;
+ }
+
+ // viewportRect describes the part of the content view that is actually visible. Since a
+ // negative width/height can happen (e.g during start-up), we check for this to avoid rebuilding
+ // the table (and e.g calculate initial row/column sizes) based on a premature viewport rect.
+ viewportRect = QRectF(q->contentX(), q->contentY(), q->width(), q->height());
+ if (!viewportRect.isValid())
+ return;
+
+ if (tableInvalid) {
+ beginRebuildTable();
+ if (loadRequest.isActive())
+ return;
+ }
+
+ if (tableRebuilding)
+ endRebuildTable();
+
+ if (loadedItems.isEmpty()) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "no items loaded, meaning empty model or no delegate";
+ return;
+ }
+
+ if (columnRowPositionsInvalid)
+ relayoutTable();
+
+ if (hasBufferedItems && nextEdgeToLoad(viewportRect)) {
+ // We are about to load more edges, so trim down the table as much
+ // as possible to avoid loading cells that are outside the viewport.
+ unloadBuffer();
+ }
+
+ loadAndUnloadVisibleEdges();
+
+ if (loadRequest.isActive())
+ return;
+
+ if (cacheBuffer > 0) {
+ // When polish hasn't been called for a while (which means that the viewport
+ // rect hasn't changed), we start buffering items. We delay this operation by
+ // using a timer to increase performance (by not loading hidden items) while
+ // the user is flicking.
+ cacheBufferDelayTimer.start(kBufferTimerInterval);
+ }
+}
+
+void QQuickTableViewPrivate::createWrapperModel()
+{
+ Q_Q(QQuickTableView);
+
+ delegateModel = new QQmlDelegateModel(qmlContext(q), q);
+ if (q->isComponentComplete())
+ delegateModel->componentComplete();
+ model = delegateModel;
+}
+
+void QQuickTableViewPrivate::itemCreatedCallback(int modelIndex, QObject*)
+{
+ if (blockItemCreatedCallback)
+ return;
+
+ qCDebug(lcTableViewDelegateLifecycle) << "item done loading:"
+ << cellAtModelIndex(modelIndex);
+
+ // Since the item we waited for has finished incubating, we can
+ // continue with the load request. processLoadRequest will
+ // ask the model for the requested item once more, which will be
+ // quick since the model has cached it.
+ processLoadRequest();
+ loadAndUnloadVisibleEdges();
+ updatePolish();
+}
+
+void QQuickTableViewPrivate::initItemCallback(int modelIndex, QObject *object)
+{
+ Q_UNUSED(modelIndex);
+ auto attached = getAttachedObject(object);
+ if (!attached)
+ return;
+
+ // Even though row and column is injected directly into the context of a delegate item
+ // from QQmlDelegateModel and its model classes, they will only return which row and
+ // column an item represents in the model. This might be different from which
+ // cell an item ends up in in the Table, if a different rows/columns has been set
+ // on it (which is typically the case for list models). For those cases, Table.row
+ // and Table.column can be helpful.
+ QPoint cell = cellAtModelIndex(modelIndex);
+ attached->setTableView(q_func());
+ attached->setColumn(cell.x());
+ attached->setRow(cell.y());
+}
+
+void QQuickTableViewPrivate::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
+{
+ Q_UNUSED(changeSet);
+ Q_UNUSED(reset);
+
+ // TODO: implement fine-grained support for model changes
+ invalidateTable();
+}
+
+QQuickTableView::QQuickTableView(QQuickItem *parent)
+ : QQuickFlickable(*(new QQuickTableViewPrivate), parent)
+{
+}
+
+int QQuickTableView::rows() const
+{
+ return d_func()->tableSize.height();
+}
+
+int QQuickTableView::columns() const
+{
+ return d_func()->tableSize.width();
+}
+
+qreal QQuickTableView::rowSpacing() const
+{
+ return d_func()->cellSpacing.height();
+}
+
+void QQuickTableView::setRowSpacing(qreal spacing)
+{
+ Q_D(QQuickTableView);
+ if (qFuzzyCompare(d->cellSpacing.height(), spacing))
+ return;
+
+ d->cellSpacing.setHeight(spacing);
+ d->invalidateColumnRowPositions();
+ emit rowSpacingChanged();
+}
+
+qreal QQuickTableView::columnSpacing() const
+{
+ return d_func()->cellSpacing.width();
+}
+
+void QQuickTableView::setColumnSpacing(qreal spacing)
+{
+ Q_D(QQuickTableView);
+ if (qFuzzyCompare(d->cellSpacing.width(), spacing))
+ return;
+
+ d->cellSpacing.setWidth(spacing);
+ d->invalidateColumnRowPositions();
+ emit columnSpacingChanged();
+}
+
+qreal QQuickTableView::topMargin() const
+{
+ return d_func()->tableMargins.top();
+}
+
+void QQuickTableView::setTopMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.top(), margin))
+ return;
+
+ d->tableMargins.setTop(margin);
+ d->invalidateColumnRowPositions();
+ emit topMarginChanged();
+}
+
+qreal QQuickTableView::bottomMargin() const
+{
+ return d_func()->tableMargins.bottom();
+}
+
+void QQuickTableView::setBottomMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.bottom(), margin))
+ return;
+
+ d->tableMargins.setBottom(margin);
+ d->invalidateColumnRowPositions();
+ emit bottomMarginChanged();
+}
+
+qreal QQuickTableView::leftMargin() const
+{
+ return d_func()->tableMargins.left();
+}
+
+void QQuickTableView::setLeftMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.left(), margin))
+ return;
+
+ d->tableMargins.setLeft(margin);
+ d->invalidateColumnRowPositions();
+ emit leftMarginChanged();
+}
+
+qreal QQuickTableView::rightMargin() const
+{
+ return d_func()->tableMargins.right();
+}
+
+void QQuickTableView::setRightMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.right(), margin))
+ return;
+
+ d->tableMargins.setRight(margin);
+ d->invalidateColumnRowPositions();
+ emit rightMarginChanged();
+}
+
+int QQuickTableView::cacheBuffer() const
+{
+ return d_func()->cacheBuffer;
+}
+
+void QQuickTableView::setCacheBuffer(int newBuffer)
+{
+ Q_D(QQuickTableView);
+ if (d->cacheBuffer == newBuffer || newBuffer < 0)
+ return;
+
+ d->cacheBuffer = newBuffer;
+
+ if (newBuffer == 0)
+ d->unloadBuffer();
+
+ emit cacheBufferChanged();
+ polish();
+}
+
+QVariant QQuickTableView::model() const
+{
+ return d_func()->modelVariant;
+}
+
+void QQuickTableView::setModel(const QVariant &newModel)
+{
+ Q_D(QQuickTableView);
+
+ d->modelVariant = newModel;
+ QVariant effectiveModelVariant = d->modelVariant;
+ if (effectiveModelVariant.userType() == qMetaTypeId<QJSValue>())
+ effectiveModelVariant = effectiveModelVariant.value<QJSValue>().toVariant();
+
+ if (d->model) {
+ QObjectPrivate::disconnect(d->model, &QQmlInstanceModel::createdItem, d, &QQuickTableViewPrivate::itemCreatedCallback);
+ QObjectPrivate::disconnect(d->model, &QQmlInstanceModel::initItem, d, &QQuickTableViewPrivate::initItemCallback);
+ QObjectPrivate::disconnect(d->model, &QQmlInstanceModel::modelUpdated, d, &QQuickTableViewPrivate::modelUpdated);
+ }
+
+ const auto instanceModel = qobject_cast<QQmlInstanceModel *>(qvariant_cast<QObject*>(effectiveModelVariant));
+
+ if (instanceModel) {
+ if (d->delegateModel)
+ delete d->delegateModel;
+ d->model = instanceModel;
+ d->delegateModel = qmlobject_cast<QQmlDelegateModel *>(instanceModel);
+ } else {
+ if (!d->delegateModel)
+ d->createWrapperModel();
+ QQmlDelegateModelPrivate::get(d->delegateModel)->m_useFirstColumnOnly = false;
+ d->delegateModel->setModel(effectiveModelVariant);
+ }
+
+ Q_ASSERT(d->model);
+ QObjectPrivate::connect(d->model, &QQmlInstanceModel::createdItem, d, &QQuickTableViewPrivate::itemCreatedCallback);
+ QObjectPrivate::connect(d->model, &QQmlInstanceModel::initItem, d, &QQuickTableViewPrivate::initItemCallback);
+ QObjectPrivate::connect(d->model, &QQmlInstanceModel::modelUpdated, d, &QQuickTableViewPrivate::modelUpdated);
+
+ d->invalidateTable();
+
+ emit modelChanged();
+}
+
+QQmlComponent *QQuickTableView::delegate() const
+{
+ Q_D(const QQuickTableView);
+ if (d->delegateModel)
+ return d->delegateModel->delegate();
+
+ return nullptr;
+}
+
+void QQuickTableView::setDelegate(QQmlComponent *newDelegate)
+{
+ Q_D(QQuickTableView);
+ if (newDelegate == delegate())
+ return;
+
+ if (!d->delegateModel)
+ d->createWrapperModel();
+
+ d->delegateModel->setDelegate(newDelegate);
+ d->invalidateTable();
+
+ emit delegateChanged();
+}
+
+QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
+{
+ return new QQuickTableViewAttached(obj);
+}
+
+void QQuickTableView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickTableView);
+ QQuickFlickable::geometryChanged(newGeometry, oldGeometry);
+ // We update the viewport rect from within updatePolish to
+ // ensure that we update when we're ready to update, and not
+ // while we're in the middle of loading/unloading edges.
+ d->updatePolish();
+}
+
+void QQuickTableView::viewportMoved(Qt::Orientations orientation)
+{
+ Q_D(QQuickTableView);
+ QQuickFlickable::viewportMoved(orientation);
+ // We update the viewport rect from within updatePolish to
+ // ensure that we update when we're ready to update, and not
+ // while we're in the middle of loading/unloading edges.
+ d->updatePolish();
+}
+
+void QQuickTableView::componentComplete()
+{
+ Q_D(QQuickTableView);
+
+ if (!d->model)
+ setModel(QVariant());
+
+ if (d->delegateModel)
+ d->delegateModel->componentComplete();
+
+ QQuickFlickable::componentComplete();
+}
+
+#include "moc_qquicktableview_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
new file mode 100644
index 0000000000..f3a589b9e4
--- /dev/null
+++ b/src/quick/items/qquicktableview_p.h
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTABLEVIEW_P_H
+#define QQUICKTABLEVIEW_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qpointer.h>
+#include <QtQuick/private/qtquickglobal_p.h>
+#include <QtQuick/private/qquickflickable_p.h>
+#include <QtQml/private/qqmlnullablevalue_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTableViewAttached;
+class QQuickTableViewPrivate;
+class QQmlChangeSet;
+
+class Q_QUICK_PRIVATE_EXPORT QQuickTableView : public QQuickFlickable
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int rows READ rows NOTIFY rowsChanged)
+ Q_PROPERTY(int columns READ columns NOTIFY columnsChanged)
+ Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged)
+ Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged)
+ Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
+ Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
+ Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
+ Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+
+public:
+ QQuickTableView(QQuickItem *parent = nullptr);
+
+ int rows() const;
+ int columns() const;
+
+ qreal rowSpacing() const;
+ void setRowSpacing(qreal spacing);
+
+ qreal columnSpacing() const;
+ void setColumnSpacing(qreal spacing);
+
+ qreal topMargin() const;
+ void setTopMargin(qreal margin);
+
+ qreal bottomMargin() const;
+ void setBottomMargin(qreal margin);
+
+ qreal leftMargin() const;
+ void setLeftMargin(qreal margin);
+
+ qreal rightMargin() const;
+ void setRightMargin(qreal margin);
+
+ int cacheBuffer() const;
+ void setCacheBuffer(int newBuffer);
+
+ QVariant model() const;
+ void setModel(const QVariant &newModel);
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *);
+
+ static QQuickTableViewAttached *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void rowsChanged();
+ void columnsChanged();
+ void rowSpacingChanged();
+ void columnSpacingChanged();
+ void topMarginChanged();
+ void bottomMarginChanged();
+ void leftMarginChanged();
+ void rightMarginChanged();
+ void cacheBufferChanged();
+ void modelChanged();
+ void delegateChanged();
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void viewportMoved(Qt::Orientations orientation) override;
+ void componentComplete() override;
+
+private:
+ Q_DISABLE_COPY(QQuickTableView)
+ Q_DECLARE_PRIVATE(QQuickTableView)
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickTableViewAttached : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QQuickTableView *tableView READ tableView NOTIFY tableViewChanged)
+ Q_PROPERTY(qreal cellWidth READ cellWidth WRITE setCellWidth NOTIFY cellWidthChanged)
+ Q_PROPERTY(qreal cellHeight READ cellHeight WRITE setCellHeight NOTIFY cellHeightChanged)
+ Q_PROPERTY(int row READ row NOTIFY rowChanged)
+ Q_PROPERTY(int column READ column NOTIFY columnChanged)
+
+public:
+ QQuickTableViewAttached(QObject *parent)
+ : QObject(parent) {}
+
+ QQuickTableView *tableView() const { return m_tableview; }
+ void setTableView(QQuickTableView *newTableView) {
+ if (newTableView == m_tableview)
+ return;
+ m_tableview = newTableView;
+ Q_EMIT tableViewChanged();
+ }
+
+ qreal cellWidth() const { return m_cellWidth; }
+ void setCellWidth(qreal newWidth) {
+ if (newWidth == m_cellWidth)
+ return;
+ m_cellWidth = newWidth;
+ Q_EMIT cellWidthChanged();
+ }
+
+ qreal cellHeight() const { return m_cellHeight; }
+ void setCellHeight(qreal newHeight) {
+ if (newHeight == m_cellHeight)
+ return;
+ m_cellHeight = newHeight;
+ Q_EMIT cellHeightChanged();
+ }
+
+ int row() const { return m_row; }
+ void setRow(int newRow) {
+ if (newRow == m_row)
+ return;
+ m_row = newRow;
+ Q_EMIT rowChanged();
+ }
+
+ int column() const { return m_column; }
+ void setColumn(int newColumn) {
+ if (newColumn == m_column)
+ return;
+ m_column = newColumn;
+ Q_EMIT columnChanged();
+ }
+
+Q_SIGNALS:
+ void tableViewChanged();
+ void cellWidthChanged();
+ void cellHeightChanged();
+ void rowChanged();
+ void columnChanged();
+
+private:
+ QPointer<QQuickTableView> m_tableview;
+ int m_row = -1;
+ int m_column = -1;
+ QQmlNullableValue<qreal> m_cellWidth;
+ QQmlNullableValue<qreal> m_cellHeight;
+
+ friend class QQuickTableViewPrivate;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickTableView)
+QML_DECLARE_TYPEINFO(QQuickTableView, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKTABLEVIEW_P_H
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
new file mode 100644
index 0000000000..fa3cf95268
--- /dev/null
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -0,0 +1,342 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquicktableview_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtQml/private/qqmldelegatemodel_p.h>
+#include <QtQml/private/qqmlincubator_p.h>
+#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQml/qqmlinfo.h>
+
+#include <QtQuick/private/qquickflickable_p_p.h>
+#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcTableViewDelegateLifecycle)
+
+static const int kDefaultCacheBuffer = 300;
+static const qreal kDefaultRowHeight = 50;
+static const qreal kDefaultColumnWidth = 50;
+
+class FxTableItem;
+
+class Q_QML_AUTOTEST_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickTableView)
+
+public:
+ class TableEdgeLoadRequest
+ {
+ // Whenever we need to load new rows or columns in the
+ // table, we fill out a TableEdgeLoadRequest.
+ // TableEdgeLoadRequest is just a struct that keeps track
+ // of which cells that needs to be loaded, and which cell
+ // the table is currently loading. The loading itself is
+ // done by QQuickTableView.
+
+ public:
+ void begin(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
+ {
+ Q_ASSERT(!active);
+ active = true;
+ tableEdge = Qt::Edge(0);
+ tableCells = QLine(cell, cell);
+ mode = incubationMode;
+ cellCount = 1;
+ currentIndex = 0;
+ qCDebug(lcTableViewDelegateLifecycle()) << "begin top-left:" << toString();
+ }
+
+ void begin(const QLine cellsToLoad, Qt::Edge edgeToLoad, QQmlIncubator::IncubationMode incubationMode)
+ {
+ Q_ASSERT(!active);
+ active = true;
+ tableEdge = edgeToLoad;
+ tableCells = cellsToLoad;
+ mode = incubationMode;
+ cellCount = tableCells.x2() - tableCells.x1() + tableCells.y2() - tableCells.y1() + 1;
+ currentIndex = 0;
+ qCDebug(lcTableViewDelegateLifecycle()) << "begin:" << toString();
+ }
+
+ inline void markAsDone() { active = false; }
+ inline bool isActive() { return active; }
+
+ inline QPoint firstCell() { return tableCells.p1(); }
+ inline QPoint lastCell() { return tableCells.p2(); }
+ inline QPoint currentCell() { return cellAt(currentIndex); }
+ inline QPoint previousCell() { return cellAt(currentIndex - 1); }
+
+ inline bool atBeginning() { return currentIndex == 0; }
+ inline bool hasCurrentCell() { return currentIndex < cellCount; }
+ inline void moveToNextCell() { ++currentIndex; }
+
+ inline Qt::Edge edge() { return tableEdge; }
+ inline QQmlIncubator::IncubationMode incubationMode() { return mode; }
+
+ QString toString()
+ {
+ QString str;
+ QDebug dbg(&str);
+ dbg.nospace() << "TableSectionLoadRequest(" << "edge:"
+ << tableEdge << " cells:" << tableCells << " incubation:";
+
+ switch (mode) {
+ case QQmlIncubator::Asynchronous:
+ dbg << "Asynchronous";
+ break;
+ case QQmlIncubator::AsynchronousIfNested:
+ dbg << "AsynchronousIfNested";
+ break;
+ case QQmlIncubator::Synchronous:
+ dbg << "Synchronous";
+ break;
+ }
+
+ return str;
+ }
+
+ private:
+ Qt::Edge tableEdge = Qt::Edge(0);
+ QLine tableCells;
+ int currentIndex = 0;
+ int cellCount = 0;
+ bool active = false;
+ QQmlIncubator::IncubationMode mode = QQmlIncubator::AsynchronousIfNested;
+
+ QPoint cellAt(int index)
+ {
+ int x = tableCells.p1().x() + (tableCells.dx() ? index : 0);
+ int y = tableCells.p1().y() + (tableCells.dy() ? index : 0);
+ return QPoint(x, y);
+ }
+ };
+
+ struct ColumnRowSize
+ {
+ // ColumnRowSize is a helper class for storing row heights
+ // and column widths. We calculate the average width of a column
+ // the first time it's scrolled into view based on the size of
+ // the loaded items in the new column. Since we never load more items
+ // that what fits inside the viewport (cachebuffer aside), this calculation
+ // would be different depending on which row you were at when the column
+ // was scrolling in. To avoid that a column resizes when it's scrolled
+ // in and out and in again, we store its width. But to avoid storing
+ // the width for all columns, we choose to only store the width if it
+ // differs from the column(s) to the left. The same logic applies for row heights.
+ // 'index' translates to either 'row' or 'column'.
+ int index;
+ qreal size;
+
+ static bool lessThan(const ColumnRowSize& a, const ColumnRowSize& b)
+ {
+ return a.index < b.index;
+ }
+ };
+
+public:
+ QQuickTableViewPrivate();
+ ~QQuickTableViewPrivate() override;
+
+ static inline QQuickTableViewPrivate *get(QQuickTableView *q) { return q->d_func(); }
+
+ void updatePolish() override;
+
+public:
+ QList<FxTableItem *> loadedItems;
+
+ // model, delegateModel and modelVariant all points to the same model. modelVariant
+ // is the model assigned by the user. And delegateModel is the wrapper model we create
+ // around it. But if the model is an instance model directly, we cannot wrap it, so
+ // we need a pointer for that case as well.
+ QQmlInstanceModel* model = nullptr;
+ QPointer<QQmlDelegateModel> delegateModel = nullptr;
+ QVariant modelVariant;
+
+ // loadedTable describes the table cells that are currently loaded (from top left
+ // row/column to bottom right row/column). loadedTableOuterRect describes the actual
+ // pixels that those cells cover, and is matched agains the viewport to determine when
+ // we need to fill up with more rows/columns. loadedTableInnerRect describes the pixels
+ // that the loaded table covers if you remove one row/column on each side of the table, and
+ // is used to determine rows/columns that are no longer visible and can be unloaded.
+ QRect loadedTable;
+ QRectF loadedTableOuterRect;
+ QRectF loadedTableInnerRect;
+
+ QRectF viewportRect = QRectF(0, 0, -1, -1);
+
+ QSize tableSize;
+
+ TableEdgeLoadRequest loadRequest;
+
+ QPoint contentSizeBenchMarkPoint = QPoint(-1, -1);
+ QSizeF cellSpacing;
+ QMarginsF tableMargins;
+
+ int cacheBuffer = kDefaultCacheBuffer;
+ QTimer cacheBufferDelayTimer;
+ bool hasBufferedItems = false;
+
+ bool blockItemCreatedCallback = false;
+ bool tableInvalid = false;
+ bool tableRebuilding = false;
+ bool columnRowPositionsInvalid = false;
+
+ QVector<ColumnRowSize> columnWidths;
+ QVector<ColumnRowSize> rowHeights;
+
+ const static QPoint kLeft;
+ const static QPoint kRight;
+ const static QPoint kUp;
+ const static QPoint kDown;
+
+#ifdef QT_DEBUG
+ QString forcedIncubationMode = qEnvironmentVariable("QT_TABLEVIEW_INCUBATION_MODE");
+#endif
+
+public:
+ QQuickTableViewAttached *getAttachedObject(const QObject *object) const;
+
+ int modelIndexAtCell(const QPoint &cell);
+ QPoint cellAtModelIndex(int modelIndex);
+
+ void calculateColumnWidthsAfterRebuilding();
+ void calculateRowHeightsAfterRebuilding();
+ void calculateColumnWidth(int column);
+ void calculateRowHeight(int row);
+ void calculateEdgeSizeFromLoadRequest();
+ void calculateTableSize();
+
+ qreal columnWidth(int column);
+ qreal rowHeight(int row);
+
+ void relayoutTable();
+ void relayoutTableItems();
+
+ void layoutVerticalEdge(Qt::Edge tableEdge);
+ void layoutHorizontalEdge(Qt::Edge tableEdge);
+ void layoutTopLeftItem();
+ void layoutTableEdgeFromLoadRequest();
+
+ void updateContentWidth();
+ void updateContentHeight();
+
+ void enforceFirstRowColumnAtOrigo();
+ void syncLoadedTableRectFromLoadedTable();
+ void syncLoadedTableFromLoadRequest();
+
+ bool canLoadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const;
+ bool canUnloadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const;
+ Qt::Edge nextEdgeToLoad(const QRectF rect);
+ Qt::Edge nextEdgeToUnload(const QRectF rect);
+
+ qreal cellWidth(const QPoint &cell);
+ qreal cellHeight(const QPoint &cell);
+
+ FxTableItem *loadedTableItem(const QPoint &cell) const;
+ FxTableItem *itemNextTo(const FxTableItem *fxTableItem, const QPoint &direction) const;
+ FxTableItem *createFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode);
+ FxTableItem *loadFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode);
+
+ void releaseItem(FxTableItem *fxTableItem);
+ void releaseLoadedItems();
+ void clear();
+
+ void unloadItem(const QPoint &cell);
+ void unloadItems(const QLine &items);
+
+ void loadInitialTopLeftItem();
+ void loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode);
+ void unloadEdge(Qt::Edge edge);
+ void loadAndUnloadVisibleEdges();
+ void cancelLoadRequest();
+ void processLoadRequest();
+ void beginRebuildTable();
+ void endRebuildTable();
+
+ void loadBuffer();
+ void unloadBuffer();
+ QRectF bufferRect();
+
+ void invalidateTable();
+ void invalidateColumnRowPositions();
+
+ void createWrapperModel();
+
+ void initItemCallback(int modelIndex, QObject *item);
+ void itemCreatedCallback(int modelIndex, QObject *object);
+ void modelUpdated(const QQmlChangeSet &changeSet, bool reset);
+
+ inline QString tableLayoutToString() const;
+ void dumpTable() const;
+};
+
+class FxTableItem : public QQuickItemViewFxItem
+{
+public:
+ FxTableItem(QQuickItem *item, QQuickTableView *table, bool own)
+ : QQuickItemViewFxItem(item, own, QQuickTableViewPrivate::get(table))
+ {
+ }
+
+ qreal position() const override { return 0; }
+ qreal endPosition() const override { return 0; }
+ qreal size() const override { return 0; }
+ qreal sectionSize() const override { return 0; }
+ bool contains(qreal, qreal) const override { return false; }
+
+ QPoint cell;
+};
+
+Q_DECLARE_TYPEINFO(QQuickTableViewPrivate::ColumnRowSize, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 76720e5c5d..3c260165f7 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -88,6 +88,7 @@ QQuickTextPrivate::QQuickTextPrivate()
, truncated(false), hAlignImplicit(true), rightToLeftText(false)
, layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false), formatModifiesFontSize(false)
, polishSize(false)
+ , updateSizeRecursionGuard(false)
{
implicitAntialiasing = true;
}
@@ -442,6 +443,7 @@ void QQuickTextPrivate::updateSize()
//### need to confirm cost of always setting these for richText
internalWidthUpdate = true;
+ qreal oldWidth = q->width();
qreal iWidth = -1;
if (!q->widthValid())
iWidth = size.width();
@@ -449,24 +451,35 @@ void QQuickTextPrivate::updateSize()
q->setImplicitSize(iWidth + hPadding, size.height() + vPadding);
internalWidthUpdate = false;
- if (iWidth == -1)
- q->setImplicitHeight(size.height() + vPadding);
-
- QTextBlock firstBlock = extra->doc->firstBlock();
- while (firstBlock.layout()->lineCount() == 0)
- firstBlock = firstBlock.next();
-
- QTextBlock lastBlock = extra->doc->lastBlock();
- while (lastBlock.layout()->lineCount() == 0)
- lastBlock = lastBlock.previous();
-
- if (firstBlock.lineCount() > 0 && lastBlock.lineCount() > 0) {
- QTextLine firstLine = firstBlock.layout()->lineAt(0);
- QTextLine lastLine = lastBlock.layout()->lineAt(lastBlock.layout()->lineCount() - 1);
- advance = QSizeF(lastLine.horizontalAdvance(),
- (lastLine.y() + lastBlock.layout()->position().y()) - (firstLine.y() + firstBlock.layout()->position().y()));
+ // If the implicit width update caused a recursive change of the width,
+ // we will have skipped integral parts of the layout due to the
+ // internalWidthUpdate recursion guard. To make sure everything is up
+ // to date, we need to run a second pass over the layout when updateSize()
+ // is done.
+ if (!qFuzzyCompare(q->width(), oldWidth) && !updateSizeRecursionGuard) {
+ updateSizeRecursionGuard = true;
+ updateSize();
+ updateSizeRecursionGuard = false;
} else {
- advance = QSizeF();
+ if (iWidth == -1)
+ q->setImplicitHeight(size.height() + vPadding);
+
+ QTextBlock firstBlock = extra->doc->firstBlock();
+ while (firstBlock.layout()->lineCount() == 0)
+ firstBlock = firstBlock.next();
+
+ QTextBlock lastBlock = extra->doc->lastBlock();
+ while (lastBlock.layout()->lineCount() == 0)
+ lastBlock = lastBlock.previous();
+
+ if (firstBlock.lineCount() > 0 && lastBlock.lineCount() > 0) {
+ QTextLine firstLine = firstBlock.layout()->lineAt(0);
+ QTextLine lastLine = lastBlock.layout()->lineAt(lastBlock.layout()->lineCount() - 1);
+ advance = QSizeF(lastLine.horizontalAdvance(),
+ (lastLine.y() + lastBlock.layout()->position().y()) - (firstLine.y() + firstBlock.layout()->position().y()));
+ } else {
+ advance = QSizeF();
+ }
}
}
diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h
index b0b1492d57..fd26d966c8 100644
--- a/src/quick/items/qquicktext_p_p.h
+++ b/src/quick/items/qquicktext_p_p.h
@@ -174,6 +174,7 @@ public:
bool needToUpdateLayout:1;
bool formatModifiesFontSize:1;
bool polishSize:1; // Workaround for problem with polish called after updateSize (QTBUG-42636)
+ bool updateSizeRecursionGuard:1;
static const QChar elideChar;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index d9db8b56b4..c80e052dad 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -88,6 +88,8 @@ Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch")
Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target")
Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse")
Q_LOGGING_CATEGORY(DBG_MOUSE_TARGET, "qt.quick.mouse.target")
+Q_LOGGING_CATEGORY(lcWheelTarget, "qt.quick.wheel.target")
+Q_LOGGING_CATEGORY(lcGestureTarget, "qt.quick.gesture.target")
Q_LOGGING_CATEGORY(DBG_HOVER_TRACE, "qt.quick.hover.trace")
Q_LOGGING_CATEGORY(DBG_FOCUS, "qt.quick.focus")
Q_LOGGING_CATEGORY(DBG_DIRTY, "qt.quick.dirty")
@@ -256,14 +258,16 @@ void QQuickWindow::hideEvent(QHideEvent *)
void QQuickWindow::focusOutEvent(QFocusEvent *ev)
{
Q_D(QQuickWindow);
- d->contentItem->setFocus(false, ev->reason());
+ if (d->contentItem)
+ d->contentItem->setFocus(false, ev->reason());
}
/*! \reimp */
void QQuickWindow::focusInEvent(QFocusEvent *ev)
{
Q_D(QQuickWindow);
- d->contentItem->setFocus(true, ev->reason());
+ if (d->contentItem)
+ d->contentItem->setFocus(true, ev->reason());
d->updateFocusItemTransform();
}
@@ -1315,7 +1319,9 @@ QQuickWindow::~QQuickWindow()
#if QT_CONFIG(draganddrop)
delete d->dragGrabber; d->dragGrabber = nullptr;
#endif
- delete d->contentItem; d->contentItem = nullptr;
+ QQuickRootItem *root = d->contentItem;
+ d->contentItem = nullptr;
+ delete root;
qDeleteAll(d->pointerEventInstances);
d->pointerEventInstances.clear();
@@ -1571,6 +1577,8 @@ bool QQuickWindow::event(QEvent *e)
return d->deliverTouchCancelEvent(static_cast<QTouchEvent*>(e));
break;
case QEvent::Enter: {
+ if (!d->contentItem)
+ return false;
QEnterEvent *enter = static_cast<QEnterEvent*>(e);
bool accepted = enter->isAccepted();
bool delivered = d->deliverHoverEvent(d->contentItem, enter->windowPos(), d->lastMousePosition,
@@ -1592,7 +1600,8 @@ bool QQuickWindow::event(QEvent *e)
break;
#endif
case QEvent::WindowDeactivate:
- contentItem()->windowDeactivateEvent();
+ if (d->contentItem)
+ d->contentItem->windowDeactivateEvent();
break;
case QEvent::Close: {
// TOOD Qt 6 (binary incompatible)
@@ -1617,7 +1626,7 @@ bool QQuickWindow::event(QEvent *e)
}
#if QT_CONFIG(gestures)
case QEvent::NativeGesture:
- d->deliverNativeGestureEvent(d->contentItem, static_cast<QNativeGestureEvent*>(e));
+ d->deliverSinglePointEventUntilAccepted(d->pointerEventInstance(e));
break;
#endif
case QEvent::ShortcutOverride:
@@ -1886,43 +1895,57 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
return false;
}
-#if QT_CONFIG(wheelevent)
-bool QQuickWindowPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
+// Simple delivery of non-mouse, non-touch Pointer Events: visit the items and handlers
+// in the usual reverse-paint-order until propagation is stopped
+bool QQuickWindowPrivate::deliverSinglePointEventUntilAccepted(QQuickPointerEvent *event)
{
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QPointF p = item->mapFromScene(event->posF());
- if (!item->contains(p))
- return false;
- }
+ Q_ASSERT(event->pointCount() == 1);
+ QQuickEventPoint *point = event->point(0);
+ QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point->scenePosition(), false, false);
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
- continue;
- if (deliverWheelEvent(child, event))
- return true;
- }
-
- QPointF p = item->mapFromScene(event->posF());
-
- if (item->contains(p)) {
- QWheelEvent wheel(p, event->globalPosF(), event->pixelDelta(), event->angleDelta(), event->delta(),
- event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted());
- wheel.setTimestamp(event->timestamp());
- wheel.accept();
- QCoreApplication::sendEvent(item, &wheel);
- if (wheel.isAccepted()) {
- event->accept();
+ for (QQuickItem *item : targetItems) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ event->localize(item);
+ // Let Pointer Handlers have the first shot
+ itemPrivate->handlePointerEvent(event);
+ if (point->isAccepted())
return true;
+ QPointF g = item->window()->mapToGlobal(point->scenePosition().toPoint());
+#if QT_CONFIG(wheelevent)
+ // Let the Item have a chance to handle it
+ if (QQuickPointerScrollEvent *pse = event->asPointerScrollEvent()) {
+ QWheelEvent wheel(point->position(), g, pse->pixelDelta().toPoint(), pse->angleDelta().toPoint(),
+ pse->buttons(), pse->modifiers(), pse->phase(),
+ pse->isInverted(), pse->synthSource());
+ wheel.setTimestamp(pse->timestamp());
+ wheel.accept();
+ QCoreApplication::sendEvent(item, &wheel);
+ if (wheel.isAccepted()) {
+ qCDebug(lcWheelTarget) << &wheel << "->" << item;
+ event->setAccepted(true);
+ return true;
+ }
}
+#endif
+#if QT_CONFIG(gestures)
+ if (QQuickPointerNativeGestureEvent *pnge = event->asPointerNativeGestureEvent()) {
+ QNativeGestureEvent nge(pnge->type(), pnge->device()->qTouchDevice(), point->position(), point->scenePosition(), g,
+ pnge->value(), 0L, 0L); // TODO can't copy things I can't access
+ nge.accept();
+ QCoreApplication::sendEvent(item, &nge);
+ if (nge.isAccepted()) {
+ qCDebug(lcGestureTarget) << &nge << "->" << item;
+ event->setAccepted(true);
+ return true;
+ }
+ }
+#endif // gestures
}
- return false;
+ return false; // it wasn't handled
}
+#if QT_CONFIG(wheelevent)
/*! \reimp */
void QQuickWindow::wheelEvent(QWheelEvent *event)
{
@@ -1937,55 +1960,11 @@ void QQuickWindow::wheelEvent(QWheelEvent *event)
return;
event->ignore();
- d->deliverWheelEvent(d->contentItem, event);
+ d->deliverPointerEvent(d->pointerEventInstance(event));
d->lastWheelEventAccepted = event->isAccepted();
}
#endif // wheelevent
-#if QT_CONFIG(gestures)
-bool QQuickWindowPrivate::deliverNativeGestureEvent(QQuickItem *item, QNativeGestureEvent *event)
-{
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- QPointF p = item->mapFromScene(event->windowPos());
- if ((itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) && !item->contains(p))
- return false;
-
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
- continue;
- if (deliverNativeGestureEvent(child, event))
- return true;
- }
-
- // Try the Item's pointer handlers first
- QQuickPointerEvent *pointerEvent = pointerEventInstance(event);
- pointerEvent->localize(item);
- if (itemPrivate->handlePointerEvent(pointerEvent, false)) {
- if (pointerEvent->allPointsAccepted()) {
- event->accept();
- return true;
- }
- }
-
- // If still not accepted, try direct delivery to the item
- if (item->contains(p)) {
- QNativeGestureEvent copy(event->gestureType(), event->device(), p, event->windowPos(), event->screenPos(),
- event->value(), 0L, 0L); // TODO can't copy things I can't access
- event->accept();
- item->event(&copy);
- if (copy.isAccepted()) {
- event->accept();
- return true;
- }
- }
-
- return false;
-}
-#endif // gestures
-
bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event)
{
qCDebug(DBG_TOUCH) << event;
@@ -2229,6 +2208,8 @@ QQuickPointerEvent *QQuickWindowPrivate::queryPointerEventInstance(QQuickPointer
if (eventType == QEvent::NativeGesture && !qobject_cast<QQuickPointerNativeGestureEvent*>(e))
continue;
#endif
+ if (eventType == QEvent::Wheel && !qobject_cast<QQuickPointerScrollEvent*>(e))
+ continue;
// Otherwise we assume there's only one event type per device.
// More disambiguation tests might need to be added above if that changes later.
if (e->device() == device)
@@ -2248,7 +2229,10 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevic
// QWindowSystemInterface::handleMouseEvent() does not take a device parameter:
// we assume all mouse events come from one mouse (the "core pointer").
// So when the event is a mouse event, device == QQuickPointerDevice::genericMouseDevice()
- ev = new QQuickPointerMouseEvent(q, device);
+ if (eventType == QEvent::Wheel)
+ ev = new QQuickPointerScrollEvent(q, device);
+ else
+ ev = new QQuickPointerMouseEvent(q, device);
break;
case QQuickPointerDevice::TouchPad:
case QQuickPointerDevice::TouchScreen:
@@ -2282,6 +2266,7 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) con
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
+ case QEvent::Wheel:
dev = QQuickPointerDevice::genericMouseDevice();
break;
case QEvent::TouchBegin:
@@ -2324,7 +2309,7 @@ void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event)
} else if (event->asPointerTouchEvent()) {
deliverTouchEvent(event->asPointerTouchEvent());
} else {
- Q_ASSERT(false);
+ deliverSinglePointEventUntilAccepted(event);
}
event->reset(nullptr);
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index b5e3a2c1eb..eb2f4d20fa 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -152,12 +152,7 @@ public:
bool sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent);
bool sendFilteredPointerEvent(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent = nullptr);
bool sendFilteredPointerEventImpl(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent);
-#if QT_CONFIG(wheelevent)
- bool deliverWheelEvent(QQuickItem *, QWheelEvent *);
-#endif
-#if QT_CONFIG(gestures)
- bool deliverNativeGestureEvent(QQuickItem *, QNativeGestureEvent *);
-#endif
+ bool deliverSinglePointEventUntilAccepted(QQuickPointerEvent *);
// entry point of events to the window
void handleTouchEvent(QTouchEvent *);
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
index d715d900ba..2e5fdbbe6b 100644
--- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
@@ -77,6 +77,11 @@ QSGSoftwareRenderableNode *QSGAbstractSoftwareRenderer::renderableNode(QSGNode *
return m_nodes.value(node, nullptr);
}
+const QLinkedList<QSGSoftwareRenderableNode*> &QSGAbstractSoftwareRenderer::renderableNodes() const
+{
+ return m_renderableNodes;
+}
+
void QSGAbstractSoftwareRenderer::addNodeMapping(QSGNode *node, QSGSoftwareRenderableNode *renderableNode)
{
m_nodes.insert(node, renderableNode);
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
index f6594d931a..99204ef25e 100644
--- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
@@ -88,6 +88,7 @@ protected:
QRect backgroundRect();
// only known after calling optimizeRenderList()
bool isOpaque() const { return m_isOpaque; }
+ const QLinkedList<QSGSoftwareRenderableNode*> &renderableNodes() const;
private:
void nodeAdded(QSGNode *node);
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp
index bf3141bc32..2c361e03e2 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp
@@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE
QSGSoftwareInternalRectangleNode::QSGSoftwareInternalRectangleNode()
: m_penWidth(0)
, m_radius(0)
+ , m_vertical(true)
, m_cornerPixmapIsDirty(true)
, m_devicePixelRatio(1)
{
@@ -186,6 +187,15 @@ void QSGSoftwareInternalRectangleNode::setGradientStops(const QGradientStops &st
markDirty(DirtyMaterial);
}
+void QSGSoftwareInternalRectangleNode::setGradientVertical(bool vertical)
+{
+ if (m_vertical != vertical) {
+ m_vertical = vertical;
+ m_cornerPixmapIsDirty = true;
+ markDirty(DirtyMaterial);
+ }
+}
+
void QSGSoftwareInternalRectangleNode::setRadius(qreal radius)
{
if (m_radius != radius) {
@@ -209,7 +219,7 @@ void QSGSoftwareInternalRectangleNode::update()
}
if (!m_stops.isEmpty()) {
- QLinearGradient gradient(QPoint(0,0), QPoint(0,1));
+ QLinearGradient gradient(QPoint(0,0), QPoint(m_vertical ? 0 : 1, m_vertical ? 1 : 0));
gradient.setStops(m_stops);
gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
m_brush = QBrush(gradient);
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h
index 1f87424d2a..125520de26 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h
@@ -69,6 +69,7 @@ public:
void setPenColor(const QColor &color) override;
void setPenWidth(qreal width) override;
void setGradientStops(const QGradientStops &stops) override;
+ void setGradientVertical(bool vertical) override;
void setRadius(qreal radius) override;
void setAntialiasing(bool antialiasing) override { Q_UNUSED(antialiasing) }
void setAligned(bool aligned) override;
@@ -91,6 +92,7 @@ private:
double m_radius;
QPen m_pen;
QBrush m_brush;
+ bool m_vertical;
bool m_cornerPixmapIsDirty;
QPixmap m_cornerPixmap;
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h
index 8fc87db179..b20d0a1828 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h
@@ -72,7 +72,7 @@ class QSGSoftwareNinePatchNode;
class QSGSoftwareSpriteNode;
class QSGRenderNode;
-class QSGSoftwareRenderableNode
+class Q_QUICK_PRIVATE_EXPORT QSGSoftwareRenderableNode
{
public:
enum NodeType {
@@ -104,6 +104,7 @@ public:
bool isOpaque() const { return m_isOpaque; }
bool isDirty() const { return m_isDirty; }
bool isDirtyRegionEmpty() const;
+ QSGNode *handle() const { return m_handle.node; }
void setTransform(const QTransform &transform);
void setClipRegion(const QRegion &clipRegion, bool hasClipRegion = true);
@@ -123,6 +124,7 @@ public:
private:
union RenderableNodeHandle {
+ QSGNode *node;
QSGSimpleRectNode *simpleRectNode;
QSGSimpleTextureNode *simpleTextureNode;
QSGSoftwareInternalImageNode *imageNode;
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 9c88b8272c..c23163a6b3 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -136,6 +136,7 @@ public:
virtual void setPenColor(const QColor &color) = 0;
virtual void setPenWidth(qreal width) = 0;
virtual void setGradientStops(const QGradientStops &stops) = 0;
+ virtual void setGradientVertical(bool vertical) = 0;
virtual void setRadius(qreal radius) = 0;
virtual void setAntialiasing(bool antialiasing) { Q_UNUSED(antialiasing) }
virtual void setAligned(bool aligned) = 0;
diff --git a/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp b/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp
index df124cce35..91317ee2d7 100644
--- a/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp
@@ -68,19 +68,30 @@ namespace
{
float x, y;
Color4ub color;
- void set(float nx, float ny, Color4ub ncolor)
+
+ void set(float primary, float secondary, Color4ub ncolor, bool vertical)
{
- x = nx; y = ny; color = ncolor;
+ if (vertical) {
+ x = secondary; y = primary;
+ } else {
+ x = primary; y = secondary;
+ }
+ color = ncolor;
}
};
struct SmoothVertex : public Vertex
{
float dx, dy;
- void set(float nx, float ny, Color4ub ncolor, float ndx, float ndy)
+
+ void set(float primary, float secondary, Color4ub ncolor, float dPrimary, float dSecondary, bool vertical)
{
- Vertex::set(nx, ny, ncolor);
- dx = ndx; dy = ndy;
+ Vertex::set(primary, secondary, ncolor, vertical);
+ if (vertical) {
+ dx = dSecondary; dy = dPrimary;
+ } else {
+ dx = dPrimary; dy = dSecondary;
+ }
}
};
@@ -103,6 +114,7 @@ QSGBasicInternalRectangleNode::QSGBasicInternalRectangleNode()
, m_antialiasing(false)
, m_gradient_is_opaque(true)
, m_dirty_geometry(false)
+ , m_gradient_is_vertical(true)
, m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0)
{
setGeometry(&m_geometry);
@@ -160,6 +172,15 @@ void QSGBasicInternalRectangleNode::setGradientStops(const QGradientStops &stops
m_dirty_geometry = true;
}
+void QSGBasicInternalRectangleNode::setGradientVertical(bool vertical)
+{
+ if (vertical == m_gradient_is_vertical)
+ return;
+ m_gradient_is_vertical = vertical;
+ m_dirty_geometry = true;
+}
+
+
void QSGBasicInternalRectangleNode::setRadius(qreal radius)
{
if (radius == m_radius)
@@ -230,12 +251,15 @@ void QSGBasicInternalRectangleNode::updateGeometry()
Color4ub transparent = { 0, 0, 0, 0 };
const QGradientStops &stops = m_gradient_stops;
+ float length = (m_gradient_is_vertical ? height : width);
+ float secondaryLength = (m_gradient_is_vertical ? width : height);
+
int nextGradientStop = 0;
- float gradientPos = penWidth / height;
+ float gradientPos = penWidth / length;
while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
++nextGradientStop;
int lastGradientStop = stops.size() - 1;
- float lastGradientPos = 1.0f - penWidth / height;
+ float lastGradientPos = 1.0f - penWidth / length;
while (lastGradientStop >= nextGradientStop && stops.at(lastGradientStop).first >= lastGradientPos)
--lastGradientStop;
int gradientIntersections = (lastGradientStop - nextGradientStop + 1);
@@ -319,40 +343,46 @@ void QSGBasicInternalRectangleNode::updateGeometry()
quint16 *indices = g->indexDataAsUShort();
quint16 index = 0;
- float py = 0; // previous inner y-coordinate.
- float plx = 0; // previous inner left x-coordinate.
- float prx = 0; // previous inner right x-coordinate.
+ float pp = 0; // previous inner primary coordinate.
+ float pss = 0; // previous inner secondary start coordinate.
+ float pse = 0; // previous inner secondary end coordinate.
float angle = 0.5f * float(M_PI) / segments;
float cosStep = qFastCos(angle);
float sinStep = qFastSin(angle);
+ float innerStart = (m_gradient_is_vertical ? innerRect.top() : innerRect.left());
+ float innerEnd = (m_gradient_is_vertical ? innerRect.bottom() : innerRect.right());
+ float innerLength = (m_gradient_is_vertical ? innerRect.height() : innerRect.width());
+ float innerSecondaryStart = (m_gradient_is_vertical ? innerRect.left() : innerRect.top());
+ float innerSecondaryEnd = (m_gradient_is_vertical ? innerRect.right() : innerRect.bottom());
+
for (int part = 0; part < 2; ++part) {
float c = 1 - part;
float s = part;
for (int i = 0; i <= segments; ++i) {
- float y, lx, rx;
+ float p, ss, se;
if (innerRadius > 0) {
- y = (part ? innerRect.bottom() : innerRect.top()) - innerRadius * c; // current inner y-coordinate.
- lx = innerRect.left() - innerRadius * s; // current inner left x-coordinate.
- rx = innerRect.right() + innerRadius * s; // current inner right x-coordinate.
- gradientPos = ((part ? innerRect.height() : 0) + radius - innerRadius * c) / height;
+ p = (part ? innerEnd : innerStart) - innerRadius * c; // current inner primary coordinate.
+ ss = innerSecondaryStart - innerRadius * s; // current inner secondary start coordinate.
+ se = innerSecondaryEnd + innerRadius * s; // current inner secondary end coordinate.
+ gradientPos = ((part ? innerLength : 0) + radius - innerRadius * c) / length;
} else {
- y = (part ? innerRect.bottom() + innerRadius : innerRect.top() - innerRadius); // current inner y-coordinate.
- lx = innerRect.left() - innerRadius; // current inner left x-coordinate.
- rx = innerRect.right() + innerRadius; // current inner right x-coordinate.
- gradientPos = ((part ? innerRect.height() + innerRadius : -innerRadius) + radius) / height;
+ p = (part ? innerEnd + innerRadius : innerStart - innerRadius); // current inner primary coordinate.
+ ss = innerSecondaryStart - innerRadius; // current inner secondary start coordinate.
+ se = innerSecondaryEnd + innerRadius; // current inner secondary end coordinate.
+ gradientPos = ((part ? innerLength + innerRadius : -innerRadius) + radius) / length;
}
- float Y = (part ? innerRect.bottom() : innerRect.top()) - outerRadius * c; // current outer y-coordinate.
- float lX = innerRect.left() - outerRadius * s; // current outer left x-coordinate.
- float rX = innerRect.right() + outerRadius * s; // current outer right x-coordinate.
+ float outerEdge = (part ? innerEnd : innerStart) - outerRadius * c; // current outer primary coordinate.
+ float outerSecondaryStart = innerSecondaryStart - outerRadius * s; // current outer secondary start coordinate.
+ float outerSecondaryEnd = innerSecondaryEnd + outerRadius * s; // current outer secondary end coordinate.
while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
// Insert vertices at gradient stops.
- float gy = (innerRect.top() - radius) + stops.at(nextGradientStop).first * height;
- float t = (gy - py) / (y - py);
- float glx = plx * (1 - t) + t * lx;
- float grx = prx * (1 - t) + t * rx;
+ float gp = (innerStart - radius) + stops.at(nextGradientStop).first * length;
+ float t = (gp - pp) / (p - pp);
+ float gis = pss * (1 - t) + t * ss; // gradient inner start
+ float gie = pse * (1 - t) + t * se; // gradient inner end
fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
@@ -377,23 +407,23 @@ void QSGBasicInternalRectangleNode::updateGeometry()
indices[innerAATail++] = index + 3;
bool lower = stops.at(nextGradientStop).first > 0.5f;
- float dy = lower ? qMin(0.0f, height - gy - delta) : qMax(0.0f, delta - gy);
- smoothVertices[index++].set(grx, gy, fillColor, width - grx - delta, dy);
- smoothVertices[index++].set(glx, gy, fillColor, delta - glx, dy);
+ float dp = lower ? qMin(0.0f, length - gp - delta) : qMax(0.0f, delta - gp);
+ smoothVertices[index++].set(gp, gie, fillColor, dp, secondaryLength - gie - delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, gis, fillColor, dp, delta - gis, m_gradient_is_vertical);
if (penWidth) {
- smoothVertices[index++].set(grx, gy, borderColor, 0.49f * penWidth * s, -0.49f * penWidth * c);
- smoothVertices[index++].set(glx, gy, borderColor, -0.49f * penWidth * s, -0.49f * penWidth * c);
+ smoothVertices[index++].set(gp, gie, borderColor, -0.49f * penWidth * c, 0.49f * penWidth * s, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, gis, borderColor, -0.49f * penWidth * c, -0.49f * penWidth * s, m_gradient_is_vertical);
} else {
- dy = lower ? delta : -delta;
- smoothVertices[index++].set(grx, gy, transparent, delta, dy);
- smoothVertices[index++].set(glx, gy, transparent, -delta, dy);
+ dp = lower ? delta : -delta;
+ smoothVertices[index++].set(gp, gie, transparent, dp, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, gis, transparent, dp, -delta, m_gradient_is_vertical);
}
} else {
- vertices[index++].set(grx, gy, fillColor);
- vertices[index++].set(glx, gy, fillColor);
+ vertices[index++].set(gp, gie, fillColor, m_gradient_is_vertical);
+ vertices[index++].set(gp, gis, fillColor, m_gradient_is_vertical);
if (penWidth) {
- vertices[index++].set(grx, gy, borderColor);
- vertices[index++].set(glx, gy, borderColor);
+ vertices[index++].set(gp, gie, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(gp, gis, borderColor, m_gradient_is_vertical);
}
}
++nextGradientStop;
@@ -430,41 +460,41 @@ void QSGBasicInternalRectangleNode::updateGeometry()
indices[innerAATail++] = index + 1;
indices[innerAATail++] = index + 3;
- float dy = part ? qMin(0.0f, height - y - delta) : qMax(0.0f, delta - y);
- smoothVertices[index++].set(rx, y, fillColor, width - rx - delta, dy);
- smoothVertices[index++].set(lx, y, fillColor, delta - lx, dy);
+ float dp = part ? qMin(0.0f, length - p - delta) : qMax(0.0f, delta - p);
+ smoothVertices[index++].set(p, se, fillColor, dp, secondaryLength - se - delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(p, ss, fillColor, dp, delta - ss, m_gradient_is_vertical);
- dy = part ? delta : -delta;
+ dp = part ? delta : -delta;
if (penWidth) {
- smoothVertices[index++].set(rx, y, borderColor, 0.49f * penWidth * s, -0.49f * penWidth * c);
- smoothVertices[index++].set(lx, y, borderColor, -0.49f * penWidth * s, -0.49f * penWidth * c);
- smoothVertices[index++].set(rX, Y, borderColor, -0.49f * penWidth * s, 0.49f * penWidth * c);
- smoothVertices[index++].set(lX, Y, borderColor, 0.49f * penWidth * s, 0.49f * penWidth * c);
- smoothVertices[index++].set(rX, Y, transparent, delta, dy);
- smoothVertices[index++].set(lX, Y, transparent, -delta, dy);
+ smoothVertices[index++].set(p, se, borderColor, -0.49f * penWidth * c, 0.49f * penWidth * s, m_gradient_is_vertical);
+ smoothVertices[index++].set(p, ss, borderColor, -0.49f * penWidth * c, -0.49f * penWidth * s, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, 0.49f * penWidth * c, -0.49f * penWidth * s, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryStart, borderColor, 0.49f * penWidth * c, 0.49f * penWidth * s, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryEnd, transparent, dp, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryStart, transparent, dp, -delta, m_gradient_is_vertical);
indices[--outerAAHead] = index - 2;
indices[--outerAAHead] = index - 4;
indices[outerAATail++] = index - 3;
indices[outerAATail++] = index - 1;
} else {
- smoothVertices[index++].set(rx, y, transparent, delta, dy);
- smoothVertices[index++].set(lx, y, transparent, -delta, dy);
+ smoothVertices[index++].set(p, se, transparent, dp, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(p, ss, transparent, dp, -delta, m_gradient_is_vertical);
}
} else {
- vertices[index++].set(rx, y, fillColor);
- vertices[index++].set(lx, y, fillColor);
+ vertices[index++].set(p, se, fillColor, m_gradient_is_vertical);
+ vertices[index++].set(p, ss, fillColor, m_gradient_is_vertical);
if (penWidth) {
- vertices[index++].set(rx, y, borderColor);
- vertices[index++].set(lx, y, borderColor);
- vertices[index++].set(rX, Y, borderColor);
- vertices[index++].set(lX, Y, borderColor);
+ vertices[index++].set(p, se, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(p, ss, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(outerEdge, outerSecondaryStart, borderColor, m_gradient_is_vertical);
}
}
- py = y;
- plx = lx;
- prx = rx;
+ pp = p;
+ pss = ss;
+ pse = se;
// Rotate
qreal tmp = c;
@@ -543,19 +573,24 @@ void QSGBasicInternalRectangleNode::updateGeometry()
quint16 *indices = g->indexDataAsUShort();
quint16 index = 0;
- float lx = innerRect.left();
- float rx = innerRect.right();
- float lX = outerRect.left();
- float rX = outerRect.right();
+ float innerStart = (m_gradient_is_vertical ? innerRect.top() : innerRect.left());
+ float innerEnd = (m_gradient_is_vertical ? innerRect.bottom() : innerRect.right());
+ float outerStart = (m_gradient_is_vertical ? outerRect.top() : outerRect.left());
+ float outerEnd = (m_gradient_is_vertical ? outerRect.bottom() : outerRect.right());
+
+ float innerSecondaryStart = (m_gradient_is_vertical ? innerRect.left() : innerRect.top());
+ float innerSecondaryEnd = (m_gradient_is_vertical ? innerRect.right() : innerRect.bottom());
+ float outerSecondaryStart = (m_gradient_is_vertical ? outerRect.left() : outerRect.top());
+ float outerSecondaryEnd = (m_gradient_is_vertical ? outerRect.right() : outerRect.bottom());
for (int part = -1; part <= 1; part += 2) {
- float y = (part == 1 ? innerRect.bottom() : innerRect.top());
- float Y = (part == 1 ? outerRect.bottom() : outerRect.top());
- gradientPos = (y - innerRect.top() + penWidth) / height;
+ float innerEdge = (part == 1 ? innerEnd : innerStart);
+ float outerEdge = (part == 1 ? outerEnd : outerStart);
+ gradientPos = (innerEdge - innerStart + penWidth) / length;
while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
// Insert vertices at gradient stops.
- float gy = (innerRect.top() - penWidth) + stops.at(nextGradientStop).first * height;
+ float gp = (innerStart - penWidth) + stops.at(nextGradientStop).first * length;
fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
@@ -580,22 +615,22 @@ void QSGBasicInternalRectangleNode::updateGeometry()
indices[innerAATail++] = index + 3;
bool lower = stops.at(nextGradientStop).first > 0.5f;
- float dy = lower ? qMin(0.0f, height - gy - delta) : qMax(0.0f, delta - gy);
- smoothVertices[index++].set(rx, gy, fillColor, width - rx - delta, dy);
- smoothVertices[index++].set(lx, gy, fillColor, delta - lx, dy);
+ float dp = lower ? qMin(0.0f, length - gp - delta) : qMax(0.0f, delta - gp);
+ smoothVertices[index++].set(gp, innerSecondaryEnd, fillColor, dp, secondaryLength - innerSecondaryEnd - delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, innerSecondaryStart, fillColor, dp, delta - innerSecondaryStart, m_gradient_is_vertical);
if (penWidth) {
- smoothVertices[index++].set(rx, gy, borderColor, 0.49f * penWidth, (lower ? 0.49f : -0.49f) * penWidth);
- smoothVertices[index++].set(lx, gy, borderColor, -0.49f * penWidth, (lower ? 0.49f : -0.49f) * penWidth);
+ smoothVertices[index++].set(gp, innerSecondaryEnd, borderColor, (lower ? 0.49f : -0.49f) * penWidth, 0.49f * penWidth, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, innerSecondaryStart, borderColor, (lower ? 0.49f : -0.49f) * penWidth, -0.49f * penWidth, m_gradient_is_vertical);
} else {
- smoothVertices[index++].set(rx, gy, transparent, delta, lower ? delta : -delta);
- smoothVertices[index++].set(lx, gy, transparent, -delta, lower ? delta : -delta);
+ smoothVertices[index++].set(gp, innerSecondaryEnd, transparent, lower ? delta : -delta, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, innerSecondaryStart, transparent, lower ? delta : -delta, -delta, m_gradient_is_vertical);
}
} else {
- vertices[index++].set(rx, gy, fillColor);
- vertices[index++].set(lx, gy, fillColor);
+ vertices[index++].set(gp, innerSecondaryEnd, fillColor, m_gradient_is_vertical);
+ vertices[index++].set(gp, innerSecondaryStart, fillColor, m_gradient_is_vertical);
if (penWidth) {
- vertices[index++].set(rx, gy, borderColor);
- vertices[index++].set(lx, gy, borderColor);
+ vertices[index++].set(gp, innerSecondaryEnd, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(gp, innerSecondaryStart, borderColor, m_gradient_is_vertical);
}
}
++nextGradientStop;
@@ -632,34 +667,34 @@ void QSGBasicInternalRectangleNode::updateGeometry()
indices[innerAATail++] = index + 1;
indices[innerAATail++] = index + 3;
- float dy = part == 1 ? qMin(0.0f, height - y - delta) : qMax(0.0f, delta - y);
- smoothVertices[index++].set(rx, y, fillColor, width - rx - delta, dy);
- smoothVertices[index++].set(lx, y, fillColor, delta - lx, dy);
+ float dp = part == 1 ? qMin(0.0f, length - innerEdge - delta) : qMax(0.0f, delta - innerEdge);
+ smoothVertices[index++].set(innerEdge, innerSecondaryEnd, fillColor, dp, secondaryLength - innerSecondaryEnd - delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(innerEdge, innerSecondaryStart, fillColor, dp, delta - innerSecondaryStart, m_gradient_is_vertical);
if (penWidth) {
- smoothVertices[index++].set(rx, y, borderColor, 0.49f * penWidth, 0.49f * penWidth * part);
- smoothVertices[index++].set(lx, y, borderColor, -0.49f * penWidth, 0.49f * penWidth * part);
- smoothVertices[index++].set(rX, Y, borderColor, -0.49f * penWidth, -0.49f * penWidth * part);
- smoothVertices[index++].set(lX, Y, borderColor, 0.49f * penWidth, -0.49f * penWidth * part);
- smoothVertices[index++].set(rX, Y, transparent, delta, delta * part);
- smoothVertices[index++].set(lX, Y, transparent, -delta, delta * part);
+ smoothVertices[index++].set(innerEdge, innerSecondaryEnd, borderColor, 0.49f * penWidth * part, 0.49f * penWidth, m_gradient_is_vertical);
+ smoothVertices[index++].set(innerEdge, innerSecondaryStart, borderColor, 0.49f * penWidth * part, -0.49f * penWidth, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, -0.49f * penWidth * part, -0.49f * penWidth, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryStart, borderColor, -0.49f * penWidth * part, 0.49f * penWidth, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryEnd, transparent, delta * part, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryStart, transparent, delta * part, -delta, m_gradient_is_vertical);
indices[--outerAAHead] = index - 2;
indices[--outerAAHead] = index - 4;
indices[outerAATail++] = index - 3;
indices[outerAATail++] = index - 1;
} else {
- smoothVertices[index++].set(rx, y, transparent, delta, delta * part);
- smoothVertices[index++].set(lx, y, transparent, -delta, delta * part);
+ smoothVertices[index++].set(innerEdge, innerSecondaryEnd, transparent, delta * part, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(innerEdge, innerSecondaryStart, transparent, delta * part, -delta, m_gradient_is_vertical);
}
} else {
- vertices[index++].set(rx, y, fillColor);
- vertices[index++].set(lx, y, fillColor);
+ vertices[index++].set(innerEdge, innerSecondaryEnd, fillColor, m_gradient_is_vertical);
+ vertices[index++].set(innerEdge, innerSecondaryStart, fillColor, m_gradient_is_vertical);
if (penWidth) {
- vertices[index++].set(rx, y, borderColor);
- vertices[index++].set(lx, y, borderColor);
- vertices[index++].set(rX, Y, borderColor);
- vertices[index++].set(lX, Y, borderColor);
+ vertices[index++].set(innerEdge, innerSecondaryEnd, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(innerEdge, innerSecondaryStart, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(outerEdge, outerSecondaryStart, borderColor, m_gradient_is_vertical);
}
}
}
diff --git a/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h b/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h
index 98e53669ce..99f26b9aed 100644
--- a/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h
+++ b/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h
@@ -66,6 +66,7 @@ public:
void setPenColor(const QColor &color) override;
void setPenWidth(qreal width) override;
void setGradientStops(const QGradientStops &stops) override;
+ void setGradientVertical(bool vertical) override;
void setRadius(qreal radius) override;
void setAntialiasing(bool antialiasing) override;
void setAligned(bool aligned) override;
@@ -90,6 +91,7 @@ protected:
uint m_antialiasing : 1;
uint m_gradient_is_opaque : 1;
uint m_dirty_geometry : 1;
+ uint m_gradient_is_vertical : 1;
QSGGeometry m_geometry;
};
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index 9ee1a323e5..02be9daac0 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -234,6 +234,27 @@ QQmlProperty QQuickAbstractAnimationPrivate::createProperty(QObject *obj, const
The corresponding handler is \c onStopped.
*/
+/*!
+ \qmlsignal QtQuick::Animation::finished()
+ \since 5.12
+
+ This signal is emitted when the animation has finished naturally.
+
+ It is not emitted when \l running is set to \c false, nor for animations whose
+ \l loops property is set to \c Animation.Infinite.
+
+ In addition, it is only emitted for top-level, standalone animations. It
+ will not be emitted for animations in a Behavior or Transition, or
+ animations that are part of an animation group.
+
+ If \l alwaysRunToEnd is true, this signal will not be emitted until the
+ animation has completed its current iteration.
+
+ The corresponding handler is \c onFinished.
+
+ \sa stopped(), started(), running
+*/
+
void QQuickAbstractAnimation::setRunning(bool r)
{
Q_D(QQuickAbstractAnimation);
@@ -656,6 +677,7 @@ void QQuickAbstractAnimationPrivate::animationFinished(QAbstractAnimationJob*)
if (loopCount != 1)
animationInstance->setLoopCount(loopCount);
}
+ emit q->finished();
}
QQuickAbstractAnimation::ThreadingModel QQuickAbstractAnimation::threadingModel() const
diff --git a/src/quick/util/qquickanimation_p.h b/src/quick/util/qquickanimation_p.h
index 2293f2597f..746cb938bd 100644
--- a/src/quick/util/qquickanimation_p.h
+++ b/src/quick/util/qquickanimation_p.h
@@ -126,6 +126,7 @@ Q_SIGNALS:
void pausedChanged(bool);
void alwaysRunToEndChanged(bool);
void loopCountChanged(int);
+ Q_REVISION(12) void finished();
public Q_SLOTS:
void restart();
diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp
index f7c8724318..5d7664433b 100644
--- a/src/quick/util/qquickimageprovider.cpp
+++ b/src/quick/util/qquickimageprovider.cpp
@@ -39,8 +39,10 @@
#include "qquickimageprovider.h"
+#include "qquickimageprovider_p.h"
#include "qquickpixmapcache_p.h"
#include <QtQuick/private/qsgcontext_p.h>
+#include <private/qqmlglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -160,7 +162,10 @@ QQuickTextureFactory *QQuickTextureFactory::textureFactoryForImage(const QImage
Constructs the image response
*/
QQuickImageResponse::QQuickImageResponse()
+ : QObject(*(new QQuickImageResponsePrivate))
{
+ qmlobject_connect(this, QQuickImageResponse, SIGNAL(finished()),
+ this, QQuickImageResponse, SLOT(_q_finished()));
}
/*!
diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h
index 4f8193789a..82d0501697 100644
--- a/src/quick/util/qquickimageprovider.h
+++ b/src/quick/util/qquickimageprovider.h
@@ -69,6 +69,8 @@ public:
static QQuickTextureFactory *textureFactoryForImage(const QImage &image);
};
+class QQuickImageResponsePrivate;
+
class Q_QUICK_EXPORT QQuickImageResponse : public QObject
{
Q_OBJECT
@@ -84,6 +86,10 @@ public Q_SLOTS:
Q_SIGNALS:
void finished();
+
+private:
+ Q_DECLARE_PRIVATE(QQuickImageResponse)
+ Q_PRIVATE_SLOT(d_func(), void _q_finished())
};
class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase
diff --git a/src/quick/util/qquickimageprovider_p.h b/src/quick/util/qquickimageprovider_p.h
new file mode 100644
index 0000000000..b5baf79319
--- /dev/null
+++ b/src/quick/util/qquickimageprovider_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKQQUICKIMAGEPROVIDER_P_H
+#define QQUICKQQUICKIMAGEPROVIDER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtquickglobal_p.h>
+#include <private/qobject_p.h>
+#include <qquickimageprovider.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickImageResponsePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickImageResponse)
+public:
+ bool finished = false;
+
+ void _q_finished() { finished = true; }
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QQUICKQQUICKIMAGEPROVIDER_P_H
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 4237ec3edf..0dd2a88ca1 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -39,6 +39,7 @@
#include "qquickpixmapcache_p.h"
#include <qquickimageprovider.h>
+#include "qquickimageprovider_p.h"
#include <qqmlengine.h>
#include <private/qqmlglobal_p.h>
@@ -179,6 +180,8 @@ public:
QQuickPixmapReaderThreadObject(QQuickPixmapReader *);
void processJobs();
bool event(QEvent *e) override;
+public slots:
+ void asyncResponseFinished(QQuickImageResponse *response);
private slots:
void networkRequestDone();
void asyncResponseFinished();
@@ -613,10 +616,15 @@ void QQuickPixmapReaderThreadObject::networkRequestDone()
#endif
}
+void QQuickPixmapReaderThreadObject::asyncResponseFinished(QQuickImageResponse *response)
+{
+ reader->asyncResponseFinished(response);
+}
+
void QQuickPixmapReaderThreadObject::asyncResponseFinished()
{
QQuickImageResponse *response = static_cast<QQuickImageResponse *>(sender());
- reader->asyncResponseFinished(response);
+ asyncResponseFinished(response);
}
void QQuickPixmapReader::processJobs()
@@ -800,7 +808,14 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
response = asyncProvider->requestImageResponse(imageId(url), runningJob->requestSize);
}
- QObject::connect(response, SIGNAL(finished()), threadObject, SLOT(asyncResponseFinished()));
+ // Might be that the async provider was so quick it emitted the signal before we
+ // could connect to it.
+ if (static_cast<QQuickImageResponsePrivate*>(QObjectPrivate::get(response))->finished) {
+ QMetaObject::invokeMethod(threadObject, "asyncResponseFinished",
+ Qt::QueuedConnection, Q_ARG(QQuickImageResponse*, response));
+ } else {
+ QObject::connect(response, SIGNAL(finished()), threadObject, SLOT(asyncResponseFinished()));
+ }
asyncResponses.insert(response, runningJob);
break;
diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp
index bd9f04e562..decc6eac31 100644
--- a/src/quick/util/qquickprofiler.cpp
+++ b/src/quick/util/qquickprofiler.cpp
@@ -116,9 +116,8 @@ void QQuickProfiler::stopProfilingImpl()
m_data.clear();
}
-void QQuickProfiler::reportDataImpl(bool trackLocations)
+void QQuickProfiler::reportDataImpl()
{
- Q_UNUSED(trackLocations);
QMutexLocker lock(&m_dataMutex);
emit dataReady(m_data);
m_data.clear();
diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h
index d699ddf371..28b058c2e8 100644
--- a/src/quick/util/qquickprofiler_p.h
+++ b/src/quick/util/qquickprofiler_p.h
@@ -357,7 +357,7 @@ protected:
void startProfilingImpl(quint64 features);
void stopProfilingImpl();
- void reportDataImpl(bool trackLocations);
+ void reportDataImpl();
void setTimer(const QElapsedTimer &t);
};
diff --git a/src/quick/util/qquickstate.cpp b/src/quick/util/qquickstate.cpp
index b953ad1c7f..3ca6440784 100644
--- a/src/quick/util/qquickstate.cpp
+++ b/src/quick/util/qquickstate.cpp
@@ -222,7 +222,7 @@ bool QQuickState::isWhenKnown() const
QQmlBinding *QQuickState::when() const
{
Q_D(const QQuickState);
- return d->when;
+ return d->when.data();
}
void QQuickState::setWhen(QQmlBinding *when)
diff --git a/src/quick/util/qquickstate_p_p.h b/src/quick/util/qquickstate_p_p.h
index f1bc24c558..61472b4d06 100644
--- a/src/quick/util/qquickstate_p_p.h
+++ b/src/quick/util/qquickstate_p_p.h
@@ -203,12 +203,12 @@ class QQuickStatePrivate : public QObjectPrivate
public:
QQuickStatePrivate()
- : when(nullptr), named(false), inState(false), group(nullptr) {}
+ : named(false), inState(false), group(nullptr) {}
typedef QList<QQuickSimpleAction> SimpleActionList;
QString name;
- QQmlBinding *when;
+ QQmlBinding::Ptr when;
bool named;
struct OperationGuard : public QQmlGuard<QQuickStateOperation>
diff --git a/src/quick/util/qquicksvgparser.cpp b/src/quick/util/qquicksvgparser.cpp
index 2bf9c121d3..0687913565 100644
--- a/src/quick/util/qquicksvgparser.cpp
+++ b/src/quick/util/qquicksvgparser.cpp
@@ -280,11 +280,8 @@ bool QQuickSvgParser::parsePathDataFast(const QString &dataStr, QPainterPath &pa
++str;
QChar pathElem = *str;
++str;
- QChar endc = *end;
- *const_cast<QChar *>(end) = 0; // parseNumbersArray requires 0-termination that QStringRef cannot guarantee
QVarLengthArray<qreal, 8> arg;
parseNumbersArray(str, arg);
- *const_cast<QChar *>(end) = endc;
if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z'))
arg.append(0);//dummy
const qreal *num = arg.constData();
diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp
index b2e5b84cf4..31d4d4c437 100644
--- a/src/quick/util/qquickutilmodule.cpp
+++ b/src/quick/util/qquickutilmodule.cpp
@@ -132,4 +132,7 @@ void QQuickUtilModule::defineModule()
qmlRegisterType<QQuickShortcut,9>("QtQuick", 2, 9, "Shortcut");
#endif
+
+ qmlRegisterUncreatableType<QQuickAbstractAnimation, 12>("QtQuick", 2, 12, "Animation",
+ QQuickAbstractAnimation::tr("Animation is an abstract class"));
}
diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri
index edcb268cd9..c51f082d03 100644
--- a/src/quick/util/util.pri
+++ b/src/quick/util/util.pri
@@ -53,6 +53,7 @@ HEADERS += \
$$PWD/qquickfontloader_p.h \
$$PWD/qquickstyledtext_p.h \
$$PWD/qquickimageprovider.h \
+ $$PWD/qquickimageprovider_p.h \
$$PWD/qquicksvgparser_p.h \
$$PWD/qquickvaluetypes_p.h \
$$PWD/qquickanimator_p.h \