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 StretchRow::layoutChildrenWithDefaultSize() {
	//static int count = 0;
	//qDebug() << "Row Default Size" << ++count;
	Q_ASSERT(m_defaultSize != 0);

	const QList<QQuickItem *> childrenList = childItems();
	if (childrenList.isEmpty()) return;

    const int layoutHeight = height();
	qreal currX = m_leftMargin;
    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 (currX > 0) {
			currX += m_spacing;
		}
		if (currX != child->x()) child->setX(currX);
		// check if item has a stretch proportion set:
		if (child->implicitWidth() < 0) {
			// yes -> set it to default size:
			qreal newWidth = m_defaultSize * child->implicitWidth() * -1;
			if (newWidth != child->width()) child->setWidth(newWidth);
		}
		// set height of all items to fill the layout:
		if (layoutHeight != child->height()) child->setHeight(layoutHeight);
		currX += child->width();
	}
	currX += m_rightMargin;

	// set implicit size to fit all items:
	if (currX != implicitWidth()) setImplicitWidth(currX);
}
void StretchRow::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,  &StretchRow::polish, Qt::UniqueConnection);
            if (child->implicitWidth() < 0) {
				// only listen to implicitWidth changes if this is a relative-sized item
                connect(child, &QQuickItem::implicitWidthChanged,
					this,  &StretchRow::polish, Qt::UniqueConnection);
            } else {
				// only listen to width changes if this is a relative-sized item
                connect(child, &QQuickItem::widthChanged,
                    this,  &StretchRow::polish, Qt::UniqueConnection);
            }
		}
    }
}
void StretchRow::layoutChildrenWithProportions() {
	//static int count = 0;
	//qDebug() << "Row Proportions" << ++count;
	const QList<QQuickItem*> childrenList = childItems();
	if (childrenList.isEmpty()) return;
	if (width() <= 0) return;
	int visibleItems = 0;
    qreal availableForStretch = width() - m_leftMargin - m_rightMargin;
	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->implicitWidth() >= 0) {
			// no stretch proportion set -> leave size and remove it from available space:
			availableForStretch -= child->width();
		} else {
			// a stretch proportion is set -> add it to sum:
			sumStretchProportions += (child->implicitWidth() * -1);
		}
		visibleItems++;
	}
	// remove spacing from available space:
	availableForStretch -= m_spacing * (visibleItems - 1);

    const int layoutHeight = height();
    QPointer<QQuickItem> lastStretchItem = nullptr;
    qreal currX = m_leftMargin;
    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 (currX > 0) {
			currX += m_spacing;
        }
        if (currX != child->x()) child->setX(currX);
		// check if item has a stretch proportion set (if not do nothing):
		if (child->implicitWidth() < 0) {
			// get the stretch proportion:
			qreal stretchProportion = (child->implicitWidth() * -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 newWidth = qRound(availableForStretch * relationOfSpaceAvailableForStretch);
            if (newWidth != child->width()) child->setWidth(newWidth);
			lastStretchItem = child;
		}
        // set height of all items to fill the layout:
        if (layoutHeight != child->height()) child->setHeight(layoutHeight);
		currX += child->width();
	}
	currX += m_rightMargin;

	// check if last item fills whole remaining space in this layout:
	// (can happen because of rounding mistakes)
	if (lastStretchItem) {
		double pxMissing = width() - currX;
        if (pxMissing > 0.0001) {
            // qInfo() << "StretchRow layout mismatch: " << pxMissing;
			// it does not -> adjust it:
			lastStretchItem->setWidth(lastStretchItem->width() + pxMissing);
		}
	}
}
Example #5
0
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);
    }
}