From 6cc1703af1f403168b7251616a7685aa83de8caa Mon Sep 17 00:00:00 2001 From: "Eduardo M. Fleury" Date: Tue, 10 Nov 2009 16:55:43 -0300 Subject: QGAL: Move size information from AnchorData to QGraphicsAnchorPrivate To solve the spacing persistency bug, this commit saves the preferredSize (spacing) information inside QGraphicsAnchorPrivate. The problem started when we could not rely on "AnchorData->prefSize" to keep the spacing information for user-defined anchors. This happens because that member can be overriden if the spacing is negative (anchor is inverted) or its sizePolicy is of type "Ignored" (it is overriden by minSize). Then, to decide where to store it, we aimed to make something similar to what happens with item-internal anchors. Those can rely on their items to get fresh information regarding their size, so we decided that user-anchors (that don't have items, but do have QGraphicsAnchors) could read such information from there. This refactory also reduced the deep indirection that existed in the "QGraphicsAnchor->setSpacing" call. Previously it would call internal layout methods to do some black magic, that's now gone. As the spacing information is now stored in the anchor itself, it can do pretty much all the work and, after that, just invalidate the layout. Also, moved information like "AnchorData->hasSize" to QGAnchor as its pretty much related to the preferredSize information itself. Signed-off-by: Eduardo M. Fleury Reviewed-by: Caio Marcelo de Oliveira Filho --- src/gui/graphicsview/qgraphicsanchorlayout.h | 1 + src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 148 +++++++++-------------- src/gui/graphicsview/qgraphicsanchorlayout_p.h | 25 ++-- 3 files changed, 66 insertions(+), 108 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout.h b/src/gui/graphicsview/qgraphicsanchorlayout.h index 01c3a86..1a0c458 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout.h @@ -76,6 +76,7 @@ private: Q_DECLARE_PRIVATE(QGraphicsAnchor) friend class QGraphicsAnchorLayoutPrivate; + friend class AnchorData; }; class Q_GUI_EXPORT QGraphicsAnchorLayout : public QGraphicsLayout diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index 182594e..872fecb 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -55,7 +55,8 @@ QT_BEGIN_NAMESPACE QGraphicsAnchorPrivate::QGraphicsAnchorPrivate(int version) : QObjectPrivate(version), layoutPrivate(0), data(0), - sizePolicy(QSizePolicy::Fixed) + sizePolicy(QSizePolicy::Fixed), preferredSize(0), + hasSize(true), reversed(false) { } @@ -76,31 +77,60 @@ void QGraphicsAnchorPrivate::setSizePolicy(QSizePolicy::Policy policy) void QGraphicsAnchorPrivate::setSpacing(qreal value) { - if (data) { - layoutPrivate->setAnchorSize(data, &value); - } else { + if (!data) { qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist."); + return; } + + const qreal rawValue = reversed ? -preferredSize : preferredSize; + if (hasSize && (rawValue == value)) + return; + + // The anchor has an user-defined size + hasSize = true; + + // The simplex solver cannot handle negative sizes. To workaround that, + // if value is less than zero, we reverse the anchor and set the absolute + // value; + if (value >= 0) { + preferredSize = value; + if (reversed) + qSwap(data->from, data->to); + reversed = false; + } else { + preferredSize = -value; + if (!reversed) + qSwap(data->from, data->to); + reversed = true; + } + + layoutPrivate->q_func()->invalidate(); } void QGraphicsAnchorPrivate::unsetSpacing() { - if (data) { - layoutPrivate->setAnchorSize(data, 0); - } else { + if (!data) { qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist."); + return; } + + // Return to standard direction + hasSize = false; + if (reversed) + qSwap(data->from, data->to); + reversed = false; + + layoutPrivate->q_func()->invalidate(); } qreal QGraphicsAnchorPrivate::spacing() const { - qreal size = 0; - if (data) { - layoutPrivate->anchorSize(data, 0, &size, 0); - } else { + if (!data) { qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist."); + return 0; } - return size; + + return reversed ? -preferredSize : preferredSize; } @@ -146,8 +176,8 @@ bool AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo) qreal prefSizeHint; qreal maxSizeHint; - // It is an internal anchor if (item) { + // It is an internal anchor, fetch size information from the item if (isLayoutAnchor) { minSize = 0; prefSize = 0; @@ -175,14 +205,16 @@ bool AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo) } } } else { + // It is a user-created anchor, fetch size information from the associated QGraphicsAnchor Q_ASSERT(graphicsAnchor); - policy = graphicsAnchor->sizePolicy(); + QGraphicsAnchorPrivate *anchorPrivate = graphicsAnchor->d_func(); + policy = anchorPrivate->sizePolicy; minSizeHint = 0; - if (hasSize) { + if (anchorPrivate->hasSize) { // One can only configure the preferred size of a normal anchor. Their minimum and // maximum "size hints" are always 0 and QWIDGETSIZE_MAX, correspondingly. However, // their effective size hints might be narrowed down due to their size policies. - prefSizeHint = prefSize; + prefSizeHint = anchorPrivate->preferredSize; } else { const Qt::Orientation orient = Qt::Orientation(QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge) + 1); qreal s = styleInfo->defaultSpacing(orient); @@ -1565,7 +1597,13 @@ QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *fi correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge); AnchorData *data = new AnchorData; - if (!spacing) { + QGraphicsAnchor *graphicsAnchor = acquireGraphicsAnchor(data); + + addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data); + + if (spacing) { + graphicsAnchor->setSpacing(*spacing); + } else { // If firstItem or secondItem is the layout itself, the spacing will default to 0. // Otherwise, the following matrix is used (questionmark means that the spacing // is queried from the style): @@ -1578,22 +1616,13 @@ QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *fi || secondItem == q || pickEdge(firstEdge, Horizontal) == Qt::AnchorHorizontalCenter || oppositeEdge(firstEdge) != secondEdge) { - data->setPreferredSize(0); + graphicsAnchor->setSpacing(0); } else { - data->unsetSize(); + graphicsAnchor->unsetSpacing(); } - addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data); - - } else if (*spacing >= 0) { - data->setPreferredSize(*spacing); - addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data); - - } else { - data->setPreferredSize(-*spacing); - addAnchor_helper(secondItem, secondEdge, firstItem, firstEdge, data); } - return acquireGraphicsAnchor(data); + return graphicsAnchor; } void QGraphicsAnchorLayoutPrivate::addAnchor_helper(QGraphicsLayoutItem *firstItem, @@ -1753,67 +1782,6 @@ void QGraphicsAnchorLayoutPrivate::removeAnchor_helper(AnchorVertex *v1, AnchorV removeInternalVertex(v2->m_item, v2->m_edge); } -/*! - \internal - Only called from outside. (calls invalidate()) -*/ -void QGraphicsAnchorLayoutPrivate::setAnchorSize(AnchorData *data, const qreal *anchorSize) -{ - Q_Q(QGraphicsAnchorLayout); - // ### we can avoid restoration if we really want to, but we would have to - // search recursively through all composite anchors - Q_ASSERT(data); - restoreSimplifiedGraph(edgeOrientation(data->from->m_edge)); - - QGraphicsLayoutItem *firstItem = data->from->m_item; - QGraphicsLayoutItem *secondItem = data->to->m_item; - Qt::AnchorPoint firstEdge = data->from->m_edge; - Qt::AnchorPoint secondEdge = data->to->m_edge; - - // Use heuristics to find out what the user meant with this anchor. - correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge); - if (data->from->m_item != firstItem) - qSwap(data->from, data->to); - - if (anchorSize) { - // ### The current implementation makes "setAnchorSize" behavior - // dependent on the argument order for cases where we have - // no heuristic. Ie. two widgets, same anchor point. - - // We cannot have negative sizes inside the graph. This would cause - // the simplex solver to fail because all simplex variables are - // positive by definition. - // "negative spacing" is handled by inverting the standard item order. - if (*anchorSize >= 0) { - data->setPreferredSize(*anchorSize); - } else { - data->setPreferredSize(-*anchorSize); - qSwap(data->from, data->to); - } - } else { - data->unsetSize(); - } - q->invalidate(); -} - -void QGraphicsAnchorLayoutPrivate::anchorSize(const AnchorData *data, - qreal *minSize, - qreal *prefSize, - qreal *maxSize) const -{ - Q_ASSERT(minSize || prefSize || maxSize); - Q_ASSERT(data); - QGraphicsAnchorLayoutPrivate *that = const_cast(this); - that->restoreSimplifiedGraph(Orientation(data->orientation)); - - if (minSize) - *minSize = data->minSize; - if (prefSize) - *prefSize = data->prefSize; - if (maxSize) - *maxSize = data->maxSize; -} - AnchorVertex *QGraphicsAnchorLayoutPrivate::addInternalVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge) { diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index 26df109..cb8c4dd 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -126,7 +126,7 @@ struct AnchorData : public QSimplexVariable { sizeAtMinimum(0), sizeAtPreferred(0), sizeAtMaximum(0), item(0), graphicsAnchor(0), skipInPreferred(0), - type(Normal), hasSize(true), isLayoutAnchor(false), + type(Normal), isLayoutAnchor(false), isCenterAnchor(false), orientation(0), dependency(Independent) {} @@ -141,17 +141,6 @@ struct AnchorData : public QSimplexVariable { QString name; #endif - inline void setPreferredSize(qreal size) - { - prefSize = size; - hasSize = true; - } - - inline void unsetSize() - { - hasSize = false; - } - // Anchor is semantically directed AnchorVertex *from; AnchorVertex *to; @@ -182,7 +171,6 @@ struct AnchorData : public QSimplexVariable { uint skipInPreferred : 1; uint type : 2; // either Normal, Sequential or Parallel - uint hasSize : 1; // if false, get size from style. uint isLayoutAnchor : 1; // if this anchor is an internal layout anchor uint isCenterAnchor : 1; uint orientation : 1; @@ -355,7 +343,13 @@ public: QGraphicsAnchorLayoutPrivate *layoutPrivate; AnchorData *data; + + // Size information for user controlled anchor QSizePolicy::Policy sizePolicy; + qreal preferredSize; + + uint hasSize : 1; // if false, get size from style. + uint reversed : 1; // if true, the anchor was inverted to keep its value positive }; @@ -450,11 +444,6 @@ public: void removeAnchor(AnchorVertex *firstVertex, AnchorVertex *secondVertex); void removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2); - void setAnchorSize(AnchorData *data, const qreal *anchorSize); - void anchorSize(const AnchorData *data, - qreal *minSize = 0, - qreal *prefSize = 0, - qreal *maxSize = 0) const; void removeAnchors(QGraphicsLayoutItem *item); -- cgit v0.12