From 16558ac71509fe51a4cf18f238e4f61b37323fe4 Mon Sep 17 00:00:00 2001
From: Jan Arve Saether <jan-arve.saether@digia.com>
Date: Wed, 8 May 2013 17:02:40 +0200
Subject: [PATCH] Return infinity instead of -1 as a default value for max
 sizes

This was a bit inconsistent, because in the case of a Rectangle its
Layout.maximumWidth would return -1 by default (which was supposed to
be interpreted as infinity) However, since the maximumWidth propagated
up to the layout, the layout.Layout.maximumWidth would return
1000000000. Adding two Rectangles to the layout would make
layout.Layout.maximumWidth return 2000000000, and adding a third item
with Layout.maximumWidth:1 would make layout.Layout.maximumWidth
return 2000000001

With this change, since infinity + number = infinity, everything
that can grow to infinity will just return infinity.

In addition a developer can now more intuitively do comparisons
like this:

if (value > Layout.minimumWidth && value < Layout.maximumWidth)

instead of

if ((value == -1 || value > Layout.minimumWidth) &&
    (value != -1 && value < Layout.maximumWidth))

Now, as a bonus, it becomes less consistent to set an attached
(min,max) property to -1 in order to reset it to its implicit value.

This also fixes a documentation issue with regards to the attached
Layout.{min|max}imum{Width|Height} properties. It only told the story
correct if the item was not a layout, and updates the docs for the max
sizes to mention that it returns Number.POSITIVE_INFINITY

Change-Id: Ia638064fd3ed5614d7e496a9b5e4aa8fcb7307f7
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
---
 src/layouts/qquickgridlayoutengine.cpp     |  5 +-
 src/layouts/qquicklayout.cpp               | 58 +++++++++++++++++-----
 src/layouts/qquicklayout_p.h               | 13 ++---
 src/layouts/qquicklinearlayout.cpp         | 12 +++--
 src/layouts/qquicklinearlayout_p.h         |  1 +
 tests/auto/controls/data/tst_rowlayout.qml | 33 ++++++++----
 6 files changed, 86 insertions(+), 36 deletions(-)

diff --git a/src/layouts/qquickgridlayoutengine.cpp b/src/layouts/qquickgridlayoutengine.cpp
index e734e9fef..bacfd965b 100644
--- a/src/layouts/qquickgridlayoutengine.cpp
+++ b/src/layouts/qquickgridlayoutengine.cpp
@@ -204,9 +204,8 @@ Fixed    | Layout.fillWidth               | Expanding if layout, Fixed if item |
         }
     }
     //--- GATHER MAXIMUM SIZE HINTS ---
-    // They are always q_declarativeLayoutMaxSize
-    combineHints(cachedSizeHints[Qt::MaximumSize].rwidth(), q_declarativeLayoutMaxSize);
-    combineHints(cachedSizeHints[Qt::MaximumSize].rheight(), q_declarativeLayoutMaxSize);
+    combineHints(cachedSizeHints[Qt::MaximumSize].rwidth(), std::numeric_limits<qreal>::infinity());
+    combineHints(cachedSizeHints[Qt::MaximumSize].rheight(), std::numeric_limits<qreal>::infinity());
 
     //--- GATHER DESCENT
     // ### Not implemented
diff --git a/src/layouts/qquicklayout.cpp b/src/layouts/qquicklayout.cpp
index 6d36a92e6..d26737e2d 100644
--- a/src/layouts/qquicklayout.cpp
+++ b/src/layouts/qquicklayout.cpp
@@ -43,6 +43,7 @@
 #include <QEvent>
 #include <QtCore/qcoreapplication.h>
 #include <QtCore/qnumeric.h>
