QQuickAnchors::~QQuickAnchors()
{
Q_D(QQuickAnchors);
+ d->inDestructor = true;
d->remDepend(d->fill);
d->remDepend(d->centerIn);
d->remDepend(d->left.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()
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();
}
return;
if (!f) {
- d->remDepend(d->fill);
+ QQuickItem *oldFill = d->fill;
d->fill = f;
+ d->remDepend(oldFill);
emit fillChanged();
return;
}
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();
return;
if (!c) {
- d->remDepend(d->centerIn);
+ QQuickItem *oldCI = d->centerIn;
d->centerIn = c;
+ d->remDepend(oldCI);
emit centerInChanged();
return;
}
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();
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();
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();
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();
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();
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();
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();
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();
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)
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;
void setItemPos(const QPointF &);
void setItemSize(const QSizeF &);
+ void update();
void updateOnComplete();
void updateMe();
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) {
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();
}
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();
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; }
};
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();