TextEdit: add support for padding
authorJ-P Nurmi <jpnurmi@theqtcompany.com>
Wed, 4 Feb 2015 17:00:53 +0000 (18:00 +0100)
committerJ-P Nurmi <jpnurmi@theqtcompany.com>
Thu, 5 Mar 2015 22:45:19 +0000 (22:45 +0000)
This makes it possible for TextArea to inherit TextEdit, reserve
space for the decoration, and set the desired property defaults
without having to create dozens of property aliases.

[ChangeLog][QtQuick][TextEdit] Added padding, leftPadding, topPadding,
rightPadding and bottomPadding properties.

Task-number: QTBUG-41559
Change-Id: I4fa22f86e6151524a63b2b862f17bc9d6a713142
Reviewed-by: Alan Alpert <aalpert@blackberry.com>
src/quick/items/qquicktextedit.cpp
src/quick/items/qquicktextedit_p.h
src/quick/items/qquicktextedit_p_p.h
tests/auto/quick/qquicktextedit/data/padding.qml [new file with mode: 0644]
tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp

index a6755d84d7e662668f1fc5f394c6b5ba3d767036..db66e333d3c6177c06d96172d09bbf55e4c5693f 100644 (file)
@@ -695,6 +695,62 @@ Qt::InputMethodHints QQuickTextEditPrivate::effectiveInputMethodHints() const
 }
 #endif
 
+void QQuickTextEditPrivate::setTopPadding(qreal value, bool reset)
+{
+    Q_Q(QQuickTextEdit);
+    qreal oldPadding = q->topPadding();
+    topPadding = value;
+    explicitTopPadding = !reset;
+    if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) {
+        q->updateSize();
+        emit q->topPaddingChanged();
+    }
+}
+
+void QQuickTextEditPrivate::setLeftPadding(qreal value, bool reset)
+{
+    Q_Q(QQuickTextEdit);
+    qreal oldPadding = q->topPadding();
+    leftPadding = value;
+    explicitLeftPadding = !reset;
+    if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) {
+        q->updateSize();
+        emit q->leftPaddingChanged();
+        if (q->isComponentComplete()) {
+            updateType = QQuickTextEditPrivate::UpdatePaintNode;
+            q->update();
+        }
+    }
+}
+
+void QQuickTextEditPrivate::setRightPadding(qreal value, bool reset)
+{
+    Q_Q(QQuickTextEdit);
+    qreal oldPadding = q->topPadding();
+    rightPadding = value;
+    explicitRightPadding = !reset;
+    if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) {
+        q->updateSize();
+        emit q->rightPaddingChanged();
+        if (q->isComponentComplete()) {
+            updateType = QQuickTextEditPrivate::UpdatePaintNode;
+            q->update();
+        }
+    }
+}
+
+void QQuickTextEditPrivate::setBottomPadding(qreal value, bool reset)
+{
+    Q_Q(QQuickTextEdit);
+    qreal oldPadding = q->topPadding();
+    bottomPadding = value;
+    explicitBottomPadding = !reset;
+    if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) {
+        q->updateSize();
+        emit q->bottomPaddingChanged();
+    }
+}
+
 QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const
 {
     Q_D(const QQuickTextEdit);
@@ -2220,7 +2276,7 @@ void QQuickTextEdit::updateSize()
         return;
     }
 
-    qreal naturalWidth = d->implicitWidth;
+    qreal naturalWidth = d->implicitWidth - leftPadding() - rightPadding();
 
     qreal newWidth = d->document->idealWidth();
     // ### assumes that if the width is set, the text will fill to edges
@@ -2238,13 +2294,13 @@ void QQuickTextEdit::updateSize()
 
             const bool wasInLayout = d->inLayout;
             d->inLayout = true;
-            setImplicitWidth(naturalWidth);
+            setImplicitWidth(naturalWidth + leftPadding() + rightPadding());
             d->inLayout = wasInLayout;
             if (d->inLayout)    // probably the result of a binding loop, but by letting it
                 return;         // get this far we'll get a warning to that effect.
         }
         if (d->document->textWidth() != width()) {
-            d->document->setTextWidth(width());
+            d->document->setTextWidth(width() - leftPadding() - rightPadding());
             newWidth = d->document->idealWidth();
         }
         //### need to confirm cost of always setting these
@@ -2259,12 +2315,12 @@ void QQuickTextEdit::updateSize()
 
     // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
     if (!widthValid() && !d->requireImplicitWidth)
-        setImplicitSize(newWidth, newHeight);
+        setImplicitSize(newWidth + leftPadding() + rightPadding(), newHeight + topPadding() + bottomPadding());
     else
-        setImplicitHeight(newHeight);
+        setImplicitHeight(newHeight + topPadding() + bottomPadding());
 
-    d->xoff = qMax(qreal(0), QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign()));
-    d->yoff = QQuickTextUtil::alignedY(d->document->size().height(), height(), d->vAlign);
+    d->xoff = leftPadding() + qMax(qreal(0), QQuickTextUtil::alignedX(d->document->size().width(), width() - leftPadding() - rightPadding(), effectiveHAlign()));
+    d->yoff = topPadding() + QQuickTextUtil::alignedY(d->document->size().height(), height() - topPadding() - bottomPadding(), d->vAlign);
     setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
 
     QSizeF size(newWidth, newHeight);
@@ -2679,7 +2735,131 @@ void QQuickTextEdit::append(const QString &text)
 QString QQuickTextEdit::linkAt(qreal x, qreal y) const
 {
     Q_D(const QQuickTextEdit);
-    return d->control->anchorAt(QPointF(x, y));
+    return d->control->anchorAt(QPointF(x + topPadding(), y + leftPadding()));
+}
+
+/*!
+    \since 5.6
+    \qmlproperty real QtQuick::TextEdit::padding
+    \qmlproperty real QtQuick::TextEdit::topPadding
+    \qmlproperty real QtQuick::TextEdit::leftPadding
+    \qmlproperty real QtQuick::TextEdit::bottomPadding
+    \qmlproperty real QtQuick::TextEdit::rightPadding
+
+    These properties hold the padding around the content. This space is reserved
+    in addition to the contentWidth and contentHeight.
+*/
+qreal QQuickTextEdit::padding() const
+{
+    Q_D(const QQuickTextEdit);
+    return d->padding;
+}
+
+void QQuickTextEdit::setPadding(qreal padding)
+{
+    Q_D(QQuickTextEdit);
+    if (qFuzzyCompare(d->padding, padding))
+        return;
+    d->padding = padding;
+    updateSize();
+    if (isComponentComplete()) {
+        d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
+        update();
+    }
+    emit paddingChanged();
+    if (!d->explicitTopPadding)
+        emit topPaddingChanged();
+    if (!d->explicitLeftPadding)
+        emit leftPaddingChanged();
+    if (!d->explicitRightPadding)
+        emit rightPaddingChanged();
+    if (!d->explicitBottomPadding)
+        emit bottomPaddingChanged();
+}
+
+void QQuickTextEdit::resetPadding()
+{
+    setPadding(0);
+}
+
+qreal QQuickTextEdit::topPadding() const
+{
+    Q_D(const QQuickTextEdit);
+    if (d->explicitTopPadding)
+        return d->topPadding;
+    return d->padding;
+}
+
+void QQuickTextEdit::setTopPadding(qreal padding)
+{
+    Q_D(QQuickTextEdit);
+    d->setTopPadding(padding);
+}
+
+void QQuickTextEdit::resetTopPadding()
+{
+    Q_D(QQuickTextEdit);
+    d->setTopPadding(0, true);
+}
+
+qreal QQuickTextEdit::leftPadding() const
+{
+    Q_D(const QQuickTextEdit);
+    if (d->explicitLeftPadding)
+        return d->leftPadding;
+    return d->padding;
+}
+
+void QQuickTextEdit::setLeftPadding(qreal padding)
+{
+    Q_D(QQuickTextEdit);
+    d->setLeftPadding(padding);
+}
+
+void QQuickTextEdit::resetLeftPadding()
+{
+    Q_D(QQuickTextEdit);
+    d->setLeftPadding(0, true);
+}
+
+qreal QQuickTextEdit::rightPadding() const
+{
+    Q_D(const QQuickTextEdit);
+    if (d->explicitRightPadding)
+        return d->rightPadding;
+    return d->padding;
+}
+
+void QQuickTextEdit::setRightPadding(qreal padding)
+{
+    Q_D(QQuickTextEdit);
+    d->setRightPadding(padding);
+}
+
+void QQuickTextEdit::resetRightPadding()
+{
+    Q_D(QQuickTextEdit);
+    d->setRightPadding(0, true);
+}
+
+qreal QQuickTextEdit::bottomPadding() const
+{
+    Q_D(const QQuickTextEdit);
+    if (d->explicitBottomPadding)
+        return d->bottomPadding;
+    return d->padding;
+}
+
+void QQuickTextEdit::setBottomPadding(qreal padding)
+{
+    Q_D(QQuickTextEdit);
+    d->setBottomPadding(padding);
+}
+
+void QQuickTextEdit::resetBottomPadding()
+{
+    Q_D(QQuickTextEdit);
+    d->setBottomPadding(0, true);
 }
 
 QT_END_NAMESPACE
