diff options
author | Jan Arve Saether <jan-arve.saether@digia.com> | 2013-03-13 15:01:40 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-04-04 17:45:43 +0200 |
commit | 6758f510dc70551114366f8e76887a7d585290c4 (patch) | |
tree | acc8178c600d1d4b51c8e06bd0e4d5436884778f /src/layouts/qquicklinearlayout.cpp | |
parent | 0608949d4c2762db58fba65adfaa2b7be23cdba5 (diff) | |
download | qtquickcontrols-6758f510dc70551114366f8e76887a7d585290c4.tar.gz |
Add support for auto-positioning of items in a grid layout
Items will be laid sequentially in the grid, either in LeftToRight
mode or TopToBottom mode (depending on the value of the flow property)
Change-Id: Ib080517260ac4519171e77abd533cad3f306f70e
Reviewed-by: Jens Bache-Wiig <jens.bache-wiig@digia.com>
Diffstat (limited to 'src/layouts/qquicklinearlayout.cpp')
-rw-r--r-- | src/layouts/qquicklinearlayout.cpp | 235 |
1 files changed, 181 insertions, 54 deletions
diff --git a/src/layouts/qquicklinearlayout.cpp b/src/layouts/qquicklinearlayout.cpp index a0cb6335..635bb576 100644 --- a/src/layouts/qquicklinearlayout.cpp +++ b/src/layouts/qquicklinearlayout.cpp @@ -42,6 +42,7 @@ #include "qquicklinearlayout_p.h" #include <QtCore/qnumeric.h> #include "qdebug.h" +#include <limits> /*! \qmltype RowLayout \instantiates QQuickRowLayout @@ -158,10 +159,7 @@ void QQuickGridLayoutBase::updateLayoutItems() return; quickLayoutDebug() << "QQuickGridLayoutBase::updateLayoutItems"; d->engine.deleteItems(); - foreach (QQuickItem *child, childItems()) { - if (child->isVisible()) - insertLayoutItem(child); - } + insertLayoutItems(); invalidate(); quickLayoutDebug() << "QQuickGridLayoutBase::updateLayoutItems LEAVING"; @@ -223,41 +221,6 @@ void QQuickGridLayoutBase::geometryChanged(const QRectF &newGeometry, const QRec rearrange(newGeometry.size()); } -void QQuickGridLayoutBase::insertLayoutItem(QQuickItem *item) -{ - Q_D(QQuickGridLayoutBase); - if (!item) { - qWarning("QGraphicsGridLayout::addItem: cannot add null item"); - return; - } - QQuickLayoutAttached *info = attachedLayoutObject(item, false); - int row = 0; - int column = 0; - int rowSpan = 1; - int columnSpan = 1; - Qt::Alignment alignment = 0; - if (info) { - row = info->row(); - column = info->column(); - rowSpan = info->rowSpan(); - columnSpan = info->columnSpan(); - } - if (row < 0 || column < 0) { - qWarning("QQuickGridLayoutBase::insertLayoutItemAt: invalid row/column: %d", - row < 0 ? row : column); - return; - } - if (columnSpan < 1 || rowSpan < 1) { - qWarning("QQuickGridLayoutBase::addItem: invalid row span/column span: %d", - rowSpan < 1 ? rowSpan : columnSpan); - return; - } - QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(item, row, column, rowSpan, columnSpan, alignment); - d->engine.insertItem(layoutItem, -1); - - setupItemLayout(item); -} - void QQuickGridLayoutBase::removeGridItem(QGridLayoutItem *gridItem) { Q_D(QQuickGridLayoutBase); @@ -378,6 +341,168 @@ void QQuickGridLayout::setRowSpacing(qreal spacing) invalidate(); } +int QQuickGridLayout::columns() const +{ + Q_D(const QQuickGridLayout); + return d->columns; +} + +void QQuickGridLayout::setColumns(int columns) +{ + Q_D(QQuickGridLayout); + if (d->columns == columns) + return; + d->columns = columns; + invalidate(); + emit columnsChanged(); +} + +int QQuickGridLayout::rows() const +{ + Q_D(const QQuickGridLayout); + return d->rows; +} + +void QQuickGridLayout::setRows(int rows) +{ + Q_D(QQuickGridLayout); + if (d->rows == rows) + return; + d->rows = rows; + invalidate(); + emit rowsChanged(); +} + +QQuickGridLayout::Flow QQuickGridLayout::flow() const +{ + Q_D(const QQuickGridLayout); + return d->flow; +} + +void QQuickGridLayout::setFlow(QQuickGridLayout::Flow flow) +{ + Q_D(QQuickGridLayout); + if (d->flow == flow) + return; + d->flow = flow; + invalidate(); + emit flowChanged(); +} + +void QQuickGridLayout::insertLayoutItems() +{ + Q_D(QQuickGridLayout); + + int nextCellPos[2] = {0,0}; + int &nextColumn = nextCellPos[0]; + int &nextRow = nextCellPos[1]; + + const int flowOrientation = flow(); + int &flowColumn = nextCellPos[flowOrientation]; + int &flowRow = nextCellPos[1 - flowOrientation]; + int flowBound = (flowOrientation == QQuickGridLayout::LeftToRight) ? columns() : rows(); + + if (flowBound < 0) + flowBound = std::numeric_limits<int>::max(); + + foreach (QQuickItem *child, childItems()) { + if (child->isVisible()) { + QQuickLayoutAttached *info = attachedLayoutObject(child, false); + + // Will skip Repeater among other things + const bool skipItem = !info && (!child->width() || !child->height()) + && (!child->implicitWidth() || !child->implicitHeight()); + if (skipItem) + continue; + + int row = -1; + int column = -1; + int span[2] = {1,1}; + int &columnSpan = span[0]; + int &rowSpan = span[1]; + + bool invalidRowColumn = false; + if (info) { + if (info->isRowSet() || info->isColumnSet()) { + // If row is specified and column is not specified (or vice versa), + // the unspecified component of the cell position should default to 0 + row = column = 0; + if (info->isRowSet()) { + row = info->row(); + invalidRowColumn = row < 0; + } + if (info->isColumnSet()) { + column = info->column(); + invalidRowColumn = column < 0; + } + } + if (invalidRowColumn) { + qWarning("QQuickGridLayoutBase::insertLayoutItems: invalid row/column: %d", + row < 0 ? row : column); + return; + } + rowSpan = info->rowSpan(); + columnSpan = info->columnSpan(); + if (columnSpan < 1 || rowSpan < 1) { + qWarning("QQuickGridLayoutBase::addItem: invalid row span/column span: %d", + rowSpan < 1 ? rowSpan : columnSpan); + return; + } + } + + Q_ASSERT(columnSpan >= 1); + Q_ASSERT(rowSpan >= 1); + + if (row >= 0) + nextRow = row; + if (column >= 0) + nextColumn = column; + + if (row < 0 || column < 0) { + /* if row or column is not specified, find next position by + advancing in the flow direction until there is a cell that + can accept the item. + + The acceptance rules are pretty simple, but complexity arises + when an item requires several cells (due to spans): + 1. Check if the cells that the item will require + does not extend beyond columns (for LeftToRight) or + rows (for TopToBottom). + 2. Check if the cells that the item will require is not already + taken by another item. + */ + bool cellAcceptsItem; + while (true) { + // Check if the item does not span beyond the layout bound + cellAcceptsItem = (flowColumn + span[flowOrientation]) <= flowBound; + + // Check if all the required cells are not taken + for (int rs = 0; cellAcceptsItem && rs < rowSpan; ++rs) { + for (int cs = 0; cellAcceptsItem && cs < columnSpan; ++cs) { + if (d->engine.itemAt(nextRow + rs, nextColumn + cs)) { + cellAcceptsItem = false; + } + } + } + if (cellAcceptsItem) + break; + ++flowColumn; + if (flowColumn == flowBound) { + flowColumn = 0; + ++flowRow; + } + } + } + column = nextColumn; + row = nextRow; + QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, row, column, rowSpan, columnSpan); + + d->engine.insertItem(layoutItem, -1); + + setupItemLayout(child); + } + } +} /********************************** ** @@ -410,23 +535,25 @@ void QQuickLinearLayout::setSpacing(qreal spacing) invalidate(); } - -void QQuickLinearLayout::insertLayoutItem(QQuickItem *item) +void QQuickLinearLayout::insertLayoutItems() { Q_D(QQuickLinearLayout); - const int index = d->engine.rowCount(d->orientation); - d->engine.insertRow(index, d->orientation); - - int gridRow = 0; - int gridColumn = index; - if (d->orientation == Qt::Vertical) - qSwap(gridRow, gridColumn); - QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(item, gridRow, gridColumn, 1, 1, 0); - d->engine.insertItem(layoutItem, index); - - setupItemLayout(item); + foreach (QQuickItem *child, childItems()) { + Q_ASSERT(child); + if (child->isVisible()) { + const int index = d->engine.rowCount(d->orientation); + d->engine.insertRow(index, d->orientation); + + int gridRow = 0; + int gridColumn = index; + if (d->orientation == Qt::Vertical) + qSwap(gridRow, gridColumn); + QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, gridRow, gridColumn, 1, 1, 0); + d->engine.insertItem(layoutItem, index); + + setupItemLayout(child); + } + } } - - QT_END_NAMESPACE |