diff options
author | Jan Arve Sæther <jan-arve.saether@qt.io> | 2022-08-22 14:11:50 +0200 |
---|---|---|
committer | Jan Arve Sæther <jan-arve.saether@qt.io> | 2022-12-08 01:01:11 +0100 |
commit | 373b6e54dd3b6434ec427d4f5b01335cfaa90dea (patch) | |
tree | eac6a3457da5991d6670020e9c919ac1cdc6036c | |
parent | 73a3b69f9ae6d49cc04ce9834ab6f3b88d11e35b (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.cpp | 10 | ||||
-rw-r--r-- | src/quicklayouts/qquickgridlayoutengine_p.h | 2 | ||||
-rw-r--r-- | src/quicklayouts/qquicklayout.cpp | 74 | ||||
-rw-r--r-- | src/quicklayouts/qquicklayout_p.h | 13 | ||||
-rw-r--r-- | src/quicklayouts/qquicklinearlayout.cpp | 40 | ||||
-rw-r--r-- | src/quicklayouts/qquicklinearlayout_p.h | 1 | ||||
-rw-r--r-- | src/quicklayouts/qquickstacklayout.cpp | 4 | ||||
-rw-r--r-- | src/quicklayouts/qquickstacklayout_p.h | 1 | ||||
-rw-r--r-- | tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml | 45 |
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 { |