Fix implicitHeight for Text items bindings dependent on implicitWidth.
authorAndrew den Exter <andrew.den.exter@qinetic.com.au>
Thu, 23 Apr 2015 11:29:47 +0000 (21:29 +1000)
committerAndrew den Exter <andrew.den.exter@qinetic.com.au>
Mon, 4 May 2015 12:21:26 +0000 (12:21 +0000)
Recalculate the implicitHeight on the second layout if the width
changes after setting the implicitWidth, and potentially do another
layout if the updating the implicitHeight changes the height.

Change-Id: Ib6a637452013b56dba7ae8a6862cd92156386578
Task-number: QTBUG-45546
Reviewed-by: Michael Brasser <michael.brasser@live.com>
Reviewed-by: Albert Astals Cid <albert.astals@canonical.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
src/quick/items/qquicktext.cpp
tests/auto/quick/qquicktext/data/implicitSizes.qml [new file with mode: 0644]
tests/auto/quick/qquicktext/tst_qquicktext.cpp

index c1794697a5dffa8302ea1500df783f485c07b32d..456ec25edd3a607d24dff11571c62d5d3380d429 100644 (file)
@@ -749,6 +749,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
             : largeFont;
     int scaledFontSize = largeFont;
 
+    bool widthChanged = false;
     widthExceeded = q->width() <= 0 && (singlelineElide || canWrap || horizontalFit);
     heightExceeded = q->height() <= 0 && (multilineElide || verticalFit);
 
@@ -945,6 +946,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
             if ((lineWidth < qMin(oldWidth, naturalWidth) || (widthExceeded && lineWidth > oldWidth))
                     && (singlelineElide || multilineElide || canWrap || horizontalFit
                         || q->effectiveHAlign() != QQuickText::AlignLeft)) {
+                widthChanged = true;
                 widthExceeded = false;
                 heightExceeded = false;
                 continue;
@@ -966,6 +968,39 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
                 heightExceeded = false;
                 continue;
             }
+        } else if (widthChanged) {
+            widthChanged = false;
+            if (line.isValid()) {
+                for (int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
+                    line = layout.createLine();
+                    if (!line.isValid())
+                        break;
+                    setLineGeometry(line, lineWidth, naturalHeight);
+                }
+            }
+            layout.endLayout();
+
+            bool wasInLayout = internalWidthUpdate;
+            internalWidthUpdate = true;
+            q->setImplicitHeight(naturalHeight);
+            internalWidthUpdate = wasInLayout;
+
+            multilineElide = elideMode == QQuickText::ElideRight
+                    && q->widthValid()
+                    && (q->heightValid() || maximumLineCountValid);
+            verticalFit = fontSizeMode() & QQuickText::VerticalFit
+                    && (q->heightValid() || (maximumLineCountValid && canWrap));
+
+            const qreal oldHeight = maxHeight;
+            maxHeight = q->heightValid() ? q->height() : FLT_MAX;
+            // If the height of the item has changed and it's possible the result of eliding,
+            // line count truncation or scaling has changed, do another layout.
+            if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
+                    && (multilineElide || (canWrap && maximumLineCountValid))) {
+                widthExceeded = false;
+                heightExceeded = false;
+                continue;
+            }
         } else {
             layout.endLayout();
         }
diff --git a/tests/auto/quick/qquicktext/data/implicitSizes.qml b/tests/auto/quick/qquicktext/data/implicitSizes.qml
new file mode 100644 (file)
index 0000000..fae67c0
--- /dev/null
@@ -0,0 +1,99 @@
+import QtQuick 2.0
+
+Rectangle {
+    width: 200
+    height: column.height
+
+    Column {
+        id: column
+        Text {
+            id: reference
+            objectName: "reference"
+
+            wrapMode: Text.Wrap
+            elide: Text.ElideRight
+
+            text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+Integer at ante dui Curabitur ante est, pulvinar quis adipiscing a, iaculis id ipsum. Nunc blandit
+condimentum odio vel egestas. in ipsum lacinia sit amet
+mattis orci interdum. Quisque vitae accumsan lectus. Ut nisi turpis,
+sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac
+mattis orci interdum. Quisque vitae accumsan lectus. Ut nisi turpis,
+sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac
+leo eget ipsum ultricies viverra sit amet eu orci. Praesent et tortor risus,
+viverra accumsan sapien. Sed faucibus eleifend lectus, sed euismod urna porta
+eu. Quisque vitae accumsan lectus."
+        }
+        Text {
+            id: fixedWidthAndHeight
+            objectName: "fixedWidthAndHeight"
+
+            width: 100
+            height: 100
+
+            wrapMode: Text.Wrap
+            elide: Text.ElideRight
+
+            text: reference.text
+        }
+
+        Text {
+            id: implicitWidthFixedHeight
+            objectName: "implicitWidthFixedHeight"
+
+            height: 100
+
+            wrapMode: Text.Wrap
+            elide: Text.ElideRight
+
+            text: reference.text
+        }
+        Text {
+            id: fixedWidthImplicitHeight
+            objectName: "fixedWidthImplicitHeight"
+
+            width: 100
+
+            wrapMode: Text.Wrap
+            elide: Text.ElideRight
+
+            text: reference.text
+        }
+        Text {
+            id: cappedWidthAndHeight
+            objectName: "cappedWidthAndHeight"
+
+            width: Math.min(100, implicitWidth)
+            height: Math.min(100, implicitHeight)
+
+            wrapMode: Text.Wrap
+            elide: Text.ElideRight
+
+            text: reference.text
+        }
+        Text {
+            id: cappedWidthFixedHeight
+            objectName: "cappedWidthFixedHeight"
+
+            width: Math.min(100, implicitWidth)
+            height: 100
+
+            wrapMode: Text.Wrap
+            elide: Text.ElideRight
+
+            text: reference.text
+        }
+        Text {
+            id: fixedWidthCappedHeight
+            objectName: "fixedWidthCappedHeight"
+
+            width: 100
+            height: Math.min(100, implicitHeight)
+
+            wrapMode: Text.Wrap
+            elide: Text.ElideRight
+
+            text: reference.text
+        }
+    }
+}
index f25c09fcd15f0e2befb38fd09c01cf9878867371..eb9f7529fe7d30d5bc953dd3b2f900c2056b2db5 100644 (file)
@@ -106,6 +106,7 @@ private slots:
 
     void implicitSize_data();
     void implicitSize();
