Commit 4051e698 authored by Jan Arve Saether's avatar Jan Arve Saether Committed by The Qt Project
Browse files

Fixed some bugs in how effective size hints were calculated


Do not bound explicit preferred size with implicit sizes. This
means that if Layout.preferredWidth was *explicitly* set to 50,
and Layout.maximumWidth had the implicit value 20, the effective
maximum width would be expanded to 50 in order to not disregard
the explicitly set preferred width. (covered by the tag
"expandMaxToExplicitPref" in test_sizeHint)

Note that this doesn't break any autotests, but the row layout
autotest was slightly changed to be able to add the new test cases.

This should make the behavior match the behavior of
QGraphicsGridLayout and QGraphicsLinearLayout

Change-Id: Ia23c8ef909827f14349906c003c72bb83689ef9a
Reviewed-by: default avatarCaroline Chao <caroline.chao@digia.com>
Reviewed-by: default avatarJens Bache-Wiig <jens.bache-wiig@digia.com>
parent 86df745c
6.2 5.10 5.11 5.12 5.12.1 5.12.10 5.12.11 5.12.12 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13 5.13.0 5.13.1 5.13.2 5.14 5.14.0 5.14.1 5.14.2 5.15 5.15.0 5.15.1 5.15.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.9.8 dev old/5.1 old/5.2 wip/calendar wip/tizen v5.15.0-alpha1 v5.14.1 v5.14.0 v5.14.0-rc2 v5.14.0-rc1 v5.14.0-beta3 v5.14.0-beta2 v5.14.0-beta1 v5.14.0-alpha1 v5.13.2 v5.13.1 v5.13.0 v5.13.0-rc3 v5.13.0-rc2 v5.13.0-rc1 v5.13.0-beta4 v5.13.0-beta3 v5.13.0-beta2 v5.13.0-beta1 v5.13.0-alpha1 v5.12.7 v5.12.6 v5.12.5 v5.12.4 v5.12.3 v5.12.2 v5.12.1 v5.12.0 v5.12.0-rc2 v5.12.0-rc1 v5.12.0-beta4 v5.12.0-beta3 v5.12.0-beta2 v5.12.0-beta1 v5.12.0-alpha1 v5.11.3 v5.11.2 v5.11.1 v5.11.0 v5.11.0-rc2 v5.11.0-rc1 v5.11.0-beta4 v5.11.0-beta3 v5.11.0-beta2 v5.11.0-beta1 v5.11.0-alpha1 v5.10.1 v5.10.0 v5.10.0-rc3 v5.10.0-rc2 v5.10.0-rc1 v5.10.0-beta4 v5.10.0-beta3 v5.10.0-beta2 v5.10.0-beta1 v5.10.0-alpha1 v5.9.9 v5.9.8 v5.9.7 v5.9.6 v5.9.5 v5.9.4 v5.9.3 v5.9.2 v5.9.1 v5.9.0 v5.9.0-rc2 v5.9.0-rc1 v5.9.0-beta4 v5.9.0-beta3 v5.9.0-beta2 v5.9.0-beta1 v5.9.0-alpha1 v5.8.0 v5.8.0-rc1 v5.8.0-beta1 v5.8.0-alpha1 v5.7.1 v5.7.0 v5.7.0-rc1 v5.7.0-beta1 v5.7.0-alpha1 v5.6.3 v5.6.2 v5.6.1 v5.6.1-1 v5.6.0 v5.6.0-rc1 v5.6.0-beta1 v5.6.0-alpha1 v5.5.1 v5.5.0 v5.5.0-rc1 v5.5.0-beta1 v5.5.0-alpha1 v5.4.2 v5.4.1 v5.4.0 v5.4.0-rc1 v5.4.0-beta1 v5.4.0-alpha1 v5.3.2 v5.3.1 v5.3.0 v5.3.0-rc1 v5.3.0-beta1 v5.3.0-alpha1 v5.2.1 v5.2.0 v5.2.0-rc1 v5.2.0-beta1 v5.2.0-alpha1 v5.1.1 v5.1.0 v5.1.0-rc2 v5.1.0-rc1
No related merge requests found
Showing with 97 additions and 35 deletions
......@@ -98,14 +98,62 @@ static inline void combineHints(qreal &current, qreal fallbackHint)
current = fallbackHint;
}
static inline void combineSize(QSizeF &result, const QSizeF &fallbackSize)
{
combineHints(result.rwidth(), fallbackSize.width());
combineHints(result.rheight(), fallbackSize.height());
}
static inline void combineImplicitHints(QQuickLayoutAttached *info, Qt::SizeHint which, QSizeF *size)
{
if (!info) return;
Q_ASSERT(which == Qt::MinimumSize || which == Qt::MaximumSize);
const QSizeF constraint(which == Qt::MinimumSize
? QSizeF(info->minimumWidth(), info->minimumHeight())
: QSizeF(info->maximumWidth(), info->maximumHeight()));
if (!info->isExtentExplicitlySet(Qt::Horizontal, which))
combineHints(size->rwidth(), constraint.width());
if (!info->isExtentExplicitlySet(Qt::Vertical, which))
combineHints(size->rheight(), constraint.height());
}
/*!
\internal
Note: Can potentially return the attached QQuickLayoutAttached object through \a attachedInfo.
It is like this is because it enables it to be reused.
The goal of this function is to return the effective minimum, preferred and maximum size hints
that the layout will use for this item.
This function takes care of gathering all explicitly set size hints, normalizes them so
that min < pref < max.
Further, the hints _not_explicitly_ set will then be initialized with the implicit size hints,
which is usually derived from the content of the layouts (or items).
The following table illustrates the preference of the properties used for measuring layout
items. If present, the USER properties will be preferred. If USER properties are not present,
the HINT properties will be preferred. Finally, the FALLBACK properties will be used as an
ultimate fallback.
Note that one can query if the value of Layout.minimumWidth or Layout.maximumWidth has been
explicitly or implicitly set with QQuickLayoutAttached::isExtentExplicitlySet(). This
determines if it should be used as a USER or as a HINT value.
| *Minimum* | *Preferred* | *Maximum* |
+----------------+----------------------+-----------------------+--------------------------+
|USER (explicit) | Layout.minimumWidth | Layout.preferredWidth | Layout.maximumWidth |
|HINT (implicit) | Layout.minimumWidth | implicitWidth | Layout.maximumWidth |
|FALLBACK | 0 | width | Number.POSITIVE_INFINITY |
+----------------+----------------------+-----------------------+--------------------------+
*/
void QQuickGridLayoutItem::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **attachedInfo, bool useFallbackToWidthOrHeight)
{
for (int i = 0; i < Qt::NSizeHints; ++i)
cachedSizeHints[i] = QSizeF();
QQuickLayoutAttached *info = attachedLayoutObject(item, false);
// First, retrieve the user-specified hints from the attached "Layout." properties
if (info) {
......@@ -123,16 +171,16 @@ void QQuickGridLayoutItem::effectiveSizeHints_helper(QQuickItem *item, QSizeF *c
for (int i = 0; i < NSizes; ++i) {
SizeGetter getter = horGetters.call[i];
Q_ASSERT(getter);
cachedSizeHints[i].setWidth((info->*getter)());
if (info->isExtentExplicitlySet(Qt::Horizontal, (Qt::SizeHint)i))
cachedSizeHints[i].setWidth((info->*getter)());
getter = verGetters.call[i];
Q_ASSERT(getter);
cachedSizeHints[i].setHeight((info->*getter)());
if (info->isExtentExplicitlySet(Qt::Vertical, (Qt::SizeHint)i))
cachedSizeHints[i].setHeight((info->*getter)());
}
} else {
for (int i = 0; i < NSizes; ++i)
cachedSizeHints[i] = QSize();
}
cachedSizeHints[Qt::MinimumDescent] = QSize(); //### FIXME when baseline support is added
QSizeF &minS = cachedSizeHints[Qt::MinimumSize];
QSizeF &prefS = cachedSizeHints[Qt::PreferredSize];
......@@ -144,23 +192,21 @@ void QQuickGridLayoutItem::effectiveSizeHints_helper(QQuickItem *item, QSizeF *c
// to: [10, 10, 60]
normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth());
normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight());
/*
The following table illustrates the preference of the properties used for measuring layout
items. If present, the USER properties will be preferred. If USER properties are not present,
the HINT 1 properties will be preferred. Finally, the HINT 2 properties will be used as an
ultimate fallback.
| USER | HINT 1 | HINT 2
-----+--------------------------------+-------------------+-------
MIN | Layout.minimumWidth | | 0
PREF | Layout.preferredWidth | implicitWidth | width
MAX | Layout.maximumWidth | | 1000000000 (-1)
-----+--------------------------------+-------------------+--------
Fixed | Layout.fillWidth | Expanding if layout, Fixed if item |
*/
// All explicit values gathered, now continue to gather the implicit sizes
//--- GATHER MAXIMUM SIZE HINTS ---
combineImplicitHints(info, Qt::MaximumSize, &maxS);
combineSize(maxS, QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity()));
// implicit max or min sizes should not limit an explicitly set preferred size
expandSize(maxS, prefS);
expandSize(maxS, minS);
//--- GATHER MINIMUM SIZE HINTS ---
// They are always 0
combineImplicitHints(info, Qt::MinimumSize, &minS);
expandSize(minS, QSizeF(0,0));
boundSize(minS, prefS);
boundSize(minS, maxS);
//--- GATHER PREFERRED SIZE HINTS ---
// First, from implicitWidth/Height
......@@ -203,17 +249,12 @@ Fixed | Layout.fillWidth | Expanding if layout, Fixed if item |
item->blockSignals(false);
}
}
//--- GATHER MAXIMUM SIZE HINTS ---
combineHints(cachedSizeHints[Qt::MaximumSize].rwidth(), std::numeric_limits<qreal>::infinity());
combineHints(cachedSizeHints[Qt::MaximumSize].rheight(), std::numeric_limits<qreal>::infinity());
//--- GATHER DESCENT
// ### Not implemented
// Normalize again after the implicit hints have been gathered
expandSize(minS, QSizeF(0,0));
boundSize(minS, maxS);
expandSize(prefS, minS);
boundSize(prefS, maxS);
......
......@@ -175,6 +175,22 @@ public:
qreal sizeHint(Qt::SizeHint which, Qt::Orientation orientation) const;
bool isExtentExplicitlySet(Qt::Orientation o, Qt::SizeHint whichSize) const
{
switch (whichSize) {
case Qt::MinimumSize:
return o == Qt::Horizontal ? m_isMinimumWidthSet : m_isMinimumHeightSet;
case Qt::MaximumSize:
return o == Qt::Horizontal ? m_isMaximumWidthSet : m_isMaximumHeightSet;
case Qt::PreferredSize:
return true; // Layout.preferredWidth is always explicitly set
case Qt::MinimumDescent: // Not supported
case Qt::NSizeHints:
return false;
}
return false;
}
signals:
void minimumWidthChanged();
void minimumHeightChanged();
......
......@@ -459,6 +459,12 @@ Item {
{ tag: "propagateMaximumWidth", layoutHints: [10, 20, -1], childHints: [11, 21, 30], expected:[10, 20, 30]},
{ tag: "propagateAll", layoutHints: [-1, -1, -1], childHints: [10, 20, 30], expected:[10, 20, 30]},
{ tag: "propagateCrazy", layoutHints: [-1, -1, -1], childHints: [40, 21, 30], expected:[30, 30, 30]},
{ tag: "expandMinToExplicitPref", layoutHints: [-1, 1, -1], childHints: [11, 21, 31], expected:[ 1, 1, 31]},
{ tag: "expandMaxToExplicitPref", layoutHints: [-1, 99, -1], childHints: [11, 21, 31], expected:[11, 99, 99]},
{ tag: "expandAllToExplicitMin", layoutHints: [99, -1, -1], childHints: [11, 21, 31], expected:[99, 99, 99]},
{ tag: "expandPrefToExplicitMin", layoutHints: [24, -1, -1], childHints: [11, 21, 31], expected:[24, 24, 31]},
{ tag: "boundPrefToExplicitMax", layoutHints: [-1, -1, 19], childHints: [11, 21, 31], expected:[11, 19, 19]},
{ tag: "boundAllToExplicitMax", layoutHints: [-1, -1, 9], childHints: [11, 21, 31], expected:[ 9, 9, 9]},
];
}
......@@ -468,22 +474,21 @@ Item {
function test_sizeHint(data) {
var layout = layout_sizeHint_Component.createObject(container)
layout.Layout.minimumWidth = data.layoutHints[0]
layout.Layout.preferredWidth = data.layoutHints[1]
layout.Layout.maximumWidth = data.layoutHints[2]
var child = layout.children[0].children[0]
var grid = layout.children[0]
grid.Layout.minimumWidth = data.layoutHints[0]
grid.Layout.preferredWidth = data.layoutHints[1]
grid.Layout.maximumWidth = data.layoutHints[2]
var child = grid.children[0]
if (data.implicitWidth !== undefined) {
child.implicitWidth = data.implicitWidth
}
child.Layout.minimumWidth = data.childHints[0]
child.Layout.preferredWidth = data.childHints[1]
child.Layout.maximumWidth = data.childHints[2]
var grid = layout.children[0]
var preferredWidth = layout.Layout.preferredWidth >= 0 ? layout.Layout.preferredWidth : layout.implicitWidth
var effectiveSizeHintResult = [layout.Layout.minimumWidth, preferredWidth, layout.Layout.maximumWidth]
var effectiveSizeHintResult = [layout.Layout.minimumWidth, layout.implicitWidth, layout.Layout.maximumWidth]
compare(effectiveSizeHintResult, data.expected)
layout.destroy()
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment