src/gui/graphicsview/qgraphicsanchorlayout_p.h
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #ifndef QGRAPHICSANCHORLAYOUT_P_H
       
    43 #define QGRAPHICSANCHORLAYOUT_P_H
       
    44 
       
    45 //
       
    46 //  W A R N I N G
       
    47 //  -------------
       
    48 //
       
    49 // This file is not part of the Qt API.  It exists purely as an
       
    50 // implementation detail.  This header file may change from version to
       
    51 // version without notice, or even be removed.
       
    52 //
       
    53 // We mean it.
       
    54 //
       
    55 
       
    56 #include <QGraphicsWidget>
       
    57 #include <private/qobject_p.h>
       
    58 
       
    59 #include "qgraphicslayout_p.h"
       
    60 #include "qgraphicsanchorlayout.h"
       
    61 #include "qgraph_p.h"
       
    62 #include "qsimplex_p.h"
       
    63 
       
    64 QT_BEGIN_NAMESPACE
       
    65 
       
    66 /*
       
    67   The public QGraphicsAnchorLayout interface represents an anchorage point
       
    68   as a pair of a <QGraphicsLayoutItem *> and a <Qt::AnchorPoint>.
       
    69 
       
    70   Internally though, it has a graph of anchorage points (vertices) and
       
    71   anchors (edges), represented by the AnchorVertex and AnchorData structs
       
    72   respectively.
       
    73 */
       
    74 
       
    75 /*!
       
    76   \internal
       
    77 
       
    78   Represents a vertex (anchorage point) in the internal graph
       
    79 */
       
    80 struct AnchorVertex {
       
    81     AnchorVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge)
       
    82         : m_item(item), m_edge(edge) {}
       
    83 
       
    84     AnchorVertex()
       
    85         : m_item(0), m_edge(Qt::AnchorPoint(0)) {}
       
    86 
       
    87 #ifdef QT_DEBUG
       
    88     inline QString toString() const;
       
    89 #endif
       
    90     QGraphicsLayoutItem *m_item;
       
    91     Qt::AnchorPoint m_edge;
       
    92 
       
    93     // Current distance from this vertex to the layout edge (Left or Top)
       
    94     // Value is calculated from the current anchors sizes.
       
    95     qreal distance;
       
    96 };
       
    97 
       
    98 #ifdef QT_DEBUG
       
    99 inline QString AnchorVertex::toString() const
       
   100 {
       
   101     if (!this || !m_item) {
       
   102         return QLatin1String("NULL");
       
   103     }
       
   104     QString edge;
       
   105     switch (m_edge) {
       
   106     case Qt::AnchorLeft:
       
   107         edge = QLatin1String("Left");
       
   108         break;
       
   109     case Qt::AnchorHorizontalCenter:
       
   110         edge = QLatin1String("HorizontalCenter");
       
   111         break;
       
   112     case Qt::AnchorRight:
       
   113         edge = QLatin1String("Right");
       
   114         break;
       
   115     case Qt::AnchorTop:
       
   116         edge = QLatin1String("Top");
       
   117         break;
       
   118     case Qt::AnchorVerticalCenter:
       
   119         edge = QLatin1String("VerticalCenter");
       
   120         break;
       
   121     case Qt::AnchorBottom:
       
   122         edge = QLatin1String("Bottom");
       
   123         break;
       
   124     default:
       
   125         edge = QLatin1String("None");
       
   126         break;
       
   127     }
       
   128     QString itemName;
       
   129     if (m_item->isLayout()) {
       
   130         itemName = QLatin1String("layout");
       
   131     } else {
       
   132         if (QGraphicsItem *item = m_item->graphicsItem()) {
       
   133             itemName = item->data(0).toString();
       
   134         }
       
   135     }
       
   136     edge.insert(0, QLatin1String("%1_"));
       
   137     return edge.arg(itemName);
       
   138 }
       
   139 #endif
       
   140 
       
   141 /*!
       
   142   \internal
       
   143 
       
   144   Represents an edge (anchor) in the internal graph.
       
   145 */
       
   146 struct AnchorData : public QSimplexVariable {
       
   147     enum Type {
       
   148         Normal = 0,
       
   149         Sequential,
       
   150         Parallel
       
   151     };
       
   152 
       
   153     AnchorData()
       
   154         : QSimplexVariable(), from(0), to(0),
       
   155           minSize(0), prefSize(0), expSize(0), maxSize(0),
       
   156           sizeAtMinimum(0), sizeAtPreferred(0),
       
   157           sizeAtExpanding(0), sizeAtMaximum(0),
       
   158           graphicsAnchor(0), skipInPreferred(0),
       
   159           type(Normal), hasSize(true), isLayoutAnchor(false) {}
       
   160 
       
   161     virtual void updateChildrenSizes() {}
       
   162     virtual void refreshSizeHints(qreal effectiveSpacing);
       
   163 
       
   164     virtual ~AnchorData() {}
       
   165 
       
   166 #ifdef QT_DEBUG
       
   167     void dump(int indent = 2);
       
   168     inline QString toString() const;
       
   169     QString name;
       
   170 #endif
       
   171 
       
   172     inline void setPreferredSize(qreal size)
       
   173     {
       
   174         prefSize = size;
       
   175         hasSize = true;
       
   176     }
       
   177 
       
   178     inline void unsetSize()
       
   179     {
       
   180         hasSize = false;
       
   181     }
       
   182 
       
   183     // Anchor is semantically directed
       
   184     AnchorVertex *from;
       
   185     AnchorVertex *to;
       
   186 
       
   187     // Size restrictions of this edge. For anchors internal to items, these
       
   188     // values are derived from the respective item size hints. For anchors
       
   189     // that were added by users, these values are equal to the specified anchor
       
   190     // size.
       
   191     qreal minSize;
       
   192     qreal prefSize;
       
   193     qreal expSize;
       
   194     qreal maxSize;
       
   195 
       
   196     // These attributes define which sizes should that anchor be in when the
       
   197     // layout is at its minimum, preferred or maximum sizes. Values are
       
   198     // calculated by the Simplex solver based on the current layout setup.
       
   199     qreal sizeAtMinimum;
       
   200     qreal sizeAtPreferred;
       
   201     qreal sizeAtExpanding;
       
   202     qreal sizeAtMaximum;
       
   203     QGraphicsAnchor *graphicsAnchor;
       
   204 
       
   205     uint skipInPreferred : 1;
       
   206     uint type : 2;            // either Normal, Sequential or Parallel
       
   207     uint hasSize : 1;         // if false, get size from style.
       
   208     uint isLayoutAnchor : 1;  // if this anchor is connected to a layout 'edge'
       
   209 };
       
   210 
       
   211 #ifdef QT_DEBUG
       
   212 inline QString AnchorData::toString() const
       
   213 {
       
   214     return QString::fromAscii("Anchor(%1)").arg(name);
       
   215 }
       
   216 #endif
       
   217 
       
   218 struct SequentialAnchorData : public AnchorData
       
   219 {
       
   220     SequentialAnchorData() : AnchorData()
       
   221     {
       
   222         type = AnchorData::Sequential;
       
   223 #ifdef QT_DEBUG
       
   224         name = QLatin1String("SequentialAnchorData");
       
   225 #endif
       
   226     }
       
   227 
       
   228     virtual void updateChildrenSizes();
       
   229     virtual void refreshSizeHints(qreal effectiveSpacing);
       
   230 
       
   231     void refreshSizeHints_helper(qreal effectiveSpacing, bool refreshChildren = true);
       
   232 
       
   233     void setVertices(const QVector<AnchorVertex*> &vertices)
       
   234     {
       
   235         m_children = vertices;
       
   236 #ifdef QT_DEBUG
       
   237         name = QString::fromAscii("%1 -- %2").arg(vertices.first()->toString(), vertices.last()->toString());
       
   238 #endif
       
   239     }
       
   240 
       
   241     QVector<AnchorVertex*> m_children;          // list of vertices in the sequence
       
   242     QVector<AnchorData*> m_edges;               // keep the list of edges too.
       
   243 };
       
   244 
       
   245 struct ParallelAnchorData : public AnchorData
       
   246 {
       
   247     ParallelAnchorData(AnchorData *first, AnchorData *second)
       
   248         : AnchorData(), firstEdge(first), secondEdge(second)
       
   249     {
       
   250         type = AnchorData::Parallel;
       
   251 
       
   252         // ### Those asserts force that both child anchors have the same direction,
       
   253         // but can't we simplify a pair of anchors in opposite directions?
       
   254         Q_ASSERT(first->from == second->from);
       
   255         Q_ASSERT(first->to == second->to);
       
   256         from = first->from;
       
   257         to = first->to;
       
   258 #ifdef QT_DEBUG
       
   259         name = QString::fromAscii("%1 | %2").arg(first->toString(), second->toString());
       
   260 #endif
       
   261     }
       
   262 
       
   263     virtual void updateChildrenSizes();
       
   264     virtual void refreshSizeHints(qreal effectiveSpacing);
       
   265 
       
   266     void refreshSizeHints_helper(qreal effectiveSpacing, bool refreshChildren = true);
       
   267 
       
   268     AnchorData* firstEdge;
       
   269     AnchorData* secondEdge;
       
   270 };
       
   271 
       
   272 /*!
       
   273   \internal
       
   274 
       
   275   Representation of a valid path for a given vertex in the graph.
       
   276   In this struct, "positives" is the set of anchors that have been
       
   277   traversed in the forward direction, while "negatives" is the set
       
   278   with the ones walked backwards.
       
   279 
       
   280   This paths are compared against each other to produce LP Constraints,
       
   281   the exact order in which the anchors were traversed is not relevant.
       
   282 */
       
   283 class GraphPath
       
   284 {
       
   285 public:
       
   286     GraphPath() {}
       
   287 
       
   288     QSimplexConstraint *constraint(const GraphPath &path) const;
       
   289 #ifdef QT_DEBUG
       
   290     QString toString() const;
       
   291 #endif
       
   292     QSet<AnchorData *> positives;
       
   293     QSet<AnchorData *> negatives;
       
   294 };
       
   295 
       
   296 class QGraphicsAnchorLayoutPrivate;
       
   297 /*!
       
   298     \internal
       
   299 */
       
   300 class QGraphicsAnchorPrivate : public QObjectPrivate
       
   301 {
       
   302     Q_DECLARE_PUBLIC(QGraphicsAnchor)
       
   303 
       
   304 public:
       
   305     explicit QGraphicsAnchorPrivate(int version = QObjectPrivateVersion);
       
   306     ~QGraphicsAnchorPrivate();
       
   307 
       
   308     void setSpacing(qreal value);
       
   309     void unsetSpacing();
       
   310     qreal spacing() const;
       
   311 
       
   312     void setSizePolicy(QSizePolicy::Policy policy);
       
   313 
       
   314     QGraphicsAnchorLayoutPrivate *layoutPrivate;
       
   315     AnchorData *data;
       
   316     QSizePolicy::Policy sizePolicy;
       
   317 };
       
   318 
       
   319 
       
   320 
       
   321 
       
   322 /*!
       
   323   \internal
       
   324 
       
   325   QGraphicsAnchorLayout private methods and attributes.
       
   326 */
       
   327 class Q_AUTOTEST_EXPORT QGraphicsAnchorLayoutPrivate : public QGraphicsLayoutPrivate
       
   328 {
       
   329     Q_DECLARE_PUBLIC(QGraphicsAnchorLayout)
       
   330 
       
   331 public:
       
   332     // When the layout geometry is different from its Minimum, Preferred
       
   333     // or Maximum values, interpolation is used to calculate the geometries
       
   334     // of the items.
       
   335     //
       
   336     // Interval represents which interpolation interval are we operating in.
       
   337     enum Interval {
       
   338         MinToPreferred = 0,
       
   339         PreferredToExpanding,
       
   340         ExpandingToMax
       
   341     };
       
   342 
       
   343     // Several structures internal to the layout are duplicated to handle
       
   344     // both Horizontal and Vertical restrictions.
       
   345     //
       
   346     // Orientation is used to reference the right structure in each context
       
   347     enum Orientation {
       
   348         Horizontal = 0,
       
   349         Vertical,
       
   350         NOrientations
       
   351     };
       
   352 
       
   353     QGraphicsAnchorLayoutPrivate();
       
   354 
       
   355     static QGraphicsAnchorLayoutPrivate *get(QGraphicsAnchorLayout *q)
       
   356     {
       
   357         return q ? q->d_func() : 0;
       
   358     }
       
   359 
       
   360     static Qt::AnchorPoint oppositeEdge(
       
   361         Qt::AnchorPoint edge);
       
   362 
       
   363     static Orientation edgeOrientation(Qt::AnchorPoint edge);
       
   364 
       
   365     static Qt::AnchorPoint pickEdge(Qt::AnchorPoint edge, Orientation orientation)
       
   366     {
       
   367         if (orientation == Vertical && int(edge) <= 2)
       
   368             return (Qt::AnchorPoint)(edge + 3);
       
   369         else if (orientation == Horizontal && int(edge) >= 3) {
       
   370             return (Qt::AnchorPoint)(edge - 3);
       
   371         }
       
   372         return edge;
       
   373     }
       
   374 
       
   375     // Init methods
       
   376     void createLayoutEdges();
       
   377     void deleteLayoutEdges();
       
   378     void createItemEdges(QGraphicsLayoutItem *item);
       
   379     void createCenterAnchors(QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge);
       
   380     void removeCenterAnchors(QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge, bool substitute = true);
       
   381     void removeCenterConstraints(QGraphicsLayoutItem *item, Orientation orientation);
       
   382 
       
   383     QGraphicsAnchor *acquireGraphicsAnchor(AnchorData *data)
       
   384     {
       
   385         Q_Q(QGraphicsAnchorLayout);
       
   386         if (!data->graphicsAnchor) {
       
   387             data->graphicsAnchor = new QGraphicsAnchor(q);
       
   388             data->graphicsAnchor->d_func()->data = data;
       
   389         }
       
   390         return data->graphicsAnchor;
       
   391     }
       
   392 
       
   393     // function used by the 4 API functions
       
   394     QGraphicsAnchor *addAnchor(QGraphicsLayoutItem *firstItem,
       
   395                             Qt::AnchorPoint firstEdge,
       
   396                             QGraphicsLayoutItem *secondItem,
       
   397                             Qt::AnchorPoint secondEdge,
       
   398                             qreal *spacing = 0);
       
   399 
       
   400     // Helper for Anchor Manipulation methods
       
   401     void addAnchor_helper(QGraphicsLayoutItem *firstItem,
       
   402                    Qt::AnchorPoint firstEdge,
       
   403                    QGraphicsLayoutItem *secondItem,
       
   404                    Qt::AnchorPoint secondEdge,
       
   405                    AnchorData *data);
       
   406 
       
   407     QGraphicsAnchor *getAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge,
       
   408                                QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge);
       
   409 
       
   410     void removeAnchor(AnchorVertex *firstVertex, AnchorVertex *secondVertex);
       
   411     void removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2);
       
   412     void setAnchorSize(AnchorData *data, const qreal *anchorSize);
       
   413     void anchorSize(const AnchorData *data,
       
   414                     qreal *minSize = 0,
       
   415                     qreal *prefSize = 0,
       
   416                     qreal *maxSize = 0) const;
       
   417 
       
   418     void removeAnchors(QGraphicsLayoutItem *item);
       
   419 
       
   420     void removeVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge);
       
   421 
       
   422     void correctEdgeDirection(QGraphicsLayoutItem *&firstItem,
       
   423                               Qt::AnchorPoint &firstEdge,
       
   424                               QGraphicsLayoutItem *&secondItem,
       
   425                               Qt::AnchorPoint &secondEdge);
       
   426     // for getting the actual spacing (will query the style if the
       
   427     // spacing is not explicitly set).
       
   428     qreal effectiveSpacing(Orientation orientation) const;
       
   429 
       
   430     // Activation methods
       
   431     void simplifyGraph(Orientation orientation);
       
   432     bool simplifyGraphIteration(Orientation orientation);
       
   433     void restoreSimplifiedGraph(Orientation orientation);
       
   434 
       
   435     void calculateGraphs();
       
   436     void calculateGraphs(Orientation orientation);
       
   437 
       
   438     bool calculateTrunk(Orientation orientation, const GraphPath &trunkPath,
       
   439                         const QList<QSimplexConstraint *> &constraints,
       
   440                         const QList<AnchorData *> &variables);
       
   441     bool calculateNonTrunk(const QList<QSimplexConstraint *> &constraints,
       
   442                            const QList<AnchorData *> &variables);
       
   443 
       
   444     void setAnchorSizeHintsFromItems(Orientation orientation);
       
   445     void findPaths(Orientation orientation);
       
   446     void constraintsFromPaths(Orientation orientation);
       
   447     void updateAnchorSizes(Orientation orientation);
       
   448     QList<QSimplexConstraint *> constraintsFromSizeHints(const QList<AnchorData *> &anchors);
       
   449     QList<QList<QSimplexConstraint *> > getGraphParts(Orientation orientation);
       
   450     void identifyFloatItems(const QSet<AnchorData *> &visited, Orientation orientation);
       
   451     void identifyNonFloatItems_helper(const AnchorData *ad, QSet<QGraphicsLayoutItem *> *nonFloatingItemsIdentifiedSoFar);
       
   452 
       
   453     inline AnchorVertex *internalVertex(const QPair<QGraphicsLayoutItem*, Qt::AnchorPoint> &itemEdge) const
       
   454     {
       
   455         return m_vertexList.value(itemEdge).first;
       
   456     }
       
   457 
       
   458     inline AnchorVertex *internalVertex(const QGraphicsLayoutItem *item, Qt::AnchorPoint edge) const
       
   459     {
       
   460         return internalVertex(qMakePair(const_cast<QGraphicsLayoutItem *>(item), edge));
       
   461     }
       
   462 
       
   463     AnchorVertex *addInternalVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge);
       
   464     void removeInternalVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge);
       
   465 
       
   466     // Geometry interpolation methods
       
   467     void setItemsGeometries(const QRectF &geom);
       
   468 
       
   469     void calculateVertexPositions(Orientation orientation);
       
   470     void setupEdgesInterpolation(Orientation orientation);
       
   471     void interpolateEdge(AnchorVertex *base, AnchorData *edge, Orientation orientation);
       
   472     void interpolateSequentialEdges(AnchorVertex *base, SequentialAnchorData *edge,
       
   473                                     Orientation orientation);
       
   474     void interpolateParallelEdges(AnchorVertex *base, ParallelAnchorData *edge,
       
   475                                   Orientation orientation);
       
   476 
       
   477     // Linear Programming solver methods
       
   478     bool solveMinMax(const QList<QSimplexConstraint *> &constraints,
       
   479                      GraphPath path, qreal *min, qreal *max);
       
   480     bool solvePreferred(const QList<QSimplexConstraint *> &constraints,
       
   481                         const QList<AnchorData *> &variables);
       
   482     void solveExpanding(const QList<QSimplexConstraint *> &constraints,
       
   483                         const QList<AnchorData *> &variables);
       
   484     bool hasConflicts() const;
       
   485 
       
   486 #ifdef QT_DEBUG
       
   487     void dumpGraph(const QString &name = QString());
       
   488 #endif
       
   489 
       
   490 
       
   491     qreal spacings[NOrientations];
       
   492     // Size hints from simplex engine
       
   493     qreal sizeHints[2][3];
       
   494     qreal sizeAtExpanding[2];
       
   495 
       
   496     // Items
       
   497     QVector<QGraphicsLayoutItem *> items;
       
   498 
       
   499     // Mapping between high level anchorage points (Item, Edge) to low level
       
   500     // ones (Graph Vertices)
       
   501 
       
   502     QHash<QPair<QGraphicsLayoutItem*, Qt::AnchorPoint>, QPair<AnchorVertex *, int> > m_vertexList;
       
   503 
       
   504     // Internal graph of anchorage points and anchors, for both orientations
       
   505     Graph<AnchorVertex, AnchorData> graph[2];
       
   506 
       
   507     // Graph paths and constraints, for both orientations
       
   508     QMultiHash<AnchorVertex *, GraphPath> graphPaths[2];
       
   509     QList<QSimplexConstraint *> constraints[2];
       
   510     QList<QSimplexConstraint *> itemCenterConstraints[2];
       
   511 
       
   512     // The interpolation interval and progress based on the current size
       
   513     // as well as the key values (minimum, preferred and maximum)
       
   514     Interval interpolationInterval[2];
       
   515     qreal interpolationProgress[2];
       
   516 
       
   517     // ###
       
   518     bool graphSimplified[2];
       
   519     bool graphHasConflicts[2];
       
   520     QSet<QGraphicsLayoutItem *> m_floatItems[2];
       
   521 
       
   522 #if defined(QT_DEBUG) || defined(Q_AUTOTEST_EXPORT)
       
   523     bool lastCalculationUsedSimplex[2];
       
   524 #endif
       
   525 
       
   526     uint calculateGraphCacheDirty : 1;
       
   527 
       
   528     friend class QGraphicsAnchorPrivate;
       
   529 };
       
   530 
       
   531 QT_END_NAMESPACE
       
   532 
       
   533 #endif