aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2017-10-30 15:17:25 +0100
committerJ-P Nurmi <jpnurmi@qt.io>2017-11-02 08:33:30 +0000
commit6f89cf6370daa443169d24ce45a925000b6e0248 (patch)
tree199a3fa13b698fa93cdf99e7214309fcae456927
parente02ebcdb0b10b1c9f077d813c08d83e0d17ca6b5 (diff)
Optimize QQuickTumbler
Listen to the relevant view changes once in QQuickTumbler and cache the offset/contentY instead of every QQuickTumblerAttached instance doing its own geometry and child tracking, and cache the view offset or contentY so that they are readily available while calculating displacements for attached property objects. This gives a 5% boost (40->42 frames in qmlbench) on TX1 in release mode. Change-Id: If1a77468e812e65bc07f32216ff9bf2e1dc5b935 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r--src/quicktemplates2/qquicktumbler.cpp175
-rw-r--r--src/quicktemplates2/qquicktumbler_p.h5
-rw-r--r--src/quicktemplates2/qquicktumbler_p_p.h37
3 files changed, 119 insertions, 98 deletions
diff --git a/src/quicktemplates2/qquicktumbler.cpp b/src/quicktemplates2/qquicktumbler.cpp
index 547380e6..42fbcc20 100644
--- a/src/quicktemplates2/qquicktumbler.cpp
+++ b/src/quicktemplates2/qquicktumbler.cpp
@@ -124,11 +124,13 @@ QQuickItem *QQuickTumblerPrivate::determineViewType(QQuickItem *contentItem)
view = contentItem;
viewContentItem = contentItem;
viewContentItemType = PathViewContentItem;
+ viewOffset = 0;
return contentItem;
} else if (contentItem->inherits("QQuickListView")) {
view = contentItem;
viewContentItem = qobject_cast<QQuickFlickable*>(contentItem)->contentItem();
viewContentItemType = ListViewContentItem;
+ viewContentY = 0;
return contentItem;
} else {
const auto childItems = contentItem->childItems();
@@ -147,6 +149,10 @@ void QQuickTumblerPrivate::resetViewData()
{
view = nullptr;
viewContentItem = nullptr;
+ if (viewContentItemType == PathViewContentItem)
+ viewOffset = 0;
+ else if (viewContentItemType == ListViewContentItem)
+ viewContentY = 0;
viewContentItemType = UnsupportedContentItemType;
}
@@ -229,16 +235,52 @@ void QQuickTumblerPrivate::_q_onViewCountChanged()
}
}
-void QQuickTumblerPrivate::itemChildAdded(QQuickItem *, QQuickItem *)
+void QQuickTumblerPrivate::_q_onViewOffsetChanged()
+{
+ viewOffset = view->property("offset").toReal();
+ calculateDisplacements();
+}
+
+void QQuickTumblerPrivate::_q_onViewContentYChanged()
+{
+ viewContentY = view->property("contentY").toReal();
+ calculateDisplacements();
+}
+
+void QQuickTumblerPrivate::calculateDisplacements()
+{
+ const auto items = viewContentItemChildItems();
+ for (QQuickItem *childItem : items) {
+ QQuickTumblerAttached *attached = qobject_cast<QQuickTumblerAttached *>(qmlAttachedPropertiesObject<QQuickTumbler>(childItem, false));
+ if (attached)
+ QQuickTumblerAttachedPrivate::get(attached)->calculateDisplacement();
+ }
+}
+
+void QQuickTumblerPrivate::itemChildAdded(QQuickItem *, QQuickItem *child)
{
_q_updateItemWidths();
_q_updateItemHeights();
+
+ QQuickTumblerAttached *attached = qobject_cast<QQuickTumblerAttached *>(qmlAttachedPropertiesObject<QQuickTumbler>(child, false));
+ if (attached)
+ QQuickTumblerAttachedPrivate::get(attached)->calculateDisplacement();
}
-void QQuickTumblerPrivate::itemChildRemoved(QQuickItem *, QQuickItem *)
+void QQuickTumblerPrivate::itemChildRemoved(QQuickItem *, QQuickItem *child)
{
_q_updateItemWidths();
_q_updateItemHeights();
+
+ QQuickTumblerAttached *attached = qobject_cast<QQuickTumblerAttached *>(qmlAttachedPropertiesObject<QQuickTumbler>(child, false));
+ if (attached)
+ QQuickTumblerAttachedPrivate::get(attached)->calculateDisplacement();
+}
+
+void QQuickTumblerPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &)
+{
+ if (change.sizeChange())
+ calculateDisplacements();
}
QQuickTumbler::QQuickTumbler(QQuickItem *parent)
@@ -532,8 +574,13 @@ void QQuickTumblerPrivate::disconnectFromView()
QObject::disconnect(view, SIGNAL(countChanged()), q, SLOT(_q_onViewCountChanged()));
QObject::disconnect(view, SIGNAL(movingChanged()), q, SIGNAL(movingChanged()));
+ if (viewContentItemType == PathViewContentItem)
+ QObject::disconnect(view, SIGNAL(offsetChanged()), q, SLOT(_q_onViewOffsetChanged()));
+ else
+ QObject::disconnect(view, SIGNAL(contentYChanged()), q, SLOT(_q_onViewContentYChanged()));
+
QQuickItemPrivate *oldViewContentItemPrivate = QQuickItemPrivate::get(viewContentItem);
- oldViewContentItemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Children);
+ oldViewContentItemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Children | QQuickItemPrivate::Geometry);
resetViewData();
}
@@ -557,8 +604,16 @@ void QQuickTumblerPrivate::setupViewData(QQuickItem *newControlContentItem)
QObject::connect(view, SIGNAL(countChanged()), q, SLOT(_q_onViewCountChanged()));
QObject::connect(view, SIGNAL(movingChanged()), q, SIGNAL(movingChanged()));
+ if (viewContentItemType == PathViewContentItem) {
+ QObject::connect(view, SIGNAL(offsetChanged()), q, SLOT(_q_onViewOffsetChanged()));
+ _q_onViewOffsetChanged();
+ } else {
+ QObject::connect(view, SIGNAL(contentYChanged()), q, SLOT(_q_onViewContentYChanged()));
+ _q_onViewContentYChanged();
+ }
+
QQuickItemPrivate *viewContentItemPrivate = QQuickItemPrivate::get(viewContentItem);
- viewContentItemPrivate->addItemChangeListener(this, QQuickItemPrivate::Children);
+ viewContentItemPrivate->addItemChangeListener(this, QQuickItemPrivate::Children | QQuickItemPrivate::Geometry);
// Sync the view's currentIndex with ours.
syncCurrentIndex();
@@ -700,81 +755,36 @@ QPalette QQuickTumbler::defaultPalette() const
return QQuickControlPrivate::themePalette(QPlatformTheme::ItemViewPalette);
}
-class QQuickTumblerAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener
-{
- Q_DECLARE_PUBLIC(QQuickTumblerAttached)
-public:
- QQuickTumblerAttachedPrivate()
- : tumbler(nullptr),
- index(-1),
- displacement(0)
- {
- }
-
- void init(QQuickItem *delegateItem)
- {
- if (!delegateItem->parentItem()) {
- qWarning() << "Tumbler: attached properties must be accessed through a delegate item that has a parent";
- return;
- }
-
- QVariant indexContextProperty = qmlContext(delegateItem)->contextProperty(QStringLiteral("index"));
- if (!indexContextProperty.isValid()) {
- qWarning() << "Tumbler: attempting to access attached property on item without an \"index\" property";
- return;
- }
-
- index = indexContextProperty.toInt();
-
- QQuickItem *parentItem = delegateItem;
- while ((parentItem = parentItem->parentItem())) {
- if ((tumbler = qobject_cast<QQuickTumbler*>(parentItem)))
- break;
- }
- }
-
- void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
- void itemChildAdded(QQuickItem *, QQuickItem *) override;
- void itemChildRemoved(QQuickItem *, QQuickItem *) override;
-
- void _q_calculateDisplacement();
- void emitIfDisplacementChanged(qreal oldDisplacement, qreal newDisplacement);
-
- // The Tumbler that contains the delegate. Required to calculated the displacement.
- QPointer<QQuickTumbler> tumbler;
- // The index of the delegate. Used to calculate the displacement.
- int index;
- // The displacement for our delegate.
- qreal displacement;
-};
-
-void QQuickTumblerAttachedPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &)
+QQuickTumblerAttachedPrivate::QQuickTumblerAttachedPrivate()
+ : tumbler(nullptr),
+ index(-1),
+ displacement(0)
{
- _q_calculateDisplacement();
}
-void QQuickTumblerAttachedPrivate::itemChildAdded(QQuickItem *, QQuickItem *)
+void QQuickTumblerAttachedPrivate::init(QQuickItem *delegateItem)
{
- _q_calculateDisplacement();
-}
+ if (!delegateItem->parentItem()) {
+ qWarning() << "Tumbler: attached properties must be accessed through a delegate item that has a parent";
+ return;
+ }
-void QQuickTumblerAttachedPrivate::itemChildRemoved(QQuickItem *item, QQuickItem *child)
-{
- _q_calculateDisplacement();
+ QVariant indexContextProperty = qmlContext(delegateItem)->contextProperty(QStringLiteral("index"));
+ if (!indexContextProperty.isValid()) {
+ qWarning() << "Tumbler: attempting to access attached property on item without an \"index\" property";
+ return;
+ }
- if (parent == child) {
- // The child that was removed from the contentItem was the delegate
- // that our properties are attached to. If we don't remove the change
- // listener, the contentItem will attempt to notify a destroyed
- // listener, causing a crash.
+ index = indexContextProperty.toInt();
- // item is the "actual content item" of Tumbler's contentItem, i.e. a PathView or ListView.contentItem
- QQuickItemPrivate *p = QQuickItemPrivate::get(item);
- p->removeItemChangeListener(this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Children);
+ QQuickItem *parentItem = delegateItem;
+ while ((parentItem = parentItem->parentItem())) {
+ if ((tumbler = qobject_cast<QQuickTumbler*>(parentItem)))
+ break;
}
}
-void QQuickTumblerAttachedPrivate::_q_calculateDisplacement()
+void QQuickTumblerAttachedPrivate::calculateDisplacement()
{
const int previousDisplacement = displacement;
displacement = 0;
@@ -802,7 +812,7 @@ void QQuickTumblerAttachedPrivate::_q_calculateDisplacement()
}
if (tumblerPrivate->viewContentItemType == QQuickTumblerPrivate::PathViewContentItem) {
- const qreal offset = tumblerPrivate->view->property("offset").toReal();
+ const qreal offset = tumblerPrivate->viewOffset;
displacement = count > 1 ? count - index - offset : 0;
// Don't add 1 if count <= visibleItemCount
@@ -813,7 +823,7 @@ void QQuickTumblerAttachedPrivate::_q_calculateDisplacement()
else if (displacement < -halfVisibleItems)
displacement += count;
} else {
- const qreal contentY = tumblerPrivate->view->property("contentY").toReal();
+ const qreal contentY = tumblerPrivate->viewContentY;
const qreal delegateH = delegateHeight(tumbler);
const qreal preferredHighlightBegin = tumblerPrivate->view->property("preferredHighlightBegin").toReal();
// Tumbler's displacement goes from negative at the top to positive towards the bottom, so we must switch this around.
@@ -853,31 +863,10 @@ QQuickTumblerAttached::QQuickTumblerAttached(QObject *parent)
if (!tumblerPrivate->viewContentItem)
return;
- QQuickItemPrivate *p = QQuickItemPrivate::get(tumblerPrivate->viewContentItem);
- p->addItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Children);
-
- const char *contentItemSignal = tumblerPrivate->viewContentItemType == QQuickTumblerPrivate::PathViewContentItem
- ? SIGNAL(offsetChanged()) : SIGNAL(contentYChanged());
- connect(tumblerPrivate->view, contentItemSignal, this, SLOT(_q_calculateDisplacement()));
-
- d->_q_calculateDisplacement();
+ d->calculateDisplacement();
}
}
-QQuickTumblerAttached::~QQuickTumblerAttached()
-{
- Q_D(QQuickTumblerAttached);
- if (!d->tumbler)
- return;
-
- QQuickTumblerPrivate *tumblerPrivate = QQuickTumblerPrivate::get(d->tumbler);
- if (!tumblerPrivate->viewContentItem)
- return;
-
- QQuickItemPrivate *viewContentItemPrivate = QQuickItemPrivate::get(tumblerPrivate->viewContentItem);
- viewContentItemPrivate->removeItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Children);
-}
-
/*!
\qmlattachedproperty Tumbler QtQuick.Controls::Tumbler::tumbler
\readonly
diff --git a/src/quicktemplates2/qquicktumbler_p.h b/src/quicktemplates2/qquicktumbler_p.h
index 71d1bda2..afdce23c 100644
--- a/src/quicktemplates2/qquicktumbler_p.h
+++ b/src/quicktemplates2/qquicktumbler_p.h
@@ -124,6 +124,8 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_updateItemHeights())
Q_PRIVATE_SLOT(d_func(), void _q_onViewCurrentIndexChanged())
Q_PRIVATE_SLOT(d_func(), void _q_onViewCountChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_onViewOffsetChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_onViewContentYChanged())
};
class QQuickTumblerAttachedPrivate;
@@ -136,7 +138,6 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTumblerAttached : public QObject
public:
explicit QQuickTumblerAttached(QObject *parent = nullptr);
- ~QQuickTumblerAttached();
QQuickTumbler *tumbler() const;
qreal displacement() const;
@@ -147,8 +148,6 @@ Q_SIGNALS:
private:
Q_DISABLE_COPY(QQuickTumblerAttached)
Q_DECLARE_PRIVATE(QQuickTumblerAttached)
-
- Q_PRIVATE_SLOT(d_func(), void _q_calculateDisplacement())
};
QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquicktumbler_p_p.h b/src/quicktemplates2/qquicktumbler_p_p.h
index 0dcae762..fe8a4ad2 100644
--- a/src/quicktemplates2/qquicktumbler_p_p.h
+++ b/src/quicktemplates2/qquicktumbler_p_p.h
@@ -50,11 +50,10 @@
#include <QtQuick/private/qquickitemchangelistener_p.h>
#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+#include <QtQuickTemplates2/private/qquicktumbler_p.h>
QT_BEGIN_NAMESPACE
-class QQuickTumbler;
-
class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTumblerPrivate : public QQuickControlPrivate, public QQuickItemChangeListener
{
Q_DECLARE_PUBLIC(QQuickTumbler)
@@ -84,6 +83,10 @@ public:
QQuickItem *view;
QQuickItem *viewContentItem;
ContentItemType viewContentItemType;
+ union {
+ qreal viewOffset; // PathView
+ qreal viewContentY; // ListView
+ };
int currentIndex;
int pendingCurrentIndex;
bool ignoreCurrentIndexChanges;
@@ -94,6 +97,10 @@ public:
void _q_updateItemWidths();
void _q_onViewCurrentIndexChanged();
void _q_onViewCountChanged();
+ void _q_onViewOffsetChanged();
+ void _q_onViewContentYChanged();
+
+ void calculateDisplacements();
void disconnectFromView();
void setupViewData(QQuickItem *newControlContentItem);
@@ -107,6 +114,32 @@ public:
void itemChildAdded(QQuickItem *, QQuickItem *) override;
void itemChildRemoved(QQuickItem *, QQuickItem *) override;
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange , const QRectF &) override;
+};
+
+class QQuickTumblerAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickTumblerAttached)
+
+public:
+ QQuickTumblerAttachedPrivate();
+
+ static QQuickTumblerAttachedPrivate *get(QQuickTumblerAttached *attached)
+ {
+ return attached->d_func();
+ }
+
+ void init(QQuickItem *delegateItem);
+
+ void calculateDisplacement();
+ void emitIfDisplacementChanged(qreal oldDisplacement, qreal newDisplacement);
+
+ // The Tumbler that contains the delegate. Required to calculated the displacement.
+ QPointer<QQuickTumbler> tumbler;
+ // The index of the delegate. Used to calculate the displacement.
+ int index;
+ // The displacement for our delegate.
+ qreal displacement;
};
QT_END_NAMESPACE