From c22504ae79b45268d603c2b2bc66bd2a59c331c7 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 18 May 2009 16:39:05 +1000 Subject: Simplify (hopefully) anchors, and make them less reliant on signals --- demos/declarative/flickr/content/ImageDetails.qml | 1 - src/declarative/fx/qfxanchors.cpp | 717 +++++++++------------- src/declarative/fx/qfxanchors.h | 12 +- src/declarative/fx/qfxanchors_p.h | 36 +- src/declarative/fx/qfxflipable.cpp | 1 + src/declarative/fx/qfxitem.cpp | 105 +--- src/declarative/fx/qfxitem.h | 5 - src/declarative/fx/qfxitem_p.h | 4 +- 8 files changed, 344 insertions(+), 537 deletions(-) diff --git a/demos/declarative/flickr/content/ImageDetails.qml b/demos/declarative/flickr/content/ImageDetails.qml index b8091f2..ccc91cb 100644 --- a/demos/declarative/flickr/content/ImageDetails.qml +++ b/demos/declarative/flickr/content/ImageDetails.qml @@ -89,7 +89,6 @@ Flipable { // Center image if it is smaller than the flickable area. x: ImageContainer.width > width*scale ? (ImageContainer.width - width*scale) / 2 : 0 y: ImageContainer.height > height*scale ? (ImageContainer.height - height*scale) / 2 : 0 - anchors.centeredIn: parent onStatusChanged : { // Default scale shows the entire image. if (status == 0 && width != 0) { diff --git a/src/declarative/fx/qfxanchors.cpp b/src/declarative/fx/qfxanchors.cpp index 53d0187..826d6c1 100644 --- a/src/declarative/fx/qfxanchors.cpp +++ b/src/declarative/fx/qfxanchors.cpp @@ -41,6 +41,7 @@ #include "qfxanchors_p.h" #include "qfxitem.h" +#include "qfxitem_p.h" #include #include #include @@ -132,22 +133,174 @@ static qreal adjustedPosition(QFxItem *item, QFxAnchorLine::AnchorLine anchorLin QFxAnchors::QFxAnchors(QObject *parent) : QObject(*new QFxAnchorsPrivate(), parent) { - } -void QFxAnchors::fillChanged() +QFxAnchors::~QFxAnchors() { Q_D(QFxAnchors); - if (!d->fill) + d->remDepend(d->fill); + d->remDepend(d->centeredIn); + d->remDepend(d->left.item); + d->remDepend(d->right.item); + d->remDepend(d->top.item); + d->remDepend(d->bottom.item); + d->remDepend(d->vCenter.item); + d->remDepend(d->hCenter.item); +} + +void QFxAnchorsPrivate::fillChanged() +{ + if (!fill || !isItemComplete()) + return; + + if (fill == item->itemParent()) { //child-parent + setItemPos(QPointF(leftMargin, topMargin)); + } else if (fill->itemParent() == item->itemParent()) { //siblings + setItemPos(QPointF(fill->x()+leftMargin, fill->y()+topMargin)); + } + setItemWidth(fill->width()-leftMargin-rightMargin); + setItemHeight(fill->height()-topMargin-bottomMargin); +} + +void QFxAnchorsPrivate::centeredInChanged() +{ + if (!centeredIn || fill || !isItemComplete()) return; - if (d->fill == d->item->itemParent()) { //child-parent - d->item->setPos(QPointF(leftMargin(), topMargin())); - } else if (d->fill->itemParent() == d->item->itemParent()) { //siblings - d->item->setPos(QPointF(d->fill->x()+leftMargin(), d->fill->y()+topMargin())); + if (centeredIn == item->itemParent()) { + QPointF p((item->itemParent()->width() - item->width()) / 2., + (item->itemParent()->height() - item->height()) / 2.); + setItemPos(p); + + } else if (centeredIn->itemParent() == item->itemParent()) { + + QPointF p(centeredIn->x() + (centeredIn->width() - item->width()) / 2., + centeredIn->y() + (centeredIn->height() - item->height()) / 2.); + setItemPos(p); + } +} + +void QFxAnchorsPrivate::clearItem(QFxItem *item) +{ + if (fill == item) + fill = 0; + if (centeredIn == item) + centeredIn = 0; + if (left.item == item) + left.item = 0; + if (right.item == item) { + right.item = 0; + usedAnchors &= ~QFxAnchors::HasRightAnchor; + } + if (top.item == item) { + top.item = 0; + usedAnchors &= ~QFxAnchors::HasTopAnchor; + } + if (bottom.item == item) { + bottom.item = 0; + usedAnchors &= ~QFxAnchors::HasBottomAnchor; + } + if (vCenter.item == item) { + vCenter.item = 0; + usedAnchors &= ~QFxAnchors::HasVCenterAnchor; + } + if (hCenter.item == item) { + hCenter.item = 0; + usedAnchors &= ~QFxAnchors::HasHCenterAnchor; + } +} + +void QFxAnchorsPrivate::addDepend(QFxItem *item) +{ + Q_Q(QFxAnchors); + if (!item) + return; + QFxItemPrivate *p = + static_cast(QObjectPrivate::get(item)); + p->dependantAnchors.append(q); +} + +void QFxAnchorsPrivate::remDepend(QFxItem *item) +{ + Q_Q(QFxAnchors); + if (!item) + return; + QFxItemPrivate *p = + static_cast(QObjectPrivate::get(item)); + p->dependantAnchors.removeAll(q); +} + +bool QFxAnchorsPrivate::isItemComplete() const +{ + return true; + return item->isComponentComplete(); +} + +void QFxAnchorsPrivate::setItemHeight(qreal v) +{ + updatingMe = true; + item->setHeight(v); + updatingMe = false; +} + +void QFxAnchorsPrivate::setItemWidth(qreal v) +{ + updatingMe = true; + item->setWidth(v); + updatingMe = false; +} + +void QFxAnchorsPrivate::setItemX(qreal v) +{ + updatingMe = true; + item->setX(v); + updatingMe = false; +} + +void QFxAnchorsPrivate::setItemY(qreal v) +{ + updatingMe = true; + item->setY(v); + updatingMe = false; +} + +void QFxAnchorsPrivate::setItemPos(const QPointF &v) +{ + updatingMe = true; + item->setPos(v); + updatingMe = false; +} + +void QFxAnchorsPrivate::updateMe() +{ + if (updatingMe) { + updatingMe = false; + return; } - d->item->setWidth(d->fill->width()-leftMargin()-rightMargin()); - d->item->setHeight(d->fill->height()-topMargin()-bottomMargin()); + + fillChanged(); + centeredInChanged(); + updateHorizontalAnchors(); + updateVerticalAnchors(); +} + +void QFxAnchorsPrivate::updateOnComplete() +{ + fillChanged(); + centeredInChanged(); + updateHorizontalAnchors(); + updateVerticalAnchors(); +} + +void QFxAnchorsPrivate::update(QFxItem *, const QRectF &newG, const QRectF &oldG) +{ + fillChanged(); + centeredInChanged(); + + if (newG.x() != oldG.x() || newG.width() != oldG.width()) + updateHorizontalAnchors(); + if (newG.y() != oldG.y() || newG.height() != oldG.height()) + updateVerticalAnchors(); } /*! @@ -166,37 +319,11 @@ QFxItem *QFxAnchors::fill() const void QFxAnchors::setFill(QFxItem *f) { Q_D(QFxAnchors); - if (d->fill) { - QObject::disconnect(d->fill, SIGNAL(leftChanged()), this, SLOT(fillChanged())); - QObject::disconnect(d->fill, SIGNAL(topChanged()), this, SLOT(fillChanged())); - QObject::disconnect(d->fill, SIGNAL(widthChanged()), this, SLOT(fillChanged())); - QObject::disconnect(d->fill, SIGNAL(heightChanged()), this, SLOT(fillChanged())); - QObject::disconnect(this, SIGNAL(leftMarginChanged()), this, SLOT(fillChanged())); - QObject::disconnect(this, SIGNAL(topMarginChanged()), this, SLOT(fillChanged())); - QObject::disconnect(this, SIGNAL(rightMarginChanged()), this, SLOT(fillChanged())); - QObject::disconnect(this, SIGNAL(bottomMarginChanged()), this, SLOT(fillChanged())); - } - + d->remDepend(d->fill); d->fill = f; + d->addDepend(d->fill); - if (d->fill) { - if (d->fill == d->item->itemParent()) { //child-parent - QObject::connect(d->fill, SIGNAL(widthChanged()), this, SLOT(fillChanged())); - QObject::connect(d->fill, SIGNAL(heightChanged()), this, SLOT(fillChanged())); - } else if (f->itemParent() == d->item->itemParent()) { //siblings - QObject::connect(d->fill, SIGNAL(leftChanged()), this, SLOT(fillChanged())); - QObject::connect(d->fill, SIGNAL(topChanged()), this, SLOT(fillChanged())); - QObject::connect(d->fill, SIGNAL(widthChanged()), this, SLOT(fillChanged())); - QObject::connect(d->fill, SIGNAL(heightChanged()), this, SLOT(fillChanged())); - } else { - qmlInfo(d->item) << "Can't anchor to an item that isn't a parent or sibling."; - } - } - QObject::connect(this, SIGNAL(leftMarginChanged()), this, SLOT(fillChanged())); - QObject::connect(this, SIGNAL(topMarginChanged()), this, SLOT(fillChanged())); - QObject::connect(this, SIGNAL(rightMarginChanged()), this, SLOT(fillChanged())); - QObject::connect(this, SIGNAL(bottomMarginChanged()), this, SLOT(fillChanged())); - fillChanged(); //### can/should we defer until component completion? + d->fillChanged(); } /*! @@ -223,163 +350,12 @@ void QFxAnchors::setCenteredIn(QFxItem* c) qmlInfo(d->item) << "Can't anchor to an item that isn't a parent or sibling."; return; } - d->centeredIn = c; - setHorizontalCenter(c->horizontalCenter()); - setVerticalCenter(c->verticalCenter()); -} - -void QFxAnchorsPrivate::connectVHelper(const QFxAnchorLine &edge) -{ - //### should we do disconnects first? (will it be called more than once?) - Q_Q(QFxAnchors); - if (edge.item == item->itemParent()) { //child-parent - switch(edge.anchorLine) { - case QFxAnchorLine::Bottom: - case QFxAnchorLine::VCenter: - QObject::connect(edge.item, SIGNAL(heightChanged()), q, SLOT(updateVerticalAnchors())); - break; - case QFxAnchorLine::Top: //no connection needed - default: - break; - } - } else if (edge.item->itemParent() == item->itemParent()) { //siblings - switch(edge.anchorLine) { - case QFxAnchorLine::Top: - QObject::connect(edge.item, SIGNAL(topChanged()), q, SLOT(updateVerticalAnchors())); - break; - case QFxAnchorLine::Bottom: - QObject::connect(edge.item, SIGNAL(bottomChanged()), q, SLOT(updateVerticalAnchors())); - break; - case QFxAnchorLine::VCenter: - QObject::connect(edge.item, SIGNAL(vcenterChanged()), q, SLOT(updateVerticalAnchors())); - break; - default: - break; - } - } else { - qmlInfo(item) << "Can't anchor to an item that isn't a parent or sibling."; - } -} - -void QFxAnchors::connectVAnchors() -{ - Q_D(QFxAnchors); - if (!d->checkVValid()) - return; - - if (d->usedAnchors & HasTopAnchor) { - //Handle stretching connections (if we have multiple horizontal anchors) - QFxAnchorLine *edge = 0; - if (d->usedAnchors & HasBottomAnchor) { - edge = &d->bottom; - connect(this, SIGNAL(bottomMarginChanged()), this, SLOT(updateVerticalAnchors())); - } else if (d->usedAnchors & HasVCenterAnchor) { - edge = &d->vCenter; - connect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); - } - if (edge) { - //we need to stretch - d->connectVHelper(*edge); - } - - //Handle top - d->connectVHelper(d->top); - connect(this, SIGNAL(topMarginChanged()), this, SLOT(updateVerticalAnchors())); - updateVerticalAnchors(); - } else if (d->usedAnchors & HasBottomAnchor) { - //Handle stretching connections (if we have multiple horizontal anchors) - if (d->usedAnchors & HasVCenterAnchor) { - d->connectVHelper(d->vCenter); - connect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); - } - - //Handle bottom - d->connectVHelper(d->bottom); - connect(this, SIGNAL(bottomMarginChanged()), this, SLOT(updateVerticalAnchors())); - updateVerticalAnchors(); - } else if (d->usedAnchors & HasVCenterAnchor) { - //Handle vCenter - d->connectVHelper(d->vCenter); - connect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); - updateVerticalAnchors(); - } -} - -void QFxAnchorsPrivate::connectHHelper(const QFxAnchorLine &edge) -{ - //### should we do disconnects first? (will it be called more than once?) - Q_Q(QFxAnchors); - if (edge.item == item->itemParent()) { //child-parent - switch(edge.anchorLine) { - case QFxAnchorLine::Right: - case QFxAnchorLine::HCenter: - QObject::connect(edge.item, SIGNAL(widthChanged()), q, SLOT(updateHorizontalAnchors())); - break; - case QFxAnchorLine::Left: //no connection needed - default: - break; - } - } else if (edge.item->itemParent() == item->itemParent()) { //siblings - switch(edge.anchorLine) { - case QFxAnchorLine::Left: - QObject::connect(edge.item, SIGNAL(leftChanged()), q, SLOT(updateHorizontalAnchors())); - break; - case QFxAnchorLine::Right: - QObject::connect(edge.item, SIGNAL(rightChanged()), q, SLOT(updateHorizontalAnchors())); - break; - case QFxAnchorLine::HCenter: - QObject::connect(edge.item, SIGNAL(hcenterChanged()), q, SLOT(updateHorizontalAnchors())); - break; - default: - break; - } - } else { - qmlInfo(item) << "Can't anchor to an item that isn't a parent or sibling."; - } -} - -void QFxAnchors::connectHAnchors() -{ - Q_D(QFxAnchors); - if (!d->checkHValid()) - return; - - if (d->usedAnchors & HasLeftAnchor) { - //Handle stretching connections (if we have multiple horizontal anchors) - QFxAnchorLine *edge = 0; - if (d->usedAnchors & HasRightAnchor) { - edge = &d->right; - connect(this, SIGNAL(rightMarginChanged()), this, SLOT(updateHorizontalAnchors())); - } else if (d->usedAnchors & HasHCenterAnchor) { - edge = &d->hCenter; - connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); - } - if (edge) { - //we need to stretch - d->connectHHelper(*edge); - } - //Handle left - d->connectHHelper(d->left); - connect(this, SIGNAL(leftMarginChanged()), this, SLOT(updateHorizontalAnchors())); - updateHorizontalAnchors(); - } else if (d->usedAnchors & HasRightAnchor) { - //Handle stretching connections (if we have multiple horizontal anchors) - if (d->usedAnchors & HasHCenterAnchor) { - d->connectHHelper(d->hCenter); - connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); - } + d->remDepend(d->centeredIn); + d->centeredIn = c; + d->addDepend(d->centeredIn); - //Handle right - d->connectHHelper(d->right); - connect(this, SIGNAL(rightMarginChanged()), this, SLOT(updateHorizontalAnchors())); - updateHorizontalAnchors(); - } else if (d->usedAnchors & HasHCenterAnchor) { - //Handle hCenter - d->connectHHelper(d->hCenter); - connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); - updateHorizontalAnchors(); - } + d->centeredInChanged(); } bool QFxAnchorsPrivate::calcStretch(const QFxAnchorLine &edge1, @@ -411,168 +387,124 @@ bool QFxAnchorsPrivate::calcStretch(const QFxAnchorLine &edge1, return invalid; } -void QFxAnchors::updateVerticalAnchors() +void QFxAnchorsPrivate::updateVerticalAnchors() { - Q_D(QFxAnchors); - if (!d->updatingVerticalAnchor) { - d->updatingVerticalAnchor = true; - if (d->usedAnchors & HasTopAnchor) { + if (fill || centeredIn || !isItemComplete()) + return; + + if (!updatingVerticalAnchor) { + updatingVerticalAnchor = true; + if (usedAnchors & QFxAnchors::HasTopAnchor) { //Handle stretching bool invalid = true; int height = 0; - if (d->usedAnchors & HasBottomAnchor) { - invalid = d->calcStretch(d->top, d->bottom, d->topMargin, -d->bottomMargin, QFxAnchorLine::Top, height); - } else if (d->usedAnchors & HasVCenterAnchor) { - invalid = d->calcStretch(d->top, d->vCenter, d->topMargin, d->vCenterOffset, QFxAnchorLine::Top, height); + if (usedAnchors & QFxAnchors::HasBottomAnchor) { + invalid = calcStretch(top, bottom, topMargin, -bottomMargin, QFxAnchorLine::Top, height); + } else if (usedAnchors & QFxAnchors::HasVCenterAnchor) { + invalid = calcStretch(top, vCenter, topMargin, vCenterOffset, QFxAnchorLine::Top, height); height *= 2; } if (!invalid) - d->item->setHeight(height); + setItemHeight(height); //Handle top - if (d->top.item == d->item->itemParent()) { - d->item->setY(adjustedPosition(d->top.item, d->top.anchorLine) + d->topMargin); - } else if (d->top.item->itemParent() == d->item->itemParent()) { - d->item->setY(position(d->top.item, d->top.anchorLine) + d->topMargin); + if (top.item == item->itemParent()) { + setItemY(adjustedPosition(top.item, top.anchorLine) + topMargin); + } else if (top.item->itemParent() == item->itemParent()) { + setItemY(position(top.item, top.anchorLine) + topMargin); } - } else if (d->usedAnchors & HasBottomAnchor) { + } else if (usedAnchors & QFxAnchors::HasBottomAnchor) { //Handle stretching (top + bottom case is handled above) - if (d->usedAnchors & HasVCenterAnchor) { + if (usedAnchors & QFxAnchors::HasVCenterAnchor) { int height = 0; - bool invalid = d->calcStretch(d->vCenter, d->bottom, d->vCenterOffset, -d->bottomMargin, + bool invalid = calcStretch(vCenter, bottom, vCenterOffset, -bottomMargin, QFxAnchorLine::Top, height); if (!invalid) - d->item->setHeight(height*2); + setItemHeight(height*2); } //Handle bottom - if (d->bottom.item == d->item->itemParent()) { - d->item->setY(adjustedPosition(d->bottom.item, d->bottom.anchorLine) - d->item->height() - d->bottomMargin); - } else if (d->bottom.item->itemParent() == d->item->itemParent()) { - d->item->setY(position(d->bottom.item, d->bottom.anchorLine) - d->item->height() - d->bottomMargin); + if (bottom.item == item->itemParent()) { + setItemY(adjustedPosition(bottom.item, bottom.anchorLine) - item->height() - bottomMargin); + } else if (bottom.item->itemParent() == item->itemParent()) { + setItemY(position(bottom.item, bottom.anchorLine) - item->height() - bottomMargin); } - } else if (d->usedAnchors & HasVCenterAnchor) { + } else if (usedAnchors & QFxAnchors::HasVCenterAnchor) { //(stetching handled above) //Handle vCenter - if (d->vCenter.item == d->item->itemParent()) { - d->item->setY(adjustedPosition(d->vCenter.item, d->vCenter.anchorLine) - - d->item->height()/2 + d->vCenterOffset); - } else if (d->vCenter.item->itemParent() == d->item->itemParent()) { - d->item->setY(position(d->vCenter.item, d->vCenter.anchorLine) - d->item->height()/2 + d->vCenterOffset); + if (vCenter.item == item->itemParent()) { + setItemY(adjustedPosition(vCenter.item, vCenter.anchorLine) + - item->height()/2 + vCenterOffset); + } else if (vCenter.item->itemParent() == item->itemParent()) { + setItemY(position(vCenter.item, vCenter.anchorLine) - item->height()/2 + vCenterOffset); } } - d->updatingVerticalAnchor = false; + updatingVerticalAnchor = false; } else { - qmlInfo(d->item) << "Anchor loop detected on vertical anchor."; + // ### Make this certain :) + qmlInfo(item) << "Possible anchor loop detected on vertical anchor."; } } -void QFxAnchors::updateHorizontalAnchors() +void QFxAnchorsPrivate::updateHorizontalAnchors() { - Q_D(QFxAnchors); - if (!d->updatingHorizontalAnchor) { - d->updatingHorizontalAnchor = true; + if (fill || centeredIn || !isItemComplete()) + return; - //alternate implementation (needs performance testing) - /*switch(d->usedAnchors & QFxAnchors::Horizontal_Mask) { - case 0x03: //(HasLeftAnchor | HasRightAnchor) - { - int width = 0; - if (!d->calcStretch(d->left, d->right, d->leftMargin, -d->rightMargin, QFxAnchorLine::Left, width)) - d->item->setWidth(width); - //fall though - } - case 0x11: //(HasLeftAnchor | HasHCenterAnchor) - { - if (d->usedAnchors & HasHCenterAnchor) { - int width = 0; - if (!d->calcStretch(d->left, d->hCenter, d->leftMargin, d->hCenterOffset, QFxAnchorLine::Left, width)) - d->item->setWidth(width*2); - } - //fall though - } - case HasLeftAnchor: - if (d->left.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->left.item, d->left.anchorLine) + d->leftMargin); - } else if (d->left.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->left.item, d->left.anchorLine) + d->leftMargin); - } - break; - case 0x12: //(HasRightAnchor | HasHCenterAnchor) - { - int width = 0; - if (!d->calcStretch(d->hCenter, d->right, d->hCenterOffset, -d->rightMargin, QFxAnchorLine::Left, width)) - d->item->setWidth(width*2); - //fall though - } - case HasRightAnchor: - if (d->right.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); - } else if (d->right.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); - } - break; - case HasHCenterAnchor: - if (d->hCenter.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); - } else if (d->hCenter.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); - } - break; - default: - break; - }*/ + if (!updatingHorizontalAnchor) { + updatingHorizontalAnchor = true; - if (d->usedAnchors & HasLeftAnchor) { + if (usedAnchors & QFxAnchors::HasLeftAnchor) { //Handle stretching bool invalid = true; int width = 0; - if (d->usedAnchors & HasRightAnchor) { - invalid = d->calcStretch(d->left, d->right, d->leftMargin, -d->rightMargin, QFxAnchorLine::Left, width); - } else if (d->usedAnchors & HasHCenterAnchor) { - invalid = d->calcStretch(d->left, d->hCenter, d->leftMargin, d->hCenterOffset, QFxAnchorLine::Left, width); + if (usedAnchors & QFxAnchors::HasRightAnchor) { + invalid = calcStretch(left, right, leftMargin, -rightMargin, QFxAnchorLine::Left, width); + } else if (usedAnchors & QFxAnchors::HasHCenterAnchor) { + invalid = calcStretch(left, hCenter, leftMargin, hCenterOffset, QFxAnchorLine::Left, width); width *= 2; } if (!invalid) - d->item->setWidth(width); + setItemWidth(width); //Handle left - if (d->left.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->left.item, d->left.anchorLine) + d->leftMargin); - } else if (d->left.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->left.item, d->left.anchorLine) + d->leftMargin); + if (left.item == item->itemParent()) { + setItemX(adjustedPosition(left.item, left.anchorLine) + leftMargin); + } else if (left.item->itemParent() == item->itemParent()) { + setItemX(position(left.item, left.anchorLine) + leftMargin); } - } else if (d->usedAnchors & HasRightAnchor) { + } else if (usedAnchors & QFxAnchors::HasRightAnchor) { //Handle stretching (left + right case is handled in updateLeftAnchor) - if (d->usedAnchors & HasHCenterAnchor) { + if (usedAnchors & QFxAnchors::HasHCenterAnchor) { int width = 0; - bool invalid = d->calcStretch(d->hCenter, d->right, d->hCenterOffset, -d->rightMargin, + bool invalid = calcStretch(hCenter, right, hCenterOffset, -rightMargin, QFxAnchorLine::Left, width); if (!invalid) - d->item->setWidth(width*2); + setItemWidth(width*2); } //Handle right - if (d->right.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); - } else if (d->right.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); + if (right.item == item->itemParent()) { + setItemX(adjustedPosition(right.item, right.anchorLine) - item->width() - rightMargin); + } else if (right.item->itemParent() == item->itemParent()) { + setItemX(position(right.item, right.anchorLine) - item->width() - rightMargin); } - } else if (d->usedAnchors & HasHCenterAnchor) { + } else if (usedAnchors & QFxAnchors::HasHCenterAnchor) { //Handle hCenter - if (d->hCenter.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); - } else if (d->hCenter.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); + if (hCenter.item == item->itemParent()) { + setItemX(adjustedPosition(hCenter.item, hCenter.anchorLine) - item->width()/2 + hCenterOffset); + } else if (hCenter.item->itemParent() == item->itemParent()) { + setItemX(position(hCenter.item, hCenter.anchorLine) - item->width()/2 + hCenterOffset); } } - d->updatingHorizontalAnchor = false; + updatingHorizontalAnchor = false; } else { - qmlInfo(d->item) << "Anchor loop detected on horizontal anchor."; + // ### Make this certain :) + qmlInfo(item) << "Possible anchor loop detected on horizontal anchor."; } } @@ -588,29 +520,22 @@ void QFxAnchors::setTop(const QFxAnchorLine &edge) if (!d->checkVAnchorValid(edge)) return; - d->usedAnchors |= HasTopAnchor; + if (edge.item) + d->usedAnchors |= HasTopAnchor; + else + d->usedAnchors &= ~HasTopAnchor; d->checkVValid(); + d->remDepend(d->top.item); d->top = edge; + d->addDepend(d->top.item); + d->updateVerticalAnchors(); } void QFxAnchors::resetTop() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasTopAnchor; - - //clear binding - QmlMetaProperty prop(this, "top"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(topMarginChanged()), this, SLOT(updateVerticalAnchors())); - disconnect(d->top.item, 0, this, 0); - - updateVerticalAnchors(); + setTop(QFxAnchorLine()); } QFxAnchorLine QFxAnchors::bottom() const @@ -625,29 +550,22 @@ void QFxAnchors::setBottom(const QFxAnchorLine &edge) if (!d->checkVAnchorValid(edge)) return; - d->usedAnchors |= HasBottomAnchor; + if (edge.item) + d->usedAnchors |= HasBottomAnchor; + else + d->usedAnchors &= ~HasBottomAnchor; d->checkVValid(); + d->remDepend(d->bottom.item); d->bottom = edge; + d->addDepend(d->bottom.item); + d->updateVerticalAnchors(); } void QFxAnchors::resetBottom() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasBottomAnchor; - - //clear binding - QmlMetaProperty prop(this, "bottom"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(bottomMarginChanged()), this, SLOT(updateVerticalAnchors())); - disconnect(d->bottom.item, 0, this, 0); - - updateVerticalAnchors(); + setBottom(QFxAnchorLine()); } QFxAnchorLine QFxAnchors::verticalCenter() const @@ -662,29 +580,22 @@ void QFxAnchors::setVerticalCenter(const QFxAnchorLine &edge) if (!d->checkVAnchorValid(edge)) return; - d->usedAnchors |= HasVCenterAnchor; + if (edge.item) + d->usedAnchors |= HasVCenterAnchor; + else + d->usedAnchors &= ~HasVCenterAnchor; d->checkVValid(); + d->remDepend(d->vCenter.item); d->vCenter = edge; + d->addDepend(d->vCenter.item); + d->updateVerticalAnchors(); } void QFxAnchors::resetVerticalCenter() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasVCenterAnchor; - - //clear binding - QmlMetaProperty prop(this, "verticalCenter"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); - disconnect(d->vCenter.item, 0, this, 0); - - updateVerticalAnchors(); + setVerticalCenter(QFxAnchorLine()); } QFxAnchorLine QFxAnchors::left() const @@ -699,29 +610,22 @@ void QFxAnchors::setLeft(const QFxAnchorLine &edge) if (!d->checkHAnchorValid(edge)) return; - d->usedAnchors |= HasLeftAnchor; + if (edge.item) + d->usedAnchors |= HasLeftAnchor; + else + d->usedAnchors &= ~HasLeftAnchor; d->checkHValid(); + d->remDepend(d->left.item); d->left = edge; + d->addDepend(d->left.item); + d->updateHorizontalAnchors(); } void QFxAnchors::resetLeft() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasLeftAnchor; - - //clear binding - QmlMetaProperty prop(this, "left"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(leftMarginChanged()), this, SLOT(updateHorizontalAnchors())); - disconnect(d->left.item, 0, this, 0); - - updateHorizontalAnchors(); + setLeft(QFxAnchorLine()); } QFxAnchorLine QFxAnchors::right() const @@ -736,29 +640,23 @@ void QFxAnchors::setRight(const QFxAnchorLine &edge) if (!d->checkHAnchorValid(edge)) return; - d->usedAnchors |= HasRightAnchor; + if (edge.item) + d->usedAnchors |= HasRightAnchor; + else + d->usedAnchors &= ~HasRightAnchor; d->checkHValid(); + d->remDepend(d->right.item); d->right = edge; + d->addDepend(d->right.item); + + d->updateHorizontalAnchors(); } void QFxAnchors::resetRight() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasRightAnchor; - - //clear binding - QmlMetaProperty prop(this, "right"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(rightMarginChanged()), this, SLOT(updateHorizontalAnchors())); - disconnect(d->right.item, 0, this, 0); - - updateHorizontalAnchors(); + setRight(QFxAnchorLine()); } QFxAnchorLine QFxAnchors::horizontalCenter() const @@ -773,29 +671,22 @@ void QFxAnchors::setHorizontalCenter(const QFxAnchorLine &edge) if (!d->checkHAnchorValid(edge)) return; - d->usedAnchors |= HasHCenterAnchor; + if (edge.item) + d->usedAnchors |= HasHCenterAnchor; + else + d->usedAnchors &= ~HasHCenterAnchor; d->checkHValid(); + d->remDepend(d->hCenter.item); d->hCenter = edge; + d->addDepend(d->hCenter.item); + d->updateHorizontalAnchors(); } void QFxAnchors::resetHorizontalCenter() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasHCenterAnchor; - - //clear binding - QmlMetaProperty prop(this, "horizontalCenter"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); - disconnect(d->hCenter.item, 0, this, 0); - - updateHorizontalAnchors(); + setHorizontalCenter(QFxAnchorLine()); } int QFxAnchors::leftMargin() const @@ -888,50 +779,6 @@ void QFxAnchors::setVerticalCenterOffset(int offset) emit verticalCenterOffsetChanged(); } -#if 0 -/*! - \property QFxAnchors::baseline - \brief what the baseline of the item should be anchored to (aligned with). - - The baseline of a Text item is the imaginary line on which the text sits. Controls containing - text usually set their baseline to the baseline of their text. - - For non-text items, a default baseline offset of two-thirds of the item's height is used - to determine the baseline. -*/ -int QFxAnchors::baseline() const -{ - return d->item->baseline(); -} - -void QFxAnchors::setBaseline(int baseline) -{ - d->usedAnchors |= HasBaselineAnchor; - - if (d->usedAnchors & HasTopAnchor && d->usedAnchors & HasBottomAnchor) { - qmlInfo(d->item) << "Can't specify top, bottom, and baseline anchors"; - return; - } - - if (d->usedAnchors & HasTopAnchor) { - int hoffset = baseline - d->item->baseline(); - d->item->setHeight(d->item->height() + hoffset); - } else { - if (d->usedAnchors & HasBottomAnchor) { - int hoffset = d->item->baseline() - baseline; - d->item->setHeight(d->item->height() + hoffset); - } - - int boffset = d->item->baseline() - d->item->top(); - QFxItem *parentItem = d->item->itemParent(); - if (parentItem) - d->item->setY(baseline - boffset - parentItem->top()); - else - d->item->setY(baseline - boffset); - } -} -#endif - QFxAnchors::UsedAnchors QFxAnchors::usedAnchors() const { Q_D(const QFxAnchors); diff --git a/src/declarative/fx/qfxanchors.h b/src/declarative/fx/qfxanchors.h index 5a8cc1a..2c59266 100644 --- a/src/declarative/fx/qfxanchors.h +++ b/src/declarative/fx/qfxanchors.h @@ -80,6 +80,7 @@ public: Q_DECLARE_METATYPE(QFxAnchorLine); +class QFxAnchorsPrivate; class Q_DECLARATIVE_EXPORT QFxAnchors : public QObject { Q_OBJECT @@ -101,6 +102,7 @@ class Q_DECLARATIVE_EXPORT QFxAnchors : public QObject public: QFxAnchors(QObject *parent=0); + virtual ~QFxAnchors(); enum UsedAnchor { HasLeftAnchor = 0x01, @@ -167,9 +169,6 @@ public: void setItem(QFxItem *item); - void connectHAnchors(); - void connectVAnchors(); - Q_SIGNALS: void leftMarginChanged(); void rightMarginChanged(); @@ -178,13 +177,8 @@ Q_SIGNALS: void verticalCenterOffsetChanged(); void horizontalCenterOffsetChanged(); -private Q_SLOTS: - void fillChanged(); - void updateHorizontalAnchors(); - void updateVerticalAnchors(); - private: - //### should item be a friend? (and make some of the public methods private or protected) + friend class QFxItem; Q_DISABLE_COPY(QFxAnchors) Q_DECLARE_PRIVATE(QFxAnchors) }; diff --git a/src/declarative/fx/qfxanchors_p.h b/src/declarative/fx/qfxanchors_p.h index 82c2086..b90380a 100644 --- a/src/declarative/fx/qfxanchors_p.h +++ b/src/declarative/fx/qfxanchors_p.h @@ -63,9 +63,10 @@ class QFxAnchorsPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QFxAnchors) public: QFxAnchorsPrivate() - : item(0), usedAnchors(0), fill(0), centeredIn(0), leftMargin(0), rightMargin(0), - topMargin(0), bottomMargin(0), vCenterOffset(0), hCenterOffset(0), - updatingHorizontalAnchor(false), updatingVerticalAnchor(false) + : updatingMe(false), updatingHorizontalAnchor(false), + updatingVerticalAnchor(false), item(0), usedAnchors(0), fill(0), + centeredIn(0), leftMargin(0), rightMargin(0), topMargin(0), + bottomMargin(0), vCenterOffset(0), hCenterOffset(0) { } @@ -73,14 +74,37 @@ public: { } + void clearItem(QFxItem *); + + void addDepend(QFxItem *); + void remDepend(QFxItem *); + bool isItemComplete() const; + + bool updatingMe:1; + bool updatingHorizontalAnchor:1; + bool updatingVerticalAnchor:1; + + void setItemHeight(qreal); + void setItemWidth(qreal); + void setItemX(qreal); + void setItemY(qreal); + void setItemPos(const QPointF &); + + void updateOnComplete(); + void updateMe(); + void update(QFxItem *, const QRectF &, const QRectF &); + bool checkHValid() const; bool checkVValid() const; bool checkHAnchorValid(QFxAnchorLine anchor) const; bool checkVAnchorValid(QFxAnchorLine anchor) const; - void connectHHelper(const QFxAnchorLine &anchorLine); - void connectVHelper(const QFxAnchorLine &anchorLine); bool calcStretch(const QFxAnchorLine &edge1, const QFxAnchorLine &edge2, int offset1, int offset2, QFxAnchorLine::AnchorLine line, int &stretch); + void updateHorizontalAnchors(); + void updateVerticalAnchors(); + void fillChanged(); + void centeredInChanged(); + QFxItem *item; QFxAnchors::UsedAnchors usedAnchors; @@ -101,8 +125,6 @@ public: int vCenterOffset; int hCenterOffset; - bool updatingHorizontalAnchor; - bool updatingVerticalAnchor; }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxflipable.cpp b/src/declarative/fx/qfxflipable.cpp index 24ae428..9804004 100644 --- a/src/declarative/fx/qfxflipable.cpp +++ b/src/declarative/fx/qfxflipable.cpp @@ -296,6 +296,7 @@ QFxFlipable::Side QFxFlipable::side() const //(the logic here should be kept in sync with setBackTransform and setRotation) void QFxFlipable::transformChanged(const QSimpleCanvas::Matrix &trans) { + qWarning("Transform changed"); Q_D(QFxFlipable); QPointF p1(0, 0); QPointF p2(1, 0); diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index b737615..3cbcd6a 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -52,6 +52,7 @@ #include "qmlengine.h" #include "qmlstate.h" #include "qlistmodelinterface.h" +#include "qfxanchors_p.h" #include "qfxtransform.h" #include "qfxscalegrid.h" @@ -434,6 +435,14 @@ void QFxItem::doUpdate() QFxItem::~QFxItem() { Q_D(QFxItem); + for (int ii = 0; ii < d->dependantAnchors.count(); ++ii) { + QFxAnchors *anchor = d->dependantAnchors.at(ii); + anchor->d_func()->clearItem(this); + } + for (int ii = 0; ii < d->dependantAnchors.count(); ++ii) { + QFxAnchors *anchor = d->dependantAnchors.at(ii); + anchor->d_func()->updateOnComplete(); + } delete d->_anchorLines; d->_anchorLines = 0; } @@ -1062,85 +1071,30 @@ void QFxItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { Q_D(QFxItem); - if (newGeometry.width() != oldGeometry.width()) { - int xoffset = oldGeometry.width() - newGeometry.width(); - d->handleWidthChange(xoffset); - } - if (newGeometry.height() != oldGeometry.height()) { - int yoffset = oldGeometry.height() - newGeometry.height(); - d->handleHeightChange(yoffset); - } + if (d->_anchors) + d->_anchors->d_func()->updateMe(); - if (newGeometry.x() != oldGeometry.x()) { - emit leftChanged(); - emit hcenterChanged(); - emit rightChanged(); + if (newGeometry.size() != oldGeometry.size()) { + if (rotation() && transformOrigin() != QFxItem::TopLeft) + setRotation(rotation()); + if (scale() && transformOrigin() != QFxItem::TopLeft) + setScale(scale()); } - if (newGeometry.y() != oldGeometry.y()) { + if (newGeometry.x() != oldGeometry.x()) + emit leftChanged(); + if (newGeometry.width() != oldGeometry.width()) + emit widthChanged(); + if (newGeometry.y() != oldGeometry.y()) emit topChanged(); - emit vcenterChanged(); - emit bottomChanged(); - } -} - -void QFxItemPrivate::handleWidthChange(int xoffset) -{ - Q_Q(QFxItem); - if (!_anchors) { - emit q->hcenterChanged(); - emit q->rightChanged(); - } else { - QFxAnchors::UsedAnchors used = anchors()->usedAnchors(); - if (used & QFxAnchors::HasHCenterAnchor) { - q->setX(q->x() + xoffset/2); - emit q->rightChanged(); - } else if ((used & QFxAnchors::HasRightAnchor) && !(used & QFxAnchors::HasLeftAnchor)) { - q->setX(q->x() + xoffset); - emit q->hcenterChanged(); - } else { - emit q->hcenterChanged(); - emit q->rightChanged(); - } - } - if (q->rotation() && q->transformOrigin() != QFxItem::TopLeft) - q->setRotation(q->rotation()); - if (q->scale() && q->transformOrigin() != QFxItem::TopLeft) - q->setScale(q->scale()); - emit q->widthChanged(); -} + if (newGeometry.height() != oldGeometry.height()) + emit heightChanged(); -void QFxItemPrivate::handleHeightChange(int yoffset) -{ - Q_Q(QFxItem); - if (!_anchors) { - emit q->vcenterChanged(); - emit q->bottomChanged(); - emit q->baselineChanged(); - } else { - QFxAnchors::UsedAnchors used = anchors()->usedAnchors(); - if (used & QFxAnchors::HasBaselineAnchor) { - q->setY(q->y() + yoffset - q->baselineOffset()); - emit q->bottomChanged(); - emit q->vcenterChanged(); - } else if (used & QFxAnchors::HasVCenterAnchor) { - q->setY(q->y() + yoffset/2); - emit q->bottomChanged(); - } else if ((used & QFxAnchors::HasBottomAnchor) && !(used & QFxAnchors::HasTopAnchor)) { - q->setY(q->y() + yoffset); - emit q->vcenterChanged(); - } else { - emit q->vcenterChanged(); - emit q->bottomChanged(); - emit q->baselineChanged(); - } + for(int ii = 0; ii < d->dependantAnchors.count(); ++ii) { + QFxAnchors *anchor = d->dependantAnchors.at(ii); + anchor->d_func()->update(this, newGeometry, oldGeometry); } - if (q->rotation() && q->transformOrigin() != QFxItem::TopLeft) - q->setRotation(q->rotation()); - if (q->scale() && q->transformOrigin() != QFxItem::TopLeft) - q->setScale(q->scale()); - emit q->heightChanged(); } /*! @@ -1483,7 +1437,6 @@ void QFxItem::setBaselineOffset(int offset) d->_baselineOffset = offset; emit baselineOffsetChanged(); - emit baselineChanged(); } /*! @@ -2075,10 +2028,8 @@ void QFxItem::componentComplete() d->_componentComplete = true; if (d->_stateGroup) d->_stateGroup->componentComplete(); - if (d->_anchors) { - d->anchors()->connectHAnchors(); - d->anchors()->connectVAnchors(); - } + if (d->_anchors) + d->anchors()->d_func()->updateOnComplete(); if (!d->_transform.isEmpty()) updateTransform(); } diff --git a/src/declarative/fx/qfxitem.h b/src/declarative/fx/qfxitem.h index 549c9c2..437709f 100644 --- a/src/declarative/fx/qfxitem.h +++ b/src/declarative/fx/qfxitem.h @@ -213,14 +213,9 @@ public Q_SLOTS: Q_SIGNALS: void leftChanged(); - void rightChanged(); void widthChanged(); void heightChanged(); void topChanged(); - void bottomChanged(); - void hcenterChanged(); - void vcenterChanged(); - void baselineChanged(); void baselineOffsetChanged(); void stateChanged(const QString &); void focusChanged(); diff --git a/src/declarative/fx/qfxitem_p.h b/src/declarative/fx/qfxitem_p.h index f2da3ba..8ca7fda 100644 --- a/src/declarative/fx/qfxitem_p.h +++ b/src/declarative/fx/qfxitem_p.h @@ -129,6 +129,7 @@ public: } return _anchors; } + QList dependantAnchors; QFxAnchors *_anchors; QFxContents *_contents; QFxItem *qmlItem; @@ -171,9 +172,6 @@ public: QmlStateGroup *states(); QmlStateGroup *_stateGroup; - - void handleWidthChange(int xoffset); - void handleHeightChange(int xoffset); }; QT_END_NAMESPACE -- cgit v0.12