index c260cea1466d293ae99def5c938f7d049e2351b6..5b6b0c767b5efca82fbb4a132fdb6e6f098d9061 100644 (file)
@@ -93,6 +93,11 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem
     Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged)
     Q_PROPERTY(QQuickTextDocument *textDocument READ textDocument FINAL REVISION 1)
     Q_PROPERTY(QString hoveredLink READ hoveredLink NOTIFY linkHovered REVISION 2)
+    Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged REVISION 6)
+    Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged REVISION 6)
+    Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged REVISION 6)
+    Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6)
+    Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6)
 
 public:
     QQuickTextEdit(QQuickItem *parent=0);
@@ -247,6 +252,26 @@ public:
 
     Q_REVISION(3) Q_INVOKABLE QString linkAt(qreal x, qreal y) const;
 
+    qreal padding() const;
+    void setPadding(qreal padding);
+    void resetPadding();
+
+    qreal topPadding() const;
+    void setTopPadding(qreal padding);
+    void resetTopPadding();
+
+    qreal leftPadding() const;
+    void setLeftPadding(qreal padding);
+    void resetLeftPadding();
+
+    qreal rightPadding() const;
+    void setRightPadding(qreal padding);
+    void resetRightPadding();
+
+    qreal bottomPadding() const;
+    void setBottomPadding(qreal padding);
+    void resetBottomPadding();
+
 Q_SIGNALS:
     void textChanged();
     void contentSizeChanged();
@@ -284,6 +309,11 @@ Q_SIGNALS:
     void inputMethodHintsChanged();
     void renderTypeChanged();
     Q_REVISION(6) void editingFinished();
+    Q_REVISION(6) void paddingChanged();
+    Q_REVISION(6) void topPaddingChanged();
+    Q_REVISION(6) void leftPaddingChanged();
+    Q_REVISION(6) void rightPaddingChanged();
+    Q_REVISION(6) void bottomPaddingChanged();
 
 public Q_SLOTS:
     void selectAll();
index 0cf0f46532bac041d13c6e6d87793c36924fde59..20c0d1ca9cd9b90ece242ffc9a70f7a00914578e 100644 (file)
@@ -84,7 +84,9 @@ public:
 
     QQuickTextEditPrivate()
         : color(QRgb(0xFF000000)), selectionColor(QRgb(0xFF000080)), selectedTextColor(QRgb(0xFFFFFFFF))
-        , textMargin(0.0), xoff(0), yoff(0), font(sourceFont), cursorComponent(0), cursorItem(0), document(0), control(0)
+        , textMargin(0.0), xoff(0), yoff(0), padding(0), topPadding(0), leftPadding(0), rightPadding(0), bottomPadding(0)
+        , explicitTopPadding(false), explicitLeftPadding(false), explicitRightPadding(false), explicitBottomPadding(false)
+        , font(sourceFont), cursorComponent(0), cursorItem(0), document(0), control(0)
         , quickDocument(0), lastSelectionStart(0), lastSelectionEnd(0), lineCount(0)
         , hAlign(QQuickTextEdit::AlignLeft), vAlign(QQuickTextEdit::AlignTop)
         , format(QQuickTextEdit::PlainText), wrapMode(QQuickTextEdit::NoWrap)
@@ -131,6 +133,11 @@ public:
     Qt::InputMethodHints effectiveInputMethodHints() const;
 #endif
 
+    void setTopPadding(qreal value, bool reset = false);
+    void setLeftPadding(qreal value, bool reset = false);
+    void setRightPadding(qreal value, bool reset = false);
+    void setBottomPadding(qreal value, bool reset = false);
+
     QColor color;
     QColor selectionColor;
     QColor selectedTextColor;
@@ -140,6 +147,15 @@ public:
     qreal textMargin;
     qreal xoff;
     qreal yoff;
