diff options
-rw-r--r-- | src/quick/items/qquicktext.cpp | 10 | ||||
-rw-r--r-- | src/quick/items/qquicktext_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquicktextedit.cpp | 47 | ||||
-rw-r--r-- | src/quick/items/qquicktextedit_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquicktextinput.cpp | 52 | ||||
-rw-r--r-- | src/quick/items/qquicktextinput_p.h | 2 | ||||
-rw-r--r-- | src/quick/items/qquicktextinput_p_p.h | 2 | ||||
-rw-r--r-- | tests/auto/quick/qquicktext/tst_qquicktext.cpp | 45 | ||||
-rw-r--r-- | tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp | 148 | ||||
-rw-r--r-- | tests/auto/quick/qquicktextinput/data/horizontalAlignment_RightToLeft.qml | 2 | ||||
-rw-r--r-- | tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp | 212 |
11 files changed, 460 insertions, 62 deletions
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 2407ade988..4d39f0baad 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -2039,6 +2039,16 @@ QRectF QQuickText::boundingRect() const return rect; } +QRectF QQuickText::clipRect() const +{ + Q_D(const QQuickText); + + QRectF rect = QQuickImplicitSizeItem::clipRect(); + if (d->style != Normal) + rect.adjust(-1, 0, 1, 2); + return rect; +} + /*! \internal */ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index e643d1dfb9..e69159eac9 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -197,6 +197,7 @@ public: qreal contentHeight() const; QRectF boundingRect() const; + QRectF clipRect() const; Q_INVOKABLE void doLayout(); Q_SIGNALS: diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 59d78acc4b..cd5f262f37 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1818,7 +1818,48 @@ void QQuickTextEdit::updateSelectionMarkers() QRectF QQuickTextEdit::boundingRect() const { Q_D(const QQuickTextEdit); - QRectF r = QQuickImplicitSizeItem::boundingRect(); + QRectF r(0, -d->yoff, d->contentSize.width(), d->contentSize.height()); + int cursorWidth = 1; + if (d->cursor) + cursorWidth = 0; + else if (!d->document->isEmpty()) + cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor + + // Could include font max left/right bearings to either side of rectangle. + + r.setRight(r.right() + cursorWidth); + + qreal h = height(); + switch (d->vAlign) { + case AlignTop: + break; + case AlignBottom: + r.moveTop(h - r.height()); + break; + case AlignVCenter: + r.moveTop((h - r.height()) / 2); + break; + } + + qreal w = width(); + switch (d->hAlign) { + case AlignLeft: + break; + case AlignRight: + r.moveLeft(w - r.width()); + break; + case AlignHCenter: + r.moveLeft((w - r.width()) / 2); + break; + } + + return r; +} + +QRectF QQuickTextEdit::clipRect() const +{ + Q_D(const QQuickTextEdit); + QRectF r = QQuickImplicitSizeItem::clipRect(); int cursorWidth = 1; if (d->cursor) cursorWidth = d->cursor->width(); @@ -1828,7 +1869,7 @@ QRectF QQuickTextEdit::boundingRect() const // Could include font max left/right bearings to either side of rectangle. r.setRight(r.right() + cursorWidth); - return r.translated(0,d->yoff); + return r; } qreal QQuickTextEditPrivate::getImplicitWidth() const @@ -1903,7 +1944,7 @@ void QQuickTextEdit::updateSize() if (!widthValid() && !d->requireImplicitWidth) iWidth = newWidth; - qreal newHeight = d->document->isEmpty() ? fm.height() : d->document->size().height(); + qreal newHeight = d->document->isEmpty() ? qCeil(fm.height()) : d->document->size().height(); if (iWidth > -1) setImplicitSize(iWidth, newHeight); diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h index b28ec9d7d7..9f904cae67 100644 --- a/src/quick/items/qquicktextedit_p.h +++ b/src/quick/items/qquicktextedit_p.h @@ -229,6 +229,7 @@ public: Q_INVOKABLE void moveCursorSelection(int pos, SelectionMode mode); QRectF boundingRect() const; + QRectF clipRect() const; bool isInputMethodComposing() const; diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 863729416d..c9019c6670 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -1655,7 +1655,7 @@ void QQuickTextInputPrivate::updateVerticalScroll() Q_Q(QQuickTextInput); const int preeditLength = m_textLayout.preeditAreaText().length(); const qreal height = qMax<qreal>(0, q->height()); - qreal heightUsed = boundingRect.height(); + qreal heightUsed = contentSize.height(); qreal previousScroll = vscroll; if (!autoScroll || heightUsed <= height) { @@ -2265,7 +2265,7 @@ bool QQuickTextInput::canRedo() const qreal QQuickTextInput::contentWidth() const { Q_D(const QQuickTextInput); - return d->boundingRect.width(); + return d->contentSize.width(); } /*! @@ -2278,7 +2278,7 @@ qreal QQuickTextInput::contentWidth() const qreal QQuickTextInput::contentHeight() const { Q_D(const QQuickTextInput); - return d->boundingRect.height(); + return d->contentSize.height(); } void QQuickTextInput::moveCursorSelection(int position) @@ -2597,10 +2597,36 @@ QRectF QQuickTextInput::boundingRect() const { Q_D(const QQuickTextInput); + int cursorWidth = d->cursorItem ? 0 : 1; + + qreal hscroll = d->hscroll; + if (!d->autoScroll || d->contentSize.width() < width()) { + switch (effectiveHAlign()) { + case AlignLeft: + break; + case AlignRight: + hscroll += d->contentSize.width() - width(); + break; + case AlignHCenter: + hscroll += (d->contentSize.width() - width()) / 2; + break; + } + } + + // Could include font max left/right bearings to either side of rectangle. + QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height()); + r.setRight(r.right() + cursorWidth); + return r; +} + +QRectF QQuickTextInput::clipRect() const +{ + Q_D(const QQuickTextInput); + int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1; // Could include font max left/right bearings to either side of rectangle. - QRectF r = QQuickImplicitSizeItem::boundingRect(); + QRectF r = QQuickImplicitSizeItem::clipRect(); r.setRight(r.right() + cursorWidth); return r; } @@ -2727,7 +2753,6 @@ void QQuickTextInputPrivate::updateLayout() if (!q->isComponentComplete()) return; - const QRectF previousRect = boundingRect; QTextOption option = m_textLayout.textOption(); option.setTextDirection(layoutDirection()); @@ -2736,8 +2761,8 @@ void QQuickTextInputPrivate::updateLayout() m_textLayout.setTextOption(option); m_textLayout.setFont(font); - boundingRect = QRectF(); m_textLayout.beginLayout(); + QTextLine line = m_textLayout.createLine(); if (requireImplicitWidth) { line.setLineWidth(INT_MAX); @@ -2750,12 +2775,14 @@ void QQuickTextInputPrivate::updateLayout() } qreal lineWidth = q->widthValid() ? q->width() : INT_MAX; qreal height = 0; + qreal width = 0; do { line.setLineWidth(lineWidth); - line.setPosition(QPointF(line.position().x(), height)); - boundingRect = boundingRect.united(line.naturalTextRect()); + line.setPosition(QPointF(0, height)); height += line.height(); + width = qMax(width, line.naturalTextWidth()); + line = m_textLayout.createLine(); } while (line.isValid()); m_textLayout.endLayout(); @@ -2765,15 +2792,18 @@ void QQuickTextInputPrivate::updateLayout() textLayoutDirty = true; + const QSizeF previousSize = contentSize; + contentSize = QSizeF(width, height); + updateType = UpdatePaintNode; q->update(); if (!requireImplicitWidth && !q->widthValid()) - q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height())); + q->setImplicitSize(width, height); else - q->setImplicitHeight(qCeil(boundingRect.height())); + q->setImplicitHeight(height); - if (previousRect != boundingRect) + if (previousSize != contentSize) emit q->contentSizeChanged(); } diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h index 9d32eeec60..9a3be0f116 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -245,6 +245,8 @@ public: QVariant inputMethodQuery(Qt::InputMethodQuery property) const; QRectF boundingRect() const; + QRectF clipRect() const; + #ifndef QT_NO_CLIPBOARD bool canPaste() const; #endif diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index 1bc2cf548b..d952b27b6f 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -172,7 +172,7 @@ public: }; QElapsedTimer tripleClickTimer; - QRectF boundingRect; + QSizeF contentSize; QPointF pressPos; QPointF tripleClickStartPoint; diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index 297fa0106f..d1899a62b7 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -114,6 +114,7 @@ private slots: void boundingRect_data(); void boundingRect(); + void clipRect(); void lineLaidOut(); void imgTagsBaseUrl_data(); @@ -1802,6 +1803,50 @@ void tst_qquicktext::boundingRect() QVERIFY(text->boundingRect().height() > line.height()); } +void tst_qquicktext::clipRect() +{ + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\n Text {}", QUrl()); + QScopedPointer<QObject> object(component.create()); + QQuickText *text = qobject_cast<QQuickText *>(object.data()); + QVERIFY(text); + + QTextLayout layout; + layout.setFont(text->font()); + + QCOMPARE(text->clipRect().x(), qreal(0)); + QCOMPARE(text->clipRect().y(), qreal(0)); + QCOMPARE(text->clipRect().width(), text->width()); + QCOMPARE(text->clipRect().height(), text->height()); + + text->setText("Hello World"); + + QCOMPARE(text->clipRect().x(), qreal(0)); + QCOMPARE(text->clipRect().y(), qreal(0)); + QCOMPARE(text->clipRect().width(), text->width()); + QCOMPARE(text->clipRect().height(), text->height()); + + // Clip rect follows the item not content dimensions. + text->setWidth(text->width() / 2); + QCOMPARE(text->clipRect().x(), qreal(0)); + QCOMPARE(text->clipRect().y(), qreal(0)); + QCOMPARE(text->clipRect().width(), text->width()); + QCOMPARE(text->clipRect().height(), text->height()); + + text->setHeight(text->height() * 2); + QCOMPARE(text->clipRect().x(), qreal(0)); + QCOMPARE(text->clipRect().y(), qreal(0)); + QCOMPARE(text->clipRect().width(), text->width()); + QCOMPARE(text->clipRect().height(), text->height()); + + // Setting a style adds a small amount of padding to the clip rect. + text->setStyle(QQuickText::Outline); + QCOMPARE(text->clipRect().x(), qreal(-1)); + QCOMPARE(text->clipRect().y(), qreal(0)); + QCOMPARE(text->clipRect().width(), text->width() + 2); + QCOMPARE(text->clipRect().height(), text->height() + 2); +} + void tst_qquicktext::lineLaidOut() { QQuickView *canvas = createView(testFile("lineLayout.qml")); diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index 1a5f52f941..9c34a7c8d8 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -152,6 +152,8 @@ private slots: void implicitSize_data(); void implicitSize(); void contentSize(); + void boundingRect(); + void clipRect(); void implicitSizeBinding_data(); void implicitSizeBinding(); @@ -2657,6 +2659,152 @@ void tst_qquicktextedit::implicitSizeBinding() QCOMPARE(textObject->height(), textObject->implicitHeight()); } +void tst_qquicktextedit::clipRect() +{ + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\n TextEdit {}", QUrl()); + QScopedPointer<QObject> object(component.create()); + QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(object.data()); + QVERIFY(edit); + + QCOMPARE(edit->clipRect().x(), qreal(0)); + QCOMPARE(edit->clipRect().y(), qreal(0)); + + QCOMPARE(edit->clipRect().width(), edit->width() + edit->cursorRectangle().width()); + QCOMPARE(edit->clipRect().height(), edit->height()); + + edit->setText("Hello World"); + QCOMPARE(edit->clipRect().x(), qreal(0)); + QCOMPARE(edit->clipRect().y(), qreal(0)); + // XXX: TextEdit allows an extra 3 pixels boundary for the cursor beyond it's width for non + // empty text. TextInput doesn't. + QCOMPARE(edit->clipRect().width(), edit->width() + edit->cursorRectangle().width() + 3); + QCOMPARE(edit->clipRect().height(), edit->height()); + + // clip rect shouldn't exceed the size of the item, expect for the cursor width; + edit->setWidth(edit->width() / 2); + QCOMPARE(edit->clipRect().x(), qreal(0)); + QCOMPARE(edit->clipRect().y(), qreal(0)); + QCOMPARE(edit->clipRect().width(), edit->width() + edit->cursorRectangle().width() + 3); + QCOMPARE(edit->clipRect().height(), edit->height()); + + edit->setHeight(edit->height() * 2); + QCOMPARE(edit->clipRect().x(), qreal(0)); + QCOMPARE(edit->clipRect().y(), qreal(0)); + QCOMPARE(edit->clipRect().width(), edit->width() + edit->cursorRectangle().width() + 3); + QCOMPARE(edit->clipRect().height(), edit->height()); + + QQmlComponent cursorComponent(&engine); + cursorComponent.setData("import QtQuick 2.0\nRectangle { height: 20; width: 8 }", QUrl()); + + edit->setCursorDelegate(&cursorComponent); + + // If a cursor delegate is used it's size should determine the excess width. + QCOMPARE(edit->clipRect().x(), qreal(0)); + QCOMPARE(edit->clipRect().y(), qreal(0)); + QCOMPARE(edit->clipRect().width(), edit->width() + 8 + 3); + QCOMPARE(edit->clipRect().height(), edit->height()); + + // Alignment and wrapping don't affect the clip rect. + edit->setHAlign(QQuickTextEdit::AlignRight); + QCOMPARE(edit->clipRect().x(), qreal(0)); + QCOMPARE(edit->clipRect().y(), qreal(0)); + QCOMPARE(edit->clipRect().width(), edit->width() + 8 + 3); + QCOMPARE(edit->clipRect().height(), edit->height()); + + edit->setWrapMode(QQuickTextEdit::Wrap); + QCOMPARE(edit->clipRect().x(), qreal(0)); + QCOMPARE(edit->clipRect().y(), qreal(0)); + QCOMPARE(edit->clipRect().width(), edit->width() + 8 + 3); + QCOMPARE(edit->clipRect().height(), edit->height()); + + edit->setVAlign(QQuickTextEdit::AlignBottom); + QCOMPARE(edit->clipRect().x(), qreal(0)); + QCOMPARE(edit->clipRect().y(), qreal(0)); + QCOMPARE(edit->clipRect().width(), edit->width() + 8 + 3); + QCOMPARE(edit->clipRect().height(), edit->height()); +} + +void tst_qquicktextedit::boundingRect() +{ + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\n TextEdit {}", QUrl()); + QScopedPointer<QObject> object(component.create()); + QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(object.data()); + QVERIFY(edit); + + QTextLayout layout; + layout.setFont(edit->font()); + + if (!qmlDisableDistanceField()) { + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); + } + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + QCOMPARE(edit->boundingRect().x(), qreal(0)); + QCOMPARE(edit->boundingRect().y(), qreal(0)); + QCOMPARE(edit->boundingRect().width(), edit->cursorRectangle().width()); + QCOMPARE(edit->boundingRect().height(), line.height()); + + edit->setText("Hello World"); + + layout.setText(edit->text()); + layout.beginLayout(); + line = layout.createLine(); + layout.endLayout(); + + QCOMPARE(edit->boundingRect().x(), qreal(0)); + QCOMPARE(edit->boundingRect().y(), qreal(0)); + QCOMPARE(edit->boundingRect().width(), line.naturalTextWidth() + edit->cursorRectangle().width() + 3); + QCOMPARE(edit->boundingRect().height(), line.height()); + + // the size of the bounding rect shouldn't be bounded by the size of item. + edit->setWidth(edit->width() / 2); + QCOMPARE(edit->boundingRect().x(), qreal(0)); + QCOMPARE(edit->boundingRect().y(), qreal(0)); + QCOMPARE(edit->boundingRect().width(), line.naturalTextWidth() + edit->cursorRectangle().width() + 3); + QCOMPARE(edit->boundingRect().height(), line.height()); + + edit->setHeight(edit->height() * 2); + QCOMPARE(edit->boundingRect().x(), qreal(0)); + QCOMPARE(edit->boundingRect().y(), qreal(0)); + QCOMPARE(edit->boundingRect().width(), line.naturalTextWidth() + edit->cursorRectangle().width() + 3); + QCOMPARE(edit->boundingRect().height(), line.height()); + + QQmlComponent cursorComponent(&engine); + cursorComponent.setData("import QtQuick 2.0\nRectangle { height: 20; width: 8 }", QUrl()); + + edit->setCursorDelegate(&cursorComponent); + + // Don't include the size of a cursor delegate as it has its own bounding rect. + QCOMPARE(edit->boundingRect().x(), qreal(0)); + QCOMPARE(edit->boundingRect().y(), qreal(0)); + QCOMPARE(edit->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(edit->boundingRect().height(), line.height()); + + edit->setHAlign(QQuickTextEdit::AlignRight); + QCOMPARE(edit->boundingRect().x(), edit->width() - line.naturalTextWidth()); + QCOMPARE(edit->boundingRect().y(), qreal(0)); + QCOMPARE(edit->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(edit->boundingRect().height(), line.height()); + + edit->setWrapMode(QQuickTextEdit::Wrap); + QCOMPARE(edit->boundingRect().right(), edit->width()); + QCOMPARE(edit->boundingRect().y(), qreal(0)); + QVERIFY(edit->boundingRect().width() < line.naturalTextWidth()); + QVERIFY(edit->boundingRect().height() > line.height()); + + edit->setVAlign(QQuickTextEdit::AlignBottom); + QCOMPARE(edit->boundingRect().right(), edit->width()); + QCOMPARE(edit->boundingRect().bottom(), edit->height()); + QVERIFY(edit->boundingRect().width() < line.naturalTextWidth()); + QVERIFY(edit->boundingRect().height() > line.height()); +} + void tst_qquicktextedit::preeditCursorRectangle() { QString preeditText = "super"; diff --git a/tests/auto/quick/qquicktextinput/data/horizontalAlignment_RightToLeft.qml b/tests/auto/quick/qquicktextinput/data/horizontalAlignment_RightToLeft.qml index 5f88025536..d14caea619 100644 --- a/tests/auto/quick/qquicktextinput/data/horizontalAlignment_RightToLeft.qml +++ b/tests/auto/quick/qquicktextinput/data/horizontalAlignment_RightToLeft.qml @@ -19,6 +19,8 @@ Rectangle { anchors.fill: parent text: top.text focus: true + + cursorDelegate: Rectangle { } } } } diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index 6f75698c1f..27e557bee5 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -129,6 +129,7 @@ private slots: void horizontalAlignment_RightToLeft(); void verticalAlignment(); + void clipRect(); void boundingRect(); void positionAt(); @@ -1309,43 +1310,41 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() const QString rtlText = textInput->text(); - QQuickTextInputPrivate *textInputPrivate = QQuickTextInputPrivate::get(textInput); - QVERIFY(textInputPrivate != 0); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1); + QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); + QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); // implicit alignment should follow the reading direction of RTL text QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1); + QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); + QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); // explicitly left aligned textInput->setHAlign(QQuickTextInput::AlignLeft); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft); QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); - QCOMPARE(textInputPrivate->boundingRect.left() - textInputPrivate->hscroll, qreal(0)); + QCOMPARE(textInput->boundingRect().left(), qreal(0)); // explicitly right aligned textInput->setHAlign(QQuickTextInput::AlignRight); QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1); + QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); + QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); // explicitly center aligned textInput->setHAlign(QQuickTextInput::AlignHCenter); QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignHCenter); - QVERIFY(textInputPrivate->boundingRect.left() - textInputPrivate->hscroll > 0); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll < textInput->width()); + QVERIFY(textInput->boundingRect().left() > 0); + QVERIFY(textInput->boundingRect().right() < textInput->width()); // reseted alignment should go back to following the text reading direction textInput->resetHAlign(); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1); + QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); + QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); // mirror the text item QQuickItemPrivate::get(textInput)->setLayoutMirror(true); @@ -1353,21 +1352,21 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() // mirrored implicit alignment should continue to follow the reading direction of the text QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1); + QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); + QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); // explicitly right aligned behaves as left aligned textInput->setHAlign(QQuickTextInput::AlignRight); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignLeft); - QCOMPARE(textInputPrivate->boundingRect.left() - textInputPrivate->hscroll, qreal(0)); + QCOMPARE(textInput->boundingRect().left(), qreal(0)); // mirrored explicitly left aligned behaves as right aligned textInput->setHAlign(QQuickTextInput::AlignLeft); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft); QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignRight); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1); + QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); + QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); // disable mirroring QQuickItemPrivate::get(textInput)->setLayoutMirror(false); @@ -1377,7 +1376,7 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() // English text should be implicitly left aligned textInput->setText("Hello world!"); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft); - QCOMPARE(textInputPrivate->boundingRect.left() - textInputPrivate->hscroll, qreal(0)); + QCOMPARE(textInput->boundingRect().left(), qreal(0)); canvas.requestActivateWindow(); QTest::qWaitForWindowShown(&canvas); @@ -1400,15 +1399,15 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() platformInputContext.setInputDirection(Qt::LeftToRight); QVERIFY(qApp->inputMethod()->inputDirection() == Qt::LeftToRight); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft); - QCOMPARE(textInputPrivate->boundingRect.left() - textInputPrivate->hscroll, qreal(0)); + QCOMPARE(textInput->boundingRect().left(), qreal(0)); QSignalSpy cursorRectangleSpy(textInput, SIGNAL(cursorRectangleChanged())); platformInputContext.setInputDirection(Qt::RightToLeft); QVERIFY(qApp->inputMethod()->inputDirection() == Qt::RightToLeft); QCOMPARE(cursorRectangleSpy.count(), 1); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1); + QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); + QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); // set input direction while having content platformInputContext.setInputDirection(Qt::LeftToRight); @@ -1417,8 +1416,8 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() QTest::keyClick(&canvas, Qt::Key_Backspace); QVERIFY(textInput->text().isEmpty()); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1); + QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); + QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); // input direction changed while not having focus platformInputContext.setInputDirection(Qt::LeftToRight); @@ -1426,13 +1425,13 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() platformInputContext.setInputDirection(Qt::RightToLeft); textInput->setFocus(true); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1); + QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); + QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); textInput->setHAlign(QQuickTextInput::AlignRight); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1); - QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1); + QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); + QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); } void tst_qquicktextinput::verticalAlignment() @@ -1442,33 +1441,30 @@ void tst_qquicktextinput::verticalAlignment() QVERIFY(textInput != 0); canvas.show(); - QQuickTextInputPrivate *textInputPrivate = QQuickTextInputPrivate::get(textInput); - QVERIFY(textInputPrivate != 0); - QCOMPARE(textInput->vAlign(), QQuickTextInput::AlignTop); - QVERIFY(textInputPrivate->boundingRect.bottom() - textInputPrivate->vscroll < canvas.height() / 2); + QVERIFY(textInput->boundingRect().bottom() < canvas.height() / 2); QVERIFY(textInput->cursorRectangle().bottom() < canvas.height() / 2); QVERIFY(textInput->positionToRectangle(0).bottom() < canvas.height() / 2); // bottom aligned textInput->setVAlign(QQuickTextInput::AlignBottom); QCOMPARE(textInput->vAlign(), QQuickTextInput::AlignBottom); - QVERIFY(textInputPrivate->boundingRect.top() - textInputPrivate->vscroll > canvas.height() / 2); + QVERIFY(textInput->boundingRect().top() > canvas.height() / 2); QVERIFY(textInput->cursorRectangle().top() > canvas.height() / 2); QVERIFY(textInput->positionToRectangle(0).top() > canvas.height() / 2); // explicitly center aligned textInput->setVAlign(QQuickTextInput::AlignVCenter); QCOMPARE(textInput->vAlign(), QQuickTextInput::AlignVCenter); - QVERIFY(textInputPrivate->boundingRect.top() - textInputPrivate->vscroll < canvas.height() / 2); - QVERIFY(textInputPrivate->boundingRect.bottom() - textInputPrivate->vscroll > canvas.height() / 2); + QVERIFY(textInput->boundingRect().top() < canvas.height() / 2); + QVERIFY(textInput->boundingRect().bottom() > canvas.height() / 2); QVERIFY(textInput->cursorRectangle().top() < canvas.height() / 2); QVERIFY(textInput->cursorRectangle().bottom() > canvas.height() / 2); QVERIFY(textInput->positionToRectangle(0).top() < canvas.height() / 2); QVERIFY(textInput->positionToRectangle(0).bottom() > canvas.height() / 2); } -void tst_qquicktextinput::boundingRect() +void tst_qquicktextinput::clipRect() { QQmlComponent component(&engine); component.setData("import QtQuick 2.0\n TextInput {}", QUrl()); @@ -1476,21 +1472,29 @@ void tst_qquicktextinput::boundingRect() QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object.data()); QVERIFY(input); - QCOMPARE(input->width() + input->cursorRectangle().width(), input->boundingRect().width()); - QCOMPARE(input->height(), input->boundingRect().height()); + QCOMPARE(input->clipRect().x(), qreal(0)); + QCOMPARE(input->clipRect().y(), qreal(0)); + QCOMPARE(input->clipRect().width(), input->width() + input->cursorRectangle().width()); + QCOMPARE(input->clipRect().height(), input->height()); input->setText("Hello World"); - QCOMPARE(input->width() + input->cursorRectangle().width(), input->boundingRect().width()); - QCOMPARE(input->height(), input->boundingRect().height()); + QCOMPARE(input->clipRect().x(), qreal(0)); + QCOMPARE(input->clipRect().y(), qreal(0)); + QCOMPARE(input->clipRect().width(), input->width() + input->cursorRectangle().width()); + QCOMPARE(input->clipRect().height(), input->height()); - // bounding rect shouldn't exceed the size of the item, expect for the cursor width; + // clip rect shouldn't exceed the size of the item, expect for the cursor width; input->setWidth(input->width() / 2); - QCOMPARE(input->width() + input->cursorRectangle().width(), input->boundingRect().width()); - QCOMPARE(input->height(), input->boundingRect().height()); + QCOMPARE(input->clipRect().x(), qreal(0)); + QCOMPARE(input->clipRect().y(), qreal(0)); + QCOMPARE(input->clipRect().width(), input->width() + input->cursorRectangle().width()); + QCOMPARE(input->clipRect().height(), input->height()); input->setHeight(input->height() * 2); - QCOMPARE(input->width() + input->cursorRectangle().width(), input->boundingRect().width()); - QCOMPARE(input->height(), input->boundingRect().height()); + QCOMPARE(input->clipRect().x(), qreal(0)); + QCOMPARE(input->clipRect().y(), qreal(0)); + QCOMPARE(input->clipRect().width(), input->width() + input->cursorRectangle().width()); + QCOMPARE(input->clipRect().height(), input->height()); QQmlComponent cursorComponent(&engine); cursorComponent.setData("import QtQuick 2.0\nRectangle { height: 20; width: 8 }", QUrl()); @@ -1498,8 +1502,122 @@ void tst_qquicktextinput::boundingRect() input->setCursorDelegate(&cursorComponent); // If a cursor delegate is used it's size should determine the excess width. - QCOMPARE(input->width() + 8, input->boundingRect().width()); - QCOMPARE(input->height(), input->boundingRect().height()); + QCOMPARE(input->clipRect().x(), qreal(0)); + QCOMPARE(input->clipRect().y(), qreal(0)); + QCOMPARE(input->clipRect().width(), input->width() + 8); + QCOMPARE(input->clipRect().height(), input->height()); + + // Alignment, auto scroll, wrapping all don't affect the clip rect. + input->setAutoScroll(false); + QCOMPARE(input->clipRect().x(), qreal(0)); + QCOMPARE(input->clipRect().y(), qreal(0)); + QCOMPARE(input->clipRect().width(), input->width() + 8); + QCOMPARE(input->clipRect().height(), input->height()); + + input->setHAlign(QQuickTextInput::AlignRight); + QCOMPARE(input->clipRect().x(), qreal(0)); + QCOMPARE(input->clipRect().y(), qreal(0)); + QCOMPARE(input->clipRect().width(), input->width() + 8); + QCOMPARE(input->clipRect().height(), input->height()); + + input->setWrapMode(QQuickTextInput::Wrap); + QCOMPARE(input->clipRect().x(), qreal(0)); + QCOMPARE(input->clipRect().y(), qreal(0)); + QCOMPARE(input->clipRect().width(), input->width() + 8); + QCOMPARE(input->clipRect().height(), input->height()); + + input->setVAlign(QQuickTextInput::AlignBottom); + QCOMPARE(input->clipRect().x(), qreal(0)); + QCOMPARE(input->clipRect().y(), qreal(0)); + QCOMPARE(input->clipRect().width(), input->width() + 8); + QCOMPARE(input->clipRect().height(), input->height()); +} + +void tst_qquicktextinput::boundingRect() +{ + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\n TextInput {}", QUrl()); + QScopedPointer<QObject> object(component.create()); + QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object.data()); + QVERIFY(input); + + QTextLayout layout; + layout.setFont(input->font()); + + if (!qmlDisableDistanceField()) { + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); + } + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + QCOMPARE(input->boundingRect().x(), qreal(0)); + QCOMPARE(input->boundingRect().y(), qreal(0)); + QCOMPARE(input->boundingRect().width(), input->cursorRectangle().width()); + QCOMPARE(input->boundingRect().height(), line.height()); + + input->setText("Hello World"); + + layout.setText(input->text()); + layout.beginLayout(); + line = layout.createLine(); + layout.endLayout(); + + QCOMPARE(input->boundingRect().x(), qreal(0)); + QCOMPARE(input->boundingRect().y(), qreal(0)); + QCOMPARE(input->boundingRect().width(), line.naturalTextWidth() + input->cursorRectangle().width()); + QCOMPARE(input->boundingRect().height(), line.height()); + + // the size of the bounding rect shouldn't be bounded by the size of item. + input->setWidth(input->width() / 2); + QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth()); + QCOMPARE(input->boundingRect().y(), qreal(0)); + QCOMPARE(input->boundingRect().width(), line.naturalTextWidth() + input->cursorRectangle().width()); + QCOMPARE(input->boundingRect().height(), line.height()); + + input->setHeight(input->height() * 2); + QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth()); + QCOMPARE(input->boundingRect().y(), qreal(0)); + QCOMPARE(input->boundingRect().width(), line.naturalTextWidth() + input->cursorRectangle().width()); + QCOMPARE(input->boundingRect().height(), line.height()); + + QQmlComponent cursorComponent(&engine); + cursorComponent.setData("import QtQuick 2.0\nRectangle { height: 20; width: 8 }", QUrl()); + + input->setCursorDelegate(&cursorComponent); + + // Don't include the size of a cursor delegate as it has its own bounding rect. + QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth()); + QCOMPARE(input->boundingRect().y(), qreal(0)); + QCOMPARE(input->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(input->boundingRect().height(), line.height()); + + // Bounding rect left aligned when auto scroll is disabled; + input->setAutoScroll(false); + QCOMPARE(input->boundingRect().x(), qreal(0)); + QCOMPARE(input->boundingRect().y(), qreal(0)); + QCOMPARE(input->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(input->boundingRect().height(), line.height()); + + input->setHAlign(QQuickTextInput::AlignRight); + QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth()); + QCOMPARE(input->boundingRect().y(), qreal(0)); + QCOMPARE(input->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(input->boundingRect().height(), line.height()); + + input->setWrapMode(QQuickTextInput::Wrap); + QCOMPARE(input->boundingRect().right(), input->width()); + QCOMPARE(input->boundingRect().y(), qreal(0)); + QVERIFY(input->boundingRect().width() < line.naturalTextWidth()); + QVERIFY(input->boundingRect().height() > line.height()); + + input->setVAlign(QQuickTextInput::AlignBottom); + QCOMPARE(input->boundingRect().right(), input->width()); + QCOMPARE(input->boundingRect().bottom(), input->height()); + QVERIFY(input->boundingRect().width() < line.naturalTextWidth()); + QVERIFY(input->boundingRect().height() > line.height()); } void tst_qquicktextinput::positionAt() |