/*! \internal */ QSizeF *QGraphicsLayoutItemPrivate::effectiveSizeHints(const QSizeF &constraint) const { Q_Q(const QGraphicsLayoutItem); QSizeF *sizeHintCache; const bool hasConstraint = constraint.width() >= 0 || constraint.height() >= 0; if (hasConstraint) { if (!sizeHintWithConstraintCacheDirty && constraint == cachedConstraint) return cachedSizeHintsWithConstraints; sizeHintCache = cachedSizeHintsWithConstraints; } else { if (!sizeHintCacheDirty) return cachedSizeHints; sizeHintCache = cachedSizeHints; } for (int i = 0; i < Qt::NSizeHints; ++i) { sizeHintCache[i] = constraint; if (userSizeHints) combineSize(sizeHintCache[i], userSizeHints[i]); } QSizeF &minS = sizeHintCache[Qt::MinimumSize]; QSizeF &prefS = sizeHintCache[Qt::PreferredSize]; QSizeF &maxS = sizeHintCache[Qt::MaximumSize]; QSizeF &descentS = sizeHintCache[Qt::MinimumDescent]; normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth()); normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight()); // if the minimum, preferred and maximum sizes contradict each other // (e.g. the minimum is larger than the maximum) we give priority to // the maximum size, then the minimum size and finally the preferred size COMBINE_SIZE(maxS, q->sizeHint(Qt::MaximumSize, maxS)); combineSize(maxS, QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); expandSize(maxS, prefS); expandSize(maxS, minS); boundSize(maxS, QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); COMBINE_SIZE(minS, q->sizeHint(Qt::MinimumSize, minS)); expandSize(minS, QSizeF(0, 0)); boundSize(minS, prefS); boundSize(minS, maxS); COMBINE_SIZE(prefS, q->sizeHint(Qt::PreferredSize, prefS)); expandSize(prefS, minS); boundSize(prefS, maxS); // Not supported yet // COMBINE_SIZE(descentS, q->sizeHint(Qt::MinimumDescent, constraint)); if (hasConstraint) { cachedConstraint = constraint; sizeHintWithConstraintCacheDirty = false; } else { sizeHintCacheDirty = false; } return sizeHintCache; }
/*! \internal Note: Can potentially return the attached QQuickLayoutAttached object through \a attachedInfo. It is like this is because it enables it to be reused. The goal of this function is to return the effective minimum, preferred and maximum size hints that the layout will use for this item. This function takes care of gathering all explicitly set size hints, normalizes them so that min < pref < max. Further, the hints _not_explicitly_ set will then be initialized with the implicit size hints, which is usually derived from the content of the layouts (or items). The following table illustrates the preference of the properties used for measuring layout items. If present, the USER properties will be preferred. If USER properties are not present, the HINT properties will be preferred. Finally, the FALLBACK properties will be used as an ultimate fallback. Note that one can query if the value of Layout.minimumWidth or Layout.maximumWidth has been explicitly or implicitly set with QQuickLayoutAttached::isExtentExplicitlySet(). This determines if it should be used as a USER or as a HINT value. Fractional size hints will be ceiled to the closest integer. This is in order to give some slack when the items are snapped to the pixel grid. | *Minimum* | *Preferred* | *Maximum* | +----------------+----------------------+-----------------------+--------------------------+ |USER (explicit) | Layout.minimumWidth | Layout.preferredWidth | Layout.maximumWidth | |HINT (implicit) | Layout.minimumWidth | implicitWidth | Layout.maximumWidth | |FALLBACK | 0 | width | Number.POSITIVE_INFINITY | +----------------+----------------------+-----------------------+--------------------------+ */ void QQuickGridLayoutItem::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **attachedInfo, bool useFallbackToWidthOrHeight) { for (int i = 0; i < Qt::NSizeHints; ++i) cachedSizeHints[i] = QSizeF(); QQuickLayoutAttached *info = attachedLayoutObject(item, false); // First, retrieve the user-specified hints from the attached "Layout." properties if (info) { struct Getters { SizeGetter call[NSizes]; }; static Getters horGetters = { {&QQuickLayoutAttached::minimumWidth, &QQuickLayoutAttached::preferredWidth, &QQuickLayoutAttached::maximumWidth}, }; static Getters verGetters = { {&QQuickLayoutAttached::minimumHeight, &QQuickLayoutAttached::preferredHeight, &QQuickLayoutAttached::maximumHeight} }; for (int i = 0; i < NSizes; ++i) { SizeGetter getter = horGetters.call[i]; Q_ASSERT(getter); if (info->isExtentExplicitlySet(Qt::Horizontal, (Qt::SizeHint)i)) cachedSizeHints[i].setWidth(qCeil((info->*getter)())); getter = verGetters.call[i]; Q_ASSERT(getter); if (info->isExtentExplicitlySet(Qt::Vertical, (Qt::SizeHint)i)) cachedSizeHints[i].setHeight(qCeil((info->*getter)())); } } QSizeF &minS = cachedSizeHints[Qt::MinimumSize]; QSizeF &prefS = cachedSizeHints[Qt::PreferredSize]; QSizeF &maxS = cachedSizeHints[Qt::MaximumSize]; QSizeF &descentS = cachedSizeHints[Qt::MinimumDescent]; // For instance, will normalize the following user-set hints // from: [10, 5, 60] // to: [10, 10, 60] normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth()); normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight()); // All explicit values gathered, now continue to gather the implicit sizes //--- GATHER MAXIMUM SIZE HINTS --- combineImplicitHints(info, Qt::MaximumSize, &maxS); combineSize(maxS, QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity())); // implicit max or min sizes should not limit an explicitly set preferred size expandSize(maxS, prefS); expandSize(maxS, minS); //--- GATHER MINIMUM SIZE HINTS --- combineImplicitHints(info, Qt::MinimumSize, &minS); expandSize(minS, QSizeF(0,0)); boundSize(minS, prefS); boundSize(minS, maxS); //--- GATHER PREFERRED SIZE HINTS --- // First, from implicitWidth/Height qreal &prefWidth = prefS.rwidth(); qreal &prefHeight = prefS.rheight(); if (prefWidth < 0 && item->implicitWidth() > 0) prefWidth = qCeil(item->implicitWidth()); if (prefHeight < 0 && item->implicitHeight() > 0) prefHeight = qCeil(item->implicitHeight()); // If that fails, make an ultimate fallback to width/height if (!info && (prefWidth < 0 || prefHeight < 0)) info = attachedLayoutObject(item); if (useFallbackToWidthOrHeight && info) { /* This block is a bit hacky, but if we want to support using width/height as preferred size hints in layouts, (which we think most people expect), we only want to use the initial width. This is because the width will change due to layout rearrangement, and the preferred width should return the same value, regardless of the current width. We therefore store the width in the implicitWidth attached property. Since the layout listens to changes of implicitWidth, (it will basically cause an invalidation of the layout), we have to disable that notification while we set the implicit width (and height). Only use this fallback the first time the size hint is queried. Otherwise, we might end up picking a width that is different than what was specified in the QML. */ if (prefWidth < 0 || prefHeight < 0) { item->blockSignals(true); if (prefWidth < 0) { prefWidth = item->width(); item->setImplicitWidth(prefWidth); } if (prefHeight < 0) { prefHeight = item->height(); item->setImplicitHeight(prefHeight); } item->blockSignals(false); } } // Normalize again after the implicit hints have been gathered expandSize(prefS, minS); boundSize(prefS, maxS); //--- GATHER DESCENT // Minimum descent is only applicable for the effective minimum height, // so we gather the descent last. const qreal minimumDescent = minS.height() - item->baselineOffset(); descentS.setHeight(minimumDescent); if (attachedInfo) *attachedInfo = info; }