src/gui/graphicsview/qgraphicsanchorlayout_p.h
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
--- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h	Tue Jan 26 12:42:25 2010 +0200
+++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h	Tue Feb 02 00:43:10 2010 +0200
@@ -60,7 +60,7 @@
 #include "qgraphicsanchorlayout.h"
 #include "qgraph_p.h"
 #include "qsimplex_p.h"
-
+#ifndef QT_NO_GRAPHICSVIEW
 QT_BEGIN_NAMESPACE
 
 /*
@@ -78,28 +78,194 @@
   Represents a vertex (anchorage point) in the internal graph
 */
 struct AnchorVertex {
+    enum Type {
+        Normal = 0,
+        Pair
+    };
+
     AnchorVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge)
-        : m_item(item), m_edge(edge) {}
+        : m_item(item), m_edge(edge), m_type(Normal) {}
 
     AnchorVertex()
-        : m_item(0), m_edge(Qt::AnchorPoint(0)) {}
+        : m_item(0), m_edge(Qt::AnchorPoint(0)), m_type(Normal) {}
 
 #ifdef QT_DEBUG
     inline QString toString() const;
 #endif
+
     QGraphicsLayoutItem *m_item;
     Qt::AnchorPoint m_edge;
+    uint m_type : 1;
 
     // Current distance from this vertex to the layout edge (Left or Top)
     // Value is calculated from the current anchors sizes.
     qreal distance;
 };
 