+    void dependentImplicitSizes();
     void contentSize();
     void implicitSizeBinding_data();
     void implicitSizeBinding();
@@ -2206,6 +2207,62 @@ void tst_qquicktext::implicitSize()
     delete textObject;
 }
 
+void tst_qquicktext::dependentImplicitSizes()
+{
+    QQmlComponent component(&engine, testFile("implicitSizes.qml"));
+    QScopedPointer<QObject> object(component.create());
+    QVERIFY(object.data());
+
+    QQuickText *reference = object->findChild<QQuickText *>("reference");
+    QQuickText *fixedWidthAndHeight = object->findChild<QQuickText *>("fixedWidthAndHeight");
+    QQuickText *implicitWidthFixedHeight = object->findChild<QQuickText *>("implicitWidthFixedHeight");
+    QQuickText *fixedWidthImplicitHeight = object->findChild<QQuickText *>("fixedWidthImplicitHeight");
+    QQuickText *cappedWidthAndHeight = object->findChild<QQuickText *>("cappedWidthAndHeight");
+    QQuickText *cappedWidthFixedHeight = object->findChild<QQuickText *>("cappedWidthFixedHeight");
+    QQuickText *fixedWidthCappedHeight = object->findChild<QQuickText *>("fixedWidthCappedHeight");
+
+    QVERIFY(reference);
+    QVERIFY(fixedWidthAndHeight);
+    QVERIFY(implicitWidthFixedHeight);
+    QVERIFY(fixedWidthImplicitHeight);
+    QVERIFY(cappedWidthAndHeight);
+    QVERIFY(cappedWidthFixedHeight);
+    QVERIFY(fixedWidthCappedHeight);
+
+    QCOMPARE(reference->width(), reference->implicitWidth());
+    QCOMPARE(reference->height(), reference->implicitHeight());
+
+    QVERIFY(fixedWidthAndHeight->width() < fixedWidthAndHeight->implicitWidth());
+    QVERIFY(fixedWidthAndHeight->height() < fixedWidthAndHeight->implicitHeight());
+    QCOMPARE(fixedWidthAndHeight->implicitWidth(), reference->implicitWidth());
+    QVERIFY(fixedWidthAndHeight->implicitHeight() > reference->implicitHeight());
+
+    QCOMPARE(implicitWidthFixedHeight->width(), implicitWidthFixedHeight->implicitWidth());
+    QVERIFY(implicitWidthFixedHeight->height() < implicitWidthFixedHeight->implicitHeight());
+    QCOMPARE(implicitWidthFixedHeight->implicitWidth(), reference->implicitWidth());
+    QCOMPARE(implicitWidthFixedHeight->implicitHeight(), reference->implicitHeight());
+
+    QVERIFY(fixedWidthImplicitHeight->width() < fixedWidthImplicitHeight->implicitWidth());
+    QCOMPARE(fixedWidthImplicitHeight->height(), fixedWidthImplicitHeight->implicitHeight());
+    QCOMPARE(fixedWidthImplicitHeight->implicitWidth(), reference->implicitWidth());
+    QCOMPARE(fixedWidthImplicitHeight->implicitHeight(), fixedWidthAndHeight->implicitHeight());
+
+    QVERIFY(cappedWidthAndHeight->width() < cappedWidthAndHeight->implicitWidth());
+    QVERIFY(cappedWidthAndHeight->height() < cappedWidthAndHeight->implicitHeight());
+    QCOMPARE(cappedWidthAndHeight->implicitWidth(), reference->implicitWidth());
+    QCOMPARE(cappedWidthAndHeight->implicitHeight(), fixedWidthAndHeight->implicitHeight());
+
+    QVERIFY(cappedWidthFixedHeight->width() < cappedWidthAndHeight->implicitWidth());
+    QVERIFY(cappedWidthFixedHeight->height() < cappedWidthFixedHeight->implicitHeight());
+    QCOMPARE(cappedWidthFixedHeight->implicitWidth(), reference->implicitWidth());
+    QCOMPARE(cappedWidthFixedHeight->implicitHeight(), fixedWidthAndHeight->implicitHeight());
+
+    QVERIFY(fixedWidthCappedHeight->width() < fixedWidthCappedHeight->implicitWidth());
+    QVERIFY(fixedWidthCappedHeight->height() < fixedWidthCappedHeight->implicitHeight());
+    QCOMPARE(fixedWidthCappedHeight->implicitWidth(), reference->implicitWidth());
+    QCOMPARE(fixedWidthCappedHeight->implicitHeight(), fixedWidthAndHeight->implicitHeight());
+}
+
 void tst_qquicktext::contentSize()
 {
     QString componentStr = "import QtQuick 2.0\nText { width: 75; height: 16; font.pixelSize: 10 }";