aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Brasser <michael.brasser@nokia.com>2011-11-25 12:53:57 +1000
committerQt by Nokia <qt-info@nokia.com>2011-11-30 03:21:12 +0100
commita782a3e5d6c73aaa8de065452349a7b925c0faf9 (patch)
tree6483d372d5ae0204dfb66d94ffee0f6a6b5c3225 /src
parentfa59f1e675ca39990e56380e659e9e6490370c83 (diff)
Anchoring system optimizations.
Do a better job of only updating anchors when needed. For example, if an item is anchored to its parent, it shouldn't react when the parent moves, only when it resizes. Change-Id: I57b480631fc6e89ab214b3fd337478d2e6534044 Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/declarative/items/qquickanchors.cpp118
-rw-r--r--src/declarative/items/qquickanchors_p_p.h5
-rw-r--r--src/declarative/items/qquickitem.cpp49
-rw-r--r--src/declarative/items/qquickitem_p.h18
4 files changed, 157 insertions, 33 deletions
diff --git a/src/declarative/items/qquickanchors.cpp b/src/declarative/items/qquickanchors.cpp
index 678347cc73..8ebdc374fb 100644
--- a/src/declarative/items/qquickanchors.cpp
+++ b/src/declarative/items/qquickanchors.cpp
@@ -146,6 +146,7 @@ QQuickAnchors::QQuickAnchors(QQuickItem *item, QObject *parent)
QQuickAnchors::~QQuickAnchors()
{
Q_D(QQuickAnchors);
+ d->inDestructor = true;
d->remDepend(d->fill);
d->remDepend(d->centerIn);
d->remDepend(d->left.item);
@@ -249,22 +250,67 @@ void QQuickAnchorsPrivate::clearItem(QQuickItem *item)
}
}
+int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem)
+{
+ QQuickItemPrivate::GeometryChangeTypes dependency = QQuickItemPrivate::NoChange;
+
+ if (!controlItem || inDestructor)
+ return dependency;
+
+ if (fill == controlItem) {
+ if ((controlItem == item->parentItem()))
+ dependency |= QQuickItemPrivate::SizeChange;
+ else //sibling
+ dependency |= QQuickItemPrivate::GeometryChange;
+ return dependency; //exit early
+ }
+
+ if (centerIn == controlItem) {
+ if ((controlItem == item->parentItem()))
+ dependency |= QQuickItemPrivate::SizeChange;
+ else //sibling
+ dependency |= QQuickItemPrivate::GeometryChange;
+ return dependency; //exit early
+ }
+
+ if ((usedAnchors & QQuickAnchors::LeftAnchor && left.item == controlItem) ||
+ (usedAnchors & QQuickAnchors::RightAnchor && right.item == controlItem) ||
+ (usedAnchors & QQuickAnchors::HCenterAnchor && hCenter.item == controlItem)) {
+ if ((controlItem == item->parentItem()))
+ dependency |= QQuickItemPrivate::WidthChange;
+ else //sibling
+ dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::XChange | QQuickItemPrivate::WidthChange);
+ }
+
+ if ((usedAnchors & QQuickAnchors::TopAnchor && top.item == controlItem) ||
+ (usedAnchors & QQuickAnchors::BottomAnchor && bottom.item == controlItem) ||
+ (usedAnchors & QQuickAnchors::VCenterAnchor && vCenter.item == controlItem) ||
+ (usedAnchors & QQuickAnchors::BaselineAnchor && baseline.item == controlItem)) {
+ if ((controlItem == item->parentItem()))
+ dependency |= QQuickItemPrivate::HeightChange;
+ else //sibling
+ dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::YChange | QQuickItemPrivate::HeightChange);
+ }
+
+ return dependency;
+}
+
void QQuickAnchorsPrivate::addDepend(QQuickItem *item)
{
- if (!item)
+ if (!item || !componentComplete)
return;
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
- p->addItemChangeListener(this, QQuickItemPrivate::Geometry);
+ p->updateOrAddGeometryChangeListener(this, QFlags<QQuickItemPrivate::GeometryChangeType>(calculateDependency(item)));
}
void QQuickAnchorsPrivate::remDepend(QQuickItem *item)
{
- if (!item)
+ if (!item || !componentComplete)
return;
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
- p->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
+ p->updateOrRemoveGeometryChangeListener(this, QFlags<QQuickItemPrivate::GeometryChangeType>(calculateDependency(item)));
}
bool QQuickAnchors::mirrored()
@@ -339,27 +385,41 @@ void QQuickAnchorsPrivate::updateMe()
return;
}
- fillChanged();
- centerInChanged();
- updateHorizontalAnchors();
- updateVerticalAnchors();
+ update();
}
void QQuickAnchorsPrivate::updateOnComplete()
{
+ //optimization to only set initial dependencies once, at completion time
+ QSet<QQuickItem *> dependencies;
+ dependencies << fill << centerIn
+ << left.item << right.item << hCenter.item
+ << top.item << bottom.item << vCenter.item << baseline.item;
+
+ foreach (QQuickItem *dependency, dependencies)
+ addDepend(dependency);
+
+ update();
+}
+
+
+void QQuickAnchorsPrivate::update()
+{
fillChanged();
centerInChanged();
- updateHorizontalAnchors();
- updateVerticalAnchors();
+ if (usedAnchors & QQuickAnchorLine::Horizontal_Mask)
+ updateHorizontalAnchors();
+ if (usedAnchors & QQuickAnchorLine::Vertical_Mask)
+ updateVerticalAnchors();
}
void QQuickAnchorsPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newG, const QRectF &oldG)
{
fillChanged();
centerInChanged();
- if (newG.x() != oldG.x() || newG.width() != oldG.width())
+ if ((usedAnchors & QQuickAnchorLine::Horizontal_Mask) && (newG.x() != oldG.x() || newG.width() != oldG.width()))
updateHorizontalAnchors();
- if (newG.y() != oldG.y() || newG.height() != oldG.height())
+ if ((usedAnchors & QQuickAnchorLine::Vertical_Mask) && (newG.y() != oldG.y() || newG.height() != oldG.height()))
updateVerticalAnchors();
}
@@ -376,8 +436,9 @@ void QQuickAnchors::setFill(QQuickItem *f)
return;
if (!f) {
- d->remDepend(d->fill);
+ QQuickItem *oldFill = d->fill;
d->fill = f;
+ d->remDepend(oldFill);
emit fillChanged();
return;
}
@@ -385,8 +446,9 @@ void QQuickAnchors::setFill(QQuickItem *f)
qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling.");
return;
}
- d->remDepend(d->fill);
+ QQuickItem *oldFill = d->fill;
d->fill = f;
+ d->remDepend(oldFill);
d->addDepend(d->fill);
emit fillChanged();
d->fillChanged();
@@ -410,8 +472,9 @@ void QQuickAnchors::setCenterIn(QQuickItem* c)
return;
if (!c) {
- d->remDepend(d->centerIn);
+ QQuickItem *oldCI = d->centerIn;
d->centerIn = c;
+ d->remDepend(oldCI);
emit centerInChanged();
return;
}
@@ -419,9 +482,9 @@ void QQuickAnchors::setCenterIn(QQuickItem* c)
qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling.");
return;
}
-
- d->remDepend(d->centerIn);
+ QQuickItem *oldCI = d->centerIn;
d->centerIn = c;
+ d->remDepend(oldCI);
d->addDepend(d->centerIn);
emit centerInChanged();
d->centerInChanged();
@@ -642,8 +705,9 @@ void QQuickAnchors::setTop(const QQuickAnchorLine &edge)
return;
}
- d->remDepend(d->top.item);
+ QQuickItem *oldTop = d->top.item;
d->top = edge;
+ d->remDepend(oldTop);
d->addDepend(d->top.item);
emit topChanged();
d->updateVerticalAnchors();
@@ -678,8 +742,9 @@ void QQuickAnchors::setBottom(const QQuickAnchorLine &edge)
return;
}
- d->remDepend(d->bottom.item);
+ QQuickItem *oldBottom = d->bottom.item;
d->bottom = edge;
+ d->remDepend(oldBottom);
d->addDepend(d->bottom.item);
emit bottomChanged();
d->updateVerticalAnchors();
@@ -714,8 +779,9 @@ void QQuickAnchors::setVerticalCenter(const QQuickAnchorLine &edge)
return;
}
- d->remDepend(d->vCenter.item);
+ QQuickItem *oldVCenter = d->vCenter.item;
d->vCenter = edge;
+ d->remDepend(oldVCenter);
d->addDepend(d->vCenter.item);
emit verticalCenterChanged();
d->updateVerticalAnchors();
@@ -750,8 +816,9 @@ void QQuickAnchors::setBaseline(const QQuickAnchorLine &edge)
return;
}
- d->remDepend(d->baseline.item);
+ QQuickItem *oldBaseline = d->baseline.item;
d->baseline = edge;
+ d->remDepend(oldBaseline);
d->addDepend(d->baseline.item);
emit baselineChanged();
d->updateVerticalAnchors();
@@ -786,8 +853,9 @@ void QQuickAnchors::setLeft(const QQuickAnchorLine &edge)
return;
}
- d->remDepend(d->left.item);
+ QQuickItem *oldLeft = d->left.item;
d->left = edge;
+ d->remDepend(oldLeft);
d->addDepend(d->left.item);
emit leftChanged();
d->updateHorizontalAnchors();
@@ -822,8 +890,9 @@ void QQuickAnchors::setRight(const QQuickAnchorLine &edge)
return;
}
- d->remDepend(d->right.item);
+ QQuickItem *oldRight = d->right.item;
d->right = edge;
+ d->remDepend(oldRight);
d->addDepend(d->right.item);
emit rightChanged();
d->updateHorizontalAnchors();
@@ -858,8 +927,9 @@ void QQuickAnchors::setHorizontalCenter(const QQuickAnchorLine &edge)
return;
}
- d->remDepend(d->hCenter.item);
+ QQuickItem *oldHCenter = d->hCenter.item;
d->hCenter = edge;
+ d->remDepend(oldHCenter);
d->addDepend(d->hCenter.item);
emit horizontalCenterChanged();
d->updateHorizontalAnchors();
diff --git a/src/declarative/items/qquickanchors_p_p.h b/src/declarative/items/qquickanchors_p_p.h
index eae7981617..50d55b081f 100644
--- a/src/declarative/items/qquickanchors_p_p.h
+++ b/src/declarative/items/qquickanchors_p_p.h
@@ -92,7 +92,7 @@ class QQuickAnchorsPrivate : public QObjectPrivate, public QQuickItemChangeListe
Q_DECLARE_PUBLIC(QQuickAnchors)
public:
QQuickAnchorsPrivate(QQuickItem *i)
- : componentComplete(true), updatingMe(false), updatingHorizontalAnchor(0),
+ : componentComplete(true), updatingMe(false), inDestructor(false), updatingHorizontalAnchor(0),
updatingVerticalAnchor(0), updatingFill(0), updatingCenterIn(0), item(i), usedAnchors(0), fill(0),
centerIn(0), leftMargin(0), rightMargin(0), topMargin(0), bottomMargin(0),
margins(0), vCenterOffset(0), hCenterOffset(0), baselineOffset(0)
@@ -101,12 +101,14 @@ public:
void clearItem(QQuickItem *);
+ int calculateDependency(QQuickItem *);
void addDepend(QQuickItem *);
void remDepend(QQuickItem *);
bool isItemComplete() const;
bool componentComplete:1;
bool updatingMe:1;
+ bool inDestructor:1;
uint updatingHorizontalAnchor:2;
uint updatingVerticalAnchor:2;
uint updatingFill:2;
@@ -119,6 +121,7 @@ public:
void setItemPos(const QPointF &);
void setItemSize(const QSizeF &);
+ void update();
void updateOnComplete();
void updateMe();
diff --git a/src/declarative/items/qquickitem.cpp b/src/declarative/items/qquickitem.cpp
index e020a0088c..a4a5ab4d0e 100644
--- a/src/declarative/items/qquickitem.cpp
+++ b/src/declarative/items/qquickitem.cpp
@@ -1759,7 +1759,7 @@ QQuickItem::~QQuickItem()
for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
QQuickAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
if (anchor && anchor->item && anchor->item->parent() != this) //child will be deleted anyway
- anchor->updateOnComplete();
+ anchor->update();
}
for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
@@ -2784,19 +2784,32 @@ void QQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
if (d->_anchors)
QQuickAnchorsPrivate::get(d->_anchors)->updateMe();
+ bool xChange = (newGeometry.x() != oldGeometry.x());
+ bool yChange = (newGeometry.y() != oldGeometry.y());
+ bool widthChange = (newGeometry.width() != oldGeometry.width());
+ bool heightChange = (newGeometry.height() != oldGeometry.height());
+
for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
const QQuickItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
- if (change.types & QQuickItemPrivate::Geometry)
- change.listener->itemGeometryChanged(this, newGeometry, oldGeometry);
+ if (change.types & QQuickItemPrivate::Geometry) {
+ if (change.gTypes == QQuickItemPrivate::GeometryChange) {
+ change.listener->itemGeometryChanged(this, newGeometry, oldGeometry);
+ } else if ((xChange && (change.gTypes & QQuickItemPrivate::XChange)) ||
+ (yChange && (change.gTypes & QQuickItemPrivate::YChange)) ||
+ (widthChange && (change.gTypes & QQuickItemPrivate::WidthChange)) ||
+ (heightChange && (change.gTypes & QQuickItemPrivate::HeightChange))) {
+ change.listener->itemGeometryChanged(this, newGeometry, oldGeometry);
+ }
+ }
}
- if (newGeometry.x() != oldGeometry.x())
+ if (xChange)
emit xChanged();
- if (newGeometry.y() != oldGeometry.y())
+ if (yChange)
emit yChanged();
- if (newGeometry.width() != oldGeometry.width())
+ if (widthChange)
emit widthChanged();
- if (newGeometry.height() != oldGeometry.height())
+ if (heightChange)
emit heightChanged();
}
@@ -2834,6 +2847,28 @@ void QQuickItemPrivate::removeItemChangeListener(QQuickItemChangeListener *liste
changeListeners.removeOne(change);
}
+void QQuickItemPrivate::updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener, GeometryChangeTypes types)
+{
+ ChangeListener change(listener, types);
+ int index = changeListeners.find(change);
+ if (index > -1)
+ changeListeners[index].gTypes = change.gTypes; //we may have different GeometryChangeTypes
+ else
+ changeListeners.append(change);
+}
+
+void QQuickItemPrivate::updateOrRemoveGeometryChangeListener(QQuickItemChangeListener *listener, GeometryChangeTypes types)
+{
+ ChangeListener change(listener, types);
+ if (types == NoChange) {
+ changeListeners.removeOne(change);
+ } else {
+ int index = changeListeners.find(change);
+ if (index > -1)
+ changeListeners[index].gTypes = change.gTypes; //we may have different GeometryChangeTypes
+ }
+}
+
void QQuickItem::keyPressEvent(QKeyEvent *event)
{
event->ignore();
diff --git a/src/declarative/items/qquickitem_p.h b/src/declarative/items/qquickitem_p.h
index 38e5d154f8..e9ddae5f75 100644
--- a/src/declarative/items/qquickitem_p.h
+++ b/src/declarative/items/qquickitem_p.h
@@ -216,10 +216,24 @@ public:
Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
+ enum GeometryChangeType {
+ NoChange = 0,
+ XChange = 0x01,
+ YChange = 0x02,
+ WidthChange = 0x04,
+ HeightChange = 0x08,
+ SizeChange = WidthChange | HeightChange,
+ GeometryChange = XChange | YChange | SizeChange
+ };
+
+ Q_DECLARE_FLAGS(GeometryChangeTypes, GeometryChangeType)
+
struct ChangeListener {
- ChangeListener(QQuickItemChangeListener *l, QQuickItemPrivate::ChangeTypes t) : listener(l), types(t) {}
+ ChangeListener(QQuickItemChangeListener *l, QQuickItemPrivate::ChangeTypes t) : listener(l), types(t), gTypes(GeometryChange) {}
+ ChangeListener(QQuickItemChangeListener *l, QQuickItemPrivate::GeometryChangeTypes gt) : listener(l), types(Geometry), gTypes(gt) {}
QQuickItemChangeListener *listener;
QQuickItemPrivate::ChangeTypes types;
+ QQuickItemPrivate::GeometryChangeTypes gTypes; //NOTE: not used for ==
bool operator==(const ChangeListener &other) const { return listener == other.listener && types == other.types; }
};
@@ -227,6 +241,8 @@ public:
changeListeners.append(ChangeListener(listener, types));
}
void removeItemChangeListener(QQuickItemChangeListener *, ChangeTypes types);
+ void updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener, GeometryChangeTypes types);
+ void updateOrRemoveGeometryChangeListener(QQuickItemChangeListener *listener, GeometryChangeTypes types);
QPODVector<ChangeListener,4> changeListeners;
QDeclarativeStateGroup *_states();