diff options
Diffstat (limited to 'src/gui/graphicsview/qgridlayoutengine.cpp')
-rw-r--r-- | src/gui/graphicsview/qgridlayoutengine.cpp | 226 |
1 files changed, 192 insertions, 34 deletions
diff --git a/src/gui/graphicsview/qgridlayoutengine.cpp b/src/gui/graphicsview/qgridlayoutengine.cpp index ae5bf90..e486b4d 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,17 @@ QRectF QGridLayoutItem::geometryWithin(qreal x, qreal y, qreal width, qreal heig qreal cellWidth = width; qreal cellHeight = height; - QSizeF size = effectiveMaxSize().boundedTo(QSizeF(cellWidth, cellHeight)); + + QSizeF size = effectiveMaxSize(QSizeF(-1,-1)); + if (hasDynamicConstraint()) { + if (dynamicConstraintOrientation() == Qt::Vertical) { + if (size.width() > cellWidth) + size = effectiveMaxSize(QSizeF(cellWidth, -1)); + } else if(size.height() > cellHeight) { + size = effectiveMaxSize(QSizeF(-1, cellHeight)); + } + } + size = size.boundedTo(QSizeF(cellWidth, cellHeight)); width = size.width(); height = size.height(); @@ -675,13 +703,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 +717,7 @@ QSizeF QGridLayoutItem::effectiveMaxSize() const } if (!size.isValid()) { - QSizeF maxSize = layoutItem()->effectiveSizeHint(Qt::MaximumSize); + QSizeF maxSize = layoutItem()->effectiveSizeHint(Qt::MaximumSize, size); if (size.width() == -1) size.setWidth(maxSize.width()); if (size.height() == -1) @@ -1010,6 +1038,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,19 +1103,78 @@ 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); + QGridLayoutBox sizehint_totalBoxes[NOrientations]; + + if(rowCount() < 1 || columnCount() < 1 || !hasDynamicConstraint()) { + //No items with height for width, so it doesn't matter which order we do these in + if(q_cachedDataForStyleInfo != styleInfo) { + ensureColumnAndRowData(&q_columnData, &sizehint_totalBoxes[Hor], styleInfo, NULL, NULL, Qt::Horizontal); + ensureColumnAndRowData(&q_rowData, &sizehint_totalBoxes[Ver], styleInfo, NULL, NULL, Qt::Vertical); + } else { + sizehint_totalBoxes[Hor] = q_totalBoxes[Hor]; + sizehint_totalBoxes[Ver] = q_totalBoxes[Ver]; + } + } else if(constraintOrientation() == Qt::Vertical) { + //We have items whose width depends on their height + if(q_cachedDataForStyleInfo != styleInfo) + ensureColumnAndRowData(&q_columnData, &sizehint_totalBoxes[Hor], styleInfo, NULL, NULL, Qt::Horizontal); + else + sizehint_totalBoxes[Hor] = q_totalBoxes[Hor]; + QVector<qreal> sizehint_xx; + QVector<qreal> sizehint_widths; + + sizehint_xx.resize(columnCount()); + sizehint_widths.resize(columnCount()); + qreal width = constraint.width(); + if(width < 0) { + /* It's not obvious what the behaviour should be. */ +/* if(which == Qt::MaximumSize) + width = sizehint_totalBoxes[Hor].q_maximumSize; + else if(which == Qt::MinimumSize) + width = sizehint_totalBoxes[Hor].q_minimumSize; + else*/ + width = sizehint_totalBoxes[Hor].q_preferredSize; + } + //Calculate column widths and positions, and put results in q_xx.data() and q_widths.data() so that we can use this information as + //constraints to find the row heights + q_columnData.calculateGeometries(0, columnCount(), width, sizehint_xx.data(), sizehint_widths.data(), + 0, sizehint_totalBoxes[Hor]); + ensureColumnAndRowData(&q_rowData, &sizehint_totalBoxes[Ver], styleInfo, sizehint_xx.data(), sizehint_widths.data(), Qt::Vertical); + } else { + //We have items whose height depends on their width + ensureColumnAndRowData(&q_rowData, &sizehint_totalBoxes[Ver], styleInfo, NULL, NULL, Qt::Vertical); + QVector<qreal> sizehint_yy; + QVector<qreal> sizehint_heights; + + sizehint_yy.resize(rowCount()); + sizehint_heights.resize(rowCount()); + qreal height = constraint.height(); + if(height < 0) { +/* if(which == Qt::MaximumSize) + height = sizehint_totalBoxes[Ver].q_maximumSize; + else if(which == Qt::MinimumSize) + height = sizehint_totalBoxes[Ver].q_minimumSize; + else*/ + height = sizehint_totalBoxes[Ver].q_preferredSize; + } + //Calculate row heights and positions, and put results in q_yy.data() and q_heights.data() so that we can use this information as + //constraints to find the column widths + q_rowData.calculateGeometries(0, rowCount(), height, sizehint_yy.data(), sizehint_heights.data(), + 0, sizehint_totalBoxes[Ver]); + ensureColumnAndRowData(&q_columnData, &sizehint_totalBoxes[Hor], styleInfo, sizehint_yy.data(), sizehint_heights.data(), Qt::Vertical); + } switch (which) { case Qt::MinimumSize: - return QSizeF(q_totalBoxes[Hor].q_minimumSize, q_totalBoxes[Ver].q_minimumSize); + return QSizeF(sizehint_totalBoxes[Hor].q_minimumSize, sizehint_totalBoxes[Ver].q_minimumSize); case Qt::PreferredSize: - return QSizeF(q_totalBoxes[Hor].q_preferredSize, q_totalBoxes[Ver].q_preferredSize); + return QSizeF(sizehint_totalBoxes[Hor].q_preferredSize, sizehint_totalBoxes[Ver].q_preferredSize); case Qt::MaximumSize: - return QSizeF(q_totalBoxes[Hor].q_maximumSize, q_totalBoxes[Ver].q_maximumSize); + return QSizeF(sizehint_totalBoxes[Hor].q_maximumSize, sizehint_totalBoxes[Ver].q_maximumSize); case Qt::MinimumDescent: - return QSizeF(-1.0, q_totalBoxes[Hor].q_minimumDescent); // ### doesn't work + return QSizeF(-1.0, sizehint_totalBoxes[Hor].q_minimumDescent); // ### doesn't work default: break; } @@ -1262,6 +1350,7 @@ void QGridLayoutEngine::insertOrRemoveRows(int row, int delta, Qt::Orientation o } void QGridLayoutEngine::fillRowData(QGridLayoutRowData *rowData, const QLayoutStyleInfo &styleInfo, + qreal *colPositions, qreal *colSizes, Qt::Orientation orientation) const { const int ButtonMask = QSizePolicy::ButtonBox | QSizePolicy::PushButton; @@ -1375,7 +1464,21 @@ void QGridLayoutEngine::fillRowData(QGridLayoutRowData *rowData, const QLayoutSt box = &multiCell.q_box; multiCell.q_stretch = itemStretch; } - box->combine(item->box(orientation)); + // Items with constraints need to be passed the constraint + if (colSizes && colPositions && item->hasDynamicConstraint() && orientation == item->dynamicConstraintOrientation()) { + /* Get the width of the item by summing up the widths of the columns that it spans. + * We need to have already calculated the widths of the columns by calling + * q_columns->calculateGeometries() before hand and passing the value in the colSizes + * and colPositions parameters. + * The variable name is still colSizes even when it actually has the row sizes + */ + qreal length = colSizes[item->lastColumn(orientation)]; + if (item->columnSpan(orientation) != 1) + length += colPositions[item->lastColumn(orientation)] - colPositions[item->firstColumn(orientation)]; + box->combine(item->box(orientation, length)); + } else { + box->combine(item->box(orientation)); + } if (effectiveRowSpan == 1) { QSizePolicy::ControlTypes controls = item->controlTypes(top); @@ -1512,44 +1615,99 @@ void QGridLayoutEngine::ensureEffectiveFirstAndLastRows() const } } -void QGridLayoutEngine::ensureColumnAndRowData(const QLayoutStyleInfo &styleInfo) const +void QGridLayoutEngine::ensureColumnAndRowData(QGridLayoutRowData *rowData, QGridLayoutBox *totalBox, + const QLayoutStyleInfo &styleInfo, + qreal *colPositions, qreal *colSizes, + Qt::Orientation orientation) const { - if (q_cachedDataForStyleInfo == styleInfo) - return; - - q_columnData.reset(columnCount()); - q_rowData.reset(rowCount()); - - fillRowData(&q_columnData, styleInfo, Qt::Horizontal); - fillRowData(&q_rowData, styleInfo, Qt::Vertical); + rowData->reset(rowCount(orientation)); + fillRowData(rowData, styleInfo, colPositions, colSizes, orientation); + rowData->distributeMultiCells(); + *totalBox = rowData->totalBox(0, rowCount(orientation)); + //We have items whose width depends on their height +} - q_columnData.distributeMultiCells(); - q_rowData.distributeMultiCells(); +/** + 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; +} - q_totalBoxes[Hor] = q_columnData.totalBox(0, columnCount()); - q_totalBoxes[Ver] = q_rowData.totalBox(0, rowCount()); +bool QGridLayoutEngine::hasDynamicConstraint() const +{ + if (!ensureDynamicConstraint()) + return false; + return q_cachedConstraintOrientation != NoConstraint; +} - q_cachedDataForStyleInfo = styleInfo; +/* + * 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 { - ensureColumnAndRowData(styleInfo); - if (q_cachedSize == size) + if (q_cachedDataForStyleInfo == styleInfo && q_cachedSize == size) return; + q_cachedDataForStyleInfo = styleInfo; + q_cachedSize = size; + q_xx.resize(columnCount()); - q_yy.resize(rowCount()); q_widths.resize(columnCount()); + q_yy.resize(rowCount()); 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]); - q_cachedSize = size; + if(constraintOrientation() != Qt::Horizontal) { + //We might have items whose width depends on their height + ensureColumnAndRowData(&q_columnData, &q_totalBoxes[Hor], styleInfo, NULL, NULL, Qt::Horizontal); + //Calculate column widths and positions, and put results in q_xx.data() and q_widths.data() so that we can use this information as + //constraints to find the row heights + q_columnData.calculateGeometries(0, columnCount(), size.width(), q_xx.data(), q_widths.data(), + 0, q_totalBoxes[Hor]); + ensureColumnAndRowData(&q_rowData, &q_totalBoxes[Ver], styleInfo, q_xx.data(), q_widths.data(), Qt::Vertical); + //Calculate row heights and positions, and put results in q_yy.data() and q_heights.data() + q_rowData.calculateGeometries(0, rowCount(), size.height(), q_yy.data(), q_heights.data(), + q_descents.data(), q_totalBoxes[Ver]); + } else { + //We have items whose height depends on their width + ensureColumnAndRowData(&q_rowData, &q_totalBoxes[Ver], styleInfo, NULL, NULL, Qt::Vertical); + //Calculate row heights and positions, and put results in q_yy.data() and q_heights.data() so that we can use this information as + //constraints to find the column widths + q_rowData.calculateGeometries(0, rowCount(), size.height(), q_yy.data(), q_heights.data(), + q_descents.data(), q_totalBoxes[Ver]); + ensureColumnAndRowData(&q_columnData, &q_totalBoxes[Hor], styleInfo, q_yy.data(), q_heights.data(), Qt::Horizontal); + //Calculate row heights and positions, and put results in q_yy.data() and q_heights.data() + q_columnData.calculateGeometries(0, columnCount(), size.width(), q_xx.data(), q_widths.data(), + 0, q_totalBoxes[Hor]); + } } QT_END_NAMESPACE |