+    qreal padding;
+    qreal topPadding;
+    qreal leftPadding;
+    qreal rightPadding;
+    qreal bottomPadding;
+    bool explicitTopPadding;
+    bool explicitLeftPadding;
+    bool explicitRightPadding;
+    bool explicitBottomPadding;
 
     QString text;
     QUrl baseUrl;
diff --git a/tests/auto/quick/qquicktextedit/data/padding.qml b/tests/auto/quick/qquicktextedit/data/padding.qml
new file mode 100644 (file)
index 0000000..f4852be
--- /dev/null
@@ -0,0 +1,12 @@
+import QtQuick 2.6
+
+TextEdit {
+    width: 200; height: 200
+    text: "Hello Qt"
+
+    padding: 10
+    topPadding: 20
+    leftPadding: 30
+    rightPadding: 40
+    bottomPadding: 50
+}
index 86f25ace489cc12a4b9599b92c166c9e07e6b1cc..256e5b4bd5f8d19d53b0e8ecd3a4d0b64e3e944c 100644 (file)
@@ -205,6 +205,8 @@ private slots:
     void cursorRectangle_QTBUG_38947();
     void textCached_QTBUG_41583();
 
+    void padding();
+
 private:
     void simulateKeys(QWindow *window, const QList<Key> &keys);
     void simulateKeys(QWindow *window, const QKeySequence &sequence);
@@ -5363,6 +5365,84 @@ void tst_qquicktextedit::textCached_QTBUG_41583()
     QVERIFY(!textedit->property("empty").toBool());
 }
 
+void tst_qquicktextedit::padding()
+{
+    QScopedPointer<QQuickView> window(new QQuickView);
+    window->setSource(testFileUrl("padding.qml"));
+    QTRY_COMPARE(window->status(), QQuickView::Ready);
+    window->show();
+    QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+    QQuickItem *root = window->rootObject();
+    QVERIFY(root);
+    QQuickTextEdit *obj = qobject_cast<QQuickTextEdit*>(root);
+    QVERIFY(obj != 0);
+
+    qreal cw = obj->contentWidth();
+    qreal ch = obj->contentHeight();
+
+    QVERIFY(cw > 0);
+    QVERIFY(ch > 0);
+
+    QCOMPARE(obj->topPadding(), 20.0);
+    QCOMPARE(obj->leftPadding(), 30.0);
+    QCOMPARE(obj->rightPadding(), 40.0);
+    QCOMPARE(obj->bottomPadding(), 50.0);
+
+    QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding());
+    QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding());
+
+    obj->setTopPadding(2.25);
+    QCOMPARE(obj->topPadding(), 2.25);
+    QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding());
+
+    obj->setLeftPadding(3.75);
+    QCOMPARE(obj->leftPadding(), 3.75);
+    QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding());
+
+    obj->setRightPadding(4.4);
+    QCOMPARE(obj->rightPadding(), 4.4);
+    QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding());
+
+    obj->setBottomPadding(1.11);
+    QCOMPARE(obj->bottomPadding(), 1.11);
+    QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding());
+
+    obj->setText("Qt");
+    QVERIFY(obj->contentWidth() < cw);
+    QCOMPARE(obj->contentHeight(), ch);
+    cw = obj->contentWidth();
+
+    QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding());
+    QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding());
+
+    obj->setFont(QFont("Courier", 96));
+    QVERIFY(obj->contentWidth() > cw);
+    QVERIFY(obj->contentHeight() > ch);
+    cw = obj->contentWidth();
+    ch = obj->contentHeight();
+
+    QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding());
+    QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding());
+
+    obj->resetTopPadding();
+    QCOMPARE(obj->topPadding(), 10.0);
+    obj->resetLeftPadding();
+    QCOMPARE(obj->leftPadding(), 10.0);
+    obj->resetRightPadding();
+    QCOMPARE(obj->rightPadding(), 10.0);
+    obj->resetBottomPadding();
+    QCOMPARE(obj->bottomPadding(), 10.0);
+
+    obj->resetPadding();
+    QCOMPARE(obj->padding(), 0.0);
+    QCOMPARE(obj->topPadding(), 0.0);
+    QCOMPARE(obj->leftPadding(), 0.0);
+    QCOMPARE(obj->rightPadding(), 0.0);
+    QCOMPARE(obj->bottomPadding(), 0.0);
+
+    delete root;
+}
+
 QTEST_MAIN(tst_qquicktextedit)
 
 #include "tst_qquicktextedit.moc"