+/*!
+  \internal
+
+  Represents an edge (anchor) in the internal graph.
+*/
+struct AnchorData : public QSimplexVariable {
+    enum Type {
+        Normal = 0,
+        Sequential,
+        Parallel
+    };
+
+    enum Dependency {
+        Independent = 0,
+        Master,
+        Slave
+    };
+
+    AnchorData()
+        : QSimplexVariable(), from(0), to(0),
+          minSize(0), prefSize(0), maxSize(0),
+          minPrefSize(0), maxPrefSize(0),
+          sizeAtMinimum(0), sizeAtPreferred(0),
+          sizeAtMaximum(0), item(0), graphicsAnchor(0),
+          type(Normal), isLayoutAnchor(false),
+          isCenterAnchor(false), orientation(0),
+          dependency(Independent) {}
+    virtual ~AnchorData();
+
+    virtual void updateChildrenSizes() {}
+    void refreshSizeHints(const QLayoutStyleInfo *styleInfo = 0);
+
+#ifdef QT_DEBUG
+    void dump(int indent = 2);
+    inline QString toString() const;
+    QString name;
+#endif
+
+    // Anchor is semantically directed
+    AnchorVertex *from;
+    AnchorVertex *to;
+
+    // Nominal sizes
+    // These are the intrinsic size restrictions for a given item. They are
+    // used as input for the calculation of the actual sizes.
+    // These values are filled by the refreshSizeHints method, based on the
+    // anchor size policy, the size hints of the item it (possibly) represents
+    // and the layout spacing information.
+    qreal minSize;
+    qreal prefSize;
+    qreal maxSize;
+
+    qreal minPrefSize;
+    qreal maxPrefSize;
+
+    // Calculated sizes
+    // These attributes define which sizes should that anchor be in when the
+    // layout is at its minimum, preferred or maximum sizes. Values are
+    // calculated by the Simplex solver based on the current layout setup.
+    qreal sizeAtMinimum;
+    qreal sizeAtPreferred;
+    qreal sizeAtMaximum;
+
+    // References to the classes that represent this anchor in the public world
+    // An anchor may represent a LayoutItem, it may also be acessible externally
+    // through a GraphicsAnchor "handler".
+    QGraphicsLayoutItem *item;
+    QGraphicsAnchor *graphicsAnchor;
+
+    uint type : 2;            // either Normal, Sequential or Parallel
+    uint isLayoutAnchor : 1;  // if this anchor is an internal layout anchor
+    uint isCenterAnchor : 1;
+    uint orientation : 1;
+    uint dependency : 2;      // either Independent, Master or Slave
+};
+
+#ifdef QT_DEBUG
+inline QString AnchorData::toString() const
+{
+    return QString::fromAscii("Anchor(%1)").arg(name);
+}
+#endif
+
+struct SequentialAnchorData : public AnchorData
+{
+    SequentialAnchorData(const QVector<AnchorVertex *> &vertices, const QVector<AnchorData *> &edges)
+        : AnchorData(), m_children(vertices), m_edges(edges)
+    {
+        type = AnchorData::Sequential;
+        orientation = m_edges.at(0)->orientation;
+#ifdef QT_DEBUG
+        name = QString::fromAscii("%1 -- %2").arg(vertices.first()->toString(), vertices.last()->toString());
+#endif
+    }
+
+    virtual void updateChildrenSizes();
+    void calculateSizeHints();
+
+    QVector<AnchorVertex*> m_children;          // list of vertices in the sequence
+    QVector<AnchorData*> m_edges;               // keep the list of edges too.
+};
+
+struct ParallelAnchorData : public AnchorData
+{
+    ParallelAnchorData(AnchorData *first, AnchorData *second)
+        : AnchorData(), firstEdge(first), secondEdge(second)
+    {
+        type = AnchorData::Parallel;
+        orientation = first->orientation;
+
+        // This assert whether the child anchors share their vertices
+        Q_ASSERT(((first->from == second->from) && (first->to == second->to)) ||
+                 ((first->from == second->to) && (first->to == second->from)));
+
+        // Our convention will be that the parallel group anchor will have the same
+        // direction as the first anchor.
+        from = first->from;
+        to = first->to;
+#ifdef QT_DEBUG
+        name = QString::fromAscii("%1 | %2").arg(first->toString(), second->toString());
+#endif
+    }
+
+    virtual void updateChildrenSizes();
+    bool calculateSizeHints();
+
+    bool secondForward() const {
+        // We have the convention that the first children will define the direction of the
+        // pararell group. Note that we can't rely on 'this->from' or 'this->to'  because they
+        // might be changed by vertex simplification.
+        return firstEdge->from == secondEdge->from;
+    }
+
+    AnchorData* firstEdge;
+    AnchorData* secondEdge;
+
+    QList<QSimplexConstraint *> m_firstConstraints;
+    QList<QSimplexConstraint *> m_secondConstraints;
+};
+
+struct AnchorVertexPair : public AnchorVertex {
+    AnchorVertexPair(AnchorVertex *v1, AnchorVertex *v2, AnchorData *data)
+        : AnchorVertex(), m_first(v1), m_second(v2), m_removedAnchor(data) {
+        m_type = AnchorVertex::Pair;
+    }
+
+    AnchorVertex *m_first;
+    AnchorVertex *m_second;
+
+    AnchorData *m_removedAnchor;
+    QList<AnchorData *> m_firstAnchors;
+    QList<AnchorData *> m_secondAnchors;
+};
+
 #ifdef QT_DEBUG
 inline QString AnchorVertex::toString() const
 {
-    if (!this || !m_item) {
+    if (!this) {
         return QLatin1String("NULL");
+    } else if (m_type == Pair) {
+        const AnchorVertexPair *vp = static_cast<const AnchorVertexPair *>(this);
+        return QString::fromAscii("(%1, %2)").arg(vp->m_first->toString()).arg(vp->m_second->toString());
+    } else if (!m_item) {
+        return QString::fromAscii("NULL_%1").arg(quintptr(this));
     }
     QString edge;
     switch (m_edge) {
@@ -141,137 +307,6 @@
 /*!
   \internal
 
-  Represents an edge (anchor) in the internal graph.
-*/
-struct AnchorData : public QSimplexVariable {
-    enum Type {
-        Normal = 0,
-        Sequential,
-        Parallel
-    };
-
-    AnchorData()
-        : QSimplexVariable(), from(0), to(0),
-          minSize(0), prefSize(0), expSize(0), maxSize(0),
-          sizeAtMinimum(0), sizeAtPreferred(0),
-          sizeAtExpanding(0), sizeAtMaximum(0),
-          graphicsAnchor(0), skipInPreferred(0),
-          type(Normal), hasSize(true), isLayoutAnchor(false) {}
-
-    virtual void updateChildrenSizes() {}
-    virtual void refreshSizeHints(qreal effectiveSpacing);
-
-    virtual ~AnchorData() {}
-
-#ifdef QT_DEBUG
-    void dump(int indent = 2);
-    inline QString toString() const;
-    QString name;
-#endif
-
-    inline void setPreferredSize(qreal size)
-    {
-        prefSize = size;
-        hasSize = true;
-    }
-
-    inline void unsetSize()
-    {
-        hasSize = false;
-    }
-
-    // Anchor is semantically directed
-    AnchorVertex *from;
-    AnchorVertex *to;
-
-    // Size restrictions of this edge. For anchors internal to items, these
-    // values are derived from the respective item size hints. For anchors
-    // that were added by users, these values are equal to the specified anchor
-    // size.
-    qreal minSize;
-    qreal prefSize;
-    qreal expSize;
-    qreal maxSize;
-
-    // These attributes define which sizes should that anchor be in when the
-    // layout is at its minimum, preferred or maximum sizes. Values are
-    // calculated by the Simplex solver based on the current layout setup.
-    qreal sizeAtMinimum;
-    qreal sizeAtPreferred;
-    qreal sizeAtExpanding;
-    qreal sizeAtMaximum;
-    QGraphicsAnchor *graphicsAnchor;
-
-    uint skipInPreferred : 1;
-    uint type : 2;            // either Normal, Sequential or Parallel
-    uint hasSize : 1;         // if false, get size from style.
-    uint isLayoutAnchor : 1;  // if this anchor is connected to a layout 'edge'
-};
-
-#ifdef QT_DEBUG
-inline QString AnchorData::toString() const
-{
-    return QString::fromAscii("Anchor(%1)").arg(name);
-}
-#endif
-
-struct SequentialAnchorData : public AnchorData
-{
-    SequentialAnchorData() : AnchorData()
-    {
-        type = AnchorData::Sequential;
-#ifdef QT_DEBUG
-        name = QLatin1String("SequentialAnchorData");
-#endif
-    }
-
-    virtual void updateChildrenSizes();
-    virtual void refreshSizeHints(qreal effectiveSpacing);
-
-    void refreshSizeHints_helper(qreal effectiveSpacing, bool refreshChildren = true);
-
-    void setVertices(const QVector<AnchorVertex*> &vertices)
-    {
-        m_children = vertices;
-#ifdef QT_DEBUG
-        name = QString::fromAscii("%1 -- %2").arg(vertices.first()->toString(), vertices.last()->toString());
-#endif
-    }
-
-    QVector<AnchorVertex*> m_children;          // list of vertices in the sequence
-    QVector<AnchorData*> m_edges;               // keep the list of edges too.
-};
-
-struct ParallelAnchorData : public AnchorData
-{
-    ParallelAnchorData(AnchorData *first, AnchorData *second)
-        : AnchorData(), firstEdge(first), secondEdge(second)
-    {
-        type = AnchorData::Parallel;
-
-        // ### Those asserts force that both child anchors have the same direction,
-        // but can't we simplify a pair of anchors in opposite directions?
-        Q_ASSERT(first->from == second->from);
-        Q_ASSERT(first->to == second->to);
-        from = first->from;
-        to = first->to;
-#ifdef QT_DEBUG
-        name = QString::fromAscii("%1 | %2").arg(first->toString(), second->toString());
-#endif
-    }
-
-    virtual void updateChildrenSizes();
-    virtual void refreshSizeHints(qreal effectiveSpacing);
-
-    void refreshSizeHints_helper(qreal effectiveSpacing, bool refreshChildren = true);
-
-    AnchorData* firstEdge;
-    AnchorData* secondEdge;
-};
-
-/*!
-  \internal
-
   Representation of a valid path for a given vertex in the graph.
   In this struct, "positives" is the set of anchors that have been
   traversed in the forward direction, while "negatives" is the set
@@ -313,7 +348,12 @@
 
     QGraphicsAnchorLayoutPrivate *layoutPrivate;
     AnchorData *data;
+
+    // Size information for user controlled anchor
     QSizePolicy::Policy sizePolicy;
+    qreal preferredSize;
+
+    uint hasSize : 1;         // if false, get size from style.
 };
 
 
@@ -335,9 +375,10 @@
     //
     // Interval represents which interpolation interval are we operating in.
     enum Interval {
-        MinToPreferred = 0,
-        PreferredToExpanding,
-        ExpandingToMax
+        MinimumToMinPreferred = 0,
+        MinPreferredToPreferred,
+        PreferredToMaxPreferred,
+        MaxPreferredToMaximum
     };
 
     // Several structures internal to the layout are duplicated to handle
@@ -409,11 +450,6 @@
 
     void removeAnchor(AnchorVertex *firstVertex, AnchorVertex *secondVertex);
     void removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2);
-    void setAnchorSize(AnchorData *data, const qreal *anchorSize);
-    void anchorSize(const AnchorData *data,
-                    qreal *minSize = 0,
-                    qreal *prefSize = 0,
-                    qreal *maxSize = 0) const;
 
     void removeAnchors(QGraphicsLayoutItem *item);
 
@@ -423,25 +459,37 @@
                               Qt::AnchorPoint &firstEdge,
                               QGraphicsLayoutItem *&secondItem,
                               Qt::AnchorPoint &secondEdge);
-    // for getting the actual spacing (will query the style if the
-    // spacing is not explicitly set).
-    qreal effectiveSpacing(Orientation orientation) const;
+
+    QLayoutStyleInfo &styleInfo() const;
 
-    // Activation methods
-    void simplifyGraph(Orientation orientation);
-    bool simplifyGraphIteration(Orientation orientation);
-    void restoreSimplifiedGraph(Orientation orientation);
+    AnchorData *addAnchorMaybeParallel(AnchorData *newAnchor, bool *feasible);
 
+    // Activation
     void calculateGraphs();
     void calculateGraphs(Orientation orientation);
 
+    // Simplification
+    bool simplifyGraph(Orientation orientation);
+    bool simplifyVertices(Orientation orientation);
+    bool simplifyGraphIteration(Orientation orientation, bool *feasible);
+
+    bool replaceVertex(Orientation orientation, AnchorVertex *oldV,
+                       AnchorVertex *newV, const QList<AnchorData *> &edges);
+
+
+    void restoreSimplifiedGraph(Orientation orientation);
+    void restoreSimplifiedAnchor(AnchorData *edge);
+    void restoreSimplifiedConstraints(ParallelAnchorData *parallel);
+    void restoreVertices(Orientation orientation);
+
     bool calculateTrunk(Orientation orientation, const GraphPath &trunkPath,
                         const QList<QSimplexConstraint *> &constraints,
                         const QList<AnchorData *> &variables);
     bool calculateNonTrunk(const QList<QSimplexConstraint *> &constraints,
                            const QList<AnchorData *> &variables);
 
-    void setAnchorSizeHintsFromItems(Orientation orientation);
+    // Support functions for calculateGraph()
+    void refreshAllSizeHints(Orientation orientation);
     void findPaths(Orientation orientation);
     void constraintsFromPaths(Orientation orientation);
     void updateAnchorSizes(Orientation orientation);
@@ -460,6 +508,17 @@
         return internalVertex(qMakePair(const_cast<QGraphicsLayoutItem *>(item), edge));
     }
 
+    inline void changeLayoutVertex(Orientation orientation, AnchorVertex *oldV, AnchorVertex *newV)
+    {
+        if (layoutFirstVertex[orientation] == oldV)
+            layoutFirstVertex[orientation] = newV;
+        else if (layoutCentralVertex[orientation] == oldV)
+            layoutCentralVertex[orientation] = newV;
+        else if (layoutLastVertex[orientation] == oldV)
+            layoutLastVertex[orientation] = newV;
+    }
+
+
     AnchorVertex *addInternalVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge);
     void removeInternalVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge);
 
@@ -468,19 +527,13 @@
 
     void calculateVertexPositions(Orientation orientation);
     void setupEdgesInterpolation(Orientation orientation);
-    void interpolateEdge(AnchorVertex *base, AnchorData *edge, Orientation orientation);
-    void interpolateSequentialEdges(AnchorVertex *base, SequentialAnchorData *edge,
-                                    Orientation orientation);
-    void interpolateParallelEdges(AnchorVertex *base, ParallelAnchorData *edge,
-                                  Orientation orientation);
+    void interpolateEdge(AnchorVertex *base, AnchorData *edge);
 
     // Linear Programming solver methods
     bool solveMinMax(const QList<QSimplexConstraint *> &constraints,
                      GraphPath path, qreal *min, qreal *max);
     bool solvePreferred(const QList<QSimplexConstraint *> &constraints,
                         const QList<AnchorData *> &variables);
-    void solveExpanding(const QList<QSimplexConstraint *> &constraints,
-                        const QList<AnchorData *> &variables);
     bool hasConflicts() const;
 
 #ifdef QT_DEBUG
@@ -491,7 +544,6 @@
     qreal spacings[NOrientations];
     // Size hints from simplex engine
     qreal sizeHints[2][3];
-    qreal sizeAtExpanding[2];
 
     // Items
     QVector<QGraphicsLayoutItem *> items;
@@ -504,6 +556,14 @@
     // Internal graph of anchorage points and anchors, for both orientations
     Graph<AnchorVertex, AnchorData> graph[2];
 
+    AnchorVertex *layoutFirstVertex[2];
+    AnchorVertex *layoutCentralVertex[2];
+    AnchorVertex *layoutLastVertex[2];
+
+    // Combined anchors in order of creation
+    QList<AnchorVertexPair *> simplifiedVertices[2];
+    QList<AnchorData *> anchorsFromSimplifiedVertices[2];
+
     // Graph paths and constraints, for both orientations
     QMultiHash<AnchorVertex *, GraphPath> graphPaths[2];
     QList<QSimplexConstraint *> constraints[2];
@@ -514,8 +574,6 @@
     Interval interpolationInterval[2];
     qreal interpolationProgress[2];
 
-    // ###
-    bool graphSimplified[2];
     bool graphHasConflicts[2];
     QSet<QGraphicsLayoutItem *> m_floatItems[2];
 
@@ -524,10 +582,13 @@
 #endif
 
     uint calculateGraphCacheDirty : 1;
+    mutable uint styleInfoDirty : 1;
+    mutable QLayoutStyleInfo cachedStyleInfo;
 
     friend class QGraphicsAnchorPrivate;
 };
 
 QT_END_NAMESPACE
+#endif //QT_NO_GRAPHICSVIEW
 
 #endif