aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew den Exter <andrew.den-exter@nokia.com>2012-04-19 11:08:28 +1000
committerQt by Nokia <qt-info@nokia.com>2012-04-27 06:27:46 +0200
commit2a6e105f43885e0901c252bffc77bd1c9db87b67 (patch)
treefbab5df14ceeb7e3a798cdbe4e5c6d5effff331d
parent1770fa632facf2f1e4bb05e7689efc939d46cfef (diff)
Fix bounding rects of text items.
Ensure the rectangles are correctly positioned with right and center aligned text, not just sized correctly. Also add padding to the clip rects so the cursor and styled text aren't clipped at the item boundaries. Change-Id: I03ef140589154ebd49b600b0a4c4fbeff845c10f Reviewed-by: Yann Bodson <yann.bodson@nokia.com>
-rw-r--r--src/quick/items/qquicktext.cpp10
-rw-r--r--src/quick/items/qquicktext_p.h1
-rw-r--r--src/quick/items/qquicktextedit.cpp47
-rw-r--r--src/quick/items/qquicktextedit_p.h1
-rw-r--r--src/quick/items/qquicktextinput.cpp52
-rw-r--r--src/quick/items/qquicktextinput_p.h2
-rw-r--r--src/quick/items/qquicktextinput_p_p.h2
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp45
-rw-r--r--tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp148
-rw-r--r--tests/auto/quick/qquicktextinput/data/horizontalAlignment_RightToLeft.qml2
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp212
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()