src/gui/graphicsview/qgraphicsanchorlayout_p.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
    38 ** $QT_END_LICENSE$
    38 ** $QT_END_LICENSE$
    39 **
    39 **
    40 ****************************************************************************/
    40 ****************************************************************************/
    41 
    41 
    42 #include <QtGui/qwidget.h>
    42 #include <QtGui/qwidget.h>
       
    43 #include <QtGui/qapplication.h>
    43 #include <QtCore/qlinkedlist.h>
    44 #include <QtCore/qlinkedlist.h>
    44 #include <QtCore/qstack.h>
    45 #include <QtCore/qstack.h>
    45 
    46 
    46 #ifdef QT_DEBUG
    47 #ifdef QT_DEBUG
    47 #include <QtCore/qfile.h>
    48 #include <QtCore/qfile.h>
    48 #endif
    49 #endif
    49 
    50 
    50 #include "qgraphicsanchorlayout_p.h"
    51 #include "qgraphicsanchorlayout_p.h"
    51 
    52 
       
    53 #ifndef QT_NO_GRAPHICSVIEW
    52 QT_BEGIN_NAMESPACE
    54 QT_BEGIN_NAMESPACE
    53 
    55 
       
    56 // To ensure that all variables inside the simplex solver are non-negative,
       
    57 // we limit the size of anchors in the interval [-limit, limit]. Then before
       
    58 // sending them to the simplex solver we add "limit" as an offset, so that
       
    59 // they are actually calculated in the interval [0, 2 * limit]
       
    60 // To avoid numerical errors in platforms where we use single precision,
       
    61 // we use a tighter limit for the variables range.
       
    62 const qreal g_offset = (sizeof(qreal) == sizeof(double)) ? QWIDGETSIZE_MAX : QWIDGETSIZE_MAX / 32;
    54 
    63 
    55 QGraphicsAnchorPrivate::QGraphicsAnchorPrivate(int version)
    64 QGraphicsAnchorPrivate::QGraphicsAnchorPrivate(int version)
    56     : QObjectPrivate(version), layoutPrivate(0), data(0),
    65     : QObjectPrivate(version), layoutPrivate(0), data(0),
    57       sizePolicy(QSizePolicy::Fixed)
    66       sizePolicy(QSizePolicy::Fixed), preferredSize(0),
       
    67       hasSize(true)
    58 {
    68 {
    59 }
    69 }
    60 
    70 
    61 QGraphicsAnchorPrivate::~QGraphicsAnchorPrivate()
    71 QGraphicsAnchorPrivate::~QGraphicsAnchorPrivate()
    62 {
    72 {
    63     layoutPrivate->removeAnchor(data->from, data->to);
    73     if (data) {
       
    74         // The QGraphicsAnchor was already deleted at this moment. We must clean
       
    75         // the dangling pointer to avoid double deletion in the AnchorData dtor.
       
    76         data->graphicsAnchor = 0;
       
    77 
       
    78         layoutPrivate->removeAnchor(data->from, data->to);
       
    79     }
    64 }
    80 }
    65 
    81 
    66 void QGraphicsAnchorPrivate::setSizePolicy(QSizePolicy::Policy policy)
    82 void QGraphicsAnchorPrivate::setSizePolicy(QSizePolicy::Policy policy)
    67 {
    83 {
    68     if (sizePolicy != policy) {
    84     if (sizePolicy != policy) {
    71     }
    87     }
    72 }
    88 }
    73 
    89 
    74 void QGraphicsAnchorPrivate::setSpacing(qreal value)
    90 void QGraphicsAnchorPrivate::setSpacing(qreal value)
    75 {
    91 {
    76     if (data) {
    92     if (!data) {
    77         layoutPrivate->setAnchorSize(data, &value);
       
    78     } else {
       
    79         qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
    93         qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
    80     }
    94         return;
       
    95     }
       
    96 
       
    97     if (hasSize && (preferredSize == value))
       
    98         return;
       
    99 
       
   100     // The anchor has an user-defined size
       
   101     hasSize = true;
       
   102     preferredSize = value;
       
   103 
       
   104     layoutPrivate->q_func()->invalidate();
    81 }
   105 }
    82 
   106 
    83 void QGraphicsAnchorPrivate::unsetSpacing()
   107 void QGraphicsAnchorPrivate::unsetSpacing()
    84 {
   108 {
    85     if (data) {
   109     if (!data) {
    86         layoutPrivate->setAnchorSize(data, 0);
       
    87     } else {
       
    88         qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
   110         qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
    89     }
   111         return;
       
   112     }
       
   113 
       
   114     // Return to standard direction
       
   115     hasSize = false;
       
   116 
       
   117     layoutPrivate->q_func()->invalidate();
    90 }
   118 }
    91 
   119 
    92 qreal QGraphicsAnchorPrivate::spacing() const
   120 qreal QGraphicsAnchorPrivate::spacing() const
    93 {
   121 {
    94     qreal size = 0;
   122     if (!data) {
    95     if (data) {
       
    96         layoutPrivate->anchorSize(data, 0, &size, 0);
       
    97     } else {
       
    98         qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
   123         qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
    99     }
   124         return 0;
   100     return size;
   125     }
   101 }
   126 
   102 
   127     return preferredSize;
   103 
   128 }
   104 static void internalSizeHints(QSizePolicy::Policy policy,
   129 
   105                               qreal minSizeHint, qreal prefSizeHint, qreal maxSizeHint,
   130 
   106                               qreal *minSize, qreal *prefSize,
   131 static void applySizePolicy(QSizePolicy::Policy policy,
   107                               qreal *expSize, qreal *maxSize)
   132                             qreal minSizeHint, qreal prefSizeHint, qreal maxSizeHint,
       
   133                             qreal *minSize, qreal *prefSize,
       
   134                             qreal *maxSize)
   108 {
   135 {
   109     // minSize, prefSize and maxSize are initialized
   136     // minSize, prefSize and maxSize are initialized
   110     // with item's preferred Size: this is QSizePolicy::Fixed.
   137     // with item's preferred Size: this is QSizePolicy::Fixed.
   111     //
   138     //
   112     // Then we check each flag to find the resultant QSizePolicy,
   139     // Then we check each flag to find the resultant QSizePolicy,
   132     // Note that these two initializations are affected by the previous flags
   159     // Note that these two initializations are affected by the previous flags
   133     if (policy & QSizePolicy::IgnoreFlag)
   160     if (policy & QSizePolicy::IgnoreFlag)
   134         *prefSize = *minSize;
   161         *prefSize = *minSize;
   135     else
   162     else
   136         *prefSize = prefSizeHint;
   163         *prefSize = prefSizeHint;
   137 
   164 }
   138     if (policy & QSizePolicy::ExpandFlag)
   165 
   139         *expSize = *maxSize;
   166 AnchorData::~AnchorData()
   140     else
   167 {
   141         *expSize = *prefSize;
   168     if (graphicsAnchor) {
   142 }
   169         // Remove reference to ourself to avoid double removal in
   143 
   170         // QGraphicsAnchorPrivate dtor.
   144 void AnchorData::refreshSizeHints(qreal effectiveSpacing)
   171         graphicsAnchor->d_func()->data = 0;
   145 {
   172 
   146     const bool isInternalAnchor = from->m_item == to->m_item;
   173         delete graphicsAnchor;
   147 
   174     }
       
   175 }
       
   176 
       
   177 
       
   178 void AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo)
       
   179 {
   148     QSizePolicy::Policy policy;
   180     QSizePolicy::Policy policy;
   149     qreal minSizeHint;
   181     qreal minSizeHint;
   150     qreal prefSizeHint;
   182     qreal prefSizeHint;
   151     qreal maxSizeHint;
   183     qreal maxSizeHint;
   152 
   184 
   153     if (isInternalAnchor) {
   185     if (item) {
   154         const QGraphicsAnchorLayoutPrivate::Orientation orient =
   186         // It is an internal anchor, fetch size information from the item
   155             QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge);
       
   156         const Qt::AnchorPoint centerEdge =
       
   157             QGraphicsAnchorLayoutPrivate::pickEdge(Qt::AnchorHorizontalCenter, orient);
       
   158         bool hasCenter = (from->m_edge == centerEdge || to->m_edge == centerEdge);
       
   159 
       
   160         if (isLayoutAnchor) {
   187         if (isLayoutAnchor) {
   161             minSize = 0;
   188             minSize = 0;
   162             prefSize = 0;
   189             prefSize = 0;
   163             expSize = 0;
       
   164             maxSize = QWIDGETSIZE_MAX;
   190             maxSize = QWIDGETSIZE_MAX;
   165             if (hasCenter)
   191             if (isCenterAnchor)
   166                 maxSize /= 2;
   192                 maxSize /= 2;
       
   193 
       
   194             minPrefSize = prefSize;
       
   195             maxPrefSize = maxSize;
   167             return;
   196             return;
   168         } else {
   197         } else {
   169 
   198             if (orientation == QGraphicsAnchorLayoutPrivate::Horizontal) {
   170             QGraphicsLayoutItem *item = from->m_item;
       
   171             if (orient == QGraphicsAnchorLayoutPrivate::Horizontal) {
       
   172                 policy = item->sizePolicy().horizontalPolicy();
   199                 policy = item->sizePolicy().horizontalPolicy();
   173                 minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width();
   200                 minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width();
   174                 prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width();
   201                 prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width();
   175                 maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width();
   202                 maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width();
   176             } else {
   203             } else {
   178                 minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height();
   205                 minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height();
   179                 prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height();
   206                 prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height();
   180                 maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height();
   207                 maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height();
   181             }
   208             }
   182 
   209 
   183             if (hasCenter) {
   210             if (isCenterAnchor) {
   184                 minSizeHint /= 2;
   211                 minSizeHint /= 2;
   185                 prefSizeHint /= 2;
   212                 prefSizeHint /= 2;
   186                 maxSizeHint /= 2;
   213                 maxSizeHint /= 2;
   187             }
   214             }
   188         }
   215         }
   189     } else {
   216     } else {
       
   217         // It is a user-created anchor, fetch size information from the associated QGraphicsAnchor
   190         Q_ASSERT(graphicsAnchor);
   218         Q_ASSERT(graphicsAnchor);
   191         policy = graphicsAnchor->sizePolicy();
   219         QGraphicsAnchorPrivate *anchorPrivate = graphicsAnchor->d_func();
       
   220 
       
   221         // Policy, min and max sizes are straightforward
       
   222         policy = anchorPrivate->sizePolicy;
   192         minSizeHint = 0;
   223         minSizeHint = 0;
   193         if (hasSize) {
   224         maxSizeHint = QWIDGETSIZE_MAX;
   194             // One can only configure the preferred size of a normal anchor. Their minimum and
   225 
   195             // maximum "size hints" are always 0 and QWIDGETSIZE_MAX, correspondingly. However,
   226         // Preferred Size
   196             // their effective size hints might be narrowed down due to their size policies.
   227         if (anchorPrivate->hasSize) {
   197             prefSizeHint = prefSize;
   228             // Anchor has user-defined size
       
   229             prefSizeHint = anchorPrivate->preferredSize;
   198         } else {
   230         } else {
   199             prefSizeHint = effectiveSpacing;
   231             // Fetch size information from style
   200         }
   232             const Qt::Orientation orient = Qt::Orientation(QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge) + 1);
   201         maxSizeHint = QWIDGETSIZE_MAX;
   233             qreal s = styleInfo->defaultSpacing(orient);
   202     }
   234             if (s < 0) {
   203     internalSizeHints(policy, minSizeHint, prefSizeHint, maxSizeHint, 
   235                 QSizePolicy::ControlType controlTypeFrom = from->m_item->sizePolicy().controlType();
   204                       &minSize, &prefSize, &expSize, &maxSize);
   236                 QSizePolicy::ControlType controlTypeTo = to->m_item->sizePolicy().controlType();
       
   237                 s = styleInfo->perItemSpacing(controlTypeFrom, controlTypeTo, orient);
       
   238 
       
   239                 // ### Currently we do not support negative anchors inside the graph.
       
   240                 // To avoid those being created by a negative style spacing, we must
       
   241                 // make this test.
       
   242                 if (s < 0)
       
   243                     s = 0;
       
   244             }
       
   245             prefSizeHint = s;
       
   246         }
       
   247     }
       
   248 
       
   249     // Fill minSize, prefSize and maxSize based on policy and sizeHints
       
   250     applySizePolicy(policy, minSizeHint, prefSizeHint, maxSizeHint,
       
   251                     &minSize, &prefSize, &maxSize);
       
   252 
       
   253     minPrefSize = prefSize;
       
   254     maxPrefSize = maxSize;
   205 
   255 
   206     // Set the anchor effective sizes to preferred.
   256     // Set the anchor effective sizes to preferred.
   207     //
   257     //
   208     // Note: The idea here is that all items should remain at their
   258     // Note: The idea here is that all items should remain at their
   209     // preferred size unless where that's impossible.  In cases where
   259     // preferred size unless where that's impossible.  In cases where
   210     // the item is subject to restrictions (anchored to the layout
   260     // the item is subject to restrictions (anchored to the layout
   211     // edges, for instance), the simplex solver will be run to
   261     // edges, for instance), the simplex solver will be run to
   212     // recalculate and override the values we set here.
   262     // recalculate and override the values we set here.
   213     sizeAtMinimum = prefSize;
   263     sizeAtMinimum = prefSize;
   214     sizeAtPreferred = prefSize;
   264     sizeAtPreferred = prefSize;
   215     sizeAtExpanding = prefSize;
       
   216     sizeAtMaximum = prefSize;
   265     sizeAtMaximum = prefSize;
   217 }
   266 }
   218 
   267 
   219 void ParallelAnchorData::updateChildrenSizes()
   268 void ParallelAnchorData::updateChildrenSizes()
   220 {
   269 {
   221     firstEdge->sizeAtMinimum = secondEdge->sizeAtMinimum = sizeAtMinimum;
   270     firstEdge->sizeAtMinimum = sizeAtMinimum;
   222     firstEdge->sizeAtPreferred = secondEdge->sizeAtPreferred = sizeAtPreferred;
   271     firstEdge->sizeAtPreferred = sizeAtPreferred;
   223     firstEdge->sizeAtExpanding = secondEdge->sizeAtExpanding = sizeAtExpanding;
   272     firstEdge->sizeAtMaximum = sizeAtMaximum;
   224     firstEdge->sizeAtMaximum = secondEdge->sizeAtMaximum = sizeAtMaximum;
   273 
       
   274     if (secondForward()) {
       
   275         secondEdge->sizeAtMinimum = sizeAtMinimum;
       
   276         secondEdge->sizeAtPreferred = sizeAtPreferred;
       
   277         secondEdge->sizeAtMaximum = sizeAtMaximum;
       
   278     } else {
       
   279         secondEdge->sizeAtMinimum = -sizeAtMinimum;
       
   280         secondEdge->sizeAtPreferred = -sizeAtPreferred;
       
   281         secondEdge->sizeAtMaximum = -sizeAtMaximum;
       
   282     }
   225 
   283 
   226     firstEdge->updateChildrenSizes();
   284     firstEdge->updateChildrenSizes();
   227     secondEdge->updateChildrenSizes();
   285     secondEdge->updateChildrenSizes();
   228 }
   286 }
   229 
   287 
   230 void ParallelAnchorData::refreshSizeHints(qreal effectiveSpacing)
   288 /*
   231 {
   289   \internal
   232     refreshSizeHints_helper(effectiveSpacing);
   290 
   233 }
   291   Initialize the parallel anchor size hints using the sizeHint information from
   234 
   292   its children.
   235 void ParallelAnchorData::refreshSizeHints_helper(qreal effectiveSpacing,
   293 
   236                                                  bool refreshChildren)
   294   Note that parallel groups can lead to unfeasibility, so during calculation, we can
   237 {
   295   find out one unfeasibility. Because of that this method return boolean. This can't
   238     if (refreshChildren) {
   296   happen in sequential, so there the method is void.
   239         firstEdge->refreshSizeHints(effectiveSpacing);
   297  */
   240         secondEdge->refreshSizeHints(effectiveSpacing);
   298 bool ParallelAnchorData::calculateSizeHints()
   241     }
   299 {
   242 
   300     // Normalize second child sizes.
   243     // ### should we warn if the parallel connection is invalid?
   301     // A negative anchor of sizes min, minPref, pref, maxPref and max, is equivalent
   244     // e.g. 1-2-3 with 10-20-30, the minimum of the latter is
   302     // to a forward anchor of sizes -max, -maxPref, -pref, -minPref, -min
   245     // bigger than the maximum of the former.
   303     qreal secondMin;
   246 
   304     qreal secondMinPref;
   247     minSize = qMax(firstEdge->minSize, secondEdge->minSize);
   305     qreal secondPref;
   248     maxSize = qMin(firstEdge->maxSize, secondEdge->maxSize);
   306     qreal secondMaxPref;
   249 
   307     qreal secondMax;
   250     expSize = qMax(firstEdge->expSize, secondEdge->expSize);
   308 
   251     expSize = qMin(expSize, maxSize);
   309     if (secondForward()) {
   252 
   310         secondMin = secondEdge->minSize;
   253     prefSize = qMax(firstEdge->prefSize, secondEdge->prefSize);
   311         secondMinPref = secondEdge->minPrefSize;
   254     prefSize = qMin(prefSize, expSize);
   312         secondPref = secondEdge->prefSize;
       
   313         secondMaxPref = secondEdge->maxPrefSize;
       
   314         secondMax = secondEdge->maxSize;
       
   315     } else {
       
   316         secondMin = -secondEdge->maxSize;
       
   317         secondMinPref = -secondEdge->maxPrefSize;
       
   318         secondPref = -secondEdge->prefSize;
       
   319         secondMaxPref = -secondEdge->minPrefSize;
       
   320         secondMax = -secondEdge->minSize;
       
   321     }
       
   322 
       
   323     minSize = qMax(firstEdge->minSize, secondMin);
       
   324     maxSize = qMin(firstEdge->maxSize, secondMax);
       
   325 
       
   326     // This condition means that the maximum size of one anchor being simplified is smaller than
       
   327     // the minimum size of the other anchor. The consequence is that there won't be a valid size
       
   328     // for this parallel setup.
       
   329     if (minSize > maxSize) {
       
   330         return false;
       
   331     }
       
   332 
       
   333     // Preferred size calculation
       
   334     // The calculation of preferred size is done as follows:
       
   335     //
       
   336     // 1) Check whether one of the child anchors is the layout structural anchor
       
   337     //    If so, we can simply copy the preferred information from the other child,
       
   338     //    after bounding it to our minimum and maximum sizes.
       
   339     //    If not, then we proceed with the actual calculations.
       
   340     //
       
   341     // 2) The whole algorithm for preferred size calculation is based on the fact
       
   342     //    that, if a given anchor cannot remain at its preferred size, it'd rather
       
   343     //    grow than shrink.
       
   344     //
       
   345     //    What happens though is that while this affirmative is true for simple
       
   346     //    anchors, it may not be true for sequential anchors that have one or more
       
   347     //    reversed anchors inside it. That happens because when a sequential anchor
       
   348     //    grows, any reversed anchors inside it may be required to shrink, something
       
   349     //    we try to avoid, as said above.
       
   350     //
       
   351     //    To overcome this, besides their actual preferred size "prefSize", each anchor
       
   352     //    exports what we call "minPrefSize" and "maxPrefSize". These two values define
       
   353     //    a surrounding interval where, if required to move, the anchor would rather
       
   354     //    remain inside.
       
   355     //
       
   356     //    For standard anchors, this area simply represents the region between
       
   357     //    prefSize and maxSize, which makes sense since our first affirmation.
       
   358     //    For composed anchors, these values are calculated as to reduce the global
       
   359     //    "damage", that is, to reduce the total deviation and the total amount of
       
   360     //    anchors that had to shrink.
       
   361 
       
   362     if (firstEdge->isLayoutAnchor) {
       
   363         prefSize = qBound(minSize, secondPref, maxSize);
       
   364         minPrefSize = qBound(minSize, secondMinPref, maxSize);
       
   365         maxPrefSize = qBound(minSize, secondMaxPref, maxSize);
       
   366     } else if (secondEdge->isLayoutAnchor) {
       
   367         prefSize = qBound(minSize, firstEdge->prefSize, maxSize);
       
   368         minPrefSize = qBound(minSize, firstEdge->minPrefSize, maxSize);
       
   369         maxPrefSize = qBound(minSize, firstEdge->maxPrefSize, maxSize);
       
   370     } else {
       
   371         // Calculate the intersection between the "preferred" regions of each child
       
   372         const qreal lowerBoundary =
       
   373             qBound(minSize, qMax(firstEdge->minPrefSize, secondMinPref), maxSize);
       
   374         const qreal upperBoundary =
       
   375             qBound(minSize, qMin(firstEdge->maxPrefSize, secondMaxPref), maxSize);
       
   376         const qreal prefMean =
       
   377             qBound(minSize, (firstEdge->prefSize + secondPref) / 2, maxSize);
       
   378 
       
   379         if (lowerBoundary < upperBoundary) {
       
   380             // If there is an intersection between the two regions, this intersection
       
   381             // will be used as the preferred region of the parallel anchor itself.
       
   382             // The preferred size will be the bounded average between the two preferred
       
   383             // sizes.
       
   384             prefSize = qBound(lowerBoundary, prefMean, upperBoundary);
       
   385             minPrefSize = lowerBoundary;
       
   386             maxPrefSize = upperBoundary;
       
   387         } else {
       
   388             // If there is no intersection, we have to attribute "damage" to at least
       
   389             // one of the children. The minimum total damage is achieved in points
       
   390             // inside the region that extends from (1) the upper boundary of the lower
       
   391             // region to (2) the lower boundary of the upper region.
       
   392             // Then, we expose this region as _our_ preferred region and once again,
       
   393             // use the bounded average as our preferred size.
       
   394             prefSize = qBound(upperBoundary, prefMean, lowerBoundary);
       
   395             minPrefSize = upperBoundary;
       
   396             maxPrefSize = lowerBoundary;
       
   397         }
       
   398     }
   255 
   399 
   256     // See comment in AnchorData::refreshSizeHints() about sizeAt* values
   400     // See comment in AnchorData::refreshSizeHints() about sizeAt* values
   257     sizeAtMinimum = prefSize;
   401     sizeAtMinimum = prefSize;
   258     sizeAtPreferred = prefSize;
   402     sizeAtPreferred = prefSize;
   259     sizeAtExpanding = prefSize;
       
   260     sizeAtMaximum = prefSize;
   403     sizeAtMaximum = prefSize;
       
   404 
       
   405     return true;
   261 }
   406 }
   262 
   407 
   263 /*!
   408 /*!
   264     \internal
   409     \internal
   265     returns the factor in the interval [-1, 1].
   410     returns the factor in the interval [-1, 1].
   266     -1 is at Minimum
   411     -1 is at Minimum
   267      0 is at Preferred
   412      0 is at Preferred
   268      1 is at Maximum
   413      1 is at Maximum
   269 */
   414 */
   270 static QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> getFactor(qreal value, qreal min,
   415 static QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> getFactor(qreal value, qreal min,
   271                                                                       qreal pref, qreal exp,
   416                                                                       qreal minPref, qreal pref,
   272                                                                       qreal max)
   417                                                                       qreal maxPref, qreal max)
   273 {
   418 {
   274     QGraphicsAnchorLayoutPrivate::Interval interval;
   419     QGraphicsAnchorLayoutPrivate::Interval interval;
   275     qreal lower;
   420     qreal lower;
   276     qreal upper;
   421     qreal upper;
   277 
   422 
   278     if (value < pref) {
   423     if (value < minPref) {
   279         interval = QGraphicsAnchorLayoutPrivate::MinToPreferred;
   424         interval = QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred;
   280         lower = min;
   425         lower = min;
       
   426         upper = minPref;
       
   427     } else if (value < pref) {
       
   428         interval = QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred;
       
   429         lower = minPref;
   281         upper = pref;
   430         upper = pref;
   282     } else if (value < exp) {
   431     } else if (value < maxPref) {
   283         interval = QGraphicsAnchorLayoutPrivate::PreferredToExpanding;
   432         interval = QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred;
   284         lower = pref;
   433         lower = pref;
   285         upper = exp;
   434         upper = maxPref;
   286     } else {
   435     } else {
   287         interval = QGraphicsAnchorLayoutPrivate::ExpandingToMax;
   436         interval = QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum;
   288         lower = exp;
   437         lower = maxPref;
   289         upper = max;
   438         upper = max;
   290     }
   439     }
   291 
   440 
   292     qreal progress;
   441     qreal progress;
   293     if (upper == lower) {
   442     if (upper == lower) {
   298 
   447 
   299     return qMakePair(interval, progress);
   448     return qMakePair(interval, progress);
   300 }
   449 }
   301 
   450 
   302 static qreal interpolate(const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> &factor,
   451 static qreal interpolate(const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> &factor,
   303                          qreal min, qreal pref,
   452                          qreal min, qreal minPref, qreal pref, qreal maxPref, qreal max)
   304                          qreal exp, qreal max)
       
   305 {
   453 {
   306     qreal lower;
   454     qreal lower;
   307     qreal upper;
   455     qreal upper;
   308 
   456 
   309     switch (factor.first) {
   457     switch (factor.first) {
   310     case QGraphicsAnchorLayoutPrivate::MinToPreferred:
   458     case QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred:
   311         lower = min;
   459         lower = min;
       
   460         upper = minPref;
       
   461         break;
       
   462     case QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred:
       
   463         lower = minPref;
   312         upper = pref;
   464         upper = pref;
   313         break;
   465         break;
   314     case QGraphicsAnchorLayoutPrivate::PreferredToExpanding:
   466     case QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred:
   315         lower = pref;
   467         lower = pref;
   316         upper = exp;
   468         upper = maxPref;
   317         break;
   469         break;
   318     case QGraphicsAnchorLayoutPrivate::ExpandingToMax:
   470     case QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum:
   319         lower = exp;
   471         lower = maxPref;
   320         upper = max;
   472         upper = max;
   321         break;
   473         break;
   322     }
   474     }
   323 
   475 
   324     return lower + factor.second * (upper - lower);
   476     return lower + factor.second * (upper - lower);
   325 }
   477 }
   326 
   478 
   327 void SequentialAnchorData::updateChildrenSizes()
   479 void SequentialAnchorData::updateChildrenSizes()
   328 {
   480 {
   329     // ### REMOVE ME
       
   330     // ### check whether we are guarantee to get those or we need to warn stuff at this
       
   331     // point.
       
   332     Q_ASSERT(sizeAtMinimum > minSize || qFuzzyCompare(sizeAtMinimum, minSize));
       
   333     Q_ASSERT(sizeAtMinimum < maxSize || qFuzzyCompare(sizeAtMinimum, maxSize));
       
   334     Q_ASSERT(sizeAtPreferred > minSize || qFuzzyCompare(sizeAtPreferred, minSize));
       
   335     Q_ASSERT(sizeAtPreferred < maxSize || qFuzzyCompare(sizeAtPreferred, maxSize));
       
   336     Q_ASSERT(sizeAtExpanding > minSize || qFuzzyCompare(sizeAtExpanding, minSize));
       
   337     Q_ASSERT(sizeAtExpanding < maxSize || qFuzzyCompare(sizeAtExpanding, maxSize));
       
   338     Q_ASSERT(sizeAtMaximum > minSize || qFuzzyCompare(sizeAtMaximum, minSize));
       
   339     Q_ASSERT(sizeAtMaximum < maxSize || qFuzzyCompare(sizeAtMaximum, maxSize));
       
   340 
       
   341     // Band here refers if the value is in the Minimum To Preferred
   481     // Band here refers if the value is in the Minimum To Preferred
   342     // band (the lower band) or the Preferred To Maximum (the upper band).
   482     // band (the lower band) or the Preferred To Maximum (the upper band).
   343 
   483 
   344     const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> minFactor =
   484     const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> minFactor =
   345         getFactor(sizeAtMinimum, minSize, prefSize, expSize, maxSize);
   485         getFactor(sizeAtMinimum, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);
   346     const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> prefFactor =
   486     const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> prefFactor =
   347         getFactor(sizeAtPreferred, minSize, prefSize, expSize, maxSize);
   487         getFactor(sizeAtPreferred, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);
   348     const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> expFactor =
       
   349         getFactor(sizeAtExpanding, minSize, prefSize, expSize, maxSize);
       
   350     const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> maxFactor =
   488     const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> maxFactor =
   351         getFactor(sizeAtMaximum, minSize, prefSize, expSize, maxSize);
   489         getFactor(sizeAtMaximum, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);
       
   490 
       
   491     // XXX This is not safe if Vertex simplification takes place after the sequential
       
   492     // anchor is created. In that case, "prev" will be a group-vertex, different from
       
   493     // "from" or "to", that _contains_ one of them.
       
   494     AnchorVertex *prev = from;
   352 
   495 
   353     for (int i = 0; i < m_edges.count(); ++i) {
   496     for (int i = 0; i < m_edges.count(); ++i) {
   354         AnchorData *e = m_edges.at(i);
   497         AnchorData *e = m_edges.at(i);
   355 
   498 
   356         e->sizeAtMinimum = interpolate(minFactor, e->minSize, e->prefSize, e->expSize, e->maxSize);
   499         const bool edgeIsForward = (e->from == prev);
   357         e->sizeAtPreferred = interpolate(prefFactor, e->minSize, e->prefSize, e->expSize, e->maxSize);
   500         if (edgeIsForward) {
   358         e->sizeAtExpanding = interpolate(expFactor, e->minSize, e->prefSize, e->expSize, e->maxSize);
   501             e->sizeAtMinimum = interpolate(minFactor, e->minSize, e->minPrefSize,
   359         e->sizeAtMaximum = interpolate(maxFactor, e->minSize, e->prefSize, e->expSize, e->maxSize);
   502                                            e->prefSize, e->maxPrefSize, e->maxSize);
       
   503             e->sizeAtPreferred = interpolate(prefFactor, e->minSize, e->minPrefSize,
       
   504                                            e->prefSize, e->maxPrefSize, e->maxSize);
       
   505             e->sizeAtMaximum = interpolate(maxFactor, e->minSize, e->minPrefSize,
       
   506                                            e->prefSize, e->maxPrefSize, e->maxSize);
       
   507             prev = e->to;
       
   508         } else {
       
   509             Q_ASSERT(prev == e->to);
       
   510             e->sizeAtMinimum = interpolate(minFactor, e->maxSize, e->maxPrefSize,
       
   511                                            e->prefSize, e->minPrefSize, e->minSize);
       
   512             e->sizeAtPreferred = interpolate(prefFactor, e->maxSize, e->maxPrefSize,
       
   513                                            e->prefSize, e->minPrefSize, e->minSize);
       
   514             e->sizeAtMaximum = interpolate(maxFactor, e->maxSize, e->maxPrefSize,
       
   515                                            e->prefSize, e->minPrefSize, e->minSize);
       
   516             prev = e->from;
       
   517         }
   360 
   518 
   361         e->updateChildrenSizes();
   519         e->updateChildrenSizes();
   362     }
   520     }
   363 }
   521 }
   364 
   522 
   365 void SequentialAnchorData::refreshSizeHints(qreal effectiveSpacing)
   523 void SequentialAnchorData::calculateSizeHints()
   366 {
       
   367     refreshSizeHints_helper(effectiveSpacing);
       
   368 }
       
   369 
       
   370 void SequentialAnchorData::refreshSizeHints_helper(qreal effectiveSpacing,
       
   371                                                    bool refreshChildren)
       
   372 {
   524 {
   373     minSize = 0;
   525     minSize = 0;
   374     prefSize = 0;
   526     prefSize = 0;
   375     expSize = 0;
       
   376     maxSize = 0;
   527     maxSize = 0;
       
   528     minPrefSize = 0;
       
   529     maxPrefSize = 0;
       
   530 
       
   531     AnchorVertex *prev = from;
   377 
   532 
   378     for (int i = 0; i < m_edges.count(); ++i) {
   533     for (int i = 0; i < m_edges.count(); ++i) {
   379         AnchorData *edge = m_edges.at(i);
   534         AnchorData *edge = m_edges.at(i);
   380 
   535 
   381         // If it's the case refresh children information first
   536         const bool edgeIsForward = (edge->from == prev);
   382         if (refreshChildren)
   537         if (edgeIsForward) {
   383             edge->refreshSizeHints(effectiveSpacing);
   538             minSize += edge->minSize;
   384 
   539             prefSize += edge->prefSize;
   385         minSize += edge->minSize;
   540             maxSize += edge->maxSize;
   386         prefSize += edge->prefSize;
   541             minPrefSize += edge->minPrefSize;
   387         expSize += edge->expSize;
   542             maxPrefSize += edge->maxPrefSize;
   388         maxSize += edge->maxSize;
   543             prev = edge->to;
       
   544         } else {
       
   545             Q_ASSERT(prev == edge->to);
       
   546             minSize -= edge->maxSize;
       
   547             prefSize -= edge->prefSize;
       
   548             maxSize -= edge->minSize;
       
   549             minPrefSize -= edge->maxPrefSize;
       
   550             maxPrefSize -= edge->minPrefSize;
       
   551             prev = edge->from;
       
   552         }
   389     }
   553     }
   390 
   554 
   391     // See comment in AnchorData::refreshSizeHints() about sizeAt* values
   555     // See comment in AnchorData::refreshSizeHints() about sizeAt* values
   392     sizeAtMinimum = prefSize;
   556     sizeAtMinimum = prefSize;
   393     sizeAtPreferred = prefSize;
   557     sizeAtPreferred = prefSize;
   394     sizeAtExpanding = prefSize;
       
   395     sizeAtMaximum = prefSize;
   558     sizeAtMaximum = prefSize;
   396 }
   559 }
   397 
   560 
   398 #ifdef QT_DEBUG
   561 #ifdef QT_DEBUG
   399 void AnchorData::dump(int indent) {
   562 void AnchorData::dump(int indent) {
   456     return string;
   619     return string;
   457 }
   620 }
   458 #endif
   621 #endif
   459 
   622 
   460 QGraphicsAnchorLayoutPrivate::QGraphicsAnchorLayoutPrivate()
   623 QGraphicsAnchorLayoutPrivate::QGraphicsAnchorLayoutPrivate()
   461     : calculateGraphCacheDirty(1)
   624     : calculateGraphCacheDirty(true), styleInfoDirty(true)
   462 {
   625 {
   463     for (int i = 0; i < NOrientations; ++i) {
   626     for (int i = 0; i < NOrientations; ++i) {
   464         for (int j = 0; j < 3; ++j) {
   627         for (int j = 0; j < 3; ++j) {
   465             sizeHints[i][j] = -1;
   628             sizeHints[i][j] = -1;
   466         }
   629         }
   467         sizeAtExpanding[i] = -1;
       
   468         interpolationProgress[i] = -1;
   630         interpolationProgress[i] = -1;
   469 
   631 
   470         spacings[i] = -1;
   632         spacings[i] = -1;
   471         graphSimplified[i] = false;
       
   472         graphHasConflicts[i] = false;
   633         graphHasConflicts[i] = false;
       
   634 
       
   635         layoutFirstVertex[i] = 0;
       
   636         layoutCentralVertex[i] = 0;
       
   637         layoutLastVertex[i] = 0;
   473     }
   638     }
   474 }
   639 }
   475 
   640 
   476 Qt::AnchorPoint QGraphicsAnchorLayoutPrivate::oppositeEdge(Qt::AnchorPoint edge)
   641 Qt::AnchorPoint QGraphicsAnchorLayoutPrivate::oppositeEdge(Qt::AnchorPoint edge)
   477 {
   642 {
   508         return FLT_MAX;
   673         return FLT_MAX;
   509     return a + b;
   674     return a + b;
   510 }
   675 }
   511 
   676 
   512 /*!
   677 /*!
   513  * \internal
   678     \internal
   514  *
   679 
   515  * Takes the sequence of vertices described by (\a before, \a vertices, \a after) and replaces
   680     Adds \a newAnchor to the graph.
   516  * all anchors connected to the vertices in \a vertices with one simplified anchor between
   681 
   517  * \a before and \a after. The simplified anchor will be a placeholder for all the previous
   682     Returns the newAnchor itself if it could be added without further changes to the graph. If a
   518  * anchors between \a before and \a after, and can be restored back to the anchors it is a
   683     new parallel anchor had to be created, then returns the new parallel anchor. If a parallel anchor
   519  * placeholder for.
   684     had to be created and it results in an unfeasible setup, \a feasible is set to false, otherwise
   520  */
   685     true.
   521 static bool simplifySequentialChunk(Graph<AnchorVertex, AnchorData> *graph,
   686 
   522                                     AnchorVertex *before,
   687     Note that in the case a new parallel anchor is created, it might also take over some constraints
   523                                     const QVector<AnchorVertex*> &vertices,
   688     from its children anchors.
   524                                     AnchorVertex *after)
   689 */
   525 {
   690 AnchorData *QGraphicsAnchorLayoutPrivate::addAnchorMaybeParallel(AnchorData *newAnchor, bool *feasible)
   526     AnchorData *data = graph->edgeData(before, vertices.first());
   691 {
   527     Q_ASSERT(data);
   692     Orientation orientation = Orientation(newAnchor->orientation);
   528 
   693     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
   529     const bool forward = (before == data->from);
   694     *feasible = true;
   530     QVector<AnchorVertex *> orderedVertices;
   695 
   531 
   696     // If already exists one anchor where newAnchor is supposed to be, we create a parallel
   532     if (forward) {
   697     // anchor.
   533         orderedVertices = vertices;
   698     if (AnchorData *oldAnchor = g.takeEdge(newAnchor->from, newAnchor->to)) {
   534     } else {
   699         ParallelAnchorData *parallel = new ParallelAnchorData(oldAnchor, newAnchor);
   535         qSwap(before, after);
   700 
   536         for (int i = vertices.count() - 1; i >= 0; --i)
   701         // The parallel anchor will "replace" its children anchors in
   537             orderedVertices.append(vertices.at(i));
   702         // every center constraint that they appear.
   538     }
   703 
   539 
   704         // ### If the dependent (center) anchors had reference(s) to their constraints, we
       
   705         // could avoid traversing all the itemCenterConstraints.
       
   706         QList<QSimplexConstraint *> &constraints = itemCenterConstraints[orientation];
       
   707 
       
   708         AnchorData *children[2] = { oldAnchor, newAnchor };
       
   709         QList<QSimplexConstraint *> *childrenConstraints[2] = { &parallel->m_firstConstraints,
       
   710                                                                 &parallel->m_secondConstraints };
       
   711 
       
   712         for (int i = 0; i < 2; ++i) {
       
   713             AnchorData *child = children[i];
       
   714             QList<QSimplexConstraint *> *childConstraints = childrenConstraints[i];
       
   715 
       
   716             // We need to fix the second child constraints if the parallel group will have the
       
   717             // opposite direction of the second child anchor. For the point of view of external
       
   718             // entities, this anchor was reversed. So if at some point we say that the parallel
       
   719             // has a value of 20, this mean that the second child (when reversed) will be
       
   720             // assigned -20.
       
   721             const bool needsReverse = i == 1 && !parallel->secondForward();
       
   722 
       
   723             if (!child->isCenterAnchor)
       
   724                 continue;
       
   725 
       
   726             parallel->isCenterAnchor = true;
       
   727 
       
   728             for (int j = 0; j < constraints.count(); ++j) {
       
   729                 QSimplexConstraint *c = constraints[j];
       
   730                 if (c->variables.contains(child)) {
       
   731                     childConstraints->append(c);
       
   732                     qreal v = c->variables.take(child);
       
   733                     if (needsReverse)
       
   734                         v *= -1;
       
   735                     c->variables.insert(parallel, v);
       
   736                 }
       
   737             }
       
   738         }
       
   739 
       
   740         // At this point we can identify that the parallel anchor is not feasible, e.g. one
       
   741         // anchor minimum size is bigger than the other anchor maximum size.
       
   742         *feasible = parallel->calculateSizeHints();
       
   743         newAnchor = parallel;
       
   744     }
       
   745 
       
   746     g.createEdge(newAnchor->from, newAnchor->to, newAnchor);
       
   747     return newAnchor;
       
   748 }
       
   749 
       
   750 /*!
       
   751     \internal
       
   752 
       
   753     Takes the sequence of vertices described by (\a before, \a vertices, \a after) and removes
       
   754     all anchors connected to the vertices in \a vertices, returning one simplified anchor between
       
   755     \a before and \a after.
       
   756 
       
   757     Note that this function doesn't add the created anchor to the graph. This should be done by
       
   758     the caller.
       
   759 */
       
   760 static AnchorData *createSequence(Graph<AnchorVertex, AnchorData> *graph,
       
   761                                   AnchorVertex *before,
       
   762                                   const QVector<AnchorVertex*> &vertices,
       
   763                                   AnchorVertex *after)
       
   764 {
   540 #if defined(QT_DEBUG) && 0
   765 #if defined(QT_DEBUG) && 0
   541     QString strVertices;
   766     QString strVertices;
   542     for (int i = 0; i < orderedVertices.count(); ++i) {
   767     for (int i = 0; i < vertices.count(); ++i) {
   543         strVertices += QString::fromAscii("%1 - ").arg(orderedVertices.at(i)->toString());
   768         strVertices += QString::fromAscii("%1 - ").arg(vertices.at(i)->toString());
   544     }
   769     }
   545     QString strPath = QString::fromAscii("%1 - %2%3").arg(before->toString(), strVertices, after->toString());
   770     QString strPath = QString::fromAscii("%1 - %2%3").arg(before->toString(), strVertices, after->toString());
   546     qDebug("simplifying [%s] to [%s - %s]", qPrintable(strPath), qPrintable(before->toString()), qPrintable(after->toString()));
   771     qDebug("simplifying [%s] to [%s - %s]", qPrintable(strPath), qPrintable(before->toString()), qPrintable(after->toString()));
   547 #endif
   772 #endif
   548 
   773 
   549     SequentialAnchorData *sequence = new SequentialAnchorData;
       
   550     AnchorVertex *prev = before;
   774     AnchorVertex *prev = before;
   551 
   775     QVector<AnchorData *> edges;
   552     for (int i = 0; i <= orderedVertices.count(); ++i) {
   776 
   553         AnchorVertex *next = (i < orderedVertices.count()) ? orderedVertices.at(i) : after;
   777     // Take from the graph, the edges that will be simplificated
       
   778     for (int i = 0; i < vertices.count(); ++i) {
       
   779         AnchorVertex *next = vertices.at(i);
   554         AnchorData *ad = graph->takeEdge(prev, next);
   780         AnchorData *ad = graph->takeEdge(prev, next);
   555         Q_ASSERT(ad);
   781         Q_ASSERT(ad);
   556         sequence->m_edges.append(ad);
   782         edges.append(ad);
   557         prev = next;
   783         prev = next;
   558     }
   784     }
   559 
   785 
   560     sequence->setVertices(orderedVertices);
   786     // Take the last edge (not covered in the loop above)
       
   787     AnchorData *ad = graph->takeEdge(vertices.last(), after);
       
   788     Q_ASSERT(ad);
       
   789     edges.append(ad);
       
   790 
       
   791     // Create sequence
       
   792     SequentialAnchorData *sequence = new SequentialAnchorData(vertices, edges);
   561     sequence->from = before;
   793     sequence->from = before;
   562     sequence->to = after;
   794     sequence->to = after;
   563 
   795 
   564     sequence->refreshSizeHints_helper(0, false);
   796     sequence->calculateSizeHints();
   565 
   797 
   566     // Note that since layout 'edges' can't be simplified away from
   798     return sequence;
   567     // the graph, it's safe to assume that if there's a layout
       
   568     // 'edge', it'll be in the boundaries of the sequence.
       
   569     sequence->isLayoutAnchor = (sequence->m_edges.first()->isLayoutAnchor
       
   570                                 || sequence->m_edges.last()->isLayoutAnchor);
       
   571 
       
   572     AnchorData *newAnchor = sequence;
       
   573     if (AnchorData *oldAnchor = graph->takeEdge(before, after)) {
       
   574         ParallelAnchorData *parallel = new ParallelAnchorData(oldAnchor, sequence);
       
   575         parallel->isLayoutAnchor = (oldAnchor->isLayoutAnchor
       
   576                                      || sequence->isLayoutAnchor);
       
   577         parallel->refreshSizeHints_helper(0, false);
       
   578         newAnchor = parallel;
       
   579     }
       
   580     graph->createEdge(before, after, newAnchor);
       
   581 
       
   582     // True if we created a parallel anchor
       
   583     return newAnchor != sequence;
       
   584 }
   799 }
   585 
   800 
   586 /*!
   801 /*!
   587    \internal
   802    \internal
   588 
   803 
   615       - Then create a parallel anchor that holds the sequential anchor and the anchor just taken
   830       - Then create a parallel anchor that holds the sequential anchor and the anchor just taken
   616         out of the graph.
   831         out of the graph.
   617    2. Go to (1)
   832    2. Go to (1)
   618    3. Done
   833    3. Done
   619 
   834 
       
   835    When creating the parallel anchors, the algorithm might identify unfeasible situations. In this
       
   836    case the simplification process stops and returns false. Otherwise returns true.
   620 */
   837 */
   621 void QGraphicsAnchorLayoutPrivate::simplifyGraph(Orientation orientation)
   838 bool QGraphicsAnchorLayoutPrivate::simplifyGraph(Orientation orientation)
   622 {
   839 {
   623     static bool noSimplification = !qgetenv("QT_ANCHORLAYOUT_NO_SIMPLIFICATION").isEmpty();
   840     if (items.isEmpty())
   624     if (noSimplification || items.isEmpty())
   841         return true;
   625         return;
   842 
   626 
   843 #if defined(QT_DEBUG) && 0
   627     if (graphSimplified[orientation])
       
   628         return;
       
   629     graphSimplified[orientation] = true;
       
   630 
       
   631 #if 0
       
   632     qDebug("Simplifying Graph for %s",
   844     qDebug("Simplifying Graph for %s",
   633            orientation == Horizontal ? "Horizontal" : "Vertical");
   845            orientation == Horizontal ? "Horizontal" : "Vertical");
       
   846 
       
   847     static int count = 0;
       
   848     if (orientation == Horizontal) {
       
   849         count++;
       
   850         dumpGraph(QString::fromAscii("%1-full").arg(count));
       
   851     }
   634 #endif
   852 #endif
   635 
   853 
   636     if (!graph[orientation].rootVertex())
   854     // Vertex simplification
   637         return;
   855     if (!simplifyVertices(orientation)) {
   638 
   856         restoreVertices(orientation);
       
   857         return false;
       
   858     }
       
   859 
       
   860     // Anchor simplification
   639     bool dirty;
   861     bool dirty;
       
   862     bool feasible = true;
   640     do {
   863     do {
   641         dirty = simplifyGraphIteration(orientation);
   864         dirty = simplifyGraphIteration(orientation, &feasible);
   642     } while (dirty);
   865     } while (dirty && feasible);
       
   866 
       
   867     // Note that if we are not feasible, we fallback and make sure that the graph is fully restored
       
   868     if (!feasible) {
       
   869         restoreSimplifiedGraph(orientation);
       
   870         restoreVertices(orientation);
       
   871         return false;
       
   872     }
       
   873 
       
   874 #if defined(QT_DEBUG) && 0
       
   875     dumpGraph(QString::fromAscii("%1-simplified-%2").arg(count).arg(
       
   876                   QString::fromAscii(orientation == Horizontal ? "Horizontal" : "Vertical")));
       
   877 #endif
       
   878 
       
   879     return true;
       
   880 }
       
   881 
       
   882 static AnchorVertex *replaceVertex_helper(AnchorData *data, AnchorVertex *oldV, AnchorVertex *newV)
       
   883 {
       
   884     AnchorVertex *other;
       
   885     if (data->from == oldV) {
       
   886         data->from = newV;
       
   887         other = data->to;
       
   888     } else {
       
   889         data->to = newV;
       
   890         other = data->from;
       
   891     }
       
   892     return other;
       
   893 }
       
   894 
       
   895 bool QGraphicsAnchorLayoutPrivate::replaceVertex(Orientation orientation, AnchorVertex *oldV,
       
   896                                                  AnchorVertex *newV, const QList<AnchorData *> &edges)
       
   897 {
       
   898     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
       
   899     bool feasible = true;
       
   900 
       
   901     for (int i = 0; i < edges.count(); ++i) {
       
   902         AnchorData *ad = edges[i];
       
   903         AnchorVertex *otherV = replaceVertex_helper(ad, oldV, newV);
       
   904 
       
   905 #if defined(QT_DEBUG)
       
   906         ad->name = QString::fromAscii("%1 --to--> %2").arg(ad->from->toString()).arg(ad->to->toString());
       
   907 #endif
       
   908 
       
   909         bool newFeasible;
       
   910         AnchorData *newAnchor = addAnchorMaybeParallel(ad, &newFeasible);
       
   911         feasible &= newFeasible;
       
   912 
       
   913         if (newAnchor != ad) {
       
   914             // A parallel was created, we mark that in the list of anchors created by vertex
       
   915             // simplification. This is needed because we want to restore them in a separate step
       
   916             // from the restoration of anchor simplification.
       
   917             anchorsFromSimplifiedVertices[orientation].append(newAnchor);
       
   918         }
       
   919 
       
   920         g.takeEdge(oldV, otherV);
       
   921     }
       
   922 
       
   923     return feasible;
       
   924 }
       
   925 
       
   926 /*!
       
   927     \internal
       
   928 */
       
   929 bool QGraphicsAnchorLayoutPrivate::simplifyVertices(Orientation orientation)
       
   930 {
       
   931     Q_Q(QGraphicsAnchorLayout);
       
   932     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
       
   933 
       
   934     // We'll walk through vertices
       
   935     QStack<AnchorVertex *> stack;
       
   936     stack.push(layoutFirstVertex[orientation]);
       
   937     QSet<AnchorVertex *> visited;
       
   938 
       
   939     while (!stack.isEmpty()) {
       
   940         AnchorVertex *v = stack.pop();
       
   941         visited.insert(v);
       
   942 
       
   943         // Each adjacent of 'v' is a possible vertex to be merged. So we traverse all of
       
   944         // them. Since once a merge is made, we might add new adjacents, and we don't want to
       
   945         // pass two times through one adjacent. The 'index' is used to track our position.
       
   946         QList<AnchorVertex *> adjacents = g.adjacentVertices(v);
       
   947         int index = 0;
       
   948 
       
   949         while (index < adjacents.count()) {
       
   950             AnchorVertex *next = adjacents.at(index);
       
   951             index++;
       
   952 
       
   953             AnchorData *data = g.edgeData(v, next);
       
   954             const bool bothLayoutVertices = v->m_item == q && next->m_item == q;
       
   955             const bool zeroSized = !data->minSize && !data->maxSize;
       
   956 
       
   957             if (!bothLayoutVertices && zeroSized) {
       
   958 
       
   959                 // Create a new vertex pair, note that we keep a list of those vertices so we can
       
   960                 // easily process them when restoring the graph.
       
   961                 AnchorVertexPair *newV = new AnchorVertexPair(v, next, data);
       
   962                 simplifiedVertices[orientation].append(newV);
       
   963 
       
   964                 // Collect the anchors of both vertices, the new vertex pair will take their place
       
   965                 // in those anchors
       
   966                 const QList<AnchorVertex *> &vAdjacents = g.adjacentVertices(v);
       
   967                 const QList<AnchorVertex *> &nextAdjacents = g.adjacentVertices(next);
       
   968 
       
   969                 for (int i = 0; i < vAdjacents.count(); ++i) {
       
   970                     AnchorVertex *adjacent = vAdjacents.at(i);
       
   971                     if (adjacent != next) {
       
   972                         AnchorData *ad = g.edgeData(v, adjacent);
       
   973                         newV->m_firstAnchors.append(ad);
       
   974                     }
       
   975                 }
       
   976 
       
   977                 for (int i = 0; i < nextAdjacents.count(); ++i) {
       
   978                     AnchorVertex *adjacent = nextAdjacents.at(i);
       
   979                     if (adjacent != v) {
       
   980                         AnchorData *ad = g.edgeData(next, adjacent);
       
   981                         newV->m_secondAnchors.append(ad);
       
   982 
       
   983                         // We'll also add new vertices to the adjacent list of the new 'v', to be
       
   984                         // created as a vertex pair and replace the current one.
       
   985                         if (!adjacents.contains(adjacent))
       
   986                             adjacents.append(adjacent);
       
   987                     }
       
   988                 }
       
   989 
       
   990                 // ### merge this loop into the ones that calculated m_firstAnchors/m_secondAnchors?
       
   991                 // Make newV take the place of v and next
       
   992                 bool feasible = replaceVertex(orientation, v, newV, newV->m_firstAnchors);
       
   993                 feasible &= replaceVertex(orientation, next, newV, newV->m_secondAnchors);
       
   994 
       
   995                 // Update the layout vertex information if one of the vertices is a layout vertex.
       
   996                 AnchorVertex *layoutVertex = 0;
       
   997                 if (v->m_item == q)
       
   998                     layoutVertex = v;
       
   999                 else if (next->m_item == q)
       
  1000                     layoutVertex = next;
       
  1001 
       
  1002                 if (layoutVertex) {
       
  1003                     // Layout vertices always have m_item == q...
       
  1004                     newV->m_item = q;
       
  1005                     changeLayoutVertex(orientation, layoutVertex, newV);
       
  1006                 }
       
  1007 
       
  1008                 g.takeEdge(v, next);
       
  1009 
       
  1010                 // If a non-feasibility is found, we leave early and cancel the simplification
       
  1011                 if (!feasible)
       
  1012                     return false;
       
  1013 
       
  1014                 v = newV;
       
  1015                 visited.insert(newV);
       
  1016 
       
  1017             } else if (!visited.contains(next) && !stack.contains(next)) {
       
  1018                 // If the adjacent is not fit for merge and it wasn't visited by the outermost
       
  1019                 // loop, we add it to the stack.
       
  1020                 stack.push(next);
       
  1021             }
       
  1022         }
       
  1023     }
       
  1024 
       
  1025     return true;
   643 }
  1026 }
   644 
  1027 
   645 /*!
  1028 /*!
   646     \internal
  1029     \internal
   647 
  1030 
   654     inserted, the collected list is cleared in order to find the next sequence to simplify.
  1037     inserted, the collected list is cleared in order to find the next sequence to simplify.
   655 
  1038 
   656     Note that there are some catches to this that are not covered by the above explanation, see
  1039     Note that there are some catches to this that are not covered by the above explanation, see
   657     the function comments for more details.
  1040     the function comments for more details.
   658 */
  1041 */
   659 bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutPrivate::Orientation orientation)
  1042 bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutPrivate::Orientation orientation,
       
  1043                                                           bool *feasible)
   660 {
  1044 {
   661     Q_Q(QGraphicsAnchorLayout);
  1045     Q_Q(QGraphicsAnchorLayout);
   662     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
  1046     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
   663 
  1047 
   664     QSet<AnchorVertex *> visited;
  1048     QSet<AnchorVertex *> visited;
   665     QStack<QPair<AnchorVertex *, AnchorVertex *> > stack;
  1049     QStack<QPair<AnchorVertex *, AnchorVertex *> > stack;
   666     stack.push(qMakePair(static_cast<AnchorVertex *>(0), g.rootVertex()));
  1050     stack.push(qMakePair(static_cast<AnchorVertex *>(0), layoutFirstVertex[orientation]));
   667     QVector<AnchorVertex*> candidates;
  1051     QVector<AnchorVertex*> candidates;
   668     bool candidatesForward;
       
   669 
       
   670     const Qt::AnchorPoint centerEdge = pickEdge(Qt::AnchorHorizontalCenter, orientation);
       
   671 
  1052 
   672     // Walk depth-first, in the stack we store start of the candidate sequence (beforeSequence)
  1053     // Walk depth-first, in the stack we store start of the candidate sequence (beforeSequence)
   673     // and the vertex to be visited.
  1054     // and the vertex to be visited.
   674     while (!stack.isEmpty()) {
  1055     while (!stack.isEmpty()) {
   675         QPair<AnchorVertex *, AnchorVertex *> pair = stack.pop();
  1056         QPair<AnchorVertex *, AnchorVertex *> pair = stack.pop();
   681         // and do a simplification step.
  1062         // and do a simplification step.
   682         //
  1063         //
   683         // A vertex can trigger an end of sequence if
  1064         // A vertex can trigger an end of sequence if
   684         // (a) it is a layout vertex, we don't simplify away the layout vertices;
  1065         // (a) it is a layout vertex, we don't simplify away the layout vertices;
   685         // (b) it does not have exactly 2 adjacents;
  1066         // (b) it does not have exactly 2 adjacents;
   686         // (c) it will change the direction of the sequence;
  1067         // (c) its next adjacent is already visited (a cycle in the graph).
   687         // (d) its next adjacent is already visited (a cycle in the graph).
  1068         // (d) the next anchor is a center anchor.
   688 
  1069 
   689         const QList<AnchorVertex *> &adjacents = g.adjacentVertices(v);
  1070         const QList<AnchorVertex *> &adjacents = g.adjacentVertices(v);
   690         const bool isLayoutVertex = v->m_item == q;
  1071         const bool isLayoutVertex = v->m_item == q;
   691         AnchorVertex *afterSequence = v;
  1072         AnchorVertex *afterSequence = v;
   692         bool endOfSequence = false;
  1073         bool endOfSequence = false;
   697 
  1078 
   698         // Identifies cases (a) and (b)
  1079         // Identifies cases (a) and (b)
   699         endOfSequence = isLayoutVertex || adjacents.count() != 2;
  1080         endOfSequence = isLayoutVertex || adjacents.count() != 2;
   700 
  1081 
   701         if (!endOfSequence) {
  1082         if (!endOfSequence) {
   702             // If this is the first vertice, determine what is the direction to use for this
  1083             // This is a tricky part. We peek at the next vertex to find out whether
   703             // sequence.
       
   704             if (candidates.isEmpty()) {
       
   705                 const AnchorData *data = g.edgeData(beforeSequence, v);
       
   706                 Q_ASSERT(data);
       
   707                 candidatesForward = (beforeSequence == data->from);
       
   708             }
       
   709 
       
   710             // This is a tricky part. We peek at the next vertex to find out
       
   711             //
  1084             //
   712             // - whether the edge from this vertex to the next vertex has the same direction;
  1085             // - we already visited the next vertex (c);
   713             // - whether we already visited the next vertex.
  1086             // - the next anchor is a center (d).
   714             //
  1087             //
   715             // Those are needed to identify (c) and (d). Note that unlike (a) and (b), we preempt
  1088             // Those are needed to identify the remaining end of sequence cases. Note that unlike
   716             // the end of sequence by looking into the next vertex.
  1089             // (a) and (b), we preempt the end of sequence by looking into the next vertex.
   717 
  1090 
   718             // Peek at the next vertex
  1091             // Peek at the next vertex
   719             AnchorVertex *after;
  1092             AnchorVertex *after;
   720             if (candidates.isEmpty())
  1093             if (candidates.isEmpty())
   721                 after = (beforeSequence == adjacents.last() ? adjacents.first() : adjacents.last());
  1094                 after = (beforeSequence == adjacents.last() ? adjacents.first() : adjacents.last());
   726             // when simplifying FLOATing anchors.
  1099             // when simplifying FLOATing anchors.
   727             Q_ASSERT(!candidates.contains(after));
  1100             Q_ASSERT(!candidates.contains(after));
   728 
  1101 
   729             const AnchorData *data = g.edgeData(v, after);
  1102             const AnchorData *data = g.edgeData(v, after);
   730             Q_ASSERT(data);
  1103             Q_ASSERT(data);
   731             const bool willChangeDirection = (candidatesForward != (v == data->from));
       
   732             const bool cycleFound = visited.contains(after);
  1104             const bool cycleFound = visited.contains(after);
   733 
  1105 
   734             // Now cases (c) and (d)...
  1106             // Now cases (c) and (d)...
   735             endOfSequence = willChangeDirection || cycleFound;
  1107             endOfSequence = cycleFound || data->isCenterAnchor;
   736 
  1108 
   737             if (endOfSequence) {
  1109             if (!endOfSequence) {
   738                 if (!willChangeDirection) {
       
   739                     // If the direction will not change, we can add the current vertex to the
       
   740                     // candidates list and we know that 'after' can be used as afterSequence.
       
   741                     candidates.append(v);
       
   742                     afterSequence = after;
       
   743                 }
       
   744             } else {
       
   745                 // If it's not an end of sequence, then the vertex didn't trigger neither of the
  1110                 // If it's not an end of sequence, then the vertex didn't trigger neither of the
   746                 // previously four cases, so it can be added to the candidates list.
  1111                 // previously three cases, so it can be added to the candidates list.
       
  1112                 candidates.append(v);
       
  1113             } else if (cycleFound && (beforeSequence != after)) {
       
  1114                 afterSequence = after;
   747                 candidates.append(v);
  1115                 candidates.append(v);
   748             }
  1116             }
   749         }
  1117         }
   750 
  1118 
   751         //
  1119         //
   775         // Create a sequence for (beforeSequence, candidates, afterSequence).
  1143         // Create a sequence for (beforeSequence, candidates, afterSequence).
   776         //
  1144         //
   777 
  1145 
   778         // One restriction we have is to not simplify half of an anchor and let the other half
  1146         // One restriction we have is to not simplify half of an anchor and let the other half
   779         // unsimplified. So we remove center edges before and after the sequence.
  1147         // unsimplified. So we remove center edges before and after the sequence.
   780         if (beforeSequence->m_edge == centerEdge && beforeSequence->m_item == candidates.first()->m_item) {
  1148         const AnchorData *firstAnchor = g.edgeData(beforeSequence, candidates.first());
       
  1149         if (firstAnchor->isCenterAnchor) {
   781             beforeSequence = candidates.first();
  1150             beforeSequence = candidates.first();
   782             candidates.remove(0);
  1151             candidates.remove(0);
   783 
  1152 
   784             // If there's not candidates to be simplified, leave.
  1153             // If there's not candidates to be simplified, leave.
   785             if (candidates.isEmpty())
  1154             if (candidates.isEmpty())
   786                 continue;
  1155                 continue;
   787         }
  1156         }
   788 
  1157 
   789         if (afterSequence->m_edge == centerEdge && afterSequence->m_item == candidates.last()->m_item) {
  1158         const AnchorData *lastAnchor = g.edgeData(candidates.last(), afterSequence);
       
  1159         if (lastAnchor->isCenterAnchor) {
   790             afterSequence = candidates.last();
  1160             afterSequence = candidates.last();
   791             candidates.remove(candidates.count() - 1);
  1161             candidates.remove(candidates.count() - 1);
   792 
  1162 
   793             if (candidates.isEmpty())
  1163             if (candidates.isEmpty())
   794                 continue;
  1164                 continue;
   795         }
  1165         }
   796 
  1166 
   797         // This function will remove the candidates from the graph and create one edge between
  1167         //
   798         // beforeSequence and afterSequence. This function returns true if the sequential
  1168         // Add the sequence to the graph.
   799         // simplification also caused a parallel simplification to be created. In this case we end
  1169         //
   800         // the iteration and start again (since all the visited state we have may be outdated).
  1170 
   801         if (simplifySequentialChunk(&g, beforeSequence, candidates, afterSequence))
  1171         AnchorData *sequence = createSequence(&g, beforeSequence, candidates, afterSequence);
       
  1172 
       
  1173         // If 'beforeSequence' and 'afterSequence' already had an anchor between them, we'll
       
  1174         // create a parallel anchor between the new sequence and the old anchor.
       
  1175         bool newFeasible;
       
  1176         AnchorData *newAnchor = addAnchorMaybeParallel(sequence, &newFeasible);
       
  1177 
       
  1178         if (!newFeasible) {
       
  1179             *feasible = false;
       
  1180             return false;
       
  1181         }
       
  1182 
       
  1183         // When a new parallel anchor is create in the graph, we finish the iteration and return
       
  1184         // true to indicate a new iteration is needed. This happens because a parallel anchor
       
  1185         // changes the number of adjacents one vertex has, possibly opening up oportunities for
       
  1186         // building candidate lists (when adjacents == 2).
       
  1187         if (newAnchor != sequence)
   802             return true;
  1188             return true;
   803 
  1189 
   804         // If there was no parallel simplification, we'll keep walking the graph. So we clear the
  1190         // If there was no parallel simplification, we'll keep walking the graph. So we clear the
   805         // candidates list to start again.
  1191         // candidates list to start again.
   806         candidates.clear();
  1192         candidates.clear();
   807     }
  1193     }
   808 
  1194 
   809     return false;
  1195     return false;
   810 }
  1196 }
   811 
  1197 
   812 static void restoreSimplifiedAnchor(Graph<AnchorVertex, AnchorData> &g,
  1198 void QGraphicsAnchorLayoutPrivate::restoreSimplifiedAnchor(AnchorData *edge)
   813                                     AnchorData *edge,
  1199 {
   814                                     AnchorVertex *before,
       
   815                                     AnchorVertex *after)
       
   816 {
       
   817     Q_ASSERT(edge->type != AnchorData::Normal);
       
   818 #if 0
  1200 #if 0
   819     static const char *anchortypes[] = {"Normal",
  1201     static const char *anchortypes[] = {"Normal",
   820                                         "Sequential",
  1202                                         "Sequential",
   821                                         "Parallel"};
  1203                                         "Parallel"};
   822     qDebug("Restoring %s edge.", anchortypes[int(edge->type)]);
  1204     qDebug("Restoring %s edge.", anchortypes[int(edge->type)]);
   823 #endif
  1205 #endif
   824     if (edge->type == AnchorData::Sequential) {
  1206 
   825         SequentialAnchorData* seqEdge = static_cast<SequentialAnchorData*>(edge);
  1207     Graph<AnchorVertex, AnchorData> &g = graph[edge->orientation];
   826         // restore the sequential anchor
  1208 
   827         AnchorVertex *prev = before;
  1209     if (edge->type == AnchorData::Normal) {
   828         AnchorVertex *last = after;
  1210         g.createEdge(edge->from, edge->to, edge);
   829         if (edge->from != prev)
  1211 
   830             qSwap(last, prev);
  1212     } else if (edge->type == AnchorData::Sequential) {
   831 
  1213         SequentialAnchorData *sequence = static_cast<SequentialAnchorData *>(edge);
   832         for (int i = 0; i < seqEdge->m_edges.count(); ++i) {
  1214 
   833             AnchorVertex *v1 = (i < seqEdge->m_children.count()) ? seqEdge->m_children.at(i) : last;
  1215         for (int i = 0; i < sequence->m_edges.count(); ++i) {
   834             AnchorData *data = seqEdge->m_edges.at(i);
  1216             AnchorData *data = sequence->m_edges.at(i);
   835             if (data->type != AnchorData::Normal) {
  1217             restoreSimplifiedAnchor(data);
   836                 restoreSimplifiedAnchor(g, data, prev, v1);
  1218         }
   837             } else {
  1219 
   838                 g.createEdge(prev, v1, data);
  1220         delete sequence;
   839             }
  1221 
   840             prev = v1;
       
   841         }
       
   842     } else if (edge->type == AnchorData::Parallel) {
  1222     } else if (edge->type == AnchorData::Parallel) {
   843         ParallelAnchorData* parallelEdge = static_cast<ParallelAnchorData*>(edge);
  1223 
   844         AnchorData *parallelEdges[2] = {parallelEdge->firstEdge,
  1224         // Skip parallel anchors that were created by vertex simplification, they will be processed
   845                                         parallelEdge->secondEdge};
  1225         // later, when restoring vertex simplification.
   846         for (int i = 0; i < 2; ++i) {
  1226         // ### we could improve this check bit having a bit inside 'edge'
   847             AnchorData *data = parallelEdges[i];
  1227         if (anchorsFromSimplifiedVertices[edge->orientation].contains(edge))
   848             if (data->type == AnchorData::Normal) {
  1228             return;
   849                 g.createEdge(before, after, data);
  1229 
   850             } else {
  1230         ParallelAnchorData* parallel = static_cast<ParallelAnchorData*>(edge);
   851                 restoreSimplifiedAnchor(g, data, before, after);
  1231         restoreSimplifiedConstraints(parallel);
   852             }
  1232 
   853         }
  1233         // ### Because of the way parallel anchors are created in the anchor simplification
       
  1234         // algorithm, we know that one of these will be a sequence, so it'll be safe if the other
       
  1235         // anchor create an edge between the same vertices as the parallel.
       
  1236         Q_ASSERT(parallel->firstEdge->type == AnchorData::Sequential
       
  1237                  || parallel->secondEdge->type == AnchorData::Sequential);
       
  1238         restoreSimplifiedAnchor(parallel->firstEdge);
       
  1239         restoreSimplifiedAnchor(parallel->secondEdge);
       
  1240 
       
  1241         delete parallel;
       
  1242     }
       
  1243 }
       
  1244 
       
  1245 void QGraphicsAnchorLayoutPrivate::restoreSimplifiedConstraints(ParallelAnchorData *parallel)
       
  1246 {
       
  1247     if (!parallel->isCenterAnchor)
       
  1248         return;
       
  1249 
       
  1250     for (int i = 0; i < parallel->m_firstConstraints.count(); ++i) {
       
  1251         QSimplexConstraint *c = parallel->m_firstConstraints.at(i);
       
  1252         qreal v = c->variables[parallel];
       
  1253         c->variables.remove(parallel);
       
  1254         c->variables.insert(parallel->firstEdge, v);
       
  1255     }
       
  1256 
       
  1257     // When restoring, we might have to revert constraints back. See comments on
       
  1258     // addAnchorMaybeParallel().
       
  1259     const bool needsReverse = !parallel->secondForward();
       
  1260 
       
  1261     for (int i = 0; i < parallel->m_secondConstraints.count(); ++i) {
       
  1262         QSimplexConstraint *c = parallel->m_secondConstraints.at(i);
       
  1263         qreal v = c->variables[parallel];
       
  1264         if (needsReverse)
       
  1265             v *= -1;
       
  1266         c->variables.remove(parallel);
       
  1267         c->variables.insert(parallel->secondEdge, v);
   854     }
  1268     }
   855 }
  1269 }
   856 
  1270 
   857 void QGraphicsAnchorLayoutPrivate::restoreSimplifiedGraph(Orientation orientation)
  1271 void QGraphicsAnchorLayoutPrivate::restoreSimplifiedGraph(Orientation orientation)
   858 {
  1272 {
   859     if (!graphSimplified[orientation])
       
   860         return;
       
   861     graphSimplified[orientation] = false;
       
   862 
       
   863 #if 0
  1273 #if 0
   864     qDebug("Restoring Simplified Graph for %s",
  1274     qDebug("Restoring Simplified Graph for %s",
   865            orientation == Horizontal ? "Horizontal" : "Vertical");
  1275            orientation == Horizontal ? "Horizontal" : "Vertical");
   866 #endif
  1276 #endif
   867 
  1277 
       
  1278     // Restore anchor simplification
   868     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
  1279     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
   869 
       
   870     QList<QPair<AnchorVertex*, AnchorVertex*> > connections = g.connections();
  1280     QList<QPair<AnchorVertex*, AnchorVertex*> > connections = g.connections();
   871     for (int i = 0; i < connections.count(); ++i) {
  1281     for (int i = 0; i < connections.count(); ++i) {
   872         AnchorVertex *v1 = connections.at(i).first;
  1282         AnchorVertex *v1 = connections.at(i).first;
   873         AnchorVertex *v2 = connections.at(i).second;
  1283         AnchorVertex *v2 = connections.at(i).second;
   874         AnchorData *edge = g.edgeData(v1, v2);
  1284         AnchorData *edge = g.edgeData(v1, v2);
   875         if (edge->type != AnchorData::Normal) {
  1285 
   876             AnchorData *oldEdge = g.takeEdge(v1, v2);
  1286         // We restore only sequential anchors and parallels that were not created by
   877             restoreSimplifiedAnchor(g, edge, v1, v2);
  1287         // vertex simplification.
   878             delete oldEdge;
  1288         if (edge->type == AnchorData::Sequential
   879         }
  1289             || (edge->type == AnchorData::Parallel &&
   880     }
  1290                 !anchorsFromSimplifiedVertices[orientation].contains(edge))) {
       
  1291 
       
  1292             g.takeEdge(v1, v2);
       
  1293             restoreSimplifiedAnchor(edge);
       
  1294         }
       
  1295     }
       
  1296 
       
  1297     restoreVertices(orientation);
       
  1298 }
       
  1299 
       
  1300 void QGraphicsAnchorLayoutPrivate::restoreVertices(Orientation orientation)
       
  1301 {
       
  1302     Q_Q(QGraphicsAnchorLayout);
       
  1303 
       
  1304     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
       
  1305     QList<AnchorVertexPair *> &toRestore = simplifiedVertices[orientation];
       
  1306 
       
  1307     // Since we keep a list of parallel anchors and vertices that were created during vertex
       
  1308     // simplification, we can now iterate on those lists instead of traversing the graph
       
  1309     // recursively.
       
  1310 
       
  1311     // First, restore the constraints changed when we created parallel anchors. Note that this
       
  1312     // works at this point because the constraints doesn't depend on vertex information and at
       
  1313     // this point it's always safe to identify whether the second child is forward or backwards.
       
  1314     // In the next step, we'll change the anchors vertices so that would not be possible anymore.
       
  1315     QList<AnchorData *> &parallelAnchors = anchorsFromSimplifiedVertices[orientation];
       
  1316 
       
  1317     for (int i = parallelAnchors.count() - 1; i >= 0; --i) {
       
  1318         ParallelAnchorData *parallel = static_cast<ParallelAnchorData *>(parallelAnchors.at(i));
       
  1319         restoreSimplifiedConstraints(parallel);
       
  1320     }
       
  1321 
       
  1322     // Then, we will restore the vertices in the inverse order of creation, this way we ensure that
       
  1323     // the vertex being restored was not wrapped by another simplification.
       
  1324     for (int i = toRestore.count() - 1; i >= 0; --i) {
       
  1325         AnchorVertexPair *pair = toRestore.at(i);
       
  1326         QList<AnchorVertex *> adjacents = g.adjacentVertices(pair);
       
  1327 
       
  1328         // Restore the removed edge, this will also restore both vertices 'first' and 'second' to
       
  1329         // the graph structure.
       
  1330         AnchorVertex *first = pair->m_first;
       
  1331         AnchorVertex *second = pair->m_second;
       
  1332         g.createEdge(first, second, pair->m_removedAnchor);
       
  1333 
       
  1334         // Restore the anchors for the first child vertex
       
  1335         for (int j = 0; j < pair->m_firstAnchors.count(); ++j) {
       
  1336             AnchorData *ad = pair->m_firstAnchors.at(j);
       
  1337             Q_ASSERT(ad->from == pair || ad->to == pair);
       
  1338 
       
  1339             replaceVertex_helper(ad, pair, first);
       
  1340             g.createEdge(ad->from, ad->to, ad);
       
  1341         }
       
  1342 
       
  1343         // Restore the anchors for the second child vertex
       
  1344         for (int j = 0; j < pair->m_secondAnchors.count(); ++j) {
       
  1345             AnchorData *ad = pair->m_secondAnchors.at(j);
       
  1346             Q_ASSERT(ad->from == pair || ad->to == pair);
       
  1347 
       
  1348             replaceVertex_helper(ad, pair, second);
       
  1349             g.createEdge(ad->from, ad->to, ad);
       
  1350         }
       
  1351 
       
  1352         for (int j = 0; j < adjacents.count(); ++j) {
       
  1353             g.takeEdge(pair, adjacents.at(j));
       
  1354         }
       
  1355 
       
  1356         // The pair simplified a layout vertex, so place back the correct vertex in the variable
       
  1357         // that track layout vertices
       
  1358         if (pair->m_item == q) {
       
  1359             AnchorVertex *layoutVertex = first->m_item == q ? first : second;
       
  1360             Q_ASSERT(layoutVertex->m_item == q);
       
  1361             changeLayoutVertex(orientation, pair, layoutVertex);
       
  1362         }
       
  1363 
       
  1364         delete pair;
       
  1365     }
       
  1366     qDeleteAll(parallelAnchors);
       
  1367     parallelAnchors.clear();
       
  1368     toRestore.clear();
   881 }
  1369 }
   882 
  1370 
   883 QGraphicsAnchorLayoutPrivate::Orientation
  1371 QGraphicsAnchorLayoutPrivate::Orientation
   884 QGraphicsAnchorLayoutPrivate::edgeOrientation(Qt::AnchorPoint edge)
  1372 QGraphicsAnchorLayoutPrivate::edgeOrientation(Qt::AnchorPoint edge)
   885 {
  1373 {
   903     // Horizontal
  1391     // Horizontal
   904     AnchorData *data = new AnchorData;
  1392     AnchorData *data = new AnchorData;
   905     addAnchor_helper(layout, Qt::AnchorLeft, layout,
  1393     addAnchor_helper(layout, Qt::AnchorLeft, layout,
   906                      Qt::AnchorRight, data);
  1394                      Qt::AnchorRight, data);
   907     data->maxSize = QWIDGETSIZE_MAX;
  1395     data->maxSize = QWIDGETSIZE_MAX;
   908     data->skipInPreferred = 1;
  1396 
   909 
  1397     // Save a reference to layout vertices
   910     // Set the Layout Left edge as the root of the horizontal graph.
  1398     layoutFirstVertex[Horizontal] = internalVertex(layout, Qt::AnchorLeft);
   911     AnchorVertex *v = internalVertex(layout, Qt::AnchorLeft);
  1399     layoutCentralVertex[Horizontal] = 0;
   912     graph[Horizontal].setRootVertex(v);
  1400     layoutLastVertex[Horizontal] = internalVertex(layout, Qt::AnchorRight);
   913 
  1401 
   914     // Vertical
  1402     // Vertical
   915     data = new AnchorData;
  1403     data = new AnchorData;
   916     addAnchor_helper(layout, Qt::AnchorTop, layout,
  1404     addAnchor_helper(layout, Qt::AnchorTop, layout,
   917                      Qt::AnchorBottom, data);
  1405                      Qt::AnchorBottom, data);
   918     data->maxSize = QWIDGETSIZE_MAX;
  1406     data->maxSize = QWIDGETSIZE_MAX;
   919     data->skipInPreferred = 1;
  1407 
   920 
  1408     // Save a reference to layout vertices
   921     // Set the Layout Top edge as the root of the vertical graph.
  1409     layoutFirstVertex[Vertical] = internalVertex(layout, Qt::AnchorTop);
   922     v = internalVertex(layout, Qt::AnchorTop);
  1410     layoutCentralVertex[Vertical] = 0;
   923     graph[Vertical].setRootVertex(v);
  1411     layoutLastVertex[Vertical] = internalVertex(layout, Qt::AnchorBottom);
   924 }
  1412 }
   925 
  1413 
   926 void QGraphicsAnchorLayoutPrivate::deleteLayoutEdges()
  1414 void QGraphicsAnchorLayoutPrivate::deleteLayoutEdges()
   927 {
  1415 {
   928     Q_Q(QGraphicsAnchorLayout);
  1416     Q_Q(QGraphicsAnchorLayout);
   929 
  1417 
   930     Q_ASSERT(internalVertex(q, Qt::AnchorHorizontalCenter) == NULL);
  1418     Q_ASSERT(!internalVertex(q, Qt::AnchorHorizontalCenter));
   931     Q_ASSERT(internalVertex(q, Qt::AnchorVerticalCenter) == NULL);
  1419     Q_ASSERT(!internalVertex(q, Qt::AnchorVerticalCenter));
   932 
  1420 
   933     removeAnchor_helper(internalVertex(q, Qt::AnchorLeft),
  1421     removeAnchor_helper(internalVertex(q, Qt::AnchorLeft),
   934                         internalVertex(q, Qt::AnchorRight));
  1422                         internalVertex(q, Qt::AnchorRight));
   935     removeAnchor_helper(internalVertex(q, Qt::AnchorTop),
  1423     removeAnchor_helper(internalVertex(q, Qt::AnchorTop),
   936                         internalVertex(q, Qt::AnchorBottom));
  1424                         internalVertex(q, Qt::AnchorBottom));
   937 }
  1425 }
   938 
  1426 
   939 void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item)
  1427 void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item)
   940 {
  1428 {
   941     Q_ASSERT(!graphSimplified[Horizontal] && !graphSimplified[Vertical]);
       
   942 
       
   943     items.append(item);
  1429     items.append(item);
   944 
  1430 
   945     // Create horizontal and vertical internal anchors for the item and
  1431     // Create horizontal and vertical internal anchors for the item and
   946     // refresh its size hint / policy values.
  1432     // refresh its size hint / policy values.
   947     AnchorData *data = new AnchorData;
  1433     AnchorData *data = new AnchorData;
   948     addAnchor_helper(item, Qt::AnchorLeft, item, Qt::AnchorRight, data);
  1434     addAnchor_helper(item, Qt::AnchorLeft, item, Qt::AnchorRight, data);
   949     data->refreshSizeHints(0); // 0 = effectiveSpacing, will not be used
  1435     data->refreshSizeHints();
   950 
  1436 
   951     data = new AnchorData;
  1437     data = new AnchorData;
   952     addAnchor_helper(item, Qt::AnchorTop, item, Qt::AnchorBottom, data);
  1438     addAnchor_helper(item, Qt::AnchorTop, item, Qt::AnchorBottom, data);
   953     data->refreshSizeHints(0); // 0 = effectiveSpacing, will not be used
  1439     data->refreshSizeHints();
   954 }
  1440 }
   955 
  1441 
   956 /*!
  1442 /*!
   957   \internal
  1443   \internal
   958 
  1444 
   965   these anchors must have the same time at all times.
  1451   these anchors must have the same time at all times.
   966 */
  1452 */
   967 void QGraphicsAnchorLayoutPrivate::createCenterAnchors(
  1453 void QGraphicsAnchorLayoutPrivate::createCenterAnchors(
   968     QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge)
  1454     QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge)
   969 {
  1455 {
       
  1456     Q_Q(QGraphicsAnchorLayout);
       
  1457 
   970     Orientation orientation;
  1458     Orientation orientation;
   971     switch (centerEdge) {
  1459     switch (centerEdge) {
   972     case Qt::AnchorHorizontalCenter:
  1460     case Qt::AnchorHorizontalCenter:
   973         orientation = Horizontal;
  1461         orientation = Horizontal;
   974         break;
  1462         break;
   978     default:
  1466     default:
   979         // Don't create center edges unless needed
  1467         // Don't create center edges unless needed
   980         return;
  1468         return;
   981     }
  1469     }
   982 
  1470 
   983     Q_ASSERT(!graphSimplified[orientation]);
       
   984 
       
   985     // Check if vertex already exists
  1471     // Check if vertex already exists
   986     if (internalVertex(item, centerEdge))
  1472     if (internalVertex(item, centerEdge))
   987         return;
  1473         return;
   988 
  1474 
   989     // Orientation code
  1475     // Orientation code
  1006     QSimplexConstraint *c = new QSimplexConstraint;
  1492     QSimplexConstraint *c = new QSimplexConstraint;
  1007 
  1493 
  1008     AnchorData *data = new AnchorData;
  1494     AnchorData *data = new AnchorData;
  1009     c->variables.insert(data, 1.0);
  1495     c->variables.insert(data, 1.0);
  1010     addAnchor_helper(item, firstEdge, item, centerEdge, data);
  1496     addAnchor_helper(item, firstEdge, item, centerEdge, data);
  1011     data->refreshSizeHints(0);
  1497     data->isCenterAnchor = true;
       
  1498     data->dependency = AnchorData::Master;
       
  1499     data->refreshSizeHints();
  1012 
  1500 
  1013     data = new AnchorData;
  1501     data = new AnchorData;
  1014     c->variables.insert(data, -1.0);
  1502     c->variables.insert(data, -1.0);
  1015     addAnchor_helper(item, centerEdge, item, lastEdge, data);
  1503     addAnchor_helper(item, centerEdge, item, lastEdge, data);
  1016     data->refreshSizeHints(0);
  1504     data->isCenterAnchor = true;
       
  1505     data->dependency = AnchorData::Slave;
       
  1506     data->refreshSizeHints();
  1017 
  1507 
  1018     itemCenterConstraints[orientation].append(c);
  1508     itemCenterConstraints[orientation].append(c);
  1019 
  1509 
  1020     // Remove old one
  1510     // Remove old one
  1021     removeAnchor_helper(first, last);
  1511     removeAnchor_helper(first, last);
       
  1512 
       
  1513     if (item == q) {
       
  1514         layoutCentralVertex[orientation] = internalVertex(q, centerEdge);
       
  1515     }
  1022 }
  1516 }
  1023 
  1517 
  1024 void QGraphicsAnchorLayoutPrivate::removeCenterAnchors(
  1518 void QGraphicsAnchorLayoutPrivate::removeCenterAnchors(
  1025     QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge,
  1519     QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge,
  1026     bool substitute)
  1520     bool substitute)
  1027 {
  1521 {
       
  1522     Q_Q(QGraphicsAnchorLayout);
       
  1523 
  1028     Orientation orientation;
  1524     Orientation orientation;
  1029     switch (centerEdge) {
  1525     switch (centerEdge) {
  1030     case Qt::AnchorHorizontalCenter:
  1526     case Qt::AnchorHorizontalCenter:
  1031         orientation = Horizontal;
  1527         orientation = Horizontal;
  1032         break;
  1528         break;
  1036     default:
  1532     default:
  1037         // Don't remove edges that not the center ones
  1533         // Don't remove edges that not the center ones
  1038         return;
  1534         return;
  1039     }
  1535     }
  1040 
  1536 
  1041     Q_ASSERT(!graphSimplified[orientation]);
       
  1042 
       
  1043     // Orientation code
  1537     // Orientation code
  1044     Qt::AnchorPoint firstEdge;
  1538     Qt::AnchorPoint firstEdge;
  1045     Qt::AnchorPoint lastEdge;
  1539     Qt::AnchorPoint lastEdge;
  1046 
  1540 
  1047     if (orientation == Horizontal) {
  1541     if (orientation == Horizontal) {
  1064 
  1558 
  1065 
  1559 
  1066     AnchorData *oldData = g.edgeData(first, center);
  1560     AnchorData *oldData = g.edgeData(first, center);
  1067     // Remove center constraint
  1561     // Remove center constraint
  1068     for (int i = itemCenterConstraints[orientation].count() - 1; i >= 0; --i) {
  1562     for (int i = itemCenterConstraints[orientation].count() - 1; i >= 0; --i) {
  1069         if (itemCenterConstraints[orientation][i]->variables.contains(oldData)) {
  1563         if (itemCenterConstraints[orientation].at(i)->variables.contains(oldData)) {
  1070             delete itemCenterConstraints[orientation].takeAt(i);
  1564             delete itemCenterConstraints[orientation].takeAt(i);
  1071             break;
  1565             break;
  1072         }
  1566         }
  1073     }
  1567     }
  1074 
  1568 
  1075     if (substitute) {
  1569     if (substitute) {
  1076         // Create the new anchor that should substitute the left-center-right anchors.
  1570         // Create the new anchor that should substitute the left-center-right anchors.
  1077         AnchorData *data = new AnchorData;
  1571         AnchorData *data = new AnchorData;
  1078         addAnchor_helper(item, firstEdge, item, lastEdge, data);
  1572         addAnchor_helper(item, firstEdge, item, lastEdge, data);
  1079         data->refreshSizeHints(0);
  1573         data->refreshSizeHints();
  1080 
  1574 
  1081         // Remove old anchors
  1575         // Remove old anchors
  1082         removeAnchor_helper(first, center);
  1576         removeAnchor_helper(first, center);
  1083         removeAnchor_helper(center, internalVertex(item, lastEdge));
  1577         removeAnchor_helper(center, internalVertex(item, lastEdge));
  1084 
  1578 
  1095         // when all non-internal anchors is removed it will automatically merge the
  1589         // when all non-internal anchors is removed it will automatically merge the
  1096         // center anchor into a left-right (or top-bottom) anchor. We must also delete that.
  1590         // center anchor into a left-right (or top-bottom) anchor. We must also delete that.
  1097         // by this time, the center vertex is deleted and merged into a non-centered internal anchor
  1591         // by this time, the center vertex is deleted and merged into a non-centered internal anchor
  1098         removeAnchor_helper(first, internalVertex(item, lastEdge));
  1592         removeAnchor_helper(first, internalVertex(item, lastEdge));
  1099     }
  1593     }
       
  1594 
       
  1595     if (item == q) {
       
  1596         layoutCentralVertex[orientation] = 0;
       
  1597     }
  1100 }
  1598 }
  1101 
  1599 
  1102 
  1600 
  1103 void QGraphicsAnchorLayoutPrivate::removeCenterConstraints(QGraphicsLayoutItem *item,
  1601 void QGraphicsAnchorLayoutPrivate::removeCenterConstraints(QGraphicsLayoutItem *item,
  1104                                                            Orientation orientation)
  1602                                                            Orientation orientation)
  1105 {
  1603 {
  1106     Q_ASSERT(!graphSimplified[orientation]);
       
  1107 
       
  1108     // Remove the item center constraints associated to this item
  1604     // Remove the item center constraints associated to this item
  1109     // ### This is a temporary solution. We should probably use a better
  1605     // ### This is a temporary solution. We should probably use a better
  1110     // data structure to hold items and/or their associated constraints
  1606     // data structure to hold items and/or their associated constraints
  1111     // so that we can remove those easily
  1607     // so that we can remove those easily
  1112 
  1608 
  1124     Q_ASSERT(first);
  1620     Q_ASSERT(first);
  1125     AnchorData *internalAnchor = graph[orientation].edgeData(first, center);
  1621     AnchorData *internalAnchor = graph[orientation].edgeData(first, center);
  1126 
  1622 
  1127     // Look for our anchor in all item center constraints, then remove it
  1623     // Look for our anchor in all item center constraints, then remove it
  1128     for (int i = 0; i < itemCenterConstraints[orientation].size(); ++i) {
  1624     for (int i = 0; i < itemCenterConstraints[orientation].size(); ++i) {
  1129         if (itemCenterConstraints[orientation][i]->variables.contains(internalAnchor)) {
  1625         if (itemCenterConstraints[orientation].at(i)->variables.contains(internalAnchor)) {
  1130             delete itemCenterConstraints[orientation].takeAt(i);
  1626             delete itemCenterConstraints[orientation].takeAt(i);
  1131             break;
  1627             break;
  1132         }
  1628         }
  1133     }
  1629     }
  1134 }
  1630 }
  1135 
  1631 
  1136 /*!
  1632 /*!
  1137  * \internal
  1633  * \internal
       
  1634  * Implements the high level "addAnchor" feature. Called by the public API
       
  1635  * addAnchor method.
  1138  *
  1636  *
  1139  * Helper function that is called from the anchor functions in the public API.
  1637  * The optional \a spacing argument defines the size of the anchor. If not provided,
  1140  * If \a spacing is 0, it will pick up the spacing defined by the style.
  1638  * the anchor size is either 0 or not-set, depending on type of anchor created (see
       
  1639  * matrix below).
       
  1640  *
       
  1641  * All anchors that remain with size not-set will assume the standard spacing,
       
  1642  * set either by the layout style or through the "setSpacing" layout API.
  1141  */
  1643  */
  1142 QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *firstItem,
  1644 QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *firstItem,
  1143                                                       Qt::AnchorPoint firstEdge,
  1645                                                          Qt::AnchorPoint firstEdge,
  1144                                                       QGraphicsLayoutItem *secondItem,
  1646                                                          QGraphicsLayoutItem *secondItem,
  1145                                                       Qt::AnchorPoint secondEdge,
  1647                                                          Qt::AnchorPoint secondEdge,
  1146                                                       qreal *spacing)
  1648                                                          qreal *spacing)
  1147 {
  1649 {
  1148     Q_Q(QGraphicsAnchorLayout);
  1650     Q_Q(QGraphicsAnchorLayout);
  1149     if ((firstItem == 0) || (secondItem == 0)) {
  1651     if ((firstItem == 0) || (secondItem == 0)) {
  1150         qWarning("QGraphicsAnchorLayout::addAnchor(): "
  1652         qWarning("QGraphicsAnchorLayout::addAnchor(): "
  1151                  "Cannot anchor NULL items");
  1653                  "Cannot anchor NULL items");
  1162         qWarning("QGraphicsAnchorLayout::addAnchor(): "
  1664         qWarning("QGraphicsAnchorLayout::addAnchor(): "
  1163                  "Cannot anchor edges of different orientations");
  1665                  "Cannot anchor edges of different orientations");
  1164         return 0;
  1666         return 0;
  1165     }
  1667     }
  1166 
  1668 
  1167     // Guarantee that the graph is no simplified when adding this anchor,
  1669     const QGraphicsLayoutItem *parentWidget = q->parentLayoutItem();
  1168     // anchor manipulation always happen in the full graph
  1670     if (firstItem == parentWidget || secondItem == parentWidget) {
  1169     restoreSimplifiedGraph(edgeOrientation(firstEdge));
  1671         qWarning("QGraphicsAnchorLayout::addAnchor(): "
       
  1672                  "You cannot add the parent of the layout to the layout.");
       
  1673         return 0;
       
  1674     }
  1170 
  1675 
  1171     // In QGraphicsAnchorLayout, items are represented in its internal
  1676     // In QGraphicsAnchorLayout, items are represented in its internal
  1172     // graph as four anchors that connect:
  1677     // graph as four anchors that connect:
  1173     //  - Left -> HCenter
  1678     //  - Left -> HCenter
  1174     //  - HCenter-> Right
  1679     //  - HCenter-> Right
  1175     //  - Top -> VCenter
  1680     //  - Top -> VCenter
  1176     //  - VCenter -> Bottom
  1681     //  - VCenter -> Bottom
  1177 
  1682 
  1178     // Ensure that the internal anchors have been created for both items.
  1683     // Ensure that the internal anchors have been created for both items.
  1179     if (firstItem != q && !items.contains(firstItem)) {
  1684     if (firstItem != q && !items.contains(firstItem)) {
  1180         restoreSimplifiedGraph(edgeOrientation(firstEdge) == Horizontal ? Vertical : Horizontal);
       
  1181         createItemEdges(firstItem);
  1685         createItemEdges(firstItem);
  1182         addChildLayoutItem(firstItem);
  1686         addChildLayoutItem(firstItem);
  1183     }
  1687     }
  1184     if (secondItem != q && !items.contains(secondItem)) {
  1688     if (secondItem != q && !items.contains(secondItem)) {
  1185         restoreSimplifiedGraph(edgeOrientation(firstEdge) == Horizontal ? Vertical : Horizontal);
       
  1186         createItemEdges(secondItem);
  1689         createItemEdges(secondItem);
  1187         addChildLayoutItem(secondItem);
  1690         addChildLayoutItem(secondItem);
  1188     }
  1691     }
  1189 
  1692 
  1190     // Create center edges if needed
  1693     // Create center edges if needed
  1193 
  1696 
  1194     // Use heuristics to find out what the user meant with this anchor.
  1697     // Use heuristics to find out what the user meant with this anchor.
  1195     correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge);
  1698     correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge);
  1196 
  1699 
  1197     AnchorData *data = new AnchorData;
  1700     AnchorData *data = new AnchorData;
  1198     if (!spacing) {
  1701     QGraphicsAnchor *graphicsAnchor = acquireGraphicsAnchor(data);
       
  1702 
       
  1703     addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data);
       
  1704 
       
  1705     if (spacing) {
       
  1706         graphicsAnchor->setSpacing(*spacing);
       
  1707     } else {
  1199         // If firstItem or secondItem is the layout itself, the spacing will default to 0.
  1708         // If firstItem or secondItem is the layout itself, the spacing will default to 0.
  1200         // Otherwise, the following matrix is used (questionmark means that the spacing
  1709         // Otherwise, the following matrix is used (questionmark means that the spacing
  1201         // is queried from the style):
  1710         // is queried from the style):
  1202         //                from
  1711         //                from
  1203         //  to      Left    HCenter Right
  1712         //  to      Left    HCenter Right
  1206         //  Right   ?       0       0
  1715         //  Right   ?       0       0
  1207         if (firstItem == q
  1716         if (firstItem == q
  1208             || secondItem == q
  1717             || secondItem == q
  1209             || pickEdge(firstEdge, Horizontal) == Qt::AnchorHorizontalCenter
  1718             || pickEdge(firstEdge, Horizontal) == Qt::AnchorHorizontalCenter
  1210             || oppositeEdge(firstEdge) != secondEdge) {
  1719             || oppositeEdge(firstEdge) != secondEdge) {
  1211             data->setPreferredSize(0);
  1720             graphicsAnchor->setSpacing(0);
  1212         } else {
  1721         } else {
  1213             data->unsetSize();
  1722             graphicsAnchor->unsetSpacing();
  1214         }
  1723         }
  1215         addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data);
  1724     }
  1216 
  1725 
  1217     } else if (*spacing >= 0) {
  1726     return graphicsAnchor;
  1218         data->setPreferredSize(*spacing);
  1727 }
  1219         addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data);
  1728 
  1220 
  1729 /*
  1221     } else {
  1730   \internal
  1222         data->setPreferredSize(-*spacing);
  1731 
  1223         addAnchor_helper(secondItem, secondEdge, firstItem, firstEdge, data);
  1732   This method adds an AnchorData to the internal graph. It is responsible for doing
  1224     }
  1733   the boilerplate part of such task.
  1225 
  1734 
  1226     return acquireGraphicsAnchor(data);
  1735   If another AnchorData exists between the mentioned vertices, it is deleted and
  1227 }
  1736   the new one is inserted.
  1228 
  1737 */
  1229 void QGraphicsAnchorLayoutPrivate::addAnchor_helper(QGraphicsLayoutItem *firstItem,
  1738 void QGraphicsAnchorLayoutPrivate::addAnchor_helper(QGraphicsLayoutItem *firstItem,
  1230                                              Qt::AnchorPoint firstEdge,
  1739                                                     Qt::AnchorPoint firstEdge,
  1231                                              QGraphicsLayoutItem *secondItem,
  1740                                                     QGraphicsLayoutItem *secondItem,
  1232                                              Qt::AnchorPoint secondEdge,
  1741                                                     Qt::AnchorPoint secondEdge,
  1233                                              AnchorData *data)
  1742                                                     AnchorData *data)
  1234 {
  1743 {
  1235     Q_Q(QGraphicsAnchorLayout);
  1744     Q_Q(QGraphicsAnchorLayout);
  1236 
  1745 
  1237     // Guarantee that the graph is no simplified when adding this anchor,
  1746     const Orientation orientation = edgeOrientation(firstEdge);
  1238     // anchor manipulation always happen in the full graph
  1747 
  1239     restoreSimplifiedGraph(edgeOrientation(firstEdge));
  1748     // Create or increase the reference count for the related vertices.
  1240 
       
  1241     // Is the Vertex (firstItem, firstEdge) already represented in our
       
  1242     // internal structure?
       
  1243     AnchorVertex *v1 = addInternalVertex(firstItem, firstEdge);
  1749     AnchorVertex *v1 = addInternalVertex(firstItem, firstEdge);
  1244     AnchorVertex *v2 = addInternalVertex(secondItem, secondEdge);
  1750     AnchorVertex *v2 = addInternalVertex(secondItem, secondEdge);
  1245 
  1751 
  1246     // Remove previous anchor
  1752     // Remove previous anchor
  1247     // ### Could we update the existing edgeData rather than creating a new one?
  1753     if (graph[orientation].edgeData(v1, v2)) {
  1248     if (graph[edgeOrientation(firstEdge)].edgeData(v1, v2)) {
       
  1249         removeAnchor_helper(v1, v2);
  1754         removeAnchor_helper(v1, v2);
  1250     }
  1755     }
       
  1756 
       
  1757     // If its an internal anchor, set the associated item
       
  1758     if (firstItem == secondItem)
       
  1759         data->item = firstItem;
       
  1760 
       
  1761     data->orientation = orientation;
  1251 
  1762 
  1252     // Create a bi-directional edge in the sense it can be transversed both
  1763     // Create a bi-directional edge in the sense it can be transversed both
  1253     // from v1 or v2. "data" however is shared between the two references
  1764     // from v1 or v2. "data" however is shared between the two references
  1254     // so we still know that the anchor direction is from 1 to 2.
  1765     // so we still know that the anchor direction is from 1 to 2.
  1255     data->from = v1;
  1766     data->from = v1;
  1256     data->to = v2;
  1767     data->to = v2;
  1257 #ifdef QT_DEBUG
  1768 #ifdef QT_DEBUG
  1258     data->name = QString::fromAscii("%1 --to--> %2").arg(v1->toString()).arg(v2->toString());
  1769     data->name = QString::fromAscii("%1 --to--> %2").arg(v1->toString()).arg(v2->toString());
  1259 #endif
  1770 #endif
  1260     // Keep track of anchors that are connected to the layout 'edges'
  1771     // ### bit to track internal anchors, since inside AnchorData methods
  1261     data->isLayoutAnchor = (v1->m_item == q || v2->m_item == q);
  1772     // we don't have access to the 'q' pointer.
  1262 
  1773     data->isLayoutAnchor = (data->item == q);
  1263     graph[edgeOrientation(firstEdge)].createEdge(v1, v2, data);
  1774 
       
  1775     graph[orientation].createEdge(v1, v2, data);
  1264 }
  1776 }
  1265 
  1777 
  1266 QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::getAnchor(QGraphicsLayoutItem *firstItem,
  1778 QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::getAnchor(QGraphicsLayoutItem *firstItem,
  1267                                                          Qt::AnchorPoint firstEdge,
  1779                                                          Qt::AnchorPoint firstEdge,
  1268                                                          QGraphicsLayoutItem *secondItem,
  1780                                                          QGraphicsLayoutItem *secondItem,
  1269                                                          Qt::AnchorPoint secondEdge)
  1781                                                          Qt::AnchorPoint secondEdge)
  1270 {
  1782 {
  1271     Orientation orient = edgeOrientation(firstEdge);
  1783     // Do not expose internal anchors
  1272     restoreSimplifiedGraph(orient);
  1784     if (firstItem == secondItem)
  1273 
  1785         return 0;
       
  1786 
       
  1787     const Orientation orientation = edgeOrientation(firstEdge);
  1274     AnchorVertex *v1 = internalVertex(firstItem, firstEdge);
  1788     AnchorVertex *v1 = internalVertex(firstItem, firstEdge);
  1275     AnchorVertex *v2 = internalVertex(secondItem, secondEdge);
  1789     AnchorVertex *v2 = internalVertex(secondItem, secondEdge);
  1276 
  1790 
  1277     QGraphicsAnchor *graphicsAnchor = 0;
  1791     QGraphicsAnchor *graphicsAnchor = 0;
  1278 
  1792 
  1279     AnchorData *data = graph[orient].edgeData(v1, v2);
  1793     AnchorData *data = graph[orientation].edgeData(v1, v2);
  1280     if (data)
  1794     if (data) {
  1281         graphicsAnchor = acquireGraphicsAnchor(data);
  1795         // We could use "acquireGraphicsAnchor" here, but to avoid a regression where
       
  1796         // an internal anchor was wrongly exposed, I want to ensure no new
       
  1797         // QGraphicsAnchor instances are created by this call.
       
  1798         // This assumption must hold because anchors are either user-created (and already
       
  1799         // have their public object created), or they are internal (and must not reach
       
  1800         // this point).
       
  1801         Q_ASSERT(data->graphicsAnchor);
       
  1802         graphicsAnchor = data->graphicsAnchor;
       
  1803     }
  1282     return graphicsAnchor;
  1804     return graphicsAnchor;
  1283 }
  1805 }
  1284 
  1806 
  1285 /*!
  1807 /*!
  1286  * \internal
  1808  * \internal
  1291 void QGraphicsAnchorLayoutPrivate::removeAnchor(AnchorVertex *firstVertex,
  1813 void QGraphicsAnchorLayoutPrivate::removeAnchor(AnchorVertex *firstVertex,
  1292                                                 AnchorVertex *secondVertex)
  1814                                                 AnchorVertex *secondVertex)
  1293 {
  1815 {
  1294     Q_Q(QGraphicsAnchorLayout);
  1816     Q_Q(QGraphicsAnchorLayout);
  1295 
  1817 
  1296     // Actually delete the anchor
  1818     // Save references to items while it's safe to assume the vertices exist
  1297     removeAnchor_helper(firstVertex, secondVertex);
       
  1298 
       
  1299     QGraphicsLayoutItem *firstItem = firstVertex->m_item;
  1819     QGraphicsLayoutItem *firstItem = firstVertex->m_item;
  1300     QGraphicsLayoutItem *secondItem = secondVertex->m_item;
  1820     QGraphicsLayoutItem *secondItem = secondVertex->m_item;
       
  1821 
       
  1822     // Delete the anchor (may trigger deletion of center vertices)
       
  1823     removeAnchor_helper(firstVertex, secondVertex);
       
  1824 
       
  1825     // Ensure no dangling pointer is left behind
       
  1826     firstVertex = secondVertex = 0;
  1301 
  1827 
  1302     // Checking if the item stays in the layout or not
  1828     // Checking if the item stays in the layout or not
  1303     bool keepFirstItem = false;
  1829     bool keepFirstItem = false;
  1304     bool keepSecondItem = false;
  1830     bool keepSecondItem = false;
  1305 
  1831 
  1359   private methods.
  1885   private methods.
  1360 */
  1886 */
  1361 void QGraphicsAnchorLayoutPrivate::removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2)
  1887 void QGraphicsAnchorLayoutPrivate::removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2)
  1362 {
  1888 {
  1363     Q_ASSERT(v1 && v2);
  1889     Q_ASSERT(v1 && v2);
  1364     // Guarantee that the graph is no simplified when removing this anchor,
       
  1365     // anchor manipulation always happen in the full graph
       
  1366     Orientation o = edgeOrientation(v1->m_edge);
       
  1367     restoreSimplifiedGraph(o);
       
  1368 
  1890 
  1369     // Remove edge from graph
  1891     // Remove edge from graph
       
  1892     const Orientation o = edgeOrientation(v1->m_edge);
  1370     graph[o].removeEdge(v1, v2);
  1893     graph[o].removeEdge(v1, v2);
  1371 
  1894 
  1372     // Decrease vertices reference count (may trigger a deletion)
  1895     // Decrease vertices reference count (may trigger a deletion)
  1373     removeInternalVertex(v1->m_item, v1->m_edge);
  1896     removeInternalVertex(v1->m_item, v1->m_edge);
  1374     removeInternalVertex(v2->m_item, v2->m_edge);
  1897     removeInternalVertex(v2->m_item, v2->m_edge);
  1375 }
       
  1376 
       
  1377 /*!
       
  1378     \internal
       
  1379     Only called from outside. (calls invalidate())
       
  1380 */
       
  1381 void QGraphicsAnchorLayoutPrivate::setAnchorSize(AnchorData *data, const qreal *anchorSize)
       
  1382 {
       
  1383     Q_Q(QGraphicsAnchorLayout);
       
  1384     // ### we can avoid restoration if we really want to, but we would have to
       
  1385     // search recursively through all composite anchors
       
  1386     Q_ASSERT(data);
       
  1387     restoreSimplifiedGraph(edgeOrientation(data->from->m_edge));
       
  1388 
       
  1389     QGraphicsLayoutItem *firstItem = data->from->m_item;
       
  1390     QGraphicsLayoutItem *secondItem = data->to->m_item;
       
  1391     Qt::AnchorPoint firstEdge = data->from->m_edge;
       
  1392     Qt::AnchorPoint secondEdge = data->to->m_edge;
       
  1393 
       
  1394     // Use heuristics to find out what the user meant with this anchor.
       
  1395     correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge);
       
  1396     if (data->from->m_item != firstItem)
       
  1397         qSwap(data->from, data->to);
       
  1398 
       
  1399     if (anchorSize) {
       
  1400         // ### The current implementation makes "setAnchorSize" behavior
       
  1401         //     dependent on the argument order for cases where we have
       
  1402         //     no heuristic. Ie. two widgets, same anchor point.
       
  1403 
       
  1404         // We cannot have negative sizes inside the graph. This would cause
       
  1405         // the simplex solver to fail because all simplex variables are
       
  1406         // positive by definition.
       
  1407         // "negative spacing" is handled by inverting the standard item order.
       
  1408         if (*anchorSize >= 0) {
       
  1409             data->setPreferredSize(*anchorSize);
       
  1410         } else {
       
  1411             data->setPreferredSize(-*anchorSize);
       
  1412             qSwap(data->from, data->to);
       
  1413         }
       
  1414     } else {
       
  1415         data->unsetSize();
       
  1416     }
       
  1417     q->invalidate();
       
  1418 }
       
  1419 
       
  1420 void QGraphicsAnchorLayoutPrivate::anchorSize(const AnchorData *data,
       
  1421                                               qreal *minSize,
       
  1422                                               qreal *prefSize,
       
  1423                                               qreal *maxSize) const
       
  1424 {
       
  1425     Q_ASSERT(minSize || prefSize || maxSize);
       
  1426     Q_ASSERT(data);
       
  1427     QGraphicsAnchorLayoutPrivate *that = const_cast<QGraphicsAnchorLayoutPrivate *>(this);
       
  1428     that->restoreSimplifiedGraph(edgeOrientation(data->from->m_edge));
       
  1429 
       
  1430     if (minSize)
       
  1431         *minSize = data->minSize;
       
  1432     if (prefSize)
       
  1433         *prefSize = data->prefSize;
       
  1434     if (maxSize)
       
  1435         *maxSize = data->maxSize;
       
  1436 }
  1898 }
  1437 
  1899 
  1438 AnchorVertex *QGraphicsAnchorLayoutPrivate::addInternalVertex(QGraphicsLayoutItem *item,
  1900 AnchorVertex *QGraphicsAnchorLayoutPrivate::addInternalVertex(QGraphicsLayoutItem *item,
  1439                                                               Qt::AnchorPoint edge)
  1901                                                               Qt::AnchorPoint edge)
  1440 {
  1902 {
  1498     }
  1960     }
  1499 }
  1961 }
  1500 
  1962 
  1501 void QGraphicsAnchorLayoutPrivate::removeAnchors(QGraphicsLayoutItem *item)
  1963 void QGraphicsAnchorLayoutPrivate::removeAnchors(QGraphicsLayoutItem *item)
  1502 {
  1964 {
  1503     Q_ASSERT(!graphSimplified[Horizontal] && !graphSimplified[Vertical]);
       
  1504 
       
  1505     // remove the center anchor first!!
  1965     // remove the center anchor first!!
  1506     removeCenterAnchors(item, Qt::AnchorHorizontalCenter, false);
  1966     removeCenterAnchors(item, Qt::AnchorHorizontalCenter, false);
  1507     removeVertex(item, Qt::AnchorLeft);
  1967     removeVertex(item, Qt::AnchorLeft);
  1508     removeVertex(item, Qt::AnchorRight);
  1968     removeVertex(item, Qt::AnchorRight);
  1509 
  1969 
  1563         qSwap(firstItem, secondItem);
  2023         qSwap(firstItem, secondItem);
  1564         qSwap(firstEdge, secondEdge);
  2024         qSwap(firstEdge, secondEdge);
  1565     }
  2025     }
  1566 }
  2026 }
  1567 
  2027 
  1568 qreal QGraphicsAnchorLayoutPrivate::effectiveSpacing(Orientation orientation) const
  2028 QLayoutStyleInfo &QGraphicsAnchorLayoutPrivate::styleInfo() const
  1569 {
  2029 {
  1570     Q_Q(const QGraphicsAnchorLayout);
  2030     if (styleInfoDirty) {
  1571     qreal s = spacings[orientation];
  2031         Q_Q(const QGraphicsAnchorLayout);
  1572     if (s < 0) {
  2032         //### Fix this if QGV ever gets support for Metal style or different Aqua sizes.
  1573         // ### make sure behaviour is the same as in QGraphicsGridLayout
  2033         QWidget *wid = 0;
       
  2034 
  1574         QGraphicsLayoutItem *parent = q->parentLayoutItem();
  2035         QGraphicsLayoutItem *parent = q->parentLayoutItem();
  1575         while (parent && parent->isLayout()) {
  2036         while (parent && parent->isLayout()) {
  1576             parent = parent->parentLayoutItem();
  2037             parent = parent->parentLayoutItem();
  1577         }
  2038         }
       
  2039         QGraphicsWidget *w = 0;
  1578         if (parent) {
  2040         if (parent) {
  1579             QGraphicsItem *parentItem = parent->graphicsItem();
  2041             QGraphicsItem *parentItem = parent->graphicsItem();
  1580             if (parentItem && parentItem->isWidget()) {
  2042             if (parentItem && parentItem->isWidget())
  1581                 QGraphicsWidget *w = static_cast<QGraphicsWidget*>(parentItem);
  2043                 w = static_cast<QGraphicsWidget*>(parentItem);
  1582                 s = w->style()->pixelMetric(orientation == Horizontal
  2044         }
  1583                                             ? QStyle::PM_LayoutHorizontalSpacing
  2045 
  1584                                             : QStyle::PM_LayoutVerticalSpacing);
  2046         QStyle *style = w ? w->style() : QApplication::style();
  1585             }
  2047         cachedStyleInfo = QLayoutStyleInfo(style, wid);
  1586         }
  2048         cachedStyleInfo.setDefaultSpacing(Qt::Horizontal, spacings[0]);
  1587     }
  2049         cachedStyleInfo.setDefaultSpacing(Qt::Vertical, spacings[1]);
  1588 
  2050 
  1589     // ### Currently we do not support negative anchors inside the graph.
  2051         styleInfoDirty = false;
  1590     // To avoid those being created by a negative style spacing, we must
  2052     }
  1591     // make this test.
  2053     return cachedStyleInfo;
  1592     if (s < 0)
       
  1593         s = 0;
       
  1594 
       
  1595     return s;
       
  1596 }
  2054 }
  1597 
  2055 
  1598 /*!
  2056 /*!
  1599   \internal
  2057   \internal
  1600 
  2058 
  1604 */
  2062 */
  1605 void QGraphicsAnchorLayoutPrivate::calculateGraphs()
  2063 void QGraphicsAnchorLayoutPrivate::calculateGraphs()
  1606 {
  2064 {
  1607     if (!calculateGraphCacheDirty)
  2065     if (!calculateGraphCacheDirty)
  1608         return;
  2066         return;
  1609 
       
  1610 #if defined(QT_DEBUG) && 0
       
  1611     static int count = 0;
       
  1612     count++;
       
  1613     dumpGraph(QString::fromAscii("%1-before").arg(count));
       
  1614 #endif
       
  1615 
       
  1616     calculateGraphs(Horizontal);
  2067     calculateGraphs(Horizontal);
  1617     calculateGraphs(Vertical);
  2068     calculateGraphs(Vertical);
  1618 
  2069     calculateGraphCacheDirty = false;
  1619 #if defined(QT_DEBUG) && 0
       
  1620     dumpGraph(QString::fromAscii("%1-after").arg(count));
       
  1621 #endif
       
  1622 
       
  1623     calculateGraphCacheDirty = 0;
       
  1624 }
  2070 }
  1625 
  2071 
  1626 // ### Maybe getGraphParts could return the variables when traversing, at least
  2072 // ### Maybe getGraphParts could return the variables when traversing, at least
  1627 // for trunk...
  2073 // for trunk...
  1628 QList<AnchorData *> getVariables(QList<QSimplexConstraint *> constraints)
  2074 QList<AnchorData *> getVariables(QList<QSimplexConstraint *> constraints)
  1629 {
  2075 {
  1630     QSet<AnchorData *> variableSet;
  2076     QSet<AnchorData *> variableSet;
  1631     for (int i = 0; i < constraints.count(); ++i) {
  2077     for (int i = 0; i < constraints.count(); ++i) {
  1632         const QSimplexConstraint *c = constraints[i];
  2078         const QSimplexConstraint *c = constraints.at(i);
  1633         foreach (QSimplexVariable *var, c->variables.keys()) {
  2079         foreach (QSimplexVariable *var, c->variables.keys()) {
  1634             variableSet += static_cast<AnchorData *>(var);
  2080             variableSet += static_cast<AnchorData *>(var);
  1635         }
  2081         }
  1636     }
  2082     }
  1637     return variableSet.toList();
  2083     return variableSet.toList();
  1638 }
  2084 }
  1639 
  2085 
  1640 /*!
  2086 /*!
  1641   \internal
  2087     \internal
  1642 
  2088 
  1643   Calculate graphs is the method that puts together all the helper routines
  2089     Calculate graphs is the method that puts together all the helper routines
  1644   so that the AnchorLayout can calculate the sizes of each item.
  2090     so that the AnchorLayout can calculate the sizes of each item.
  1645 
  2091 
  1646   In a nutshell it should do:
  2092     In a nutshell it should do:
  1647 
  2093 
  1648   1) Update anchor nominal sizes, that is, the size that each anchor would
  2094     1) Refresh anchor nominal sizes, that is, the size that each anchor would
  1649      have if no other restrictions applied. This is done by quering the
  2095        have if no other restrictions applied. This is done by quering the
  1650      layout style and the sizeHints of the items belonging to the layout.
  2096        layout style and the sizeHints of the items belonging to the layout.
  1651 
  2097 
  1652   2) Simplify the graph by grouping together parallel and sequential anchors
  2098     2) Simplify the graph by grouping together parallel and sequential anchors
  1653      into "group anchors". These have equivalent minimum, preferred and maximum
  2099        into "group anchors". These have equivalent minimum, preferred and maximum
  1654      sizeHints as the anchors they replace.
  2100        sizeHints as the anchors they replace.
  1655 
  2101 
  1656   3) Check if we got to a trivial case. In some cases, the whole graph can be
  2102     3) Check if we got to a trivial case. In some cases, the whole graph can be
  1657      simplified into a single anchor. If so, use this information. If not,
  2103        simplified into a single anchor. If so, use this information. If not,
  1658      then call the Simplex solver to calculate the anchors sizes.
  2104        then call the Simplex solver to calculate the anchors sizes.
  1659 
  2105 
  1660   4) Once the root anchors had its sizes calculated, propagate that to the
  2106     4) Once the root anchors had its sizes calculated, propagate that to the
  1661      anchors they represent.
  2107        anchors they represent.
  1662 */
  2108 */
  1663 void QGraphicsAnchorLayoutPrivate::calculateGraphs(
  2109 void QGraphicsAnchorLayoutPrivate::calculateGraphs(
  1664     QGraphicsAnchorLayoutPrivate::Orientation orientation)
  2110     QGraphicsAnchorLayoutPrivate::Orientation orientation)
  1665 {
  2111 {
  1666     Q_Q(QGraphicsAnchorLayout);
  2112 #if defined(QT_DEBUG) || defined(Q_AUTOTEST_EXPORT)
       
  2113     lastCalculationUsedSimplex[orientation] = false;
       
  2114 #endif
       
  2115 
       
  2116     static bool simplificationEnabled = qgetenv("QT_ANCHORLAYOUT_NO_SIMPLIFICATION").isEmpty();
       
  2117 
       
  2118     // Reset the nominal sizes of each anchor based on the current item sizes
       
  2119     refreshAllSizeHints(orientation);
  1667 
  2120 
  1668     // Simplify the graph
  2121     // Simplify the graph
  1669     simplifyGraph(orientation);
  2122     if (simplificationEnabled && !simplifyGraph(orientation)) {
  1670 
  2123         qWarning("QGraphicsAnchorLayout: anchor setup is not feasible.");
  1671     // Reset the nominal sizes of each anchor based on the current item sizes
  2124         graphHasConflicts[orientation] = true;
  1672     setAnchorSizeHintsFromItems(orientation);
  2125         return;
       
  2126     }
  1673 
  2127 
  1674     // Traverse all graph edges and store the possible paths to each vertex
  2128     // Traverse all graph edges and store the possible paths to each vertex
  1675     findPaths(orientation);
  2129     findPaths(orientation);
  1676 
  2130 
  1677     // From the paths calculated above, extract the constraints that the current
  2131     // From the paths calculated above, extract the constraints that the current
  1691     QList<QList<QSimplexConstraint *> > parts = getGraphParts(orientation);
  2145     QList<QList<QSimplexConstraint *> > parts = getGraphParts(orientation);
  1692 
  2146 
  1693     // Now run the simplex solver to calculate Minimum, Preferred and Maximum sizes
  2147     // Now run the simplex solver to calculate Minimum, Preferred and Maximum sizes
  1694     // of the "trunk" set of constraints and variables.
  2148     // of the "trunk" set of constraints and variables.
  1695     // ### does trunk always exist? empty = trunk is the layout left->center->right
  2149     // ### does trunk always exist? empty = trunk is the layout left->center->right
  1696     QList<QSimplexConstraint *> trunkConstraints = parts[0];
  2150     QList<QSimplexConstraint *> trunkConstraints = parts.at(0);
  1697     QList<AnchorData *> trunkVariables = getVariables(trunkConstraints);
  2151     QList<AnchorData *> trunkVariables = getVariables(trunkConstraints);
  1698 
  2152 
  1699     // For minimum and maximum, use the path between the two layout sides as the
  2153     // For minimum and maximum, use the path between the two layout sides as the
  1700     // objective function.
  2154     // objective function.
  1701     AnchorVertex *v = internalVertex(q, pickEdge(Qt::AnchorRight, orientation));
  2155     AnchorVertex *v = layoutLastVertex[orientation];
  1702     GraphPath trunkPath = graphPaths[orientation].value(v);
  2156     GraphPath trunkPath = graphPaths[orientation].value(v);
  1703 
  2157 
  1704     bool feasible = calculateTrunk(orientation, trunkPath, trunkConstraints, trunkVariables);
  2158     bool feasible = calculateTrunk(orientation, trunkPath, trunkConstraints, trunkVariables);
  1705 
  2159 
  1706     // For the other parts that not the trunk, solve only for the preferred size
  2160     // For the other parts that not the trunk, solve only for the preferred size
  1710     // Skipping the first (trunk)
  2164     // Skipping the first (trunk)
  1711     for (int i = 1; i < parts.count(); ++i) {
  2165     for (int i = 1; i < parts.count(); ++i) {
  1712         if (!feasible)
  2166         if (!feasible)
  1713             break;
  2167             break;
  1714 
  2168 
  1715         QList<QSimplexConstraint *> partConstraints = parts[i];
  2169         QList<QSimplexConstraint *> partConstraints = parts.at(i);
  1716         QList<AnchorData *> partVariables = getVariables(partConstraints);
  2170         QList<AnchorData *> partVariables = getVariables(partConstraints);
  1717         Q_ASSERT(!partVariables.isEmpty());
  2171         Q_ASSERT(!partVariables.isEmpty());
  1718         feasible &= calculateNonTrunk(partConstraints, partVariables);
  2172         feasible &= calculateNonTrunk(partConstraints, partVariables);
  1719     }
  2173     }
  1720 
  2174 
  1727     // Clean up our data structures. They are not needed anymore since
  2181     // Clean up our data structures. They are not needed anymore since
  1728     // distribution uses just interpolation.
  2182     // distribution uses just interpolation.
  1729     qDeleteAll(constraints[orientation]);
  2183     qDeleteAll(constraints[orientation]);
  1730     constraints[orientation].clear();
  2184     constraints[orientation].clear();
  1731     graphPaths[orientation].clear(); // ###
  2185     graphPaths[orientation].clear(); // ###
       
  2186 
       
  2187     if (simplificationEnabled)
       
  2188         restoreSimplifiedGraph(orientation);
       
  2189 }
       
  2190 
       
  2191 /*!
       
  2192     \internal
       
  2193 
       
  2194     Shift all the constraints by a certain amount. This allows us to deal with negative values in
       
  2195     the linear program if they are bounded by a certain limit. Functions should be careful to
       
  2196     call it again with a negative amount, to shift the constraints back.
       
  2197 */
       
  2198 static void shiftConstraints(const QList<QSimplexConstraint *> &constraints, qreal amount)
       
  2199 {
       
  2200     for (int i = 0; i < constraints.count(); ++i) {
       
  2201         QSimplexConstraint *c = constraints.at(i);
       
  2202         qreal multiplier = 0;
       
  2203         foreach (qreal v, c->variables.values()) {
       
  2204             multiplier += v;
       
  2205         }
       
  2206         c->constant += multiplier * amount;
       
  2207     }
  1732 }
  2208 }
  1733 
  2209 
  1734 /*!
  2210 /*!
  1735     \internal
  2211     \internal
  1736 
  2212 
  1752     if (needsSimplex) {
  2228     if (needsSimplex) {
  1753 
  2229 
  1754         QList<QSimplexConstraint *> sizeHintConstraints = constraintsFromSizeHints(variables);
  2230         QList<QSimplexConstraint *> sizeHintConstraints = constraintsFromSizeHints(variables);
  1755         QList<QSimplexConstraint *> allConstraints = constraints + sizeHintConstraints;
  2231         QList<QSimplexConstraint *> allConstraints = constraints + sizeHintConstraints;
  1756 
  2232 
       
  2233         shiftConstraints(allConstraints, g_offset);
       
  2234 
  1757         // Solve min and max size hints
  2235         // Solve min and max size hints
  1758         qreal min, max;
  2236         qreal min, max;
  1759         feasible = solveMinMax(allConstraints, path, &min, &max);
  2237         feasible = solveMinMax(allConstraints, path, &min, &max);
  1760 
  2238 
  1761         if (feasible) {
  2239         if (feasible) {
  1762             solvePreferred(allConstraints, variables);
  2240             solvePreferred(constraints, variables);
  1763 
  2241 
  1764             // Note that we don't include the sizeHintConstraints, since they
  2242             // Calculate and set the preferred size for the layout,
  1765             // have a different logic for solveExpanding().
       
  1766             solveExpanding(constraints, variables);
       
  1767 
       
  1768             // Calculate and set the preferred and expanding sizes for the layout,
       
  1769             // from the edge sizes that were calculated above.
  2243             // from the edge sizes that were calculated above.
  1770             qreal pref(0.0);
  2244             qreal pref(0.0);
  1771             qreal expanding(0.0);
       
  1772             foreach (const AnchorData *ad, path.positives) {
  2245             foreach (const AnchorData *ad, path.positives) {
  1773                 pref += ad->sizeAtPreferred;
  2246                 pref += ad->sizeAtPreferred;
  1774                 expanding += ad->sizeAtExpanding;
       
  1775             }
  2247             }
  1776             foreach (const AnchorData *ad, path.negatives) {
  2248             foreach (const AnchorData *ad, path.negatives) {
  1777                 pref -= ad->sizeAtPreferred;
  2249                 pref -= ad->sizeAtPreferred;
  1778                 expanding -= ad->sizeAtExpanding;
       
  1779             }
  2250             }
  1780 
  2251 
  1781             sizeHints[orientation][Qt::MinimumSize] = min;
  2252             sizeHints[orientation][Qt::MinimumSize] = min;
  1782             sizeHints[orientation][Qt::PreferredSize] = pref;
  2253             sizeHints[orientation][Qt::PreferredSize] = pref;
  1783             sizeHints[orientation][Qt::MaximumSize] = max;
  2254             sizeHints[orientation][Qt::MaximumSize] = max;
  1784             sizeAtExpanding[orientation] = expanding;
       
  1785         }
  2255         }
  1786 
  2256 
  1787         qDeleteAll(sizeHintConstraints);
  2257         qDeleteAll(sizeHintConstraints);
       
  2258         shiftConstraints(constraints, -g_offset);
  1788 
  2259 
  1789     } else {
  2260     } else {
  1790         // No Simplex is necessary because the path was simplified all the way to a single
  2261         // No Simplex is necessary because the path was simplified all the way to a single
  1791         // anchor.
  2262         // anchor.
  1792         Q_ASSERT(path.positives.count() == 1);
  2263         Q_ASSERT(path.positives.count() == 1);
  1793         Q_ASSERT(path.negatives.count() == 0);
  2264         Q_ASSERT(path.negatives.count() == 0);
  1794 
  2265 
  1795         AnchorData *ad = path.positives.toList()[0];
  2266         AnchorData *ad = path.positives.toList()[0];
  1796         ad->sizeAtMinimum = ad->minSize;
  2267         ad->sizeAtMinimum = ad->minSize;
  1797         ad->sizeAtPreferred = ad->prefSize;
  2268         ad->sizeAtPreferred = ad->prefSize;
  1798         ad->sizeAtExpanding = ad->expSize;
       
  1799         ad->sizeAtMaximum = ad->maxSize;
  2269         ad->sizeAtMaximum = ad->maxSize;
  1800 
  2270 
  1801         sizeHints[orientation][Qt::MinimumSize] = ad->sizeAtMinimum;
  2271         sizeHints[orientation][Qt::MinimumSize] = ad->sizeAtMinimum;
  1802         sizeHints[orientation][Qt::PreferredSize] = ad->sizeAtPreferred;
  2272         sizeHints[orientation][Qt::PreferredSize] = ad->sizeAtPreferred;
  1803         sizeHints[orientation][Qt::MaximumSize] = ad->sizeAtMaximum;
  2273         sizeHints[orientation][Qt::MaximumSize] = ad->sizeAtMaximum;
  1804         sizeAtExpanding[orientation] = ad->sizeAtExpanding;
       
  1805     }
  2274     }
  1806 
  2275 
  1807 #if defined(QT_DEBUG) || defined(Q_AUTOTEST_EXPORT)
  2276 #if defined(QT_DEBUG) || defined(Q_AUTOTEST_EXPORT)
  1808     lastCalculationUsedSimplex[orientation] = needsSimplex;
  2277     lastCalculationUsedSimplex[orientation] = needsSimplex;
  1809 #endif
  2278 #endif
  1815     \internal
  2284     \internal
  1816 */
  2285 */
  1817 bool QGraphicsAnchorLayoutPrivate::calculateNonTrunk(const QList<QSimplexConstraint *> &constraints,
  2286 bool QGraphicsAnchorLayoutPrivate::calculateNonTrunk(const QList<QSimplexConstraint *> &constraints,
  1818                                                      const QList<AnchorData *> &variables)
  2287                                                      const QList<AnchorData *> &variables)
  1819 {
  2288 {
  1820     QList<QSimplexConstraint *> sizeHintConstraints = constraintsFromSizeHints(variables);
  2289     shiftConstraints(constraints, g_offset);
  1821     bool feasible = solvePreferred(constraints + sizeHintConstraints, variables);
  2290     bool feasible = solvePreferred(constraints, variables);
  1822 
  2291 
  1823     if (feasible) {
  2292     if (feasible) {
  1824         // Propagate size at preferred to other sizes. Semi-floats always will be
  2293         // Propagate size at preferred to other sizes. Semi-floats always will be
  1825         // in their sizeAtPreferred.
  2294         // in their sizeAtPreferred.
  1826         for (int j = 0; j < variables.count(); ++j) {
  2295         for (int j = 0; j < variables.count(); ++j) {
  1827             AnchorData *ad = variables[j];
  2296             AnchorData *ad = variables.at(j);
  1828             Q_ASSERT(ad);
  2297             Q_ASSERT(ad);
  1829             ad->sizeAtMinimum = ad->sizeAtPreferred;
  2298             ad->sizeAtMinimum = ad->sizeAtPreferred;
  1830             ad->sizeAtExpanding = ad->sizeAtPreferred;
       
  1831             ad->sizeAtMaximum = ad->sizeAtPreferred;
  2299             ad->sizeAtMaximum = ad->sizeAtPreferred;
  1832         }
  2300         }
  1833     }
  2301     }
  1834 
  2302 
  1835     qDeleteAll(sizeHintConstraints);
  2303     shiftConstraints(constraints, -g_offset);
  1836     return feasible;
  2304     return feasible;
  1837 }
  2305 }
  1838 
  2306 
  1839 /*!
  2307 /*!
  1840   \internal
  2308     \internal
  1841 
  2309 
  1842   For graph edges ("anchors") that represent items, this method updates their
  2310     Traverse the graph refreshing the size hints. Edges will query their associated
  1843   intrinsic size restrictions, based on the item size hints.
  2311     item or graphicsAnchor for their size hints.
  1844 */
  2312 */
  1845 void QGraphicsAnchorLayoutPrivate::setAnchorSizeHintsFromItems(Orientation orientation)
  2313 void QGraphicsAnchorLayoutPrivate::refreshAllSizeHints(Orientation orientation)
  1846 {
  2314 {
  1847     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
  2315     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
  1848     QList<QPair<AnchorVertex *, AnchorVertex *> > vertices = g.connections();
  2316     QList<QPair<AnchorVertex *, AnchorVertex *> > vertices = g.connections();
  1849 
  2317 
  1850     qreal spacing = effectiveSpacing(orientation);
  2318     QLayoutStyleInfo styleInf = styleInfo();
  1851 
       
  1852     for (int i = 0; i < vertices.count(); ++i) {
  2319     for (int i = 0; i < vertices.count(); ++i) {
  1853         AnchorData *data = g.edgeData(vertices.at(i).first, vertices.at(i).second);;
  2320         AnchorData *data = g.edgeData(vertices.at(i).first, vertices.at(i).second);
  1854         Q_ASSERT(data->from && data->to);
  2321         data->refreshSizeHints(&styleInf);
  1855         data->refreshSizeHints(spacing);
       
  1856     }
  2322     }
  1857 }
  2323 }
  1858 
  2324 
  1859 /*!
  2325 /*!
  1860   \internal
  2326   \internal
  1870 {
  2336 {
  1871     QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;
  2337     QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;
  1872 
  2338 
  1873     QSet<AnchorData *> visited;
  2339     QSet<AnchorData *> visited;
  1874 
  2340 
  1875     AnchorVertex *root = graph[orientation].rootVertex();
  2341     AnchorVertex *root = layoutFirstVertex[orientation];
  1876 
  2342 
  1877     graphPaths[orientation].insert(root, GraphPath());
  2343     graphPaths[orientation].insert(root, GraphPath());
  1878 
  2344 
  1879     foreach (AnchorVertex *v, graph[orientation].adjacentVertices(root)) {
  2345     foreach (AnchorVertex *v, graph[orientation].adjacentVertices(root)) {
  1880         queue.enqueue(qMakePair(root, v));
  2346         queue.enqueue(qMakePair(root, v));
  1928             continue;
  2394             continue;
  1929 
  2395 
  1930         QList<GraphPath> pathsToVertex = graphPaths[orientation].values(vertex);
  2396         QList<GraphPath> pathsToVertex = graphPaths[orientation].values(vertex);
  1931         for (int i = 1; i < valueCount; ++i) {
  2397         for (int i = 1; i < valueCount; ++i) {
  1932             constraints[orientation] += \
  2398             constraints[orientation] += \
  1933                 pathsToVertex[0].constraint(pathsToVertex[i]);
  2399                 pathsToVertex[0].constraint(pathsToVertex.at(i));
  1934         }
  2400         }
  1935     }
  2401     }
  1936 }
  2402 }
  1937 
  2403 
  1938 /*!
  2404 /*!
  1956   sizes, as specified in its size hints
  2422   sizes, as specified in its size hints
  1957 */
  2423 */
  1958 QList<QSimplexConstraint *> QGraphicsAnchorLayoutPrivate::constraintsFromSizeHints(
  2424 QList<QSimplexConstraint *> QGraphicsAnchorLayoutPrivate::constraintsFromSizeHints(
  1959     const QList<AnchorData *> &anchors)
  2425     const QList<AnchorData *> &anchors)
  1960 {
  2426 {
       
  2427     if (anchors.isEmpty())
       
  2428         return QList<QSimplexConstraint *>();
       
  2429 
       
  2430     // Look for the layout edge. That can be either the first half in case the
       
  2431     // layout is split in two, or the whole layout anchor.
       
  2432     Orientation orient = Orientation(anchors.first()->orientation);
       
  2433     AnchorData *layoutEdge = 0;
       
  2434     if (layoutCentralVertex[orient]) {
       
  2435         layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutCentralVertex[orient]);
       
  2436     } else {
       
  2437         layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutLastVertex[orient]);
       
  2438     }
       
  2439 
       
  2440     // If maxSize is less then "infinite", that means there are other anchors
       
  2441     // grouped together with this one. We can't ignore its maximum value so we
       
  2442     // set back the variable to NULL to prevent the continue condition from being
       
  2443     // satisfied in the loop below.
       
  2444     const qreal expectedMax = layoutCentralVertex[orient] ? QWIDGETSIZE_MAX / 2 : QWIDGETSIZE_MAX;
       
  2445     qreal actualMax;
       
  2446     if (layoutEdge->from == layoutFirstVertex[orient]) {
       
  2447         actualMax = layoutEdge->maxSize;
       
  2448     } else {
       
  2449         actualMax = -layoutEdge->minSize;
       
  2450     }
       
  2451     if (actualMax != expectedMax) {
       
  2452         layoutEdge = 0;
       
  2453     }
       
  2454 
       
  2455     // For each variable, create constraints based on size hints
  1961     QList<QSimplexConstraint *> anchorConstraints;
  2456     QList<QSimplexConstraint *> anchorConstraints;
       
  2457     bool unboundedProblem = true;
  1962     for (int i = 0; i < anchors.size(); ++i) {
  2458     for (int i = 0; i < anchors.size(); ++i) {
       
  2459         AnchorData *ad = anchors.at(i);
       
  2460 
       
  2461         // Anchors that have their size directly linked to another one don't need constraints
       
  2462         // For exammple, the second half of an item has exactly the same size as the first half
       
  2463         // thus constraining the latter is enough.
       
  2464         if (ad->dependency == AnchorData::Slave)
       
  2465             continue;
       
  2466 
       
  2467         // To use negative variables inside simplex, we shift them so the minimum negative value is
       
  2468         // mapped to zero before solving. To make sure that it works, we need to guarantee that the
       
  2469         // variables are all inside a certain boundary.
       
  2470         qreal boundedMin = qBound(-g_offset, ad->minSize, g_offset);
       
  2471         qreal boundedMax = qBound(-g_offset, ad->maxSize, g_offset);
       
  2472 
       
  2473         if ((boundedMin == boundedMax) || qFuzzyCompare(boundedMin, boundedMax)) {
       
  2474             QSimplexConstraint *c = new QSimplexConstraint;
       
  2475             c->variables.insert(ad, 1.0);
       
  2476             c->constant = boundedMin;
       
  2477             c->ratio = QSimplexConstraint::Equal;
       
  2478             anchorConstraints += c;
       
  2479             unboundedProblem = false;
       
  2480         } else {
       
  2481             QSimplexConstraint *c = new QSimplexConstraint;
       
  2482             c->variables.insert(ad, 1.0);
       
  2483             c->constant = boundedMin;
       
  2484             c->ratio = QSimplexConstraint::MoreOrEqual;
       
  2485             anchorConstraints += c;
       
  2486 
       
  2487             // We avoid adding restrictions to the layout internal anchors. That's
       
  2488             // to prevent unnecessary fair distribution from happening due to this
       
  2489             // artificial restriction.
       
  2490             if (ad == layoutEdge)
       
  2491                 continue;
       
  2492 
       
  2493             c = new QSimplexConstraint;
       
  2494             c->variables.insert(ad, 1.0);
       
  2495             c->constant = boundedMax;
       
  2496             c->ratio = QSimplexConstraint::LessOrEqual;
       
  2497             anchorConstraints += c;
       
  2498             unboundedProblem = false;
       
  2499         }
       
  2500     }
       
  2501 
       
  2502     // If no upper boundary restriction was added, add one to avoid unbounded problem
       
  2503     if (unboundedProblem) {
  1963         QSimplexConstraint *c = new QSimplexConstraint;
  2504         QSimplexConstraint *c = new QSimplexConstraint;
  1964         c->variables.insert(anchors[i], 1.0);
  2505         c->variables.insert(layoutEdge, 1.0);
  1965         c->constant = anchors[i]->minSize;
  2506         // The maximum size that the layout can take
  1966         c->ratio = QSimplexConstraint::MoreOrEqual;
  2507         c->constant = g_offset;
  1967         anchorConstraints += c;
       
  1968 
       
  1969         c = new QSimplexConstraint;
       
  1970         c->variables.insert(anchors[i], 1.0);
       
  1971         c->constant = anchors[i]->maxSize;
       
  1972         c->ratio = QSimplexConstraint::LessOrEqual;
  2508         c->ratio = QSimplexConstraint::LessOrEqual;
  1973         anchorConstraints += c;
  2509         anchorConstraints += c;
  1974     }
  2510     }
  1975 
  2511 
  1976     return anchorConstraints;
  2512     return anchorConstraints;
  1980   \internal
  2516   \internal
  1981 */
  2517 */
  1982 QList< QList<QSimplexConstraint *> >
  2518 QList< QList<QSimplexConstraint *> >
  1983 QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation)
  2519 QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation)
  1984 {
  2520 {
  1985     Q_Q(QGraphicsAnchorLayout);
  2521     Q_ASSERT(layoutFirstVertex[orientation] && layoutLastVertex[orientation]);
  1986 
  2522 
  1987     // Find layout vertices and edges for the current orientation.
  2523     AnchorData *edgeL1 = 0;
  1988     AnchorVertex *layoutFirstVertex = \
  2524     AnchorData *edgeL2 = 0;
  1989         internalVertex(q, pickEdge(Qt::AnchorLeft, orientation));
       
  1990 
       
  1991     AnchorVertex *layoutCentralVertex = \
       
  1992         internalVertex(q, pickEdge(Qt::AnchorHorizontalCenter, orientation));
       
  1993 
       
  1994     AnchorVertex *layoutLastVertex = \
       
  1995         internalVertex(q, pickEdge(Qt::AnchorRight, orientation));
       
  1996 
       
  1997     Q_ASSERT(layoutFirstVertex && layoutLastVertex);
       
  1998 
       
  1999     AnchorData *edgeL1 = NULL;
       
  2000     AnchorData *edgeL2 = NULL;
       
  2001 
  2525 
  2002     // The layout may have a single anchor between Left and Right or two half anchors
  2526     // The layout may have a single anchor between Left and Right or two half anchors
  2003     // passing through the center
  2527     // passing through the center
  2004     if (layoutCentralVertex) {
  2528     if (layoutCentralVertex[orientation]) {
  2005         edgeL1 = graph[orientation].edgeData(layoutFirstVertex, layoutCentralVertex);
  2529         edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutCentralVertex[orientation]);
  2006         edgeL2 = graph[orientation].edgeData(layoutCentralVertex, layoutLastVertex);
  2530         edgeL2 = graph[orientation].edgeData(layoutCentralVertex[orientation], layoutLastVertex[orientation]);
  2007     } else {
  2531     } else {
  2008         edgeL1 = graph[orientation].edgeData(layoutFirstVertex, layoutLastVertex);
  2532         edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutLastVertex[orientation]);
  2009     }
  2533     }
  2010 
  2534 
  2011     QLinkedList<QSimplexConstraint *> remainingConstraints;
  2535     QLinkedList<QSimplexConstraint *> remainingConstraints;
  2012     for (int i = 0; i < constraints[orientation].count(); ++i) {
  2536     for (int i = 0; i < constraints[orientation].count(); ++i) {
  2013         remainingConstraints += constraints[orientation][i];
  2537         remainingConstraints += constraints[orientation].at(i);
  2014     }
  2538     }
  2015     for (int i = 0; i < itemCenterConstraints[orientation].count(); ++i) {
  2539     for (int i = 0; i < itemCenterConstraints[orientation].count(); ++i) {
  2016         remainingConstraints += itemCenterConstraints[orientation][i];
  2540         remainingConstraints += itemCenterConstraints[orientation].at(i);
  2017     }
  2541     }
  2018 
  2542 
  2019     QList<QSimplexConstraint *> trunkConstraints;
  2543     QList<QSimplexConstraint *> trunkConstraints;
  2020     QSet<QSimplexVariable *> trunkVariables;
  2544     QSet<QSimplexVariable *> trunkVariables;
  2021 
  2545 
  2108 {
  2632 {
  2109     Q_Q(QGraphicsAnchorLayout);
  2633     Q_Q(QGraphicsAnchorLayout);
  2110 
  2634 
  2111     switch(ad->type) {
  2635     switch(ad->type) {
  2112     case AnchorData::Normal:
  2636     case AnchorData::Normal:
  2113         if (ad->from->m_item == ad->to->m_item && ad->to->m_item != q)
  2637         if (ad->item && ad->item != q)
  2114             nonFloatingItemsIdentifiedSoFar->insert(ad->to->m_item);
  2638             nonFloatingItemsIdentifiedSoFar->insert(ad->item);
  2115         break;
  2639         break;
  2116     case AnchorData::Sequential:
  2640     case AnchorData::Sequential:
  2117         foreach (const AnchorData *d, static_cast<const SequentialAnchorData *>(ad)->m_edges)
  2641         foreach (const AnchorData *d, static_cast<const SequentialAnchorData *>(ad)->m_edges)
  2118             identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar);
  2642             identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar);
  2119         break;
  2643         break;
  2193 {
  2717 {
  2194     QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;
  2718     QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;
  2195     QSet<AnchorVertex *> visited;
  2719     QSet<AnchorVertex *> visited;
  2196 
  2720 
  2197     // Get root vertex
  2721     // Get root vertex
  2198     AnchorVertex *root = graph[orientation].rootVertex();
  2722     AnchorVertex *root = layoutFirstVertex[orientation];
  2199 
  2723 
  2200     root->distance = 0;
  2724     root->distance = 0;
  2201     visited.insert(root);
  2725     visited.insert(root);
  2202 
  2726 
  2203     // Add initial edges to the queue
  2727     // Add initial edges to the queue
  2206     }
  2730     }
  2207 
  2731 
  2208     // Do initial calculation required by "interpolateEdge()"
  2732     // Do initial calculation required by "interpolateEdge()"
  2209     setupEdgesInterpolation(orientation);
  2733     setupEdgesInterpolation(orientation);
  2210 
  2734 
  2211     // Traverse the graph and calculate vertex positions, we need to
  2735     // Traverse the graph and calculate vertex positions
  2212     // visit all pairs since each of them could have a sequential
       
  2213     // anchor inside, which hides more vertices.
       
  2214     while (!queue.isEmpty()) {
  2736     while (!queue.isEmpty()) {
  2215         QPair<AnchorVertex *, AnchorVertex *> pair = queue.dequeue();
  2737         QPair<AnchorVertex *, AnchorVertex *> pair = queue.dequeue();
  2216         AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second);
  2738         AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second);
  2217 
  2739 
  2218         // Both vertices were interpolated, and the anchor itself can't have other
  2740         if (visited.contains(pair.second))
  2219         // anchors inside (it's not a complex anchor).
       
  2220         if (edge->type == AnchorData::Normal && visited.contains(pair.second))
       
  2221             continue;
  2741             continue;
  2222 
  2742 
  2223         visited.insert(pair.second);
  2743         visited.insert(pair.second);
  2224         interpolateEdge(pair.first, edge, orientation);
  2744         interpolateEdge(pair.first, edge);
  2225 
  2745 
  2226         QList<AnchorVertex *> adjacents = graph[orientation].adjacentVertices(pair.second);
  2746         QList<AnchorVertex *> adjacents = graph[orientation].adjacentVertices(pair.second);
  2227         for (int i = 0; i < adjacents.count(); ++i) {
  2747         for (int i = 0; i < adjacents.count(); ++i) {
  2228             if (!visited.contains(adjacents.at(i)))
  2748             if (!visited.contains(adjacents.at(i)))
  2229                 queue.enqueue(qMakePair(pair.second, adjacents.at(i)));
  2749                 queue.enqueue(qMakePair(pair.second, adjacents.at(i)));
  2248 
  2768 
  2249     QPair<Interval, qreal> result;
  2769     QPair<Interval, qreal> result;
  2250     result = getFactor(current,
  2770     result = getFactor(current,
  2251                        sizeHints[orientation][Qt::MinimumSize],
  2771                        sizeHints[orientation][Qt::MinimumSize],
  2252                        sizeHints[orientation][Qt::PreferredSize],
  2772                        sizeHints[orientation][Qt::PreferredSize],
  2253                        sizeAtExpanding[orientation],
  2773                        sizeHints[orientation][Qt::PreferredSize],
       
  2774                        sizeHints[orientation][Qt::PreferredSize],
  2254                        sizeHints[orientation][Qt::MaximumSize]);
  2775                        sizeHints[orientation][Qt::MaximumSize]);
  2255 
  2776 
  2256     interpolationInterval[orientation] = result.first;
  2777     interpolationInterval[orientation] = result.first;
  2257     interpolationProgress[orientation] = result.second;
  2778     interpolationProgress[orientation] = result.second;
  2258 }
  2779 }
  2259 
  2780 
  2260 /*!
  2781 /*!
  2261   \internal
  2782     \internal
  2262 
  2783 
  2263   Calculate the current Edge size based on the current Layout size and the
  2784     Calculate the current Edge size based on the current Layout size and the
  2264   size the edge is supposed to have when the layout is at its:
  2785     size the edge is supposed to have when the layout is at its:
  2265 
  2786 
  2266    - minimum size,
  2787     - minimum size,
  2267    - preferred size,
  2788     - preferred size,
  2268    - size when all expanding anchors are expanded,
  2789     - maximum size.
  2269    - maximum size.
  2790 
  2270 
  2791     These three key values are calculated in advance using linear
  2271    These three key values are calculated in advance using linear
  2792     programming (more expensive) or the simplification algorithm, then
  2272    programming (more expensive) or the simplification algorithm, then
  2793     subsequential resizes of the parent layout require a simple
  2273    subsequential resizes of the parent layout require a simple
  2794     interpolation.
  2274    interpolation.
  2795 */
  2275 
  2796 void QGraphicsAnchorLayoutPrivate::interpolateEdge(AnchorVertex *base, AnchorData *edge)
  2276    If the edge is sequential or parallel, it's possible to have more
  2797 {
  2277    vertices to be initalized, so it calls specialized functions that
  2798     const Orientation orientation = Orientation(edge->orientation);
  2278    will recurse back to interpolateEdge().
       
  2279  */
       
  2280 void QGraphicsAnchorLayoutPrivate::interpolateEdge(AnchorVertex *base,
       
  2281                                                    AnchorData *edge,
       
  2282                                                    Orientation orientation)
       
  2283 {
       
  2284     const QPair<Interval, qreal> factor(interpolationInterval[orientation],
  2799     const QPair<Interval, qreal> factor(interpolationInterval[orientation],
  2285                                         interpolationProgress[orientation]);
  2800                                         interpolationProgress[orientation]);
  2286 
  2801 
  2287     qreal edgeDistance = interpolate(factor, edge->sizeAtMinimum, edge->sizeAtPreferred,
  2802     qreal edgeDistance = interpolate(factor, edge->sizeAtMinimum, edge->sizeAtPreferred,
  2288                                      edge->sizeAtExpanding, edge->sizeAtMaximum);
  2803                                      edge->sizeAtPreferred, edge->sizeAtPreferred,
       
  2804                                      edge->sizeAtMaximum);
  2289 
  2805 
  2290     Q_ASSERT(edge->from == base || edge->to == base);
  2806     Q_ASSERT(edge->from == base || edge->to == base);
  2291 
  2807 
  2292     if (edge->from == base)
  2808     // Calculate the distance for the vertex opposite to the base
       
  2809     if (edge->from == base) {
  2293         edge->to->distance = base->distance + edgeDistance;
  2810         edge->to->distance = base->distance + edgeDistance;
  2294     else
  2811     } else {
  2295         edge->from->distance = base->distance - edgeDistance;
  2812         edge->from->distance = base->distance - edgeDistance;
  2296 
  2813     }
  2297     // Process child anchors
       
  2298     if (edge->type == AnchorData::Sequential)
       
  2299         interpolateSequentialEdges(edge->from,
       
  2300                                    static_cast<SequentialAnchorData *>(edge),
       
  2301                                    orientation);
       
  2302     else if (edge->type == AnchorData::Parallel)
       
  2303         interpolateParallelEdges(edge->from,
       
  2304                                  static_cast<ParallelAnchorData *>(edge),
       
  2305                                  orientation);
       
  2306 }
       
  2307 
       
  2308 void QGraphicsAnchorLayoutPrivate::interpolateParallelEdges(
       
  2309     AnchorVertex *base, ParallelAnchorData *data, Orientation orientation)
       
  2310 {
       
  2311     // In parallels the boundary vertices are already calculate, we
       
  2312     // just need to look for sequential groups inside, because only
       
  2313     // them may have new vertices associated.
       
  2314 
       
  2315     // First edge
       
  2316     if (data->firstEdge->type == AnchorData::Sequential)
       
  2317         interpolateSequentialEdges(base,
       
  2318                                    static_cast<SequentialAnchorData *>(data->firstEdge),
       
  2319                                    orientation);
       
  2320     else if (data->firstEdge->type == AnchorData::Parallel)
       
  2321         interpolateParallelEdges(base,
       
  2322                                  static_cast<ParallelAnchorData *>(data->firstEdge),
       
  2323                                  orientation);
       
  2324 
       
  2325     // Second edge
       
  2326     if (data->secondEdge->type == AnchorData::Sequential)
       
  2327         interpolateSequentialEdges(base,
       
  2328                                    static_cast<SequentialAnchorData *>(data->secondEdge),
       
  2329                                    orientation);
       
  2330     else if (data->secondEdge->type == AnchorData::Parallel)
       
  2331         interpolateParallelEdges(base,
       
  2332                                  static_cast<ParallelAnchorData *>(data->secondEdge),
       
  2333                                  orientation);
       
  2334 }
       
  2335 
       
  2336 void QGraphicsAnchorLayoutPrivate::interpolateSequentialEdges(
       
  2337     AnchorVertex *base, SequentialAnchorData *data, Orientation orientation)
       
  2338 {
       
  2339     AnchorVertex *prev = base;
       
  2340 
       
  2341     // ### I'm not sure whether this assumption is safe. If not,
       
  2342     // consider that m_edges.last() could be used instead (so
       
  2343     // at(0) would be the one to be treated specially).
       
  2344     Q_ASSERT(base == data->m_edges.at(0)->to || base == data->m_edges.at(0)->from);
       
  2345 
       
  2346     // Skip the last
       
  2347     for (int i = 0; i < data->m_edges.count() - 1; ++i) {
       
  2348         AnchorData *child = data->m_edges.at(i);
       
  2349         interpolateEdge(prev, child, orientation);
       
  2350         prev = child->to;
       
  2351     }
       
  2352 
       
  2353     // Treat the last specially, since we already calculated it's end
       
  2354     // vertex, so it's only interesting if it's a complex one
       
  2355     if (data->m_edges.last()->type != AnchorData::Normal)
       
  2356         interpolateEdge(prev, data->m_edges.last(), orientation);
       
  2357 }
  2814 }
  2358 
  2815 
  2359 bool QGraphicsAnchorLayoutPrivate::solveMinMax(const QList<QSimplexConstraint *> &constraints,
  2816 bool QGraphicsAnchorLayoutPrivate::solveMinMax(const QList<QSimplexConstraint *> &constraints,
  2360                                                GraphPath path, qreal *min, qreal *max)
  2817                                                GraphPath path, qreal *min, qreal *max)
  2361 {
  2818 {
  2369             objective.variables.insert(*iter, 1.0);
  2826             objective.variables.insert(*iter, 1.0);
  2370 
  2827 
  2371         for (iter = path.negatives.constBegin(); iter != path.negatives.constEnd(); ++iter)
  2828         for (iter = path.negatives.constBegin(); iter != path.negatives.constEnd(); ++iter)
  2372             objective.variables.insert(*iter, -1.0);
  2829             objective.variables.insert(*iter, -1.0);
  2373 
  2830 
       
  2831         const qreal objectiveOffset = (path.positives.count() - path.negatives.count()) * g_offset;
  2374         simplex.setObjective(&objective);
  2832         simplex.setObjective(&objective);
  2375 
  2833 
  2376         // Calculate minimum values
  2834         // Calculate minimum values
  2377         *min = simplex.solveMin();
  2835         *min = simplex.solveMin() - objectiveOffset;
  2378 
  2836 
  2379         // Save sizeAtMinimum results
  2837         // Save sizeAtMinimum results
  2380         QList<QSimplexVariable *> variables = simplex.constraintsVariables();
  2838         QList<AnchorData *> variables = getVariables(constraints);
  2381         for (int i = 0; i < variables.size(); ++i) {
  2839         for (int i = 0; i < variables.size(); ++i) {
  2382             AnchorData *ad = static_cast<AnchorData *>(variables[i]);
  2840             AnchorData *ad = static_cast<AnchorData *>(variables.at(i));
  2383             Q_ASSERT(ad->result >= ad->minSize || qFuzzyCompare(ad->result, ad->minSize));
  2841             ad->sizeAtMinimum = ad->result - g_offset;
  2384             ad->sizeAtMinimum = ad->result;
       
  2385         }
  2842         }
  2386 
  2843 
  2387         // Calculate maximum values
  2844         // Calculate maximum values
  2388         *max = simplex.solveMax();
  2845         *max = simplex.solveMax() - objectiveOffset;
  2389 
  2846 
  2390         // Save sizeAtMaximum results
  2847         // Save sizeAtMaximum results
  2391         for (int i = 0; i < variables.size(); ++i) {
  2848         for (int i = 0; i < variables.size(); ++i) {
  2392             AnchorData *ad = static_cast<AnchorData *>(variables[i]);
  2849             AnchorData *ad = static_cast<AnchorData *>(variables.at(i));
  2393             Q_ASSERT(ad->result <= ad->maxSize || qFuzzyCompare(ad->result, ad->maxSize));
  2850             ad->sizeAtMaximum = ad->result - g_offset;
  2394             ad->sizeAtMaximum = ad->result;
       
  2395         }
  2851         }
  2396     }
  2852     }
  2397     return feasible;
  2853     return feasible;
       
  2854 }
       
  2855 
       
  2856 enum slackType { Grower = -1, Shrinker = 1 };
       
  2857 static QPair<QSimplexVariable *, QSimplexConstraint *> createSlack(QSimplexConstraint *sizeConstraint,
       
  2858                                                                    qreal interval, slackType type)
       
  2859 {
       
  2860     QSimplexVariable *slack = new QSimplexVariable;
       
  2861     sizeConstraint->variables.insert(slack, type);
       
  2862 
       
  2863     QSimplexConstraint *limit = new QSimplexConstraint;
       
  2864     limit->variables.insert(slack, 1.0);
       
  2865     limit->ratio = QSimplexConstraint::LessOrEqual;
       
  2866     limit->constant = interval;
       
  2867 
       
  2868     return qMakePair(slack, limit);
  2398 }
  2869 }
  2399 
  2870 
  2400 bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint *> &constraints,
  2871 bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint *> &constraints,
  2401                                                   const QList<AnchorData *> &variables)
  2872                                                   const QList<AnchorData *> &variables)
  2402 {
  2873 {
  2405     QSimplexConstraint objective;
  2876     QSimplexConstraint objective;
  2406 
  2877 
  2407     // Fill the objective coefficients for this variable. In the
  2878     // Fill the objective coefficients for this variable. In the
  2408     // end the objective function will be
  2879     // end the objective function will be
  2409     //
  2880     //
  2410     //     z = n * (A_shrink + B_shrink + ...) + (A_grower + B_grower + ...)
  2881     //     z = n * (A_shrinker_hard + A_grower_hard + B_shrinker_hard + B_grower_hard + ...) +
       
  2882     //             (A_shrinker_soft + A_grower_soft + B_shrinker_soft + B_grower_soft + ...)
  2411     //
  2883     //
  2412     // where n is the number of variables that have
  2884     // where n is the number of variables that have
  2413     // slacks. Note that here we use the number of variables
  2885     // slacks. Note that here we use the number of variables
  2414     // as coefficient, this is to mark the "shrinker slack
  2886     // as coefficient, this is to mark the "shrinker slack
  2415     // variable" less likely to get value than the "grower
  2887     // variable" less likely to get value than the "grower
  2417 
  2889 
  2418     // This will fill the values for the structural constraints
  2890     // This will fill the values for the structural constraints
  2419     // and we now fill the values for the slack constraints (one per variable),
  2891     // and we now fill the values for the slack constraints (one per variable),
  2420     // which have this form (the constant A_pref was set when creating the slacks):
  2892     // which have this form (the constant A_pref was set when creating the slacks):
  2421     //
  2893     //
  2422     //      A + A_shrinker - A_grower = A_pref
  2894     //      A + A_shrinker_hard + A_shrinker_soft - A_grower_hard - A_grower_soft = A_pref
  2423     //
  2895     //
  2424     for (int i = 0; i < variables.size(); ++i) {
  2896     for (int i = 0; i < variables.size(); ++i) {
  2425         AnchorData *ad = variables[i];
  2897         AnchorData *ad = variables.at(i);
  2426         if (ad->skipInPreferred)
  2898 
       
  2899         // The layout original structure anchors are not relevant in preferred size calculation
       
  2900         if (ad->isLayoutAnchor)
  2427             continue;
  2901             continue;
  2428 
  2902 
  2429         QSimplexVariable *grower = new QSimplexVariable;
  2903         // By default, all variables are equal to their preferred size. If they have room to
  2430         QSimplexVariable *shrinker = new QSimplexVariable;
  2904         // grow or shrink, such flexibility will be added by the additional variables below.
  2431         QSimplexConstraint *c = new QSimplexConstraint;
  2905         QSimplexConstraint *sizeConstraint = new QSimplexConstraint;
  2432         c->variables.insert(ad, 1.0);
  2906         preferredConstraints += sizeConstraint;
  2433         c->variables.insert(shrinker, 1.0);
  2907         sizeConstraint->variables.insert(ad, 1.0);
  2434         c->variables.insert(grower, -1.0);
  2908         sizeConstraint->constant = ad->prefSize + g_offset;
  2435         c->constant = ad->prefSize;
  2909 
  2436 
  2910         // Can easily shrink
  2437         preferredConstraints += c;
  2911         QPair<QSimplexVariable *, QSimplexConstraint *> slack;
  2438         preferredVariables += grower;
  2912         const qreal softShrinkInterval = ad->prefSize - ad->minPrefSize;
  2439         preferredVariables += shrinker;
  2913         if (softShrinkInterval) {
  2440 
  2914             slack = createSlack(sizeConstraint, softShrinkInterval, Shrinker);
  2441         objective.variables.insert(grower, 1.0);
  2915             preferredVariables += slack.first;
  2442         objective.variables.insert(shrinker, variables.size());
  2916             preferredConstraints += slack.second;
  2443     }
  2917 
  2444 
  2918             // Add to objective with ratio == 1 (soft)
       
  2919             objective.variables.insert(slack.first, 1.0);
       
  2920         }
       
  2921 
       
  2922         // Can easily grow
       
  2923         const qreal softGrowInterval = ad->maxPrefSize - ad->prefSize;
       
  2924         if (softGrowInterval) {
       
  2925             slack = createSlack(sizeConstraint, softGrowInterval, Grower);
       
  2926             preferredVariables += slack.first;
       
  2927             preferredConstraints += slack.second;
       
  2928 
       
  2929             // Add to objective with ratio == 1 (soft)
       
  2930             objective.variables.insert(slack.first, 1.0);
       
  2931         }
       
  2932 
       
  2933         // Can shrink if really necessary
       
  2934         const qreal hardShrinkInterval = ad->minPrefSize - ad->minSize;
       
  2935         if (hardShrinkInterval) {
       
  2936             slack = createSlack(sizeConstraint, hardShrinkInterval, Shrinker);
       
  2937             preferredVariables += slack.first;
       
  2938             preferredConstraints += slack.second;
       
  2939 
       
  2940             // Add to objective with ratio == N (hard)
       
  2941             objective.variables.insert(slack.first, variables.size());
       
  2942         }
       
  2943 
       
  2944         // Can grow if really necessary
       
  2945         const qreal hardGrowInterval = ad->maxSize - ad->maxPrefSize;
       
  2946         if (hardGrowInterval) {
       
  2947             slack = createSlack(sizeConstraint, hardGrowInterval, Grower);
       
  2948             preferredVariables += slack.first;
       
  2949             preferredConstraints += slack.second;
       
  2950 
       
  2951             // Add to objective with ratio == N (hard)
       
  2952             objective.variables.insert(slack.first, variables.size());
       
  2953         }
       
  2954     }
  2445 
  2955 
  2446     QSimplex *simplex = new QSimplex;
  2956     QSimplex *simplex = new QSimplex;
  2447     bool feasible = simplex->setConstraints(constraints + preferredConstraints);
  2957     bool feasible = simplex->setConstraints(constraints + preferredConstraints);
  2448     if (feasible) {
  2958     if (feasible) {
  2449         simplex->setObjective(&objective);
  2959         simplex->setObjective(&objective);
  2451         // Calculate minimum values
  2961         // Calculate minimum values
  2452         simplex->solveMin();
  2962         simplex->solveMin();
  2453 
  2963 
  2454         // Save sizeAtPreferred results
  2964         // Save sizeAtPreferred results
  2455         for (int i = 0; i < variables.size(); ++i) {
  2965         for (int i = 0; i < variables.size(); ++i) {
  2456             AnchorData *ad = variables[i];
  2966             AnchorData *ad = variables.at(i);
  2457             ad->sizeAtPreferred = ad->result;
  2967             ad->sizeAtPreferred = ad->result - g_offset;
  2458         }
  2968         }
  2459 
  2969 
  2460         // Make sure we delete the simplex solver -before- we delete the
  2970         // Make sure we delete the simplex solver -before- we delete the
  2461         // constraints used by it.
  2971         // constraints used by it.
  2462         delete simplex;
  2972         delete simplex;
  2464     // Delete constraints and variables we created.
  2974     // Delete constraints and variables we created.
  2465     qDeleteAll(preferredConstraints);
  2975     qDeleteAll(preferredConstraints);
  2466     qDeleteAll(preferredVariables);
  2976     qDeleteAll(preferredVariables);
  2467 
  2977 
  2468     return feasible;
  2978     return feasible;
  2469 }
       
  2470 
       
  2471 /*!
       
  2472     \internal
       
  2473     Calculate the "expanding" keyframe
       
  2474 
       
  2475     This new keyframe sits between the already existing sizeAtPreferred and
       
  2476     sizeAtMaximum keyframes. Its goal is to modify the interpolation between
       
  2477     the latter as to respect the "expanding" size policy of some anchors.
       
  2478 
       
  2479     Previously all items would be subject to a linear interpolation between
       
  2480     sizeAtPreferred and sizeAtMaximum values. This will change now, the
       
  2481     expanding anchors will change their size before the others. To calculate
       
  2482     this keyframe we use the following logic:
       
  2483 
       
  2484     1) Ask each anchor for their desired expanding size (ad->expSize), this
       
  2485     value depends on the anchor expanding property in the following way:
       
  2486 
       
  2487     - Expanding normal anchors want to grow towards their maximum size
       
  2488     - Non-expanding normal anchors want to remain at their preferred size.
       
  2489     - Sequential anchors wants to grow towards a size that is calculated by:
       
  2490         summarizing it's child anchors, where it will use preferred size for non-expanding anchors
       
  2491         and maximum size for expanding anchors.
       
  2492     - Parallel anchors want to grow towards the smallest maximum size of all the expanding anchors.
       
  2493 
       
  2494     2) Clamp their desired values to the value they assume in the neighbour
       
  2495     keyframes (sizeAtPreferred and sizeAtExpanding)
       
  2496 
       
  2497     3) Run simplex with a setup that ensures the following:
       
  2498 
       
  2499       a. Anchors will change their value from their sizeAtPreferred towards
       
  2500          their sizeAtMaximum as much as required to ensure that ALL anchors
       
  2501          reach their respective "desired" expanding sizes.
       
  2502 
       
  2503       b. No anchors will change their value beyond what is NEEDED to satisfy
       
  2504          the requirement above.
       
  2505 
       
  2506     The final result is that, at the "expanding" keyframe expanding anchors
       
  2507     will grow and take with them all anchors that are parallel to them.
       
  2508     However, non-expanding anchors will remain at their preferred size unless
       
  2509     they are forced to grow by a parallel expanding anchor.
       
  2510 
       
  2511     Note: For anchors where the sizeAtPreferred is bigger than sizeAtMaximum,
       
  2512           the visual effect when the layout grows from its preferred size is
       
  2513           the following: Expanding anchors will keep their size while non
       
  2514           expanding ones will shrink. Only after non-expanding anchors have
       
  2515           shrinked all the way, the expanding anchors will start to shrink too.
       
  2516 */
       
  2517 void QGraphicsAnchorLayoutPrivate::solveExpanding(const QList<QSimplexConstraint *> &constraints,
       
  2518                                                   const QList<AnchorData *> &variables)
       
  2519 {
       
  2520     QList<QSimplexConstraint *> itemConstraints;
       
  2521     QSimplexConstraint *objective = new QSimplexConstraint;
       
  2522     bool hasExpanding = false;
       
  2523 
       
  2524     // Construct the simplex constraints and objective
       
  2525     for (int i = 0; i < variables.size(); ++i) {
       
  2526         // For each anchor
       
  2527         AnchorData *ad = variables[i];
       
  2528 
       
  2529         // Clamp the desired expanding size
       
  2530         qreal upperBoundary = qMax(ad->sizeAtPreferred, ad->sizeAtMaximum);
       
  2531         qreal lowerBoundary = qMin(ad->sizeAtPreferred, ad->sizeAtMaximum);
       
  2532         qreal boundedExpSize = qBound(lowerBoundary, ad->expSize, upperBoundary);
       
  2533 
       
  2534         // Expanding anchors are those that want to move from their preferred size
       
  2535         if (boundedExpSize != ad->sizeAtPreferred)
       
  2536             hasExpanding = true;
       
  2537 
       
  2538         // Lock anchor between boundedExpSize and sizeAtMaximum (ensure 3.a)
       
  2539         if (boundedExpSize == ad->sizeAtMaximum) {
       
  2540             // The interval has only one possible value, we can use an "Equal"
       
  2541             // constraint and don't need to add this variable to the objective.
       
  2542             QSimplexConstraint *itemC = new QSimplexConstraint;
       
  2543             itemC->ratio = QSimplexConstraint::Equal;
       
  2544             itemC->variables.insert(ad, 1.0);
       
  2545             itemC->constant = boundedExpSize;
       
  2546             itemConstraints << itemC;
       
  2547         } else {
       
  2548             // Add MoreOrEqual and LessOrEqual constraints.
       
  2549             QSimplexConstraint *itemC = new QSimplexConstraint;
       
  2550             itemC->ratio = QSimplexConstraint::MoreOrEqual;
       
  2551             itemC->variables.insert(ad, 1.0);
       
  2552             itemC->constant = qMin(boundedExpSize, ad->sizeAtMaximum);
       
  2553             itemConstraints << itemC;
       
  2554 
       
  2555             itemC = new QSimplexConstraint;
       
  2556             itemC->ratio = QSimplexConstraint::LessOrEqual;
       
  2557             itemC->variables.insert(ad, 1.0);
       
  2558             itemC->constant = qMax(boundedExpSize, ad->sizeAtMaximum);
       
  2559             itemConstraints << itemC;
       
  2560 
       
  2561             // Create objective to avoid the anchors from moving away from
       
  2562             // the preferred size more than the needed amount. (ensure 3.b)
       
  2563             // The objective function is the distance between sizeAtPreferred
       
  2564             // and sizeAtExpanding, it will be minimized.
       
  2565             if (ad->sizeAtExpanding < ad->sizeAtMaximum) {
       
  2566                 // Try to shrink this variable towards its sizeAtPreferred value
       
  2567                 objective->variables.insert(ad, 1.0);
       
  2568             } else {
       
  2569                 // Try to grow this variable towards its sizeAtPreferred value
       
  2570                 objective->variables.insert(ad, -1.0);
       
  2571             }
       
  2572         }
       
  2573     }
       
  2574 
       
  2575     // Solve
       
  2576     if (hasExpanding == false) {
       
  2577         // If no anchors are expanding, we don't need to run the simplex
       
  2578         // Set all variables to their preferred size
       
  2579         for (int i = 0; i < variables.size(); ++i) {
       
  2580             variables[i]->sizeAtExpanding = variables[i]->sizeAtPreferred;
       
  2581         }
       
  2582     } else {
       
  2583         // Run simplex
       
  2584         QSimplex simplex;
       
  2585 
       
  2586         // Satisfy expanding (3.a)
       
  2587         bool feasible = simplex.setConstraints(constraints + itemConstraints);
       
  2588         Q_ASSERT(feasible);
       
  2589 
       
  2590         // Reduce damage (3.b)
       
  2591         simplex.setObjective(objective);
       
  2592         simplex.solveMin();
       
  2593 
       
  2594         // Collect results
       
  2595         for (int i = 0; i < variables.size(); ++i) {
       
  2596             variables[i]->sizeAtExpanding = variables[i]->result;
       
  2597         }
       
  2598     }
       
  2599 
       
  2600     delete objective;
       
  2601     qDeleteAll(itemConstraints);
       
  2602 }
  2979 }
  2603 
  2980 
  2604 /*!
  2981 /*!
  2605     \internal
  2982     \internal
  2606     Returns true if there are no arrangement that satisfies all constraints.
  2983     Returns true if there are no arrangement that satisfies all constraints.
  2633     file.close();
  3010     file.close();
  2634 }
  3011 }
  2635 #endif
  3012 #endif
  2636 
  3013 
  2637 QT_END_NAMESPACE
  3014 QT_END_NAMESPACE
       
  3015 #endif //QT_NO_GRAPHICSVIEW