+#include <limits>
 
 /*!
     \qmltype Layout
@@ -78,8 +79,8 @@ QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent)
       m_minimumHeight(0),
       m_preferredWidth(-1),
       m_preferredHeight(-1),
-      m_maximumWidth(-1),
-      m_maximumHeight(-1),
+      m_maximumWidth(std::numeric_limits<qreal>::infinity()),
+      m_maximumHeight(std::numeric_limits<qreal>::infinity()),
       m_row(-1),
       m_column(-1),
       m_rowSpan(1),
@@ -101,8 +102,15 @@ QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent)
 /*!
     \qmlproperty real Layout::minimumWidth
 
-    This property holds the minimum width of an item in a layout.
-    The default is \c 0.
+    This property holds the maximum width of an item in a layout.
+    The default value is the items implicit minimum width.
+
+    If the item is a layout, the implicit minimum width will be the minimum width the layout can
+    have without any of its items shrink beyond their minimum width.
+    The implicit minimum width for any other item is \c 0.
+
+    Setting this value to -1 will reset the width back to its implicit minimum width.
+
 
     \sa preferredWidth
     \sa maximumWidth
@@ -123,8 +131,13 @@ void QQuickLayoutAttached::setMinimumWidth(qreal width)
 /*!
     \qmlproperty real Layout::minimumHeight
 
-    This property holds the minimum height of an item in a layout.
-    The default is \c 0.
+    The default value is the items implicit minimum height.
+
+    If the item is a layout, the implicit minimum height will be the minimum height the layout can
+    have without any of its items shrink beyond their minimum height.
+    The implicit minimum height for any other item is \c 0.
+
+    Setting this value to -1 will reset the height back to its implicit minimum height.
 
     \sa preferredHeight
     \sa maximumHeight
@@ -188,10 +201,13 @@ void QQuickLayoutAttached::setPreferredHeight(qreal height)
     \qmlproperty real Layout::maximumWidth
 
     This property holds the maximum width of an item in a layout.
-    The default is \c -1, which means it there is no limit on the maxiumum width.
+    The default value is the items implicit maximum width.
+
+    If the item is a layout, the implicit maximum width will be the maximum width the layout can
+    have without any of its items grow beyond their maximum width.
+    The implicit maximum width for any other item is \c Number.POSITIVE_INFINITE.
 
-    \note There is actually a limit on the maximum width, but it's set to such a
-    large number that the arrangement is virtually the same as if it didn't have a limit.
+    Setting this value to -1 will reset the width back to its implicit maximum width.
 
     \sa minimumWidth
     \sa preferredWidth
@@ -212,11 +228,13 @@ void QQuickLayoutAttached::setMaximumWidth(qreal width)
 /*!
     \qmlproperty real Layout::maximumHeight
 
-    This property holds the maximum height of an item in a layout.
-    The default is \c -1, which means it there is no limit on the maxiumum height.
+    The default value is the items implicit maximum height.
 
-    \note There is actually a limit on the maximum height, but it's set to such a
-    large number that the arrangement is virtually the same as if it didn't have a limit.
+    If the item is a layout, the implicit maximum height will be the maximum height the layout can
+    have without any of its items grow beyond their maximum height.
+    The implicit maximum height for any other item is \c Number.POSITIVE_INFINITE.
+
+    Setting this value to -1 will reset the height back to its implicit maximum height.
 
     \sa minimumHeight
     \sa preferredHeight
@@ -389,6 +407,20 @@ void QQuickLayoutAttached::setColumn(int column)
     \sa column
 */
 
+
+qreal QQuickLayoutAttached::sizeHint(Qt::SizeHint which, Qt::Orientation orientation) const
+{
+    qreal result = 0;
+    if (QQuickLayout *layout = qobject_cast<QQuickLayout *>(item())) {
+        const QSizeF sz = layout->sizeHint(which);
+        result = (orientation == Qt::Horizontal ? sz.width() : sz.height());
+    } else {
+        if (which == Qt::MaximumSize)
+            result = std::numeric_limits<qreal>::infinity();
+    }
+    return result;
+}
+
 void QQuickLayoutAttached::invalidateItem()
 {
     if (!m_changesNotificationEnabled)
diff --git a/src/layouts/qquicklayout_p.h b/src/layouts/qquicklayout_p.h
index 8d9464476..8a334677a 100644
--- a/src/layouts/qquicklayout_p.h
+++ b/src/layouts/qquicklayout_p.h
@@ -50,8 +50,6 @@ QT_BEGIN_NAMESPACE
 
 class QQuickLayoutAttached;
 
-static const qreal q_declarativeLayoutMaxSize = 10e8;
-
 #if 0 && !defined(QT_NO_DEBUG) && !defined(QT_NO_DEBUG_OUTPUT)
 # define quickLayoutDebug QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug
 #else
@@ -77,6 +75,7 @@ public:
 
 
     void componentComplete();
+    virtual QSizeF sizeHint(Qt::SizeHint whichSizeHint) const = 0;
     virtual void invalidate(QQuickItem * childItem = 0);
 protected:
     bool event(QEvent *e);
@@ -123,10 +122,10 @@ class QQuickLayoutAttached : public QObject
 public:
     QQuickLayoutAttached(QObject *object);
 
-    qreal minimumWidth() const { return m_minimumWidth; }
+    qreal minimumWidth() const { return m_minimumWidth < 0 ? sizeHint(Qt::MinimumSize, Qt::Horizontal) : m_minimumWidth; }
     void setMinimumWidth(qreal width);
 
-    qreal minimumHeight() const { return m_minimumHeight; }
+    qreal minimumHeight() const { return m_minimumHeight < 0 ? sizeHint(Qt::MinimumSize, Qt::Vertical) : m_minimumHeight; }
     void setMinimumHeight(qreal height);
 
     qreal preferredWidth() const { return m_preferredWidth; }
@@ -135,10 +134,10 @@ public:
     qreal preferredHeight() const { return m_preferredHeight; }
     void setPreferredHeight(qreal width);
 
-    qreal maximumWidth() const { return m_maximumWidth; }
+    qreal maximumWidth() const { return m_maximumWidth < 0 ? sizeHint(Qt::MaximumSize, Qt::Horizontal) : m_maximumWidth; }
     void setMaximumWidth(qreal width);
 
-    qreal maximumHeight() const { return m_maximumHeight; }
+    qreal maximumHeight() const { return m_maximumHeight < 0 ? sizeHint(Qt::MaximumSize, Qt::Vertical) : m_maximumHeight; }
     void setMaximumHeight(qreal height);
 
     void setMinimumImplicitSize(const QSizeF &sz);
@@ -174,6 +173,8 @@ public:
         return old;
     }
 
