aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Arve Sæther <jan-arve.saether@qt.io>2022-08-22 14:11:50 +0200
committerJan Arve Sæther <jan-arve.saether@qt.io>2022-12-08 01:01:11 +0100
commit373b6e54dd3b6434ec427d4f5b01335cfaa90dea (patch)
treeeac6a3457da5991d6670020e9c919ac1cdc6036c
parent73a3b69f9ae6d49cc04ce9834ab6f3b88d11e35b (diff)
Add {horizontal,vertical}StretchFactor
This utilizes the standard implementation of stretch factors that is already in the QGridLayoutEngine [ChangeLog][QtQuick][Layouts] Added support for stretch factors Fixes: QTBUG-32923 Change-Id: I4afa7636dda465af2230c2919daa5c40831c44ae Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
-rw-r--r--src/quicklayouts/qquickgridlayoutengine.cpp10
-rw-r--r--src/quicklayouts/qquickgridlayoutengine_p.h2
-rw-r--r--src/quicklayouts/qquicklayout.cpp74
-rw-r--r--src/quicklayouts/qquicklayout_p.h13
-rw-r--r--src/quicklayouts/qquicklinearlayout.cpp40
-rw-r--r--src/quicklayouts/qquicklinearlayout_p.h1
-rw-r--r--src/quicklayouts/qquickstacklayout.cpp4
-rw-r--r--src/quicklayouts/qquickstacklayout_p.h1
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml45
9 files changed, 188 insertions, 2 deletions
diff --git a/src/quicklayouts/qquickgridlayoutengine.cpp b/src/quicklayouts/qquickgridlayoutengine.cpp
index daec5151dc..82d229befb 100644
--- a/src/quicklayouts/qquickgridlayoutengine.cpp
+++ b/src/quicklayouts/qquickgridlayoutengine.cpp
@@ -15,4 +15,14 @@ void QQuickGridLayoutEngine::setAlignment(QQuickItem *quickItem, Qt::Alignment a
}
}
+void QQuickGridLayoutEngine::setStretchFactor(QQuickItem *quickItem, int stretch,
+ Qt::Orientation orientation)
+{
+ Q_ASSERT(stretch >= -1); // -1 is reset
+ if (QGridLayoutItem *item = findLayoutItem(quickItem)) {
+ item->setStretchFactor(stretch, orientation);
+ invalidate();
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/quicklayouts/qquickgridlayoutengine_p.h b/src/quicklayouts/qquickgridlayoutengine_p.h
index 412e56b29a..a59679761d 100644
--- a/src/quicklayouts/qquickgridlayoutengine_p.h
+++ b/src/quicklayouts/qquickgridlayoutengine_p.h
@@ -119,6 +119,8 @@ public:
void setAlignment(QQuickItem *quickItem, Qt::Alignment alignment);
+ void setStretchFactor(QQuickItem *quickItem, int stretch, Qt::Orientation orientation);
+
};
diff --git a/src/quicklayouts/qquicklayout.cpp b/src/quicklayouts/qquicklayout.cpp
index 74167db3e7..3699b3fbcf 100644
--- a/src/quicklayouts/qquicklayout.cpp
+++ b/src/quicklayouts/qquicklayout.cpp
@@ -88,7 +88,9 @@ QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent)
m_isLeftMarginSet(false),
m_isTopMarginSet(false),
m_isRightMarginSet(false),
- m_isBottomMarginSet(false)
+ m_isBottomMarginSet(false),
+ m_horizontalStretch(-1),
+ m_verticalStretch(-1)
{
}
@@ -412,6 +414,76 @@ void QQuickLayoutAttached::setAlignment(Qt::Alignment align)
}
/*!
+ \qmlattachedproperty int Layout::horizontalStretchFactor
+
+ This property allows you to specify the horizontal stretch factor. By default, two identical
+ items arranged in a linear layout will have the same size, but if the first item has a
+ stretch factor of 1 and the second item has a stretch factor of 2, the first item will \e
+ aim to get 1/3 of the available space, and the second will \e aim to get 2/3 of the available
+ space. Note that, whether they become exactly 1/3 and 2/3 of the available space depends on
+ their size hints. This is because when e.g a horizontal layout is shown in its minimum width
+ all its child items will consequently also have their minimum width.
+
+ Likewise, when a horizontal layout has its preferred width, all child items will have their
+ preferred widths, and when a horizontal layout has its maximum width, all child items will have
+ their maximum widths. This strategy is applied regardless of what the individual stretch
+ factors are. As a consequence of this, stretch factors will only determine the growth rate of
+ child items \e between the preferredWidth and maximumWidth range.
+
+ The default value is \c -1, which means that no stretch factor is applied.
+
+ \note This requires that Layout::fillWidth is set to true
+
+ \sa verticalStretchFactor
+*/
+void QQuickLayoutAttached::setHorizontalStretchFactor(int factor)
+{
+ if (factor != m_horizontalStretch) {
+ m_horizontalStretch = factor;
+ if (QQuickLayout *layout = parentLayout()) {
+ layout->setStretchFactor(item(), factor, Qt::Horizontal);
+ invalidateItem();
+ }
+ emit horizontalStretchFactorChanged();
+ }
+}
+
+/*!
+ \qmlattachedproperty int Layout::verticalStretchFactor
+
+ This property allows you to specify the vertical stretch factor. By default, two identical
+ items arranged in a linear layout will have the same size, but if the first item has a
+ stretch factor of 1 and the second item has a stretch factor of 2, the first item will \e
+ aim to get 1/3 of the available space, and the second will \e aim to get 2/3 of the available
+ space. Note that, whether they become exactly 1/3 and 2/3 of the available space depends on
+ their size hints. This is because when e.g a vertical layout is shown in its minimum height
+ all its child items will consequently also have their minimum height.
+
+ Likewise, when a vertical layout has its preferred height, all child items will have their
+ preferred heights, and when a vertical layout has its maximum height, all child items will have
+ their maximum heights. This strategy is applied regardless of what the individual stretch
+ factors are. As a consequence of this, stretch factors will only determine the growth rate of
+ child items \e between the preferredHeight and maximumHeight range.
+
+ The default value is \c -1, which means that no stretch factor is applied.
+
+ \note This requires that Layout::fillHeight is set to true
+
+ \sa horizontalStretchFactor
+*/
+void QQuickLayoutAttached::setVerticalStretchFactor(int factor)
+{
+ if (factor != m_verticalStretch) {
+ m_verticalStretch = factor;
+ if (QQuickLayout *layout = parentLayout()) {
+ layout->setStretchFactor(item(), factor, Qt::Vertical);
+ invalidateItem();
+ }
+ emit verticalStretchFactorChanged();
+ }
+}
+
+/*!
\qmlattachedproperty real Layout::margins
Sets the margins outside of an item to all have the same value. The item
diff --git a/src/quicklayouts/qquicklayout_p.h b/src/quicklayouts/qquicklayout_p.h
index 40ee74614a..df9c4cad97 100644
--- a/src/quicklayouts/qquicklayout_p.h
+++ b/src/quicklayouts/qquicklayout_p.h
@@ -63,6 +63,8 @@ public:
void componentComplete() override;
virtual QSizeF sizeHint(Qt::SizeHint whichSizeHint) const = 0;
virtual void setAlignment(QQuickItem *item, Qt::Alignment align) = 0;
+ virtual void setStretchFactor(QQuickItem *item, int stretchFactor, Qt::Orientation orient) = 0;
+
virtual void invalidate(QQuickItem * childItem = nullptr);
virtual void updateLayoutItems() = 0;
@@ -170,6 +172,8 @@ class Q_QUICKLAYOUTS_PRIVATE_EXPORT QQuickLayoutAttached : public QObject
Q_PROPERTY(int rowSpan READ rowSpan WRITE setRowSpan NOTIFY rowSpanChanged)
Q_PROPERTY(int columnSpan READ columnSpan WRITE setColumnSpan NOTIFY columnSpanChanged)
Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged)
+ Q_PROPERTY(int horizontalStretchFactor READ horizontalStretchFactor WRITE setHorizontalStretchFactor NOTIFY horizontalStretchFactorChanged)
+ Q_PROPERTY(int verticalStretchFactor READ verticalStretchFactor WRITE setVerticalStretchFactor NOTIFY verticalStretchFactorChanged)
Q_PROPERTY(qreal margins READ margins WRITE setMargins NOTIFY marginsChanged)
Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin RESET resetLeftMargin NOTIFY leftMarginChanged)
@@ -224,6 +228,11 @@ public:
Qt::Alignment alignment() const { return m_alignment; }
void setAlignment(Qt::Alignment align);
+ int horizontalStretchFactor() const { return m_horizontalStretch; }
+ void setHorizontalStretchFactor(int stretchFactor);
+ int verticalStretchFactor() const { return m_verticalStretch; }
+ void setVerticalStretchFactor(int stretchFactor);
+
qreal margins() const { return m_defaultMargins; }
void setMargins(qreal m);
@@ -299,6 +308,8 @@ Q_SIGNALS:
void rowSpanChanged();
void columnSpanChanged();
void alignmentChanged();
+ void horizontalStretchFactorChanged();
+ void verticalStretchFactorChanged();
private:
void invalidateItem();
@@ -340,6 +351,8 @@ private:
unsigned m_isRightMarginSet : 1;
unsigned m_isBottomMarginSet : 1;
Qt::Alignment m_alignment;
+ int m_horizontalStretch;
+ int m_verticalStretch;
friend class QQuickLayout;
};
diff --git a/src/quicklayouts/qquicklinearlayout.cpp b/src/quicklayouts/qquicklinearlayout.cpp
index 8cb3ecfcf1..c7beb6045e 100644
--- a/src/quicklayouts/qquicklinearlayout.cpp
+++ b/src/quicklayouts/qquicklinearlayout.cpp
@@ -284,6 +284,12 @@ void QQuickGridLayoutBase::setAlignment(QQuickItem *item, Qt::Alignment alignmen
maybeSubscribeToBaseLineOffsetChanges(item);
}
+void QQuickGridLayoutBase::setStretchFactor(QQuickItem *item, int stretchFactor, Qt::Orientation orient)
+{
+ Q_D(QQuickGridLayoutBase);
+ d->engine.setStretchFactor(item, stretchFactor, orient);
+}
+
QQuickGridLayoutBase::~QQuickGridLayoutBase()
{
Q_D(QQuickGridLayoutBase);
@@ -642,6 +648,8 @@ void QQuickGridLayout::insertLayoutItems()
QQuickLayoutAttached *info = attachedLayoutObject(child, false);
Qt::Alignment alignment;
+ int hStretch = -1;
+ int vStretch = -1;
int row = -1;
int column = -1;
int span[2] = {1,1};
@@ -681,6 +689,12 @@ void QQuickGridLayout::insertLayoutItems()
return;
}
alignment = info->alignment();
+ hStretch = info->horizontalStretchFactor();
+ if (hStretch >= 0 && !info->fillWidth())
+ qmlWarning(child) << "horizontalStretchFactor requires fillWidth to also be set to true";
+ vStretch = info->verticalStretchFactor();
+ if (vStretch >= 0 && !info->fillHeight())
+ qmlWarning(child) << "verticalStretchFactor requires fillHeight to also be set to true";
}
Q_ASSERT(columnSpan >= 1);
@@ -732,6 +746,10 @@ void QQuickGridLayout::insertLayoutItems()
column = nextColumn;
row = nextRow;
QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, row, column, rowSpan, columnSpan, alignment);
+ if (hStretch >= 0)
+ layoutItem->setStretchFactor(hStretch, Qt::Horizontal);
+ if (vStretch >= 0)
+ layoutItem->setStretchFactor(vStretch, Qt::Vertical);
d->engine.insertItem(layoutItem, -1);
}
}
@@ -827,8 +845,17 @@ void QQuickLinearLayout::insertLayoutItems()
QQuickLayoutAttached *info = attachedLayoutObject(child, false);
Qt::Alignment alignment;
- if (info)
+ int hStretch = -1;
+ int vStretch = -1;
+ bool fillWidth = false;
+ bool fillHeight = false;
+ if (info) {
alignment = info->alignment();
+ hStretch = info->horizontalStretchFactor();
+ vStretch = info->verticalStretchFactor();
+ fillWidth = info->fillWidth();
+ fillHeight = info->fillHeight();
+ }
const int index = d->engine.rowCount(d->orientation);
d->engine.insertRow(index, d->orientation);
@@ -838,6 +865,17 @@ void QQuickLinearLayout::insertLayoutItems()
if (d->orientation == Qt::Vertical)
qSwap(gridRow, gridColumn);
QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, gridRow, gridColumn, 1, 1, alignment);
+
+ if (hStretch >= 0) {
+ if (!fillWidth)
+ qmlWarning(child) << "horizontalStretchFactor requires fillWidth to also be set to true";
+ layoutItem->setStretchFactor(hStretch, Qt::Horizontal);
+ }
+ if (vStretch >= 0) {
+ if (!fillHeight)
+ qmlWarning(child) << "verticalStretchFactor requires fillHeight to also be set to true";
+ layoutItem->setStretchFactor(vStretch, Qt::Vertical);
+ }
d->engine.insertItem(layoutItem, index);
}
}
diff --git a/src/quicklayouts/qquicklinearlayout_p.h b/src/quicklayouts/qquicklinearlayout_p.h
index 15ce953ead..a29106e8a2 100644
--- a/src/quicklayouts/qquicklinearlayout_p.h
+++ b/src/quicklayouts/qquicklinearlayout_p.h
@@ -55,6 +55,7 @@ public:
void setLayoutDirection(Qt::LayoutDirection dir);
Qt::LayoutDirection effectiveLayoutDirection() const;
void setAlignment(QQuickItem *item, Qt::Alignment align) override;
+ void setStretchFactor(QQuickItem *item, int stretchFactor, Qt::Orientation orient) override;
/* QQuickItemChangeListener */
void itemDestroyed(QQuickItem *item) override;
diff --git a/src/quicklayouts/qquickstacklayout.cpp b/src/quicklayouts/qquickstacklayout.cpp
index 217e1df406..e07a44053b 100644
--- a/src/quicklayouts/qquickstacklayout.cpp
+++ b/src/quicklayouts/qquickstacklayout.cpp
@@ -334,6 +334,10 @@ void QQuickStackLayout::rearrange(const QSizeF &newSize)
QQuickLayout::rearrange(newSize);
}
+void QQuickStackLayout::setStretchFactor(QQuickItem * /*item*/, int /*stretchFactor*/, Qt::Orientation /*orient*/)
+{
+}
+
void QQuickStackLayout::collectItemSizeHints(QQuickItem *item, QSizeF *sizeHints)
{
QQuickLayoutAttached *info = nullptr;
diff --git a/src/quicklayouts/qquickstacklayout_p.h b/src/quicklayouts/qquickstacklayout_p.h
index a27f7f6f7a..5ffa3d5c41 100644
--- a/src/quicklayouts/qquickstacklayout_p.h
+++ b/src/quicklayouts/qquickstacklayout_p.h
@@ -45,6 +45,7 @@ public:
void invalidate(QQuickItem *childItem = nullptr) override;
void updateLayoutItems() override { }
void rearrange(const QSizeF &) override;
+ void setStretchFactor(QQuickItem *item, int stretchFactor, Qt::Orientation orient) override;
// iterator
Q_INVOKABLE QQuickItem *itemAt(int index) const override;
diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
index 4fd288cfc1..506893b631 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
@@ -901,6 +901,51 @@ Item {
layout.destroy();
}
+ function test_distribution_data()
+ {
+ return [
+ {
+ tag: "one",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ ]
+ },
+ layoutWidth: 28,
+ expectedWidths: [20, 8]
+ },{
+ tag: "two",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, horizontalStretchFactor: 4, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, horizontalStretchFactor: 1, fillWidth: true},
+ ]
+ },
+ layoutWidth: 28,
+ expectedWidths: [22, 6]
+ }
+ ];
+ }
+
+ function test_distribution(data)
+ {
+ var layout = layout_rowLayout_Component.createObject(container)
+ layout.spacing = 0
+ buildLayout(layout, data.layout.items)
+ waitForPolish(layout)
+ layout.width = data.layoutWidth
+
+ let actualWidths = []
+ for (let i = 0; i < layout.children.length; i++) {
+ actualWidths.push(layout.children[i].width)
+ }
+ compare(actualWidths, data.expectedWidths)
+ layout.destroy();
+ }
+
Component {
id: layout_alignToPixelGrid_Component
RowLayout {