void QQuickStretchColumnContainer::updatePolish (void) { const QList<QQuickItem *> childrenList = childItems (); /// find items and stretchers qreal tmpW = 0; qreal tmpH = 0; int nbItems = 0; int nbStretch = 0; for (QList<QQuickItem *>::const_iterator it = childrenList.constBegin (); it != childrenList.constEnd (); it++) { QQuickItem * child = (* it); if (child != Q_NULLPTR && !child->inherits ("QQuickRepeater") && child->isVisible ()) { if (child->implicitWidth () > tmpW) { tmpW = child->implicitWidth (); } if (child->implicitHeight () >= 0) { tmpH += child->implicitHeight (); } else { nbStretch++; } nbItems++; } } /// resize layout if (nbItems > 1) { tmpH += (m_spacing * (nbItems -1)); } setImplicitWidth (tmpW); setImplicitHeight (tmpH); const qreal layoutWidth = width (); const qreal layoutHeight = height (); const qreal autoSize = (nbStretch > 0 ? (layoutHeight - tmpH) / qreal (nbStretch) : 0); /// position children int currY = 0; for (QList<QQuickItem *>::const_iterator it = childrenList.constBegin (); it != childrenList.constEnd (); it++) { QQuickItem * child = (* it); if (child != Q_NULLPTR && !child->inherits ("QQuickRepeater") && child->isVisible ()) { if (currY) { currY += m_spacing; } child->setY (currY); child->setWidth (layoutWidth); child->setHeight (child->implicitHeight () >= 0 ? child->implicitHeight () : autoSize); currY += child->height (); } } }
void StretchColumn::layoutChildrenWithDefaultSize() { //static int count = 0; //qDebug() << "Column Default Size" << ++count; Q_ASSERT(m_defaultSize != 0); const QList<QQuickItem *> childrenList = childItems(); if (childrenList.isEmpty()) return; const int contentWidth = width() - m_leftMargin - m_rightMargin; qreal currY = 0; for (QList<QQuickItem *>::const_iterator it = childrenList.constBegin(); it != childrenList.constEnd(); ++it) { QQuickItem* child = (*it); if (child == Q_NULLPTR || !child->isVisible()) { continue; } // add spacing if it is not the first item: if (currY > 0) { currY += m_spacing; } if (currY != child->y()) child->setY(currY); // check if item has a stretch proportion set: if (child->implicitHeight() < 0) { // yes -> set it to default size multiplied by relative size: qreal newHeight = m_defaultSize * child->implicitHeight() * -1; if (newHeight != child->height()) child->setHeight(newHeight); } // set width of all items to fill the layout: if (m_leftMargin != child->x()) child->setX(m_leftMargin); if (contentWidth != child->width()) child->setWidth(contentWidth); currY += child->height(); } // set implicit size to fit all items: if (currY != implicitHeight()) setImplicitHeight(currY); }
void StretchColumn::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData & value) { if (change == QQuickItem::ItemChildAddedChange) { QQuickItem* child = value.item; if (child != Q_NULLPTR) { connect(child, &QQuickItem::visibleChanged, this, &StretchColumn::polish, Qt::UniqueConnection); if (child->implicitHeight() < 0) { // only listen to implicitHeight changes if this is a relative-sized item connect(child, &QQuickItem::implicitHeightChanged, this, &StretchColumn::polish, Qt::UniqueConnection); } else { // only listen to height changes if this is a fixed-sized item connect(child, &QQuickItem::heightChanged, this, &StretchColumn::polish, Qt::UniqueConnection); // add | Qt::QueuedConnection? } } } }
void StretchColumn::layoutChildrenWithProportions() { //static int count = 0; //qDebug() << "Column Proportions" << ++count; const QList<QQuickItem*> childrenList = childItems(); if (childrenList.isEmpty()) return; if (height() <= 0) return; int visibleItems = 0; qreal availableForStretch = height(); qreal sumStretchProportions = 0.0; // iterate over all children and calculate available size to stretch items: for (QList<QQuickItem *>::const_iterator it = childrenList.constBegin(); it != childrenList.constEnd(); ++it) { QQuickItem* child = (*it); if (child == Q_NULLPTR || !child->isVisible()) { continue; } if (child->implicitHeight() >= 0) { // no stretch proportion set -> leave size and remove it from available space: availableForStretch -= child->height(); } else { // a stretch proportion is set -> add it to sum: sumStretchProportions += (child->implicitHeight() * -1); } visibleItems++; } // remove spacing from available space: availableForStretch -= m_spacing * (visibleItems - 1); const int contentWidth = width() - m_leftMargin - m_rightMargin; QPointer<QQuickItem> lastStretchItem = nullptr; qreal currY = 0; for (QList<QQuickItem *>::const_iterator it = childrenList.constBegin(); it != childrenList.constEnd(); ++it) { QQuickItem* child = (*it); if (child == Q_NULLPTR || !child->isVisible()) { continue; } // add spacing if it is not the first item: if (currY > 0) { currY += m_spacing; } if (currY != child->y()) child->setY(currY); // check if item has a stretch proportion set (if not do nothing): if (child->implicitHeight() < 0) { // get the stretch proportion: qreal stretchProportion = (child->implicitHeight() * -1); // calculate the relation of the total space available for stretched items // that this item will use: // (sumStretchProportion can not be 0 (in divison) because if this "if" is executed, // there has been at least one item with a stretch proportion set) qreal relationOfSpaceAvailableForStretch = stretchProportion / sumStretchProportions; qreal newHeight = qRound(availableForStretch * relationOfSpaceAvailableForStretch); if (newHeight != child->height()) child->setHeight(newHeight); lastStretchItem = child; } // set width of all items to fill the layout: if (m_leftMargin != child->x()) child->setX(m_leftMargin); if (contentWidth != child->width()) child->setWidth(contentWidth); currY += child->height(); } // check if last item fills whole remaining space in this layout: // (can happen because of rounding mistakes) if (lastStretchItem) { double pxMissing = height() - currY; if (pxMissing > 0.0001) { // qInfo() << "StretchColumn layout mismatch: " << pxMissing; // it does not -> adjust it: lastStretchItem->setHeight(lastStretchItem->height() + pxMissing); } } }
void QQuickComponentsLinearLayout::reconfigureLayout() { if (!isComponentComplete()) return; const int count = m_items.count(); if (count == 0) return; qreal totalSpacing = 0; qreal totalSizeHint = 0; qreal totalMinimumSize = 0; qreal totalMaximumSize = 0; QVector<QQuickComponentsLayoutInfo> itemData; for (int i = 0; i < count; i++) { QQuickItem *item = m_items.at(i); QObject *attached = qmlAttachedPropertiesObject<QQuickComponentsLayout>(item); QQuickComponentsLayoutAttached *info = static_cast<QQuickComponentsLayoutAttached *>(attached); QQuickComponentsLayoutInfo data; if (m_orientation == Horizontal) { data.sizeHint = item->implicitWidth(); data.minimumSize = info->minimumWidth(); data.maximumSize = info->maximumWidth(); data.expansive = (info->horizontalSizePolicy() == QQuickComponentsLayout::Expanding); data.stretch = info->horizontalSizePolicy() == Expanding ? 1.0 : 0; } else { data.sizeHint = item->implicitHeight(); data.minimumSize = info->minimumHeight(); data.maximumSize = info->maximumHeight(); data.expansive = (info->verticalSizePolicy() == QQuickComponentsLayout::Expanding); data.stretch = info->verticalSizePolicy() == Expanding ? 1.0 : 0; } itemData.append(data); // sum totalSizeHint += data.sizeHint; totalMinimumSize += data.minimumSize; totalMaximumSize += data.maximumSize; // don't count last spacing if (i < count - 1) totalSpacing += data.spacing + m_spacing; } if (m_orientation == Horizontal) { qDeclarativeLayoutCalculate(itemData, 0, count, 0, width(), m_spacing); for (int i = 0; i < count; i++) { QQuickItem *item = m_items.at(i); const QQuickComponentsLayoutInfo &data = itemData.at(i); item->setX(data.pos); item->setY(height()/2 - item->height()/2); item->setWidth(data.size); } } else { qDeclarativeLayoutCalculate(itemData, 0, count, 0, height(), m_spacing); for (int i = 0; i < count; i++) { QQuickItem *item = m_items.at(i); const QQuickComponentsLayoutInfo &data = itemData.at(i); item->setY(data.pos); item->setX(width()/2 - item->width()/2); item->setHeight(data.size); } } // propagate hints to upper levels QObject *attached = qmlAttachedPropertiesObject<QQuickComponentsLayout>(this); QQuickComponentsLayoutAttached *info = static_cast<QQuickComponentsLayoutAttached *>(attached); if (m_orientation == Horizontal) { setImplicitWidth(totalSizeHint); info->setMinimumWidth(totalMinimumSize + totalSpacing); info->setMaximumWidth(totalMaximumSize + totalSpacing); } else { setImplicitHeight(totalSizeHint); info->setMinimumHeight(totalMinimumSize + totalSpacing); info->setMaximumHeight(totalMaximumSize + totalSpacing); } }