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);
		}
	}
}
예제 #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);
    }
}