+    qreal sizeHint(Qt::SizeHint which, Qt::Orientation orientation) const;
+
 signals:
     void minimumWidthChanged();
     void minimumHeightChanged();
diff --git a/src/layouts/qquicklinearlayout.cpp b/src/layouts/qquicklinearlayout.cpp
index c45310027..d5bd503a7 100644
--- a/src/layouts/qquicklinearlayout.cpp
+++ b/src/layouts/qquicklinearlayout.cpp
@@ -171,6 +171,12 @@ void QQuickGridLayoutBase::setOrientation(Qt::Orientation orientation)
     invalidate();
 }
 
+QSizeF QQuickGridLayoutBase::sizeHint(Qt::SizeHint whichSizeHint) const
+{
+    Q_D(const QQuickGridLayoutBase);
+    return d->engine.sizeHint(whichSizeHint, QSizeF());
+}
+
 void QQuickGridLayoutBase::componentComplete()
 {
     Q_D(QQuickGridLayoutBase);
@@ -241,9 +247,9 @@ void QQuickGridLayoutBase::invalidate(QQuickItem *childItem)
 
     QQuickLayoutAttached *info = attachedLayoutObject(this);
 
-    const QSizeF min = d->engine.sizeHint(Qt::MinimumSize, QSizeF());
-    const QSizeF pref = d->engine.sizeHint(Qt::PreferredSize, QSizeF());
-    const QSizeF max = d->engine.sizeHint(Qt::MaximumSize, QSizeF());
+    const QSizeF min = sizeHint(Qt::MinimumSize);
+    const QSizeF pref = sizeHint(Qt::PreferredSize);
+    const QSizeF max = sizeHint(Qt::MaximumSize);
 
     const bool old = info->setChangesNotificationEnabled(false);
     info->setMinimumImplicitSize(min);
diff --git a/src/layouts/qquicklinearlayout_p.h b/src/layouts/qquicklinearlayout_p.h
index f1a9b39f5..76cc206b9 100644
--- a/src/layouts/qquicklinearlayout_p.h
+++ b/src/layouts/qquicklinearlayout_p.h
@@ -68,6 +68,7 @@ public:
     void invalidate(QQuickItem *childItem = 0);
     Qt::Orientation orientation() const;
     void setOrientation(Qt::Orientation orientation);
+    QSizeF sizeHint(Qt::SizeHint whichSizeHint) const Q_DECL_OVERRIDE;
 
 protected:
     void updateLayoutItems();
diff --git a/tests/auto/controls/data/tst_rowlayout.qml b/tests/auto/controls/data/tst_rowlayout.qml
index 1b9573e0c..6e2d1334a 100644
--- a/tests/auto/controls/data/tst_rowlayout.qml
+++ b/tests/auto/controls/data/tst_rowlayout.qml
@@ -129,6 +129,8 @@ Item {
             tmp.width = 30
             compare(tmp.r1.width, 10);
             compare(tmp.r2.width, 20);
+            compare(tmp.Layout.minimumWidth, 0)
+            compare(tmp.Layout.maximumWidth, Number.POSITIVE_INFINITY)
             tmp.destroy()
         }
 
@@ -393,8 +395,8 @@ Item {
 
         function test_sizeHintNormalization_data() {
             return [
-                    { tag: "fallbackValues",  widthHints: [-1, -1, -1], expected:[0,42,1000000000], implicitWidth: 42},
-                    { tag: "acceptZeroWidths",  widthHints: [0, 0, 0], expected:[0,0,0], implicitWidth: 42},
+                    { tag: "fallbackValues",  widthHints: [-1, -1, -1], implicitWidth: 42, expected:[0,42,Number.POSITIVE_INFINITY]},
+                    { tag: "acceptZeroWidths",  widthHints: [0, 0, 0], implicitWidth: 42, expected:[0,0,0]},
                     { tag: "123",  widthHints: [1,2,3],  expected:[1,2,3]},
                     { tag: "132",  widthHints: [1,3,2],  expected:[1,2,2]},
                     { tag: "213",  widthHints: [2,1,3],  expected:[2,2,3]},
@@ -402,12 +404,12 @@ Item {
                     { tag: "321",  widthHints: [3,2,1],  expected:[1,1,1]},
                     { tag: "312",  widthHints: [3,1,2],  expected:[2,2,2]},
 
-                    { tag: "1i3",  widthHints: [1,-1,3],  expected:[1,2,3], implicitWidth: 2},
-                    { tag: "1i2",  widthHints: [1,-1,2],  expected:[1,2,2], implicitWidth: 3},
-                    { tag: "2i3",  widthHints: [2,-1,3],  expected:[2,2,3], implicitWidth: 1},
-                    { tag: "2i1",  widthHints: [2,-1,1],  expected:[1,1,1], implicitWidth: 3},
-                    { tag: "3i1",  widthHints: [3,-1,1],  expected:[1,1,1], implicitWidth: 2},
-                    { tag: "3i2",  widthHints: [3,-1,2],  expected:[2,2,2], implicitWidth: 1},
+                    { tag: "1i3",  widthHints: [1,-1,3], implicitWidth: 2,  expected:[1,2,3]},
+                    { tag: "1i2",  widthHints: [1,-1,2], implicitWidth: 3,  expected:[1,2,2]},
+                    { tag: "2i3",  widthHints: [2,-1,3], implicitWidth: 1,  expected:[2,2,3]},
+                    { tag: "2i1",  widthHints: [2,-1,1], implicitWidth: 3,  expected:[1,1,1]},
+                    { tag: "3i1",  widthHints: [3,-1,1], implicitWidth: 2,  expected:[1,1,1]},
+                    { tag: "3i2",  widthHints: [3,-1,2], implicitWidth: 1,  expected:[2,2,2]},
                     ];
         }
 
@@ -495,15 +497,19 @@ Item {
             child.Layout.preferredWidth = -1
             compare(itemSizeHints(layout), [0, 0, 3])
             child.Layout.maximumWidth = -1
-            compare(itemSizeHints(layout), [0, 0, 1000000000])
+            compare(itemSizeHints(layout), [0, 0, Number.POSITIVE_INFINITY])
+            layout.Layout.maximumWidth = 1000
+            compare(itemSizeHints(layout), [0, 0, 1000])
+            layout.Layout.maximumWidth = -1
+            compare(itemSizeHints(layout), [0, 0, Number.POSITIVE_INFINITY])
 
             layout.implicitWidthChangedCount = 0
             child.Layout.minimumWidth = 10
-            compare(itemSizeHints(layout), [10, 10, 1000000000])
+            compare(itemSizeHints(layout), [10, 10, Number.POSITIVE_INFINITY])
             compare(layout.implicitWidthChangedCount, 1)
 
             child.Layout.preferredWidth = 20
-            compare(itemSizeHints(layout), [10, 20, 1000000000])
+            compare(itemSizeHints(layout), [10, 20, Number.POSITIVE_INFINITY])
             compare(layout.implicitWidthChangedCount, 2)
 
             child.Layout.maximumWidth = 30
@@ -518,6 +524,11 @@ Item {
             compare(itemSizeHints(layout), [10, 20, 30])
             compare(layout.implicitWidthChangedCount, 4)
 
+            layout.Layout.maximumWidth = 29
+            compare(layout.Layout.maximumWidth, 29)
+            layout.Layout.maximumWidth = -1
+            compare(layout.Layout.maximumWidth, 30)
+
             layout.destroy()
         }
         Component {
-- 
GitLab