From 61943383ccff409d60d9837d58e4372dc6f22f23 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 22 May 2009 10:32:16 +1000 Subject: Add support for baseline anchoring. --- src/declarative/fx/qfxanchors.cpp | 52 ++++++++++++++++++++-- src/declarative/fx/qfxanchors.h | 5 +++ src/declarative/fx/qfxanchors_p.h | 1 + src/declarative/fx/qfxitem.cpp | 55 ++++++++++-------------- src/declarative/fx/qfxitem.h | 2 + src/declarative/fx/qfxitem_p.h | 1 + src/declarative/fx/qfxtext.cpp | 4 -- tests/auto/declarative/anchors/data/illegal1.qml | 10 +++++ tests/auto/declarative/anchors/data/illegal2.qml | 11 +++++ tests/auto/declarative/anchors/data/illegal3.qml | 10 +++++ tests/auto/declarative/anchors/tst_anchors.cpp | 43 ++++++++++++++++++ 11 files changed, 154 insertions(+), 40 deletions(-) create mode 100644 tests/auto/declarative/anchors/data/illegal1.qml create mode 100644 tests/auto/declarative/anchors/data/illegal2.qml create mode 100644 tests/auto/declarative/anchors/data/illegal3.qml diff --git a/src/declarative/fx/qfxanchors.cpp b/src/declarative/fx/qfxanchors.cpp index 235511f..681a9fa 100644 --- a/src/declarative/fx/qfxanchors.cpp +++ b/src/declarative/fx/qfxanchors.cpp @@ -146,6 +146,7 @@ QFxAnchors::~QFxAnchors() d->remDepend(d->bottom.item); d->remDepend(d->vCenter.item); d->remDepend(d->hCenter.item); + d->remDepend(d->baseline.item); } void QFxAnchorsPrivate::fillChanged() @@ -210,6 +211,10 @@ void QFxAnchorsPrivate::clearItem(QFxItem *item) hCenter.item = 0; usedAnchors &= ~QFxAnchors::HasHCenterAnchor; } + if (baseline.item == item) { + baseline.item = 0; + usedAnchors &= ~QFxAnchors::HasBaselineAnchor; + } } void QFxAnchorsPrivate::addDepend(QFxItem *item) @@ -430,8 +435,6 @@ void QFxAnchorsPrivate::updateVerticalAnchors() } else if (bottom.item->itemParent() == item->itemParent()) { setItemY(position(bottom.item, bottom.anchorLine) - item->height() - bottomMargin); } - - } else if (usedAnchors & QFxAnchors::HasVCenterAnchor) { //(stetching handled above) @@ -442,6 +445,11 @@ void QFxAnchorsPrivate::updateVerticalAnchors() } else if (vCenter.item->itemParent() == item->itemParent()) { setItemY(position(vCenter.item, vCenter.anchorLine) - item->height()/2 + vCenterOffset); } + } else if (usedAnchors & QFxAnchors::HasBaselineAnchor) { + //Handle baseline + if (baseline.item->itemParent() == item->itemParent()) { + setItemY(position(baseline.item, baseline.anchorLine) - item->baselineOffset()); + } } updatingVerticalAnchor = false; } else { @@ -599,6 +607,36 @@ void QFxAnchors::resetVerticalCenter() setVerticalCenter(QFxAnchorLine()); } +QFxAnchorLine QFxAnchors::baseline() const +{ + Q_D(const QFxAnchors); + return d->baseline; +} + +void QFxAnchors::setBaseline(const QFxAnchorLine &edge) +{ + Q_D(QFxAnchors); + if (!d->checkVAnchorValid(edge)) + return; + + if (edge.item) + d->usedAnchors |= HasBaselineAnchor; + else + d->usedAnchors &= ~HasBaselineAnchor; + + d->checkVValid(); + + d->remDepend(d->baseline.item); + d->baseline = edge; + d->addDepend(d->baseline.item); + d->updateVerticalAnchors(); +} + +void QFxAnchors::resetBaseline() +{ + setBaseline(QFxAnchorLine()); +} + QFxAnchorLine QFxAnchors::left() const { Q_D(const QFxAnchors); @@ -797,7 +835,7 @@ bool QFxAnchorsPrivate::checkHValid() const if (usedAnchors & QFxAnchors::HasLeftAnchor && usedAnchors & QFxAnchors::HasRightAnchor && usedAnchors & QFxAnchors::HasHCenterAnchor) { - qmlInfo(item) << "Can't specify left, right, and hcenter anchors"; + qmlInfo(item) << "Can't specify left, right, and hcenter anchors."; return false; } @@ -822,7 +860,13 @@ bool QFxAnchorsPrivate::checkVValid() const if (usedAnchors & QFxAnchors::HasTopAnchor && usedAnchors & QFxAnchors::HasBottomAnchor && usedAnchors & QFxAnchors::HasVCenterAnchor) { - qmlInfo(item) << "Can't specify top, bottom, and vcenter anchors"; + qmlInfo(item) << "Can't specify top, bottom, and vcenter anchors."; + return false; + } else if (usedAnchors & QFxAnchors::HasBaselineAnchor && + (usedAnchors & QFxAnchors::HasTopAnchor || + usedAnchors & QFxAnchors::HasBottomAnchor || + usedAnchors & QFxAnchors::HasVCenterAnchor)) { + qmlInfo(item) << "Baseline anchor can't be used in conjunction with top, bottom, or vcenter anchors."; return false; } diff --git a/src/declarative/fx/qfxanchors.h b/src/declarative/fx/qfxanchors.h index 9d776ab..3f142c4 100644 --- a/src/declarative/fx/qfxanchors.h +++ b/src/declarative/fx/qfxanchors.h @@ -91,6 +91,7 @@ class Q_DECLARATIVE_EXPORT QFxAnchors : public QObject Q_PROPERTY(QFxAnchorLine top READ top WRITE setTop RESET resetTop); Q_PROPERTY(QFxAnchorLine bottom READ bottom WRITE setBottom RESET resetBottom); Q_PROPERTY(QFxAnchorLine verticalCenter READ verticalCenter WRITE setVerticalCenter RESET resetVerticalCenter); + Q_PROPERTY(QFxAnchorLine baseline READ baseline WRITE setBaseline RESET resetBaseline); Q_PROPERTY(int leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged); Q_PROPERTY(int rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged); Q_PROPERTY(int horizontalCenterOffset READ horizontalCenterOffset WRITE setHorizontalCenterOffset NOTIFY horizontalCenterOffsetChanged()); @@ -141,6 +142,10 @@ public: void setVerticalCenter(const QFxAnchorLine &edge); void resetVerticalCenter(); + QFxAnchorLine baseline() const; + void setBaseline(const QFxAnchorLine &edge); + void resetBaseline(); + int leftMargin() const; void setLeftMargin(int); diff --git a/src/declarative/fx/qfxanchors_p.h b/src/declarative/fx/qfxanchors_p.h index b90380a..32d8b75 100644 --- a/src/declarative/fx/qfxanchors_p.h +++ b/src/declarative/fx/qfxanchors_p.h @@ -117,6 +117,7 @@ public: QFxAnchorLine bottom; QFxAnchorLine vCenter; QFxAnchorLine hCenter; + QFxAnchorLine baseline; int leftMargin; int rightMargin; diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index 3cbcd6a..561a124 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -259,24 +259,10 @@ void QFxContents::setItem(QFxItem *item) */ /*! - \fn void QFxItem::baselineChanged() - - This signal is emitted when the baseline of the item changes. - - The baseline may change in response to a change to the baselineOffset - property or due to the geometry of the item changing. -*/ - -/*! \fn void QFxItem::baselineOffsetChanged() - This signal is emitted when the baseline of the item is changed - via the baselineOffset property. - - The baseline corresponds to the baseline of the text contained in - the item. It is useful for aligning the text in items placed - beside each other. The default baseline is positioned at - 2/3 of the height of the item. + This signal is emitted when the baseline offset of the item + is changed. */ /*! @@ -286,24 +272,12 @@ void QFxContents::setItem(QFxItem *item) */ /*! - \fn void QFxItem::rightChanged() - - This signal is emitted when the right coordinate of the item changes. -*/ - -/*! \fn void QFxItem::topChanged() This signal is emitted when the top coordinate of the item changes. */ /*! - \fn void QFxItem::bottomChanged() - - This signal is emitted when the bottom coordinate of the item changes. -*/ - -/*! \fn void QFxItem::widthChanged() This signal is emitted when the width of the item changes. @@ -1282,6 +1256,15 @@ QFxAnchorLine QFxItem::verticalCenter() const } /*! + \internal +*/ +QFxAnchorLine QFxItem::baseline() const +{ + Q_D(const QFxItem); + return d->anchorLines()->baseline; +} + +/*! \property QFxItem::top One of the anchor lines of the item. @@ -1336,6 +1319,7 @@ QFxAnchorLine QFxItem::verticalCenter() const \qmlproperty AnchorLine Item::right \qmlproperty AnchorLine Item::horizontalCenter \qmlproperty AnchorLine Item::verticalCenter + \qmlproperty AnchorLine Item::baseline The anchor lines of the item. @@ -1349,6 +1333,7 @@ QFxAnchorLine QFxItem::verticalCenter() const \qmlproperty AnchorLine Item::anchors.right \qmlproperty AnchorLine Item::anchors.horizontalCenter \qmlproperty AnchorLine Item::anchors.verticalCenter + \qmlproperty AnchorLine Item::anchors.baseline \qmlproperty Item Item::anchors.fill @@ -1408,20 +1393,19 @@ QFxAnchorLine QFxItem::verticalCenter() const /*! \property QFxItem::baselineOffset - \brief The position of the item's baseline in global (scene) coordinates. + \brief The position of the item's baseline in local coordinates. 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. + For non-text items, a default baseline offset of 0 is used. */ int QFxItem::baselineOffset() const { Q_D(const QFxItem); if (!d->_baselineOffset.isValid()) { - return height()*2/3; //### default baseline is 2/3 of the way to the bottom of the item + return 0; } else return d->_baselineOffset; } @@ -1437,6 +1421,11 @@ void QFxItem::setBaselineOffset(int offset) d->_baselineOffset = offset; emit baselineOffsetChanged(); + + for(int ii = 0; ii < d->dependantAnchors.count(); ++ii) { + QFxAnchors *anchor = d->dependantAnchors.at(ii); + anchor->d_func()->updateVerticalAnchors(); + } } /*! @@ -2100,6 +2089,8 @@ QFxItemPrivate::AnchorLines::AnchorLines(QFxItem *q) bottom.anchorLine = QFxAnchorLine::Bottom; vCenter.item = q; vCenter.anchorLine = QFxAnchorLine::VCenter; + baseline.item = q; + baseline.anchorLine = QFxAnchorLine::Baseline; } QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxitem.h b/src/declarative/fx/qfxitem.h index d34a9fb..0b4f897 100644 --- a/src/declarative/fx/qfxitem.h +++ b/src/declarative/fx/qfxitem.h @@ -127,6 +127,7 @@ class Q_DECLARATIVE_EXPORT QFxItem : public QSimpleCanvasItem, public QmlParserS Q_PROPERTY(QFxAnchorLine top READ top) Q_PROPERTY(QFxAnchorLine bottom READ bottom) Q_PROPERTY(QFxAnchorLine verticalCenter READ verticalCenter) + Q_PROPERTY(QFxAnchorLine baseline READ baseline) Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged) Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged) Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged) @@ -258,6 +259,7 @@ private: QFxAnchorLine top() const; QFxAnchorLine bottom() const; QFxAnchorLine verticalCenter() const; + QFxAnchorLine baseline() const; void init(QFxItem *parent); friend class QmlStatePrivate; diff --git a/src/declarative/fx/qfxitem_p.h b/src/declarative/fx/qfxitem_p.h index 85ce171..b5f9554 100644 --- a/src/declarative/fx/qfxitem_p.h +++ b/src/declarative/fx/qfxitem_p.h @@ -157,6 +157,7 @@ public: QFxAnchorLine top; QFxAnchorLine bottom; QFxAnchorLine vCenter; + QFxAnchorLine baseline; }; mutable AnchorLines *_anchorLines; AnchorLines *anchorLines() const { diff --git a/src/declarative/fx/qfxtext.cpp b/src/declarative/fx/qfxtext.cpp index e84255d..2542413 100644 --- a/src/declarative/fx/qfxtext.cpp +++ b/src/declarative/fx/qfxtext.cpp @@ -571,7 +571,6 @@ QSize QFxTextPrivate::setupTextLayout(QTextLayout *layout) QFont f; if (_font) f = _font->font(); QFontMetrics fm = QFontMetrics(f); - int leading = fm.leading(); int height = 0; qreal widthUsed = 0; qreal lineWidth = 0; @@ -592,9 +591,6 @@ QSize QFxTextPrivate::setupTextLayout(QTextLayout *layout) } layout->endLayout(); - if (layout->lineCount() == 1) - height -= leading; - for (int i = 0; i < layout->lineCount(); ++i) { QTextLine line = layout->lineAt(i); widthUsed = qMax(widthUsed, line.naturalTextWidth()); diff --git a/tests/auto/declarative/anchors/data/illegal1.qml b/tests/auto/declarative/anchors/data/illegal1.qml new file mode 100644 index 0000000..635bf95 --- /dev/null +++ b/tests/auto/declarative/anchors/data/illegal1.qml @@ -0,0 +1,10 @@ +Rect { + id: rect + width: 120; height: 200; color: "white" + Rect { id: TheRect; width: 100; height: 100 } + Rect { + anchors.left: TheRect.left + anchors.right: TheRect.right + anchors.horizontalCenter: TheRect.horizontalCenter + } +} diff --git a/tests/auto/declarative/anchors/data/illegal2.qml b/tests/auto/declarative/anchors/data/illegal2.qml new file mode 100644 index 0000000..425d0e4 --- /dev/null +++ b/tests/auto/declarative/anchors/data/illegal2.qml @@ -0,0 +1,11 @@ +Rect { + id: rect + width: 120; height: 200; color: "white" + Text { id: Text1; text: "Hello" } + Text { + id: Text2; + anchors.baseline: Text1.baseline; + anchors.top: Text1.top; + text: "World" + } +} diff --git a/tests/auto/declarative/anchors/data/illegal3.qml b/tests/auto/declarative/anchors/data/illegal3.qml new file mode 100644 index 0000000..fa48b78 --- /dev/null +++ b/tests/auto/declarative/anchors/data/illegal3.qml @@ -0,0 +1,10 @@ +Rect { + id: rect + width: 120; height: 200; color: "white" + Item { + Rect { id: TheRect; width: 100; height: 100 } + } + Rect { + anchors.left: TheRect.left + } +} diff --git a/tests/auto/declarative/anchors/tst_anchors.cpp b/tests/auto/declarative/anchors/tst_anchors.cpp index 8087d6e..587b4ab 100644 --- a/tests/auto/declarative/anchors/tst_anchors.cpp +++ b/tests/auto/declarative/anchors/tst_anchors.cpp @@ -16,6 +16,7 @@ public: private slots: void basicAnchors(); void loops(); + void illegalSets(); }; /* @@ -118,6 +119,48 @@ void tst_anchors::loops() } } +void tst_anchors::illegalSets() +{ + { + QFxView *view = new QFxView; + + view->setUrl(QUrl("file://" SRCDIR "/data/illegal1.qml")); + + //### ignoreMessage doesn't seem to work + //QTest::ignoreMessage(QtWarningMsg, "QML QFxRect (unknown location): Can't specify left, right, and hcenter anchors."); + view->execute(); + qApp->processEvents(); + + delete view; + } + + { + QFxView *view = new QFxView; + + view->setUrl(QUrl("file://" SRCDIR "/data/illegal2.qml")); + + //### ignoreMessage doesn't seem to work here + //QTest::ignoreMessage(QtWarningMsg, "QML QFxText (unknown location): Baseline anchor can't be used in conjunction with top, bottom, or vcenter anchors."); + view->execute(); + //qApp->processEvents(); + + delete view; + } + + { + QFxView *view = new QFxView; + + view->setUrl(QUrl("file://" SRCDIR "/data/illegal3.qml")); + + //### ignoreMessage doesn't seem to work here + //QTest::ignoreMessage(QtWarningMsg, "Can't anchor to an item that isn't a parent or sibling."); + view->execute(); + qApp->processEvents(); + + delete view; + } +} + QTEST_MAIN(tst_anchors) #include "tst_anchors.moc" -- cgit v0.12