diff options
author | Mitch Curtis <mitch.curtis@qt.io> | 2017-02-07 13:54:29 +0100 |
---|---|---|
committer | Mitch Curtis <mitch.curtis@qt.io> | 2017-02-23 13:45:52 +0000 |
commit | 2556bfdab42dc0aefb34bb7cf304063c7db0ff00 (patch) | |
tree | 5b9d638a3a7a6a6a78781022fe8e2831a844a7a1 /src/quick/items/qquickpositioners.cpp | |
parent | 3681514f80a2f6a568b0508a58b5e486cee00b0f (diff) |
Positioners: allow distinguishing between implicit/explicit child size
In Qt Quick Controls 2, we plan on using positioners to layout an icon
next to text in a button, for example.
Consider the following example:
AbstractButton {
id: button
text: "Button"
contentItem: Row {
Text {
text: button.text
width: parent.width
}
}
background: Rectangle {
radius: 5
color: "lightsteelblue"
opacity: button.pressed ? 1.0 : 0.8
}
}
In Qt Quick Controls 2, implicit size propagates "up" from the
delegates/building blocks to the control, whereas explicit size
propagates "down" from the control to the delegates/building blocks.
Providing a reasonable implicit size is important to make controls
behave well in layouts, etc., and the internal building blocks must
follow the size of the control to retain sensible looks when a control
is resized.
In the example above, contentItem needs to have a "natural" (implicit)
size representing the ideal fit of the content, but it needs to respect
the explicitly provided size from the control too.
With the current behavior, as the explicit width of the Row is 0, the
Text item (via the width binding) sets explicit width to 0, and Row
uses that explicit width rather than the implicit width, thus, Row here
will have an implicit width of 0, which is not what the control wants.
This patch:
- Allows subclasses of positioners to set
QQuickBasePositionerPrivate::useImplicitSize to true in order to tell
positioners to use implicit size rather than explicit size. This is
not exposed as public API, as this behavior is typically not
something desirable in the positioners themselves. For example,
Row { Rectangle { width: 100; height: 100 } } would have an implicit
size of 0, as Rectangle has no implicit size.
- Adds QQuickImplicitRow and QQuickImplicitGrid, which are private
subclasses of their respective positioners that simply set
useImplicitSize to true in their constructors.
- Exports the wrappers privately so that they can be registered by
other modules as QML types.
Change-Id: Ie68aabd7fbf6c76375badf6e338f2f238f3fc392
Reviewed-by: J-P Nurmi <jpnurmi@qt.io>
Reviewed-by: Robin Burchell <robin.burchell@crimson.no>
Diffstat (limited to 'src/quick/items/qquickpositioners.cpp')
-rw-r--r-- | src/quick/items/qquickpositioners.cpp | 100 |
1 files changed, 68 insertions, 32 deletions
diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp index 51eafd9217..be92bb0954 100644 --- a/src/quick/items/qquickpositioners.cpp +++ b/src/quick/items/qquickpositioners.cpp @@ -48,8 +48,19 @@ QT_BEGIN_NAMESPACE -static const QQuickItemPrivate::ChangeTypes watchedChanges - = QQuickItemPrivate::Geometry +// The default item change types that positioners are interested in. +static const QQuickItemPrivate::ChangeTypes explicitSizeItemChangeTypes = + QQuickItemPrivate::Geometry + | QQuickItemPrivate::SiblingOrder + | QQuickItemPrivate::Visibility + | QQuickItemPrivate::Destroyed; + +// The item change types for positioners that are only interested in the implicit +// size of the items they manage. These are used if useImplicitSize is true. +// useImplicitSize should be set in the constructor, before any items are added. +static const QQuickItemPrivate::ChangeTypes implicitSizeItemChangeTypes = + QQuickItemPrivate::ImplicitWidth + | QQuickItemPrivate::ImplicitHeight | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Visibility | QQuickItemPrivate::Destroyed; @@ -57,13 +68,15 @@ static const QQuickItemPrivate::ChangeTypes watchedChanges void QQuickBasePositionerPrivate::watchChanges(QQuickItem *other) { QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other); - otherPrivate->addItemChangeListener(this, watchedChanges); + otherPrivate->addItemChangeListener(this, useImplicitSize + ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes); } void QQuickBasePositionerPrivate::unwatchChanges(QQuickItem* other) { QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other); - otherPrivate->removeItemChangeListener(this, watchedChanges); + otherPrivate->removeItemChangeListener(this, useImplicitSize + ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes); } @@ -323,7 +336,7 @@ void QQuickBasePositioner::prePositioning() if (wIdx < 0) { d->watchChanges(child); posItem.isNew = true; - if (!childPrivate->explicitVisible || !child->width() || !child->height()) { + if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) { posItem.isVisible = false; posItem.index = -1; unpositionedItems.append(posItem); @@ -345,7 +358,7 @@ void QQuickBasePositioner::prePositioning() PositionedItem *item = &oldItems[wIdx]; // Items are only omitted from positioning if they are explicitly hidden // i.e. their positioning is not affected if an ancestor is hidden. - if (!childPrivate->explicitVisible || !child->width() || !child->height()) { + if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) { item->isVisible = false; item->index = -1; unpositionedItems.append(*item); @@ -944,6 +957,7 @@ QQuickColumn::QQuickColumn(QQuickItem *parent) void QQuickColumn::doPositioning(QSizeF *contentSize) { //Precondition: All items in the positioned list have a valid item pointer and should be positioned + QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this)); qreal voffset = topPadding(); const qreal padding = leftPadding() + rightPadding(); contentSize->setWidth(qMax(contentSize->width(), padding)); @@ -952,9 +966,9 @@ void QQuickColumn::doPositioning(QSizeF *contentSize) PositionedItem &child = positionedItems[ii]; positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child); child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); - contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding)); + contentSize->setWidth(qMax(contentSize->width(), d->itemWidth(child.item) + padding)); - voffset += child.item->height(); + voffset += d->itemHeight(child.item); voffset += spacing(); } @@ -1222,9 +1236,9 @@ void QQuickRow::doPositioning(QSizeF *contentSize) hoffsets << hoffset; } - contentSize->setHeight(qMax(contentSize->height(), child.item->height() + padding)); + contentSize->setHeight(qMax(contentSize->height(), d->itemHeight(child.item) + padding)); - hoffset += child.item->width(); + hoffset += d->itemWidth(child.item); hoffset += spacing(); } @@ -1245,7 +1259,7 @@ void QQuickRow::doPositioning(QSizeF *contentSize) int acc = 0; for (int ii = 0; ii < positionedItems.count(); ++ii) { PositionedItem &child = positionedItems[ii]; - hoffset = end - hoffsets[acc++] - child.item->width(); + hoffset = end - hoffsets[acc++] - d->itemWidth(child.item); positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child); child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); } @@ -1746,10 +1760,12 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) break; const PositionedItem &child = positionedItems.at(childIndex++); - if (child.item->width() > maxColWidth[j]) - maxColWidth[j] = child.item->width(); - if (child.item->height() > maxRowHeight[i]) - maxRowHeight[i] = child.item->height(); + const qreal childWidth = d->itemWidth(child.item); + const qreal childHeight = d->itemHeight(child.item); + if (childWidth > maxColWidth[j]) + maxColWidth[j] = childWidth; + if (childHeight > maxRowHeight[i]) + maxRowHeight[i] = childHeight; } } } else { @@ -1764,10 +1780,12 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) break; const PositionedItem &child = positionedItems.at(childIndex++); - if (child.item->width() > maxColWidth[j]) - maxColWidth[j] = child.item->width(); - if (child.item->height() > maxRowHeight[i]) - maxRowHeight[i] = child.item->height(); + const qreal childWidth = d->itemWidth(child.item); + const qreal childHeight = d->itemHeight(child.item); + if (childWidth > maxColWidth[j]) + maxColWidth[j] = childWidth; + if (childHeight > maxRowHeight[i]) + maxRowHeight[i] = childHeight; } } } @@ -1809,20 +1827,22 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem &child = positionedItems[i]; qreal childXOffset = xoffset; + const qreal childWidth = d->itemWidth(child.item); + const qreal childHeight = d->itemHeight(child.item); if (effectiveHAlign() == AlignRight) - childXOffset += maxColWidth[curCol] - child.item->width(); + childXOffset += maxColWidth[curCol] - childWidth; else if (hItemAlign() == AlignHCenter) - childXOffset += (maxColWidth[curCol] - child.item->width())/2.0; + childXOffset += (maxColWidth[curCol] - childWidth)/2.0; if (!d->isLeftToRight()) childXOffset -= maxColWidth[curCol]; qreal alignYOffset = yoffset; if (m_vItemAlign == AlignVCenter) - alignYOffset += (maxRowHeight[curRow] - child.item->height())/2.0; + alignYOffset += (maxRowHeight[curRow] - childHeight)/2.0; else if (m_vItemAlign == AlignBottom) - alignYOffset += maxRowHeight[curRow] - child.item->height(); + alignYOffset += maxRowHeight[curRow] - childHeight; positionItem(childXOffset, alignYOffset, &child); child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); @@ -2140,15 +2160,17 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem &child = positionedItems[i]; + const qreal childWidth = d->itemWidth(child.item); + const qreal childHeight = d->itemHeight(child.item); if (d->flow == LeftToRight) { - if (widthValid() && hoffset != hoffset1 && hoffset + child.item->width() + hoffset2 > width()) { + if (widthValid() && hoffset != hoffset1 && hoffset + childWidth + hoffset2 > width()) { hoffset = hoffset1; voffset += linemax + spacing(); linemax = 0; } } else { - if (heightValid() && voffset != voffset1 && voffset + child.item->height() + bottomPadding() > height()) { + if (heightValid() && voffset != voffset1 && voffset + childHeight + bottomPadding() > height()) { voffset = voffset1; hoffset += linemax + spacing(); linemax = 0; @@ -2165,17 +2187,17 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) child.bottomPadding = bottomPadding(); } - contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width() + hoffset2)); - contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height() + bottomPadding())); + contentSize->setWidth(qMax(contentSize->width(), hoffset + childWidth + hoffset2)); + contentSize->setHeight(qMax(contentSize->height(), voffset + childHeight + bottomPadding())); if (d->flow == LeftToRight) { - hoffset += child.item->width(); + hoffset += childWidth; hoffset += spacing(); - linemax = qMax(linemax, child.item->height()); + linemax = qMax(linemax, childHeight); } else { - voffset += child.item->height(); + voffset += childHeight; voffset += spacing(); - linemax = qMax(linemax, child.item->width()); + linemax = qMax(linemax, childWidth); } } @@ -2190,7 +2212,7 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) int acc = 0; for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem &child = positionedItems[i]; - hoffset = end - hoffsets[acc++] - child.item->width(); + hoffset = end - hoffsets[acc++] - d->itemWidth(child.item); positionItemX(hoffset, &child); child.leftPadding = leftPadding(); child.rightPadding = rightPadding(); @@ -2214,4 +2236,18 @@ void QQuickFlow::reportConflictingAnchors() qmlWarning(this) << "Cannot specify anchors for items inside Flow." << " Flow will not function."; } +QQuickImplicitRow::QQuickImplicitRow(QQuickItem *parent) + : QQuickRow(parent) +{ + QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this); + d->useImplicitSize = true; +} + +QQuickImplicitGrid::QQuickImplicitGrid(QQuickItem *parent) + : QQuickGrid(parent) +{ + QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this); + d->useImplicitSize = true; +} + QT_END_NAMESPACE |