summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/graphicsview/qgraphicslayoutitem.cpp51
-rw-r--r--src/gui/graphicsview/qgraphicslayoutitem_p.h6
-rw-r--r--src/gui/graphicsview/qgridlayoutengine.cpp251
-rw-r--r--src/gui/graphicsview/qgridlayoutengine_p.h23
-rw-r--r--tests/auto/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp364
5 files changed, 678 insertions, 17 deletions
diff --git a/src/gui/graphicsview/qgraphicslayoutitem.cpp b/src/gui/graphicsview/qgraphicslayoutitem.cpp
index ad4b2b5..634f68c 100644
--- a/src/gui/graphicsview/qgraphicslayoutitem.cpp
+++ b/src/gui/graphicsview/qgraphicslayoutitem.cpp
@@ -48,6 +48,7 @@
#include "qgraphicslayoutitem.h"
#include "qgraphicslayoutitem_p.h"
#include "qwidget.h"
+#include "qgraphicswidget.h"
#include <QtDebug>
@@ -139,9 +140,11 @@ QSizeF *QGraphicsLayoutItemPrivate::effectiveSizeHints(const QSizeF &constraint)
if (!sizeHintCacheDirty && cachedConstraint == constraint)
return cachedSizeHints;
+ const bool hasConstraint = constraint.width() >= 0 || constraint.height() >= 0;
+
for (int i = 0; i < Qt::NSizeHints; ++i) {
cachedSizeHints[i] = constraint;
- if (userSizeHints)
+ if (userSizeHints && !hasConstraint)
combineSize(cachedSizeHints[i], userSizeHints[i]);
}
@@ -259,6 +262,52 @@ void QGraphicsLayoutItemPrivate::setSizeComponent(
q->updateGeometry();
}
+
+bool QGraphicsLayoutItemPrivate::hasHeightForWidth() const
+{
+ Q_Q(const QGraphicsLayoutItem);
+ if (isLayout) {
+ const QGraphicsLayout *l = static_cast<const QGraphicsLayout *>(q);
+ for (int i = l->count() - 1; i >= 0; --i) {
+ if (QGraphicsLayoutItemPrivate::get(l->itemAt(i))->hasHeightForWidth())
+ return true;
+ }
+ } else if (QGraphicsItem *item = q->graphicsItem()) {
+ if (item->isWidget()) {
+ QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item);
+ if (w->layout()) {
+ return QGraphicsLayoutItemPrivate::get(w->layout())->hasHeightForWidth();
+ }
+ }
+ }
+ return q->sizePolicy().hasHeightForWidth();
+}
+
+bool QGraphicsLayoutItemPrivate::hasWidthForHeight() const
+{
+ // enable this code when we add QSizePolicy::hasWidthForHeight() (For 4.8)
+#if 1
+ return false;
+#else
+ Q_Q(const QGraphicsLayoutItem);
+ if (isLayout) {
+ const QGraphicsLayout *l = static_cast<const QGraphicsLayout *>(q);
+ for (int i = l->count() - 1; i >= 0; --i) {
+ if (QGraphicsLayoutItemPrivate::get(l->itemAt(i))->hasWidthForHeight())
+ return true;
+ }
+ } else if (QGraphicsItem *item = q->graphicsItem()) {
+ if (item->isWidget()) {
+ QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item);
+ if (w->layout()) {
+ return QGraphicsLayoutItemPrivate::get(w->layout())->hasWidthForHeight();
+ }
+ }
+ }
+ return q->sizePolicy().hasWidthForHeight();
+#endif
+}
+
/*!
\class QGraphicsLayoutItem
\brief The QGraphicsLayoutItem class can be inherited to allow your custom
diff --git a/src/gui/graphicsview/qgraphicslayoutitem_p.h b/src/gui/graphicsview/qgraphicslayoutitem_p.h
index 15cc7a5..b752e03 100644
--- a/src/gui/graphicsview/qgraphicslayoutitem_p.h
+++ b/src/gui/graphicsview/qgraphicslayoutitem_p.h
@@ -65,6 +65,9 @@ class Q_AUTOTEST_EXPORT QGraphicsLayoutItemPrivate
public:
virtual ~QGraphicsLayoutItemPrivate();
QGraphicsLayoutItemPrivate(QGraphicsLayoutItem *parent, bool isLayout);
+ static QGraphicsLayoutItemPrivate *get(QGraphicsLayoutItem *q) { return q->d_func();}
+ static const QGraphicsLayoutItemPrivate *get(const QGraphicsLayoutItem *q) { return q->d_func();}
+
void init();
QSizeF *effectiveSizeHints(const QSizeF &constraint) const;
QGraphicsItem *parentItem() const;
@@ -73,6 +76,9 @@ public:
enum SizeComponent { Width, Height };
void setSizeComponent(Qt::SizeHint which, SizeComponent component, qreal value);
+ bool hasHeightForWidth() const;
+ bool hasWidthForHeight() const;
+
QSizePolicy sizePolicy;
QGraphicsLayoutItem *parent;
diff --git a/src/gui/graphicsview/qgridlayoutengine.cpp b/src/gui/graphicsview/qgridlayoutengine.cpp
index ae5bf90..1e3addc 100644
--- a/src/gui/graphicsview/qgridlayoutengine.cpp
+++ b/src/gui/graphicsview/qgridlayoutengine.cpp
@@ -545,6 +545,24 @@ QSizePolicy::Policy QGridLayoutItem::sizePolicy(Qt::Orientation orientation) con
: sizePolicy.verticalPolicy();
}
+/*
+ returns true if the size policy returns true for either hasHeightForWidth()
+ or hasWidthForHeight()
+ */
+bool QGridLayoutItem::hasDynamicConstraint() const
+{
+ return QGraphicsLayoutItemPrivate::get(q_layoutItem)->hasHeightForWidth()
+ || QGraphicsLayoutItemPrivate::get(q_layoutItem)->hasWidthForHeight();
+}
+
+Qt::Orientation QGridLayoutItem::dynamicConstraintOrientation() const
+{
+ if (QGraphicsLayoutItemPrivate::get(q_layoutItem)->hasHeightForWidth())
+ return Qt::Vertical;
+ else //if (QGraphicsLayoutItemPrivate::get(q_layoutItem)->hasWidthForHeight())
+ return Qt::Horizontal;
+}
+
QSizePolicy::ControlTypes QGridLayoutItem::controlTypes(LayoutSide /* side */) const
{
return q_layoutItem->sizePolicy().controlType();
@@ -613,7 +631,14 @@ QRectF QGridLayoutItem::geometryWithin(qreal x, qreal y, qreal width, qreal heig
qreal cellWidth = width;
qreal cellHeight = height;
- QSizeF size = effectiveMaxSize().boundedTo(QSizeF(cellWidth, cellHeight));
+ QSize constraint;
+ if (hasDynamicConstraint()) {
+ if (dynamicConstraintOrientation() == Qt::Vertical)
+ constraint.setWidth(cellWidth);
+ else
+ constraint.setHeight(cellHeight);
+ }
+ QSizeF size = effectiveMaxSize(constraint).boundedTo(QSizeF(cellWidth, cellHeight));
width = size.width();
height = size.height();
@@ -675,13 +700,13 @@ void QGridLayoutItem::insertOrRemoveRows(int row, int delta, Qt::Orientation ori
Note that effectiveSizeHint does not take sizePolicy into consideration,
(since it only evaluates the hints, as the name implies)
*/
-QSizeF QGridLayoutItem::effectiveMaxSize() const
+QSizeF QGridLayoutItem::effectiveMaxSize(const QSizeF &constraint) const
{
- QSizeF size;
+ QSizeF size = constraint;
bool vGrow = (sizePolicy(Qt::Vertical) & QSizePolicy::GrowFlag) == QSizePolicy::GrowFlag;
bool hGrow = (sizePolicy(Qt::Horizontal) & QSizePolicy::GrowFlag) == QSizePolicy::GrowFlag;
if (!vGrow || !hGrow) {
- QSizeF pref = layoutItem()->effectiveSizeHint(Qt::PreferredSize);
+ QSizeF pref = layoutItem()->effectiveSizeHint(Qt::PreferredSize, constraint);
if (!vGrow)
size.setHeight(pref.height());
if (!hGrow)
@@ -689,7 +714,7 @@ QSizeF QGridLayoutItem::effectiveMaxSize() const
}
if (!size.isValid()) {
- QSizeF maxSize = layoutItem()->effectiveSizeHint(Qt::MaximumSize);
+ QSizeF maxSize = layoutItem()->effectiveSizeHint(Qt::MaximumSize, constraint);
if (size.width() == -1)
size.setWidth(maxSize.width());
if (size.height() == -1)
@@ -1010,6 +1035,7 @@ void QGridLayoutEngine::invalidate()
q_cachedEffectiveLastRows[Ver] = -1;
q_cachedDataForStyleInfo.invalidate();
q_cachedSize = QSizeF();
+ q_cachedConstraintOrientation = UnknownConstraint;
}
static void visualRect(QRectF *geom, Qt::LayoutDirection dir, const QRectF &contentsRect)
@@ -1074,10 +1100,13 @@ QRectF QGridLayoutEngine::cellRect(const QLayoutStyleInfo &styleInfo,
}
QSizeF QGridLayoutEngine::sizeHint(const QLayoutStyleInfo &styleInfo, Qt::SizeHint which,
- const QSizeF & /* constraint */) const
+ const QSizeF &constraint) const
{
ensureColumnAndRowData(styleInfo);
+ if (hasDynamicConstraint())
+ return dynamicallyConstrainedSizeHint(which, constraint);
+
switch (which) {
case Qt::MinimumSize:
return QSizeF(q_totalBoxes[Hor].q_minimumSize, q_totalBoxes[Ver].q_minimumSize);
@@ -1375,7 +1404,11 @@ void QGridLayoutEngine::fillRowData(QGridLayoutRowData *rowData, const QLayoutSt
box = &multiCell.q_box;
multiCell.q_stretch = itemStretch;
}
- box->combine(item->box(orientation));
+ // Items with constraints are not included in the orientation that
+ // they are constrained (since it depends on the hfw/constraint function).
+ // They must be combined at a later stage.
+ if (!item->hasDynamicConstraint() || orientation != item->dynamicConstraintOrientation())
+ box->combine(item->box(orientation));
if (effectiveRowSpan == 1) {
QSizePolicy::ControlTypes controls = item->controlTypes(top);
@@ -1532,6 +1565,138 @@ void QGridLayoutEngine::ensureColumnAndRowData(const QLayoutStyleInfo &styleInfo
q_cachedDataForStyleInfo = styleInfo;
}
+QSizeF QGridLayoutEngine::dynamicallyConstrainedSizeHint(Qt::SizeHint which,
+ const QSizeF &constraint) const
+{
+ Q_ASSERT(hasDynamicConstraint());
+ if (constraint.width() < 0 && constraint.height() < 0) {
+ // Process the hfw / wfh items that we did not process in fillRowData()
+ const Qt::Orientation constraintOrient = constraintOrientation();
+
+ QGridLayoutRowData rowData = constraintOrient == Qt::Vertical ? q_rowData : q_columnData;
+ for (int i = q_items.count() - 1; i >= 0; --i) {
+ QGridLayoutItem *item = q_items.at(i);
+ if (item->hasDynamicConstraint()) {
+ QGridLayoutBox box = item->box(constraintOrient);
+ QGridLayoutBox &rowBox = rowData.boxes[item->firstRow(constraintOrient)];
+ rowBox.combine(box);
+ }
+ }
+
+ QGridLayoutBox totalBoxes[2];
+ if (constraintOrient == Qt::Vertical) {
+ totalBoxes[Hor] = q_columnData.totalBox(0, columnCount());
+ totalBoxes[Ver] = rowData.totalBox(0, rowCount());
+ } else {
+ totalBoxes[Hor] = rowData.totalBox(0, columnCount());
+ totalBoxes[Ver] = q_rowData.totalBox(0, rowCount());
+ }
+ return QSizeF(totalBoxes[Hor].q_sizes(which), totalBoxes[Ver].q_sizes(which));
+ }
+
+
+ Q_ASSERT(constraint.width() >= 0 || constraint.height() >= 0);
+ q_xx.resize(columnCount());
+ q_yy.resize(rowCount());
+ q_widths.resize(columnCount());
+ q_heights.resize(rowCount());
+ q_descents.resize(rowCount());
+
+
+ const Qt::Orientation orientation = constraintOrientation();
+ QGridLayoutRowData *colData;
+ QGridLayoutRowData constrainedRowData;
+ QGridLayoutBox *totalBox;
+ qreal *sizes;
+ qreal *pos;
+ qreal *descents;
+ qreal targetSize;
+ qreal cCount;
+ qreal rCount;
+
+ if (orientation == Qt::Vertical) {
+ // height for width
+ colData = &q_columnData;
+ totalBox = &q_totalBoxes[Hor];
+ sizes = q_widths.data();
+ pos = q_xx.data();
+ descents = 0;
+ targetSize = constraint.width();
+ cCount = columnCount();
+ rCount = rowCount();
+ constrainedRowData = q_rowData;
+ } else {
+ // width for height
+ colData = &q_rowData;
+ totalBox = &q_totalBoxes[Ver];
+ sizes = q_heights.data();
+ pos = q_yy.data();
+ descents = q_descents.data();
+ targetSize = constraint.height();
+ cCount = rowCount();
+ rCount = columnCount();
+ constrainedRowData = q_columnData;
+ }
+ colData->calculateGeometries(0, cCount, targetSize, pos, sizes, descents, *totalBox);
+ for (int i = q_items.count() - 1; i >= 0; --i) {
+ QGridLayoutItem *item = q_items.at(i);
+
+ if (item->hasDynamicConstraint()) {
+ const qreal size = sizes[item->firstColumn(orientation)];
+ QGridLayoutBox box = item->box(orientation, size);
+ QGridLayoutBox &rowBox = constrainedRowData.boxes[item->firstRow(orientation)];
+ rowBox.combine(box);
+ }
+ }
+ const qreal newSize = constrainedRowData.totalBox(0, rCount).q_sizes(which);
+
+ return (orientation == Qt::Vertical) ? QSizeF(targetSize, newSize) : QSizeF(newSize, targetSize);
+}
+
+
+/**
+ returns false if the layout has contradicting constraints (i.e. some items with a horizontal
+ constraint and other items with a vertical constraint)
+ */
+bool QGridLayoutEngine::ensureDynamicConstraint() const
+{
+ if (q_cachedConstraintOrientation == UnknownConstraint) {
+ for (int i = q_items.count() - 1; i >= 0; --i) {
+ QGridLayoutItem *item = q_items.at(i);
+ if (item->hasDynamicConstraint()) {
+ Qt::Orientation itemConstraintOrientation = item->dynamicConstraintOrientation();
+ if (q_cachedConstraintOrientation == UnknownConstraint) {
+ q_cachedConstraintOrientation = itemConstraintOrientation;
+ } else if (q_cachedConstraintOrientation != itemConstraintOrientation) {
+ q_cachedConstraintOrientation = UnfeasibleConstraint;
+ qWarning("QGridLayoutEngine: Unfeasible, cannot mix horizontal and"
+ " vertical constraint in the same layout");
+ return false;
+ }
+ }
+ }
+ if (q_cachedConstraintOrientation == UnknownConstraint)
+ q_cachedConstraintOrientation = NoConstraint;
+ }
+ return true;
+}
+
+bool QGridLayoutEngine::hasDynamicConstraint() const
+{
+ if (!ensureDynamicConstraint())
+ return false;
+ return q_cachedConstraintOrientation != NoConstraint;
+}
+
+/*
+ * return value is only valid if hasConstraint() returns true
+ */
+Qt::Orientation QGridLayoutEngine::constraintOrientation() const
+{
+ (void)ensureDynamicConstraint();
+ return (Qt::Orientation)q_cachedConstraintOrientation;
+}
+
void QGridLayoutEngine::ensureGeometries(const QLayoutStyleInfo &styleInfo,
const QSizeF &size) const
{
@@ -1544,10 +1709,74 @@ void QGridLayoutEngine::ensureGeometries(const QLayoutStyleInfo &styleInfo,
q_widths.resize(columnCount());
q_heights.resize(rowCount());
q_descents.resize(rowCount());
- q_columnData.calculateGeometries(0, columnCount(), size.width(), q_xx.data(), q_widths.data(),
- 0, q_totalBoxes[Hor]);
- q_rowData.calculateGeometries(0, rowCount(), size.height(), q_yy.data(), q_heights.data(),
- q_descents.data(), q_totalBoxes[Ver]);
+
+
+ Qt::Orientation orientation = Qt::Vertical;
+ if (hasDynamicConstraint())
+ orientation = constraintOrientation();
+
+ /*
+ In order to do hfw we need to first distribute the columns, then the rows.
+ In order to do wfh we need to first distribute the rows, then the columns.
+
+ If there is no constraint, the order of distributing the rows or columns first is irrelevant.
+ We choose horizontal just to keep the same behaviour as before (however, there shouldn't
+ be any behaviour difference).
+ */
+
+ QGridLayoutRowData *colData;
+ QGridLayoutRowData rowData;
+ qreal *widths;
+ qreal *heights;
+ qreal *xx;
+ qreal *yy;
+ qreal *xdescents = 0;
+ qreal *ydescents = 0;
+ qreal cCount;
+ qreal rCount;
+ QSizeF oSize = size;
+ if (orientation == Qt::Vertical) {
+ // height for width
+ colData = &q_columnData;
+ rowData = q_rowData;
+ widths = q_widths.data();
+ heights = q_heights.data();
+ xx = q_xx.data();
+ yy = q_yy.data();
+ cCount = columnCount();
+ rCount = rowCount();
+ ydescents = q_descents.data();
+ } else {
+ // width for height
+ colData = &q_rowData;
+ rowData = q_columnData;
+ widths = q_heights.data();
+ heights = q_widths.data();
+ xx = q_yy.data();
+ yy = q_xx.data();
+ cCount = rowCount();
+ rCount = columnCount();
+ xdescents = q_descents.data();
+ oSize.transpose();
+ }
+
+ colData->calculateGeometries(0, cCount, oSize.width(), xx, widths,
+ xdescents, q_totalBoxes[orientation == Qt::Horizontal]);
+ for (int i = q_items.count() - 1; i >= 0; --i) {
+ QGridLayoutItem *item = q_items.at(i);
+ const int col = item->firstColumn(orientation);
+ const int row = item->firstRow(orientation);
+ if (item->hasDynamicConstraint()) {
+ const qreal sz = widths[col];
+ QGridLayoutBox box = item->box(orientation, sz);
+ rowData.boxes[row].combine(box);
+ }
+ }
+
+ QGridLayoutBox &totalBox = q_totalBoxes[orientation == Qt::Vertical];
+ totalBox = rowData.totalBox(0, rCount);
+ rowData.calculateGeometries(0, rCount, oSize.height(), yy, heights,
+ ydescents, totalBox);
q_cachedSize = size;
}
diff --git a/src/gui/graphicsview/qgridlayoutengine_p.h b/src/gui/graphicsview/qgridlayoutengine_p.h
index 9ac9a8e..580af7e 100644
--- a/src/gui/graphicsview/qgridlayoutengine_p.h
+++ b/src/gui/graphicsview/qgridlayoutengine_p.h
@@ -91,6 +91,14 @@ enum LayoutSide {
Bottom
};
+enum {
+ NoConstraint,
+ HorizontalConstraint,
+ VerticalConstraint,
+ UnknownConstraint, // need to update cache
+ UnfeasibleConstraint // not feasible, it be has some items with Vertical and others with Horizontal constraints
+};
+
template <typename T>
class QLayoutParameter
{
@@ -270,6 +278,10 @@ public:
inline void setAlignment(Qt::Alignment alignment) { q_alignment = alignment; }
QSizePolicy::Policy sizePolicy(Qt::Orientation orientation) const;
+
+ bool hasDynamicConstraint() const;
+ Qt::Orientation dynamicConstraintOrientation() const;
+
QSizePolicy::ControlTypes controlTypes(LayoutSide side) const;
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
QGridLayoutBox box(Qt::Orientation orientation, qreal constraint = -1.0) const;
@@ -280,7 +292,7 @@ public:
void setGeometry(const QRectF &rect);
void transpose();
void insertOrRemoveRows(int row, int delta, Qt::Orientation orientation = Qt::Vertical);
- QSizeF effectiveMaxSize() const;
+ QSizeF effectiveMaxSize(const QSizeF &constraint) const;
#ifdef QT_DEBUG
void dump(int indent = 0) const;
@@ -372,6 +384,14 @@ public:
int column, int rowSpan, int columnSpan) const;
QSizeF sizeHint(const QLayoutStyleInfo &styleInfo, Qt::SizeHint which,
const QSizeF &constraint) const;
+
+ // heightForWidth / widthForHeight support
+ QSizeF dynamicallyConstrainedSizeHint(Qt::SizeHint which, const QSizeF &constraint) const;
+ bool ensureDynamicConstraint() const;
+ bool hasDynamicConstraint() const;
+ Qt::Orientation constraintOrientation() const;
+
+
QSizePolicy::ControlTypes controlTypes(LayoutSide side) const;
void transpose();
void setVisualDirection(Qt::LayoutDirection direction);
@@ -405,6 +425,7 @@ private:
// Lazily computed from the above user input
mutable int q_cachedEffectiveFirstRows[NOrientations];
mutable int q_cachedEffectiveLastRows[NOrientations];
+ mutable quint8 q_cachedConstraintOrientation : 2;
// Layout item input
mutable QLayoutStyleInfo q_cachedDataForStyleInfo;
diff --git a/tests/auto/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp b/tests/auto/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp
index 5b03767..03c1d5b 100644
--- a/tests/auto/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp
+++ b/tests/auto/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp
@@ -107,12 +107,13 @@ private slots:
void avoidRecursionInInsertItem();
void styleInfoLeak();
void task236367_maxSizeHint();
+ void heightForWidth();
};
class RectWidget : public QGraphicsWidget
{
public:
- RectWidget(QGraphicsItem *parent = 0) : QGraphicsWidget(parent){}
+ RectWidget(QGraphicsItem *parent = 0) : QGraphicsWidget(parent), m_fnConstraint(0) {}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
@@ -125,9 +126,12 @@ public:
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const
{
- if (m_sizeHints[which].isValid()) {
+ if (constraint.width() < 0 && constraint.height() < 0 && m_sizeHints[which].isValid()) {
return m_sizeHints[which];
}
+ if (m_fnConstraint) {
+ return m_fnConstraint(which, constraint);
+ }
return QGraphicsWidget::sizeHint(which, constraint);
}
@@ -136,7 +140,13 @@ public:
updateGeometry();
}
+ void setConstraintFunction(QSizeF (*fnConstraint)(Qt::SizeHint, const QSizeF &)) {
+ m_fnConstraint = fnConstraint;
+ }
+
QSizeF m_sizeHints[Qt::NSizeHints];
+ QSizeF (*m_fnConstraint)(Qt::SizeHint, const QSizeF &);
+
};
struct ItemDesc
@@ -146,7 +156,8 @@ struct ItemDesc
m_rowSpan(1),
m_colSpan(1),
m_sizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)),
- m_align(0)
+ m_align(0),
+ m_fnConstraint(0)
{
}
@@ -213,8 +224,20 @@ struct ItemDesc
return (*this);
}
+ ItemDesc &heightForWidth(QSizeF (*fnConstraint)(Qt::SizeHint, const QSizeF &)) {
+ m_fnConstraint = fnConstraint;
+ m_constraintOrientation = Qt::Vertical;
+ return (*this);
+ }
+
void apply(QGraphicsGridLayout *layout, QGraphicsWidget *item) {
- item->setSizePolicy(m_sizePolicy);
+ QSizePolicy sp = m_sizePolicy;
+ if (m_fnConstraint) {
+ sp.setHeightForWidth(m_constraintOrientation == Qt::Vertical);
+ //sp.setWidthForHeight(m_constraintOrientation == Qt::Horizontal);
+ }
+
+ item->setSizePolicy(sp);
for (int i = 0; i < Qt::NSizeHints; ++i) {
if (!m_sizes[i].isValid())
continue;
@@ -233,6 +256,7 @@ struct ItemDesc
break;
}
}
+
layout->addItem(item, m_pos.first, m_pos.second, m_rowSpan, m_colSpan);
layout->setAlignment(item, m_align);
}
@@ -240,6 +264,7 @@ struct ItemDesc
void apply(QGraphicsGridLayout *layout, RectWidget *item) {
for (int i = 0; i < Qt::NSizeHints; ++i)
item->setSizeHint((Qt::SizeHint)i, m_sizeHints[i]);
+ item->setConstraintFunction(m_fnConstraint);
apply(layout, static_cast<QGraphicsWidget*>(item));
}
@@ -251,6 +276,9 @@ struct ItemDesc
QSizeF m_sizeHints[Qt::NSizeHints];
QSizeF m_sizes[Qt::NSizeHints];
Qt::Alignment m_align;
+
+ Qt::Orientation m_constraintOrientation;
+ QSizeF (*m_fnConstraint)(Qt::SizeHint, const QSizeF &);
};
typedef QList<ItemDesc> ItemList;
@@ -2116,6 +2144,17 @@ void tst_QGraphicsGridLayout::alignment2()
delete widget;
}
+static QSizeF hfw1(Qt::SizeHint, const QSizeF &constraint)
+{
+ QSizeF result(constraint);
+ if (constraint.width() < 0 && constraint.height() < 0) {
+ return QSizeF(50, 400);
+ } else if (constraint.width() >= 0) {
+ result.setHeight(20000./constraint.width());
+ }
+ return result;
+}
+
void tst_QGraphicsGridLayout::geometries_data()
{
@@ -2145,6 +2184,186 @@ void tst_QGraphicsGridLayout::geometries_data()
<< QRectF(0, 0, 60,10) << QRectF(0, 10, 60,10)
);
+ // change layout height and verify
+ QTest::newRow("hfw-h401") << (ItemList()
+ << ItemDesc(0,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(0,1)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,1)
+ .minSize(QSizeF(40,40))
+ .preferredSize(QSizeF(50,400))
+ .maxSize(QSizeF(500, 500))
+ .heightForWidth(hfw1)
+ )
+ << QSizeF(100, 401)
+ << (RectList()
+ << QRectF(0, 0, 50, 1) << QRectF(50, 0, 50, 1)
+ << QRectF(0, 1, 50,100) << QRectF(50, 1, 50,400)
+ );
+
+
+ QTest::newRow("hfw-h408") << (ItemList()
+ << ItemDesc(0,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(0,1)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,1)
+ .minSize(QSizeF(40,40))
+ .preferredSize(QSizeF(50,400))
+ .maxSize(QSizeF(500, 500))
+ .heightForWidth(hfw1)
+ )
+ << QSizeF(100, 408)
+ << (RectList()
+ << QRectF(0, 0, 50, 8) << QRectF(50, 0, 50, 8)
+ << QRectF(0, 8, 50,100) << QRectF(50, 8, 50,400)
+ );
+
+ QTest::newRow("hfw-h410") << (ItemList()
+ << ItemDesc(0,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(0,1)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,1)
+ .minSize(QSizeF(40,40))
+ .preferredSize(QSizeF(50,400))
+ .maxSize(QSizeF(500, 500))
+ .heightForWidth(hfw1)
+ )
+ << QSizeF(100, 410)
+ << (RectList()
+ << QRectF(0, 0, 50,10) << QRectF(50, 0, 50,10)
+ << QRectF(0, 10, 50,100) << QRectF(50, 10, 50,400)
+ );
+
+ QTest::newRow("hfw-h470") << (ItemList()
+ << ItemDesc(0,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(0,1)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,1)
+ .minSize(QSizeF(40,40))
+ .preferredSize(QSizeF(50,400))
+ .maxSize(QSizeF(500, 500))
+ .heightForWidth(hfw1)
+ )
+ << QSizeF(100, 470)
+ << (RectList()
+ << QRectF(0, 0, 50,70) << QRectF(50, 0, 50,70)
+ << QRectF(0, 70, 50,100) << QRectF(50, 70, 50,400)
+ );
+
+
+ // change layout width and verify
+ QTest::newRow("hfw-w100") << (ItemList()
+ << ItemDesc(0,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(0,1)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,1)
+ .minSize(QSizeF(40,40))
+ .preferredSize(QSizeF(50,400))
+ .maxSize(QSizeF(5000, 5000))
+ .heightForWidth(hfw1)
+ )
+ << QSizeF(100, 401)
+ << (RectList()
+ << QRectF( 0, 0, 50, 1) << QRectF( 50, 0, 50, 1)
+ << QRectF( 0, 1, 50, 100) << QRectF( 50, 1, 50, 400)
+ );
+
+ QTest::newRow("hfw-w160") << (ItemList()
+ << ItemDesc(0,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(0,1)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,1)
+ .minSize(QSizeF(40,40))
+ .preferredSize(QSizeF(50,400))
+ .maxSize(QSizeF(5000, 5000))
+ .heightForWidth(hfw1)
+ )
+ << QSizeF(160, 401)
+ << (RectList()
+ << QRectF( 0, 0, 80, 100) << QRectF( 80, 0, 80, 100)
+ << QRectF( 0, 100, 80, 100) << QRectF( 80, 100, 80, 250)
+ );
+
+
+ QTest::newRow("hfw-w500") << (ItemList()
+ << ItemDesc(0,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(0,1)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,0)
+ .minSize(QSizeF(1,1))
+ .preferredSize(QSizeF(50,10))
+ .maxSize(QSizeF(100, 100))
+ << ItemDesc(1,1)
+ .minSize(QSizeF(40,40))
+ .preferredSize(QSizeF(50,400))
+ .maxSize(QSizeF(5000, 5000))
+ .heightForWidth(hfw1)
+ )
+ << QSizeF(500, 401)
+ << (RectList()
+ << QRectF( 0, 0, 100, 100) << QRectF(100, 0, 100, 100)
+ << QRectF( 0, 100, 100, 100) << QRectF(100, 100, 400, 50)
+ );
+
}
void tst_QGraphicsGridLayout::geometries()
@@ -2215,6 +2434,143 @@ void tst_QGraphicsGridLayout::task236367_maxSizeHint()
QCOMPARE(widget->size(), QSizeF(w, h));
}
+/*
+static qreal hfw(qreal w)
+{
+ if (w == 0)
+ return 20000;
+ return 20000/w;
+}
+*/
+static QSizeF hfw(Qt::SizeHint /*which*/, const QSizeF &constraint)
+{
+ QSizeF result(constraint);
+ const qreal cw = constraint.width();
+ const qreal ch = constraint.height();
+ if (cw < 0 && ch < 0) {
+ return QSizeF(200, 100);
+ } else if (cw >= 0) {
+ result.setHeight(20000./cw);
+ } else if (cw == 0) {
+ result.setHeight(20000);
+ } else if (ch >= 0) {
+ result.setWidth(20000./ch);
+ } else if (ch == 0) {
+ result.setWidth(20000);
+ }
+
+ return result;
+}
+
+static qreal growthFactorBelowPreferredSize(qreal desired, qreal sumAvailable, qreal sumDesired)
+{
+ Q_ASSERT(sumDesired != 0.0);
+ return desired * qPow(sumAvailable / sumDesired, desired / sumDesired);
+}
+
+static void expectedWidth(qreal minSize1, qreal prefSize1,
+ qreal minSize2, qreal prefSize2,
+ qreal targetSize, qreal *width1, qreal *width2)
+{
+ qreal sumAvail,factor1,factor2;
+ // stretch behaviour is different below and above preferred size...
+ if (targetSize < prefSize1 + prefSize2) {
+ sumAvail = targetSize - minSize1 - minSize2;
+ const qreal desired1 = prefSize1 - minSize1;
+ const qreal desired2 = prefSize2 - minSize2;
+ const qreal sumDesired = desired1 + desired2;
+ factor1 = growthFactorBelowPreferredSize(desired1, sumAvail, sumDesired);
+ factor2 = growthFactorBelowPreferredSize(desired2, sumAvail, sumDesired);
+ const qreal sumFactors = factor1 + factor2;
+ *width1 = sumAvail*factor1/sumFactors + minSize1;
+ *width2 = sumAvail*factor2/sumFactors + minSize2;
+ } else {
+ sumAvail = targetSize - prefSize1 - prefSize2;
+ factor1 = prefSize1;
+ factor2 = prefSize2;
+ const qreal sumFactors = factor1 + factor2;
+ *width1 = sumAvail*factor1/sumFactors + prefSize1;
+ *width2 = sumAvail*factor2/sumFactors + prefSize2;
+ }
+}
+
+
+bool qFuzzyCompare(const QSizeF &a, const QSizeF &b)
+{
+ return qFuzzyCompare(a.width(), b.width()) && qFuzzyCompare(a.height(), b.height());
+}
+
+void tst_QGraphicsGridLayout::heightForWidth()
+{
+ QGraphicsWidget *widget = new QGraphicsWidget;
+ QGraphicsGridLayout *layout = new QGraphicsGridLayout;
+ widget->setLayout(layout);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ RectWidget *w00 = new RectWidget;
+ w00->setSizeHint(Qt::MinimumSize, QSizeF(1,1));
+ w00->setSizeHint(Qt::PreferredSize, QSizeF(10,10));
+ w00->setSizeHint(Qt::MaximumSize, QSizeF(100,100));
+ layout->addItem(w00, 0, 0);
+
+ RectWidget *w01 = new RectWidget;
+ w01->setSizeHint(Qt::MinimumSize, QSizeF(1,1));
+ w01->setSizeHint(Qt::PreferredSize, QSizeF(10,10));
+ w01->setSizeHint(Qt::MaximumSize, QSizeF(100,100));
+ layout->addItem(w01, 0, 1);
+
+ RectWidget *w10 = new RectWidget;
+ w10->setSizeHint(Qt::MinimumSize, QSizeF(1,1));
+ w10->setSizeHint(Qt::PreferredSize, QSizeF(10,10));
+ w10->setSizeHint(Qt::MaximumSize, QSizeF(100,100));
+ layout->addItem(w10, 1, 0);
+
+ RectWidget *w11 = new RectWidget;
+ w11->setSizeHint(Qt::MinimumSize, QSizeF(1,1));
+ w11->setSizeHint(Qt::MaximumSize, QSizeF(30000,30000));
+ w11->setConstraintFunction(hfw);
+ QSizePolicy sp(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ sp.setHeightForWidth(true);
+ w11->setSizePolicy(sp);
+ layout->addItem(w11, 1, 1);
+
+ QSizeF prefSize = layout->effectiveSizeHint(Qt::PreferredSize, QSizeF(-1, -1));
+ QCOMPARE(prefSize, QSizeF(10+200, 10+100));
+
+ QCOMPARE(layout->effectiveSizeHint(Qt::MinimumSize, QSizeF(2, -1)), QSizeF(2, 20001));
+ QCOMPARE(layout->effectiveSizeHint(Qt::PreferredSize, QSizeF(2, -1)), QSizeF(2, 20010));
+ QCOMPARE(layout->effectiveSizeHint(Qt::MaximumSize, QSizeF(2, -1)), QSizeF(2, 20100));
+ qreal width1;
+ qreal width2;
+ expectedWidth(1, 10, 1, 200, 20, &width1, &width2);
+ QSizeF expectedSize = hfw(Qt::MinimumSize, QSizeF(width2, -1)) + QSizeF(width1, 1);
+ QCOMPARE(layout->effectiveSizeHint(Qt::MinimumSize, QSizeF(20, -1)), expectedSize);
+ expectedSize.rheight()+=9;
+ QCOMPARE(layout->effectiveSizeHint(Qt::PreferredSize, QSizeF(20, -1)), expectedSize);
+ expectedSize.rheight()+=90;
+ QCOMPARE(layout->effectiveSizeHint(Qt::MaximumSize, QSizeF(20, -1)), expectedSize);
+
+ expectedWidth(1, 10, 1, 200, 300, &width1, &width2);
+ expectedSize = hfw(Qt::MinimumSize, QSizeF(width2, -1)) + QSizeF(width1, 1);
+ QCOMPARE(layout->effectiveSizeHint(Qt::MinimumSize, QSizeF(300, -1)), expectedSize);
+ expectedSize.rheight()+=9;
+ QCOMPARE(layout->effectiveSizeHint(Qt::PreferredSize, QSizeF(300, -1)), expectedSize);
+ // the height of the hfw widget is shorter than the one to the left, which is 100, so
+ // the total height of the last row is 100 (which leaves the layout height to be 200)
+ QCOMPARE(layout->effectiveSizeHint(Qt::MaximumSize, QSizeF(300, -1)), QSizeF(300, 200));
+
+ // the hfw item is shorter than the item to the left
+ expectedWidth(1, 10, 1, 200, 500, &width1, &width2);
+ expectedSize = hfw(Qt::MinimumSize, QSizeF(width2, -1)) + QSizeF(width1, 1);
+ QCOMPARE(layout->effectiveSizeHint(Qt::MinimumSize, QSizeF(500, -1)), expectedSize);
+ expectedSize.rheight()+=9;
+ QCOMPARE(layout->effectiveSizeHint(Qt::PreferredSize, QSizeF(500, -1)), expectedSize);
+ // the height of the hfw widget is shorter than the one to the left, which is 100, so
+ // the total height of the last row is 100 (which leaves the layout height to be 200)
+ QCOMPARE(layout->effectiveSizeHint(Qt::MaximumSize, QSizeF(500, -1)), QSizeF(500, 200));
+
+}
+
QTEST_MAIN(tst_QGraphicsGridLayout)
#include "tst_qgraphicsgridlayout.moc"