summaryrefslogtreecommitdiffstats
path: root/src/widgets/graphicsview
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2011-05-07 00:02:01 +0200
committerLars Knoll <lars.knoll@nokia.com>2011-05-07 00:02:01 +0200
commitf67b8df3ebdba2d398b9cce686b7c644adffff08 (patch)
tree062dd469f7cf8daa01a32d3e7b767b8fbdb7573a /src/widgets/graphicsview
parent32ce4fe9e6a94e77828e976776cf08da85254ff2 (diff)
library split
Diffstat (limited to 'src/widgets/graphicsview')
-rw-r--r--src/widgets/graphicsview/graphicsview.pri52
-rw-r--r--src/widgets/graphicsview/qgraph_p.h286
-rw-r--r--src/widgets/graphicsview/qgraphicsanchorlayout.cpp533
-rw-r--r--src/widgets/graphicsview/qgraphicsanchorlayout.h128
-rw-r--r--src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp3015
-rw-r--r--src/widgets/graphicsview/qgraphicsanchorlayout_p.h594
-rw-r--r--src/widgets/graphicsview/qgraphicsgridlayout.cpp690
-rw-r--r--src/widgets/graphicsview/qgraphicsgridlayout.h144
-rw-r--r--src/widgets/graphicsview/qgraphicsitem.cpp11597
-rw-r--r--src/widgets/graphicsview/qgraphicsitem.h1172
-rw-r--r--src/widgets/graphicsview/qgraphicsitem_p.h891
-rw-r--r--src/widgets/graphicsview/qgraphicsitemanimation.cpp599
-rw-r--r--src/widgets/graphicsview/qgraphicsitemanimation.h120
-rw-r--r--src/widgets/graphicsview/qgraphicslayout.cpp451
-rw-r--r--src/widgets/graphicsview/qgraphicslayout.h98
-rw-r--r--src/widgets/graphicsview/qgraphicslayout_p.cpp198
-rw-r--r--src/widgets/graphicsview/qgraphicslayout_p.h154
-rw-r--r--src/widgets/graphicsview/qgraphicslayoutitem.cpp935
-rw-r--r--src/widgets/graphicsview/qgraphicslayoutitem.h155
-rw-r--r--src/widgets/graphicsview/qgraphicslayoutitem_p.h103
-rw-r--r--src/widgets/graphicsview/qgraphicslinearlayout.cpp568
-rw-r--r--src/widgets/graphicsview/qgraphicslinearlayout.h119
-rw-r--r--src/widgets/graphicsview/qgraphicsproxywidget.cpp1570
-rw-r--r--src/widgets/graphicsview/qgraphicsproxywidget.h147
-rw-r--r--src/widgets/graphicsview/qgraphicsproxywidget_p.h130
-rw-r--r--src/widgets/graphicsview/qgraphicsscene.cpp6491
-rw-r--r--src/widgets/graphicsview/qgraphicsscene.h329
-rw-r--r--src/widgets/graphicsview/qgraphicsscene_bsp.cpp296
-rw-r--r--src/widgets/graphicsview/qgraphicsscene_bsp_p.h132
-rw-r--r--src/widgets/graphicsview/qgraphicsscene_p.h359
-rw-r--r--src/widgets/graphicsview/qgraphicsscenebsptreeindex.cpp719
-rw-r--r--src/widgets/graphicsview/qgraphicsscenebsptreeindex_p.h206
-rw-r--r--src/widgets/graphicsview/qgraphicssceneevent.cpp1674
-rw-r--r--src/widgets/graphicsview/qgraphicssceneevent.h326
-rw-r--r--src/widgets/graphicsview/qgraphicssceneindex.cpp648
-rw-r--r--src/widgets/graphicsview/qgraphicssceneindex_p.h182
-rw-r--r--src/widgets/graphicsview/qgraphicsscenelinearindex.cpp95
-rw-r--r--src/widgets/graphicsview/qgraphicsscenelinearindex_p.h109
-rw-r--r--src/widgets/graphicsview/qgraphicstransform.cpp594
-rw-r--r--src/widgets/graphicsview/qgraphicstransform.h159
-rw-r--r--src/widgets/graphicsview/qgraphicstransform_p.h78
-rw-r--r--src/widgets/graphicsview/qgraphicsview.cpp3880
-rw-r--r--src/widgets/graphicsview/qgraphicsview.h316
-rw-r--r--src/widgets/graphicsview/qgraphicsview_p.h233
-rw-r--r--src/widgets/graphicsview/qgraphicswidget.cpp2388
-rw-r--r--src/widgets/graphicsview/qgraphicswidget.h257
-rw-r--r--src/widgets/graphicsview/qgraphicswidget_p.cpp910
-rw-r--r--src/widgets/graphicsview/qgraphicswidget_p.h226
-rw-r--r--src/widgets/graphicsview/qgridlayoutengine.cpp1742
-rw-r--r--src/widgets/graphicsview/qgridlayoutengine_p.h458
-rw-r--r--src/widgets/graphicsview/qsimplex_p.cpp673
-rw-r--r--src/widgets/graphicsview/qsimplex_p.h208
52 files changed, 48137 insertions, 0 deletions
diff --git a/src/widgets/graphicsview/graphicsview.pri b/src/widgets/graphicsview/graphicsview.pri
new file mode 100644
index 0000000000..547d7ce7ae
--- /dev/null
+++ b/src/widgets/graphicsview/graphicsview.pri
@@ -0,0 +1,52 @@
+# Qt graphicsview module
+HEADERS += graphicsview/qgraphicsgridlayout.h \
+ graphicsview/qgraphicsitem.h \
+ graphicsview/qgraphicsitem_p.h \
+ graphicsview/qgraphicsitemanimation.h \
+ graphicsview/qgraphicslayout.h \
+ graphicsview/qgraphicslayout_p.h \
+ graphicsview/qgraphicslayoutitem.h \
+ graphicsview/qgraphicslayoutitem_p.h \
+ graphicsview/qgraphicslinearlayout.h \
+ graphicsview/qgraphicsproxywidget.h \
+ graphicsview/qgraphicsscene.h \
+ graphicsview/qgraphicsscene_bsp_p.h \
+ graphicsview/qgraphicsscene_p.h \
+ graphicsview/qgraphicsscenebsptreeindex_p.h \
+ graphicsview/qgraphicssceneevent.h \
+ graphicsview/qgraphicssceneindex_p.h \
+ graphicsview/qgraphicsscenelinearindex_p.h \
+ graphicsview/qgraphicstransform.h \
+ graphicsview/qgraphicstransform_p.h \
+ graphicsview/qgraphicsview.h \
+ graphicsview/qgraphicsview_p.h \
+ graphicsview/qgraphicswidget.h \
+ graphicsview/qgraphicswidget_p.h \
+ graphicsview/qgridlayoutengine_p.h \
+ graphicsview/qgraph_p.h \
+ graphicsview/qsimplex_p.h \
+ graphicsview/qgraphicsanchorlayout_p.h \
+ graphicsview/qgraphicsanchorlayout.h
+
+SOURCES += graphicsview/qgraphicsgridlayout.cpp \
+ graphicsview/qgraphicsitem.cpp \
+ graphicsview/qgraphicsitemanimation.cpp \
+ graphicsview/qgraphicslayout.cpp \
+ graphicsview/qgraphicslayout_p.cpp \
+ graphicsview/qgraphicslayoutitem.cpp \
+ graphicsview/qgraphicslinearlayout.cpp \
+ graphicsview/qgraphicsproxywidget.cpp \
+ graphicsview/qgraphicsscene.cpp \
+ graphicsview/qgraphicsscene_bsp.cpp \
+ graphicsview/qgraphicsscenebsptreeindex.cpp \
+ graphicsview/qgraphicssceneevent.cpp \
+ graphicsview/qgraphicssceneindex.cpp \
+ graphicsview/qgraphicsscenelinearindex.cpp \
+ graphicsview/qgraphicstransform.cpp \
+ graphicsview/qgraphicsview.cpp \
+ graphicsview/qgraphicswidget.cpp \
+ graphicsview/qgraphicswidget_p.cpp \
+ graphicsview/qgridlayoutengine.cpp \
+ graphicsview/qsimplex_p.cpp \
+ graphicsview/qgraphicsanchorlayout_p.cpp \
+ graphicsview/qgraphicsanchorlayout.cpp
diff --git a/src/widgets/graphicsview/qgraph_p.h b/src/widgets/graphicsview/qgraph_p.h
new file mode 100644
index 0000000000..094fbd1c2a
--- /dev/null
+++ b/src/widgets/graphicsview/qgraph_p.h
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPH_P_H
+#define QGRAPH_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QHash>
+#include <QtCore/QQueue>
+#include <QtCore/QString>
+#include <QtCore/QDebug>
+
+#include <float.h>
+
+QT_BEGIN_NAMESPACE
+
+template <typename Vertex, typename EdgeData>
+class Graph
+{
+public:
+ Graph() {}
+
+ class const_iterator {
+ public:
+ const_iterator(const Graph *graph, bool begin) : g(graph){
+ if (begin) {
+ row = g->m_graph.constBegin();
+ //test if the graph is empty
+ if (row != g->m_graph.constEnd())
+ {
+ column = (*row)->constBegin();
+ }
+ } else {
+ row = g->m_graph.constEnd();
+ }
+ }
+
+ inline Vertex *operator*() {
+ return column.key();
+ }
+
+ inline Vertex *from() const {
+ return row.key();
+ }
+
+ inline Vertex *to() const {
+ return column.key();
+ }
+
+ inline bool operator==(const const_iterator &o) const { return !(*this != o); }
+ inline bool operator!=(const const_iterator &o) const {
+ if (row == g->m_graph.end()) {
+ return row != o.row;
+ } else {
+ return row != o.row || column != o.column;
+ }
+ }
+ inline const_iterator& operator=(const const_iterator &o) const { row = o.row; column = o.column; return *this;}
+
+ // prefix
+ const_iterator &operator++() {
+ if (row != g->m_graph.constEnd()) {
+ ++column;
+ if (column == (*row)->constEnd()) {
+ ++row;
+ if (row != g->m_graph.constEnd()) {
+ column = (*row)->constBegin();
+ }
+ }
+ }
+ return *this;
+ }
+
+ private:
+ const Graph *g;
+ Q_TYPENAME QHash<Vertex *, QHash<Vertex *, EdgeData *> * >::const_iterator row;
+ Q_TYPENAME QHash<Vertex *, EdgeData *>::const_iterator column;
+ };
+
+ const_iterator constBegin() const {
+ return const_iterator(this,true);
+ }
+
+ const_iterator constEnd() const {
+ return const_iterator(this,false);
+ }
+
+ /*!
+ * \internal
+ *
+ * If there is an edge between \a first and \a second, it will return a structure
+ * containing the data associated with the edge, otherwise it will return 0.
+ *
+ */
+ EdgeData *edgeData(Vertex* first, Vertex* second) {
+ QHash<Vertex *, EdgeData *> *row = m_graph.value(first);
+ return row ? row->value(second) : 0;
+ }
+
+ void createEdge(Vertex *first, Vertex *second, EdgeData *data)
+ {
+ // Creates a bidirectional edge
+#if defined(QT_DEBUG) && 0
+ qDebug("Graph::createEdge(): %s",
+ qPrintable(QString::fromAscii("%1-%2")
+ .arg(first->toString()).arg(second->toString())));
+#endif
+ if (edgeData(first, second)) {
+#ifdef QT_DEBUG
+ qWarning("%s-%s already has an edge", qPrintable(first->toString()), qPrintable(second->toString()));
+#endif
+ }
+ createDirectedEdge(first, second, data);
+ createDirectedEdge(second, first, data);
+ }
+
+ void removeEdge(Vertex *first, Vertex *second)
+ {
+ // Removes a bidirectional edge
+#if defined(QT_DEBUG) && 0
+ qDebug("Graph::removeEdge(): %s",
+ qPrintable(QString::fromAscii("%1-%2")
+ .arg(first->toString()).arg(second->toString())));
+#endif
+ EdgeData *data = edgeData(first, second);
+ removeDirectedEdge(first, second);
+ removeDirectedEdge(second, first);
+ if (data) delete data;
+ }
+
+ EdgeData *takeEdge(Vertex* first, Vertex* second)
+ {
+#if defined(QT_DEBUG) && 0
+ qDebug("Graph::takeEdge(): %s",
+ qPrintable(QString::fromAscii("%1-%2")
+ .arg(first->toString()).arg(second->toString())));
+#endif
+ // Removes a bidirectional edge
+ EdgeData *data = edgeData(first, second);
+ if (data) {
+ removeDirectedEdge(first, second);
+ removeDirectedEdge(second, first);
+ }
+ return data;
+ }
+
+ QList<Vertex *> adjacentVertices(Vertex *vertex) const
+ {
+ QHash<Vertex *, EdgeData *> *row = m_graph.value(vertex);
+ QList<Vertex *> l;
+ if (row)
+ l = row->keys();
+ return l;
+ }
+
+ QSet<Vertex*> vertices() const {
+ QSet<Vertex *> setOfVertices;
+ for (const_iterator it = constBegin(); it != constEnd(); ++it) {
+ setOfVertices.insert(*it);
+ }
+ return setOfVertices;
+ }
+
+ QList<QPair<Vertex*, Vertex*> > connections() const {
+ QList<QPair<Vertex*, Vertex*> > conns;
+ for (const_iterator it = constBegin(); it != constEnd(); ++it) {
+ Vertex *from = it.from();
+ Vertex *to = it.to();
+ // do not return (from,to) *and* (to,from)
+ if (from < to) {
+ conns.append(qMakePair(from, to));
+ }
+ }
+ return conns;
+ }
+
+#if defined(QT_DEBUG)
+ QString serializeToDot() { // traversal
+ QString strVertices;
+ QString edges;
+
+ QSet<Vertex *> setOfVertices = vertices();
+ for (Q_TYPENAME QSet<Vertex*>::const_iterator it = setOfVertices.begin(); it != setOfVertices.end(); ++it) {
+ Vertex *v = *it;
+ QList<Vertex*> adjacents = adjacentVertices(v);
+ for (int i = 0; i < adjacents.count(); ++i) {
+ Vertex *v1 = adjacents.at(i);
+ EdgeData *data = edgeData(v, v1);
+ bool forward = data->from == v;
+ if (forward) {
+ edges += QString::fromAscii("\"%1\"->\"%2\" [label=\"[%3,%4,%5,%6,%7]\" color=\"#000000\"] \n")
+ .arg(v->toString())
+ .arg(v1->toString())
+ .arg(data->minSize)
+ .arg(data->minPrefSize)
+ .arg(data->prefSize)
+ .arg(data->maxPrefSize)
+ .arg(data->maxSize)
+ ;
+ }
+ }
+ strVertices += QString::fromAscii("\"%1\" [label=\"%2\"]\n").arg(v->toString()).arg(v->toString());
+ }
+ return QString::fromAscii("%1\n%2\n").arg(strVertices).arg(edges);
+ }
+#endif
+
+protected:
+ void createDirectedEdge(Vertex *from, Vertex *to, EdgeData *data)
+ {
+ QHash<Vertex *, EdgeData *> *adjacentToFirst = m_graph.value(from);
+ if (!adjacentToFirst) {
+ adjacentToFirst = new QHash<Vertex *, EdgeData *>();
+ m_graph.insert(from, adjacentToFirst);
+ }
+ adjacentToFirst->insert(to, data);
+ }
+
+ void removeDirectedEdge(Vertex *from, Vertex *to)
+ {
+ QHash<Vertex *, EdgeData *> *adjacentToFirst = m_graph.value(from);
+ Q_ASSERT(adjacentToFirst);
+
+ adjacentToFirst->remove(to);
+ if (adjacentToFirst->isEmpty()) {
+ //nobody point to 'from' so we can remove it from the graph
+ m_graph.remove(from);
+ delete adjacentToFirst;
+ }
+ }
+
+private:
+ QHash<Vertex *, QHash<Vertex *, EdgeData *> *> m_graph;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout.cpp b/src/widgets/graphicsview/qgraphicsanchorlayout.cpp
new file mode 100644
index 0000000000..9bb5424641
--- /dev/null
+++ b/src/widgets/graphicsview/qgraphicsanchorlayout.cpp
@@ -0,0 +1,533 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QGraphicsAnchorLayout
+ \brief The QGraphicsAnchorLayout class provides a layout where one can anchor widgets
+ together in Graphics View.
+ \since 4.6
+ \ingroup appearance
+ \ingroup geomanagement
+ \ingroup graphicsview-api
+
+ The anchor layout allows developers to specify how widgets should be placed relative to
+ each other, and to the layout itself. The specification is made by adding anchors to the
+ layout by calling addAnchor(), addAnchors() or addCornerAnchors().
+
+ Existing anchors in the layout can be accessed with the anchor() function.
+ Items that are anchored are automatically added to the layout, and if items
+ are removed, all their anchors will be automatically removed.
+
+ \div {class="float-left"}
+ \inlineimage simpleanchorlayout-example.png Using an anchor layout to align simple colored widgets.
+ \enddiv
+
+ Anchors are always set up between edges of an item, where the "center" is also considered to
+ be an edge. Consider the following example:
+
+ \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding anchors
+
+ Here, the right edge of item \c a is anchored to the left edge of item \c b and the bottom
+ edge of item \c a is anchored to the top edge of item \c b, with the result that
+ item \c b will be placed diagonally to the right and below item \c b.
+
+ The addCornerAnchors() function provides a simpler way of anchoring the corners
+ of two widgets than the two individual calls to addAnchor() shown in the code
+ above. Here, we see how a widget can be anchored to the top-left corner of the enclosing
+ layout:
+
+ \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding a corner anchor
+
+ In cases where anchors are used to match the widths or heights of widgets, it is
+ convenient to use the addAnchors() function. As with the other functions for specifying
+ anchors, it can also be used to anchor a widget to a layout.
+
+ \clearfloat
+ \section1 Size Hints and Size Policies in an Anchor Layout
+
+ QGraphicsAnchorLayout respects each item's size hints and size policies.
+ Note that there are some properties of QSizePolicy that are \l{Known issues}{not respected}.
+
+ \section1 Spacing within an Anchor Layout
+
+ The layout may distribute some space between the items. If the spacing has not been
+ explicitly specified, the actual amount of space will usually be 0.
+
+ However, if the first edge is the \e opposite of the second edge (e.g., the right edge
+ of the first widget is anchored to the left edge of the second widget), the size of the
+ anchor will be queried from the style through a pixel metric:
+ \l{QStyle::}{PM_LayoutHorizontalSpacing} for horizontal anchors and
+ \l{QStyle::}{PM_LayoutVerticalSpacing} for vertical anchors.
+
+ If the spacing is negative, the items will overlap to some extent.
+
+
+ \section1 Known issues
+ There are some features that QGraphicsAnchorLayout currently does not support.
+ This might change in the future, so avoid using these features if you want to
+ avoid any future regressions in behaviour:
+ \list
+
+ \o Stretch factors are not respected.
+
+ \o QSizePolicy::ExpandFlag is not respected.
+
+ \o Height for width is not respected.
+
+ \endlist
+
+ \sa QGraphicsLinearLayout, QGraphicsGridLayout, QGraphicsLayout
+*/
+
+/*!
+ \class QGraphicsAnchor
+ \brief The QGraphicsAnchor class represents an anchor between two items in a
+ QGraphicsAnchorLayout.
+ \since 4.6
+ \ingroup appearance
+ \ingroup geomanagement
+ \ingroup graphicsview-api
+
+ The graphics anchor provides an API that enables you to query and manipulate the
+ properties an anchor has. When an anchor is added to the layout with
+ QGraphicsAnchorLayout::addAnchor(), a QGraphicsAnchor instance is returned where the properties
+ are initialized to their default values. The properties can then be further changed, and they
+ will be picked up the next time the layout is activated.
+
+ \sa QGraphicsAnchorLayout::anchor()
+
+*/
+#include "qgraphicsanchorlayout_p.h"
+#ifndef QT_NO_GRAPHICSVIEW
+QT_BEGIN_NAMESPACE
+
+QGraphicsAnchor::QGraphicsAnchor(QGraphicsAnchorLayout *parentLayout)
+ : QObject(*(new QGraphicsAnchorPrivate))
+{
+ Q_D(QGraphicsAnchor);
+ Q_ASSERT(parentLayout);
+ d->layoutPrivate = parentLayout->d_func();
+}
+
+/*!
+ Removes the QGraphicsAnchor object from the layout and destroys it.
+*/
+QGraphicsAnchor::~QGraphicsAnchor()
+{
+}
+
+/*!
+ \property QGraphicsAnchor::sizePolicy
+ \brief the size policy for the QGraphicsAnchor.
+
+ By setting the size policy on an anchor you can configure how the anchor can resize itself
+ from its preferred spacing. For instance, if the anchor has the size policy
+ QSizePolicy::Minimum, the spacing is the minimum size of the anchor. However, its size
+ can grow up to the anchors maximum size. If the default size policy is QSizePolicy::Fixed,
+ the anchor can neither grow or shrink, which means that the only size the anchor can have
+ is the spacing. QSizePolicy::Fixed is the default size policy.
+ QGraphicsAnchor always has a minimum spacing of 0 and a very large maximum spacing.
+
+ \sa QGraphicsAnchor::spacing
+*/
+
+void QGraphicsAnchor::setSizePolicy(QSizePolicy::Policy policy)
+{
+ Q_D(QGraphicsAnchor);
+ d->setSizePolicy(policy);
+}
+
+QSizePolicy::Policy QGraphicsAnchor::sizePolicy() const
+{
+ Q_D(const QGraphicsAnchor);
+ return d->sizePolicy;
+}
+
+/*!
+ \property QGraphicsAnchor::spacing
+ \brief the preferred space between items in the QGraphicsAnchorLayout.
+
+ Depending on the anchor type, the default spacing is either
+ 0 or a value returned from the style.
+
+ \sa QGraphicsAnchorLayout::addAnchor()
+*/
+void QGraphicsAnchor::setSpacing(qreal spacing)
+{
+ Q_D(QGraphicsAnchor);
+ d->setSpacing(spacing);
+}
+
+qreal QGraphicsAnchor::spacing() const
+{
+ Q_D(const QGraphicsAnchor);
+ return d->spacing();
+}
+
+void QGraphicsAnchor::unsetSpacing()
+{
+ Q_D(QGraphicsAnchor);
+ d->unsetSpacing();
+}
+
+/*!
+ Constructs a QGraphicsAnchorLayout instance. \a parent is passed to
+ QGraphicsLayout's constructor.
+ */
+QGraphicsAnchorLayout::QGraphicsAnchorLayout(QGraphicsLayoutItem *parent)
+ : QGraphicsLayout(*new QGraphicsAnchorLayoutPrivate(), parent)
+{
+ Q_D(QGraphicsAnchorLayout);
+ d->createLayoutEdges();
+}
+
+/*!
+ Destroys the QGraphicsAnchorLayout object.
+*/
+QGraphicsAnchorLayout::~QGraphicsAnchorLayout()
+{
+ Q_D(QGraphicsAnchorLayout);
+
+ for (int i = count() - 1; i >= 0; --i) {
+ QGraphicsLayoutItem *item = d->items.at(i);
+ removeAt(i);
+ if (item) {
+ if (item->ownedByLayout())
+ delete item;
+ }
+ }
+
+ d->removeCenterConstraints(this, QGraphicsAnchorLayoutPrivate::Horizontal);
+ d->removeCenterConstraints(this, QGraphicsAnchorLayoutPrivate::Vertical);
+ d->deleteLayoutEdges();
+
+ Q_ASSERT(d->itemCenterConstraints[0].isEmpty());
+ Q_ASSERT(d->itemCenterConstraints[1].isEmpty());
+ Q_ASSERT(d->items.isEmpty());
+ Q_ASSERT(d->m_vertexList.isEmpty());
+}
+
+/*!
+ Creates an anchor between the edge \a firstEdge of item \a firstItem and the edge \a secondEdge
+ of item \a secondItem. The spacing of the anchor is picked up from the style. Anchors
+ between a layout edge and an item edge will have a size of 0.
+ If there is already an anchor between the edges, the the new anchor will replace the old one.
+
+ \a firstItem and \a secondItem are automatically added to the layout if they are not part
+ of the layout. This means that count() can increase by up to 2.
+
+ The spacing an anchor will get depends on the type of anchor. For instance, anchors from the
+ Right edge of one item to the Left edge of another (or vice versa) will use the default
+ horizontal spacing. The same behaviour applies to Bottom to Top anchors, (but they will use
+ the default vertical spacing). For all other anchor combinations, the spacing will be 0.
+ All anchoring functions will follow this rule.
+
+ The spacing can also be set manually by using QGraphicsAnchor::setSpacing() method.
+
+ Calling this function where \a firstItem or \a secondItem are ancestors of the layout have
+ undefined behaviour.
+
+ \sa addAnchors(), addCornerAnchors()
+ */
+QGraphicsAnchor *
+QGraphicsAnchorLayout::addAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge,
+ QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge)
+{
+ Q_D(QGraphicsAnchorLayout);
+ QGraphicsAnchor *a = d->addAnchor(firstItem, firstEdge, secondItem, secondEdge);
+ invalidate();
+ return a;
+}
+
+/*!
+ Returns the anchor between the anchor points defined by \a firstItem and \a firstEdge and
+ \a secondItem and \a secondEdge. If there is no such anchor, the function will return 0.
+*/
+QGraphicsAnchor *
+QGraphicsAnchorLayout::anchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge,
+ QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge)
+{
+ Q_D(QGraphicsAnchorLayout);
+ return d->getAnchor(firstItem, firstEdge, secondItem, secondEdge);
+}
+
+/*!
+ Creates two anchors between \a firstItem and \a secondItem specified by the corners,
+ \a firstCorner and \a secondCorner, where one is for the horizontal edge and another
+ one for the vertical edge.
+
+ This is a convenience function, since anchoring corners can be expressed as anchoring
+ two edges. For instance:
+
+ \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding a corner anchor in two steps
+
+ This can also be achieved with the following line of code:
+
+ \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding a corner anchor
+
+ If there is already an anchor between the edge pairs, it will be replaced by the anchors that
+ this function specifies.
+
+ \a firstItem and \a secondItem are automatically added to the layout if they are not part of the
+ layout. This means that count() can increase by up to 2.
+
+ \sa addAnchor(), addAnchors()
+*/
+void QGraphicsAnchorLayout::addCornerAnchors(QGraphicsLayoutItem *firstItem,
+ Qt::Corner firstCorner,
+ QGraphicsLayoutItem *secondItem,
+ Qt::Corner secondCorner)
+{
+ Q_D(QGraphicsAnchorLayout);
+
+ // Horizontal anchor
+ Qt::AnchorPoint firstEdge = (firstCorner & 1 ? Qt::AnchorRight: Qt::AnchorLeft);
+ Qt::AnchorPoint secondEdge = (secondCorner & 1 ? Qt::AnchorRight: Qt::AnchorLeft);
+ if (d->addAnchor(firstItem, firstEdge, secondItem, secondEdge)) {
+ // Vertical anchor
+ firstEdge = (firstCorner & 2 ? Qt::AnchorBottom: Qt::AnchorTop);
+ secondEdge = (secondCorner & 2 ? Qt::AnchorBottom: Qt::AnchorTop);
+ d->addAnchor(firstItem, firstEdge, secondItem, secondEdge);
+
+ invalidate();
+ }
+}
+
+/*!
+ Anchors two or four edges of \a firstItem with the corresponding
+ edges of \a secondItem, so that \a firstItem has the same size as
+ \a secondItem in the dimensions specified by \a orientations.
+
+ For example, the following example anchors the left and right edges of two items
+ to match their widths:
+
+ \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding anchors to match sizes in two steps
+
+ This can also be achieved using the following line of code:
+
+ \snippet examples/graphicsview/simpleanchorlayout/main.cpp adding anchors to match sizes
+
+ \sa addAnchor(), addCornerAnchors()
+*/
+void QGraphicsAnchorLayout::addAnchors(QGraphicsLayoutItem *firstItem,
+ QGraphicsLayoutItem *secondItem,
+ Qt::Orientations orientations)
+{
+ bool ok = true;
+ if (orientations & Qt::Horizontal) {
+ // Currently, if the first is ok, then the rest of the calls should be ok
+ ok = addAnchor(secondItem, Qt::AnchorLeft, firstItem, Qt::AnchorLeft) != 0;
+ if (ok)
+ addAnchor(firstItem, Qt::AnchorRight, secondItem, Qt::AnchorRight);
+ }
+ if (orientations & Qt::Vertical && ok) {
+ addAnchor(secondItem, Qt::AnchorTop, firstItem, Qt::AnchorTop);
+ addAnchor(firstItem, Qt::AnchorBottom, secondItem, Qt::AnchorBottom);
+ }
+}
+
+/*!
+ Sets the default horizontal spacing for the anchor layout to \a spacing.
+
+ \sa horizontalSpacing(), setVerticalSpacing(), setSpacing()
+*/
+void QGraphicsAnchorLayout::setHorizontalSpacing(qreal spacing)
+{
+ Q_D(QGraphicsAnchorLayout);
+
+ d->spacings[0] = spacing;
+ invalidate();
+}
+
+/*!
+ Sets the default vertical spacing for the anchor layout to \a spacing.
+
+ \sa verticalSpacing(), setHorizontalSpacing(), setSpacing()
+*/
+void QGraphicsAnchorLayout::setVerticalSpacing(qreal spacing)
+{
+ Q_D(QGraphicsAnchorLayout);
+
+ d->spacings[1] = spacing;
+ invalidate();
+}
+
+/*!
+ Sets the default horizontal and the default vertical spacing for the anchor layout to \a spacing.
+
+ If an item is anchored with no spacing associated with the anchor, it will use the default
+ spacing.
+
+ QGraphicsAnchorLayout does not support negative spacings. Setting a negative value will unset the
+ previous spacing and make the layout use the spacing provided by the current widget style.
+
+ \sa setHorizontalSpacing(), setVerticalSpacing()
+*/
+void QGraphicsAnchorLayout::setSpacing(qreal spacing)
+{
+ Q_D(QGraphicsAnchorLayout);
+
+ d->spacings[0] = d->spacings[1] = spacing;
+ invalidate();
+}
+
+/*!
+ Returns the default horizontal spacing for the anchor layout.
+
+ \sa verticalSpacing(), setHorizontalSpacing()
+*/
+qreal QGraphicsAnchorLayout::horizontalSpacing() const
+{
+ Q_D(const QGraphicsAnchorLayout);
+ return d->styleInfo().defaultSpacing(Qt::Horizontal);
+}
+
+/*!
+ Returns the default vertical spacing for the anchor layout.
+
+ \sa horizontalSpacing(), setVerticalSpacing()
+*/
+qreal QGraphicsAnchorLayout::verticalSpacing() const
+{
+ Q_D(const QGraphicsAnchorLayout);
+ return d->styleInfo().defaultSpacing(Qt::Vertical);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsAnchorLayout::setGeometry(const QRectF &geom)
+{
+ Q_D(QGraphicsAnchorLayout);
+
+ QGraphicsLayout::setGeometry(geom);
+ d->calculateVertexPositions(QGraphicsAnchorLayoutPrivate::Horizontal);
+ d->calculateVertexPositions(QGraphicsAnchorLayoutPrivate::Vertical);
+ d->setItemsGeometries(geom);
+}
+
+/*!
+ Removes the layout item at \a index without destroying it. Ownership of
+ the item is transferred to the caller.
+
+ Removing an item will also remove any of the anchors associated with it.
+
+ \sa itemAt(), count()
+*/
+void QGraphicsAnchorLayout::removeAt(int index)
+{
+ Q_D(QGraphicsAnchorLayout);
+ QGraphicsLayoutItem *item = d->items.value(index);
+
+ if (!item)
+ return;
+
+ // Removing an item affects both horizontal and vertical graphs
+ d->removeCenterConstraints(item, QGraphicsAnchorLayoutPrivate::Horizontal);
+ d->removeCenterConstraints(item, QGraphicsAnchorLayoutPrivate::Vertical);
+ d->removeAnchors(item);
+ d->items.remove(index);
+
+ item->setParentLayoutItem(0);
+ invalidate();
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsAnchorLayout::count() const
+{
+ Q_D(const QGraphicsAnchorLayout);
+ return d->items.size();
+}
+
+/*!
+ \reimp
+*/
+QGraphicsLayoutItem *QGraphicsAnchorLayout::itemAt(int index) const
+{
+ Q_D(const QGraphicsAnchorLayout);
+ return d->items.value(index);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsAnchorLayout::invalidate()
+{
+ Q_D(QGraphicsAnchorLayout);
+ QGraphicsLayout::invalidate();
+ d->calculateGraphCacheDirty = true;
+ d->styleInfoDirty = true;
+}
+
+/*!
+ \reimp
+*/
+QSizeF QGraphicsAnchorLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ Q_UNUSED(constraint);
+ Q_D(const QGraphicsAnchorLayout);
+
+ // Some setup calculations are delayed until the information is
+ // actually needed, avoiding unnecessary recalculations when
+ // adding multiple anchors.
+
+ // sizeHint() / effectiveSizeHint() already have a cache
+ // mechanism, using invalidate() to force recalculation. However
+ // sizeHint() is called three times after invalidation (for max,
+ // min and pref), but we just need do our setup once.
+
+ const_cast<QGraphicsAnchorLayoutPrivate *>(d)->calculateGraphs();
+
+ // ### apply constraint!
+ QSizeF engineSizeHint(
+ d->sizeHints[QGraphicsAnchorLayoutPrivate::Horizontal][which],
+ d->sizeHints[QGraphicsAnchorLayoutPrivate::Vertical][which]);
+
+ qreal left, top, right, bottom;
+ getContentsMargins(&left, &top, &right, &bottom);
+
+ return engineSizeHint + QSizeF(left + right, top + bottom);
+}
+
+QT_END_NAMESPACE
+#endif //QT_NO_GRAPHICSVIEW
diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout.h b/src/widgets/graphicsview/qgraphicsanchorlayout.h
new file mode 100644
index 0000000000..cdb14bc3ba
--- /dev/null
+++ b/src/widgets/graphicsview/qgraphicsanchorlayout.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSANCHORLAYOUT_H
+#define QGRAPHICSANCHORLAYOUT_H
+
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/qgraphicslayout.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+class QGraphicsAnchorPrivate;
+class QGraphicsAnchorLayout;
+class QGraphicsAnchorLayoutPrivate;
+
+class Q_GUI_EXPORT QGraphicsAnchor : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing RESET unsetSpacing)
+ Q_PROPERTY(QSizePolicy::Policy sizePolicy READ sizePolicy WRITE setSizePolicy)
+public:
+ void setSpacing(qreal spacing);
+ void unsetSpacing();
+ qreal spacing() const;
+ void setSizePolicy(QSizePolicy::Policy policy);
+ QSizePolicy::Policy sizePolicy() const;
+ ~QGraphicsAnchor();
+private:
+ QGraphicsAnchor(QGraphicsAnchorLayout *parent);
+
+ Q_DECLARE_PRIVATE(QGraphicsAnchor)
+
+ friend class QGraphicsAnchorLayoutPrivate;
+ friend struct AnchorData;
+};
+
+class Q_GUI_EXPORT QGraphicsAnchorLayout : public QGraphicsLayout
+{
+public:
+ QGraphicsAnchorLayout(QGraphicsLayoutItem *parent = 0);
+ virtual ~QGraphicsAnchorLayout();
+
+ QGraphicsAnchor *addAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge,
+ QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge);
+ QGraphicsAnchor *anchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge,
+ QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge);
+
+ void addCornerAnchors(QGraphicsLayoutItem *firstItem, Qt::Corner firstCorner,
+ QGraphicsLayoutItem *secondItem, Qt::Corner secondCorner);
+
+ void addAnchors(QGraphicsLayoutItem *firstItem,
+ QGraphicsLayoutItem *secondItem,
+ Qt::Orientations orientations = Qt::Horizontal | Qt::Vertical);
+
+ void setHorizontalSpacing(qreal spacing);
+ void setVerticalSpacing(qreal spacing);
+ void setSpacing(qreal spacing);
+ qreal horizontalSpacing() const;
+ qreal verticalSpacing() const;
+
+ void removeAt(int index);
+ void setGeometry(const QRectF &rect);
+ int count() const;
+ QGraphicsLayoutItem *itemAt(int index) const;
+
+ void invalidate();
+protected:
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+private:
+ Q_DISABLE_COPY(QGraphicsAnchorLayout)
+ Q_DECLARE_PRIVATE(QGraphicsAnchorLayout)
+
+ friend class QGraphicsAnchor;
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp b/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp
new file mode 100644
index 0000000000..48cbec3d62
--- /dev/null
+++ b/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp
@@ -0,0 +1,3015 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qwidget.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/qlinkedlist.h>
+#include <QtCore/qstack.h>
+
+#ifdef QT_DEBUG
+#include <QtCore/qfile.h>
+#endif
+
+#include "qgraphicsanchorlayout_p.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+QT_BEGIN_NAMESPACE
+
+// To ensure that all variables inside the simplex solver are non-negative,
+// we limit the size of anchors in the interval [-limit, limit]. Then before
+// sending them to the simplex solver we add "limit" as an offset, so that
+// they are actually calculated in the interval [0, 2 * limit]
+// To avoid numerical errors in platforms where we use single precision,
+// we use a tighter limit for the variables range.
+const qreal g_offset = (sizeof(qreal) == sizeof(double)) ? QWIDGETSIZE_MAX : QWIDGETSIZE_MAX / 32;
+
+QGraphicsAnchorPrivate::QGraphicsAnchorPrivate(int version)
+ : QObjectPrivate(version), layoutPrivate(0), data(0),
+ sizePolicy(QSizePolicy::Fixed), preferredSize(0),
+ hasSize(true)
+{
+}
+
+QGraphicsAnchorPrivate::~QGraphicsAnchorPrivate()
+{
+ if (data) {
+ // The QGraphicsAnchor was already deleted at this moment. We must clean
+ // the dangling pointer to avoid double deletion in the AnchorData dtor.
+ data->graphicsAnchor = 0;
+
+ layoutPrivate->removeAnchor(data->from, data->to);
+ }
+}
+
+void QGraphicsAnchorPrivate::setSizePolicy(QSizePolicy::Policy policy)
+{
+ if (sizePolicy != policy) {
+ sizePolicy = policy;
+ layoutPrivate->q_func()->invalidate();
+ }
+}
+
+void QGraphicsAnchorPrivate::setSpacing(qreal value)
+{
+ if (!data) {
+ qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
+ return;
+ }
+
+ if (hasSize && (preferredSize == value))
+ return;
+
+ // The anchor has an user-defined size
+ hasSize = true;
+ preferredSize = value;
+
+ layoutPrivate->q_func()->invalidate();
+}
+
+void QGraphicsAnchorPrivate::unsetSpacing()
+{
+ if (!data) {
+ qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
+ return;
+ }
+
+ // Return to standard direction
+ hasSize = false;
+
+ layoutPrivate->q_func()->invalidate();
+}
+
+qreal QGraphicsAnchorPrivate::spacing() const
+{
+ if (!data) {
+ qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
+ return 0;
+ }
+
+ return preferredSize;
+}
+
+
+static void applySizePolicy(QSizePolicy::Policy policy,
+ qreal minSizeHint, qreal prefSizeHint, qreal maxSizeHint,
+ qreal *minSize, qreal *prefSize,
+ qreal *maxSize)
+{
+ // minSize, prefSize and maxSize are initialized
+ // with item's preferred Size: this is QSizePolicy::Fixed.
+ //
+ // Then we check each flag to find the resultant QSizePolicy,
+ // according to the following table:
+ //
+ // constant value
+ // QSizePolicy::Fixed 0
+ // QSizePolicy::Minimum GrowFlag
+ // QSizePolicy::Maximum ShrinkFlag
+ // QSizePolicy::Preferred GrowFlag | ShrinkFlag
+ // QSizePolicy::Ignored GrowFlag | ShrinkFlag | IgnoreFlag
+
+ if (policy & QSizePolicy::ShrinkFlag)
+ *minSize = minSizeHint;
+ else
+ *minSize = prefSizeHint;
+
+ if (policy & QSizePolicy::GrowFlag)
+ *maxSize = maxSizeHint;
+ else
+ *maxSize = prefSizeHint;
+
+ // Note that these two initializations are affected by the previous flags
+ if (policy & QSizePolicy::IgnoreFlag)
+ *prefSize = *minSize;
+ else
+ *prefSize = prefSizeHint;
+}
+
+AnchorData::~AnchorData()
+{
+ if (graphicsAnchor) {
+ // Remove reference to ourself to avoid double removal in
+ // QGraphicsAnchorPrivate dtor.
+ graphicsAnchor->d_func()->data = 0;
+
+ delete graphicsAnchor;
+ }
+}
+
+
+void AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo)
+{
+ QSizePolicy::Policy policy;
+ qreal minSizeHint;
+ qreal prefSizeHint;
+ qreal maxSizeHint;
+
+ if (item) {
+ // It is an internal anchor, fetch size information from the item
+ if (isLayoutAnchor) {
+ minSize = 0;
+ prefSize = 0;
+ maxSize = QWIDGETSIZE_MAX;
+ if (isCenterAnchor)
+ maxSize /= 2;
+
+ minPrefSize = prefSize;
+ maxPrefSize = maxSize;
+ return;
+ } else {
+ if (orientation == QGraphicsAnchorLayoutPrivate::Horizontal) {
+ policy = item->sizePolicy().horizontalPolicy();
+ minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width();
+ prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width();
+ maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width();
+ } else {
+ policy = item->sizePolicy().verticalPolicy();
+ minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height();
+ prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height();
+ maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height();
+ }
+
+ if (isCenterAnchor) {
+ minSizeHint /= 2;
+ prefSizeHint /= 2;
+ maxSizeHint /= 2;
+ }
+ }
+ } else {
+ // It is a user-created anchor, fetch size information from the associated QGraphicsAnchor
+ Q_ASSERT(graphicsAnchor);
+ QGraphicsAnchorPrivate *anchorPrivate = graphicsAnchor->d_func();
+
+ // Policy, min and max sizes are straightforward
+ policy = anchorPrivate->sizePolicy;
+ minSizeHint = 0;
+ maxSizeHint = QWIDGETSIZE_MAX;
+
+ // Preferred Size
+ if (anchorPrivate->hasSize) {
+ // Anchor has user-defined size
+ prefSizeHint = anchorPrivate->preferredSize;
+ } else {
+ // Fetch size information from style
+ const Qt::Orientation orient = Qt::Orientation(QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge) + 1);
+ qreal s = styleInfo->defaultSpacing(orient);
+ if (s < 0) {
+ QSizePolicy::ControlType controlTypeFrom = from->m_item->sizePolicy().controlType();
+ QSizePolicy::ControlType controlTypeTo = to->m_item->sizePolicy().controlType();
+ s = styleInfo->perItemSpacing(controlTypeFrom, controlTypeTo, orient);
+
+ // ### Currently we do not support negative anchors inside the graph.
+ // To avoid those being created by a negative style spacing, we must
+ // make this test.
+ if (s < 0)
+ s = 0;
+ }
+ prefSizeHint = s;
+ }
+ }
+
+ // Fill minSize, prefSize and maxSize based on policy and sizeHints
+ applySizePolicy(policy, minSizeHint, prefSizeHint, maxSizeHint,
+ &minSize, &prefSize, &maxSize);
+
+ minPrefSize = prefSize;
+ maxPrefSize = maxSize;
+
+ // Set the anchor effective sizes to preferred.
+ //
+ // Note: The idea here is that all items should remain at their
+ // preferred size unless where that's impossible. In cases where
+ // the item is subject to restrictions (anchored to the layout
+ // edges, for instance), the simplex solver will be run to
+ // recalculate and override the values we set here.
+ sizeAtMinimum = prefSize;
+ sizeAtPreferred = prefSize;
+ sizeAtMaximum = prefSize;
+}
+
+void ParallelAnchorData::updateChildrenSizes()
+{
+ firstEdge->sizeAtMinimum = sizeAtMinimum;
+ firstEdge->sizeAtPreferred = sizeAtPreferred;
+ firstEdge->sizeAtMaximum = sizeAtMaximum;
+
+ if (secondForward()) {
+ secondEdge->sizeAtMinimum = sizeAtMinimum;
+ secondEdge->sizeAtPreferred = sizeAtPreferred;
+ secondEdge->sizeAtMaximum = sizeAtMaximum;
+ } else {
+ secondEdge->sizeAtMinimum = -sizeAtMinimum;
+ secondEdge->sizeAtPreferred = -sizeAtPreferred;
+ secondEdge->sizeAtMaximum = -sizeAtMaximum;
+ }
+
+ firstEdge->updateChildrenSizes();
+ secondEdge->updateChildrenSizes();
+}
+
+/*
+ \internal
+
+ Initialize the parallel anchor size hints using the sizeHint information from
+ its children.
+
+ Note that parallel groups can lead to unfeasibility, so during calculation, we can
+ find out one unfeasibility. Because of that this method return boolean. This can't
+ happen in sequential, so there the method is void.
+ */
+bool ParallelAnchorData::calculateSizeHints()
+{
+ // Normalize second child sizes.
+ // A negative anchor of sizes min, minPref, pref, maxPref and max, is equivalent
+ // to a forward anchor of sizes -max, -maxPref, -pref, -minPref, -min
+ qreal secondMin;
+ qreal secondMinPref;
+ qreal secondPref;
+ qreal secondMaxPref;
+ qreal secondMax;
+
+ if (secondForward()) {
+ secondMin = secondEdge->minSize;
+ secondMinPref = secondEdge->minPrefSize;
+ secondPref = secondEdge->prefSize;
+ secondMaxPref = secondEdge->maxPrefSize;
+ secondMax = secondEdge->maxSize;
+ } else {
+ secondMin = -secondEdge->maxSize;
+ secondMinPref = -secondEdge->maxPrefSize;
+ secondPref = -secondEdge->prefSize;
+ secondMaxPref = -secondEdge->minPrefSize;
+ secondMax = -secondEdge->minSize;
+ }
+
+ minSize = qMax(firstEdge->minSize, secondMin);
+ maxSize = qMin(firstEdge->maxSize, secondMax);
+
+ // This condition means that the maximum size of one anchor being simplified is smaller than
+ // the minimum size of the other anchor. The consequence is that there won't be a valid size
+ // for this parallel setup.
+ if (minSize > maxSize) {
+ return false;
+ }
+
+ // Preferred size calculation
+ // The calculation of preferred size is done as follows:
+ //
+ // 1) Check whether one of the child anchors is the layout structural anchor
+ // If so, we can simply copy the preferred information from the other child,
+ // after bounding it to our minimum and maximum sizes.
+ // If not, then we proceed with the actual calculations.
+ //
+ // 2) The whole algorithm for preferred size calculation is based on the fact
+ // that, if a given anchor cannot remain at its preferred size, it'd rather
+ // grow than shrink.
+ //
+ // What happens though is that while this affirmative is true for simple
+ // anchors, it may not be true for sequential anchors that have one or more
+ // reversed anchors inside it. That happens because when a sequential anchor
+ // grows, any reversed anchors inside it may be required to shrink, something
+ // we try to avoid, as said above.
+ //
+ // To overcome this, besides their actual preferred size "prefSize", each anchor
+ // exports what we call "minPrefSize" and "maxPrefSize". These two values define
+ // a surrounding interval where, if required to move, the anchor would rather
+ // remain inside.
+ //
+ // For standard anchors, this area simply represents the region between
+ // prefSize and maxSize, which makes sense since our first affirmation.
+ // For composed anchors, these values are calculated as to reduce the global
+ // "damage", that is, to reduce the total deviation and the total amount of
+ // anchors that had to shrink.
+
+ if (firstEdge->isLayoutAnchor) {
+ prefSize = qBound(minSize, secondPref, maxSize);
+ minPrefSize = qBound(minSize, secondMinPref, maxSize);
+ maxPrefSize = qBound(minSize, secondMaxPref, maxSize);
+ } else if (secondEdge->isLayoutAnchor) {
+ prefSize = qBound(minSize, firstEdge->prefSize, maxSize);
+ minPrefSize = qBound(minSize, firstEdge->minPrefSize, maxSize);
+ maxPrefSize = qBound(minSize, firstEdge->maxPrefSize, maxSize);
+ } else {
+ // Calculate the intersection between the "preferred" regions of each child
+ const qreal lowerBoundary =
+ qBound(minSize, qMax(firstEdge->minPrefSize, secondMinPref), maxSize);
+ const qreal upperBoundary =
+ qBound(minSize, qMin(firstEdge->maxPrefSize, secondMaxPref), maxSize);
+ const qreal prefMean =
+ qBound(minSize, (firstEdge->prefSize + secondPref) / 2, maxSize);
+
+ if (lowerBoundary < upperBoundary) {
+ // If there is an intersection between the two regions, this intersection
+ // will be used as the preferred region of the parallel anchor itself.
+ // The preferred size will be the bounded average between the two preferred
+ // sizes.
+ prefSize = qBound(lowerBoundary, prefMean, upperBoundary);
+ minPrefSize = lowerBoundary;
+ maxPrefSize = upperBoundary;
+ } else {
+ // If there is no intersection, we have to attribute "damage" to at least
+ // one of the children. The minimum total damage is achieved in points
+ // inside the region that extends from (1) the upper boundary of the lower
+ // region to (2) the lower boundary of the upper region.
+ // Then, we expose this region as _our_ preferred region and once again,
+ // use the bounded average as our preferred size.
+ prefSize = qBound(upperBoundary, prefMean, lowerBoundary);
+ minPrefSize = upperBoundary;
+ maxPrefSize = lowerBoundary;
+ }
+ }
+
+ // See comment in AnchorData::refreshSizeHints() about sizeAt* values
+ sizeAtMinimum = prefSize;
+ sizeAtPreferred = prefSize;
+ sizeAtMaximum = prefSize;
+
+ return true;
+}
+
+/*!
+ \internal
+ returns the factor in the interval [-1, 1].
+ -1 is at Minimum
+ 0 is at Preferred
+ 1 is at Maximum
+*/
+static QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> getFactor(qreal value, qreal min,
+ qreal minPref, qreal pref,
+ qreal maxPref, qreal max)
+{
+ QGraphicsAnchorLayoutPrivate::Interval interval;
+ qreal lower;
+ qreal upper;
+
+ if (value < minPref) {
+ interval = QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred;
+ lower = min;
+ upper = minPref;
+ } else if (value < pref) {
+ interval = QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred;
+ lower = minPref;
+ upper = pref;
+ } else if (value < maxPref) {
+ interval = QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred;
+ lower = pref;
+ upper = maxPref;
+ } else {
+ interval = QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum;
+ lower = maxPref;
+ upper = max;
+ }
+
+ qreal progress;
+ if (upper == lower) {
+ progress = 0;
+ } else {
+ progress = (value - lower) / (upper - lower);
+ }
+
+ return qMakePair(interval, progress);
+}
+
+static qreal interpolate(const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> &factor,
+ qreal min, qreal minPref, qreal pref, qreal maxPref, qreal max)
+{
+ qreal lower;
+ qreal upper;
+
+ switch (factor.first) {
+ case QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred:
+ lower = min;
+ upper = minPref;
+ break;
+ case QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred:
+ lower = minPref;
+ upper = pref;
+ break;
+ case QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred:
+ lower = pref;
+ upper = maxPref;
+ break;
+ case QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum:
+ lower = maxPref;
+ upper = max;
+ break;
+ }
+
+ return lower + factor.second * (upper - lower);
+}
+
+void SequentialAnchorData::updateChildrenSizes()
+{
+ // Band here refers if the value is in the Minimum To Preferred
+ // band (the lower band) or the Preferred To Maximum (the upper band).
+
+ const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> minFactor =
+ getFactor(sizeAtMinimum, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);
+ const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> prefFactor =
+ getFactor(sizeAtPreferred, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);
+ const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> maxFactor =
+ getFactor(sizeAtMaximum, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);
+
+ // XXX This is not safe if Vertex simplification takes place after the sequential
+ // anchor is created. In that case, "prev" will be a group-vertex, different from
+ // "from" or "to", that _contains_ one of them.
+ AnchorVertex *prev = from;
+
+ for (int i = 0; i < m_edges.count(); ++i) {
+ AnchorData *e = m_edges.at(i);
+
+ const bool edgeIsForward = (e->from == prev);
+ if (edgeIsForward) {
+ e->sizeAtMinimum = interpolate(minFactor, e->minSize, e->minPrefSize,
+ e->prefSize, e->maxPrefSize, e->maxSize);
+ e->sizeAtPreferred = interpolate(prefFactor, e->minSize, e->minPrefSize,
+ e->prefSize, e->maxPrefSize, e->maxSize);
+ e->sizeAtMaximum = interpolate(maxFactor, e->minSize, e->minPrefSize,
+ e->prefSize, e->maxPrefSize, e->maxSize);
+ prev = e->to;
+ } else {
+ Q_ASSERT(prev == e->to);
+ e->sizeAtMinimum = interpolate(minFactor, e->maxSize, e->maxPrefSize,
+ e->prefSize, e->minPrefSize, e->minSize);
+ e->sizeAtPreferred = interpolate(prefFactor, e->maxSize, e->maxPrefSize,
+ e->prefSize, e->minPrefSize, e->minSize);
+ e->sizeAtMaximum = interpolate(maxFactor, e->maxSize, e->maxPrefSize,
+ e->prefSize, e->minPrefSize, e->minSize);
+ prev = e->from;
+ }
+
+ e->updateChildrenSizes();
+ }
+}
+
+void SequentialAnchorData::calculateSizeHints()
+{
+ minSize = 0;
+ prefSize = 0;
+ maxSize = 0;
+ minPrefSize = 0;
+ maxPrefSize = 0;
+
+ AnchorVertex *prev = from;
+
+ for (int i = 0; i < m_edges.count(); ++i) {
+ AnchorData *edge = m_edges.at(i);
+
+ const bool edgeIsForward = (edge->from == prev);
+ if (edgeIsForward) {
+ minSize += edge->minSize;
+ prefSize += edge->prefSize;
+ maxSize += edge->maxSize;
+ minPrefSize += edge->minPrefSize;
+ maxPrefSize += edge->maxPrefSize;
+ prev = edge->to;
+ } else {
+ Q_ASSERT(prev == edge->to);
+ minSize -= edge->maxSize;
+ prefSize -= edge->prefSize;
+ maxSize -= edge->minSize;
+ minPrefSize -= edge->maxPrefSize;
+ maxPrefSize -= edge->minPrefSize;
+ prev = edge->from;
+ }
+ }
+
+ // See comment in AnchorData::refreshSizeHints() about sizeAt* values
+ sizeAtMinimum = prefSize;
+ sizeAtPreferred = prefSize;
+ sizeAtMaximum = prefSize;
+}
+
+#ifdef QT_DEBUG
+void AnchorData::dump(int indent) {
+ if (type == Parallel) {
+ qDebug("%*s type: parallel:", indent, "");
+ ParallelAnchorData *p = static_cast<ParallelAnchorData *>(this);
+ p->firstEdge->dump(indent+2);
+ p->secondEdge->dump(indent+2);
+ } else if (type == Sequential) {
+ SequentialAnchorData *s = static_cast<SequentialAnchorData *>(this);
+ int kids = s->m_edges.count();
+ qDebug("%*s type: sequential(%d):", indent, "", kids);
+ for (int i = 0; i < kids; ++i) {
+ s->m_edges.at(i)->dump(indent+2);
+ }
+ } else {
+ qDebug("%*s type: Normal:", indent, "");
+ }
+}
+
+#endif
+
+QSimplexConstraint *GraphPath::constraint(const GraphPath &path) const
+{
+ // Calculate
+ QSet<AnchorData *> cPositives;
+ QSet<AnchorData *> cNegatives;
+ QSet<AnchorData *> intersection;
+
+ cPositives = positives + path.negatives;
+ cNegatives = negatives + path.positives;
+
+ intersection = cPositives & cNegatives;
+
+ cPositives -= intersection;
+ cNegatives -= intersection;
+
+ // Fill
+ QSimplexConstraint *c = new QSimplexConstraint;
+ QSet<AnchorData *>::iterator i;
+ for (i = cPositives.begin(); i != cPositives.end(); ++i)
+ c->variables.insert(*i, 1.0);
+
+ for (i = cNegatives.begin(); i != cNegatives.end(); ++i)
+ c->variables.insert(*i, -1.0);
+
+ return c;
+}
+
+#ifdef QT_DEBUG
+QString GraphPath::toString() const
+{
+ QString string(QLatin1String("Path: "));
+ foreach(AnchorData *edge, positives)
+ string += QString::fromAscii(" (+++) %1").arg(edge->toString());
+
+ foreach(AnchorData *edge, negatives)
+ string += QString::fromAscii(" (---) %1").arg(edge->toString());
+
+ return string;
+}
+#endif
+
+QGraphicsAnchorLayoutPrivate::QGraphicsAnchorLayoutPrivate()
+ : calculateGraphCacheDirty(true), styleInfoDirty(true)
+{
+ for (int i = 0; i < NOrientations; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ sizeHints[i][j] = -1;
+ }
+ interpolationProgress[i] = -1;
+
+ spacings[i] = -1;
+ graphHasConflicts[i] = false;
+
+ layoutFirstVertex[i] = 0;
+ layoutCentralVertex[i] = 0;
+ layoutLastVertex[i] = 0;
+ }
+}
+
+Qt::AnchorPoint QGraphicsAnchorLayoutPrivate::oppositeEdge(Qt::AnchorPoint edge)
+{
+ switch (edge) {
+ case Qt::AnchorLeft:
+ edge = Qt::AnchorRight;
+ break;
+ case Qt::AnchorRight:
+ edge = Qt::AnchorLeft;
+ break;
+ case Qt::AnchorTop:
+ edge = Qt::AnchorBottom;
+ break;
+ case Qt::AnchorBottom:
+ edge = Qt::AnchorTop;
+ break;
+ default:
+ break;
+ }
+ return edge;
+}
+
+
+/*!
+ * \internal
+ *
+ * helper function in order to avoid overflowing anchor sizes
+ * the returned size will never be larger than FLT_MAX
+ *
+ */
+inline static qreal checkAdd(qreal a, qreal b)
+{
+ if (FLT_MAX - b < a)
+ return FLT_MAX;
+ return a + b;
+}
+
+/*!
+ \internal
+
+ Adds \a newAnchor to the graph.
+
+ Returns the newAnchor itself if it could be added without further changes to the graph. If a
+ new parallel anchor had to be created, then returns the new parallel anchor. If a parallel anchor
+ had to be created and it results in an unfeasible setup, \a feasible is set to false, otherwise
+ true.
+
+ Note that in the case a new parallel anchor is created, it might also take over some constraints
+ from its children anchors.
+*/
+AnchorData *QGraphicsAnchorLayoutPrivate::addAnchorMaybeParallel(AnchorData *newAnchor, bool *feasible)
+{
+ Orientation orientation = Orientation(newAnchor->orientation);
+ Graph<AnchorVertex, AnchorData> &g = graph[orientation];
+ *feasible = true;
+
+ // If already exists one anchor where newAnchor is supposed to be, we create a parallel
+ // anchor.
+ if (AnchorData *oldAnchor = g.takeEdge(newAnchor->from, newAnchor->to)) {
+ ParallelAnchorData *parallel = new ParallelAnchorData(oldAnchor, newAnchor);
+
+ // The parallel anchor will "replace" its children anchors in
+ // every center constraint that they appear.
+
+ // ### If the dependent (center) anchors had reference(s) to their constraints, we
+ // could avoid traversing all the itemCenterConstraints.
+ QList<QSimplexConstraint *> &constraints = itemCenterConstraints[orientation];
+
+ AnchorData *children[2] = { oldAnchor, newAnchor };
+ QList<QSimplexConstraint *> *childrenConstraints[2] = { &parallel->m_firstConstraints,
+ &parallel->m_secondConstraints };
+
+ for (int i = 0; i < 2; ++i) {
+ AnchorData *child = children[i];
+ QList<QSimplexConstraint *> *childConstraints = childrenConstraints[i];
+
+ // We need to fix the second child constraints if the parallel group will have the
+ // opposite direction of the second child anchor. For the point of view of external
+ // entities, this anchor was reversed. So if at some point we say that the parallel
+ // has a value of 20, this mean that the second child (when reversed) will be
+ // assigned -20.
+ const bool needsReverse = i == 1 && !parallel->secondForward();
+
+ if (!child->isCenterAnchor)
+ continue;
+
+ parallel->isCenterAnchor = true;
+
+ for (int j = 0; j < constraints.count(); ++j) {
+ QSimplexConstraint *c = constraints[j];
+ if (c->variables.contains(child)) {
+ childConstraints->append(c);
+ qreal v = c->variables.take(child);
+ if (needsReverse)
+ v *= -1;
+ c->variables.insert(parallel, v);
+ }
+ }
+ }
+
+ // At this point we can identify that the parallel anchor is not feasible, e.g. one
+ // anchor minimum size is bigger than the other anchor maximum size.
+ *feasible = parallel->calculateSizeHints();
+ newAnchor = parallel;
+ }
+
+ g.createEdge(newAnchor->from, newAnchor->to, newAnchor);
+ return newAnchor;
+}
+
+/*!
+ \internal
+
+ Takes the sequence of vertices described by (\a before, \a vertices, \a after) and removes
+ all anchors connected to the vertices in \a vertices, returning one simplified anchor between
+ \a before and \a after.
+
+ Note that this function doesn't add the created anchor to the graph. This should be done by
+ the caller.
+*/
+static AnchorData *createSequence(Graph<AnchorVertex, AnchorData> *graph,
+ AnchorVertex *before,
+ const QVector<AnchorVertex*> &vertices,
+ AnchorVertex *after)
+{
+#if defined(QT_DEBUG) && 0
+ QString strVertices;
+ for (int i = 0; i < vertices.count(); ++i) {
+ strVertices += QString::fromAscii("%1 - ").arg(vertices.at(i)->toString());
+ }
+ QString strPath = QString::fromAscii("%1 - %2%3").arg(before->toString(), strVertices, after->toString());
+ qDebug("simplifying [%s] to [%s - %s]", qPrintable(strPath), qPrintable(before->toString()), qPrintable(after->toString()));
+#endif
+
+ AnchorVertex *prev = before;
+ QVector<AnchorData *> edges;
+
+ // Take from the graph, the edges that will be simplificated
+ for (int i = 0; i < vertices.count(); ++i) {
+ AnchorVertex *next = vertices.at(i);
+ AnchorData *ad = graph->takeEdge(prev, next);
+ Q_ASSERT(ad);
+ edges.append(ad);
+ prev = next;
+ }
+
+ // Take the last edge (not covered in the loop above)
+ AnchorData *ad = graph->takeEdge(vertices.last(), after);
+ Q_ASSERT(ad);
+ edges.append(ad);
+
+ // Create sequence
+ SequentialAnchorData *sequence = new SequentialAnchorData(vertices, edges);
+ sequence->from = before;
+ sequence->to = after;
+
+ sequence->calculateSizeHints();
+
+ return sequence;
+}
+
+/*!
+ \internal
+
+ The purpose of this function is to simplify the graph.
+ Simplification serves two purposes:
+ 1. Reduce the number of edges in the graph, (thus the number of variables to the equation
+ solver is reduced, and the solver performs better).
+ 2. Be able to do distribution of sequences of edges more intelligently (esp. with sequential
+ anchors)
+
+ It is essential that it must be possible to restore simplified anchors back to their "original"
+ form. This is done by restoreSimplifiedAnchor().
+
+ There are two types of simplification that can be done:
+ 1. Sequential simplification
+ Sequential simplification means that all sequences of anchors will be merged into one single
+ anchor. Only anhcors that points in the same direction will be merged.
+ 2. Parallel simplification
+ If a simplified sequential anchor is about to be inserted between two vertices in the graph
+ and there already exist an anchor between those two vertices, a parallel anchor will be
+ created that serves as a placeholder for the sequential anchor and the anchor that was
+ already between the two vertices.
+
+ The process of simplification can be described as:
+
+ 1. Simplify all sequences of anchors into one anchor.
+ If no further simplification was done, go to (3)
+ - If there already exist an anchor where the sequential anchor is supposed to be inserted,
+ take that anchor out of the graph
+ - Then create a parallel anchor that holds the sequential anchor and the anchor just taken
+ out of the graph.
+ 2. Go to (1)
+ 3. Done
+
+ When creating the parallel anchors, the algorithm might identify unfeasible situations. In this
+ case the simplification process stops and returns false. Otherwise returns true.
+*/
+bool QGraphicsAnchorLayoutPrivate::simplifyGraph(Orientation orientation)
+{
+ if (items.isEmpty())
+ return true;
+
+#if defined(QT_DEBUG) && 0
+ qDebug("Simplifying Graph for %s",
+ orientation == Horizontal ? "Horizontal" : "Vertical");
+
+ static int count = 0;
+ if (orientation == Horizontal) {
+ count++;
+ dumpGraph(QString::fromAscii("%1-full").arg(count));
+ }
+#endif
+
+ // Vertex simplification
+ if (!simplifyVertices(orientation)) {
+ restoreVertices(orientation);
+ return false;
+ }
+
+ // Anchor simplification
+ bool dirty;
+ bool feasible = true;
+ do {
+ dirty = simplifyGraphIteration(orientation, &feasible);
+ } while (dirty && feasible);
+
+ // Note that if we are not feasible, we fallback and make sure that the graph is fully restored
+ if (!feasible) {
+ restoreSimplifiedGraph(orientation);
+ restoreVertices(orientation);
+ return false;
+ }
+
+#if defined(QT_DEBUG) && 0
+ dumpGraph(QString::fromAscii("%1-simplified-%2").arg(count).arg(
+ QString::fromAscii(orientation == Horizontal ? "Horizontal" : "Vertical")));
+#endif
+
+ return true;
+}
+
+static AnchorVertex *replaceVertex_helper(AnchorData *data, AnchorVertex *oldV, AnchorVertex *newV)
+{
+ AnchorVertex *other;
+ if (data->from == oldV) {
+ data->from = newV;
+ other = data->to;
+ } else {
+ data->to = newV;
+ other = data->from;
+ }
+ return other;
+}
+
+bool QGraphicsAnchorLayoutPrivate::replaceVertex(Orientation orientation, AnchorVertex *oldV,
+ AnchorVertex *newV, const QList<AnchorData *> &edges)
+{
+ Graph<AnchorVertex, AnchorData> &g = graph[orientation];
+ bool feasible = true;
+
+ for (int i = 0; i < edges.count(); ++i) {
+ AnchorData *ad = edges[i];
+ AnchorVertex *otherV = replaceVertex_helper(ad, oldV, newV);
+
+#if defined(QT_DEBUG)
+ ad->name = QString::fromAscii("%1 --to--> %2").arg(ad->from->toString()).arg(ad->to->toString());
+#endif
+
+ bool newFeasible;
+ AnchorData *newAnchor = addAnchorMaybeParallel(ad, &newFeasible);
+ feasible &= newFeasible;
+
+ if (newAnchor != ad) {
+ // A parallel was created, we mark that in the list of anchors created by vertex
+ // simplification. This is needed because we want to restore them in a separate step
+ // from the restoration of anchor simplification.
+ anchorsFromSimplifiedVertices[orientation].append(newAnchor);
+ }
+
+ g.takeEdge(oldV, otherV);
+ }
+
+ return feasible;
+}
+
+/*!
+ \internal
+*/
+bool QGraphicsAnchorLayoutPrivate::simplifyVertices(Orientation orientation)
+{
+ Q_Q(QGraphicsAnchorLayout);
+ Graph<AnchorVertex, AnchorData> &g = graph[orientation];
+
+ // We'll walk through vertices
+ QStack<AnchorVertex *> stack;
+ stack.push(layoutFirstVertex[orientation]);
+ QSet<AnchorVertex *> visited;
+
+ while (!stack.isEmpty()) {
+ AnchorVertex *v = stack.pop();
+ visited.insert(v);
+
+ // Each adjacent of 'v' is a possible vertex to be merged. So we traverse all of
+ // them. Since once a merge is made, we might add new adjacents, and we don't want to
+ // pass two times through one adjacent. The 'index' is used to track our position.
+ QList<AnchorVertex *> adjacents = g.adjacentVertices(v);
+ int index = 0;
+
+ while (index < adjacents.count()) {
+ AnchorVertex *next = adjacents.at(index);
+ index++;
+
+ AnchorData *data = g.edgeData(v, next);
+ const bool bothLayoutVertices = v->m_item == q && next->m_item == q;
+ const bool zeroSized = !data->minSize && !data->maxSize;
+
+ if (!bothLayoutVertices && zeroSized) {
+
+ // Create a new vertex pair, note that we keep a list of those vertices so we can
+ // easily process them when restoring the graph.
+ AnchorVertexPair *newV = new AnchorVertexPair(v, next, data);
+ simplifiedVertices[orientation].append(newV);
+
+ // Collect the anchors of both vertices, the new vertex pair will take their place
+ // in those anchors
+ const QList<AnchorVertex *> &vAdjacents = g.adjacentVertices(v);
+ const QList<AnchorVertex *> &nextAdjacents = g.adjacentVertices(next);
+
+ for (int i = 0; i < vAdjacents.count(); ++i) {
+ AnchorVertex *adjacent = vAdjacents.at(i);
+ if (adjacent != next) {
+ AnchorData *ad = g.edgeData(v, adjacent);
+ newV->m_firstAnchors.append(ad);
+ }
+ }
+
+ for (int i = 0; i < nextAdjacents.count(); ++i) {
+ AnchorVertex *adjacent = nextAdjacents.at(i);
+ if (adjacent != v) {
+ AnchorData *ad = g.edgeData(next, adjacent);
+ newV->m_secondAnchors.append(ad);
+
+ // We'll also add new vertices to the adjacent list of the new 'v', to be
+ // created as a vertex pair and replace the current one.
+ if (!adjacents.contains(adjacent))
+ adjacents.append(adjacent);
+ }
+ }
+
+ // ### merge this loop into the ones that calculated m_firstAnchors/m_secondAnchors?
+ // Make newV take the place of v and next
+ bool feasible = replaceVertex(orientation, v, newV, newV->m_firstAnchors);
+ feasible &= replaceVertex(orientation, next, newV, newV->m_secondAnchors);
+
+ // Update the layout vertex information if one of the vertices is a layout vertex.
+ AnchorVertex *layoutVertex = 0;
+ if (v->m_item == q)
+ layoutVertex = v;
+ else if (next->m_item == q)
+ layoutVertex = next;
+
+ if (layoutVertex) {
+ // Layout vertices always have m_item == q...
+ newV->m_item = q;
+ changeLayoutVertex(orientation, layoutVertex, newV);
+ }
+
+ g.takeEdge(v, next);
+
+ // If a non-feasibility is found, we leave early and cancel the simplification
+ if (!feasible)
+ return false;
+
+ v = newV;
+ visited.insert(newV);
+
+ } else if (!visited.contains(next) && !stack.contains(next)) {
+ // If the adjacent is not fit for merge and it wasn't visited by the outermost
+ // loop, we add it to the stack.
+ stack.push(next);
+ }
+ }
+ }
+
+ return true;
+}
+
+/*!
+ \internal
+
+ One iteration of the simplification algorithm. Returns true if another iteration is needed.
+
+ The algorithm walks the graph in depth-first order, and only collects vertices that has two
+ edges connected to it. If the vertex does not have two edges or if it is a layout edge, it
+ will take all the previously collected vertices and try to create a simplified sequential
+ anchor representing all the previously collected vertices. Once the simplified anchor is
+ inserted, the collected list is cleared in order to find the next sequence to simplify.
+
+ Note that there are some catches to this that are not covered by the above explanation, see
+ the function comments for more details.
+*/
+bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutPrivate::Orientation orientation,
+ bool *feasible)
+{
+ Q_Q(QGraphicsAnchorLayout);
+ Graph<AnchorVertex, AnchorData> &g = graph[orientation];
+
+ QSet<AnchorVertex *> visited;
+ QStack<QPair<AnchorVertex *, AnchorVertex *> > stack;
+ stack.push(qMakePair(static_cast<AnchorVertex *>(0), layoutFirstVertex[orientation]));
+ QVector<AnchorVertex*> candidates;
+
+ // Walk depth-first, in the stack we store start of the candidate sequence (beforeSequence)
+ // and the vertex to be visited.
+ while (!stack.isEmpty()) {
+ QPair<AnchorVertex *, AnchorVertex *> pair = stack.pop();
+ AnchorVertex *beforeSequence = pair.first;
+ AnchorVertex *v = pair.second;
+
+ // The basic idea is to determine whether we found an end of sequence,
+ // if that's the case, we stop adding vertices to the candidate list
+ // and do a simplification step.
+ //
+ // A vertex can trigger an end of sequence if
+ // (a) it is a layout vertex, we don't simplify away the layout vertices;
+ // (b) it does not have exactly 2 adjacents;
+ // (c) its next adjacent is already visited (a cycle in the graph).
+ // (d) the next anchor is a center anchor.
+
+ const QList<AnchorVertex *> &adjacents = g.adjacentVertices(v);
+ const bool isLayoutVertex = v->m_item == q;
+ AnchorVertex *afterSequence = v;
+ bool endOfSequence = false;
+
+ //
+ // Identify the end cases.
+ //
+
+ // Identifies cases (a) and (b)
+ endOfSequence = isLayoutVertex || adjacents.count() != 2;
+
+ if (!endOfSequence) {
+ // This is a tricky part. We peek at the next vertex to find out whether
+ //
+ // - we already visited the next vertex (c);
+ // - the next anchor is a center (d).
+ //
+ // Those are needed to identify the remaining end of sequence cases. Note that unlike
+ // (a) and (b), we preempt the end of sequence by looking into the next vertex.
+
+ // Peek at the next vertex
+ AnchorVertex *after;
+ if (candidates.isEmpty())
+ after = (beforeSequence == adjacents.last() ? adjacents.first() : adjacents.last());
+ else
+ after = (candidates.last() == adjacents.last() ? adjacents.first() : adjacents.last());
+
+ // ### At this point we assumed that candidates will not contain 'after', this may not hold
+ // when simplifying FLOATing anchors.
+ Q_ASSERT(!candidates.contains(after));
+
+ const AnchorData *data = g.edgeData(v, after);
+ Q_ASSERT(data);
+ const bool cycleFound = visited.contains(after);
+
+ // Now cases (c) and (d)...
+ endOfSequence = cycleFound || data->isCenterAnchor;
+
+ if (!endOfSequence) {
+ // If it's not an end of sequence, then the vertex didn't trigger neither of the
+ // previously three cases, so it can be added to the candidates list.
+ candidates.append(v);
+ } else if (cycleFound && (beforeSequence != after)) {
+ afterSequence = after;
+ candidates.append(v);
+ }
+ }
+
+ //
+ // Add next non-visited vertices to the stack.
+ //
+ for (int i = 0; i < adjacents.count(); ++i) {
+ AnchorVertex *next = adjacents.at(i);
+ if (visited.contains(next))
+ continue;
+
+ // If current vertex is an end of sequence, and it'll reset the candidates list. So
+ // the next vertices will build candidates lists with the current vertex as 'before'
+ // vertex. If it's not an end of sequence, we keep the original 'before' vertex,
+ // since we are keeping the candidates list.
+ if (endOfSequence)
+ stack.push(qMakePair(v, next));
+ else
+ stack.push(qMakePair(beforeSequence, next));
+ }
+
+ visited.insert(v);
+
+ if (!endOfSequence || candidates.isEmpty())
+ continue;
+
+ //
+ // Create a sequence for (beforeSequence, candidates, afterSequence).
+ //
+
+ // One restriction we have is to not simplify half of an anchor and let the other half
+ // unsimplified. So we remove center edges before and after the sequence.
+ const AnchorData *firstAnchor = g.edgeData(beforeSequence, candidates.first());
+ if (firstAnchor->isCenterAnchor) {
+ beforeSequence = candidates.first();
+ candidates.remove(0);
+
+ // If there's not candidates to be simplified, leave.
+ if (candidates.isEmpty())
+ continue;
+ }
+
+ const AnchorData *lastAnchor = g.edgeData(candidates.last(), afterSequence);
+ if (lastAnchor->isCenterAnchor) {
+ afterSequence = candidates.last();
+ candidates.remove(candidates.count() - 1);
+
+ if (candidates.isEmpty())
+ continue;
+ }
+
+ //
+ // Add the sequence to the graph.
+ //
+
+ AnchorData *sequence = createSequence(&g, beforeSequence, candidates, afterSequence);
+
+ // If 'beforeSequence' and 'afterSequence' already had an anchor between them, we'll
+ // create a parallel anchor between the new sequence and the old anchor.
+ bool newFeasible;
+ AnchorData *newAnchor = addAnchorMaybeParallel(sequence, &newFeasible);
+
+ if (!newFeasible) {
+ *feasible = false;
+ return false;
+ }
+
+ // When a new parallel anchor is create in the graph, we finish the iteration and return
+ // true to indicate a new iteration is needed. This happens because a parallel anchor
+ // changes the number of adjacents one vertex has, possibly opening up oportunities for
+ // building candidate lists (when adjacents == 2).
+ if (newAnchor != sequence)
+ return true;
+
+ // If there was no parallel simplification, we'll keep walking the graph. So we clear the
+ // candidates list to start again.
+ candidates.clear();
+ }
+
+ return false;
+}
+
+void QGraphicsAnchorLayoutPrivate::restoreSimplifiedAnchor(AnchorData *edge)
+{
+#if 0
+ static const char *anchortypes[] = {"Normal",
+ "Sequential",
+ "Parallel"};
+ qDebug("Restoring %s edge.", anchortypes[int(edge->type)]);
+#endif
+
+ Graph<AnchorVertex, AnchorData> &g = graph[edge->orientation];
+
+ if (edge->type == AnchorData::Normal) {
+ g.createEdge(edge->from, edge->to, edge);
+
+ } else if (edge->type == AnchorData::Sequential) {
+ SequentialAnchorData *sequence = static_cast<SequentialAnchorData *>(edge);
+
+ for (int i = 0; i < sequence->m_edges.count(); ++i) {
+ AnchorData *data = sequence->m_edges.at(i);
+ restoreSimplifiedAnchor(data);
+ }
+
+ delete sequence;
+
+ } else if (edge->type == AnchorData::Parallel) {
+
+ // Skip parallel anchors that were created by vertex simplification, they will be processed
+ // later, when restoring vertex simplification.
+ // ### we could improve this check bit having a bit inside 'edge'
+ if (anchorsFromSimplifiedVertices[edge->orientation].contains(edge))
+ return;
+
+ ParallelAnchorData* parallel = static_cast<ParallelAnchorData*>(edge);
+ restoreSimplifiedConstraints(parallel);
+
+ // ### Because of the way parallel anchors are created in the anchor simplification
+ // algorithm, we know that one of these will be a sequence, so it'll be safe if the other
+ // anchor create an edge between the same vertices as the parallel.
+ Q_ASSERT(parallel->firstEdge->type == AnchorData::Sequential
+ || parallel->secondEdge->type == AnchorData::Sequential);
+ restoreSimplifiedAnchor(parallel->firstEdge);
+ restoreSimplifiedAnchor(parallel->secondEdge);
+
+ delete parallel;
+ }
+}
+
+void QGraphicsAnchorLayoutPrivate::restoreSimplifiedConstraints(ParallelAnchorData *parallel)
+{
+ if (!parallel->isCenterAnchor)
+ return;
+
+ for (int i = 0; i < parallel->m_firstConstraints.count(); ++i) {
+ QSimplexConstraint *c = parallel->m_firstConstraints.at(i);
+ qreal v = c->variables[parallel];
+ c->variables.remove(parallel);
+ c->variables.insert(parallel->firstEdge, v);
+ }
+
+ // When restoring, we might have to revert constraints back. See comments on
+ // addAnchorMaybeParallel().
+ const bool needsReverse = !parallel->secondForward();
+
+ for (int i = 0; i < parallel->m_secondConstraints.count(); ++i) {
+ QSimplexConstraint *c = parallel->m_secondConstraints.at(i);
+ qreal v = c->variables[parallel];
+ if (needsReverse)
+ v *= -1;
+ c->variables.remove(parallel);
+ c->variables.insert(parallel->secondEdge, v);
+ }
+}
+
+void QGraphicsAnchorLayoutPrivate::restoreSimplifiedGraph(Orientation orientation)
+{
+#if 0
+ qDebug("Restoring Simplified Graph for %s",
+ orientation == Horizontal ? "Horizontal" : "Vertical");
+#endif
+
+ // Restore anchor simplification
+ Graph<AnchorVertex, AnchorData> &g = graph[orientation];
+ QList<QPair<AnchorVertex*, AnchorVertex*> > connections = g.connections();
+ for (int i = 0; i < connections.count(); ++i) {
+ AnchorVertex *v1 = connections.at(i).first;
+ AnchorVertex *v2 = connections.at(i).second;
+ AnchorData *edge = g.edgeData(v1, v2);
+
+ // We restore only sequential anchors and parallels that were not created by
+ // vertex simplification.
+ if (edge->type == AnchorData::Sequential
+ || (edge->type == AnchorData::Parallel &&
+ !anchorsFromSimplifiedVertices[orientation].contains(edge))) {
+
+ g.takeEdge(v1, v2);
+ restoreSimplifiedAnchor(edge);
+ }
+ }
+
+ restoreVertices(orientation);
+}
+
+void QGraphicsAnchorLayoutPrivate::restoreVertices(Orientation orientation)
+{
+ Q_Q(QGraphicsAnchorLayout);
+
+ Graph<AnchorVertex, AnchorData> &g = graph[orientation];
+ QList<AnchorVertexPair *> &toRestore = simplifiedVertices[orientation];
+
+ // Since we keep a list of parallel anchors and vertices that were created during vertex
+ // simplification, we can now iterate on those lists instead of traversing the graph
+ // recursively.
+
+ // First, restore the constraints changed when we created parallel anchors. Note that this
+ // works at this point because the constraints doesn't depend on vertex information and at
+ // this point it's always safe to identify whether the second child is forward or backwards.
+ // In the next step, we'll change the anchors vertices so that would not be possible anymore.
+ QList<AnchorData *> &parallelAnchors = anchorsFromSimplifiedVertices[orientation];
+
+ for (int i = parallelAnchors.count() - 1; i >= 0; --i) {
+ ParallelAnchorData *parallel = static_cast<ParallelAnchorData *>(parallelAnchors.at(i));
+ restoreSimplifiedConstraints(parallel);
+ }
+
+ // Then, we will restore the vertices in the inverse order of creation, this way we ensure that
+ // the vertex being restored was not wrapped by another simplification.
+ for (int i = toRestore.count() - 1; i >= 0; --i) {
+ AnchorVertexPair *pair = toRestore.at(i);
+ QList<AnchorVertex *> adjacents = g.adjacentVertices(pair);
+
+ // Restore the removed edge, this will also restore both vertices 'first' and 'second' to
+ // the graph structure.
+ AnchorVertex *first = pair->m_first;
+ AnchorVertex *second = pair->m_second;
+ g.createEdge(first, second, pair->m_removedAnchor);
+
+ // Restore the anchors for the first child vertex
+ for (int j = 0; j < pair->m_firstAnchors.count(); ++j) {
+ AnchorData *ad = pair->m_firstAnchors.at(j);
+ Q_ASSERT(ad->from == pair || ad->to == pair);
+
+ replaceVertex_helper(ad, pair, first);
+ g.createEdge(ad->from, ad->to, ad);
+ }
+
+ // Restore the anchors for the second child vertex
+ for (int j = 0; j < pair->m_secondAnchors.count(); ++j) {
+ AnchorData *ad = pair->m_secondAnchors.at(j);
+ Q_ASSERT(ad->from == pair || ad->to == pair);
+
+ replaceVertex_helper(ad, pair, second);
+ g.createEdge(ad->from, ad->to, ad);
+ }
+
+ for (int j = 0; j < adjacents.count(); ++j) {
+ g.takeEdge(pair, adjacents.at(j));
+ }
+
+ // The pair simplified a layout vertex, so place back the correct vertex in the variable
+ // that track layout vertices
+ if (pair->m_item == q) {
+ AnchorVertex *layoutVertex = first->m_item == q ? first : second;
+ Q_ASSERT(layoutVertex->m_item == q);
+ changeLayoutVertex(orientation, pair, layoutVertex);
+ }
+
+ delete pair;
+ }
+ qDeleteAll(parallelAnchors);
+ parallelAnchors.clear();
+ toRestore.clear();
+}
+
+QGraphicsAnchorLayoutPrivate::Orientation
+QGraphicsAnchorLayoutPrivate::edgeOrientation(Qt::AnchorPoint edge)
+{
+ return edge > Qt::AnchorRight ? Vertical : Horizontal;
+}
+
+/*!
+ \internal
+
+ Create internal anchors to connect the layout edges (Left to Right and
+ Top to Bottom).
+
+ These anchors doesn't have size restrictions, that will be enforced by
+ other anchors and items in the layout.
+*/
+void QGraphicsAnchorLayoutPrivate::createLayoutEdges()
+{
+ Q_Q(QGraphicsAnchorLayout);
+ QGraphicsLayoutItem *layout = q;
+
+ // Horizontal
+ AnchorData *data = new AnchorData;
+ addAnchor_helper(layout, Qt::AnchorLeft, layout,
+ Qt::AnchorRight, data);
+ data->maxSize = QWIDGETSIZE_MAX;
+
+ // Save a reference to layout vertices
+ layoutFirstVertex[Horizontal] = internalVertex(layout, Qt::AnchorLeft);
+ layoutCentralVertex[Horizontal] = 0;
+ layoutLastVertex[Horizontal] = internalVertex(layout, Qt::AnchorRight);
+
+ // Vertical
+ data = new AnchorData;
+ addAnchor_helper(layout, Qt::AnchorTop, layout,
+ Qt::AnchorBottom, data);
+ data->maxSize = QWIDGETSIZE_MAX;
+
+ // Save a reference to layout vertices
+ layoutFirstVertex[Vertical] = internalVertex(layout, Qt::AnchorTop);
+ layoutCentralVertex[Vertical] = 0;
+ layoutLastVertex[Vertical] = internalVertex(layout, Qt::AnchorBottom);
+}
+
+void QGraphicsAnchorLayoutPrivate::deleteLayoutEdges()
+{
+ Q_Q(QGraphicsAnchorLayout);
+
+ Q_ASSERT(!internalVertex(q, Qt::AnchorHorizontalCenter));
+ Q_ASSERT(!internalVertex(q, Qt::AnchorVerticalCenter));
+
+ removeAnchor_helper(internalVertex(q, Qt::AnchorLeft),
+ internalVertex(q, Qt::AnchorRight));
+ removeAnchor_helper(internalVertex(q, Qt::AnchorTop),
+ internalVertex(q, Qt::AnchorBottom));
+}
+
+void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item)
+{
+ items.append(item);
+
+ // Create horizontal and vertical internal anchors for the item and
+ // refresh its size hint / policy values.
+ AnchorData *data = new AnchorData;
+ addAnchor_helper(item, Qt::AnchorLeft, item, Qt::AnchorRight, data);
+ data->refreshSizeHints();
+
+ data = new AnchorData;
+ addAnchor_helper(item, Qt::AnchorTop, item, Qt::AnchorBottom, data);
+ data->refreshSizeHints();
+}
+
+/*!
+ \internal
+
+ By default, each item in the layout is represented internally as
+ a single anchor in each direction. For instance, from Left to Right.
+
+ However, to support anchorage of items to the center of items, we
+ must split this internal anchor into two half-anchors. From Left
+ to Center and then from Center to Right, with the restriction that
+ these anchors must have the same time at all times.
+*/
+void QGraphicsAnchorLayoutPrivate::createCenterAnchors(
+ QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge)
+{
+ Q_Q(QGraphicsAnchorLayout);
+
+ Orientation orientation;
+ switch (centerEdge) {
+ case Qt::AnchorHorizontalCenter:
+ orientation = Horizontal;
+ break;
+ case Qt::AnchorVerticalCenter:
+ orientation = Vertical;
+ break;
+ default:
+ // Don't create center edges unless needed
+ return;
+ }
+
+ // Check if vertex already exists
+ if (internalVertex(item, centerEdge))
+ return;
+
+ // Orientation code
+ Qt::AnchorPoint firstEdge;
+ Qt::AnchorPoint lastEdge;
+
+ if (orientation == Horizontal) {
+ firstEdge = Qt::AnchorLeft;
+ lastEdge = Qt::AnchorRight;
+ } else {
+ firstEdge = Qt::AnchorTop;
+ lastEdge = Qt::AnchorBottom;
+ }
+
+ AnchorVertex *first = internalVertex(item, firstEdge);
+ AnchorVertex *last = internalVertex(item, lastEdge);
+ Q_ASSERT(first && last);
+
+ // Create new anchors
+ QSimplexConstraint *c = new QSimplexConstraint;
+
+ AnchorData *data = new AnchorData;
+ c->variables.insert(data, 1.0);
+ addAnchor_helper(item, firstEdge, item, centerEdge, data);
+ data->isCenterAnchor = true;
+ data->dependency = AnchorData::Master;
+ data->refreshSizeHints();
+
+ data = new AnchorData;
+ c->variables.insert(data, -1.0);
+ addAnchor_helper(item, centerEdge, item, lastEdge, data);
+ data->isCenterAnchor = true;
+ data->dependency = AnchorData::Slave;
+ data->refreshSizeHints();
+
+ itemCenterConstraints[orientation].append(c);
+
+ // Remove old one
+ removeAnchor_helper(first, last);
+
+ if (item == q) {
+ layoutCentralVertex[orientation] = internalVertex(q, centerEdge);
+ }
+}
+
+void QGraphicsAnchorLayoutPrivate::removeCenterAnchors(
+ QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge,
+ bool substitute)
+{
+ Q_Q(QGraphicsAnchorLayout);
+
+ Orientation orientation;
+ switch (centerEdge) {
+ case Qt::AnchorHorizontalCenter:
+ orientation = Horizontal;
+ break;
+ case Qt::AnchorVerticalCenter:
+ orientation = Vertical;
+ break;
+ default:
+ // Don't remove edges that not the center ones
+ return;
+ }
+
+ // Orientation code
+ Qt::AnchorPoint firstEdge;
+ Qt::AnchorPoint lastEdge;
+
+ if (orientation == Horizontal) {
+ firstEdge = Qt::AnchorLeft;
+ lastEdge = Qt::AnchorRight;
+ } else {
+ firstEdge = Qt::AnchorTop;
+ lastEdge = Qt::AnchorBottom;
+ }
+
+ AnchorVertex *center = internalVertex(item, centerEdge);
+ if (!center)
+ return;
+ AnchorVertex *first = internalVertex(item, firstEdge);
+
+ Q_ASSERT(first);
+ Q_ASSERT(center);
+
+ Graph<AnchorVertex, AnchorData> &g = graph[orientation];
+
+
+ AnchorData *oldData = g.edgeData(first, center);
+ // Remove center constraint
+ for (int i = itemCenterConstraints[orientation].count() - 1; i >= 0; --i) {
+ if (itemCenterConstraints[orientation].at(i)->variables.contains(oldData)) {
+ delete itemCenterConstraints[orientation].takeAt(i);
+ break;
+ }
+ }
+
+ if (substitute) {
+ // Create the new anchor that should substitute the left-center-right anchors.
+ AnchorData *data = new AnchorData;
+ addAnchor_helper(item, firstEdge, item, lastEdge, data);
+ data->refreshSizeHints();
+
+ // Remove old anchors
+ removeAnchor_helper(first, center);
+ removeAnchor_helper(center, internalVertex(item, lastEdge));
+
+ } else {
+ // this is only called from removeAnchors()
+ // first, remove all non-internal anchors
+ QList<AnchorVertex*> adjacents = g.adjacentVertices(center);
+ for (int i = 0; i < adjacents.count(); ++i) {
+ AnchorVertex *v = adjacents.at(i);
+ if (v->m_item != item) {
+ removeAnchor_helper(center, internalVertex(v->m_item, v->m_edge));
+ }
+ }
+ // when all non-internal anchors is removed it will automatically merge the
+ // center anchor into a left-right (or top-bottom) anchor. We must also delete that.
+ // by this time, the center vertex is deleted and merged into a non-centered internal anchor
+ removeAnchor_helper(first, internalVertex(item, lastEdge));
+ }
+
+ if (item == q) {
+ layoutCentralVertex[orientation] = 0;
+ }
+}
+
+
+void QGraphicsAnchorLayoutPrivate::removeCenterConstraints(QGraphicsLayoutItem *item,
+ Orientation orientation)
+{
+ // Remove the item center constraints associated to this item
+ // ### This is a temporary solution. We should probably use a better
+ // data structure to hold items and/or their associated constraints
+ // so that we can remove those easily
+
+ AnchorVertex *first = internalVertex(item, orientation == Horizontal ?
+ Qt::AnchorLeft :
+ Qt::AnchorTop);
+ AnchorVertex *center = internalVertex(item, orientation == Horizontal ?
+ Qt::AnchorHorizontalCenter :
+ Qt::AnchorVerticalCenter);
+
+ // Skip if no center constraints exist
+ if (!center)
+ return;
+
+ Q_ASSERT(first);
+ AnchorData *internalAnchor = graph[orientation].edgeData(first, center);
+
+ // Look for our anchor in all item center constraints, then remove it
+ for (int i = 0; i < itemCenterConstraints[orientation].size(); ++i) {
+ if (itemCenterConstraints[orientation].at(i)->variables.contains(internalAnchor)) {
+ delete itemCenterConstraints[orientation].takeAt(i);
+ break;
+ }
+ }
+}
+
+/*!
+ * \internal
+ * Implements the high level "addAnchor" feature. Called by the public API
+ * addAnchor method.
+ *
+ * The optional \a spacing argument defines the size of the anchor. If not provided,
+ * the anchor size is either 0 or not-set, depending on type of anchor created (see
+ * matrix below).
+ *
+ * All anchors that remain with size not-set will assume the standard spacing,
+ * set either by the layout style or through the "setSpacing" layout API.
+ */
+QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *firstItem,
+ Qt::AnchorPoint firstEdge,
+ QGraphicsLayoutItem *secondItem,
+ Qt::AnchorPoint secondEdge,
+ qreal *spacing)
+{
+ Q_Q(QGraphicsAnchorLayout);
+ if ((firstItem == 0) || (secondItem == 0)) {
+ qWarning("QGraphicsAnchorLayout::addAnchor(): "
+ "Cannot anchor NULL items");
+ return 0;
+ }
+
+ if (firstItem == secondItem) {
+ qWarning("QGraphicsAnchorLayout::addAnchor(): "
+ "Cannot anchor the item to itself");
+ return 0;
+ }
+
+ if (edgeOrientation(secondEdge) != edgeOrientation(firstEdge)) {
+ qWarning("QGraphicsAnchorLayout::addAnchor(): "
+ "Cannot anchor edges of different orientations");
+ return 0;
+ }
+
+ const QGraphicsLayoutItem *parentWidget = q->parentLayoutItem();
+ if (firstItem == parentWidget || secondItem == parentWidget) {
+ qWarning("QGraphicsAnchorLayout::addAnchor(): "
+ "You cannot add the parent of the layout to the layout.");
+ return 0;
+ }
+
+ // In QGraphicsAnchorLayout, items are represented in its internal
+ // graph as four anchors that connect:
+ // - Left -> HCenter
+ // - HCenter-> Right
+ // - Top -> VCenter
+ // - VCenter -> Bottom
+
+ // Ensure that the internal anchors have been created for both items.
+ if (firstItem != q && !items.contains(firstItem)) {
+ createItemEdges(firstItem);
+ addChildLayoutItem(firstItem);
+ }
+ if (secondItem != q && !items.contains(secondItem)) {
+ createItemEdges(secondItem);
+ addChildLayoutItem(secondItem);
+ }
+
+ // Create center edges if needed
+ createCenterAnchors(firstItem, firstEdge);
+ createCenterAnchors(secondItem, secondEdge);
+
+ // Use heuristics to find out what the user meant with this anchor.
+ correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge);
+
+ AnchorData *data = new AnchorData;
+ QGraphicsAnchor *graphicsAnchor = acquireGraphicsAnchor(data);
+
+ addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data);
+
+ if (spacing) {
+ graphicsAnchor->setSpacing(*spacing);
+ } else {
+ // If firstItem or secondItem is the layout itself, the spacing will default to 0.
+ // Otherwise, the following matrix is used (questionmark means that the spacing
+ // is queried from the style):
+ // from
+ // to Left HCenter Right
+ // Left 0 0 ?
+ // HCenter 0 0 0
+ // Right ? 0 0
+ if (firstItem == q
+ || secondItem == q
+ || pickEdge(firstEdge, Horizontal) == Qt::AnchorHorizontalCenter
+ || oppositeEdge(firstEdge) != secondEdge) {
+ graphicsAnchor->setSpacing(0);
+ } else {
+ graphicsAnchor->unsetSpacing();
+ }
+ }
+
+ return graphicsAnchor;
+}
+
+/*
+ \internal
+
+ This method adds an AnchorData to the internal graph. It is responsible for doing
+ the boilerplate part of such task.
+
+ If another AnchorData exists between the mentioned vertices, it is deleted and
+ the new one is inserted.
+*/
+void QGraphicsAnchorLayoutPrivate::addAnchor_helper(QGraphicsLayoutItem *firstItem,
+ Qt::AnchorPoint firstEdge,
+ QGraphicsLayoutItem *secondItem,
+ Qt::AnchorPoint secondEdge,
+ AnchorData *data)
+{
+ Q_Q(QGraphicsAnchorLayout);
+
+ const Orientation orientation = edgeOrientation(firstEdge);
+
+ // Create or increase the reference count for the related vertices.
+ AnchorVertex *v1 = addInternalVertex(firstItem, firstEdge);
+ AnchorVertex *v2 = addInternalVertex(secondItem, secondEdge);
+
+ // Remove previous anchor
+ if (graph[orientation].edgeData(v1, v2)) {
+ removeAnchor_helper(v1, v2);
+ }
+
+ // If its an internal anchor, set the associated item
+ if (firstItem == secondItem)
+ data->item = firstItem;
+
+ data->orientation = orientation;
+
+ // Create a bi-directional edge in the sense it can be transversed both
+ // from v1 or v2. "data" however is shared between the two references
+ // so we still know that the anchor direction is from 1 to 2.
+ data->from = v1;
+ data->to = v2;
+#ifdef QT_DEBUG
+ data->name = QString::fromAscii("%1 --to--> %2").arg(v1->toString()).arg(v2->toString());
+#endif
+ // ### bit to track internal anchors, since inside AnchorData methods
+ // we don't have access to the 'q' pointer.
+ data->isLayoutAnchor = (data->item == q);
+
+ graph[orientation].createEdge(v1, v2, data);
+}
+
+QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::getAnchor(QGraphicsLayoutItem *firstItem,
+ Qt::AnchorPoint firstEdge,
+ QGraphicsLayoutItem *secondItem,
+ Qt::AnchorPoint secondEdge)
+{
+ // Do not expose internal anchors
+ if (firstItem == secondItem)
+ return 0;
+
+ const Orientation orientation = edgeOrientation(firstEdge);
+ AnchorVertex *v1 = internalVertex(firstItem, firstEdge);
+ AnchorVertex *v2 = internalVertex(secondItem, secondEdge);
+
+ QGraphicsAnchor *graphicsAnchor = 0;
+
+ AnchorData *data = graph[orientation].edgeData(v1, v2);
+ if (data) {
+ // We could use "acquireGraphicsAnchor" here, but to avoid a regression where
+ // an internal anchor was wrongly exposed, I want to ensure no new
+ // QGraphicsAnchor instances are created by this call.
+ // This assumption must hold because anchors are either user-created (and already
+ // have their public object created), or they are internal (and must not reach
+ // this point).
+ Q_ASSERT(data->graphicsAnchor);
+ graphicsAnchor = data->graphicsAnchor;
+ }
+ return graphicsAnchor;
+}
+
+/*!
+ * \internal
+ *
+ * Implements the high level "removeAnchor" feature. Called by
+ * the QAnchorData destructor.
+ */
+void QGraphicsAnchorLayoutPrivate::removeAnchor(AnchorVertex *firstVertex,
+ AnchorVertex *secondVertex)
+{
+ Q_Q(QGraphicsAnchorLayout);
+
+ // Save references to items while it's safe to assume the vertices exist
+ QGraphicsLayoutItem *firstItem = firstVertex->m_item;
+ QGraphicsLayoutItem *secondItem = secondVertex->m_item;
+
+ // Delete the anchor (may trigger deletion of center vertices)
+ removeAnchor_helper(firstVertex, secondVertex);
+
+ // Ensure no dangling pointer is left behind
+ firstVertex = secondVertex = 0;
+
+ // Checking if the item stays in the layout or not
+ bool keepFirstItem = false;
+ bool keepSecondItem = false;
+
+ QPair<AnchorVertex *, int> v;
+ int refcount = -1;
+
+ if (firstItem != q) {
+ for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) {
+ v = m_vertexList.value(qMakePair(firstItem, static_cast<Qt::AnchorPoint>(i)));
+ if (v.first) {
+ if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter)
+ refcount = 2;
+ else
+ refcount = 1;
+
+ if (v.second > refcount) {
+ keepFirstItem = true;
+ break;
+ }
+ }
+ }
+ } else
+ keepFirstItem = true;
+
+ if (secondItem != q) {
+ for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) {
+ v = m_vertexList.value(qMakePair(secondItem, static_cast<Qt::AnchorPoint>(i)));
+ if (v.first) {
+ if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter)
+ refcount = 2;
+ else
+ refcount = 1;
+
+ if (v.second > refcount) {
+ keepSecondItem = true;
+ break;
+ }
+ }
+ }
+ } else
+ keepSecondItem = true;
+
+ if (!keepFirstItem)
+ q->removeAt(items.indexOf(firstItem));
+
+ if (!keepSecondItem)
+ q->removeAt(items.indexOf(secondItem));
+
+ // Removing anchors invalidates the layout
+ q->invalidate();
+}
+
+/*
+ \internal
+
+ Implements the low level "removeAnchor" feature. Called by
+ private methods.
+*/
+void QGraphicsAnchorLayoutPrivate::removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2)
+{
+ Q_ASSERT(v1 && v2);
+
+ // Remove edge from graph
+ const Orientation o = edgeOrientation(v1->m_edge);
+ graph[o].removeEdge(v1, v2);
+
+ // Decrease vertices reference count (may trigger a deletion)
+ removeInternalVertex(v1->m_item, v1->m_edge);
+ removeInternalVertex(v2->m_item, v2->m_edge);
+}
+
+AnchorVertex *QGraphicsAnchorLayoutPrivate::addInternalVertex(QGraphicsLayoutItem *item,
+ Qt::AnchorPoint edge)
+{
+ QPair<QGraphicsLayoutItem *, Qt::AnchorPoint> pair(item, edge);
+ QPair<AnchorVertex *, int> v = m_vertexList.value(pair);
+
+ if (!v.first) {
+ Q_ASSERT(v.second == 0);
+ v.first = new AnchorVertex(item, edge);
+ }
+ v.second++;
+ m_vertexList.insert(pair, v);
+ return v.first;
+}
+
+/**
+ * \internal
+ *
+ * returns the AnchorVertex that was dereferenced, also when it was removed.
+ * returns 0 if it did not exist.
+ */
+void QGraphicsAnchorLayoutPrivate::removeInternalVertex(QGraphicsLayoutItem *item,
+ Qt::AnchorPoint edge)
+{
+ QPair<QGraphicsLayoutItem *, Qt::AnchorPoint> pair(item, edge);
+ QPair<AnchorVertex *, int> v = m_vertexList.value(pair);
+
+ if (!v.first) {
+ qWarning("This item with this edge is not in the graph");
+ return;
+ }
+
+ v.second--;
+ if (v.second == 0) {
+ // Remove reference and delete vertex
+ m_vertexList.remove(pair);
+ delete v.first;
+ } else {
+ // Update reference count
+ m_vertexList.insert(pair, v);
+
+ if ((v.second == 2) &&
+ ((edge == Qt::AnchorHorizontalCenter) ||
+ (edge == Qt::AnchorVerticalCenter))) {
+ removeCenterAnchors(item, edge, true);
+ }
+ }
+}
+
+void QGraphicsAnchorLayoutPrivate::removeVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge)
+{
+ if (AnchorVertex *v = internalVertex(item, edge)) {
+ Graph<AnchorVertex, AnchorData> &g = graph[edgeOrientation(edge)];
+ const QList<AnchorVertex *> allVertices = graph[edgeOrientation(edge)].adjacentVertices(v);
+ AnchorVertex *v2;
+ foreach (v2, allVertices) {
+ g.removeEdge(v, v2);
+ removeInternalVertex(item, edge);
+ removeInternalVertex(v2->m_item, v2->m_edge);
+ }
+ }
+}
+
+void QGraphicsAnchorLayoutPrivate::removeAnchors(QGraphicsLayoutItem *item)
+{
+ // remove the center anchor first!!
+ removeCenterAnchors(item, Qt::AnchorHorizontalCenter, false);
+ removeVertex(item, Qt::AnchorLeft);
+ removeVertex(item, Qt::AnchorRight);
+
+ removeCenterAnchors(item, Qt::AnchorVerticalCenter, false);
+ removeVertex(item, Qt::AnchorTop);
+ removeVertex(item, Qt::AnchorBottom);
+}
+
+/*!
+ \internal
+
+ Use heuristics to determine the correct orientation of a given anchor.
+
+ After API discussions, we decided we would like expressions like
+ anchor(A, Left, B, Right) to mean the same as anchor(B, Right, A, Left).
+ The problem with this is that anchors could become ambiguous, for
+ instance, what does the anchor A, B of size X mean?
+
+ "pos(B) = pos(A) + X" or "pos(A) = pos(B) + X" ?
+
+ To keep the API user friendly and at the same time, keep our algorithm
+ deterministic, we use an heuristic to determine a direction for each
+ added anchor and then keep it. The heuristic is based on the fact
+ that people usually avoid overlapping items, therefore:
+
+ "A, RIGHT to B, LEFT" means that B is to the LEFT of A.
+ "B, LEFT to A, RIGHT" is corrected to the above anchor.
+
+ Special correction is also applied when one of the items is the
+ layout. We handle Layout Left as if it was another items's Right
+ and Layout Right as another item's Left.
+*/
+void QGraphicsAnchorLayoutPrivate::correctEdgeDirection(QGraphicsLayoutItem *&firstItem,
+ Qt::AnchorPoint &firstEdge,
+ QGraphicsLayoutItem *&secondItem,
+ Qt::AnchorPoint &secondEdge)
+{
+ Q_Q(QGraphicsAnchorLayout);
+
+ if ((firstItem != q) && (secondItem != q)) {
+ // If connection is between widgets (not the layout itself)
+ // Ensure that "right-edges" sit to the left of "left-edges".
+ if (firstEdge < secondEdge) {
+ qSwap(firstItem, secondItem);
+ qSwap(firstEdge, secondEdge);
+ }
+ } else if (firstItem == q) {
+ // If connection involves the right or bottom of a layout, ensure
+ // the layout is the second item.
+ if ((firstEdge == Qt::AnchorRight) || (firstEdge == Qt::AnchorBottom)) {
+ qSwap(firstItem, secondItem);
+ qSwap(firstEdge, secondEdge);
+ }
+ } else if ((secondEdge != Qt::AnchorRight) && (secondEdge != Qt::AnchorBottom)) {
+ // If connection involves the left, center or top of layout, ensure
+ // the layout is the first item.
+ qSwap(firstItem, secondItem);
+ qSwap(firstEdge, secondEdge);
+ }
+}
+
+QLayoutStyleInfo &QGraphicsAnchorLayoutPrivate::styleInfo() const
+{
+ if (styleInfoDirty) {
+ Q_Q(const QGraphicsAnchorLayout);
+ //### Fix this if QGV ever gets support for Metal style or different Aqua sizes.
+ QWidget *wid = 0;
+
+ QGraphicsLayoutItem *parent = q->parentLayoutItem();
+ while (parent && parent->isLayout()) {
+ parent = parent->parentLayoutItem();
+ }
+ QGraphicsWidget *w = 0;
+ if (parent) {
+ QGraphicsItem *parentItem = parent->graphicsItem();
+ if (parentItem && parentItem->isWidget())
+ w = static_cast<QGraphicsWidget*>(parentItem);
+ }
+
+ QStyle *style = w ? w->style() : QApplication::style();
+ cachedStyleInfo = QLayoutStyleInfo(style, wid);
+ cachedStyleInfo.setDefaultSpacing(Qt::Horizontal, spacings[0]);
+ cachedStyleInfo.setDefaultSpacing(Qt::Vertical, spacings[1]);
+
+ styleInfoDirty = false;
+ }
+ return cachedStyleInfo;
+}
+
+/*!
+ \internal
+
+ Called on activation. Uses Linear Programming to define minimum, preferred
+ and maximum sizes for the layout. Also calculates the sizes that each item
+ should assume when the layout is in one of such situations.
+*/
+void QGraphicsAnchorLayoutPrivate::calculateGraphs()
+{
+ if (!calculateGraphCacheDirty)
+ return;
+ calculateGraphs(Horizontal);
+ calculateGraphs(Vertical);
+ calculateGraphCacheDirty = false;
+}
+
+// ### Maybe getGraphParts could return the variables when traversing, at least
+// for trunk...
+QList<AnchorData *> getVariables(QList<QSimplexConstraint *> constraints)
+{
+ QSet<AnchorData *> variableSet;
+ for (int i = 0; i < constraints.count(); ++i) {
+ const QSimplexConstraint *c = constraints.at(i);
+ foreach (QSimplexVariable *var, c->variables.keys()) {
+ variableSet += static_cast<AnchorData *>(var);
+ }
+ }
+ return variableSet.toList();
+}
+
+/*!
+ \internal
+
+ Calculate graphs is the method that puts together all the helper routines
+ so that the AnchorLayout can calculate the sizes of each item.
+
+ In a nutshell it should do:
+
+ 1) Refresh anchor nominal sizes, that is, the size that each anchor would
+ have if no other restrictions applied. This is done by quering the
+ layout style and the sizeHints of the items belonging to the layout.
+
+ 2) Simplify the graph by grouping together parallel and sequential anchors
+ into "group anchors". These have equivalent minimum, preferred and maximum
+ sizeHints as the anchors they replace.
+
+ 3) Check if we got to a trivial case. In some cases, the whole graph can be
+ simplified into a single anchor. If so, use this information. If not,
+ then call the Simplex solver to calculate the anchors sizes.
+
+ 4) Once the root anchors had its sizes calculated, propagate that to the
+ anchors they represent.
+*/
+void QGraphicsAnchorLayoutPrivate::calculateGraphs(
+ QGraphicsAnchorLayoutPrivate::Orientation orientation)
+{
+#if defined(QT_DEBUG) || defined(Q_AUTOTEST_EXPORT)
+ lastCalculationUsedSimplex[orientation] = false;
+#endif
+
+ static bool simplificationEnabled = qgetenv("QT_ANCHORLAYOUT_NO_SIMPLIFICATION").isEmpty();
+
+ // Reset the nominal sizes of each anchor based on the current item sizes
+ refreshAllSizeHints(orientation);
+
+ // Simplify the graph
+ if (simplificationEnabled && !simplifyGraph(orientation)) {
+ qWarning("QGraphicsAnchorLayout: anchor setup is not feasible.");
+ graphHasConflicts[orientation] = true;
+ return;
+ }
+
+ // Traverse all graph edges and store the possible paths to each vertex
+ findPaths(orientation);
+
+ // From the paths calculated above, extract the constraints that the current
+ // anchor setup impose, to our Linear Programming problem.
+ constraintsFromPaths(orientation);
+
+ // Split the constraints and anchors into groups that should be fed to the
+ // simplex solver independently. Currently we find two groups:
+ //
+ // 1) The "trunk", that is, the set of anchors (items) that are connected
+ // to the two opposite sides of our layout, and thus need to stretch in
+ // order to fit in the current layout size.
+ //
+ // 2) The floating or semi-floating anchors (items) that are those which
+ // are connected to only one (or none) of the layout sides, thus are not
+ // influenced by the layout size.
+ QList<QList<QSimplexConstraint *> > parts = getGraphParts(orientation);
+
+ // Now run the simplex solver to calculate Minimum, Preferred and Maximum sizes
+ // of the "trunk" set of constraints and variables.
+ // ### does trunk always exist? empty = trunk is the layout left->center->right
+ QList<QSimplexConstraint *> trunkConstraints = parts.at(0);
+ QList<AnchorData *> trunkVariables = getVariables(trunkConstraints);
+
+ // For minimum and maximum, use the path between the two layout sides as the
+ // objective function.
+ AnchorVertex *v = layoutLastVertex[orientation];
+ GraphPath trunkPath = graphPaths[orientation].value(v);
+
+ bool feasible = calculateTrunk(orientation, trunkPath, trunkConstraints, trunkVariables);
+
+ // For the other parts that not the trunk, solve only for the preferred size
+ // that is the size they will remain at, since they are not stretched by the
+ // layout.
+
+ // Skipping the first (trunk)
+ for (int i = 1; i < parts.count(); ++i) {
+ if (!feasible)
+ break;
+
+ QList<QSimplexConstraint *> partConstraints = parts.at(i);
+ QList<AnchorData *> partVariables = getVariables(partConstraints);
+ Q_ASSERT(!partVariables.isEmpty());
+ feasible &= calculateNonTrunk(partConstraints, partVariables);
+ }
+
+ // Propagate the new sizes down the simplified graph, ie. tell the
+ // group anchors to set their children anchors sizes.
+ updateAnchorSizes(orientation);
+
+ graphHasConflicts[orientation] = !feasible;
+
+ // Clean up our data structures. They are not needed anymore since
+ // distribution uses just interpolation.
+ qDeleteAll(constraints[orientation]);
+ constraints[orientation].clear();
+ graphPaths[orientation].clear(); // ###
+
+ if (simplificationEnabled)
+ restoreSimplifiedGraph(orientation);
+}
+
+/*!
+ \internal
+
+ Shift all the constraints by a certain amount. This allows us to deal with negative values in
+ the linear program if they are bounded by a certain limit. Functions should be careful to
+ call it again with a negative amount, to shift the constraints back.
+*/
+static void shiftConstraints(const QList<QSimplexConstraint *> &constraints, qreal amount)
+{
+ for (int i = 0; i < constraints.count(); ++i) {
+ QSimplexConstraint *c = constraints.at(i);
+ qreal multiplier = 0;
+ foreach (qreal v, c->variables.values()) {
+ multiplier += v;
+ }
+ c->constant += multiplier * amount;
+ }
+}
+
+/*!
+ \internal
+
+ Calculate the sizes for all anchors which are part of the trunk. This works
+ on top of a (possibly) simplified graph.
+*/
+bool QGraphicsAnchorLayoutPrivate::calculateTrunk(Orientation orientation, const GraphPath &path,
+ const QList<QSimplexConstraint *> &constraints,
+ const QList<AnchorData *> &variables)
+{
+ bool feasible = true;
+ bool needsSimplex = !constraints.isEmpty();
+
+#if 0
+ qDebug("Simplex %s for trunk of %s", needsSimplex ? "used" : "NOT used",
+ orientation == Horizontal ? "Horizontal" : "Vertical");
+#endif
+
+ if (needsSimplex) {
+
+ QList<QSimplexConstraint *> sizeHintConstraints = constraintsFromSizeHints(variables);
+ QList<QSimplexConstraint *> allConstraints = constraints + sizeHintConstraints;
+
+ shiftConstraints(allConstraints, g_offset);
+
+ // Solve min and max size hints
+ qreal min, max;
+ feasible = solveMinMax(allConstraints, path, &min, &max);
+
+ if (feasible) {
+ solvePreferred(constraints, variables);
+
+ // Calculate and set the preferred size for the layout,
+ // from the edge sizes that were calculated above.
+ qreal pref(0.0);
+ foreach (const AnchorData *ad, path.positives) {
+ pref += ad->sizeAtPreferred;
+ }
+ foreach (const AnchorData *ad, path.negatives) {
+ pref -= ad->sizeAtPreferred;
+ }
+
+ sizeHints[orientation][Qt::MinimumSize] = min;
+ sizeHints[orientation][Qt::PreferredSize] = pref;
+ sizeHints[orientation][Qt::MaximumSize] = max;
+ }
+
+ qDeleteAll(sizeHintConstraints);
+ shiftConstraints(constraints, -g_offset);
+
+ } else {
+ // No Simplex is necessary because the path was simplified all the way to a single
+ // anchor.
+ Q_ASSERT(path.positives.count() == 1);
+ Q_ASSERT(path.negatives.count() == 0);
+
+ AnchorData *ad = path.positives.toList()[0];
+ ad->sizeAtMinimum = ad->minSize;
+ ad->sizeAtPreferred = ad->prefSize;
+ ad->sizeAtMaximum = ad->maxSize;
+
+ sizeHints[orientation][Qt::MinimumSize] = ad->sizeAtMinimum;
+ sizeHints[orientation][Qt::PreferredSize] = ad->sizeAtPreferred;
+ sizeHints[orientation][Qt::MaximumSize] = ad->sizeAtMaximum;
+ }
+
+#if defined(QT_DEBUG) || defined(Q_AUTOTEST_EXPORT)
+ lastCalculationUsedSimplex[orientation] = needsSimplex;
+#endif
+
+ return feasible;
+}
+
+/*!
+ \internal
+*/
+bool QGraphicsAnchorLayoutPrivate::calculateNonTrunk(const QList<QSimplexConstraint *> &constraints,
+ const QList<AnchorData *> &variables)
+{
+ shiftConstraints(constraints, g_offset);
+ bool feasible = solvePreferred(constraints, variables);
+
+ if (feasible) {
+ // Propagate size at preferred to other sizes. Semi-floats always will be
+ // in their sizeAtPreferred.
+ for (int j = 0; j < variables.count(); ++j) {
+ AnchorData *ad = variables.at(j);
+ Q_ASSERT(ad);
+ ad->sizeAtMinimum = ad->sizeAtPreferred;
+ ad->sizeAtMaximum = ad->sizeAtPreferred;
+ }
+ }
+
+ shiftConstraints(constraints, -g_offset);
+ return feasible;
+}
+
+/*!
+ \internal
+
+ Traverse the graph refreshing the size hints. Edges will query their associated
+ item or graphicsAnchor for their size hints.
+*/
+void QGraphicsAnchorLayoutPrivate::refreshAllSizeHints(Orientation orientation)
+{
+ Graph<AnchorVertex, AnchorData> &g = graph[orientation];
+ QList<QPair<AnchorVertex *, AnchorVertex *> > vertices = g.connections();
+
+ QLayoutStyleInfo styleInf = styleInfo();
+ for (int i = 0; i < vertices.count(); ++i) {
+ AnchorData *data = g.edgeData(vertices.at(i).first, vertices.at(i).second);
+ data->refreshSizeHints(&styleInf);
+ }
+}
+
+/*!
+ \internal
+
+ This method walks the graph using a breadth-first search to find paths
+ between the root vertex and each vertex on the graph. The edges
+ directions in each path are considered and they are stored as a
+ positive edge (left-to-right) or negative edge (right-to-left).
+
+ The list of paths is used later to generate a list of constraints.
+ */
+void QGraphicsAnchorLayoutPrivate::findPaths(Orientation orientation)
+{
+ QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;
+
+ QSet<AnchorData *> visited;
+
+ AnchorVertex *root = layoutFirstVertex[orientation];
+
+ graphPaths[orientation].insert(root, GraphPath());
+
+ foreach (AnchorVertex *v, graph[orientation].adjacentVertices(root)) {
+ queue.enqueue(qMakePair(root, v));
+ }
+
+ while(!queue.isEmpty()) {
+ QPair<AnchorVertex *, AnchorVertex *> pair = queue.dequeue();
+ AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second);
+
+ if (visited.contains(edge))
+ continue;
+
+ visited.insert(edge);
+ GraphPath current = graphPaths[orientation].value(pair.first);
+
+ if (edge->from == pair.first)
+ current.positives.insert(edge);
+ else
+ current.negatives.insert(edge);
+
+ graphPaths[orientation].insert(pair.second, current);
+
+ foreach (AnchorVertex *v,
+ graph[orientation].adjacentVertices(pair.second)) {
+ queue.enqueue(qMakePair(pair.second, v));
+ }
+ }
+
+ // We will walk through every reachable items (non-float) store them in a temporary set.
+ // We them create a set of all items and subtract the non-floating items from the set in
+ // order to get the floating items. The floating items is then stored in m_floatItems
+ identifyFloatItems(visited, orientation);
+}
+
+/*!
+ \internal
+
+ Each vertex on the graph that has more than one path to it
+ represents a contra int to the sizes of the items in these paths.
+
+ This method walks the list of paths to each vertex, generate
+ the constraints and store them in a list so they can be used later
+ by the Simplex solver.
+*/
+void QGraphicsAnchorLayoutPrivate::constraintsFromPaths(Orientation orientation)
+{
+ foreach (AnchorVertex *vertex, graphPaths[orientation].uniqueKeys())
+ {
+ int valueCount = graphPaths[orientation].count(vertex);
+ if (valueCount == 1)
+ continue;
+
+ QList<GraphPath> pathsToVertex = graphPaths[orientation].values(vertex);
+ for (int i = 1; i < valueCount; ++i) {
+ constraints[orientation] += \
+ pathsToVertex[0].constraint(pathsToVertex.at(i));
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsAnchorLayoutPrivate::updateAnchorSizes(Orientation orientation)
+{
+ Graph<AnchorVertex, AnchorData> &g = graph[orientation];
+ const QList<QPair<AnchorVertex *, AnchorVertex *> > &vertices = g.connections();
+
+ for (int i = 0; i < vertices.count(); ++i) {
+ AnchorData *ad = g.edgeData(vertices.at(i).first, vertices.at(i).second);
+ ad->updateChildrenSizes();
+ }
+}
+
+/*!
+ \internal
+
+ Create LP constraints for each anchor based on its minimum and maximum
+ sizes, as specified in its size hints
+*/
+QList<QSimplexConstraint *> QGraphicsAnchorLayoutPrivate::constraintsFromSizeHints(
+ const QList<AnchorData *> &anchors)
+{
+ if (anchors.isEmpty())
+ return QList<QSimplexConstraint *>();
+
+ // Look for the layout edge. That can be either the first half in case the
+ // layout is split in two, or the whole layout anchor.
+ Orientation orient = Orientation(anchors.first()->orientation);
+ AnchorData *layoutEdge = 0;
+ if (layoutCentralVertex[orient]) {
+ layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutCentralVertex[orient]);
+ } else {
+ layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutLastVertex[orient]);
+ }
+
+ // If maxSize is less then "infinite", that means there are other anchors
+ // grouped together with this one. We can't ignore its maximum value so we
+ // set back the variable to NULL to prevent the continue condition from being
+ // satisfied in the loop below.
+ const qreal expectedMax = layoutCentralVertex[orient] ? QWIDGETSIZE_MAX / 2 : QWIDGETSIZE_MAX;
+ qreal actualMax;
+ if (layoutEdge->from == layoutFirstVertex[orient]) {
+ actualMax = layoutEdge->maxSize;
+ } else {
+ actualMax = -layoutEdge->minSize;
+ }
+ if (actualMax != expectedMax) {
+ layoutEdge = 0;
+ }
+
+ // For each variable, create constraints based on size hints
+ QList<QSimplexConstraint *> anchorConstraints;
+ bool unboundedProblem = true;
+ for (int i = 0; i < anchors.size(); ++i) {
+ AnchorData *ad = anchors.at(i);
+
+ // Anchors that have their size directly linked to another one don't need constraints
+ // For exammple, the second half of an item has exactly the same size as the first half
+ // thus constraining the latter is enough.
+ if (ad->dependency == AnchorData::Slave)
+ continue;
+
+ // To use negative variables inside simplex, we shift them so the minimum negative value is
+ // mapped to zero before solving. To make sure that it works, we need to guarantee that the
+ // variables are all inside a certain boundary.
+ qreal boundedMin = qBound(-g_offset, ad->minSize, g_offset);
+ qreal boundedMax = qBound(-g_offset, ad->maxSize, g_offset);
+
+ if ((boundedMin == boundedMax) || qFuzzyCompare(boundedMin, boundedMax)) {
+ QSimplexConstraint *c = new QSimplexConstraint;
+ c->variables.insert(ad, 1.0);
+ c->constant = boundedMin;
+ c->ratio = QSimplexConstraint::Equal;
+ anchorConstraints += c;
+ unboundedProblem = false;
+ } else {
+ QSimplexConstraint *c = new QSimplexConstraint;
+ c->variables.insert(ad, 1.0);
+ c->constant = boundedMin;
+ c->ratio = QSimplexConstraint::MoreOrEqual;
+ anchorConstraints += c;
+
+ // We avoid adding restrictions to the layout internal anchors. That's
+ // to prevent unnecessary fair distribution from happening due to this
+ // artificial restriction.
+ if (ad == layoutEdge)
+ continue;
+
+ c = new QSimplexConstraint;
+ c->variables.insert(ad, 1.0);
+ c->constant = boundedMax;
+ c->ratio = QSimplexConstraint::LessOrEqual;
+ anchorConstraints += c;
+ unboundedProblem = false;
+ }
+ }
+
+ // If no upper boundary restriction was added, add one to avoid unbounded problem
+ if (unboundedProblem) {
+ QSimplexConstraint *c = new QSimplexConstraint;
+ c->variables.insert(layoutEdge, 1.0);
+ // The maximum size that the layout can take
+ c->constant = g_offset;
+ c->ratio = QSimplexConstraint::LessOrEqual;
+ anchorConstraints += c;
+ }
+
+ return anchorConstraints;
+}
+
+/*!
+ \internal
+*/
+QList< QList<QSimplexConstraint *> >
+QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation)
+{
+ Q_ASSERT(layoutFirstVertex[orientation] && layoutLastVertex[orientation]);
+
+ AnchorData *edgeL1 = 0;
+ AnchorData *edgeL2 = 0;
+
+ // The layout may have a single anchor between Left and Right or two half anchors
+ // passing through the center
+ if (layoutCentralVertex[orientation]) {
+ edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutCentralVertex[orientation]);
+ edgeL2 = graph[orientation].edgeData(layoutCentralVertex[orientation], layoutLastVertex[orientation]);
+ } else {
+ edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutLastVertex[orientation]);
+ }
+
+ QLinkedList<QSimplexConstraint *> remainingConstraints;
+ for (int i = 0; i < constraints[orientation].count(); ++i) {
+ remainingConstraints += constraints[orientation].at(i);
+ }
+ for (int i = 0; i < itemCenterConstraints[orientation].count(); ++i) {
+ remainingConstraints += itemCenterConstraints[orientation].at(i);
+ }
+
+ QList<QSimplexConstraint *> trunkConstraints;
+ QSet<QSimplexVariable *> trunkVariables;
+
+ trunkVariables += edgeL1;
+ if (edgeL2)
+ trunkVariables += edgeL2;
+
+ bool dirty;
+ do {
+ dirty = false;
+
+ QLinkedList<QSimplexConstraint *>::iterator it = remainingConstraints.begin();
+ while (it != remainingConstraints.end()) {
+ QSimplexConstraint *c = *it;
+ bool match = false;
+
+ // Check if this constraint have some overlap with current
+ // trunk variables...
+ foreach (QSimplexVariable *ad, trunkVariables) {
+ if (c->variables.contains(ad)) {
+ match = true;
+ break;
+ }
+ }
+
+ // If so, we add it to trunk, and erase it from the
+ // remaining constraints.
+ if (match) {
+ trunkConstraints += c;
+ trunkVariables += QSet<QSimplexVariable *>::fromList(c->variables.keys());
+ it = remainingConstraints.erase(it);
+ dirty = true;
+ } else {
+ // Note that we don't erase the constraint if it's not
+ // a match, since in a next iteration of a do-while we
+ // can pass on it again and it will be a match.
+ //
+ // For example: if trunk share a variable with
+ // remainingConstraints[1] and it shares with
+ // remainingConstraints[0], we need a second iteration
+ // of the do-while loop to match both.
+ ++it;
+ }
+ }
+ } while (dirty);
+
+ QList< QList<QSimplexConstraint *> > result;
+ result += trunkConstraints;
+
+ if (!remainingConstraints.isEmpty()) {
+ QList<QSimplexConstraint *> nonTrunkConstraints;
+ QLinkedList<QSimplexConstraint *>::iterator it = remainingConstraints.begin();
+ while (it != remainingConstraints.end()) {
+ nonTrunkConstraints += *it;
+ ++it;
+ }
+ result += nonTrunkConstraints;
+ }
+
+ return result;
+}
+
+/*!
+ \internal
+
+ Use all visited Anchors on findPaths() so we can identify non-float Items.
+*/
+void QGraphicsAnchorLayoutPrivate::identifyFloatItems(const QSet<AnchorData *> &visited, Orientation orientation)
+{
+ QSet<QGraphicsLayoutItem *> nonFloating;
+
+ foreach (const AnchorData *ad, visited)
+ identifyNonFloatItems_helper(ad, &nonFloating);
+
+ QSet<QGraphicsLayoutItem *> allItems;
+ foreach (QGraphicsLayoutItem *item, items)
+ allItems.insert(item);
+ m_floatItems[orientation] = allItems - nonFloating;
+}
+
+
+/*!
+ \internal
+
+ Given an anchor, if it is an internal anchor and Normal we must mark it's item as non-float.
+ If the anchor is Sequential or Parallel, we must iterate on its children recursively until we reach
+ internal anchors (items).
+*/
+void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems_helper(const AnchorData *ad, QSet<QGraphicsLayoutItem *> *nonFloatingItemsIdentifiedSoFar)
+{
+ Q_Q(QGraphicsAnchorLayout);
+
+ switch(ad->type) {
+ case AnchorData::Normal:
+ if (ad->item && ad->item != q)
+ nonFloatingItemsIdentifiedSoFar->insert(ad->item);
+ break;
+ case AnchorData::Sequential:
+ foreach (const AnchorData *d, static_cast<const SequentialAnchorData *>(ad)->m_edges)
+ identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar);
+ break;
+ case AnchorData::Parallel:
+ identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->firstEdge, nonFloatingItemsIdentifiedSoFar);
+ identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->secondEdge, nonFloatingItemsIdentifiedSoFar);
+ break;
+ }
+}
+
+/*!
+ \internal
+
+ Use the current vertices distance to calculate and set the geometry of
+ each item.
+*/
+void QGraphicsAnchorLayoutPrivate::setItemsGeometries(const QRectF &geom)
+{
+ Q_Q(QGraphicsAnchorLayout);
+ AnchorVertex *firstH, *secondH, *firstV, *secondV;
+
+ qreal top;
+ qreal left;
+ qreal right;
+
+ q->getContentsMargins(&left, &top, &right, 0);
+ const Qt::LayoutDirection visualDir = visualDirection();
+ if (visualDir == Qt::RightToLeft)
+ qSwap(left, right);
+
+ left += geom.left();
+ top += geom.top();
+ right = geom.right() - right;
+
+ foreach (QGraphicsLayoutItem *item, items) {
+ QRectF newGeom;
+ QSizeF itemPreferredSize = item->effectiveSizeHint(Qt::PreferredSize);
+ if (m_floatItems[Horizontal].contains(item)) {
+ newGeom.setLeft(0);
+ newGeom.setRight(itemPreferredSize.width());
+ } else {
+ firstH = internalVertex(item, Qt::AnchorLeft);
+ secondH = internalVertex(item, Qt::AnchorRight);
+
+ if (visualDir == Qt::LeftToRight) {
+ newGeom.setLeft(left + firstH->distance);
+ newGeom.setRight(left + secondH->distance);
+ } else {
+ newGeom.setLeft(right - secondH->distance);
+ newGeom.setRight(right - firstH->distance);
+ }
+ }
+
+ if (m_floatItems[Vertical].contains(item)) {
+ newGeom.setTop(0);
+ newGeom.setBottom(itemPreferredSize.height());
+ } else {
+ firstV = internalVertex(item, Qt::AnchorTop);
+ secondV = internalVertex(item, Qt::AnchorBottom);
+
+ newGeom.setTop(top + firstV->distance);
+ newGeom.setBottom(top + secondV->distance);
+ }
+
+ item->setGeometry(newGeom);
+ }
+}
+
+/*!
+ \internal
+
+ Calculate the position of each vertex based on the paths to each of
+ them as well as the current edges sizes.
+*/
+void QGraphicsAnchorLayoutPrivate::calculateVertexPositions(
+ QGraphicsAnchorLayoutPrivate::Orientation orientation)
+{
+ QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;
+ QSet<AnchorVertex *> visited;
+
+ // Get root vertex
+ AnchorVertex *root = layoutFirstVertex[orientation];
+
+ root->distance = 0;
+ visited.insert(root);
+
+ // Add initial edges to the queue
+ foreach (AnchorVertex *v, graph[orientation].adjacentVertices(root)) {
+ queue.enqueue(qMakePair(root, v));
+ }
+
+ // Do initial calculation required by "interpolateEdge()"
+ setupEdgesInterpolation(orientation);
+
+ // Traverse the graph and calculate vertex positions
+ while (!queue.isEmpty()) {
+ QPair<AnchorVertex *, AnchorVertex *> pair = queue.dequeue();
+ AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second);
+
+ if (visited.contains(pair.second))
+ continue;
+
+ visited.insert(pair.second);
+ interpolateEdge(pair.first, edge);
+
+ QList<AnchorVertex *> adjacents = graph[orientation].adjacentVertices(pair.second);
+ for (int i = 0; i < adjacents.count(); ++i) {
+ if (!visited.contains(adjacents.at(i)))
+ queue.enqueue(qMakePair(pair.second, adjacents.at(i)));
+ }
+ }
+}
+
+/*!
+ \internal
+
+ Calculate interpolation parameters based on current Layout Size.
+ Must be called once before calling "interpolateEdgeSize()" for
+ the edges.
+*/
+void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation(
+ Orientation orientation)
+{
+ Q_Q(QGraphicsAnchorLayout);
+
+ qreal current;
+ current = (orientation == Horizontal) ? q->contentsRect().width() : q->contentsRect().height();
+
+ QPair<Interval, qreal> result;
+ result = getFactor(current,
+ sizeHints[orientation][Qt::MinimumSize],
+ sizeHints[orientation][Qt::PreferredSize],
+ sizeHints[orientation][Qt::PreferredSize],
+ sizeHints[orientation][Qt::PreferredSize],
+ sizeHints[orientation][Qt::MaximumSize]);
+
+ interpolationInterval[orientation] = result.first;
+ interpolationProgress[orientation] = result.second;
+}
+
+/*!
+ \internal
+
+ Calculate the current Edge size based on the current Layout size and the
+ size the edge is supposed to have when the layout is at its:
+
+ - minimum size,
+ - preferred size,
+ - maximum size.
+
+ These three key values are calculated in advance using linear
+ programming (more expensive) or the simplification algorithm, then
+ subsequential resizes of the parent layout require a simple
+ interpolation.
+*/
+void QGraphicsAnchorLayoutPrivate::interpolateEdge(AnchorVertex *base, AnchorData *edge)
+{
+ const Orientation orientation = Orientation(edge->orientation);
+ const QPair<Interval, qreal> factor(interpolationInterval[orientation],
+ interpolationProgress[orientation]);
+
+ qreal edgeDistance = interpolate(factor, edge->sizeAtMinimum, edge->sizeAtPreferred,
+ edge->sizeAtPreferred, edge->sizeAtPreferred,
+ edge->sizeAtMaximum);
+
+ Q_ASSERT(edge->from == base || edge->to == base);
+
+ // Calculate the distance for the vertex opposite to the base
+ if (edge->from == base) {
+ edge->to->distance = base->distance + edgeDistance;
+ } else {
+ edge->from->distance = base->distance - edgeDistance;
+ }
+}
+
+bool QGraphicsAnchorLayoutPrivate::solveMinMax(const QList<QSimplexConstraint *> &constraints,
+ GraphPath path, qreal *min, qreal *max)
+{
+ QSimplex simplex;
+ bool feasible = simplex.setConstraints(constraints);
+ if (feasible) {
+ // Obtain the objective constraint
+ QSimplexConstraint objective;
+ QSet<AnchorData *>::const_iterator iter;
+ for (iter = path.positives.constBegin(); iter != path.positives.constEnd(); ++iter)
+ objective.variables.insert(*iter, 1.0);
+
+ for (iter = path.negatives.constBegin(); iter != path.negatives.constEnd(); ++iter)
+ objective.variables.insert(*iter, -1.0);
+
+ const qreal objectiveOffset = (path.positives.count() - path.negatives.count()) * g_offset;
+ simplex.setObjective(&objective);
+
+ // Calculate minimum values
+ *min = simplex.solveMin() - objectiveOffset;
+
+ // Save sizeAtMinimum results
+ QList<AnchorData *> variables = getVariables(constraints);
+ for (int i = 0; i < variables.size(); ++i) {
+ AnchorData *ad = static_cast<AnchorData *>(variables.at(i));
+ ad->sizeAtMinimum = ad->result - g_offset;
+ }
+
+ // Calculate maximum values
+ *max = simplex.solveMax() - objectiveOffset;
+
+ // Save sizeAtMaximum results
+ for (int i = 0; i < variables.size(); ++i) {
+ AnchorData *ad = static_cast<AnchorData *>(variables.at(i));
+ ad->sizeAtMaximum = ad->result - g_offset;
+ }
+ }
+ return feasible;
+}
+
+enum slackType { Grower = -1, Shrinker = 1 };
+static QPair<QSimplexVariable *, QSimplexConstraint *> createSlack(QSimplexConstraint *sizeConstraint,
+ qreal interval, slackType type)
+{
+ QSimplexVariable *slack = new QSimplexVariable;
+ sizeConstraint->variables.insert(slack, type);
+
+ QSimplexConstraint *limit = new QSimplexConstraint;
+ limit->variables.insert(slack, 1.0);
+ limit->ratio = QSimplexConstraint::LessOrEqual;
+ limit->constant = interval;
+
+ return qMakePair(slack, limit);
+}
+
+bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint *> &constraints,
+ const QList<AnchorData *> &variables)
+{
+ QList<QSimplexConstraint *> preferredConstraints;
+ QList<QSimplexVariable *> preferredVariables;
+ QSimplexConstraint objective;
+
+ // Fill the objective coefficients for this variable. In the
+ // end the objective function will be
+ //
+ // z = n * (A_shrinker_hard + A_grower_hard + B_shrinker_hard + B_grower_hard + ...) +
+ // (A_shrinker_soft + A_grower_soft + B_shrinker_soft + B_grower_soft + ...)
+ //
+ // where n is the number of variables that have
+ // slacks. Note that here we use the number of variables
+ // as coefficient, this is to mark the "shrinker slack
+ // variable" less likely to get value than the "grower
+ // slack variable".
+
+ // This will fill the values for the structural constraints
+ // and we now fill the values for the slack constraints (one per variable),
+ // which have this form (the constant A_pref was set when creating the slacks):
+ //
+ // A + A_shrinker_hard + A_shrinker_soft - A_grower_hard - A_grower_soft = A_pref
+ //
+ for (int i = 0; i < variables.size(); ++i) {
+ AnchorData *ad = variables.at(i);
+
+ // The layout original structure anchors are not relevant in preferred size calculation
+ if (ad->isLayoutAnchor)
+ continue;
+
+ // By default, all variables are equal to their preferred size. If they have room to
+ // grow or shrink, such flexibility will be added by the additional variables below.
+ QSimplexConstraint *sizeConstraint = new QSimplexConstraint;
+ preferredConstraints += sizeConstraint;
+ sizeConstraint->variables.insert(ad, 1.0);
+ sizeConstraint->constant = ad->prefSize + g_offset;
+
+ // Can easily shrink
+ QPair<QSimplexVariable *, QSimplexConstraint *> slack;
+ const qreal softShrinkInterval = ad->prefSize - ad->minPrefSize;
+ if (softShrinkInterval) {
+ slack = createSlack(sizeConstraint, softShrinkInterval, Shrinker);
+ preferredVariables += slack.first;
+ preferredConstraints += slack.second;
+
+ // Add to objective with ratio == 1 (soft)
+ objective.variables.insert(slack.first, 1.0);
+ }
+
+ // Can easily grow
+ const qreal softGrowInterval = ad->maxPrefSize - ad->prefSize;
+ if (softGrowInterval) {
+ slack = createSlack(sizeConstraint, softGrowInterval, Grower);
+ preferredVariables += slack.first;
+ preferredConstraints += slack.second;
+
+ // Add to objective with ratio == 1 (soft)
+ objective.variables.insert(slack.first, 1.0);
+ }
+
+ // Can shrink if really necessary
+ const qreal hardShrinkInterval = ad->minPrefSize - ad->minSize;
+ if (hardShrinkInterval) {
+ slack = createSlack(sizeConstraint, hardShrinkInterval, Shrinker);
+ preferredVariables += slack.first;
+ preferredConstraints += slack.second;
+
+ // Add to objective with ratio == N (hard)
+ objective.variables.insert(slack.first, variables.size());
+ }
+
+ // Can grow if really necessary
+ const qreal hardGrowInterval = ad->maxSize - ad->maxPrefSize;
+ if (hardGrowInterval) {
+ slack = createSlack(sizeConstraint, hardGrowInterval, Grower);
+ preferredVariables += slack.first;
+ preferredConstraints += slack.second;
+
+ // Add to objective with ratio == N (hard)
+ objective.variables.insert(slack.first, variables.size());
+ }
+ }
+
+ QSimplex *simplex = new QSimplex;
+ bool feasible = simplex->setConstraints(constraints + preferredConstraints);
+ if (feasible) {
+ simplex->setObjective(&objective);
+
+ // Calculate minimum values
+ simplex->solveMin();
+
+ // Save sizeAtPreferred results
+ for (int i = 0; i < variables.size(); ++i) {
+ AnchorData *ad = variables.at(i);
+ ad->sizeAtPreferred = ad->result - g_offset;
+ }
+
+ // Make sure we delete the simplex solver -before- we delete the
+ // constraints used by it.
+ delete simplex;
+ }
+ // Delete constraints and variables we created.
+ qDeleteAll(preferredConstraints);
+ qDeleteAll(preferredVariables);
+
+ return feasible;
+}
+
+/*!
+ \internal
+ Returns true if there are no arrangement that satisfies all constraints.
+ Otherwise returns false.
+
+ \sa addAnchor()
+*/
+bool QGraphicsAnchorLayoutPrivate::hasConflicts() const
+{
+ QGraphicsAnchorLayoutPrivate *that = const_cast<QGraphicsAnchorLayoutPrivate*>(this);
+ that->calculateGraphs();
+
+ bool floatConflict = !m_floatItems[0].isEmpty() || !m_floatItems[1].isEmpty();
+
+ return graphHasConflicts[0] || graphHasConflicts[1] || floatConflict;
+}
+
+#ifdef QT_DEBUG
+void QGraphicsAnchorLayoutPrivate::dumpGraph(const QString &name)
+{
+ QFile file(QString::fromAscii("anchorlayout.%1.dot").arg(name));
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
+ qWarning("Could not write to %s", file.fileName().toLocal8Bit().constData());
+
+ QString str = QString::fromAscii("digraph anchorlayout {\nnode [shape=\"rect\"]\n%1}");
+ QString dotContents = graph[0].serializeToDot();
+ dotContents += graph[1].serializeToDot();
+ file.write(str.arg(dotContents).toLocal8Bit());
+
+ file.close();
+}
+#endif
+
+QT_END_NAMESPACE
+#endif //QT_NO_GRAPHICSVIEW
diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout_p.h b/src/widgets/graphicsview/qgraphicsanchorlayout_p.h
new file mode 100644
index 0000000000..9a91c3c8df
--- /dev/null
+++ b/src/widgets/graphicsview/qgraphicsanchorlayout_p.h
@@ -0,0 +1,594 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSANCHORLAYOUT_P_H
+#define QGRAPHICSANCHORLAYOUT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QGraphicsWidget>
+#include <private/qobject_p.h>
+
+#include "qgraphicslayout_p.h"
+#include "qgraphicsanchorlayout.h"
+#include "qgraph_p.h"
+#include "qsimplex_p.h"
+#ifndef QT_NO_GRAPHICSVIEW
+QT_BEGIN_NAMESPACE
+
+/*
+ The public QGraphicsAnchorLayout interface represents an anchorage point
+ as a pair of a <QGraphicsLayoutItem *> and a <Qt::AnchorPoint>.
+
+ Internally though, it has a graph of anchorage points (vertices) and
+ anchors (edges), represented by the AnchorVertex and AnchorData structs
+ respectively.
+*/
+
+/*!
+ \internal
+
+ 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_type(Normal) {}
+
+ AnchorVertex()
+ : 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) {
+ 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) {
+ case Qt::AnchorLeft:
+ edge = QLatin1String("Left");
+ break;
+ case Qt::AnchorHorizontalCenter:
+ edge = QLatin1String("HorizontalCenter");
+ break;
+ case Qt::AnchorRight:
+ edge = QLatin1String("Right");
+ break;
+ case Qt::AnchorTop:
+ edge = QLatin1String("Top");
+ break;
+ case Qt::AnchorVerticalCenter:
+ edge = QLatin1String("VerticalCenter");
+ break;
+ case Qt::AnchorBottom:
+ edge = QLatin1String("Bottom");
+ break;
+ default:
+ edge = QLatin1String("None");
+ break;
+ }
+ QString itemName;
+ if (m_item->isLayout()) {
+ itemName = QLatin1String("layout");
+ } else {
+ if (QGraphicsItem *item = m_item->graphicsItem()) {
+ itemName = item->data(0).toString();
+ }
+ }
+ edge.insert(0, QLatin1String("%1_"));
+ return edge.arg(itemName);
+}
+#endif
+
+/*!
+ \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
+ with the ones walked backwards.
+
+ This paths are compared against each other to produce LP Constraints,
+ the exact order in which the anchors were traversed is not relevant.
+*/
+class GraphPath
+{
+public:
+ GraphPath() {}
+
+ QSimplexConstraint *constraint(const GraphPath &path) const;
+#ifdef QT_DEBUG
+ QString toString() const;
+#endif
+ QSet<AnchorData *> positives;
+ QSet<AnchorData *> negatives;
+};
+
+class QGraphicsAnchorLayoutPrivate;
+/*!
+ \internal
+*/
+class QGraphicsAnchorPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsAnchor)
+
+public:
+ explicit QGraphicsAnchorPrivate(int version = QObjectPrivateVersion);
+ ~QGraphicsAnchorPrivate();
+
+ void setSpacing(qreal value);
+ void unsetSpacing();
+ qreal spacing() const;
+
+ void setSizePolicy(QSizePolicy::Policy policy);
+
+ QGraphicsAnchorLayoutPrivate *layoutPrivate;
+ AnchorData *data;
+
+ // Size information for user controlled anchor
+ QSizePolicy::Policy sizePolicy;
+ qreal preferredSize;
+
+ uint hasSize : 1; // if false, get size from style.
+};
+
+
+
+
+/*!
+ \internal
+
+ QGraphicsAnchorLayout private methods and attributes.
+*/
+class Q_AUTOTEST_EXPORT QGraphicsAnchorLayoutPrivate : public QGraphicsLayoutPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsAnchorLayout)
+
+public:
+ // When the layout geometry is different from its Minimum, Preferred
+ // or Maximum values, interpolation is used to calculate the geometries
+ // of the items.
+ //
+ // Interval represents which interpolation interval are we operating in.
+ enum Interval {
+ MinimumToMinPreferred = 0,
+ MinPreferredToPreferred,
+ PreferredToMaxPreferred,
+ MaxPreferredToMaximum
+ };
+
+ // Several structures internal to the layout are duplicated to handle
+ // both Horizontal and Vertical restrictions.
+ //
+ // Orientation is used to reference the right structure in each context
+ enum Orientation {
+ Horizontal = 0,
+ Vertical,
+ NOrientations
+ };
+
+ QGraphicsAnchorLayoutPrivate();
+
+ static QGraphicsAnchorLayoutPrivate *get(QGraphicsAnchorLayout *q)
+ {
+ return q ? q->d_func() : 0;
+ }
+
+ static Qt::AnchorPoint oppositeEdge(
+ Qt::AnchorPoint edge);
+
+ static Orientation edgeOrientation(Qt::AnchorPoint edge);
+
+ static Qt::AnchorPoint pickEdge(Qt::AnchorPoint edge, Orientation orientation)
+ {
+ if (orientation == Vertical && int(edge) <= 2)
+ return (Qt::AnchorPoint)(edge + 3);
+ else if (orientation == Horizontal && int(edge) >= 3) {
+ return (Qt::AnchorPoint)(edge - 3);
+ }
+ return edge;
+ }
+
+ // Init methods
+ void createLayoutEdges();
+ void deleteLayoutEdges();
+ void createItemEdges(QGraphicsLayoutItem *item);
+ void createCenterAnchors(QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge);
+ void removeCenterAnchors(QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge, bool substitute = true);
+ void removeCenterConstraints(QGraphicsLayoutItem *item, Orientation orientation);
+
+ QGraphicsAnchor *acquireGraphicsAnchor(AnchorData *data)
+ {
+ Q_Q(QGraphicsAnchorLayout);
+ if (!data->graphicsAnchor) {
+ data->graphicsAnchor = new QGraphicsAnchor(q);
+ data->graphicsAnchor->d_func()->data = data;
+ }
+ return data->graphicsAnchor;
+ }
+
+ // function used by the 4 API functions
+ QGraphicsAnchor *addAnchor(QGraphicsLayoutItem *firstItem,
+ Qt::AnchorPoint firstEdge,
+ QGraphicsLayoutItem *secondItem,
+ Qt::AnchorPoint secondEdge,
+ qreal *spacing = 0);
+
+ // Helper for Anchor Manipulation methods
+ void addAnchor_helper(QGraphicsLayoutItem *firstItem,
+ Qt::AnchorPoint firstEdge,
+ QGraphicsLayoutItem *secondItem,
+ Qt::AnchorPoint secondEdge,
+ AnchorData *data);
+
+ QGraphicsAnchor *getAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge,
+ QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge);
+
+ void removeAnchor(AnchorVertex *firstVertex, AnchorVertex *secondVertex);
+ void removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2);
+
+ void removeAnchors(QGraphicsLayoutItem *item);
+
+ void removeVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge);
+
+ void correctEdgeDirection(QGraphicsLayoutItem *&firstItem,
+ Qt::AnchorPoint &firstEdge,
+ QGraphicsLayoutItem *&secondItem,
+ Qt::AnchorPoint &secondEdge);
+
+ QLayoutStyleInfo &styleInfo() const;
+
+ 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);
+
+ // Support functions for calculateGraph()
+ void refreshAllSizeHints(Orientation orientation);
+ void findPaths(Orientation orientation);
+ void constraintsFromPaths(Orientation orientation);
+ void updateAnchorSizes(Orientation orientation);
+ QList<QSimplexConstraint *> constraintsFromSizeHints(const QList<AnchorData *> &anchors);
+ QList<QList<QSimplexConstraint *> > getGraphParts(Orientation orientation);
+ void identifyFloatItems(const QSet<AnchorData *> &visited, Orientation orientation);
+ void identifyNonFloatItems_helper(const AnchorData *ad, QSet<QGraphicsLayoutItem *> *nonFloatingItemsIdentifiedSoFar);
+
+ inline AnchorVertex *internalVertex(const QPair<QGraphicsLayoutItem*, Qt::AnchorPoint> &itemEdge) const
+ {
+ return m_vertexList.value(itemEdge).first;
+ }
+
+ inline AnchorVertex *internalVertex(const QGraphicsLayoutItem *item, Qt::AnchorPoint edge) const
+ {
+ 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);
+
+ // Geometry interpolation methods
+ void setItemsGeometries(const QRectF &geom);
+
+ void calculateVertexPositions(Orientation orientation);
+ void setupEdgesInterpolation(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);
+ bool hasConflicts() const;
+
+#ifdef QT_DEBUG
+ void dumpGraph(const QString &name = QString());
+#endif
+
+
+ qreal spacings[NOrientations];
+ // Size hints from simplex engine
+ qreal sizeHints[2][3];
+
+ // Items
+ QVector<QGraphicsLayoutItem *> items;
+
+ // Mapping between high level anchorage points (Item, Edge) to low level
+ // ones (Graph Vertices)
+
+ QHash<QPair<QGraphicsLayoutItem*, Qt::AnchorPoint>, QPair<AnchorVertex *, int> > m_vertexList;
+
+ // 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];
+ QList<QSimplexConstraint *> itemCenterConstraints[2];
+
+ // The interpolation interval and progress based on the current size
+ // as well as the key values (minimum, preferred and maximum)
+ Interval interpolationInterval[2];
+ qreal interpolationProgress[2];
+
+ bool graphHasConflicts[2];
+ QSet<QGraphicsLayoutItem *> m_floatItems[2];
+
+#if defined(QT_DEBUG) || defined(Q_AUTOTEST_EXPORT)
+ bool lastCalculationUsedSimplex[2];
+#endif
+
+ uint calculateGraphCacheDirty : 1;
+ mutable uint styleInfoDirty : 1;
+ mutable QLayoutStyleInfo cachedStyleInfo;
+
+ friend class QGraphicsAnchorPrivate;
+};
+
+QT_END_NAMESPACE
+#endif //QT_NO_GRAPHICSVIEW
+
+#endif
diff --git a/src/widgets/graphicsview/qgraphicsgridlayout.cpp b/src/widgets/graphicsview/qgraphicsgridlayout.cpp
new file mode 100644
index 0000000000..f6eec1d405
--- /dev/null
+++ b/src/widgets/graphicsview/qgraphicsgridlayout.cpp
@@ -0,0 +1,690 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QGraphicsGridLayout
+ \brief The QGraphicsGridLayout class provides a grid layout for managing
+ widgets in Graphics View.
+ \since 4.4
+
+ \ingroup graphicsview-api
+
+ The most common way to use QGraphicsGridLayout is to construct an object
+ on the heap with no parent, add widgets and layouts by calling addItem(),
+ and finally assign the layout to a widget by calling
+ QGraphicsWidget::setLayout(). QGraphicsGridLayout automatically computes
+ the dimensions of the grid as you add items.
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsgridlayout.cpp 0
+
+ The layout takes ownership of the items. In some cases when the layout
+ item also inherits from QGraphicsItem (such as QGraphicsWidget) there will be a
+ ambiguity in ownership because the layout item belongs to two ownership hierarchies.
+ See the documentation of QGraphicsLayoutItem::setOwnedByLayout() how to handle
+ this.
+ You can access each item in the layout by calling count() and itemAt(). Calling
+ removeAt() will remove an item from the layout, without
+ destroying it.
+
+ \section1 Size Hints and Size Policies in QGraphicsGridLayout
+
+ QGraphicsGridLayout respects each item's size hints and size policies,
+ and when a cell in the grid has more space than the items can fill, each item
+ is arranged according to the layout's alignment for that item. You can set
+ an alignment for each item by calling setAlignment(), and check the
+ alignment for any item by calling alignment(). You can also set the alignment
+ for an entire row or column by calling setRowAlignment() and setColumnAlignment()
+ respectively. By default, items are aligned to the top left.
+
+
+ \sa QGraphicsLinearLayout, QGraphicsWidget
+*/
+
+#include "qglobal.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include "qapplication.h"
+#include "qwidget.h"
+#include "qgraphicslayout_p.h"
+#include "qgraphicslayoutitem.h"
+#include "qgraphicsgridlayout.h"
+#include "qgraphicswidget.h"
+#include "qgridlayoutengine_p.h"
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsGridLayoutPrivate : public QGraphicsLayoutPrivate
+{
+public:
+ QGraphicsGridLayoutPrivate() { }
+ QLayoutStyleInfo styleInfo() const;
+
+ QGridLayoutEngine engine;
+#ifdef QT_DEBUG
+ void dump(int indent) const;
+#endif
+};
+
+Q_GLOBAL_STATIC(QWidget, globalStyleInfoWidget);
+
+QLayoutStyleInfo QGraphicsGridLayoutPrivate::styleInfo() const
+{
+ QGraphicsItem *item = parentItem();
+ QStyle *style = (item && item->isWidget()) ? static_cast<QGraphicsWidget*>(item)->style() : QApplication::style();
+ return QLayoutStyleInfo(style, globalStyleInfoWidget());
+}
+
+/*!
+ Constructs a QGraphicsGridLayout instance. \a parent is passed to
+ QGraphicsLayout's constructor.
+*/
+QGraphicsGridLayout::QGraphicsGridLayout(QGraphicsLayoutItem *parent)
+ : QGraphicsLayout(*new QGraphicsGridLayoutPrivate(), parent)
+{
+}
+
+/*!
+ Destroys the QGraphicsGridLayout object.
+*/
+QGraphicsGridLayout::~QGraphicsGridLayout()
+{
+ for (int i = count() - 1; i >= 0; --i) {
+ QGraphicsLayoutItem *item = itemAt(i);
+ // The following lines can be removed, but this removes the item
+ // from the layout more efficiently than the implementation of
+ // ~QGraphicsLayoutItem.
+ removeAt(i);
+ if (item) {
+ item->setParentLayoutItem(0);
+ if (item->ownedByLayout())
+ delete item;
+ }
+ }
+}
+
+/*!
+ Adds \a item to the grid on \a row and \a column. You can specify a
+ \a rowSpan and \a columnSpan and an optional \a alignment.
+*/
+void QGraphicsGridLayout::addItem(QGraphicsLayoutItem *item, int row, int column,
+ int rowSpan, int columnSpan, Qt::Alignment alignment)
+{
+ Q_D(QGraphicsGridLayout);
+ if (row < 0 || column < 0) {
+ qWarning("QGraphicsGridLayout::addItem: invalid row/column: %d",
+ row < 0 ? row : column);
+ return;
+ }
+ if (columnSpan < 1 || rowSpan < 1) {
+ qWarning("QGraphicsGridLayout::addItem: invalid row span/column span: %d",
+ rowSpan < 1 ? rowSpan : columnSpan);
+ return;
+ }
+ if (!item) {
+ qWarning("QGraphicsGridLayout::addItem: cannot add null item");
+ return;
+ }
+ if (item == this) {
+ qWarning("QGraphicsGridLayout::addItem: cannot insert itself");
+ return;
+ }
+
+ d->addChildLayoutItem(item);
+
+ new QGridLayoutItem(&d->engine, item, row, column, rowSpan, columnSpan, alignment);
+ invalidate();
+}
+
+/*!
+ \fn QGraphicsGridLayout::addItem(QGraphicsLayoutItem *item, int row, int column, Qt::Alignment alignment = 0)
+
+ Adds \a item to the grid on \a row and \a column. You can specify
+ an optional \a alignment for \a item.
+*/
+
+/*!
+ Sets the default horizontal spacing for the grid layout to \a spacing.
+*/
+void QGraphicsGridLayout::setHorizontalSpacing(qreal spacing)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setSpacing(spacing, Qt::Horizontal);
+ invalidate();
+}
+
+/*!
+ Returns the default horizontal spacing for the grid layout.
+*/
+qreal QGraphicsGridLayout::horizontalSpacing() const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.spacing(d->styleInfo(), Qt::Horizontal);
+}
+
+/*!
+ Sets the default vertical spacing for the grid layout to \a spacing.
+*/
+void QGraphicsGridLayout::setVerticalSpacing(qreal spacing)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setSpacing(spacing, Qt::Vertical);
+ invalidate();
+}
+
+/*!
+ Returns the default vertical spacing for the grid layout.
+*/
+qreal QGraphicsGridLayout::verticalSpacing() const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.spacing(d->styleInfo(), Qt::Vertical);
+}
+
+/*!
+ Sets the grid layout's default spacing, both vertical and
+ horizontal, to \a spacing.
+
+ \sa rowSpacing(), columnSpacing()
+*/
+void QGraphicsGridLayout::setSpacing(qreal spacing)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setSpacing(spacing, Qt::Horizontal | Qt::Vertical);
+ invalidate();
+}
+
+/*!
+ Sets the spacing for \a row to \a spacing.
+*/
+void QGraphicsGridLayout::setRowSpacing(int row, qreal spacing)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowSpacing(row, spacing, Qt::Vertical);
+ invalidate();
+}
+
+/*!
+ Returns the row spacing for \a row.
+*/
+qreal QGraphicsGridLayout::rowSpacing(int row) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowSpacing(row, Qt::Vertical);
+}
+
+/*!
+ Sets the spacing for \a column to \a spacing.
+*/
+void QGraphicsGridLayout::setColumnSpacing(int column, qreal spacing)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowSpacing(column, spacing, Qt::Horizontal);
+ invalidate();
+}
+
+/*!
+ Returns the column spacing for \a column.
+*/
+qreal QGraphicsGridLayout::columnSpacing(int column) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowSpacing(column, Qt::Horizontal);
+}
+
+/*!
+ Sets the stretch factor for \a row to \a stretch.
+*/
+void QGraphicsGridLayout::setRowStretchFactor(int row, int stretch)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowStretchFactor(row, stretch, Qt::Vertical);
+ invalidate();
+}
+
+/*!
+ Returns the stretch factor for \a row.
+*/
+int QGraphicsGridLayout::rowStretchFactor(int row) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowStretchFactor(row, Qt::Vertical);
+}
+
+/*!
+ Sets the stretch factor for \a column to \a stretch.
+*/
+void QGraphicsGridLayout::setColumnStretchFactor(int column, int stretch)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowStretchFactor(column, stretch, Qt::Horizontal);
+ invalidate();
+}
+
+/*!
+ Returns the stretch factor for \a column.
+*/
+int QGraphicsGridLayout::columnStretchFactor(int column) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowStretchFactor(column, Qt::Horizontal);
+}
+
+/*!
+ Sets the minimum height for row, \a row, to \a height.
+*/
+void QGraphicsGridLayout::setRowMinimumHeight(int row, qreal height)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowSizeHint(Qt::MinimumSize, row, height, Qt::Vertical);
+ invalidate();
+}
+
+/*!
+ Returns the minimum height for row, \a row.
+*/
+qreal QGraphicsGridLayout::rowMinimumHeight(int row) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowSizeHint(Qt::MinimumSize, row, Qt::Vertical);
+}
+
+/*!
+ Sets the preferred height for row, \a row, to \a height.
+*/
+void QGraphicsGridLayout::setRowPreferredHeight(int row, qreal height)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowSizeHint(Qt::PreferredSize, row, height, Qt::Vertical);
+ invalidate();
+}
+
+/*!
+ Returns the preferred height for row, \a row.
+*/
+qreal QGraphicsGridLayout::rowPreferredHeight(int row) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowSizeHint(Qt::PreferredSize, row, Qt::Vertical);
+}
+
+/*!
+ Sets the maximum height for row, \a row, to \a height.
+*/
+void QGraphicsGridLayout::setRowMaximumHeight(int row, qreal height)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowSizeHint(Qt::MaximumSize, row, height, Qt::Vertical);
+ invalidate();
+}
+
+/*!
+ Returns the maximum height for row, \a row.
+*/
+qreal QGraphicsGridLayout::rowMaximumHeight(int row) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowSizeHint(Qt::MaximumSize, row, Qt::Vertical);
+}
+
+/*!
+ Sets the fixed height for row, \a row, to \a height.
+*/
+void QGraphicsGridLayout::setRowFixedHeight(int row, qreal height)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowSizeHint(Qt::MinimumSize, row, height, Qt::Vertical);
+ d->engine.setRowSizeHint(Qt::MaximumSize, row, height, Qt::Vertical);
+ invalidate();
+}
+
+/*!
+ Sets the minimum width for \a column to \a width.
+*/
+void QGraphicsGridLayout::setColumnMinimumWidth(int column, qreal width)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowSizeHint(Qt::MinimumSize, column, width, Qt::Horizontal);
+ invalidate();
+}
+
+/*!
+ Returns the minimum width for \a column.
+*/
+qreal QGraphicsGridLayout::columnMinimumWidth(int column) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowSizeHint(Qt::MinimumSize, column, Qt::Horizontal);
+}
+
+/*!
+ Sets the preferred width for \a column to \a width.
+*/
+void QGraphicsGridLayout::setColumnPreferredWidth(int column, qreal width)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowSizeHint(Qt::PreferredSize, column, width, Qt::Horizontal);
+ invalidate();
+}
+
+/*!
+ Returns the preferred width for \a column.
+*/
+qreal QGraphicsGridLayout::columnPreferredWidth(int column) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowSizeHint(Qt::PreferredSize, column, Qt::Horizontal);
+}
+
+/*!
+ Sets the maximum width of \a column to \a width.
+*/
+void QGraphicsGridLayout::setColumnMaximumWidth(int column, qreal width)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowSizeHint(Qt::MaximumSize, column, width, Qt::Horizontal);
+ invalidate();
+}
+
+/*!
+ Returns the maximum width for \a column.
+*/
+qreal QGraphicsGridLayout::columnMaximumWidth(int column) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowSizeHint(Qt::MaximumSize, column, Qt::Horizontal);
+}
+
+/*!
+ Sets the fixed width of \a column to \a width.
+*/
+void QGraphicsGridLayout::setColumnFixedWidth(int column, qreal width)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowSizeHint(Qt::MinimumSize, column, width, Qt::Horizontal);
+ d->engine.setRowSizeHint(Qt::MaximumSize, column, width, Qt::Horizontal);
+ invalidate();
+}
+
+/*!
+ Sets the alignment of \a row to \a alignment.
+*/
+void QGraphicsGridLayout::setRowAlignment(int row, Qt::Alignment alignment)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowAlignment(row, alignment, Qt::Vertical);
+ invalidate();
+}
+
+/*!
+ Returns the alignment of \a row.
+*/
+Qt::Alignment QGraphicsGridLayout::rowAlignment(int row) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowAlignment(row, Qt::Vertical);
+}
+
+/*!
+ Sets the alignment for \a column to \a alignment.
+*/
+void QGraphicsGridLayout::setColumnAlignment(int column, Qt::Alignment alignment)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setRowAlignment(column, alignment, Qt::Horizontal);
+ invalidate();
+}
+
+/*!
+ Returns the alignment for \a column.
+*/
+Qt::Alignment QGraphicsGridLayout::columnAlignment(int column) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.rowAlignment(column, Qt::Horizontal);
+}
+
+/*!
+ Sets the alignment for \a item to \a alignment.
+*/
+void QGraphicsGridLayout::setAlignment(QGraphicsLayoutItem *item, Qt::Alignment alignment)
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.setAlignment(item, alignment);
+ invalidate();
+}
+
+/*!
+ Returns the alignment for \a item.
+*/
+Qt::Alignment QGraphicsGridLayout::alignment(QGraphicsLayoutItem *item) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.alignment(item);
+}
+
+/*!
+ Returns the number of rows in the grid layout. This is always one more
+ than the index of the last row that is occupied by a layout item (empty
+ rows are counted except for those at the end).
+*/
+int QGraphicsGridLayout::rowCount() const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.effectiveLastRow(Qt::Vertical) + 1;
+}
+
+/*!
+ Returns the number of columns in the grid layout. This is always one more
+ than the index of the last column that is occupied by a layout item (empty
+ columns are counted except for those at the end).
+*/
+int QGraphicsGridLayout::columnCount() const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.effectiveLastRow(Qt::Horizontal) + 1;
+}
+
+/*!
+ Returns a pointer to the layout item at (\a row, \a column).
+*/
+QGraphicsLayoutItem *QGraphicsGridLayout::itemAt(int row, int column) const
+{
+ Q_D(const QGraphicsGridLayout);
+ if (row < 0 || row >= rowCount() || column < 0 || column >= columnCount()) {
+ qWarning("QGraphicsGridLayout::itemAt: invalid row, column %d, %d", row, column);
+ return 0;
+ }
+ if (QGridLayoutItem *item = d->engine.itemAt(row, column))
+ return item->layoutItem();
+ return 0;
+}
+
+/*!
+ Returns the number of layout items in this grid layout.
+*/
+int QGraphicsGridLayout::count() const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.itemCount();
+}
+
+/*!
+ Returns the layout item at \a index, or 0 if there is no layout item at
+ this index.
+*/
+QGraphicsLayoutItem *QGraphicsGridLayout::itemAt(int index) const
+{
+ Q_D(const QGraphicsGridLayout);
+ if (index < 0 || index >= d->engine.itemCount()) {
+ qWarning("QGraphicsGridLayout::itemAt: invalid index %d", index);
+ return 0;
+ }
+ QGraphicsLayoutItem *item = 0;
+ if (QGridLayoutItem *gridItem = d->engine.itemAt(index))
+ item = gridItem->layoutItem();
+ return item;
+}
+
+/*!
+ Removes the layout item at \a index without destroying it. Ownership of
+ the item is transferred to the caller.
+
+ \sa addItem()
+*/
+void QGraphicsGridLayout::removeAt(int index)
+{
+ Q_D(QGraphicsGridLayout);
+ if (index < 0 || index >= d->engine.itemCount()) {
+ qWarning("QGraphicsGridLayout::removeAt: invalid index %d", index);
+ return;
+ }
+ if (QGridLayoutItem *gridItem = d->engine.itemAt(index)) {
+ if (QGraphicsLayoutItem *layoutItem = gridItem->layoutItem())
+ layoutItem->setParentLayoutItem(0);
+ d->engine.removeItem(gridItem);
+
+ // recalculate rowInfo.count if we remove an item that is on the right/bottommost row
+ for (int j = 0; j < NOrientations; ++j) {
+ // 0: Hor, 1: Ver
+ const Qt::Orientation orient = (j == 0 ? Qt::Horizontal : Qt::Vertical);
+ const int oldCount = d->engine.rowCount(orient);
+ if (gridItem->lastRow(orient) == oldCount - 1) {
+ const int newCount = d->engine.effectiveLastRow(orient) + 1;
+ d->engine.removeRows(newCount, oldCount - newCount, orient);
+ }
+ }
+
+ delete gridItem;
+ invalidate();
+ }
+}
+
+/*!
+ Removes the layout item \a item without destroying it.
+ Ownership of the item is transferred to the caller.
+
+ \sa addItem()
+*/
+void QGraphicsGridLayout::removeItem(QGraphicsLayoutItem *item)
+{
+ Q_D(QGraphicsGridLayout);
+ int index = d->engine.indexOf(item);
+ removeAt(index);
+}
+/*!
+ \reimp
+*/
+void QGraphicsGridLayout::invalidate()
+{
+ Q_D(QGraphicsGridLayout);
+ d->engine.invalidate();
+ QGraphicsLayout::invalidate();
+}
+
+#ifdef QT_DEBUG
+void QGraphicsGridLayoutPrivate::dump(int indent) const
+{
+ if (qt_graphicsLayoutDebug()) {
+ engine.dump(indent + 1);
+ }
+}
+#endif
+
+/*!
+ Sets the bounding geometry of the grid layout to \a rect.
+*/
+void QGraphicsGridLayout::setGeometry(const QRectF &rect)
+{
+ Q_D(QGraphicsGridLayout);
+ QGraphicsLayout::setGeometry(rect);
+ QRectF effectiveRect = geometry();
+ qreal left, top, right, bottom;
+ getContentsMargins(&left, &top, &right, &bottom);
+ Qt::LayoutDirection visualDir = d->visualDirection();
+ d->engine.setVisualDirection(visualDir);
+ if (visualDir == Qt::RightToLeft)
+ qSwap(left, right);
+ effectiveRect.adjust(+left, +top, -right, -bottom);
+ d->engine.setGeometries(d->styleInfo(), effectiveRect);
+#ifdef QT_DEBUG
+ if (qt_graphicsLayoutDebug()) {
+ static int counter = 0;
+ qDebug("==== BEGIN DUMP OF QGraphicsGridLayout (%d)====", counter++);
+ d->dump(1);
+ qDebug("==== END DUMP OF QGraphicsGridLayout ====");
+ }
+#endif
+}
+
+/*!
+ \reimp
+*/
+QSizeF QGraphicsGridLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ Q_D(const QGraphicsGridLayout);
+ qreal left, top, right, bottom;
+ getContentsMargins(&left, &top, &right, &bottom);
+ const QSizeF extraMargins(left + right, top + bottom);
+ return d->engine.sizeHint(d->styleInfo(), which , constraint - extraMargins) + extraMargins;
+}
+
+
+#if 0
+// ### kill? (implement and kill?)
+QRect QGraphicsGridLayout::cellRect(int row, int column, int rowSpan, int columnSpan) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return QRect();
+// return d->engine.cellRect(parentLayoutable(), contentsGeometry(), row, column, rowSpan, columnSpan);
+}
+
+QSizePolicy::ControlTypes QGraphicsGridLayout::controlTypes(LayoutSide side) const
+{
+ Q_D(const QGraphicsGridLayout);
+ return d->engine.controlTypes(side);
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSVIEW
diff --git a/src/widgets/graphicsview/qgraphicsgridlayout.h b/src/widgets/graphicsview/qgraphicsgridlayout.h
new file mode 100644
index 0000000000..f493eb6153
--- /dev/null
+++ b/src/widgets/graphicsview/qgraphicsgridlayout.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSGRIDLAYOUT_H
+#define QGRAPHICSGRIDLAYOUT_H
+
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/qgraphicslayout.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+class QGraphicsGridLayoutPrivate;
+
+class Q_GUI_EXPORT QGraphicsGridLayout : public QGraphicsLayout
+{
+public:
+ QGraphicsGridLayout(QGraphicsLayoutItem *parent = 0);
+ virtual ~QGraphicsGridLayout();
+
+ void addItem(QGraphicsLayoutItem *item, int row, int column, int rowSpan, int columnSpan,
+ Qt::Alignment alignment = 0);
+ inline void addItem(QGraphicsLayoutItem *item, int row, int column, Qt::Alignment alignment = 0);
+
+ void setHorizontalSpacing(qreal spacing);
+ qreal horizontalSpacing() const;
+ void setVerticalSpacing(qreal spacing);
+ qreal verticalSpacing() const;
+ void setSpacing(qreal spacing);
+
+ void setRowSpacing(int row, qreal spacing);
+ qreal rowSpacing(int row) const;
+ void setColumnSpacing(int column, qreal spacing);
+ qreal columnSpacing(int column) const;
+
+ void setRowStretchFactor(int row, int stretch);
+ int rowStretchFactor(int row) const;
+ void setColumnStretchFactor(int column, int stretch);
+ int columnStretchFactor(int column) const;
+
+ void setRowMinimumHeight(int row, qreal height);
+ qreal rowMinimumHeight(int row) const;
+ void setRowPreferredHeight(int row, qreal height);
+ qreal rowPreferredHeight(int row) const;
+ void setRowMaximumHeight(int row, qreal height);
+ qreal rowMaximumHeight(int row) const;
+ void setRowFixedHeight(int row, qreal height);
+
+ void setColumnMinimumWidth(int column, qreal width);
+ qreal columnMinimumWidth(int column) const;
+ void setColumnPreferredWidth(int column, qreal width);
+ qreal columnPreferredWidth(int column) const;
+ void setColumnMaximumWidth(int column, qreal width);
+ qreal columnMaximumWidth(int column) const;
+ void setColumnFixedWidth(int column, qreal width);
+
+ void setRowAlignment(int row, Qt::Alignment alignment);
+ Qt::Alignment rowAlignment(int row) const;
+ void setColumnAlignment(int column, Qt::Alignment alignment);
+ Qt::Alignment columnAlignment(int column) const;
+
+ void setAlignment(QGraphicsLayoutItem *item, Qt::Alignment alignment);
+ Qt::Alignment alignment(QGraphicsLayoutItem *item) const;
+
+ int rowCount() const;
+ int columnCount() const;
+
+ QGraphicsLayoutItem *itemAt(int row, int column) const;
+
+ // inherited from QGraphicsLayout
+ int count() const;
+ QGraphicsLayoutItem *itemAt(int index) const;
+ void removeAt(int index);
+ void removeItem(QGraphicsLayoutItem *item);
+
+ void invalidate();
+
+ // inherited from QGraphicsLayoutItem
+ void setGeometry(const QRectF &rect);
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+ // ####
+ //QRect cellRect(int row, int column, int rowSpan = 1, int columnSpan = 1) const;
+ //QSizePolicy::ControlTypes controlTypes(LayoutSide side) const;
+
+private:
+ Q_DISABLE_COPY(QGraphicsGridLayout)
+ Q_DECLARE_PRIVATE(QGraphicsGridLayout)
+};
+
+inline void QGraphicsGridLayout::addItem(QGraphicsLayoutItem *aitem, int arow, int acolumn, Qt::Alignment aalignment)
+{ addItem(aitem, arow, acolumn, 1, 1, aalignment); }
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
+
diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp
new file mode 100644
index 0000000000..e67fe82045
--- /dev/null
+++ b/src/widgets/graphicsview/qgraphicsitem.cpp
@@ -0,0 +1,11597 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QGraphicsItem
+ \brief The QGraphicsItem class is the base class for all graphical
+ items in a QGraphicsScene.
+ \since 4.2
+
+ \ingroup graphicsview-api
+
+ It provides a light-weight foundation for writing your own custom items.
+ This includes defining the item's geometry, collision detection, its
+ painting implementation and item interaction through its event handlers.
+ QGraphicsItem is part of the \l{Graphics View Framework}
+
+ \image graphicsview-items.png
+
+ For convenience, Qt provides a set of standard graphics items for the most
+ common shapes. These are:
+
+ \list
+ \o QGraphicsEllipseItem provides an ellipse item
+ \o QGraphicsLineItem provides a line item
+ \o QGraphicsPathItem provides an arbitrary path item
+ \o QGraphicsPixmapItem provides a pixmap item
+ \o QGraphicsPolygonItem provides a polygon item
+ \o QGraphicsRectItem provides a rectangular item
+ \o QGraphicsSimpleTextItem provides a simple text label item
+ \o QGraphicsTextItem provides an advanced text browser item
+ \endlist
+
+ All of an item's geometric information is based on its local coordinate
+ system. The item's position, pos(), is the only function that does not
+ operate in local coordinates, as it returns a position in parent
+ coordinates. \l {The Graphics View Coordinate System} describes the coordinate
+ system in detail.
+
+ You can set whether an item should be visible (i.e., drawn, and accepting
+ events), by calling setVisible(). Hiding an item will also hide its
+ children. Similarly, you can enable or disable an item by calling
+ setEnabled(). If you disable an item, all its children will also be
+ disabled. By default, items are both visible and enabled. To toggle
+ whether an item is selected or not, first enable selection by setting
+ the ItemIsSelectable flag, and then call setSelected(). Normally,
+ selection is toggled by the scene, as a result of user interaction.
+
+ To write your own graphics item, you first create a subclass of
+ QGraphicsItem, and then start by implementing its two pure virtual public
+ functions: boundingRect(), which returns an estimate of the area painted
+ by the item, and paint(), which implements the actual painting. For
+ example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 0
+
+ The boundingRect() function has many different purposes.
+ QGraphicsScene bases its item index on boundingRect(), and
+ QGraphicsView uses it both for culling invisible items, and for
+ determining the area that needs to be recomposed when drawing
+ overlapping items. In addition, QGraphicsItem's collision
+ detection mechanisms use boundingRect() to provide an efficient
+ cut-off. The fine grained collision algorithm in
+ collidesWithItem() is based on calling shape(), which returns an
+ accurate outline of the item's shape as a QPainterPath.
+
+ QGraphicsScene expects all items boundingRect() and shape() to
+ remain unchanged unless it is notified. If you want to change an
+ item's geometry in any way, you must first call
+ prepareGeometryChange() to allow QGraphicsScene to update its
+ bookkeeping.
+
+ Collision detection can be done in two ways:
+
+ \list 1
+
+ \o Reimplement shape() to return an accurate shape for your item,
+ and rely on the default implementation of collidesWithItem() to do
+ shape-shape intersection. This can be rather expensive if the
+ shapes are complex.
+
+ \o Reimplement collidesWithItem() to provide your own custom item
+ and shape collision algorithm.
+
+ \endlist
+
+ The contains() function can be called to determine whether the item \e
+ contains a point or not. This function can also be reimplemented by the
+ item. The default behavior of contains() is based on calling shape().
+
+ Items can contain other items, and also be contained by other items. All
+ items can have a parent item and a list of children. Unless the item has
+ no parent, its position is in \e parent coordinates (i.e., the parent's
+ local coordinates). Parent items propagate both their position and their
+ transformation to all children.
+
+ \img graphicsview-parentchild.png
+
+ \target Transformations
+ \section1 Transformations
+
+ QGraphicsItem supports projective transformations in addition to its base
+ position, pos(). There are several ways to change an item's transformation.
+ For simple transformations, you can call either of the convenience
+ functions setRotation() or setScale(), or you can pass any transformation
+ matrix to setTransform(). For advanced transformation control you also have
+ the option of setting several combined transformations by calling
+ setTransformations().
+
+ Item transformations accumulate from parent to child, so if both a parent
+ and child item are rotated 90 degrees, the child's total transformation
+ will be 180 degrees. Similarly, if the item's parent is scaled to 2x its
+ original size, its children will also be twice as large. An item's
+ transformation does not affect its own local geometry; all geometry
+ functions (e.g., contains(), update(), and all the mapping functions) still
+ operate in local coordinates. For convenience, QGraphicsItem provides the
+ functions sceneTransform(), which returns the item's total transformation
+ matrix (including its position and all parents' positions and
+ transformations), and scenePos(), which returns its position in scene
+ coordinates. To reset an item's matrix, call resetTransform().
+
+ Certain transformation operations produce a different outcome depending on
+ the order in which they are applied. For example, if you scale an
+ transform, and then rotate it, you may get a different result than if the
+ transform was rotated first. However, the order you set the transformation
+ properties on QGraphicsItem does not affect the resulting transformation;
+ QGraphicsItem always applies the properties in a fixed, defined order:
+
+ \list
+ \o The item's base transform is applied (transform())
+ \o The item's transformations list is applied in order (transformations())
+ \o The item is rotated relative to its transform origin point (rotation(), transformOriginPoint())
+ \o The item is scaled relative to its transform origin point (scale(), transformOriginPoint())
+ \endlist
+
+ \section1 Painting
+
+ The paint() function is called by QGraphicsView to paint the item's
+ contents. The item has no background or default fill of its own; whatever
+ is behind the item will shine through all areas that are not explicitly
+ painted in this function. You can call update() to schedule a repaint,
+ optionally passing the rectangle that needs a repaint. Depending on
+ whether or not the item is visible in a view, the item may or may not be
+ repainted; there is no equivalent to QWidget::repaint() in QGraphicsItem.
+
+ Items are painted by the view, starting with the parent items and then
+ drawing children, in ascending stacking order. You can set an item's
+ stacking order by calling setZValue(), and test it by calling
+ zValue(), where items with low z-values are painted before items with
+ high z-values. Stacking order applies to sibling items; parents are always
+ drawn before their children.
+
+ \section1 Sorting
+
+ All items are drawn in a defined, stable order, and this same order decides
+ which items will receive mouse input first when you click on the scene.
+ Normally you don't have to worry about sorting, as the items follow a
+ "natural order", following the logical structure of the scene.
+
+ An item's children are stacked on top of the parent, and sibling items are
+ stacked by insertion order (i.e., in the same order that they were either
+ added to the scene, or added to the same parent). If you add item A, and
+ then B, then B will be on top of A. If you then add C, the items' stacking
+ order will be A, then B, then C.
+
+ \image graphicsview-zorder.png
+
+ This example shows the stacking order of all limbs of the robot from the
+ \l{graphicsview/dragdroprobot}{Drag and Drop Robot} example. The torso is
+ the root item (all other items are children or descendants of the torso),
+ so it is drawn first. Next, the head is drawn, as it is the first item in
+ the torso's list of children. Then the upper left arm is drawn. As the
+ lower arm is a child of the upper arm, the lower arm is then drawn,
+ followed by the upper arm's next sibling, which is the upper right arm, and
+ so on.
+
+ For advanced users, there are ways to alter how your items are sorted:
+
+ \list
+ \o You can call setZValue() on an item to explicitly stack it on top of, or
+ under, other sibling items. The default Z value for an item is 0. Items
+ with the same Z value are stacked by insertion order.
+
+ \o You can call stackBefore() to reorder the list of children. This will
+ directly modify the insertion order.
+
+ \o You can set the ItemStacksBehindParent flag to stack a child item behind
+ its parent.
+ \endlist
+
+ The stacking order of two sibling items also counts for each item's
+ children and descendant items. So if one item is on top of another, then
+ all its children will also be on top of all the other item's children as
+ well.
+
+ \section1 Events
+
+ QGraphicsItem receives events from QGraphicsScene through the virtual
+ function sceneEvent(). This function distributes the most common events
+ to a set of convenience event handlers:
+
+ \list
+ \o contextMenuEvent() handles context menu events
+ \o focusInEvent() and focusOutEvent() handle focus in and out events
+ \o hoverEnterEvent(), hoverMoveEvent(), and hoverLeaveEvent() handles
+ hover enter, move and leave events
+ \o inputMethodEvent() handles input events, for accessibility support
+ \o keyPressEvent() and keyReleaseEvent() handle key press and release events
+ \o mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(), and
+ mouseDoubleClickEvent() handles mouse press, move, release, click and
+ doubleclick events
+ \endlist
+
+ You can filter events for any other item by installing event filters. This
+ functionality is separate from Qt's regular event filters (see
+ QObject::installEventFilter()), which only work on subclasses of QObject. After
+ installing your item as an event filter for another item by calling
+ installSceneEventFilter(), the filtered events will be received by the virtual
+ function sceneEventFilter(). You can remove item event filters by calling
+ removeSceneEventFilter().
+
+ \section1 Custom Data
+
+ Sometimes it's useful to register custom data with an item, be it a custom
+ item, or a standard item. You can call setData() on any item to store data
+ in it using a key-value pair (the key being an integer, and the value is a
+ QVariant). To get custom data from an item, call data(). This
+ functionality is completely untouched by Qt itself; it is provided for the
+ user's convenience.
+
+ \sa QGraphicsScene, QGraphicsView, {Graphics View Framework}
+*/
+
+/*!
+ \variable QGraphicsItem::Type
+
+ The type value returned by the virtual type() function in standard
+ graphics item classes in Qt. All such standard graphics item
+ classes in Qt are associated with a unique value for Type,
+ e.g. the value returned by QGraphicsPathItem::type() is 2.
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 18
+*/
+
+/*!
+ \variable QGraphicsItem::UserType
+
+ The lowest permitted type value for custom items (subclasses
+ of QGraphicsItem or any of the standard items). This value is
+ used in conjunction with a reimplementation of QGraphicsItem::type()
+ and declaring a Type enum value. Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 1
+
+ \note UserType = 65536
+*/
+
+/*!
+ \enum QGraphicsItem::GraphicsItemFlag
+
+ This enum describes different flags that you can set on an item to
+ toggle different features in the item's behavior.
+
+ All flags are disabled by default.
+
+ \value ItemIsMovable The item supports interactive movement using
+ the mouse. By clicking on the item and then dragging, the item
+ will move together with the mouse cursor. If the item has
+ children, all children are also moved. If the item is part of a
+ selection, all selected items are also moved. This feature is
+ provided as a convenience through the base implementation of
+ QGraphicsItem's mouse event handlers.
+
+ \value ItemIsSelectable The item supports selection. Enabling this
+ feature will enable setSelected() to toggle selection for the
+ item. It will also let the item be selected automatically as a
+ result of calling QGraphicsScene::setSelectionArea(), by clicking
+ on an item, or by using rubber band selection in QGraphicsView.
+
+ \value ItemIsFocusable The item supports keyboard input focus (i.e., it is
+ an input item). Enabling this flag will allow the item to accept focus,
+ which again allows the delivery of key events to
+ QGraphicsItem::keyPressEvent() and QGraphicsItem::keyReleaseEvent().
+
+ \value ItemClipsToShape The item clips to its own shape. The item cannot
+ draw or receive mouse, tablet, drag and drop or hover events outside its
+ shape. It is disabled by default. This behavior is enforced by
+ QGraphicsView::drawItems() or QGraphicsScene::drawItems(). This flag was
+ introduced in Qt 4.3.
+
+ \value ItemClipsChildrenToShape The item clips the painting of all its
+ descendants to its own shape. Items that are either direct or indirect
+ children of this item cannot draw outside this item's shape. By default,
+ this flag is disabled; children can draw anywhere. This behavior is
+ enforced by QGraphicsView::drawItems() or
+ QGraphicsScene::drawItems(). This flag was introduced in Qt 4.3.
+
+ \value ItemIgnoresTransformations The item ignores inherited
+ transformations (i.e., its position is still anchored to its parent, but
+ the parent or view rotation, zoom or shear transformations are ignored).
+ This flag is useful for keeping text label items horizontal and unscaled,
+ so they will still be readable if the view is transformed. When set, the
+ item's view geometry and scene geometry will be maintained separately. You
+ must call deviceTransform() to map coordinates and detect collisions in
+ the view. By default, this flag is disabled. This flag was introduced in
+ Qt 4.3. \note With this flag set you can still scale the item itself, and
+ that scale transformation will influence the item's children.
+
+ \value ItemIgnoresParentOpacity The item ignores its parent's opacity. The
+ item's effective opacity is the same as its own; it does not combine with
+ the parent's opacity. This flags allows your item to keep its absolute
+ opacity even if the parent is semitransparent. This flag was introduced in
+ Qt 4.5.
+
+ \value ItemDoesntPropagateOpacityToChildren The item doesn't propagate its
+ opacity to its children. This flag allows you to create a semitransparent
+ item that does not affect the opacity of its children. This flag was
+ introduced in Qt 4.5.
+
+ \value ItemStacksBehindParent The item is stacked behind its parent. By
+ default, child items are stacked on top of the parent item. But setting
+ this flag, the child will be stacked behind it. This flag is useful for
+ drop shadow effects and for decoration objects that follow the parent
+ item's geometry without drawing on top of it. This flag was introduced
+ in Qt 4.5.
+
+ \value ItemUsesExtendedStyleOption The item makes use of either
+ \l{QStyleOptionGraphicsItem::} {exposedRect} or
+ \l{QStyleOptionGraphicsItem::} {matrix} in
+ QStyleOptionGraphicsItem. By default, the
+ \l{QStyleOptionGraphicsItem::} {exposedRect} is initialized to the
+ item's boundingRect() and the
+ \l{QStyleOptionGraphicsItem::}{matrix} is untransformed. You can
+ enable this flag for the style options to be set up with more
+ fine-grained values. Note that
+ QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag
+ and always initialized to 1. Use
+ QStyleOptionGraphicsItem::levelOfDetailFromTransform() if you need
+ a higher value. This flag was introduced in Qt 4.6.
+
+ \value ItemHasNoContents The item does not paint anything (i.e., calling
+ paint() on the item has no effect). You should set this flag on items that
+ do not need to be painted to ensure that Graphics View avoids unnecessary
+ painting preparations. This flag was introduced in Qt 4.6.
+
+ \value ItemSendsGeometryChanges The item enables itemChange()
+ notifications for ItemPositionChange, ItemPositionHasChanged,
+ ItemMatrixChange, ItemTransformChange, ItemTransformHasChanged,
+ ItemRotationChange, ItemRotationHasChanged, ItemScaleChange, ItemScaleHasChanged,
+ ItemTransformOriginPointChange, and ItemTransformOriginPointHasChanged. For
+ performance reasons, these notifications are disabled by default. You must
+ enable this flag to receive notifications for position and transform
+ changes. This flag was introduced in Qt 4.6.
+
+ \value ItemAcceptsInputMethod The item supports input methods typically
+ used for Asian languages.
+ This flag was introduced in Qt 4.6.
+
+ \value ItemNegativeZStacksBehindParent The item automatically
+ stacks behind it's parent if it's z-value is negative. This flag
+ enables setZValue() to toggle ItemStacksBehindParent. This flag
+ was introduced in Qt 4.6.
+
+ \value ItemIsPanel The item is a panel. A panel provides activation and
+ contained focus handling. Only one panel can be active at a time (see
+ QGraphicsItem::isActive()). When no panel is active, QGraphicsScene
+ activates all non-panel items. Window items (i.e.,
+ QGraphicsItem::isWindow() returns true) are panels. This flag was
+ introduced in Qt 4.6.
+
+ \omitvalue ItemIsFocusScope \omit Internal only (for now). \endomit
+
+ \value ItemSendsScenePositionChanges The item enables itemChange()
+ notifications for ItemScenePositionHasChanged. For performance reasons,
+ these notifications are disabled by default. You must enable this flag
+ to receive notifications for scene position changes. This flag was
+ introduced in Qt 4.6.
+
+ \omitvalue ItemStopsClickFocusPropagation \omit The item stops propagating
+ click focus to items underneath when being clicked on. This flag
+ allows you create a non-focusable item that can be clicked on without
+ changing the focus. \endomit
+
+ \omitvalue ItemStopsFocusHandling \omit Same as
+ ItemStopsClickFocusPropagation, but also suppresses focus-out. This flag
+ allows you to completely take over focus handling.
+ This flag was introduced in Qt 4.7. \endomit
+*/
+
+/*!
+ \enum QGraphicsItem::GraphicsItemChange
+
+ This enum describes the state changes that are notified by
+ QGraphicsItem::itemChange(). The notifications are sent as the state
+ changes, and in some cases, adjustments can be made (see the documentation
+ for each change for details).
+
+ Note: Be careful with calling functions on the QGraphicsItem itself inside
+ itemChange(), as certain function calls can lead to unwanted
+ recursion. For example, you cannot call setPos() in itemChange() on an
+ ItemPositionChange notification, as the setPos() function will again call
+ itemChange(ItemPositionChange). Instead, you can return the new, adjusted
+ position from itemChange().
+
+ \value ItemEnabledChange The item's enabled state changes. If the item is
+ presently enabled, it will become disabled, and vice verca. The value
+ argument is the new enabled state (i.e., true or false). Do not call
+ setEnabled() in itemChange() as this notification is delivered. Instead,
+ you can return the new state from itemChange().
+
+ \value ItemEnabledHasChanged The item's enabled state has changed. The
+ value argument is the new enabled state (i.e., true or false). Do not call
+ setEnabled() in itemChange() as this notification is delivered. The return
+ value is ignored.
+
+ \value ItemMatrixChange The item's affine transformation matrix is
+ changing. This value is obsolete; you can use ItemTransformChange instead.
+
+ \value ItemPositionChange The item's position changes. This notification
+ is sent if the ItemSendsGeometryChanges flag is enabled, and when the
+ item's local position changes, relative to its parent (i.e., as a result
+ of calling setPos() or moveBy()). The value argument is the new position
+ (i.e., a QPointF). You can call pos() to get the original position. Do
+ not call setPos() or moveBy() in itemChange() as this notification is
+ delivered; instead, you can return the new, adjusted position from
+ itemChange(). After this notification, QGraphicsItem immediately sends the
+ ItemPositionHasChanged notification if the position changed.
+
+ \value ItemPositionHasChanged The item's position has changed. This
+ notification is sent if the ItemSendsGeometryChanges flag is enabled, and
+ after the item's local position, relative to its parent, has changed. The
+ value argument is the new position (the same as pos()), and QGraphicsItem
+ ignores the return value for this notification (i.e., a read-only
+ notification).
+
+ \value ItemTransformChange The item's transformation matrix changes. This
+ notification is send if the ItemSendsGeometryChanges flag is enabled, and
+ when the item's local transformation matrix changes (i.e., as a result of
+ calling setTransform(). The value argument is the new matrix (i.e., a
+ QTransform); to get the old matrix, call transform(). Do not call
+ setTransform() or set any of the transformation properties in itemChange()
+ as this notification is delivered; instead, you can return the new matrix
+ from itemChange(). This notification is not sent if you change the
+ transformation properties.
+
+ \value ItemTransformHasChanged The item's transformation matrix has
+ changed either because setTransform is called, or one of the
+ transformation properties is changed. This notification is sent if the
+ ItemSendsGeometryChanges flag is enabled, and after the item's local
+ transformation matrix has changed. The value argument is the new matrix
+ (same as transform()), and QGraphicsItem ignores the return value for this
+ notification (i.e., a read-only notification).
+
+ \value ItemRotationChange The item's rotation property changes. This
+ notification is sent if the ItemSendsGeometryChanges flag is enabled, and
+ when the item's rotation property changes (i.e., as a result of calling
+ setRotation()). The value argument is the new rotation (i.e., a double);
+ to get the old rotation, call rotation(). Do not call setRotation() in
+ itemChange() as this notification is delivered; instead, you can return
+ the new rotation from itemChange().
+
+ \value ItemRotationHasChanged The item's rotation property has changed.
+ This notification is sent if the ItemSendsGeometryChanges flag is enabled,
+ and after the item's rotation property has changed. The value argument is
+ the new rotation (i.e., a double), and QGraphicsItem ignores the return
+ value for this notification (i.e., a read-only notification). Do not call
+ setRotation() in itemChange() as this notification is delivered.
+
+ \value ItemScaleChange The item's scale property changes. This notification
+ is sent if the ItemSendsGeometryChanges flag is enabled, and when the item's
+ scale property changes (i.e., as a result of calling setScale()). The value
+ argument is the new scale (i.e., a double); to get the old scale, call
+ scale(). Do not call setScale() in itemChange() as this notification is
+ delivered; instead, you can return the new scale from itemChange().
+
+ \value ItemScaleHasChanged The item's scale property has changed. This
+ notification is sent if the ItemSendsGeometryChanges flag is enabled, and
+ after the item's scale property has changed. The value argument is the new
+ scale (i.e., a double), and QGraphicsItem ignores the return value for this
+ notification (i.e., a read-only notification). Do not call setScale() in
+ itemChange() as this notification is delivered.
+
+ \value ItemTransformOriginPointChange The item's transform origin point
+ property changes. This notification is sent if the ItemSendsGeometryChanges
+ flag is enabled, and when the item's transform origin point property changes
+ (i.e., as a result of calling setTransformOriginPoint()). The value argument
+ is the new origin point (i.e., a QPointF); to get the old origin point, call
+ transformOriginPoint(). Do not call setTransformOriginPoint() in itemChange()
+ as this notification is delivered; instead, you can return the new transform
+ origin point from itemChange().
+
+ \value ItemTransformOriginPointHasChanged The item's transform origin point
+ property has changed. This notification is sent if the ItemSendsGeometryChanges
+ flag is enabled, and after the item's transform origin point property has
+ changed. The value argument is the new origin point (i.e., a QPointF), and
+ QGraphicsItem ignores the return value for this notification (i.e., a read-only
+ notification). Do not call setTransformOriginPoint() in itemChange() as this
+ notification is delivered.
+
+ \value ItemSelectedChange The item's selected state changes. If the item is
+ presently selected, it will become unselected, and vice verca. The value
+ argument is the new selected state (i.e., true or false). Do not call
+ setSelected() in itemChange() as this notification is delivered; instead, you
+ can return the new selected state from itemChange().
+
+ \value ItemSelectedHasChanged The item's selected state has changed. The
+ value argument is the new selected state (i.e., true or false). Do not
+ call setSelected() in itemChange() as this notification is delivered. The
+ return value is ignored.
+
+ \value ItemVisibleChange The item's visible state changes. If the item is
+ presently visible, it will become invisible, and vice verca. The value
+ argument is the new visible state (i.e., true or false). Do not call
+ setVisible() in itemChange() as this notification is delivered; instead,
+ you can return the new visible state from itemChange().
+
+ \value ItemVisibleHasChanged The item's visible state has changed. The
+ value argument is the new visible state (i.e., true or false). Do not call
+ setVisible() in itemChange() as this notification is delivered. The return
+ value is ignored.
+
+ \value ItemParentChange The item's parent changes. The value argument is
+ the new parent item (i.e., a QGraphicsItem pointer). Do not call
+ setParentItem() in itemChange() as this notification is delivered;
+ instead, you can return the new parent from itemChange().
+
+ \value ItemParentHasChanged The item's parent has changed. The value
+ argument is the new parent (i.e., a pointer to a QGraphicsItem). Do not
+ call setParentItem() in itemChange() as this notification is
+ delivered. The return value is ignored.
+
+ \value ItemChildAddedChange A child is added to this item. The value
+ argument is the new child item (i.e., a QGraphicsItem pointer). Do not
+ pass this item to any item's setParentItem() function as this notification
+ is delivered. The return value is unused; you cannot adjust anything in
+ this notification. Note that the new child might not be fully constructed
+ when this notification is sent; calling pure virtual functions on
+ the child can lead to a crash.
+
+ \value ItemChildRemovedChange A child is removed from this item. The value
+ argument is the child item that is about to be removed (i.e., a
+ QGraphicsItem pointer). The return value is unused; you cannot adjust
+ anything in this notification.
+
+ \value ItemSceneChange The item is moved to a new scene. This notification is
+ also sent when the item is added to its initial scene, and when it is removed.
+ The item's scene() is the old scene (or 0 if the item has not been added to a
+ scene yet). The value argument is the new scene (i.e., a QGraphicsScene
+ pointer), or a null pointer if the item is removed from a scene. Do not
+ override this change by passing this item to QGraphicsScene::addItem() as this
+ notification is delivered; instead, you can return the new scene from
+ itemChange(). Use this feature with caution; objecting to a scene change can
+ quickly lead to unwanted recursion.
+
+ \value ItemSceneHasChanged The item's scene has changed. The item's scene() is
+ the new scene. This notification is also sent when the item is added to its
+ initial scene, and when it is removed.The value argument is the new scene
+ (i.e., a pointer to a QGraphicsScene). Do not call setScene() in itemChange()
+ as this notification is delivered. The return value is ignored.
+
+ \value ItemCursorChange The item's cursor changes. The value argument is
+ the new cursor (i.e., a QCursor). Do not call setCursor() in itemChange()
+ as this notification is delivered. Instead, you can return a new cursor
+ from itemChange().
+
+ \value ItemCursorHasChanged The item's cursor has changed. The value
+ argument is the new cursor (i.e., a QCursor). Do not call setCursor() as
+ this notification is delivered. The return value is ignored.
+
+ \value ItemToolTipChange The item's tooltip changes. The value argument is
+ the new tooltip (i.e., a QToolTip). Do not call setToolTip() in
+ itemChange() as this notification is delivered. Instead, you can return a
+ new tooltip from itemChange().
+
+ \value ItemToolTipHasChanged The item's tooltip has changed. The value
+ argument is the new tooltip (i.e., a QToolTip). Do not call setToolTip()
+ as this notification is delivered. The return value is ignored.
+
+ \value ItemFlagsChange The item's flags change. The value argument is the
+ new flags (i.e., a quint32). Do not call setFlags() in itemChange() as
+ this notification is delivered. Instead, you can return the new flags from
+ itemChange().
+
+ \value ItemFlagsHaveChanged The item's flags have changed. The value
+ argument is the new flags (i.e., a quint32). Do not call setFlags() in
+ itemChange() as this notification is delivered. The return value is
+ ignored.
+
+ \value ItemZValueChange The item's Z-value changes. The value argument is
+ the new Z-value (i.e., a double). Do not call setZValue() in itemChange()
+ as this notification is delivered. Instead, you can return a new Z-value
+ from itemChange().
+
+ \value ItemZValueHasChanged The item's Z-value has changed. The value
+ argument is the new Z-value (i.e., a double). Do not call setZValue() as
+ this notification is delivered. The return value is ignored.
+
+ \value ItemOpacityChange The item's opacity changes. The value argument is
+ the new opacity (i.e., a double). Do not call setOpacity() in itemChange()
+ as this notification is delivered. Instead, you can return a new opacity
+ from itemChange().
+
+ \value ItemOpacityHasChanged The item's opacity has changed. The value
+ argument is the new opacity (i.e., a double). Do not call setOpacity() as
+ this notification is delivered. The return value is ignored.
+
+ \value ItemScenePositionHasChanged The item's scene position has changed.
+ This notification is sent if the ItemSendsScenePositionChanges flag is
+ enabled, and after the item's scene position has changed (i.e., the
+ position or transformation of the item itself or the position or
+ transformation of any ancestor has changed). The value argument is the
+ new scene position (the same as scenePos()), and QGraphicsItem ignores
+ the return value for this notification (i.e., a read-only notification).
+*/
+
+/*!
+ \enum QGraphicsItem::CacheMode
+ \since 4.4
+
+ This enum describes QGraphicsItem's cache modes. Caching is used to speed
+ up rendering by allocating and rendering to an off-screen pixel buffer,
+ which can be reused when the item requires redrawing. For some paint
+ devices, the cache is stored directly in graphics memory, which makes
+ rendering very quick.
+
+ \value NoCache The default; all item caching is
+ disabled. QGraphicsItem::paint() is called every time the item needs
+ redrawing.
+
+ \value ItemCoordinateCache Caching is enabled for the item's logical
+ (local) coordinate system. QGraphicsItem creates an off-screen pixel
+ buffer with a configurable size / resolution that you can pass to
+ QGraphicsItem::setCacheMode(). Rendering quality will typically degrade,
+ depending on the resolution of the cache and the item transformation. The
+ first time the item is redrawn, it will render itself into the cache, and
+ the cache is then reused for every subsequent expose. The cache is also
+ reused as the item is transformed. To adjust the resolution of the cache,
+ you can call setCacheMode() again.
+
+ \value DeviceCoordinateCache Caching is enabled at the paint device level,
+ in device coordinates. This mode is for items that can move, but are not
+ rotated, scaled or sheared. If the item is transformed directly or
+ indirectly, the cache will be regenerated automatically. Unlike
+ ItemCoordinateCacheMode, DeviceCoordinateCache always renders at maximum
+ quality.
+
+ \sa QGraphicsItem::setCacheMode()
+*/
+
+/*!
+ \enum QGraphicsItem::Extension
+ \internal
+
+ Note: This is provided as a hook to avoid future problems related
+ to adding virtual functions. See also extension(),
+ supportsExtension() and setExtension().
+*/
+
+/*!
+ \enum QGraphicsItem::PanelModality
+ \since 4.6
+
+ This enum specifies the behavior of a modal panel. A modal panel
+ is one that blocks input to other panels. Note that items that
+ are children of a modal panel are not blocked.
+
+ The values are:
+
+ \value NonModal The panel is not modal and does not block input to
+ other panels. This is the default value for panels.
+
+ \value PanelModal The panel is modal to a single item hierarchy
+ and blocks input to its parent pane, all grandparent panels, and
+ all siblings of its parent and grandparent panels.
+
+ \value SceneModal The window is modal to the entire scene and
+ blocks input to all panels.
+
+ \sa QGraphicsItem::setPanelModality(), QGraphicsItem::panelModality(), QGraphicsItem::ItemIsPanel
+*/
+
+#include "qgraphicsitem.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include "qgraphicsscene.h"
+#include "qgraphicsscene_p.h"
+#include "qgraphicssceneevent.h"
+#include "qgraphicsview.h"
+#include "qgraphicswidget.h"
+#include "qgraphicsproxywidget.h"
+#include "qgraphicsscenebsptreeindex_p.h"
+#include <QtCore/qbitarray.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qnumeric.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qbitmap.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpainterpath.h>
+#include <QtGui/qpixmapcache.h>
+#include <QtGui/qstyleoption.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qinputcontext.h>
+#include <QtGui/qgraphicseffect.h>
+#ifndef QT_NO_ACCESSIBILITY
+# include "qaccessible.h"
+#endif
+
+#include <private/qgraphicsitem_p.h>
+#include <private/qgraphicswidget_p.h>
+#include <private/qtextcontrol_p.h>
+#include <private/qtextdocumentlayout_p.h>
+#include <private/qtextengine_p.h>
+#include <private/qwidget_p.h>
+#include <private/qapplication_p.h>
+
+#ifdef Q_WS_X11
+#include <private/qt_x11_p.h>
+#include <private/qpixmap_x11_p.h>
+#endif
+
+#include <private/qgesturemanager_p.h>
+
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+static inline void _q_adjustRect(QRect *rect)
+{
+ Q_ASSERT(rect);
+ if (!rect->width())
+ rect->adjust(0, 0, 1, 0);
+ if (!rect->height())
+ rect->adjust(0, 0, 0, 1);
+}
+
+/*
+ ### Move this into QGraphicsItemPrivate
+ */
+class QGraphicsItemCustomDataStore
+{
+public:
+ QMap<const QGraphicsItem *, QMap<int, QVariant> > data;
+};
+Q_GLOBAL_STATIC(QGraphicsItemCustomDataStore, qt_dataStore)
+
+/*!
+ \internal
+
+ Returns a QPainterPath of \a path when stroked with the \a pen.
+ Ignoring dash pattern.
+*/
+static QPainterPath qt_graphicsItem_shapeFromPath(const QPainterPath &path, const QPen &pen)
+{
+ // We unfortunately need this hack as QPainterPathStroker will set a width of 1.0
+ // if we pass a value of 0.0 to QPainterPathStroker::setWidth()
+ const qreal penWidthZero = qreal(0.00000001);
+
+ if (path == QPainterPath())
+ return path;
+ QPainterPathStroker ps;
+ ps.setCapStyle(pen.capStyle());
+ if (pen.widthF() <= 0.0)
+ ps.setWidth(penWidthZero);
+ else
+ ps.setWidth(pen.widthF());
+ ps.setJoinStyle(pen.joinStyle());
+ ps.setMiterLimit(pen.miterLimit());
+ QPainterPath p = ps.createStroke(path);
+ p.addPath(path);
+ return p;
+}
+
+/*!
+ \internal
+
+ Propagates the ancestor flag \a flag with value \a enabled to all this
+ item's children. If \a root is false, the flag is also set on this item
+ (default is true).
+*/
+void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag childFlag,
+ AncestorFlag flag, bool enabled, bool root)
+{
+ Q_Q(QGraphicsItem);
+ if (root) {
+ // For root items only. This is the item that has either enabled or
+ // disabled \a childFlag, or has been reparented.
+ switch (int(childFlag)) {
+ case -2:
+ flag = AncestorFiltersChildEvents;
+ enabled = q->filtersChildEvents();
+ break;
+ case -1:
+ flag = AncestorHandlesChildEvents;
+ enabled = q->handlesChildEvents();
+ break;
+ case QGraphicsItem::ItemClipsChildrenToShape:
+ flag = AncestorClipsChildren;
+ enabled = flags & QGraphicsItem::ItemClipsChildrenToShape;
+ break;
+ case QGraphicsItem::ItemIgnoresTransformations:
+ flag = AncestorIgnoresTransformations;
+ enabled = flags & QGraphicsItem::ItemIgnoresTransformations;
+ break;
+ default:
+ return;
+ }
+
+ if (parent) {
+ // Inherit the enabled-state from our parents.
+ if ((parent->d_ptr->ancestorFlags & flag)
+ || (int(parent->d_ptr->flags & childFlag) == childFlag)
+ || (childFlag == -1 && parent->d_ptr->handlesChildEvents)
+ || (childFlag == -2 && parent->d_ptr->filtersDescendantEvents)) {
+ enabled = true;
+ ancestorFlags |= flag;
+ } else {
+ ancestorFlags &= ~flag;
+ }
+ } else {
+ // Top-level root items don't have any ancestors, so there are no
+ // ancestor flags either.
+ ancestorFlags = 0;
+ }
+ } else {
+ // Don't set or propagate the ancestor flag if it's already correct.
+ if (((ancestorFlags & flag) && enabled) || (!(ancestorFlags & flag) && !enabled))
+ return;
+
+ // Set the flag.
+ if (enabled)
+ ancestorFlags |= flag;
+ else
+ ancestorFlags &= ~flag;
+
+ // Don't process children if the item has the main flag set on itself.
+ if ((childFlag != -1 && int(flags & childFlag) == childFlag)
+ || (int(childFlag) == -1 && handlesChildEvents)
+ || (int(childFlag) == -2 && filtersDescendantEvents))
+ return;
+ }
+
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->updateAncestorFlag(childFlag, flag, enabled, false);
+}
+
+void QGraphicsItemPrivate::updateAncestorFlags()
+{
+ int flags = 0;
+ if (parent) {
+ // Inherit the parent's ancestor flags.
+ QGraphicsItemPrivate *pd = parent->d_ptr.data();
+ flags = pd->ancestorFlags;
+
+ // Add in flags from the parent.
+ if (pd->filtersDescendantEvents)
+ flags |= AncestorFiltersChildEvents;
+ if (pd->handlesChildEvents)
+ flags |= AncestorHandlesChildEvents;
+ if (pd->flags & QGraphicsItem::ItemClipsChildrenToShape)
+ flags |= AncestorClipsChildren;
+ if (pd->flags & QGraphicsItem::ItemIgnoresTransformations)
+ flags |= AncestorIgnoresTransformations;
+ }
+
+ if (ancestorFlags == flags)
+ return; // No change; stop propagation.
+ ancestorFlags = flags;
+
+ // Propagate to children recursively.
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->updateAncestorFlags();
+}
+
+/*!
+ \internal
+
+ Propagates item group membership.
+*/
+void QGraphicsItemPrivate::setIsMemberOfGroup(bool enabled)
+{
+ Q_Q(QGraphicsItem);
+ isMemberOfGroup = enabled;
+ if (!qgraphicsitem_cast<QGraphicsItemGroup *>(q)) {
+ foreach (QGraphicsItem *child, children)
+ child->d_func()->setIsMemberOfGroup(enabled);
+ }
+}
+
+/*!
+ \internal
+
+ Maps any item pos properties of \a event to \a item's coordinate system.
+*/
+void QGraphicsItemPrivate::remapItemPos(QEvent *event, QGraphicsItem *item)
+{
+ Q_Q(QGraphicsItem);
+ switch (event->type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::GraphicsSceneMouseDoubleClick: {
+ QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent *>(event);
+ mouseEvent->setPos(item->mapFromItem(q, mouseEvent->pos()));
+ mouseEvent->setLastPos(item->mapFromItem(q, mouseEvent->pos()));
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (mouseEvent->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent->setButtonDownPos(button, item->mapFromItem(q, mouseEvent->buttonDownPos(button)));
+ }
+ }
+ break;
+ }
+ case QEvent::GraphicsSceneWheel: {
+ QGraphicsSceneWheelEvent *wheelEvent = static_cast<QGraphicsSceneWheelEvent *>(event);
+ wheelEvent->setPos(item->mapFromItem(q, wheelEvent->pos()));
+ break;
+ }
+ case QEvent::GraphicsSceneContextMenu: {
+ QGraphicsSceneContextMenuEvent *contextEvent = static_cast<QGraphicsSceneContextMenuEvent *>(event);
+ contextEvent->setPos(item->mapFromItem(q, contextEvent->pos()));
+ break;
+ }
+ case QEvent::GraphicsSceneHoverMove: {
+ QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event);
+ hoverEvent->setPos(item->mapFromItem(q, hoverEvent->pos()));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/*!
+ \internal
+
+ Maps the point \a pos from scene to item coordinates. If \a view is passed and the item
+ is untransformable, this function will correctly map \a pos from the scene using the
+ view's transformation.
+*/
+QPointF QGraphicsItemPrivate::genericMapFromScene(const QPointF &pos,
+ const QWidget *viewport) const
+{
+ Q_Q(const QGraphicsItem);
+ if (!itemIsUntransformable())
+ return q->mapFromScene(pos);
+ QGraphicsView *view = 0;
+ if (viewport)
+ view = qobject_cast<QGraphicsView *>(viewport->parentWidget());
+ if (!view)
+ return q->mapFromScene(pos);
+ // ### More ping pong than needed.
+ return q->deviceTransform(view->viewportTransform()).inverted().map(view->mapFromScene(pos));
+}
+
+/*!
+ \internal
+
+ Combines this item's position and transform onto \a transform.
+
+ If you need to change this function (e.g., adding more transformation
+ modes / options), make sure to change all places marked with COMBINE.
+*/
+void QGraphicsItemPrivate::combineTransformToParent(QTransform *x, const QTransform *viewTransform) const
+{
+ // COMBINE
+ if (viewTransform && itemIsUntransformable()) {
+ *x = q_ptr->deviceTransform(*viewTransform);
+ } else {
+ if (transformData)
+ *x *= transformData->computedFullTransform();
+ if (!pos.isNull())
+ *x *= QTransform::fromTranslate(pos.x(), pos.y());
+ }
+}
+
+/*!
+ \internal
+
+ Combines this item's position and transform onto \a transform.
+
+ If you need to change this function (e.g., adding more transformation
+ modes / options), make sure to change QGraphicsItem::deviceTransform() as
+ well.
+*/
+void QGraphicsItemPrivate::combineTransformFromParent(QTransform *x, const QTransform *viewTransform) const
+{
+ // COMBINE
+ if (viewTransform && itemIsUntransformable()) {
+ *x = q_ptr->deviceTransform(*viewTransform);
+ } else {
+ x->translate(pos.x(), pos.y());
+ if (transformData)
+ *x = transformData->computedFullTransform(x);
+ }
+}
+
+void QGraphicsItemPrivate::updateSceneTransformFromParent()
+{
+ if (parent) {
+ Q_ASSERT(!parent->d_ptr->dirtySceneTransform);
+ if (parent->d_ptr->sceneTransformTranslateOnly) {
+ sceneTransform = QTransform::fromTranslate(parent->d_ptr->sceneTransform.dx() + pos.x(),
+ parent->d_ptr->sceneTransform.dy() + pos.y());
+ } else {
+ sceneTransform = parent->d_ptr->sceneTransform;
+ sceneTransform.translate(pos.x(), pos.y());
+ }
+ if (transformData) {
+ sceneTransform = transformData->computedFullTransform(&sceneTransform);
+ sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+ } else {
+ sceneTransformTranslateOnly = parent->d_ptr->sceneTransformTranslateOnly;
+ }
+ } else if (!transformData) {
+ sceneTransform = QTransform::fromTranslate(pos.x(), pos.y());
+ sceneTransformTranslateOnly = 1;
+ } else if (transformData->onlyTransform) {
+ sceneTransform = transformData->transform;
+ if (!pos.isNull())
+ sceneTransform *= QTransform::fromTranslate(pos.x(), pos.y());
+ sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+ } else if (pos.isNull()) {
+ sceneTransform = transformData->computedFullTransform();
+ sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+ } else {
+ sceneTransform = QTransform::fromTranslate(pos.x(), pos.y());
+ sceneTransform = transformData->computedFullTransform(&sceneTransform);
+ sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+ }
+ dirtySceneTransform = 0;
+}
+
+/*!
+ \internal
+
+ This helper function helped us add input method query support in
+ Qt 4.4.1 without having to reimplement the inputMethodQuery()
+ function in QGraphicsProxyWidget. ### Qt 5: Remove. We cannot
+ remove it in 4.5+ even if we do reimplement the function properly,
+ because apps compiled with 4.4 will not be able to call the
+ reimplementation.
+*/
+QVariant QGraphicsItemPrivate::inputMethodQueryHelper(Qt::InputMethodQuery query) const
+{
+ Q_UNUSED(query);
+ return QVariant();
+}
+
+/*!
+ \internal
+
+ Make sure not to trigger any pure virtual function calls (e.g.,
+ prepareGeometryChange) if the item is in its destructor, i.e.
+ inDestructor is 1.
+*/
+void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, const QVariant *newParentVariant,
+ const QVariant *thisPointerVariant)
+{
+ Q_Q(QGraphicsItem);
+ if (newParent == parent)
+ return;
+
+ if (isWidget)
+ static_cast<QGraphicsWidgetPrivate *>(this)->fixFocusChainBeforeReparenting((newParent &&
+ newParent->isWidget()) ? static_cast<QGraphicsWidget *>(newParent) : 0,
+ scene);
+ if (scene) {
+ // Deliver the change to the index
+ if (scene->d_func()->indexMethod != QGraphicsScene::NoIndex)
+ scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParent);
+
+ // Disable scene pos notifications for old ancestors
+ if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
+ scene->d_func()->setScenePosItemEnabled(q, false);
+ }
+
+ if (subFocusItem && parent) {
+ // Make sure none of the old parents point to this guy.
+ subFocusItem->d_ptr->clearSubFocus(parent);
+ }
+
+ // We anticipate geometry changes. If the item is deleted, it will be
+ // removed from the index at a later stage, and the whole scene will be
+ // updated.
+ if (!inDestructor)
+ q_ptr->prepareGeometryChange();
+
+ if (parent) {
+ // Remove from current parent
+ parent->d_ptr->removeChild(q);
+ if (thisPointerVariant)
+ parent->itemChange(QGraphicsItem::ItemChildRemovedChange, *thisPointerVariant);
+ }
+
+ // Update toplevelitem list. If this item is being deleted, its parent
+ // will be 0 but we don't want to register/unregister it in the TLI list.
+ if (scene && !inDestructor) {
+ if (parent && !newParent) {
+ scene->d_func()->registerTopLevelItem(q);
+ } else if (!parent && newParent) {
+ scene->d_func()->unregisterTopLevelItem(q);
+ }
+ }
+
+ // Ensure any last parent focus scope does not point to this item or any of
+ // its descendents.
+ QGraphicsItem *p = parent;
+ QGraphicsItem *parentFocusScopeItem = 0;
+ while (p) {
+ if (p->d_ptr->flags & QGraphicsItem::ItemIsFocusScope) {
+ // If this item's focus scope's focus scope item points
+ // to this item or a descendent, then clear it.
+ QGraphicsItem *fsi = p->d_ptr->focusScopeItem;
+ if (q_ptr == fsi || q_ptr->isAncestorOf(fsi)) {
+ parentFocusScopeItem = fsi;
+ p->d_ptr->focusScopeItem = 0;
+ fsi->d_ptr->focusScopeItemChange(false);
+ }
+ break;
+ }
+ p = p->d_ptr->parent;
+ }
+
+ // Update graphics effect optimization flag
+ if (newParent && (graphicsEffect || mayHaveChildWithGraphicsEffect))
+ newParent->d_ptr->updateChildWithGraphicsEffectFlagRecursively();
+
+ // Update focus scope item ptr in new scope.
+ QGraphicsItem *newFocusScopeItem = subFocusItem ? subFocusItem : parentFocusScopeItem;
+ if (newFocusScopeItem && newParent) {
+ if (subFocusItem) {
+ // Find the subFocusItem's topmost focus scope.
+ QGraphicsItem *ancestorScope = 0;
+ QGraphicsItem *p = subFocusItem->d_ptr->parent;
+ while (p) {
+ if (p->d_ptr->flags & QGraphicsItem::ItemIsFocusScope)
+ ancestorScope = p;
+ if (p->d_ptr->flags & QGraphicsItem::ItemIsPanel)
+ break;
+ p = p->d_ptr->parent;
+ }
+ if (ancestorScope)
+ newFocusScopeItem = ancestorScope;
+ }
+
+ QGraphicsItem *p = newParent;
+ while (p) {
+ if (p->d_ptr->flags & QGraphicsItem::ItemIsFocusScope) {
+ p->d_ptr->focusScopeItem = newFocusScopeItem;
+ newFocusScopeItem->d_ptr->focusScopeItemChange(true);
+ // Ensure the new item is no longer the subFocusItem. The
+ // only way to set focus on a child of a focus scope is
+ // by setting focus on the scope itself.
+ if (subFocusItem && !p->focusItem())
+ subFocusItem->d_ptr->clearSubFocus();
+ break;
+ }
+ p = p->d_ptr->parent;
+ }
+ }
+
+ // Resolve depth.
+ invalidateDepthRecursively();
+
+ if ((parent = newParent)) {
+ if (parent->d_func()->scene && parent->d_func()->scene != scene) {
+ // Move this item to its new parent's scene
+ parent->d_func()->scene->addItem(q);
+ } else if (!parent->d_func()->scene && scene) {
+ // Remove this item from its former scene
+ scene->removeItem(q);
+ }
+
+ parent->d_ptr->addChild(q);
+ if (thisPointerVariant)
+ parent->itemChange(QGraphicsItem::ItemChildAddedChange, *thisPointerVariant);
+ if (scene) {
+ // Re-enable scene pos notifications for new ancestors
+ if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
+ scene->d_func()->setScenePosItemEnabled(q, true);
+ }
+
+ // Propagate dirty flags to the new parent
+ markParentDirty(/*updateBoundingRect=*/true);
+
+ // Inherit ancestor flags from the new parent.
+ updateAncestorFlags();
+
+ // Update item visible / enabled.
+ if (parent->d_ptr->visible != visible) {
+ if (!parent->d_ptr->visible || !explicitlyHidden)
+ setVisibleHelper(parent->d_ptr->visible, /* explicit = */ false, /* update = */ false);
+ }
+ if (parent->isEnabled() != enabled) {
+ if (!parent->d_ptr->enabled || !explicitlyDisabled)
+ setEnabledHelper(parent->d_ptr->enabled, /* explicit = */ false, /* update = */ false);
+ }
+
+ // Auto-activate if visible and the parent is active.
+ if (visible && parent->isActive())
+ q->setActive(true);
+ } else {
+ // Inherit ancestor flags from the new parent.
+ updateAncestorFlags();
+
+ if (!inDestructor) {
+ // Update item visible / enabled.
+ if (!visible && !explicitlyHidden)
+ setVisibleHelper(true, /* explicit = */ false);
+ if (!enabled && !explicitlyDisabled)
+ setEnabledHelper(true, /* explicit = */ false);
+ }
+ }
+
+ dirtySceneTransform = 1;
+ if (!inDestructor && (transformData || (newParent && newParent->d_ptr->transformData)))
+ transformChanged();
+
+ // Restore the sub focus chain.
+ if (subFocusItem) {
+ subFocusItem->d_ptr->setSubFocus(newParent);
+ if (parent && parent->isActive())
+ subFocusItem->setFocus();
+ }
+
+ // Deliver post-change notification
+ if (newParentVariant)
+ q->itemChange(QGraphicsItem::ItemParentHasChanged, *newParentVariant);
+
+ if (isObject)
+ emit static_cast<QGraphicsObject *>(q)->parentChanged();
+}
+
+/*!
+ \internal
+
+ Returns the bounding rect of this item's children (excluding itself).
+*/
+void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rect, QGraphicsItem *topMostEffectItem)
+{
+ Q_Q(QGraphicsItem);
+
+ QRectF childrenRect;
+ QRectF *result = rect;
+ rect = &childrenRect;
+ const bool setTopMostEffectItem = !topMostEffectItem;
+
+ for (int i = 0; i < children.size(); ++i) {
+ QGraphicsItem *child = children.at(i);
+ QGraphicsItemPrivate *childd = child->d_ptr.data();
+ if (setTopMostEffectItem)
+ topMostEffectItem = child;
+ bool hasPos = !childd->pos.isNull();
+ if (hasPos || childd->transformData) {
+ // COMBINE
+ QTransform matrix = childd->transformToParent();
+ if (x)
+ matrix *= *x;
+ *rect |= matrix.mapRect(child->d_ptr->effectiveBoundingRect(topMostEffectItem));
+ if (!childd->children.isEmpty())
+ childd->childrenBoundingRectHelper(&matrix, rect, topMostEffectItem);
+ } else {
+ if (x)
+ *rect |= x->mapRect(child->d_ptr->effectiveBoundingRect(topMostEffectItem));
+ else
+ *rect |= child->d_ptr->effectiveBoundingRect(topMostEffectItem);
+ if (!childd->children.isEmpty())
+ childd->childrenBoundingRectHelper(x, rect, topMostEffectItem);
+ }
+ }
+
+ if (flags & QGraphicsItem::ItemClipsChildrenToShape){
+ if (x)
+ *rect &= x->mapRect(q->boundingRect());
+ else
+ *rect &= q->boundingRect();
+ }
+
+ *result |= *rect;
+}
+
+void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform,
+ const QRegion &exposedRegion, bool allItems) const
+{
+ Q_ASSERT(option);
+ Q_Q(const QGraphicsItem);
+
+ // Initialize standard QStyleOption values.
+ const QRectF brect = q->boundingRect();
+ option->state = QStyle::State_None;
+ option->rect = brect.toRect();
+ option->levelOfDetail = 1;
+ option->exposedRect = brect;
+ if (selected)
+ option->state |= QStyle::State_Selected;
+ if (enabled)
+ option->state |= QStyle::State_Enabled;
+ if (q->hasFocus())
+ option->state |= QStyle::State_HasFocus;
+ if (scene) {
+ if (scene->d_func()->hoverItems.contains(q_ptr))
+ option->state |= QStyle::State_MouseOver;
+ if (q == scene->mouseGrabberItem())
+ option->state |= QStyle::State_Sunken;
+ }
+
+ if (!(flags & QGraphicsItem::ItemUsesExtendedStyleOption))
+ return;
+
+ // Initialize QStyleOptionGraphicsItem specific values (matrix, exposedRect).
+ option->matrix = worldTransform.toAffine(); //### discards perspective
+
+ if (!allItems) {
+ // Determine the item's exposed area
+ option->exposedRect = QRectF();
+ const QTransform reverseMap = worldTransform.inverted();
+ const QVector<QRect> exposedRects(exposedRegion.rects());
+ for (int i = 0; i < exposedRects.size(); ++i) {
+ option->exposedRect |= reverseMap.mapRect(QRectF(exposedRects.at(i)));
+ if (option->exposedRect.contains(brect))
+ break;
+ }
+ option->exposedRect &= brect;
+ }
+}
+
+/*!
+ \internal
+
+ Empty all cached pixmaps from the pixmap cache.
+*/
+void QGraphicsItemCache::purge()
+{
+ QPixmapCache::remove(key);
+ key = QPixmapCache::Key();
+ QMutableMapIterator<QPaintDevice *, DeviceData> it(deviceData);
+ while (it.hasNext()) {
+ DeviceData &data = it.next().value();
+ QPixmapCache::remove(data.key);
+ data.cacheIndent = QPoint();
+ }
+ deviceData.clear();
+ allExposed = true;
+ exposed.clear();
+}
+
+/*!
+ Constructs a QGraphicsItem with the given \a parent item.
+ It does not modify the parent object returned by QObject::parent().
+
+ If \a parent is 0, you can add the item to a scene by calling
+ QGraphicsScene::addItem(). The item will then become a top-level item.
+
+ \sa QGraphicsScene::addItem(), setParentItem()
+*/
+QGraphicsItem::QGraphicsItem(QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : d_ptr(new QGraphicsItemPrivate)
+{
+ d_ptr->q_ptr = this;
+ setParentItem(parent);
+
+ if (scene && parent && parent->scene() != scene) {
+ qWarning("QGraphicsItem::QGraphicsItem: ignoring scene (%p), which is"
+ " different from parent's scene (%p)",
+ scene, parent->scene());
+ return;
+ }
+ if (scene && !parent)
+ scene->addItem(this);
+}
+
+/*!
+ \internal
+*/
+QGraphicsItem::QGraphicsItem(QGraphicsItemPrivate &dd, QGraphicsItem *parent,
+ QGraphicsScene *scene)
+ : d_ptr(&dd)
+{
+ d_ptr->q_ptr = this;
+ setParentItem(parent);
+
+ if (scene && parent && parent->scene() != scene) {
+ qWarning("QGraphicsItem::QGraphicsItem: ignoring scene (%p), which is"
+ " different from parent's scene (%p)",
+ scene, parent->scene());
+ return;
+ }
+ if (scene && !parent)
+ scene->addItem(this);
+}
+
+/*!
+ Destroys the QGraphicsItem and all its children. If this item is currently
+ associated with a scene, the item will be removed from the scene before it
+ is deleted.
+
+ \note It is more efficient to remove the item from the QGraphicsScene before
+ destroying the item.
+*/
+QGraphicsItem::~QGraphicsItem()
+{
+ if (d_ptr->isObject) {
+ QGraphicsObject *o = static_cast<QGraphicsObject *>(this);
+ QObjectPrivate *p = QObjectPrivate::get(o);
+ p->wasDeleted = true;
+ if (p->declarativeData) {
+ QAbstractDeclarativeData::destroyed(p->declarativeData, o);
+ p->declarativeData = 0;
+ }
+ }
+
+ d_ptr->inDestructor = 1;
+ d_ptr->removeExtraItemCache();
+
+#ifndef QT_NO_GESTURES
+ if (d_ptr->isObject && !d_ptr->gestureContext.isEmpty()) {
+ QGraphicsObject *o = static_cast<QGraphicsObject *>(this);
+ if (QGestureManager *manager = QGestureManager::instance()) {
+ foreach (Qt::GestureType type, d_ptr->gestureContext.keys())
+ manager->cleanupCachedGestures(o, type);
+ }
+ }
+#endif
+
+ clearFocus();
+
+ // Update focus scope item ptr.
+ QGraphicsItem *p = d_ptr->parent;
+ while (p) {
+ if (p->flags() & ItemIsFocusScope) {
+ if (p->d_ptr->focusScopeItem == this)
+ p->d_ptr->focusScopeItem = 0;
+ break;
+ }
+ p = p->d_ptr->parent;
+ }
+
+ if (!d_ptr->children.isEmpty()) {
+ while (!d_ptr->children.isEmpty())
+ delete d_ptr->children.first();
+ Q_ASSERT(d_ptr->children.isEmpty());
+ }
+
+ if (d_ptr->scene) {
+ d_ptr->scene->d_func()->removeItemHelper(this);
+ } else {
+ d_ptr->resetFocusProxy();
+ setParentItem(0);
+ }
+
+#ifndef QT_NO_GRAPHICSEFFECT
+ delete d_ptr->graphicsEffect;
+#endif //QT_NO_GRAPHICSEFFECT
+ if (d_ptr->transformData) {
+ for(int i = 0; i < d_ptr->transformData->graphicsTransforms.size(); ++i) {
+ QGraphicsTransform *t = d_ptr->transformData->graphicsTransforms.at(i);
+ static_cast<QGraphicsTransformPrivate *>(t->d_ptr.data())->item = 0;
+ delete t;
+ }
+ }
+ delete d_ptr->transformData;
+
+ if (QGraphicsItemCustomDataStore *dataStore = qt_dataStore())
+ dataStore->data.remove(this);
+}
+
+/*!
+ Returns the current scene for the item, or 0 if the item is not stored in
+ a scene.
+
+ To add or move an item to a scene, call QGraphicsScene::addItem().
+*/
+QGraphicsScene *QGraphicsItem::scene() const
+{
+ return d_ptr->scene;
+}
+
+/*!
+ Returns a pointer to this item's item group, or 0 if this item is not
+ member of a group.
+
+ \sa QGraphicsItemGroup, QGraphicsScene::createItemGroup()
+*/
+QGraphicsItemGroup *QGraphicsItem::group() const
+{
+ if (!d_ptr->isMemberOfGroup)
+ return 0;
+ QGraphicsItem *parent = const_cast<QGraphicsItem *>(this);
+ while ((parent = parent->d_ptr->parent)) {
+ if (QGraphicsItemGroup *group = qgraphicsitem_cast<QGraphicsItemGroup *>(parent))
+ return group;
+ }
+ // Unreachable; if d_ptr->isMemberOfGroup is != 0, then one parent of this
+ // item is a group item.
+ return 0;
+}
+
+/*!
+ Adds this item to the item group \a group. If \a group is 0, this item is
+ removed from any current group and added as a child of the previous
+ group's parent.
+
+ \sa group(), QGraphicsScene::createItemGroup()
+*/
+void QGraphicsItem::setGroup(QGraphicsItemGroup *group)
+{
+ if (!group) {
+ if (QGraphicsItemGroup *group = this->group())
+ group->removeFromGroup(this);
+ } else {
+ group->addToGroup(this);
+ }
+}
+
+/*!
+ Returns a pointer to this item's parent item. If this item does not have a
+ parent, 0 is returned.
+
+ \sa setParentItem(), childItems()
+*/
+QGraphicsItem *QGraphicsItem::parentItem() const
+{
+ return d_ptr->parent;
+}
+
+/*!
+ Returns this item's top-level item. The top-level item is the item's
+ topmost ancestor item whose parent is 0. If an item has no parent, its own
+ pointer is returned (i.e., a top-level item is its own top-level item).
+
+ \sa parentItem()
+*/
+QGraphicsItem *QGraphicsItem::topLevelItem() const
+{
+ QGraphicsItem *parent = const_cast<QGraphicsItem *>(this);
+ while (QGraphicsItem *grandPa = parent->parentItem())
+ parent = grandPa;
+ return parent;
+}
+
+/*!
+ \since 4.6
+
+ Returns a pointer to the item's parent, cast to a QGraphicsObject. returns 0 if the parent item
+ is not a QGraphicsObject.
+
+ \sa parentItem(), childItems()
+*/
+QGraphicsObject *QGraphicsItem::parentObject() const
+{
+ QGraphicsItem *p = d_ptr->parent;
+ return (p && p->d_ptr->isObject) ? static_cast<QGraphicsObject *>(p) : 0;
+}
+
+/*!
+ \since 4.4
+
+ Returns a pointer to the item's parent widget. The item's parent widget is
+ the closest parent item that is a widget.
+
+ \sa parentItem(), childItems()
+*/
+QGraphicsWidget *QGraphicsItem::parentWidget() const
+{
+ QGraphicsItem *p = parentItem();
+ while (p && !p->isWidget())
+ p = p->parentItem();
+ return (p && p->isWidget()) ? static_cast<QGraphicsWidget *>(p) : 0;
+}
+
+/*!
+ \since 4.4
+
+ Returns a pointer to the item's top level widget (i.e., the item's
+ ancestor whose parent is 0, or whose parent is not a widget), or 0 if this
+ item does not have a top level widget. If the item is its own top level
+ widget, this function returns a pointer to the item itself.
+*/
+QGraphicsWidget *QGraphicsItem::topLevelWidget() const
+{
+ if (const QGraphicsWidget *p = parentWidget())
+ return p->topLevelWidget();
+ return isWidget() ? static_cast<QGraphicsWidget *>(const_cast<QGraphicsItem *>(this)) : 0;
+}
+
+/*!
+ \since 4.4
+
+ Returns the item's window, or 0 if this item does not have a window. If
+ the item is a window, it will return itself. Otherwise it will return the
+ closest ancestor that is a window.
+
+ \sa QGraphicsWidget::isWindow()
+*/
+QGraphicsWidget *QGraphicsItem::window() const
+{
+ QGraphicsItem *p = panel();
+ if (p && p->isWindow())
+ return static_cast<QGraphicsWidget *>(p);
+ return 0;
+}
+
+/*!
+ \since 4.6
+
+ Returns the item's panel, or 0 if this item does not have a panel. If the
+ item is a panel, it will return itself. Otherwise it will return the
+ closest ancestor that is a panel.
+
+ \sa isPanel(), ItemIsPanel
+*/
+QGraphicsItem *QGraphicsItem::panel() const
+{
+ if (d_ptr->flags & ItemIsPanel)
+ return const_cast<QGraphicsItem *>(this);
+ return d_ptr->parent ? d_ptr->parent->panel() : 0;
+}
+
+/*!
+ \since 4.6
+
+ Return the graphics item cast to a QGraphicsObject, if the class is actually a
+ graphics object, 0 otherwise.
+*/
+QGraphicsObject *QGraphicsItem::toGraphicsObject()
+{
+ return d_ptr->isObject ? static_cast<QGraphicsObject *>(this) : 0;
+}
+
+/*!
+ \since 4.6
+
+ Return the graphics item cast to a QGraphicsObject, if the class is actually a
+ graphics object, 0 otherwise.
+*/
+const QGraphicsObject *QGraphicsItem::toGraphicsObject() const
+{
+ return d_ptr->isObject ? static_cast<const QGraphicsObject *>(this) : 0;
+}
+
+/*!
+ Sets this item's parent item to \a newParent. If this item already
+ has a parent, it is first removed from the previous parent. If \a
+ newParent is 0, this item will become a top-level item.
+
+ Note that this implicitly adds this graphics item to the scene of
+ the parent. You should not \l{QGraphicsScene::addItem()}{add} the
+ item to the scene yourself.
+
+ Calling this function on an item that is an ancestor of \a newParent
+ have undefined behaviour.
+
+ \sa parentItem(), childItems()
+*/
+void QGraphicsItem::setParentItem(QGraphicsItem *newParent)
+{
+ if (newParent == this) {
+ qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this);
+ return;
+ }
+ if (newParent == d_ptr->parent)
+ return;
+
+ const QVariant newParentVariant(itemChange(QGraphicsItem::ItemParentChange,
+ QVariant::fromValue<QGraphicsItem *>(newParent)));
+ newParent = qvariant_cast<QGraphicsItem *>(newParentVariant);
+ if (newParent == d_ptr->parent)
+ return;
+
+ const QVariant thisPointerVariant(QVariant::fromValue<QGraphicsItem *>(this));
+ d_ptr->setParentItemHelper(newParent, &newParentVariant, &thisPointerVariant);
+}
+
+/*!
+ \obsolete
+
+ Use childItems() instead.
+
+ \sa setParentItem()
+*/
+QList<QGraphicsItem *> QGraphicsItem::children() const
+{
+ return childItems();
+}
+
+/*!
+ \since 4.4
+
+ Returns a list of this item's children.
+
+ The items are sorted by stacking order. This takes into account both the
+ items' insertion order and their Z-values.
+
+ \sa setParentItem(), zValue(), {QGraphicsItem#Sorting}{Sorting}
+*/
+QList<QGraphicsItem *> QGraphicsItem::childItems() const
+{
+ const_cast<QGraphicsItem *>(this)->d_ptr->ensureSortedChildren();
+ return d_ptr->children;
+}
+
+/*!
+ \since 4.4
+ Returns true if this item is a widget (i.e., QGraphicsWidget); otherwise,
+ returns false.
+*/
+bool QGraphicsItem::isWidget() const
+{
+ return d_ptr->isWidget;
+}
+
+/*!
+ \since 4.4
+ Returns true if the item is a QGraphicsWidget window, otherwise returns
+ false.
+
+ \sa QGraphicsWidget::windowFlags()
+*/
+bool QGraphicsItem::isWindow() const
+{
+ return d_ptr->isWidget && (static_cast<const QGraphicsWidget *>(this)->windowType() & Qt::Window);
+}
+
+/*!
+ \since 4.6
+ Returns true if the item is a panel; otherwise returns false.
+
+ \sa QGraphicsItem::panel(), ItemIsPanel
+*/
+bool QGraphicsItem::isPanel() const
+{
+ return d_ptr->flags & ItemIsPanel;
+}
+
+/*!
+ Returns this item's flags. The flags describe what configurable features
+ of the item are enabled and not. For example, if the flags include
+ ItemIsFocusable, the item can accept input focus.
+
+ By default, no flags are enabled.
+
+ \sa setFlags(), setFlag()
+*/
+QGraphicsItem::GraphicsItemFlags QGraphicsItem::flags() const
+{
+ return GraphicsItemFlags(d_ptr->flags);
+}
+
+/*!
+ If \a enabled is true, the item flag \a flag is enabled; otherwise, it is
+ disabled.
+
+ \sa flags(), setFlags()
+*/
+void QGraphicsItem::setFlag(GraphicsItemFlag flag, bool enabled)
+{
+ if (enabled)
+ setFlags(GraphicsItemFlags(d_ptr->flags) | flag);
+ else
+ setFlags(GraphicsItemFlags(d_ptr->flags) & ~flag);
+}
+
+/*!
+ \internal
+
+ Sets the flag \a flag on \a item and all its children, to \a enabled.
+*/
+static void _q_qgraphicsItemSetFlag(QGraphicsItem *item, QGraphicsItem::GraphicsItemFlag flag,
+ bool enabled)
+{
+ if (item->flags() & flag) {
+ // If this item already has the correct flag set, we don't have to
+ // propagate it.
+ return;
+ }
+ item->setFlag(flag, enabled);
+ foreach (QGraphicsItem *child, item->children())
+ _q_qgraphicsItemSetFlag(child, flag, enabled);
+}
+
+/*!
+ Sets the item flags to \a flags. All flags in \a flags are enabled; all
+ flags not in \a flags are disabled.
+
+ If the item had focus and \a flags does not enable ItemIsFocusable, the
+ item loses focus as a result of calling this function. Similarly, if the
+ item was selected, and \a flags does not enabled ItemIsSelectable, the
+ item is automatically unselected.
+
+ By default, no flags are enabled. (QGraphicsWidget enables the
+ ItemSendsGeometryChanges flag by default in order to track position
+ changes.)
+
+ \sa flags(), setFlag()
+*/
+void QGraphicsItem::setFlags(GraphicsItemFlags flags)
+{
+ // Notify change and check for adjustment.
+ if (quint32(d_ptr->flags) == quint32(flags))
+ return;
+ flags = GraphicsItemFlags(itemChange(ItemFlagsChange, quint32(flags)).toUInt());
+ if (quint32(d_ptr->flags) == quint32(flags))
+ return;
+ if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex)
+ d_ptr->scene->d_func()->index->itemChange(this, ItemFlagsChange, &flags);
+
+ // Flags that alter the geometry of the item (or its children).
+ const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations | ItemIsSelectable);
+ bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask);
+ if (fullUpdate)
+ d_ptr->updatePaintedViewBoundingRects(/*children=*/true);
+
+ // Keep the old flags to compare the diff.
+ GraphicsItemFlags oldFlags = GraphicsItemFlags(d_ptr->flags);
+
+ // Update flags.
+ d_ptr->flags = flags;
+
+ if (!(d_ptr->flags & ItemIsFocusable) && hasFocus()) {
+ // Clear focus on the item if it has focus when the focusable flag
+ // is unset.
+ clearFocus();
+ }
+
+ if (!(d_ptr->flags & ItemIsSelectable) && isSelected()) {
+ // Unselect the item if it is selected when the selectable flag is
+ // unset.
+ setSelected(false);
+ }
+
+ if ((flags & ItemClipsChildrenToShape) != (oldFlags & ItemClipsChildrenToShape)) {
+ // Item children clipping changes. Propagate the ancestor flag to
+ // all children.
+ d_ptr->updateAncestorFlag(ItemClipsChildrenToShape);
+ // The childrenBoundingRect is clipped to the boundingRect in case of ItemClipsChildrenToShape,
+ // which means we have to invalidate the cached childrenBoundingRect whenever this flag changes.
+ d_ptr->dirtyChildrenBoundingRect = 1;
+ d_ptr->markParentDirty(true);
+ }
+
+ if ((flags & ItemIgnoresTransformations) != (oldFlags & ItemIgnoresTransformations)) {
+ // Item children clipping changes. Propagate the ancestor flag to
+ // all children.
+ d_ptr->updateAncestorFlag(ItemIgnoresTransformations);
+ }
+
+ if ((flags & ItemNegativeZStacksBehindParent) != (oldFlags & ItemNegativeZStacksBehindParent)) {
+ // NB! We change the flags directly here, so we must also update d_ptr->flags.
+ // Note that this has do be done before the ItemStacksBehindParent check
+ // below; otherwise we will loose the change.
+
+ // Update stack-behind.
+ if (d_ptr->z < qreal(0.0))
+ flags |= ItemStacksBehindParent;
+ else
+ flags &= ~ItemStacksBehindParent;
+ d_ptr->flags = flags;
+ }
+
+ if ((flags & ItemStacksBehindParent) != (oldFlags & ItemStacksBehindParent)) {
+ // NB! This check has to come after the ItemNegativeZStacksBehindParent
+ // check above. Be careful.
+
+ // Ensure child item sorting is up to date when toggling this flag.
+ if (d_ptr->parent)
+ d_ptr->parent->d_ptr->needSortChildren = 1;
+ else if (d_ptr->scene)
+ d_ptr->scene->d_func()->needSortTopLevelItems = 1;
+ }
+
+ if ((flags & ItemAcceptsInputMethod) != (oldFlags & ItemAcceptsInputMethod)) {
+ // Update input method sensitivity in any views.
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->updateInputMethodSensitivityInViews();
+ }
+
+
+ if ((d_ptr->panelModality != NonModal)
+ && d_ptr->scene
+ && (flags & ItemIsPanel) != (oldFlags & ItemIsPanel)) {
+ // update the panel's modal state
+ if (flags & ItemIsPanel)
+ d_ptr->scene->d_func()->enterModal(this);
+ else
+ d_ptr->scene->d_func()->leaveModal(this);
+ }
+
+ if (d_ptr->scene) {
+ if ((flags & ItemSendsScenePositionChanges) != (oldFlags & ItemSendsScenePositionChanges)) {
+ if (flags & ItemSendsScenePositionChanges)
+ d_ptr->scene->d_func()->registerScenePosItem(this);
+ else
+ d_ptr->scene->d_func()->unregisterScenePosItem(this);
+ }
+ d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
+ }
+
+ // Notify change.
+ itemChange(ItemFlagsHaveChanged, quint32(flags));
+}
+
+/*!
+ \since 4.4
+ Returns the cache mode for this item. The default mode is NoCache (i.e.,
+ cache is disabled and all painting is immediate).
+
+ \sa setCacheMode()
+*/
+QGraphicsItem::CacheMode QGraphicsItem::cacheMode() const
+{
+ return QGraphicsItem::CacheMode(d_ptr->cacheMode);
+}
+
+/*!
+ \since 4.4
+ Sets the item's cache mode to \a mode.
+
+ The optional \a logicalCacheSize argument is used only by
+ ItemCoordinateCache mode, and describes the resolution of the cache
+ buffer; if \a logicalCacheSize is (100, 100), QGraphicsItem will fit the
+ item into 100x100 pixels in graphics memory, regardless of the logical
+ size of the item itself. By default QGraphicsItem uses the size of
+ boundingRect(). For all other cache modes than ItemCoordinateCache, \a
+ logicalCacheSize is ignored.
+
+ Caching can speed up rendering if your item spends a significant time
+ redrawing itself. In some cases the cache can also slow down rendering, in
+ particular when the item spends less time redrawing than QGraphicsItem
+ spends redrawing from the cache. When enabled, the item's paint() function
+ will be called only once for each call to update(); for any subsequent
+ repaint requests, the Graphics View framework will redraw from the
+ cache. This approach works particularly well with QGLWidget, which stores
+ all the cache as OpenGL textures.
+
+ Be aware that QPixmapCache's cache limit may need to be changed to obtain
+ optimal performance.
+
+ You can read more about the different cache modes in the CacheMode
+ documentation.
+
+ \sa CacheMode, QPixmapCache::setCacheLimit()
+*/
+void QGraphicsItem::setCacheMode(CacheMode mode, const QSize &logicalCacheSize)
+{
+ CacheMode lastMode = CacheMode(d_ptr->cacheMode);
+ d_ptr->cacheMode = mode;
+ bool noVisualChange = (mode == NoCache && lastMode == NoCache)
+ || (mode == NoCache && lastMode == DeviceCoordinateCache)
+ || (mode == DeviceCoordinateCache && lastMode == NoCache)
+ || (mode == DeviceCoordinateCache && lastMode == DeviceCoordinateCache);
+ if (mode == NoCache) {
+ d_ptr->removeExtraItemCache();
+ } else {
+ QGraphicsItemCache *cache = d_ptr->extraItemCache();
+
+ // Reset old cache
+ cache->purge();
+
+ if (mode == ItemCoordinateCache) {
+ if (lastMode == mode && cache->fixedSize == logicalCacheSize)
+ noVisualChange = true;
+ cache->fixedSize = logicalCacheSize;
+ }
+ }
+ if (!noVisualChange)
+ update();
+}
+
+/*!
+ \since 4.6
+
+ Returns the modality for this item.
+*/
+QGraphicsItem::PanelModality QGraphicsItem::panelModality() const
+{
+ return d_ptr->panelModality;
+}
+
+/*!
+ \since 4.6
+
+ Sets the modality for this item to \a panelModality.
+
+ Changing the modality of a visible item takes effect immediately.
+*/
+void QGraphicsItem::setPanelModality(PanelModality panelModality)
+{
+ if (d_ptr->panelModality == panelModality)
+ return;
+
+ PanelModality previousModality = d_ptr->panelModality;
+ bool enterLeaveModal = (isPanel() && d_ptr->scene && isVisible());
+ if (enterLeaveModal && panelModality == NonModal)
+ d_ptr->scene->d_func()->leaveModal(this);
+ d_ptr->panelModality = panelModality;
+ if (enterLeaveModal && d_ptr->panelModality != NonModal)
+ d_ptr->scene->d_func()->enterModal(this, previousModality);
+}
+
+/*!
+ \since 4.6
+
+ Returns true if this item is blocked by a modal panel, false otherwise. If \a blockingPanel is
+ non-zero, \a blockingPanel will be set to the modal panel that is blocking this item. If this
+ item is not blocked, \a blockingPanel will not be set by this function.
+
+ This function always returns false for items not in a scene.
+
+ \sa panelModality() setPanelModality() PanelModality
+*/
+bool QGraphicsItem::isBlockedByModalPanel(QGraphicsItem **blockingPanel) const
+{
+ if (!d_ptr->scene)
+ return false;
+
+
+ QGraphicsItem *dummy = 0;
+ if (!blockingPanel)
+ blockingPanel = &dummy;
+
+ QGraphicsScenePrivate *scene_d = d_ptr->scene->d_func();
+ if (scene_d->modalPanels.isEmpty())
+ return false;
+
+ // ###
+ if (!scene_d->popupWidgets.isEmpty() && scene_d->popupWidgets.first() == this)
+ return false;
+
+ for (int i = 0; i < scene_d->modalPanels.count(); ++i) {
+ QGraphicsItem *modalPanel = scene_d->modalPanels.at(i);
+ if (modalPanel->panelModality() == QGraphicsItem::SceneModal) {
+ // Scene modal panels block all non-descendents.
+ if (modalPanel != this && !modalPanel->isAncestorOf(this)) {
+ *blockingPanel = modalPanel;
+ return true;
+ }
+ } else {
+ // Window modal panels block ancestors and siblings/cousins.
+ if (modalPanel != this
+ && !modalPanel->isAncestorOf(this)
+ && commonAncestorItem(modalPanel)) {
+ *blockingPanel = modalPanel;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+#ifndef QT_NO_TOOLTIP
+/*!
+ Returns the item's tool tip, or an empty QString if no tool tip has been
+ set.
+
+ \sa setToolTip(), QToolTip
+*/
+QString QGraphicsItem::toolTip() const
+{
+ return d_ptr->extra(QGraphicsItemPrivate::ExtraToolTip).toString();
+}
+
+/*!
+ Sets the item's tool tip to \a toolTip. If \a toolTip is empty, the item's
+ tool tip is cleared.
+
+ \sa toolTip(), QToolTip
+*/
+void QGraphicsItem::setToolTip(const QString &toolTip)
+{
+ const QVariant toolTipVariant(itemChange(ItemToolTipChange, toolTip));
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraToolTip, toolTipVariant.toString());
+ itemChange(ItemToolTipHasChanged, toolTipVariant);
+}
+#endif // QT_NO_TOOLTIP
+
+#ifndef QT_NO_CURSOR
+/*!
+ Returns the current cursor shape for the item. The mouse cursor
+ will assume this shape when it's over this item. See the \link
+ Qt::CursorShape list of predefined cursor objects\endlink for a
+ range of useful shapes.
+
+ An editor item might want to use an I-beam cursor:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 2
+
+ If no cursor has been set, the cursor of the item beneath is used.
+
+ \sa setCursor(), hasCursor(), unsetCursor(), QWidget::cursor,
+ QApplication::overrideCursor()
+*/
+QCursor QGraphicsItem::cursor() const
+{
+ return qvariant_cast<QCursor>(d_ptr->extra(QGraphicsItemPrivate::ExtraCursor));
+}
+
+/*!
+ Sets the current cursor shape for the item to \a cursor. The mouse cursor
+ will assume this shape when it's over this item. See the \link
+ Qt::CursorShape list of predefined cursor objects\endlink for a range of
+ useful shapes.
+
+ An editor item might want to use an I-beam cursor:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 3
+
+ If no cursor has been set, the cursor of the item beneath is used.
+
+ \sa cursor(), hasCursor(), unsetCursor(), QWidget::cursor,
+ QApplication::overrideCursor()
+*/
+void QGraphicsItem::setCursor(const QCursor &cursor)
+{
+ const QVariant cursorVariant(itemChange(ItemCursorChange, QVariant::fromValue<QCursor>(cursor)));
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraCursor, qvariant_cast<QCursor>(cursorVariant));
+ d_ptr->hasCursor = 1;
+ if (d_ptr->scene) {
+ d_ptr->scene->d_func()->allItemsUseDefaultCursor = false;
+ foreach (QGraphicsView *view, d_ptr->scene->views()) {
+ view->viewport()->setMouseTracking(true);
+ // Note: Some of this logic is duplicated in QGraphicsView's mouse events.
+ if (view->underMouse()) {
+ foreach (QGraphicsItem *itemUnderCursor, view->items(view->mapFromGlobal(QCursor::pos()))) {
+ if (itemUnderCursor->hasCursor()) {
+ QMetaObject::invokeMethod(view, "_q_setViewportCursor",
+ Q_ARG(QCursor, itemUnderCursor->cursor()));
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ itemChange(ItemCursorHasChanged, cursorVariant);
+}
+
+/*!
+ Returns true if this item has a cursor set; otherwise, false is returned.
+
+ By default, items don't have any cursor set. cursor() will return a
+ standard pointing arrow cursor.
+
+ \sa unsetCursor()
+*/
+bool QGraphicsItem::hasCursor() const
+{
+ return d_ptr->hasCursor;
+}
+
+/*!
+ Clears the cursor from this item.
+
+ \sa hasCursor(), setCursor()
+*/
+void QGraphicsItem::unsetCursor()
+{
+ d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraCursor);
+ d_ptr->hasCursor = 0;
+ if (d_ptr->scene) {
+ foreach (QGraphicsView *view, d_ptr->scene->views()) {
+ if (view->underMouse() && view->itemAt(view->mapFromGlobal(QCursor::pos())) == this) {
+ QMetaObject::invokeMethod(view, "_q_unsetViewportCursor");
+ break;
+ }
+ }
+ }
+}
+
+#endif // QT_NO_CURSOR
+
+/*!
+ Returns true if the item is visible; otherwise, false is returned.
+
+ Note that the item's general visibility is unrelated to whether or not it
+ is actually being visualized by a QGraphicsView.
+
+ \sa setVisible()
+*/
+bool QGraphicsItem::isVisible() const
+{
+ return d_ptr->visible;
+}
+
+/*!
+ \since 4.4
+ Returns true if the item is visible to \a parent; otherwise, false is
+ returned. \a parent can be 0, in which case this function will return
+ whether the item is visible to the scene or not.
+
+ An item may not be visible to its ancestors even if isVisible() is true. If
+ any ancestor is hidden, the item itself will be implicitly hidden, in which
+ case this function will return false.
+
+ \sa isVisible(), setVisible()
+*/
+bool QGraphicsItem::isVisibleTo(const QGraphicsItem *parent) const
+{
+ if (!d_ptr->visible)
+ return false;
+ if (parent == this)
+ return true;
+ if (parentItem() && parentItem()->isVisibleTo(parent))
+ return true;
+ if (!parent && !parentItem())
+ return true;
+ return false;
+}
+
+/*!
+ \internal
+
+ Sets this item's visibility to \a newVisible. If \a explicitly is true,
+ this item will be "explicitly" \a newVisible; otherwise, it.. will not be.
+*/
+void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bool update)
+{
+ Q_Q(QGraphicsItem);
+
+ // Update explicit bit.
+ if (explicitly)
+ explicitlyHidden = newVisible ? 0 : 1;
+
+ // Check if there's nothing to do.
+ if (visible == quint32(newVisible))
+ return;
+
+ // Don't show child if parent is not visible
+ if (parent && newVisible && !parent->d_ptr->visible)
+ return;
+
+ // Modify the property.
+ const QVariant newVisibleVariant(q_ptr->itemChange(QGraphicsItem::ItemVisibleChange,
+ quint32(newVisible)));
+ newVisible = newVisibleVariant.toBool();
+ if (visible == quint32(newVisible))
+ return;
+ visible = newVisible;
+
+ // Schedule redrawing
+ if (update) {
+ QGraphicsItemCache *c = (QGraphicsItemCache *)qvariant_cast<void *>(extra(ExtraCacheData));
+ if (c)
+ c->purge();
+ if (scene) {
+#ifndef QT_NO_GRAPHICSEFFECT
+ invalidateParentGraphicsEffectsRecursively();
+#endif //QT_NO_GRAPHICSEFFECT
+ scene->d_func()->markDirty(q_ptr, QRectF(), /*invalidateChildren=*/false, /*force=*/true);
+ }
+ }
+
+ // Certain properties are dropped as an item becomes invisible.
+ bool hasFocus = q_ptr->hasFocus();
+ if (!newVisible) {
+ if (scene) {
+ if (scene->d_func()->mouseGrabberItems.contains(q))
+ q->ungrabMouse();
+ if (scene->d_func()->keyboardGrabberItems.contains(q))
+ q->ungrabKeyboard();
+ if (q->isPanel() && panelModality != QGraphicsItem::NonModal)
+ scene->d_func()->leaveModal(q_ptr);
+ }
+ if (hasFocus && scene) {
+ // Hiding the closest non-panel ancestor of the focus item
+ QGraphicsItem *focusItem = scene->focusItem();
+ bool clear = true;
+ if (isWidget && !focusItem->isPanel()) {
+ do {
+ if (focusItem == q_ptr) {
+ clear = !static_cast<QGraphicsWidget *>(q_ptr)->focusNextPrevChild(true);
+ break;
+ }
+ } while ((focusItem = focusItem->parentWidget()) && !focusItem->isPanel());
+ }
+ if (clear)
+ clearFocusHelper(/* giveFocusToParent = */ false);
+ }
+ if (q_ptr->isSelected())
+ q_ptr->setSelected(false);
+ } else {
+ geometryChanged = 1;
+ paintedViewBoundingRectsNeedRepaint = 1;
+ if (scene) {
+ if (isWidget) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr);
+ if (widget->windowType() == Qt::Popup)
+ scene->d_func()->addPopup(widget);
+ }
+ if (q->isPanel() && panelModality != QGraphicsItem::NonModal) {
+ scene->d_func()->enterModal(q_ptr);
+ }
+ }
+ }
+
+ // Update children with explicitly = false.
+ const bool updateChildren = update && !(flags & QGraphicsItem::ItemClipsChildrenToShape);
+ foreach (QGraphicsItem *child, children) {
+ if (!newVisible || !child->d_ptr->explicitlyHidden)
+ child->d_ptr->setVisibleHelper(newVisible, false, updateChildren);
+ }
+
+ // Update activation
+ if (scene && q->isPanel()) {
+ if (newVisible) {
+ if (parent && parent->isActive())
+ q->setActive(true);
+ } else {
+ if (q->isActive())
+ scene->setActivePanel(parent);
+ }
+ }
+
+ // Enable subfocus
+ if (scene) {
+ if (newVisible) {
+ // Item is shown
+ QGraphicsItem *p = parent;
+ bool done = false;
+ while (p) {
+ if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+ QGraphicsItem *fsi = p->d_ptr->focusScopeItem;
+ if (q_ptr == fsi || q_ptr->isAncestorOf(fsi)) {
+ done = true;
+ while (fsi->d_ptr->focusScopeItem && fsi->d_ptr->focusScopeItem->isVisible())
+ fsi = fsi->d_ptr->focusScopeItem;
+ fsi->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ true,
+ /* focusFromHide = */ false);
+ }
+ break;
+ }
+ p = p->d_ptr->parent;
+ }
+ if (!done) {
+ QGraphicsItem *fi = subFocusItem;
+ if (fi && fi != scene->focusItem()) {
+ scene->setFocusItem(fi);
+ } else if (flags & QGraphicsItem::ItemIsFocusScope &&
+ !scene->focusItem() &&
+ q->isAncestorOf(scene->d_func()->lastFocusItem)) {
+ q_ptr->setFocus();
+ }
+ }
+ } else {
+ // Item is hidden
+ if (hasFocus) {
+ QGraphicsItem *p = parent;
+ while (p) {
+ if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+ if (p->d_ptr->visible) {
+ p->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ true,
+ /* focusFromHide = */ true);
+ }
+ break;
+ }
+ p = p->d_ptr->parent;
+ }
+ }
+ }
+ }
+
+ // Deliver post-change notification.
+ q_ptr->itemChange(QGraphicsItem::ItemVisibleHasChanged, newVisibleVariant);
+
+ if (isObject)
+ emit static_cast<QGraphicsObject *>(q_ptr)->visibleChanged();
+}
+
+/*!
+ If \a visible is true, the item is made visible. Otherwise, the item is
+ made invisible. Invisible items are not painted, nor do they receive any
+ events. In particular, mouse events pass right through invisible items,
+ and are delivered to any item that may be behind. Invisible items are also
+ unselectable, they cannot take input focus, and are not detected by
+ QGraphicsScene's item location functions.
+
+ If an item becomes invisible while grabbing the mouse, (i.e., while it is
+ receiving mouse events,) it will automatically lose the mouse grab, and
+ the grab is not regained by making the item visible again; it must receive
+ a new mouse press to regain the mouse grab.
+
+ Similarly, an invisible item cannot have focus, so if the item has focus
+ when it becomes invisible, it will lose focus, and the focus is not
+ regained by simply making the item visible again.
+
+ If you hide a parent item, all its children will also be hidden. If you
+ show a parent item, all children will be shown, unless they have been
+ explicitly hidden (i.e., if you call setVisible(false) on a child, it will
+ not be reshown even if its parent is hidden, and then shown again).
+
+ Items are visible by default; it is unnecessary to call
+ setVisible() on a new item.
+
+ \sa isVisible(), show(), hide()
+*/
+void QGraphicsItem::setVisible(bool visible)
+{
+ d_ptr->setVisibleHelper(visible, /* explicit = */ true);
+}
+
+/*!
+ \fn void QGraphicsItem::hide()
+
+ Hides the item. (Items are visible by default.)
+
+ This convenience function is equivalent to calling \c setVisible(false).
+
+ \sa show(), setVisible()
+*/
+
+/*!
+ \fn void QGraphicsItem::show()
+
+ Shows the item. (Items are visible by default.)
+
+ This convenience function is equivalent to calling \c setVisible(true).
+
+ \sa hide(), setVisible()
+*/
+
+/*!
+ Returns true if the item is enabled; otherwise, false is returned.
+
+ \sa setEnabled()
+*/
+bool QGraphicsItem::isEnabled() const
+{
+ return d_ptr->enabled;
+}
+
+/*!
+ \internal
+
+ Sets this item's visibility to \a newEnabled. If \a explicitly is true,
+ this item will be "explicitly" \a newEnabled; otherwise, it.. will not be.
+*/
+void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bool update)
+{
+ // Update explicit bit.
+ if (explicitly)
+ explicitlyDisabled = newEnabled ? 0 : 1;
+
+ // Check if there's nothing to do.
+ if (enabled == quint32(newEnabled))
+ return;
+
+ // Certain properties are dropped when an item is disabled.
+ if (!newEnabled) {
+ if (scene && scene->mouseGrabberItem() == q_ptr)
+ q_ptr->ungrabMouse();
+ if (q_ptr->hasFocus()) {
+ // Disabling the closest non-panel ancestor of the focus item
+ // causes focus to pop to the next item, otherwise it's cleared.
+ QGraphicsItem *focusItem = scene->focusItem();
+ bool clear = true;
+ if (isWidget && !focusItem->isPanel() && q_ptr->isAncestorOf(focusItem)) {
+ do {
+ if (focusItem == q_ptr) {
+ clear = !static_cast<QGraphicsWidget *>(q_ptr)->focusNextPrevChild(true);
+ break;
+ }
+ } while ((focusItem = focusItem->parentWidget()) && !focusItem->isPanel());
+ }
+ if (clear)
+ q_ptr->clearFocus();
+ }
+ if (q_ptr->isSelected())
+ q_ptr->setSelected(false);
+ }
+
+ // Modify the property.
+ const QVariant newEnabledVariant(q_ptr->itemChange(QGraphicsItem::ItemEnabledChange,
+ quint32(newEnabled)));
+ enabled = newEnabledVariant.toBool();
+
+ // Schedule redraw.
+ if (update)
+ q_ptr->update();
+
+ foreach (QGraphicsItem *child, children) {
+ if (!newEnabled || !child->d_ptr->explicitlyDisabled)
+ child->d_ptr->setEnabledHelper(newEnabled, /* explicitly = */ false);
+ }
+
+ // Deliver post-change notification.
+ q_ptr->itemChange(QGraphicsItem::ItemEnabledHasChanged, newEnabledVariant);
+
+ if (isObject)
+ emit static_cast<QGraphicsObject *>(q_ptr)->enabledChanged();
+}
+
+/*!
+ If \a enabled is true, the item is enabled; otherwise, it is disabled.
+
+ Disabled items are visible, but they do not receive any events, and cannot
+ take focus nor be selected. Mouse events are discarded; they are not
+ propagated unless the item is also invisible, or if it does not accept
+ mouse events (see acceptedMouseButtons()). A disabled item cannot become the
+ mouse grabber, and as a result of this, an item loses the grab if it
+ becomes disabled when grabbing the mouse, just like it loses focus if it
+ had focus when it was disabled.
+
+ Disabled items are traditionally drawn using grayed-out colors (see \l
+ QPalette::Disabled).
+
+ If you disable a parent item, all its children will also be disabled. If
+ you enable a parent item, all children will be enabled, unless they have
+ been explicitly disabled (i.e., if you call setEnabled(false) on a child,
+ it will not be reenabled if its parent is disabled, and then enabled
+ again).
+
+ Items are enabled by default.
+
+ \note If you install an event filter, you can still intercept events
+ before they are delivered to items; this mechanism disregards the item's
+ enabled state.
+
+ \sa isEnabled()
+*/
+void QGraphicsItem::setEnabled(bool enabled)
+{
+ d_ptr->setEnabledHelper(enabled, /* explicitly = */ true);
+}
+
+/*!
+ Returns true if this item is selected; otherwise, false is returned.
+
+ Items that are in a group inherit the group's selected state.
+
+ Items are not selected by default.
+
+ \sa setSelected(), QGraphicsScene::setSelectionArea()
+*/
+bool QGraphicsItem::isSelected() const
+{
+ if (QGraphicsItemGroup *group = this->group())
+ return group->isSelected();
+ return d_ptr->selected;
+}
+
+/*!
+ If \a selected is true and this item is selectable, this item is selected;
+ otherwise, it is unselected.
+
+ If the item is in a group, the whole group's selected state is toggled by
+ this function. If the group is selected, all items in the group are also
+ selected, and if the group is not selected, no item in the group is
+ selected.
+
+ Only visible, enabled, selectable items can be selected. If \a selected
+ is true and this item is either invisible or disabled or unselectable,
+ this function does nothing.
+
+ By default, items cannot be selected. To enable selection, set the
+ ItemIsSelectable flag.
+
+ This function is provided for convenience, allowing individual toggling of
+ the selected state of an item. However, a more common way of selecting
+ items is to call QGraphicsScene::setSelectionArea(), which will call this
+ function for all visible, enabled, and selectable items within a specified
+ area on the scene.
+
+ \sa isSelected(), QGraphicsScene::selectedItems()
+*/
+void QGraphicsItem::setSelected(bool selected)
+{
+ if (QGraphicsItemGroup *group = this->group()) {
+ group->setSelected(selected);
+ return;
+ }
+
+ if (!(d_ptr->flags & ItemIsSelectable) || !d_ptr->enabled || !d_ptr->visible)
+ selected = false;
+ if (d_ptr->selected == selected)
+ return;
+ const QVariant newSelectedVariant(itemChange(ItemSelectedChange, quint32(selected)));
+ bool newSelected = newSelectedVariant.toBool();
+ if (d_ptr->selected == newSelected)
+ return;
+ d_ptr->selected = newSelected;
+
+ update();
+ if (d_ptr->scene) {
+ QGraphicsScenePrivate *sceneD = d_ptr->scene->d_func();
+ if (selected) {
+ sceneD->selectedItems << this;
+ } else {
+ // QGraphicsScene::selectedItems() lazily pulls out all items that are
+ // no longer selected.
+ }
+ if (!sceneD->selectionChanging)
+ emit d_ptr->scene->selectionChanged();
+ }
+
+ // Deliver post-change notification.
+ itemChange(QGraphicsItem::ItemSelectedHasChanged, newSelectedVariant);
+}
+
+/*!
+ \since 4.5
+
+ Returns this item's local opacity, which is between 0.0 (transparent) and
+ 1.0 (opaque). This value is combined with parent and ancestor values into
+ the effectiveOpacity(). The effective opacity decides how the item is
+ rendered.
+
+ The opacity property decides the state of the painter passed to the
+ paint() function. If the item is cached, i.e., ItemCoordinateCache or
+ DeviceCoordinateCache, the effective property will be applied to the item's
+ cache as it is rendered.
+
+ The default opacity is 1.0; fully opaque.
+
+ \sa setOpacity(), paint(), ItemIgnoresParentOpacity,
+ ItemDoesntPropagateOpacityToChildren
+*/
+qreal QGraphicsItem::opacity() const
+{
+ return d_ptr->opacity;
+}
+
+/*!
+ \since 4.5
+
+ Returns this item's \e effective opacity, which is between 0.0
+ (transparent) and 1.0 (opaque). This value is a combination of this item's
+ local opacity, and its parent and ancestors' opacities. The effective
+ opacity decides how the item is rendered.
+
+ \sa opacity(), setOpacity(), paint(), ItemIgnoresParentOpacity,
+ ItemDoesntPropagateOpacityToChildren
+*/
+qreal QGraphicsItem::effectiveOpacity() const
+{
+ return d_ptr->effectiveOpacity();
+}
+
+/*!
+ \since 4.5
+
+ Sets this item's local \a opacity, between 0.0 (transparent) and 1.0
+ (opaque). The item's local opacity is combined with parent and ancestor
+ opacities into the effectiveOpacity().
+
+ By default, opacity propagates from parent to child, so if a parent's
+ opacity is 0.5 and the child is also 0.5, the child's effective opacity
+ will be 0.25.
+
+ The opacity property decides the state of the painter passed to the
+ paint() function. If the item is cached, i.e., ItemCoordinateCache or
+ DeviceCoordinateCache, the effective property will be applied to the
+ item's cache as it is rendered.
+
+ There are two item flags that affect how the item's opacity is combined
+ with the parent: ItemIgnoresParentOpacity and
+ ItemDoesntPropagateOpacityToChildren.
+
+ \sa opacity(), effectiveOpacity()
+*/
+void QGraphicsItem::setOpacity(qreal opacity)
+{
+ // Notify change.
+ const QVariant newOpacityVariant(itemChange(ItemOpacityChange, opacity));
+
+ // Normalized opacity
+ qreal newOpacity = qBound(qreal(0), newOpacityVariant.toReal(), qreal(1));
+
+ // No change? Done.
+ if (newOpacity == d_ptr->opacity)
+ return;
+
+ bool wasFullyTransparent = d_ptr->isOpacityNull();
+ d_ptr->opacity = newOpacity;
+
+ // Notify change.
+ itemChange(ItemOpacityHasChanged, newOpacityVariant);
+
+ // Update.
+ if (d_ptr->scene) {
+#ifndef QT_NO_GRAPHICSEFFECT
+ d_ptr->invalidateParentGraphicsEffectsRecursively();
+ if (!(d_ptr->flags & ItemDoesntPropagateOpacityToChildren))
+ d_ptr->invalidateChildGraphicsEffectsRecursively(QGraphicsItemPrivate::OpacityChanged);
+#endif //QT_NO_GRAPHICSEFFECT
+ d_ptr->scene->d_func()->markDirty(this, QRectF(),
+ /*invalidateChildren=*/true,
+ /*force=*/false,
+ /*ignoreOpacity=*/d_ptr->isOpacityNull());
+ if (wasFullyTransparent)
+ d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
+ }
+
+ if (d_ptr->isObject)
+ emit static_cast<QGraphicsObject *>(this)->opacityChanged();
+}
+
+/*!
+ Returns a pointer to this item's effect if it has one; otherwise 0.
+
+ \since 4.6
+*/
+#ifndef QT_NO_GRAPHICSEFFECT
+QGraphicsEffect *QGraphicsItem::graphicsEffect() const
+{
+ return d_ptr->graphicsEffect;
+}
+
+/*!
+ Sets \a effect as the item's effect. If there already is an effect installed
+ on this item, QGraphicsItem will delete the existing effect before installing
+ the new \a effect.
+
+ If \a effect is the installed on a different item, setGraphicsEffect() will remove
+ the effect from the item and install it on this item.
+
+ QGraphicsItem takes ownership of \a effect.
+
+ \note This function will apply the effect on itself and all its children.
+
+ \since 4.6
+*/
+void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect)
+{
+ if (d_ptr->graphicsEffect == effect)
+ return;
+
+ if (d_ptr->graphicsEffect) {
+ delete d_ptr->graphicsEffect;
+ d_ptr->graphicsEffect = 0;
+ } else if (d_ptr->parent) {
+ d_ptr->parent->d_ptr->updateChildWithGraphicsEffectFlagRecursively();
+ }
+
+ if (effect) {
+ // Set new effect.
+ QGraphicsEffectSourcePrivate *sourced = new QGraphicsItemEffectSourcePrivate(this);
+ QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced);
+ d_ptr->graphicsEffect = effect;
+ effect->d_func()->setGraphicsEffectSource(source);
+ prepareGeometryChange();
+ }
+}
+#endif //QT_NO_GRAPHICSEFFECT
+
+void QGraphicsItemPrivate::updateChildWithGraphicsEffectFlagRecursively()
+{
+#ifndef QT_NO_GRAPHICSEFFECT
+ QGraphicsItemPrivate *itemPrivate = this;
+ do {
+ // parent chain already notified?
+ if (itemPrivate->mayHaveChildWithGraphicsEffect)
+ return;
+ itemPrivate->mayHaveChildWithGraphicsEffect = 1;
+ } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : 0));
+#endif
+}
+
+/*!
+ \internal
+ \since 4.6
+ Returns the effective bounding rect of the given item space rect.
+ If the item has no effect, the rect is returned unmodified.
+ If the item has an effect, the effective rect can be extend beyond the
+ item's bounding rect, depending on the effect.
+
+ \sa boundingRect()
+*/
+QRectF QGraphicsItemPrivate::effectiveBoundingRect(const QRectF &rect) const
+{
+#ifndef QT_NO_GRAPHICSEFFECT
+ Q_Q(const QGraphicsItem);
+ QGraphicsEffect *effect = graphicsEffect;
+ if (scene && effect && effect->isEnabled()) {
+ if (scene->d_func()->views.isEmpty())
+ return effect->boundingRectFor(rect);
+ QRectF sceneRect = q->mapRectToScene(rect);
+ QRectF sceneEffectRect;
+ foreach (QGraphicsView *view, scene->views()) {
+ QRectF deviceRect = view->d_func()->mapRectFromScene(sceneRect);
+ QRect deviceEffectRect = effect->boundingRectFor(deviceRect).toAlignedRect();
+ sceneEffectRect |= view->d_func()->mapRectToScene(deviceEffectRect);
+ }
+ return q->mapRectFromScene(sceneEffectRect);
+ }
+#endif //QT_NO_GRAPHICSEFFECT
+ return rect;
+}
+
+/*!
+ \internal
+ \since 4.6
+ Returns the effective bounding rect of the item.
+ If the item has no effect, this is the same as the item's bounding rect.
+ If the item has an effect, the effective rect can be larger than the item's
+ bouding rect, depending on the effect.
+
+ \sa boundingRect()
+*/
+QRectF QGraphicsItemPrivate::effectiveBoundingRect(QGraphicsItem *topMostEffectItem) const
+{
+#ifndef QT_NO_GRAPHICSEFFECT
+ Q_Q(const QGraphicsItem);
+ QRectF brect = effectiveBoundingRect(q_ptr->boundingRect());
+ if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren || topMostEffectItem == q)
+ return brect;
+
+ const QGraphicsItem *effectParent = parent;
+ while (effectParent) {
+ QGraphicsEffect *effect = effectParent->d_ptr->graphicsEffect;
+ if (scene && effect && effect->isEnabled()) {
+ const QRectF brectInParentSpace = q->mapRectToItem(effectParent, brect);
+ const QRectF effectRectInParentSpace = effectParent->d_ptr->effectiveBoundingRect(brectInParentSpace);
+ brect = effectParent->mapRectToItem(q, effectRectInParentSpace);
+ }
+ if (effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
+ || topMostEffectItem == effectParent) {
+ return brect;
+ }
+ effectParent = effectParent->d_ptr->parent;
+ }
+
+ return brect;
+#else //QT_NO_GRAPHICSEFFECT
+ return q_ptr->boundingRect();
+#endif //QT_NO_GRAPHICSEFFECT
+
+}
+
+/*!
+ \internal
+ \since 4.6
+ Returns the effective bounding rect of this item in scene coordinates,
+ by combining sceneTransform() with boundingRect(), taking into account
+ the effect that the item might have.
+
+ If the item has no effect, this is the same as sceneBoundingRect().
+
+ \sa effectiveBoundingRect(), sceneBoundingRect()
+*/
+QRectF QGraphicsItemPrivate::sceneEffectiveBoundingRect() const
+{
+ // Find translate-only offset
+ // COMBINE
+ QPointF offset;
+ const QGraphicsItem *parentItem = q_ptr;
+ const QGraphicsItemPrivate *itemd;
+ do {
+ itemd = parentItem->d_ptr.data();
+ if (itemd->transformData)
+ break;
+ offset += itemd->pos;
+ } while ((parentItem = itemd->parent));
+
+ QRectF br = effectiveBoundingRect();
+ br.translate(offset);
+ return !parentItem ? br : parentItem->sceneTransform().mapRect(br);
+}
+
+/*!
+ Returns true if this item can accept drag and drop events; otherwise,
+ returns false. By default, items do not accept drag and drop events; items
+ are transparent to drag and drop.
+
+ \sa setAcceptDrops()
+*/
+bool QGraphicsItem::acceptDrops() const
+{
+ return d_ptr->acceptDrops;
+}
+
+/*!
+ If \a on is true, this item will accept drag and drop events; otherwise,
+ it is transparent for drag and drop events. By default, items do not
+ accept drag and drop events.
+
+ \sa acceptDrops()
+*/
+void QGraphicsItem::setAcceptDrops(bool on)
+{
+ d_ptr->acceptDrops = on;
+}
+
+/*!
+ Returns the mouse buttons that this item accepts mouse events for. By
+ default, all mouse buttons are accepted.
+
+ If an item accepts a mouse button, it will become the mouse
+ grabber item when a mouse press event is delivered for that mouse
+ button. However, if the item does not accept the button,
+ QGraphicsScene will forward the mouse events to the first item
+ beneath it that does.
+
+ \sa setAcceptedMouseButtons(), mousePressEvent()
+*/
+Qt::MouseButtons QGraphicsItem::acceptedMouseButtons() const
+{
+ return Qt::MouseButtons(d_ptr->acceptedMouseButtons);
+}
+
+/*!
+ Sets the mouse \a buttons that this item accepts mouse events for.
+
+ By default, all mouse buttons are accepted. If an item accepts a
+ mouse button, it will become the mouse grabber item when a mouse
+ press event is delivered for that button. However, if the item
+ does not accept the mouse button, QGraphicsScene will forward the
+ mouse events to the first item beneath it that does.
+
+ To disable mouse events for an item (i.e., make it transparent for mouse
+ events), call setAcceptedMouseButtons(0).
+
+ \sa acceptedMouseButtons(), mousePressEvent()
+*/
+void QGraphicsItem::setAcceptedMouseButtons(Qt::MouseButtons buttons)
+{
+ if (Qt::MouseButtons(d_ptr->acceptedMouseButtons) != buttons) {
+ if (buttons == 0 && d_ptr->scene && d_ptr->scene->mouseGrabberItem() == this
+ && d_ptr->scene->d_func()->lastMouseGrabberItemHasImplicitMouseGrab) {
+ ungrabMouse();
+ }
+ d_ptr->acceptedMouseButtons = quint32(buttons);
+ }
+}
+
+/*!
+ \since 4.4
+
+ Returns true if an item accepts hover events
+ (QGraphicsSceneHoverEvent); otherwise, returns false. By default,
+ items do not accept hover events.
+
+ \sa setAcceptedMouseButtons()
+*/
+bool QGraphicsItem::acceptHoverEvents() const
+{
+ return d_ptr->acceptsHover;
+}
+
+/*!
+ \obsolete
+
+ Call acceptHoverEvents() instead.
+*/
+bool QGraphicsItem::acceptsHoverEvents() const
+{
+ return d_ptr->acceptsHover;
+}
+
+/*!
+ \since 4.4
+
+ If \a enabled is true, this item will accept hover events;
+ otherwise, it will ignore them. By default, items do not accept
+ hover events.
+
+ Hover events are delivered when there is no current mouse grabber
+ item. They are sent when the mouse cursor enters an item, when it
+ moves around inside the item, and when the cursor leaves an
+ item. Hover events are commonly used to highlight an item when
+ it's entered, and for tracking the mouse cursor as it hovers over
+ the item (equivalent to QWidget::mouseTracking).
+
+ Parent items receive hover enter events before their children, and
+ leave events after their children. The parent does not receive a
+ hover leave event if the cursor enters a child, though; the parent
+ stays "hovered" until the cursor leaves its area, including its
+ children's areas.
+
+ If a parent item handles child events, it will receive hover move,
+ drag move, and drop events as the cursor passes through its
+ children, but it does not receive hover enter and hover leave, nor
+ drag enter and drag leave events on behalf of its children.
+
+ A QGraphicsWidget with window decorations will accept hover events
+ regardless of the value of acceptHoverEvents().
+
+ \sa acceptHoverEvents(), hoverEnterEvent(), hoverMoveEvent(),
+ hoverLeaveEvent()
+*/
+void QGraphicsItem::setAcceptHoverEvents(bool enabled)
+{
+ if (d_ptr->acceptsHover == quint32(enabled))
+ return;
+ d_ptr->acceptsHover = quint32(enabled);
+ if (d_ptr->acceptsHover && d_ptr->scene && d_ptr->scene->d_func()->allItemsIgnoreHoverEvents) {
+ d_ptr->scene->d_func()->allItemsIgnoreHoverEvents = false;
+ d_ptr->scene->d_func()->enableMouseTrackingOnViews();
+ }
+}
+
+/*!
+ \obsolete
+
+ Use setAcceptHoverEvents(\a enabled) instead.
+*/
+void QGraphicsItem::setAcceptsHoverEvents(bool enabled)
+{
+ setAcceptHoverEvents(enabled);
+}
+
+/*! \since 4.6
+
+ Returns true if an item accepts \l{QTouchEvent}{touch events};
+ otherwise, returns false. By default, items do not accept touch events.
+
+ \sa setAcceptTouchEvents()
+*/
+bool QGraphicsItem::acceptTouchEvents() const
+{
+ return d_ptr->acceptTouchEvents;
+}
+
+/*!
+ \since 4.6
+
+ If \a enabled is true, this item will accept \l{QTouchEvent}{touch events};
+ otherwise, it will ignore them. By default, items do not accept
+ touch events.
+*/
+void QGraphicsItem::setAcceptTouchEvents(bool enabled)
+{
+ if (d_ptr->acceptTouchEvents == quint32(enabled))
+ return;
+ d_ptr->acceptTouchEvents = quint32(enabled);
+ if (d_ptr->acceptTouchEvents && d_ptr->scene && d_ptr->scene->d_func()->allItemsIgnoreTouchEvents) {
+ d_ptr->scene->d_func()->allItemsIgnoreTouchEvents = false;
+ d_ptr->scene->d_func()->enableTouchEventsOnViews();
+ }
+}
+
+/*!
+ \since 4.6
+
+ Returns true if this item filters child events (i.e., all events
+ intended for any of its children are instead sent to this item);
+ otherwise, false is returned.
+
+ The default value is false; child events are not filtered.
+
+ \sa setFiltersChildEvents()
+*/
+bool QGraphicsItem::filtersChildEvents() const
+{
+ return d_ptr->filtersDescendantEvents;
+}
+
+/*!
+ \since 4.6
+
+ If \a enabled is true, this item is set to filter all events for
+ all its children (i.e., all events intented for any of its
+ children are instead sent to this item); otherwise, if \a enabled
+ is false, this item will only handle its own events. The default
+ value is false.
+
+ \sa filtersChildEvents()
+*/
+void QGraphicsItem::setFiltersChildEvents(bool enabled)
+{
+ if (d_ptr->filtersDescendantEvents == enabled)
+ return;
+
+ d_ptr->filtersDescendantEvents = enabled;
+ d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
+}
+
+/*!
+ \obsolete
+
+ Returns true if this item handles child events (i.e., all events
+ intended for any of its children are instead sent to this item);
+ otherwise, false is returned.
+
+ This property is useful for item groups; it allows one item to
+ handle events on behalf of its children, as opposed to its
+ children handling their events individually.
+
+ The default is to return false; children handle their own events.
+ The exception for this is if the item is a QGraphicsItemGroup, then
+ it defaults to return true.
+
+ \sa setHandlesChildEvents()
+*/
+bool QGraphicsItem::handlesChildEvents() const
+{
+ return d_ptr->handlesChildEvents;
+}
+
+/*!
+ \obsolete
+
+ If \a enabled is true, this item is set to handle all events for
+ all its children (i.e., all events intented for any of its
+ children are instead sent to this item); otherwise, if \a enabled
+ is false, this item will only handle its own events. The default
+ value is false.
+
+ This property is useful for item groups; it allows one item to
+ handle events on behalf of its children, as opposed to its
+ children handling their events individually.
+
+ If a child item accepts hover events, its parent will receive
+ hover move events as the cursor passes through the child, but it
+ does not receive hover enter and hover leave events on behalf of
+ its child.
+
+ \sa handlesChildEvents()
+*/
+void QGraphicsItem::setHandlesChildEvents(bool enabled)
+{
+ if (d_ptr->handlesChildEvents == enabled)
+ return;
+
+ d_ptr->handlesChildEvents = enabled;
+ d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
+}
+/*!
+ \since 4.6
+ Returns true if this item is active; otherwise returns false.
+
+ An item can only be active if the scene is active. An item is active
+ if it is, or is a descendent of, an active panel. Items in non-active
+ panels are not active.
+
+ Items that are not part of a panel follow scene activation when the
+ scene has no active panel.
+
+ Only active items can gain input focus.
+
+ \sa QGraphicsScene::isActive(), QGraphicsScene::activePanel(), panel(), isPanel()
+*/
+bool QGraphicsItem::isActive() const
+{
+ if (!d_ptr->scene || !d_ptr->scene->isActive())
+ return false;
+ return panel() == d_ptr->scene->activePanel();
+}
+
+/*!
+ \since 4.6
+
+ If \a active is true, and the scene is active, this item's panel will be
+ activated. Otherwise, the panel is deactivated.
+
+ If the item is not part of an active scene, \a active will decide what
+ happens to the panel when the scene becomes active or the item is added to
+ the scene. If true, the item's panel will be activated when the item is
+ either added to the scene or the scene is activated. Otherwise, the item
+ will stay inactive independent of the scene's activated state.
+
+ \sa isPanel(), QGraphicsScene::setActivePanel(), QGraphicsScene::isActive()
+*/
+void QGraphicsItem::setActive(bool active)
+{
+ d_ptr->explicitActivate = 1;
+ d_ptr->wantsActive = active;
+ if (d_ptr->scene) {
+ if (active) {
+ // Activate this item.
+ d_ptr->scene->setActivePanel(this);
+ } else {
+ // Deactivate this item, and reactivate the last active item
+ // (if any).
+ QGraphicsItem *lastActive = d_ptr->scene->d_func()->lastActivePanel;
+ d_ptr->scene->setActivePanel(lastActive != this ? lastActive : 0);
+ }
+ }
+}
+
+/*!
+ Returns true if this item is active, and it or its \l{focusProxy()}{focus
+ proxy} has keyboard input focus; otherwise, returns false.
+
+ \sa focusItem(), setFocus(), QGraphicsScene::setFocusItem(), isActive()
+*/
+bool QGraphicsItem::hasFocus() const
+{
+ if (!d_ptr->scene || !d_ptr->scene->isActive())
+ return false;
+
+ if (d_ptr->focusProxy)
+ return d_ptr->focusProxy->hasFocus();
+
+ if (d_ptr->scene->d_func()->focusItem != this)
+ return false;
+
+ return panel() == d_ptr->scene->d_func()->activePanel;
+}
+
+/*!
+ Gives keyboard input focus to this item. The \a focusReason argument will
+ be passed into any \l{QFocusEvent}{focus event} generated by this function;
+ it is used to give an explanation of what caused the item to get focus.
+
+ Only enabled items that set the ItemIsFocusable flag can accept keyboard
+ focus.
+
+ If this item is not visible, not active, or not associated with a scene,
+ it will not gain immediate input focus. However, it will be registered as
+ the preferred focus item for its subtree of items, should it later become
+ visible.
+
+ As a result of calling this function, this item will receive a
+ \l{focusInEvent()}{focus in event} with \a focusReason. If another item
+ already has focus, that item will first receive a \l{focusOutEvent()}
+ {focus out event} indicating that it has lost input focus.
+
+ \sa clearFocus(), hasFocus(), focusItem(), focusProxy()
+*/
+void QGraphicsItem::setFocus(Qt::FocusReason focusReason)
+{
+ d_ptr->setFocusHelper(focusReason, /* climb = */ true, /* focusFromHide = */ false);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool climb, bool focusFromHide)
+{
+ // Disabled / unfocusable items cannot accept focus.
+ if (!q_ptr->isEnabled() || !(flags & QGraphicsItem::ItemIsFocusable))
+ return;
+
+ // Find focus proxy.
+ QGraphicsItem *f = q_ptr;
+ while (f->d_ptr->focusProxy)
+ f = f->d_ptr->focusProxy;
+
+ // Return if it already has focus.
+ if (scene && scene->focusItem() == f)
+ return;
+
+ // Update focus scope item ptr.
+ QGraphicsItem *p = parent;
+ while (p) {
+ if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+ QGraphicsItem *oldFocusScopeItem = p->d_ptr->focusScopeItem;
+ p->d_ptr->focusScopeItem = q_ptr;
+ if (!p->focusItem() && !focusFromHide) {
+ if (oldFocusScopeItem)
+ oldFocusScopeItem->d_ptr->focusScopeItemChange(false);
+ focusScopeItemChange(true);
+ // If you call setFocus on a child of a focus scope that
+ // doesn't currently have a focus item, then stop.
+ return;
+ }
+ break;
+ }
+ p = p->d_ptr->parent;
+ }
+
+ if (climb) {
+ while (f->d_ptr->focusScopeItem && f->d_ptr->focusScopeItem->isVisible())
+ f = f->d_ptr->focusScopeItem;
+ }
+
+ // Update the child focus chain.
+ QGraphicsItem *commonAncestor = 0;
+ if (scene && scene->focusItem()) {
+ commonAncestor = scene->focusItem()->commonAncestorItem(f);
+ scene->focusItem()->d_ptr->clearSubFocus(scene->focusItem(), commonAncestor);
+ }
+
+ f->d_ptr->setSubFocus(f, commonAncestor);
+
+ // Update the scene's focus item.
+ if (scene) {
+ QGraphicsItem *p = q_ptr->panel();
+ if ((!p && scene->isActive()) || (p && p->isActive())) {
+ // Visible items immediately gain focus from scene.
+ scene->d_func()->setFocusItemHelper(f, focusReason);
+ }
+ }
+}
+
+/*!
+ Takes keyboard input focus from the item.
+
+ If it has focus, a \l{focusOutEvent()}{focus out event} is sent to this
+ item to tell it that it is about to lose the focus.
+
+ Only items that set the ItemIsFocusable flag, or widgets that set an
+ appropriate focus policy, can accept keyboard focus.
+
+ \sa setFocus(), hasFocus(), QGraphicsWidget::focusPolicy
+*/
+void QGraphicsItem::clearFocus()
+{
+ d_ptr->clearFocusHelper(/* giveFocusToParent = */ true);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::clearFocusHelper(bool giveFocusToParent)
+{
+ if (giveFocusToParent) {
+ // Pass focus to the closest parent focus scope
+ if (!inDestructor) {
+ QGraphicsItem *p = parent;
+ while (p) {
+ if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+ if (p->d_ptr->focusScopeItem == q_ptr) {
+ p->d_ptr->focusScopeItem = 0;
+ if (!q_ptr->hasFocus()) //if it has focus, focusScopeItemChange is called elsewhere
+ focusScopeItemChange(false);
+ }
+ if (q_ptr->hasFocus())
+ p->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ false,
+ /* focusFromHide = */ false);
+ return;
+ }
+ p = p->d_ptr->parent;
+ }
+ }
+ }
+
+ if (q_ptr->hasFocus()) {
+ // Invisible items with focus must explicitly clear subfocus.
+ clearSubFocus(q_ptr);
+
+ // If this item has the scene's input focus, clear it.
+ scene->setFocusItem(0);
+ }
+}
+
+/*!
+ \since 4.6
+
+ Returns this item's focus proxy, or 0 if this item has no
+ focus proxy.
+
+ \sa setFocusProxy(), setFocus(), hasFocus()
+*/
+QGraphicsItem *QGraphicsItem::focusProxy() const
+{
+ return d_ptr->focusProxy;
+}
+
+/*!
+ \since 4.6
+
+ Sets the item's focus proxy to \a item.
+
+ If an item has a focus proxy, the focus proxy will receive
+ input focus when the item gains input focus. The item itself
+ will still have focus (i.e., hasFocus() will return true),
+ but only the focus proxy will receive the keyboard input.
+
+ A focus proxy can itself have a focus proxy, and so on. In
+ such case, keyboard input will be handled by the outermost
+ focus proxy.
+
+ The focus proxy \a item must belong to the same scene as
+ this item.
+
+ \sa focusProxy(), setFocus(), hasFocus()
+*/
+void QGraphicsItem::setFocusProxy(QGraphicsItem *item)
+{
+ if (item == d_ptr->focusProxy)
+ return;
+ if (item == this) {
+ qWarning("QGraphicsItem::setFocusProxy: cannot assign self as focus proxy");
+ return;
+ }
+ if (item) {
+ if (item->d_ptr->scene != d_ptr->scene) {
+ qWarning("QGraphicsItem::setFocusProxy: focus proxy must be in same scene");
+ return;
+ }
+ for (QGraphicsItem *f = item->focusProxy(); f != 0; f = f->focusProxy()) {
+ if (f == this) {
+ qWarning("QGraphicsItem::setFocusProxy: %p is already in the focus proxy chain", item);
+ return;
+ }
+ }
+ }
+
+ QGraphicsItem *lastFocusProxy = d_ptr->focusProxy;
+ if (lastFocusProxy)
+ lastFocusProxy->d_ptr->focusProxyRefs.removeOne(&d_ptr->focusProxy);
+ d_ptr->focusProxy = item;
+ if (item)
+ item->d_ptr->focusProxyRefs << &d_ptr->focusProxy;
+}
+
+/*!
+ \since 4.6
+
+ If this item, a child or descendant of this item currently has input
+ focus, this function will return a pointer to that item. If
+ no descendant has input focus, 0 is returned.
+
+ \sa hasFocus(), setFocus(), QWidget::focusWidget()
+*/
+QGraphicsItem *QGraphicsItem::focusItem() const
+{
+ return d_ptr->subFocusItem;
+}
+
+/*!
+ \internal
+
+ Returns this item's focus scope item.
+*/
+QGraphicsItem *QGraphicsItem::focusScopeItem() const
+{
+ return d_ptr->focusScopeItem;
+}
+
+/*!
+ \since 4.4
+ Grabs the mouse input.
+
+ This item will receive all mouse events for the scene until any of the
+ following events occurs:
+
+ \list
+ \o The item becomes invisible
+ \o The item is removed from the scene
+ \o The item is deleted
+ \o The item call ungrabMouse()
+ \o Another item calls grabMouse(); the item will regain the mouse grab
+ when the other item calls ungrabMouse().
+ \endlist
+
+ When an item gains the mouse grab, it receives a QEvent::GrabMouse
+ event. When it loses the mouse grab, it receives a QEvent::UngrabMouse
+ event. These events can be used to detect when your item gains or loses
+ the mouse grab through other means than receiving mouse button events.
+
+ It is almost never necessary to explicitly grab the mouse in Qt, as Qt
+ grabs and releases it sensibly. In particular, Qt grabs the mouse when you
+ press a mouse button, and keeps the mouse grabbed until you release the
+ last mouse button. Also, Qt::Popup widgets implicitly call grabMouse()
+ when shown, and ungrabMouse() when hidden.
+
+ Note that only visible items can grab mouse input. Calling grabMouse() on
+ an invisible item has no effect.
+
+ Keyboard events are not affected.
+
+ \sa QGraphicsScene::mouseGrabberItem(), ungrabMouse(), grabKeyboard()
+*/
+void QGraphicsItem::grabMouse()
+{
+ if (!d_ptr->scene) {
+ qWarning("QGraphicsItem::grabMouse: cannot grab mouse without scene");
+ return;
+ }
+ if (!d_ptr->visible) {
+ qWarning("QGraphicsItem::grabMouse: cannot grab mouse while invisible");
+ return;
+ }
+ d_ptr->scene->d_func()->grabMouse(this);
+}
+
+/*!
+ \since 4.4
+ Releases the mouse grab.
+
+ \sa grabMouse(), ungrabKeyboard()
+*/
+void QGraphicsItem::ungrabMouse()
+{
+ if (!d_ptr->scene) {
+ qWarning("QGraphicsItem::ungrabMouse: cannot ungrab mouse without scene");
+ return;
+ }
+ d_ptr->scene->d_func()->ungrabMouse(this);
+}
+
+/*!
+ \since 4.4
+ Grabs the keyboard input.
+
+ The item will receive all keyboard input to the scene until one of the
+ following events occur:
+
+ \list
+ \o The item becomes invisible
+ \o The item is removed from the scene
+ \o The item is deleted
+ \o The item calls ungrabKeyboard()
+ \o Another item calls grabKeyboard(); the item will regain the keyboard grab
+ when the other item calls ungrabKeyboard().
+ \endlist
+
+ When an item gains the keyboard grab, it receives a QEvent::GrabKeyboard
+ event. When it loses the keyboard grab, it receives a
+ QEvent::UngrabKeyboard event. These events can be used to detect when your
+ item gains or loses the keyboard grab through other means than gaining
+ input focus.
+
+ It is almost never necessary to explicitly grab the keyboard in Qt, as Qt
+ grabs and releases it sensibly. In particular, Qt grabs the keyboard when
+ your item gains input focus, and releases it when your item loses input
+ focus, or when the item is hidden.
+
+ Note that only visible items can grab keyboard input. Calling
+ grabKeyboard() on an invisible item has no effect.
+
+ Keyboard events are not affected.
+
+ \sa ungrabKeyboard(), grabMouse(), setFocus()
+*/
+void QGraphicsItem::grabKeyboard()
+{
+ if (!d_ptr->scene) {
+ qWarning("QGraphicsItem::grabKeyboard: cannot grab keyboard without scene");
+ return;
+ }
+ if (!d_ptr->visible) {
+ qWarning("QGraphicsItem::grabKeyboard: cannot grab keyboard while invisible");
+ return;
+ }
+ d_ptr->scene->d_func()->grabKeyboard(this);
+}
+
+/*!
+ \since 4.4
+ Releases the keyboard grab.
+
+ \sa grabKeyboard(), ungrabMouse()
+*/
+void QGraphicsItem::ungrabKeyboard()
+{
+ if (!d_ptr->scene) {
+ qWarning("QGraphicsItem::ungrabKeyboard: cannot ungrab keyboard without scene");
+ return;
+ }
+ d_ptr->scene->d_func()->ungrabKeyboard(this);
+}
+
+/*!
+ Returns the position of the item in parent coordinates. If the item has no
+ parent, its position is given in scene coordinates.
+
+ The position of the item describes its origin (local coordinate
+ (0, 0)) in parent coordinates; this function returns the same as
+ mapToParent(0, 0).
+
+ For convenience, you can also call scenePos() to determine the
+ item's position in scene coordinates, regardless of its parent.
+
+ \sa x(), y(), setPos(), transform(), {The Graphics View Coordinate System}
+*/
+QPointF QGraphicsItem::pos() const
+{
+ return d_ptr->pos;
+}
+
+/*!
+ \fn QGraphicsItem::x() const
+
+ This convenience function is equivalent to calling pos().x().
+
+ \sa y()
+*/
+
+/*!
+ \since 4.6
+
+ Set's the \a x coordinate of the item's position. Equivalent to
+ calling setPos(x, y()).
+
+ \sa x(), setPos()
+*/
+void QGraphicsItem::setX(qreal x)
+{
+ if (d_ptr->inDestructor)
+ return;
+
+ if (qIsNaN(x))
+ return;
+
+ setPos(QPointF(x, d_ptr->pos.y()));
+}
+
+/*!
+ \fn QGraphicsItem::y() const
+
+ This convenience function is equivalent to calling pos().y().
+
+ \sa x()
+*/
+
+/*!
+ \since 4.6
+
+ Set's the \a y coordinate of the item's position. Equivalent to
+ calling setPos(x(), y).
+
+ \sa x(), setPos()
+*/
+void QGraphicsItem::setY(qreal y)
+{
+ if (d_ptr->inDestructor)
+ return;
+
+ if (qIsNaN(y))
+ return;
+
+ setPos(QPointF(d_ptr->pos.x(), y));
+}
+
+/*!
+ Returns the item's position in scene coordinates. This is
+ equivalent to calling \c mapToScene(0, 0).
+
+ \sa pos(), sceneTransform(), {The Graphics View Coordinate System}
+*/
+QPointF QGraphicsItem::scenePos() const
+{
+ return mapToScene(0, 0);
+}
+
+/*!
+ \internal
+
+ Sets the position \a pos.
+*/
+void QGraphicsItemPrivate::setPosHelper(const QPointF &pos)
+{
+ Q_Q(QGraphicsItem);
+ inSetPosHelper = 1;
+ if (scene)
+ q->prepareGeometryChange();
+ QPointF oldPos = this->pos;
+ this->pos = pos;
+ dirtySceneTransform = 1;
+ inSetPosHelper = 0;
+ if (isObject) {
+ if (pos.x() != oldPos.x())
+ emit static_cast<QGraphicsObject *>(q_ptr)->xChanged();
+ if (pos.y() != oldPos.y())
+ emit static_cast<QGraphicsObject *>(q_ptr)->yChanged();
+ }
+}
+
+/*!
+ \internal
+
+ Sets the transform \a transform.
+*/
+void QGraphicsItemPrivate::setTransformHelper(const QTransform &transform)
+{
+ q_ptr->prepareGeometryChange();
+ transformData->transform = transform;
+ dirtySceneTransform = 1;
+ transformChanged();
+}
+
+/*!
+ Sets the position of the item to \a pos, which is in parent
+ coordinates. For items with no parent, \a pos is in scene
+ coordinates.
+
+ The position of the item describes its origin (local coordinate
+ (0, 0)) in parent coordinates.
+
+ \sa pos(), scenePos(), {The Graphics View Coordinate System}
+*/
+void QGraphicsItem::setPos(const QPointF &pos)
+{
+ if (d_ptr->pos == pos)
+ return;
+
+ if (d_ptr->inDestructor)
+ return;
+
+ // Update and repositition.
+ if (!(d_ptr->flags & (ItemSendsGeometryChanges | ItemSendsScenePositionChanges))) {
+ d_ptr->setPosHelper(pos);
+ if (d_ptr->isWidget)
+ static_cast<QGraphicsWidget *>(this)->d_func()->setGeometryFromSetPos();
+ if (d_ptr->scenePosDescendants)
+ d_ptr->sendScenePosChange();
+ return;
+ }
+
+ // Notify the item that the position is changing.
+ const QVariant newPosVariant(itemChange(ItemPositionChange, QVariant::fromValue<QPointF>(pos)));
+ QPointF newPos = newPosVariant.toPointF();
+ if (newPos == d_ptr->pos)
+ return;
+
+ // Update and repositition.
+ d_ptr->setPosHelper(newPos);
+
+ // Send post-notification.
+ itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant);
+ d_ptr->sendScenePosChange();
+}
+
+/*!
+ \fn void QGraphicsItem::setPos(qreal x, qreal y)
+ \overload
+
+ This convenience function is equivalent to calling setPos(QPointF(\a x, \a
+ y)).
+*/
+
+/*!
+ \fn void QGraphicsItem::moveBy(qreal dx, qreal dy)
+
+ Moves the item by \a dx points horizontally, and \a dy point
+ vertically. This function is equivalent to calling setPos(pos() +
+ QPointF(\a dx, \a dy)).
+*/
+
+/*!
+ If this item is part of a scene that is viewed by a QGraphicsView, this
+ convenience function will attempt to scroll the view to ensure that \a
+ rect is visible inside the view's viewport. If \a rect is a null rect (the
+ default), QGraphicsItem will default to the item's bounding rect. \a xmargin
+ and \a ymargin are the number of pixels the view should use for margins.
+
+ If the specified rect cannot be reached, the contents are scrolled to the
+ nearest valid position.
+
+ If this item is not viewed by a QGraphicsView, this function does nothing.
+
+ \sa QGraphicsView::ensureVisible()
+*/
+void QGraphicsItem::ensureVisible(const QRectF &rect, int xmargin, int ymargin)
+{
+ if (d_ptr->scene) {
+ QRectF sceneRect;
+ if (!rect.isNull())
+ sceneRect = sceneTransform().mapRect(rect);
+ else
+ sceneRect = sceneBoundingRect();
+ foreach (QGraphicsView *view, d_ptr->scene->d_func()->views)
+ view->ensureVisible(sceneRect, xmargin, ymargin);
+ }
+}
+
+/*!
+ \fn void QGraphicsItem::ensureVisible(qreal x, qreal y, qreal w, qreal h,
+ int xmargin = 50, int ymargin = 50)
+
+ This convenience function is equivalent to calling
+ ensureVisible(QRectF(\a x, \a y, \a w, \a h), \a xmargin, \a ymargin):
+*/
+
+/*!
+ \obsolete
+
+ Returns the item's affine transformation matrix. This is a subset or the
+ item's full transformation matrix, and might not represent the item's full
+ transformation.
+
+ Use transform() instead.
+
+ \sa setTransform(), sceneTransform()
+*/
+QMatrix QGraphicsItem::matrix() const
+{
+ return transform().toAffine();
+}
+
+/*!
+ \since 4.3
+
+ Returns this item's transformation matrix.
+
+ The transformation matrix is combined with the item's rotation(), scale()
+ and transformations() into a combined transformations for the item.
+
+ The default transformation matrix is an identity matrix.
+
+ \sa setTransform(), sceneTransform()
+*/
+QTransform QGraphicsItem::transform() const
+{
+ if (!d_ptr->transformData)
+ return QTransform();
+ return d_ptr->transformData->transform;
+}
+
+/*!
+ \since 4.6
+
+ Returns the clockwise rotation, in degrees, around the Z axis. The default
+ value is 0 (i.e., the item is not rotated).
+
+ The rotation is combined with the item's scale(), transform() and
+ transformations() to map the item's coordinate system to the parent item.
+
+ \sa setRotation(), transformOriginPoint(), {Transformations}
+*/
+qreal QGraphicsItem::rotation() const
+{
+ if (!d_ptr->transformData)
+ return 0;
+ return d_ptr->transformData->rotation;
+}
+
+/*!
+ \since 4.6
+
+ Sets the clockwise rotation \a angle, in degrees, around the Z axis. The
+ default value is 0 (i.e., the item is not rotated). Assigning a negative
+ value will rotate the item counter-clockwise. Normally the rotation angle
+ is in the range (-360, 360), but it's also possible to assign values
+ outside of this range (e.g., a rotation of 370 degrees is the same as a
+ rotation of 10 degrees).
+
+ The item is rotated around its transform origin point, which by default
+ is (0, 0). You can select a different transformation origin by calling
+ setTransformOriginPoint().
+
+ The rotation is combined with the item's scale(), transform() and
+ transformations() to map the item's coordinate system to the parent item.
+
+ \sa rotation(), setTransformOriginPoint(), {Transformations}
+*/
+void QGraphicsItem::setRotation(qreal angle)
+{
+ prepareGeometryChange();
+ qreal newRotation = angle;
+
+ if (d_ptr->flags & ItemSendsGeometryChanges) {
+ // Notify the item that the rotation is changing.
+ const QVariant newRotationVariant(itemChange(ItemRotationChange, angle));
+ newRotation = newRotationVariant.toReal();
+ }
+
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+
+ if (d_ptr->transformData->rotation == newRotation)
+ return;
+
+ d_ptr->transformData->rotation = newRotation;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+
+ // Send post-notification.
+ if (d_ptr->flags & ItemSendsGeometryChanges)
+ itemChange(ItemRotationHasChanged, newRotation);
+
+ if (d_ptr->isObject)
+ emit static_cast<QGraphicsObject *>(this)->rotationChanged();
+
+ d_ptr->transformChanged();
+}
+
+/*!
+ \since 4.6
+
+ Returns the scale factor of the item. The default scale factor is 1.0
+ (i.e., the item is not scaled).
+
+ The scale is combined with the item's rotation(), transform() and
+ transformations() to map the item's coordinate system to the parent item.
+
+ \sa setScale(), rotation(), {Transformations}
+*/
+qreal QGraphicsItem::scale() const
+{
+ if (!d_ptr->transformData)
+ return 1.;
+ return d_ptr->transformData->scale;
+}
+
+/*!
+ \since 4.6
+
+ Sets the scale \a factor of the item. The default scale factor is 1.0
+ (i.e., the item is not scaled). A scale factor of 0.0 will collapse the
+ item to a single point. If you provide a negative scale factor, the
+ item will be flipped and mirrored (i.e., rotated 180 degrees).
+
+ The item is scaled around its transform origin point, which by default
+ is (0, 0). You can select a different transformation origin by calling
+ setTransformOriginPoint().
+
+ The scale is combined with the item's rotation(), transform() and
+ transformations() to map the item's coordinate system to the parent item.
+
+ \sa scale(), setTransformOriginPoint(), {Transformations Example}
+*/
+void QGraphicsItem::setScale(qreal factor)
+{
+ prepareGeometryChange();
+ qreal newScale = factor;
+
+ if (d_ptr->flags & ItemSendsGeometryChanges) {
+ // Notify the item that the scale is changing.
+ const QVariant newScaleVariant(itemChange(ItemScaleChange, factor));
+ newScale = newScaleVariant.toReal();
+ }
+
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+
+ if (d_ptr->transformData->scale == newScale)
+ return;
+
+ d_ptr->transformData->scale = newScale;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+
+ // Send post-notification.
+ if (d_ptr->flags & ItemSendsGeometryChanges)
+ itemChange(ItemScaleHasChanged, newScale);
+
+ if (d_ptr->isObject)
+ emit static_cast<QGraphicsObject *>(this)->scaleChanged();
+
+ d_ptr->transformChanged();
+}
+
+
+/*!
+ \since 4.6
+
+ Returns a list of graphics transforms that currently apply to this item.
+
+ QGraphicsTransform is for applying and controlling a chain of individual
+ transformation operations on an item. It's particularly useful in
+ animations, where each transform operation needs to be interpolated
+ independently, or differently.
+
+ The transformations are combined with the item's rotation(), scale() and
+ transform() to map the item's coordinate system to the parent item.
+
+ \sa scale(), rotation(), transformOriginPoint(), {Transformations}
+*/
+QList<QGraphicsTransform *> QGraphicsItem::transformations() const
+{
+ if (!d_ptr->transformData)
+ return QList<QGraphicsTransform *>();
+ return d_ptr->transformData->graphicsTransforms;
+}
+
+/*!
+ \since 4.6
+
+ Sets a list of graphics \a transformations (QGraphicsTransform) that
+ currently apply to this item.
+
+ If all you want is to rotate or scale an item, you should call setRotation()
+ or setScale() instead. If you want to set an arbitrary transformation on
+ an item, you can call setTransform().
+
+ QGraphicsTransform is for applying and controlling a chain of individual
+ transformation operations on an item. It's particularly useful in
+ animations, where each transform operation needs to be interpolated
+ independently, or differently.
+
+ The transformations are combined with the item's rotation(), scale() and
+ transform() to map the item's coordinate system to the parent item.
+
+ \sa scale(), setTransformOriginPoint(), {Transformations}
+*/
+void QGraphicsItem::setTransformations(const QList<QGraphicsTransform *> &transformations)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->graphicsTransforms = transformations;
+ for (int i = 0; i < transformations.size(); ++i)
+ transformations.at(i)->d_func()->setItem(this);
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+ d_ptr->transformChanged();
+}
+
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::prependGraphicsTransform(QGraphicsTransform *t)
+{
+ if (!transformData)
+ transformData = new QGraphicsItemPrivate::TransformData;
+ if (!transformData->graphicsTransforms.contains(t))
+ transformData->graphicsTransforms.prepend(t);
+
+ Q_Q(QGraphicsItem);
+ t->d_func()->setItem(q);
+ transformData->onlyTransform = false;
+ dirtySceneTransform = 1;
+ transformChanged();
+}
+
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::appendGraphicsTransform(QGraphicsTransform *t)
+{
+ if (!transformData)
+ transformData = new QGraphicsItemPrivate::TransformData;
+ if (!transformData->graphicsTransforms.contains(t))
+ transformData->graphicsTransforms.append(t);
+
+ Q_Q(QGraphicsItem);
+ t->d_func()->setItem(q);
+ transformData->onlyTransform = false;
+ dirtySceneTransform = 1;
+ transformChanged();
+}
+
+/*!
+ \since 4.6
+
+ Returns the origin point for the transformation in item coordinates.
+
+ The default is QPointF(0,0).
+
+ \sa setTransformOriginPoint(), {Transformations}
+*/
+QPointF QGraphicsItem::transformOriginPoint() const
+{
+ if (!d_ptr->transformData)
+ return QPointF(0,0);
+ return QPointF(d_ptr->transformData->xOrigin, d_ptr->transformData->yOrigin);
+}
+
+/*!
+ \since 4.6
+
+ Sets the \a origin point for the transformation in item coordinates.
+
+ \sa transformOriginPoint(), {Transformations}
+*/
+void QGraphicsItem::setTransformOriginPoint(const QPointF &origin)
+{
+ prepareGeometryChange();
+ QPointF newOrigin = origin;
+
+ if (d_ptr->flags & ItemSendsGeometryChanges) {
+ // Notify the item that the origin point is changing.
+ const QVariant newOriginVariant(itemChange(ItemTransformOriginPointChange,
+ QVariant::fromValue<QPointF>(origin)));
+ newOrigin = newOriginVariant.toPointF();
+ }
+
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+
+ if (d_ptr->transformData->xOrigin == newOrigin.x()
+ && d_ptr->transformData->yOrigin == newOrigin.y()) {
+ return;
+ }
+
+ d_ptr->transformData->xOrigin = newOrigin.x();
+ d_ptr->transformData->yOrigin = newOrigin.y();
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+
+ // Send post-notification.
+ if (d_ptr->flags & ItemSendsGeometryChanges)
+ itemChange(ItemTransformOriginPointHasChanged, QVariant::fromValue<QPointF>(newOrigin));
+}
+
+/*!
+ \fn void QGraphicsItem::setTransformOriginPoint(qreal x, qreal y)
+
+ \since 4.6
+ \overload
+
+ Sets the origin point for the transformation in item coordinates.
+ This is equivalent to calling setTransformOriginPoint(QPointF(\a x, \a y)).
+
+ \sa setTransformOriginPoint(), {Transformations}
+*/
+
+
+/*!
+ \obsolete
+
+ Use sceneTransform() instead.
+
+ \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}
+*/
+QMatrix QGraphicsItem::sceneMatrix() const
+{
+ d_ptr->ensureSceneTransform();
+ return d_ptr->sceneTransform.toAffine();
+}
+
+
+/*!
+ \since 4.3
+
+ Returns this item's scene transformation matrix. This matrix can be used
+ to map coordinates and geometrical shapes from this item's local
+ coordinate system to the scene's coordinate system. To map coordinates
+ from the scene, you must first invert the returned matrix.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 4
+
+ Unlike transform(), which returns only an item's local transformation, this
+ function includes the item's (and any parents') position, and all the transfomation properties.
+
+ \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}, {Transformations}
+*/
+QTransform QGraphicsItem::sceneTransform() const
+{
+ d_ptr->ensureSceneTransform();
+ return d_ptr->sceneTransform;
+}
+
+/*!
+ \since 4.3
+
+ Returns this item's device transformation matrix, using \a
+ viewportTransform to map from scene to device coordinates. This matrix can
+ be used to map coordinates and geometrical shapes from this item's local
+ coordinate system to the viewport's (or any device's) coordinate
+ system. To map coordinates from the viewport, you must first invert the
+ returned matrix.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 5
+
+ This function is the same as combining this item's scene transform with
+ the view's viewport transform, but it also understands the
+ ItemIgnoresTransformations flag. The device transform can be used to do
+ accurate coordinate mapping (and collision detection) for untransformable
+ items.
+
+ \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate
+ System}, itemTransform()
+*/
+QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) const
+{
+ // Ensure we return the standard transform if we're not untransformable.
+ if (!d_ptr->itemIsUntransformable()) {
+ d_ptr->ensureSceneTransform();
+ return d_ptr->sceneTransform * viewportTransform;
+ }
+
+ // Find the topmost item that ignores view transformations.
+ const QGraphicsItem *untransformedAncestor = this;
+ QList<const QGraphicsItem *> parents;
+ while (untransformedAncestor && ((untransformedAncestor->d_ptr->ancestorFlags
+ & QGraphicsItemPrivate::AncestorIgnoresTransformations))) {
+ parents.prepend(untransformedAncestor);
+ untransformedAncestor = untransformedAncestor->parentItem();
+ }
+
+ if (!untransformedAncestor) {
+ // Assert in debug mode, continue in release.
+ Q_ASSERT_X(untransformedAncestor, "QGraphicsItem::deviceTransform",
+ "Invalid object structure!");
+ return QTransform();
+ }
+
+ // First translate the base untransformable item.
+ untransformedAncestor->d_ptr->ensureSceneTransform();
+ QPointF mappedPoint = (untransformedAncestor->d_ptr->sceneTransform * viewportTransform).map(QPointF(0, 0));
+
+ // COMBINE
+ QTransform matrix = QTransform::fromTranslate(mappedPoint.x(), mappedPoint.y());
+ if (untransformedAncestor->d_ptr->transformData)
+ matrix = untransformedAncestor->d_ptr->transformData->computedFullTransform(&matrix);
+
+ // Then transform and translate all children.
+ for (int i = 0; i < parents.size(); ++i) {
+ const QGraphicsItem *parent = parents.at(i);
+ parent->d_ptr->combineTransformFromParent(&matrix);
+ }
+
+ return matrix;
+}
+
+/*!
+ \since 4.5
+
+ Returns a QTransform that maps coordinates from this item to \a other. If
+ \a ok is not null, and if there is no such transform, the boolean pointed
+ to by \a ok will be set to false; otherwise it will be set to true.
+
+ This transform provides an alternative to the mapToItem() or mapFromItem()
+ functions, by returning the appropriate transform so that you can map
+ shapes and coordinates yourself. It also helps you write more efficient
+ code when repeatedly mapping between the same two items.
+
+ \note In rare circumstances, there is no transform that maps between two
+ items.
+
+ \sa mapToItem(), mapFromItem(), deviceTransform()
+*/
+QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) const
+{
+ // Catch simple cases first.
+ if (other == 0) {
+ qWarning("QGraphicsItem::itemTransform: null pointer passed");
+ return QTransform();
+ }
+ if (other == this) {
+ if (ok)
+ *ok = true;
+ return QTransform();
+ }
+
+ QGraphicsItem *parent = d_ptr->parent;
+ const QGraphicsItem *otherParent = other->d_ptr->parent;
+
+ // This is other's child
+ if (parent == other) {
+ if (ok)
+ *ok = true;
+ QTransform x;
+ d_ptr->combineTransformFromParent(&x);
+ return x;
+ }
+
+ // This is other's parent
+ if (otherParent == this) {
+ const QPointF &otherPos = other->d_ptr->pos;
+ if (other->d_ptr->transformData) {
+ QTransform otherToParent;
+ other->d_ptr->combineTransformFromParent(&otherToParent);
+ return otherToParent.inverted(ok);
+ }
+ if (ok)
+ *ok = true;
+ return QTransform::fromTranslate(-otherPos.x(), -otherPos.y());
+ }
+
+ // Siblings
+ if (parent == otherParent) {
+ // COMBINE
+ const QPointF &itemPos = d_ptr->pos;
+ const QPointF &otherPos = other->d_ptr->pos;
+ if (!d_ptr->transformData && !other->d_ptr->transformData) {
+ QPointF delta = itemPos - otherPos;
+ if (ok)
+ *ok = true;
+ return QTransform::fromTranslate(delta.x(), delta.y());
+ }
+
+ QTransform itemToParent;
+ d_ptr->combineTransformFromParent(&itemToParent);
+ QTransform otherToParent;
+ other->d_ptr->combineTransformFromParent(&otherToParent);
+ return itemToParent * otherToParent.inverted(ok);
+ }
+
+ // Find the closest common ancestor. If the two items don't share an
+ // ancestor, then the only way is to combine their scene transforms.
+ const QGraphicsItem *commonAncestor = commonAncestorItem(other);
+ if (!commonAncestor) {
+ d_ptr->ensureSceneTransform();
+ other->d_ptr->ensureSceneTransform();
+ return d_ptr->sceneTransform * other->d_ptr->sceneTransform.inverted(ok);
+ }
+
+ // If the two items are cousins (in sibling branches), map both to the
+ // common ancestor, and combine the two transforms.
+ bool cousins = other != commonAncestor && this != commonAncestor;
+ if (cousins) {
+ bool good = false;
+ QTransform thisToScene = itemTransform(commonAncestor, &good);
+ QTransform otherToScene(Qt::Uninitialized);
+ if (good)
+ otherToScene = other->itemTransform(commonAncestor, &good);
+ if (!good) {
+ if (ok)
+ *ok = false;
+ return QTransform();
+ }
+ return thisToScene * otherToScene.inverted(ok);
+ }
+
+ // One is an ancestor of the other; walk the chain.
+ bool parentOfOther = isAncestorOf(other);
+ const QGraphicsItem *child = parentOfOther ? other : this;
+ const QGraphicsItem *root = parentOfOther ? this : other;
+
+ QTransform x;
+ const QGraphicsItem *p = child;
+ do {
+ p->d_ptr.data()->combineTransformToParent(&x);
+ } while ((p = p->d_ptr->parent) && p != root);
+ if (parentOfOther)
+ return x.inverted(ok);
+ if (ok)
+ *ok = true;
+ return x;
+}
+
+/*!
+ \obsolete
+
+ Sets the item's affine transformation matrix. This is a subset or the
+ item's full transformation matrix, and might not represent the item's full
+ transformation.
+
+ Use setTransform() instead.
+
+ \sa transform(), {The Graphics View Coordinate System}
+*/
+void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
+{
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+
+ QTransform newTransform(combine ? QTransform(matrix) * d_ptr->transformData->transform : QTransform(matrix));
+ if (d_ptr->transformData->transform == newTransform)
+ return;
+
+ // Update and set the new transformation.
+ if (!(d_ptr->flags & ItemSendsGeometryChanges)) {
+ d_ptr->setTransformHelper(newTransform);
+ return;
+ }
+
+ // Notify the item that the transformation matrix is changing.
+ const QVariant newMatrixVariant = QVariant::fromValue<QMatrix>(newTransform.toAffine());
+ newTransform = QTransform(qvariant_cast<QMatrix>(itemChange(ItemMatrixChange, newMatrixVariant)));
+ if (d_ptr->transformData->transform == newTransform)
+ return;
+
+ // Update and set the new transformation.
+ d_ptr->setTransformHelper(newTransform);
+
+ // Send post-notification.
+ itemChange(ItemTransformHasChanged, QVariant::fromValue<QTransform>(newTransform));
+}
+
+/*!
+ \since 4.3
+
+ Sets the item's current transformation matrix to \a matrix.
+
+ If \a combine is true, then \a matrix is combined with the current matrix;
+ otherwise, \a matrix \e replaces the current matrix. \a combine is false
+ by default.
+
+ To simplify interation with items using a transformed view, QGraphicsItem
+ provides mapTo... and mapFrom... functions that can translate between
+ items' and the scene's coordinates. For example, you can call mapToScene()
+ to map an item coordiate to a scene coordinate, or mapFromScene() to map
+ from scene coordinates to item coordinates.
+
+ The transformation matrix is combined with the item's rotation(), scale()
+ and transformations() into a combined transformation that maps the item's
+ coordinate system to its parent.
+
+ \sa transform(), setRotation(), setScale(), setTransformOriginPoint(), {The Graphics View Coordinate System}, {Transformations}
+*/
+void QGraphicsItem::setTransform(const QTransform &matrix, bool combine)
+{
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+
+ QTransform newTransform(combine ? matrix * d_ptr->transformData->transform : matrix);
+ if (d_ptr->transformData->transform == newTransform)
+ return;
+
+ // Update and set the new transformation.
+ if (!(d_ptr->flags & (ItemSendsGeometryChanges | ItemSendsScenePositionChanges))) {
+ d_ptr->setTransformHelper(newTransform);
+ if (d_ptr->scenePosDescendants)
+ d_ptr->sendScenePosChange();
+ return;
+ }
+
+ // Notify the item that the transformation matrix is changing.
+ const QVariant newTransformVariant(itemChange(ItemTransformChange,
+ QVariant::fromValue<QTransform>(newTransform)));
+ newTransform = qvariant_cast<QTransform>(newTransformVariant);
+ if (d_ptr->transformData->transform == newTransform)
+ return;
+
+ // Update and set the new transformation.
+ d_ptr->setTransformHelper(newTransform);
+
+ // Send post-notification.
+ itemChange(ItemTransformHasChanged, newTransformVariant);
+ d_ptr->sendScenePosChange();
+}
+
+/*!
+ \obsolete
+
+ Use resetTransform() instead.
+*/
+void QGraphicsItem::resetMatrix()
+{
+ resetTransform();
+}
+
+/*!
+ \since 4.3
+
+ Resets this item's transformation matrix to the identity matrix or
+ all the transformation properties to their default values.
+ This is equivalent to calling \c setTransform(QTransform()).
+
+ \sa setTransform(), transform()
+*/
+void QGraphicsItem::resetTransform()
+{
+ setTransform(QTransform(), false);
+}
+
+/*!
+ \obsolete
+
+ Use
+
+ \code
+ setRotation(rotation() + angle);
+ \endcode
+
+ instead.
+
+ Rotates the current item transformation \a angle degrees clockwise around
+ its origin. To translate around an arbitrary point (x, y), you need to
+ combine translation and rotation with setTransform().
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 6
+
+ \sa setTransform(), transform(), scale(), shear(), translate()
+*/
+void QGraphicsItem::rotate(qreal angle)
+{
+ setTransform(QTransform().rotate(angle), true);
+}
+
+/*!
+ \obsolete
+
+ Use
+
+ \code
+ setTransform(QTransform::fromScale(sx, sy), true);
+ \endcode
+
+ instead.
+
+ Scales the current item transformation by (\a sx, \a sy) around its
+ origin. To scale from an arbitrary point (x, y), you need to combine
+ translation and scaling with setTransform().
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 7
+
+ \sa setTransform(), transform()
+*/
+void QGraphicsItem::scale(qreal sx, qreal sy)
+{
+ setTransform(QTransform::fromScale(sx, sy), true);
+}
+
+/*!
+ \obsolete
+
+ Use
+
+ \code
+ setTransform(QTransform().shear(sh, sv), true);
+ \endcode
+
+ instead.
+
+ Shears the current item transformation by (\a sh, \a sv).
+
+ \sa setTransform(), transform()
+*/
+void QGraphicsItem::shear(qreal sh, qreal sv)
+{
+ setTransform(QTransform().shear(sh, sv), true);
+}
+
+/*!
+ \obsolete
+
+ Use setPos() or setTransformOriginPoint() instead. For identical
+ behavior, use
+
+ \code
+ setTransform(QTransform::fromTranslate(dx, dy), true);
+ \endcode
+
+ Translates the current item transformation by (\a dx, \a dy).
+
+ If all you want is to move an item, you should call moveBy() or
+ setPos() instead; this function changes the item's translation,
+ which is conceptually separate from its position.
+
+ \sa setTransform(), transform()
+*/
+void QGraphicsItem::translate(qreal dx, qreal dy)
+{
+ setTransform(QTransform::fromTranslate(dx, dy), true);
+}
+
+/*!
+ This virtual function is called twice for all items by the
+ QGraphicsScene::advance() slot. In the first phase, all items are called
+ with \a phase == 0, indicating that items on the scene are about to
+ advance, and then all items are called with \a phase == 1. Reimplement
+ this function to update your item if you need simple scene-controlled
+ animation.
+
+ The default implementation does nothing.
+
+ For individual item animation, an alternative to this function is to
+ either use QGraphicsItemAnimation, or to multiple-inherit from QObject and
+ QGraphicsItem, and animate your item using QObject::startTimer() and
+ QObject::timerEvent().
+
+ \sa QGraphicsItemAnimation, QTimeLine
+*/
+void QGraphicsItem::advance(int phase)
+{
+ Q_UNUSED(phase);
+}
+
+/*!
+ Returns the Z-value of the item. The Z-value affects the stacking order of
+ sibling (neighboring) items.
+
+ The default Z-value is 0.
+
+ \sa setZValue(), {QGraphicsItem#Sorting}{Sorting}, stackBefore(), ItemStacksBehindParent
+*/
+qreal QGraphicsItem::zValue() const
+{
+ return d_ptr->z;
+}
+
+/*!
+ Sets the Z-value of the item to \a z. The Z value decides the stacking
+ order of sibling (neighboring) items. A sibling item of high Z value will
+ always be drawn on top of another sibling item with a lower Z value.
+
+ If you restore the Z value, the item's insertion order will decide its
+ stacking order.
+
+ The Z-value does not affect the item's size in any way.
+
+ The default Z-value is 0.
+
+ \sa zValue(), {QGraphicsItem#Sorting}{Sorting}, stackBefore(), ItemStacksBehindParent
+*/
+void QGraphicsItem::setZValue(qreal z)
+{
+ const QVariant newZVariant(itemChange(ItemZValueChange, z));
+ qreal newZ = newZVariant.toReal();
+ if (newZ == d_ptr->z)
+ return;
+
+ if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex) {
+ // Z Value has changed, we have to notify the index.
+ d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, &newZ);
+ }
+
+ d_ptr->z = newZ;
+ if (d_ptr->parent)
+ d_ptr->parent->d_ptr->needSortChildren = 1;
+ else if (d_ptr->scene)
+ d_ptr->scene->d_func()->needSortTopLevelItems = 1;
+
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
+
+ itemChange(ItemZValueHasChanged, newZVariant);
+
+ if (d_ptr->flags & ItemNegativeZStacksBehindParent)
+ setFlag(QGraphicsItem::ItemStacksBehindParent, z < qreal(0.0));
+
+ if (d_ptr->isObject)
+ emit static_cast<QGraphicsObject *>(this)->zChanged();
+}
+
+/*!
+ \internal
+
+ Ensures that the list of children is sorted by insertion order, and that
+ the siblingIndexes are packed (no gaps), and start at 0.
+
+ ### This function is almost identical to
+ QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes().
+*/
+void QGraphicsItemPrivate::ensureSequentialSiblingIndex()
+{
+ if (!sequentialOrdering) {
+ qSort(children.begin(), children.end(), insertionOrder);
+ sequentialOrdering = 1;
+ needSortChildren = 1;
+ }
+ if (holesInSiblingIndex) {
+ holesInSiblingIndex = 0;
+ for (int i = 0; i < children.size(); ++i)
+ children[i]->d_ptr->siblingIndex = i;
+ }
+}
+
+/*!
+ \internal
+*/
+inline void QGraphicsItemPrivate::sendScenePosChange()
+{
+ Q_Q(QGraphicsItem);
+ if (scene) {
+ if (flags & QGraphicsItem::ItemSendsScenePositionChanges)
+ q->itemChange(QGraphicsItem::ItemScenePositionHasChanged, q->scenePos());
+ if (scenePosDescendants) {
+ foreach (QGraphicsItem *item, scene->d_func()->scenePosItems) {
+ if (q->isAncestorOf(item))
+ item->itemChange(QGraphicsItem::ItemScenePositionHasChanged, item->scenePos());
+ }
+ }
+ }
+}
+
+/*!
+ \since 4.6
+
+ Stacks this item before \a sibling, which must be a sibling item (i.e., the
+ two items must share the same parent item, or must both be toplevel items).
+ The \a sibling must have the same Z value as this item, otherwise calling
+ this function will have no effect.
+
+ By default, all sibling items are stacked by insertion order (i.e., the
+ first item you add is drawn before the next item you add). If two items' Z
+ values are different, then the item with the highest Z value is drawn on
+ top. When the Z values are the same, the insertion order will decide the
+ stacking order.
+
+ \sa setZValue(), ItemStacksBehindParent, {QGraphicsItem#Sorting}{Sorting}
+*/
+void QGraphicsItem::stackBefore(const QGraphicsItem *sibling)
+{
+ if (sibling == this)
+ return;
+ if (!sibling || d_ptr->parent != sibling->parentItem()) {
+ qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
+ return;
+ }
+ QList<QGraphicsItem *> *siblings = d_ptr->parent
+ ? &d_ptr->parent->d_ptr->children
+ : (d_ptr->scene ? &d_ptr->scene->d_func()->topLevelItems : 0);
+ if (!siblings) {
+ qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
+ return;
+ }
+
+ // First, make sure that the sibling indexes have no holes. This also
+ // marks the children list for sorting.
+ if (d_ptr->parent)
+ d_ptr->parent->d_ptr->ensureSequentialSiblingIndex();
+ else
+ d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes();
+
+ // Only move items with the same Z value, and that need moving.
+ int siblingIndex = sibling->d_ptr->siblingIndex;
+ int myIndex = d_ptr->siblingIndex;
+ if (myIndex >= siblingIndex) {
+ siblings->move(myIndex, siblingIndex);
+ // Fixup the insertion ordering.
+ for (int i = 0; i < siblings->size(); ++i) {
+ int &index = siblings->at(i)->d_ptr->siblingIndex;
+ if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
+ ++index;
+ }
+ d_ptr->siblingIndex = siblingIndex;
+ for (int i = 0; i < siblings->size(); ++i) {
+ int &index = siblings->at(i)->d_ptr->siblingIndex;
+ if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
+ siblings->at(i)->d_ptr->siblingOrderChange();
+ }
+ d_ptr->siblingOrderChange();
+ }
+}
+
+/*!
+ Returns the bounding rect of this item's descendants (i.e., its
+ children, their children, etc.) in local coordinates. The
+ rectangle will contain all descendants after they have been mapped
+ to local coordinates. If the item has no children, this function
+ returns an empty QRectF.
+
+ This does not include this item's own bounding rect; it only returns
+ its descendants' accumulated bounding rect. If you need to include this
+ item's bounding rect, you can add boundingRect() to childrenBoundingRect()
+ using QRectF::operator|().
+
+ This function is linear in complexity; it determines the size of the
+ returned bounding rect by iterating through all descendants.
+
+ \sa boundingRect(), sceneBoundingRect()
+*/
+QRectF QGraphicsItem::childrenBoundingRect() const
+{
+ if (!d_ptr->dirtyChildrenBoundingRect)
+ return d_ptr->childrenBoundingRect;
+
+ d_ptr->childrenBoundingRect = QRectF();
+ d_ptr->childrenBoundingRectHelper(0, &d_ptr->childrenBoundingRect, 0);
+ d_ptr->dirtyChildrenBoundingRect = 0;
+ return d_ptr->childrenBoundingRect;
+}
+
+/*!
+ \fn virtual QRectF QGraphicsItem::boundingRect() const = 0
+
+ This pure virtual function defines the outer bounds of the item as
+ a rectangle; all painting must be restricted to inside an item's
+ bounding rect. QGraphicsView uses this to determine whether the
+ item requires redrawing.
+
+ Although the item's shape can be arbitrary, the bounding rect is
+ always rectangular, and it is unaffected by the items'
+ transformation.
+
+ If you want to change the item's bounding rectangle, you must first call
+ prepareGeometryChange(). This notifies the scene of the imminent change,
+ so that its can update its item geometry index; otherwise, the scene will
+ be unaware of the item's new geometry, and the results are undefined
+ (typically, rendering artifacts are left around in the view).
+
+ Reimplement this function to let QGraphicsView determine what
+ parts of the widget, if any, need to be redrawn.
+
+ Note: For shapes that paint an outline / stroke, it is important
+ to include half the pen width in the bounding rect. It is not
+ necessary to compensate for antialiasing, though.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 8
+
+ \sa boundingRegion(), shape(), contains(), {The Graphics View Coordinate
+ System}, prepareGeometryChange()
+*/
+
+/*!
+ Returns the bounding rect of this item in scene coordinates, by combining
+ sceneTransform() with boundingRect().
+
+ \sa boundingRect(), {The Graphics View Coordinate System}
+*/
+QRectF QGraphicsItem::sceneBoundingRect() const
+{
+ // Find translate-only offset
+ // COMBINE
+ QPointF offset;
+ const QGraphicsItem *parentItem = this;
+ const QGraphicsItemPrivate *itemd;
+ do {
+ itemd = parentItem->d_ptr.data();
+ if (itemd->transformData)
+ break;
+ offset += itemd->pos;
+ } while ((parentItem = itemd->parent));
+
+ QRectF br = boundingRect();
+ br.translate(offset);
+ if (!parentItem)
+ return br;
+ if (parentItem->d_ptr->hasTranslateOnlySceneTransform()) {
+ br.translate(parentItem->d_ptr->sceneTransform.dx(), parentItem->d_ptr->sceneTransform.dy());
+ return br;
+ }
+ return parentItem->d_ptr->sceneTransform.mapRect(br);
+}
+
+/*!
+ Returns the shape of this item as a QPainterPath in local
+ coordinates. The shape is used for many things, including collision
+ detection, hit tests, and for the QGraphicsScene::items() functions.
+
+ The default implementation calls boundingRect() to return a simple
+ rectangular shape, but subclasses can reimplement this function to return
+ a more accurate shape for non-rectangular items. For example, a round item
+ may choose to return an elliptic shape for better collision detection. For
+ example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 9
+
+ The outline of a shape can vary depending on the width and style of the
+ pen used when drawing. If you want to include this outline in the item's
+ shape, you can create a shape from the stroke using QPainterPathStroker.
+
+ This function is called by the default implementations of contains() and
+ collidesWithPath().
+
+ \sa boundingRect(), contains(), prepareGeometryChange(), QPainterPathStroker
+*/
+QPainterPath QGraphicsItem::shape() const
+{
+ QPainterPath path;
+ path.addRect(boundingRect());
+ return path;
+}
+
+/*!
+ Returns true if this item is clipped. An item is clipped if it has either
+ set the \l ItemClipsToShape flag, or if it or any of its ancestors has set
+ the \l ItemClipsChildrenToShape flag.
+
+ Clipping affects the item's appearance (i.e., painting), as well as mouse
+ and hover event delivery.
+
+ \sa clipPath(), shape(), setFlags()
+*/
+bool QGraphicsItem::isClipped() const
+{
+ Q_D(const QGraphicsItem);
+ return (d->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
+ || (d->flags & QGraphicsItem::ItemClipsToShape);
+}
+
+/*!
+ \since 4.5
+
+ Returns this item's clip path, or an empty QPainterPath if this item is
+ not clipped. The clip path constrains the item's appearance and
+ interaction (i.e., restricts the area the item can draw, and it also
+ restricts the area that the item receives events).
+
+ You can enable clipping by setting the ItemClipsToShape or
+ ItemClipsChildrenToShape flags. The item's clip path is calculated by
+ intersecting all clipping ancestors' shapes. If the item sets
+ ItemClipsToShape, the final clip is intersected with the item's own shape.
+
+ \note Clipping introduces a performance penalty for all items involved;
+ you should generally avoid using clipping if you can (e.g., if your items
+ always draw inside boundingRect() or shape() boundaries, clipping is not
+ necessary).
+
+ \sa isClipped(), shape(), setFlags()
+*/
+QPainterPath QGraphicsItem::clipPath() const
+{
+ Q_D(const QGraphicsItem);
+ if (!isClipped())
+ return QPainterPath();
+
+ const QRectF thisBoundingRect(boundingRect());
+ if (thisBoundingRect.isEmpty())
+ return QPainterPath();
+
+ QPainterPath clip;
+ // Start with the item's bounding rect.
+ clip.addRect(thisBoundingRect);
+
+ if (d->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) {
+ const QGraphicsItem *parent = this;
+ const QGraphicsItem *lastParent = this;
+
+ // Intersect any in-between clips starting at the top and moving downwards.
+ while ((parent = parent->d_ptr->parent)) {
+ if (parent->d_ptr->flags & ItemClipsChildrenToShape) {
+ // Map clip to the current parent and intersect with its shape/clipPath
+ clip = lastParent->itemTransform(parent).map(clip);
+ clip = clip.intersected(parent->shape());
+ if (clip.isEmpty())
+ return clip;
+ lastParent = parent;
+ }
+
+ if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren))
+ break;
+ }
+
+ if (lastParent != this) {
+ // Map clip back to the item's transform.
+ // ### what if itemtransform fails
+ clip = lastParent->itemTransform(this).map(clip);
+ }
+ }
+
+ if (d->flags & ItemClipsToShape)
+ clip = clip.intersected(shape());
+
+ return clip;
+}
+
+/*!
+ Returns true if this item contains \a point, which is in local
+ coordinates; otherwise, false is returned. It is most often called from
+ QGraphicsView to determine what item is under the cursor, and for that
+ reason, the implementation of this function should be as light-weight as
+ possible.
+
+ By default, this function calls shape(), but you can reimplement it in a
+ subclass to provide a (perhaps more efficient) implementation.
+
+ \sa shape(), boundingRect(), collidesWithPath()
+*/
+bool QGraphicsItem::contains(const QPointF &point) const
+{
+ return isClipped() ? clipPath().contains(point) : shape().contains(point);
+}
+
+/*!
+
+ Returns true if this item collides with \a other; otherwise
+ returns false.
+
+ The \a mode is applied to \a other, and the resulting shape or
+ bounding rectangle is then compared to this item's shape. The
+ default value for \a mode is Qt::IntersectsItemShape; \a other
+ collides with this item if it either intersects, contains, or is
+ contained by this item's shape (see Qt::ItemSelectionMode for
+ details).
+
+ The default implementation is based on shape intersection, and it calls
+ shape() on both items. Because the complexity of arbitrary shape-shape
+ intersection grows with an order of magnitude when the shapes are complex,
+ this operation can be noticably time consuming. You have the option of
+ reimplementing this function in a subclass of QGraphicsItem to provide a
+ custom algorithm. This allows you to make use of natural constraints in
+ the shapes of your own items, in order to improve the performance of the
+ collision detection. For instance, two untransformed perfectly circular
+ items' collision can be determined very efficiently by comparing their
+ positions and radii.
+
+ Keep in mind that when reimplementing this function and calling shape() or
+ boundingRect() on \a other, the returned coordinates must be mapped to
+ this item's coordinate system before any intersection can take place.
+
+ \sa contains(), shape()
+*/
+bool QGraphicsItem::collidesWithItem(const QGraphicsItem *other, Qt::ItemSelectionMode mode) const
+{
+ if (other == this)
+ return true;
+ if (!other)
+ return false;
+ // The items share the same clip if their closest clipper is the same, or
+ // if one clips the other.
+ bool clips = (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren);
+ bool otherClips = (other->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren);
+ if (clips || otherClips) {
+ const QGraphicsItem *closestClipper = isAncestorOf(other) ? this : parentItem();
+ while (closestClipper && !(closestClipper->flags() & ItemClipsChildrenToShape))
+ closestClipper = closestClipper->parentItem();
+ const QGraphicsItem *otherClosestClipper = other->isAncestorOf(this) ? other : other->parentItem();
+ while (otherClosestClipper && !(otherClosestClipper->flags() & ItemClipsChildrenToShape))
+ otherClosestClipper = otherClosestClipper->parentItem();
+ if (closestClipper == otherClosestClipper) {
+ d_ptr->localCollisionHack = 1;
+ bool res = collidesWithPath(mapFromItem(other, other->shape()), mode);
+ d_ptr->localCollisionHack = 0;
+ return res;
+ }
+ }
+
+ QPainterPath otherShape = other->isClipped() ? other->clipPath() : other->shape();
+ return collidesWithPath(mapFromItem(other, otherShape), mode);
+}
+
+/*!
+ Returns true if this item collides with \a path.
+
+ The collision is determined by \a mode. The default value for \a mode is
+ Qt::IntersectsItemShape; \a path collides with this item if it either
+ intersects, contains, or is contained by this item's shape.
+
+ Note that this function checks whether the item's shape or
+ bounding rectangle (depending on \a mode) is contained within \a
+ path, and not whether \a path is contained within the items shape
+ or bounding rectangle.
+
+ \sa collidesWithItem(), contains(), shape()
+*/
+bool QGraphicsItem::collidesWithPath(const QPainterPath &path, Qt::ItemSelectionMode mode) const
+{
+ if (path.isEmpty()) {
+ // No collision with empty paths.
+ return false;
+ }
+
+ QRectF rectA(boundingRect());
+ _q_adjustRect(&rectA);
+ QRectF rectB(path.controlPointRect());
+ _q_adjustRect(&rectB);
+ if (!rectA.intersects(rectB)) {
+ // This we can determine efficiently. If the two rects neither
+ // intersect nor contain eachother, then the two items do not collide.
+ return false;
+ }
+
+ // For further testing, we need this item's shape or bounding rect.
+ QPainterPath thisShape;
+ if (mode == Qt::IntersectsItemShape || mode == Qt::ContainsItemShape)
+ thisShape = (isClipped() && !d_ptr->localCollisionHack) ? clipPath() : shape();
+ else
+ thisShape.addRect(rectA);
+
+ if (thisShape == QPainterPath()) {
+ // Empty shape? No collision.
+ return false;
+ }
+
+ // Use QPainterPath boolean operations to determine the collision, O(N*logN).
+ if (mode == Qt::IntersectsItemShape || mode == Qt::IntersectsItemBoundingRect)
+ return path.intersects(thisShape);
+ return path.contains(thisShape);
+}
+
+/*!
+ Returns a list of all items that collide with this item.
+
+ The way collisions are detected is determined by applying \a mode
+ to items that are compared to this item, i.e., each item's shape
+ or bounding rectangle is checked against this item's shape. The
+ default value for \a mode is Qt::IntersectsItemShape.
+
+ \sa collidesWithItem()
+*/
+QList<QGraphicsItem *> QGraphicsItem::collidingItems(Qt::ItemSelectionMode mode) const
+{
+ if (d_ptr->scene)
+ return d_ptr->scene->collidingItems(this, mode);
+ return QList<QGraphicsItem *>();
+}
+
+/*!
+ Returns true if this item's bounding rect is completely obscured by the
+ opaque shape of any of colliding items above it (i.e., with a higher Z
+ value than this item).
+
+ Its implementation is based on calling isObscuredBy(), which you can
+ reimplement to provide a custom obscurity algorithm.
+
+ \sa opaqueArea()
+*/
+bool QGraphicsItem::isObscured() const
+{
+ return isObscured(QRectF());
+}
+
+/*!
+ \internal
+
+ Item obscurity helper function.
+
+ Returns true if the subrect \a rect of \a item's bounding rect is obscured
+ by \a other (i.e., \a other's opaque area covers \a item's \a rect
+ completely. \a other is assumed to already be "on top of" \a item
+ wrt. stacking order.
+*/
+static bool qt_QGraphicsItem_isObscured(const QGraphicsItem *item,
+ const QGraphicsItem *other,
+ const QRectF &rect)
+{
+ return other->mapToItem(item, other->opaqueArea()).contains(rect);
+}
+
+/*!
+ \overload
+ \since 4.3
+
+ Returns true if \a rect is completely obscured by the opaque shape of any
+ of colliding items above it (i.e., with a higher Z value than this item).
+
+ Unlike the default isObscured() function, this function does not call
+ isObscuredBy().
+
+ \sa opaqueArea()
+*/
+bool QGraphicsItem::isObscured(const QRectF &rect) const
+{
+ Q_D(const QGraphicsItem);
+ if (!d->scene)
+ return false;
+
+ QRectF br = boundingRect();
+ QRectF testRect = rect.isNull() ? br : rect;
+
+ foreach (QGraphicsItem *item, d->scene->items(mapToScene(br), Qt::IntersectsItemBoundingRect)) {
+ if (item == this)
+ break;
+ if (qt_QGraphicsItem_isObscured(this, item, testRect))
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \fn bool QGraphicsItem::isObscured(qreal x, qreal y, qreal w, qreal h) const
+ \since 4.3
+
+ This convenience function is equivalent to calling isObscured(QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ Returns true if this item's bounding rect is completely obscured by the
+ opaque shape of \a item.
+
+ The base implementation maps \a item's opaqueArea() to this item's
+ coordinate system, and then checks if this item's boundingRect() is fully
+ contained within the mapped shape.
+
+ You can reimplement this function to provide a custom algorithm for
+ determining whether this item is obscured by \a item.
+
+ \sa opaqueArea(), isObscured()
+*/
+bool QGraphicsItem::isObscuredBy(const QGraphicsItem *item) const
+{
+ if (!item)
+ return false;
+ return qt_closestItemFirst(item, this)
+ && qt_QGraphicsItem_isObscured(this, item, boundingRect());
+}
+
+/*!
+ This virtual function returns a shape representing the area where this
+ item is opaque. An area is opaque if it is filled using an opaque brush or
+ color (i.e., not transparent).
+
+ This function is used by isObscuredBy(), which is called by underlying
+ items to determine if they are obscured by this item.
+
+ The default implementation returns an empty QPainterPath, indicating that
+ this item is completely transparent and does not obscure any other items.
+
+ \sa isObscuredBy(), isObscured(), shape()
+*/
+QPainterPath QGraphicsItem::opaqueArea() const
+{
+ return QPainterPath();
+}
+
+/*!
+ \since 4.4
+
+ Returns the bounding region for this item. The coordinate space of the
+ returned region depends on \a itemToDeviceTransform. If you pass an
+ identity QTransform as a parameter, this function will return a local
+ coordinate region.
+
+ The bounding region describes a coarse outline of the item's visual
+ contents. Although it's expensive to calculate, it's also more precise
+ than boundingRect(), and it can help to avoid unnecessary repainting when
+ an item is updated. This is particularly efficient for thin items (e.g.,
+ lines or simple polygons). You can tune the granularity for the bounding
+ region by calling setBoundingRegionGranularity(). The default granularity
+ is 0; in which the item's bounding region is the same as its bounding
+ rect.
+
+ \a itemToDeviceTransform is the transformation from item coordinates to
+ device coordinates. If you want this function to return a QRegion in scene
+ coordinates, you can pass sceneTransform() as an argument.
+
+ \sa boundingRegionGranularity()
+*/
+QRegion QGraphicsItem::boundingRegion(const QTransform &itemToDeviceTransform) const
+{
+ // ### Ideally we would have a better way to generate this region,
+ // preferably something in the lines of QPainterPath::toRegion(QTransform)
+ // coupled with a way to generate a painter path from a set of painter
+ // operations (e.g., QPicture::toPainterPath() or so). The current
+ // approach generates a bitmap with the size of the item's bounding rect
+ // in device coordinates, scaled by b.r.granularity, then paints the item
+ // into the bitmap, converts the result to a QRegion and scales the region
+ // back to device space with inverse granularity.
+ qreal granularity = boundingRegionGranularity();
+ QRect deviceRect = itemToDeviceTransform.mapRect(boundingRect()).toRect();
+ _q_adjustRect(&deviceRect);
+ if (granularity == 0.0)
+ return QRegion(deviceRect);
+
+ int pad = 1;
+ QSize bitmapSize(qMax(1, int(deviceRect.width() * granularity) + pad * 2),
+ qMax(1, int(deviceRect.height() * granularity) + pad * 2));
+ QImage mask(bitmapSize, QImage::Format_ARGB32_Premultiplied);
+ mask.fill(0);
+ QPainter p(&mask);
+ p.setRenderHints(QPainter::Antialiasing);
+
+ // Transform painter (### this code is from QGraphicsScene::drawItemHelper
+ // and doesn't work properly with perspective transformations).
+ QPointF viewOrigo = itemToDeviceTransform.map(QPointF(0, 0));
+ QPointF offset = viewOrigo - deviceRect.topLeft();
+ p.scale(granularity, granularity);
+ p.translate(offset);
+ p.translate(pad, pad);
+ p.setWorldTransform(itemToDeviceTransform, true);
+ p.translate(itemToDeviceTransform.inverted().map(QPointF(0, 0)));
+
+ // Render
+ QStyleOptionGraphicsItem option;
+ const_cast<QGraphicsItem *>(this)->paint(&p, &option, 0);
+ p.end();
+
+ // Transform QRegion back to device space
+ QTransform unscale = QTransform::fromScale(1 / granularity, 1 / granularity);
+ QRegion r;
+ QBitmap colorMask = QBitmap::fromImage(mask.createMaskFromColor(0));
+ foreach (const QRect &rect, QRegion( colorMask ).rects()) {
+ QRect xrect = unscale.mapRect(rect).translated(deviceRect.topLeft() - QPoint(pad, pad));
+ r += xrect.adjusted(-1, -1, 1, 1) & deviceRect;
+ }
+ return r;
+}
+
+/*!
+ \since 4.4
+
+ Returns the item's bounding region granularity; a value between and
+ including 0 and 1. The default value is 0 (i.e., the lowest granularity,
+ where the bounding region corresponds to the item's bounding rectangle).
+
+\omit
+### NOTE
+\endomit
+
+ \sa setBoundingRegionGranularity()
+*/
+qreal QGraphicsItem::boundingRegionGranularity() const
+{
+ return d_ptr->hasBoundingRegionGranularity
+ ? qvariant_cast<qreal>(d_ptr->extra(QGraphicsItemPrivate::ExtraBoundingRegionGranularity))
+ : 0;
+}
+
+/*!
+ \since 4.4
+ Sets the bounding region granularity to \a granularity; a value between
+ and including 0 and 1. The default value is 0 (i.e., the lowest
+ granularity, where the bounding region corresponds to the item's bounding
+ rectangle).
+
+ The granularity is used by boundingRegion() to calculate how fine the
+ bounding region of the item should be. The highest achievable granularity
+ is 1, where boundingRegion() will return the finest outline possible for
+ the respective device (e.g., for a QGraphicsView viewport, this gives you
+ a pixel-perfect bounding region). The lowest possible granularity is
+ 0. The value of \a granularity describes the ratio between device
+ resolution and the resolution of the bounding region (e.g., a value of
+ 0.25 will provide a region where each chunk corresponds to 4x4 device
+ units / pixels).
+
+ \sa boundingRegionGranularity()
+*/
+void QGraphicsItem::setBoundingRegionGranularity(qreal granularity)
+{
+ if (granularity < 0.0 || granularity > 1.0) {
+ qWarning("QGraphicsItem::setBoundingRegionGranularity: invalid granularity %g", granularity);
+ return;
+ }
+ if (granularity == 0.0) {
+ d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraBoundingRegionGranularity);
+ d_ptr->hasBoundingRegionGranularity = 0;
+ return;
+ }
+ d_ptr->hasBoundingRegionGranularity = 1;
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraBoundingRegionGranularity,
+ QVariant::fromValue<qreal>(granularity));
+}
+
+/*!
+ \fn virtual void QGraphicsItem::paint(QPainter *painter, const
+ QStyleOptionGraphicsItem *option, QWidget *widget = 0) = 0
+
+ This function, which is usually called by QGraphicsView, paints the
+ contents of an item in local coordinates.
+
+ Reimplement this function in a QGraphicsItem subclass to provide the
+ item's painting implementation, using \a painter. The \a option parameter
+ provides style options for the item, such as its state, exposed area and
+ its level-of-detail hints. The \a widget argument is optional. If
+ provided, it points to the widget that is being painted on; otherwise, it
+ is 0. For cached painting, \a widget is always 0.
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 10
+
+ The painter's pen is 0-width by default, and its pen is initialized to the
+ QPalette::Text brush from the paint device's palette. The brush is
+ initialized to QPalette::Window.
+
+ Make sure to constrain all painting inside the boundaries of
+ boundingRect() to avoid rendering artifacts (as QGraphicsView does not
+ clip the painter for you). In particular, when QPainter renders the
+ outline of a shape using an assigned QPen, half of the outline will be
+ drawn outside, and half inside, the shape you're rendering (e.g., with a
+ pen width of 2 units, you must draw outlines 1 unit inside
+ boundingRect()). QGraphicsItem does not support use of cosmetic pens with
+ a non-zero width.
+
+ All painting is done in local coordinates.
+
+ \sa setCacheMode(), QPen::width(), {Item Coordinates}, ItemUsesExtendedStyleOption
+*/
+
+/*!
+ \internal
+ Returns true if we can discard an update request; otherwise false.
+*/
+bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreVisibleBit, bool ignoreDirtyBit,
+ bool ignoreOpacity) const
+{
+ // No scene, or if the scene is updating everything, means we have nothing
+ // to do. The only exception is if the scene tracks the growing scene rect.
+ return !scene
+ || (!visible && !ignoreVisibleBit && !this->ignoreVisible)
+ || (!ignoreDirtyBit && fullUpdatePending)
+ || (!ignoreOpacity && !this->ignoreOpacity && childrenCombineOpacity() && isFullyTransparent());
+}
+
+/*!
+ \internal
+*/
+int QGraphicsItemPrivate::depth() const
+{
+ if (itemDepth == -1)
+ const_cast<QGraphicsItemPrivate *>(this)->resolveDepth();
+
+ return itemDepth;
+}
+
+/*!
+ \internal
+*/
+#ifndef QT_NO_GRAPHICSEFFECT
+void QGraphicsItemPrivate::invalidateParentGraphicsEffectsRecursively()
+{
+ QGraphicsItemPrivate *itemPrivate = this;
+ do {
+ if (itemPrivate->graphicsEffect) {
+ itemPrivate->notifyInvalidated = 1;
+
+ if (!itemPrivate->updateDueToGraphicsEffect)
+ static_cast<QGraphicsItemEffectSourcePrivate *>(itemPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache();
+ }
+ } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : 0));
+}
+
+void QGraphicsItemPrivate::invalidateChildGraphicsEffectsRecursively(QGraphicsItemPrivate::InvalidateReason reason)
+{
+ if (!mayHaveChildWithGraphicsEffect)
+ return;
+
+ for (int i = 0; i < children.size(); ++i) {
+ QGraphicsItemPrivate *childPrivate = children.at(i)->d_ptr.data();
+ if (reason == OpacityChanged && (childPrivate->flags & QGraphicsItem::ItemIgnoresParentOpacity))
+ continue;
+ if (childPrivate->graphicsEffect) {
+ childPrivate->notifyInvalidated = 1;
+ static_cast<QGraphicsItemEffectSourcePrivate *>(childPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache();
+ }
+
+ childPrivate->invalidateChildGraphicsEffectsRecursively(reason);
+ }
+}
+#endif //QT_NO_GRAPHICSEFFECT
+
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::invalidateDepthRecursively()
+{
+ if (itemDepth == -1)
+ return;
+
+ itemDepth = -1;
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->invalidateDepthRecursively();
+}
+
+/*!
+ \internal
+
+ Resolves the stacking depth of this object and all its ancestors.
+*/
+void QGraphicsItemPrivate::resolveDepth()
+{
+ if (!parent)
+ itemDepth = 0;
+ else {
+ if (parent->d_ptr->itemDepth == -1)
+ parent->d_ptr->resolveDepth();
+ itemDepth = parent->d_ptr->itemDepth + 1;
+ }
+}
+
+/*!
+ \internal
+
+ ### This function is almost identical to
+ QGraphicsScenePrivate::registerTopLevelItem().
+*/
+void QGraphicsItemPrivate::addChild(QGraphicsItem *child)
+{
+ // Remove all holes from the sibling index list. Now the max index
+ // number is equal to the size of the children list.
+ ensureSequentialSiblingIndex();
+ needSortChildren = 1; // ### maybe 0
+ child->d_ptr->siblingIndex = children.size();
+ children.append(child);
+ if (isObject)
+ emit static_cast<QGraphicsObject *>(q_ptr)->childrenChanged();
+}
+
+/*!
+ \internal
+
+ ### This function is almost identical to
+ QGraphicsScenePrivate::unregisterTopLevelItem().
+*/
+void QGraphicsItemPrivate::removeChild(QGraphicsItem *child)
+{
+ // When removing elements in the middle of the children list,
+ // there will be a "gap" in the list of sibling indexes (0,1,3,4).
+ if (!holesInSiblingIndex)
+ holesInSiblingIndex = child->d_ptr->siblingIndex != children.size() - 1;
+ if (sequentialOrdering && !holesInSiblingIndex)
+ children.removeAt(child->d_ptr->siblingIndex);
+ else
+ children.removeOne(child);
+ // NB! Do not use children.removeAt(child->d_ptr->siblingIndex) because
+ // the child is not guaranteed to be at the index after the list is sorted.
+ // (see ensureSortedChildren()).
+ child->d_ptr->siblingIndex = -1;
+ if (isObject)
+ emit static_cast<QGraphicsObject *>(q_ptr)->childrenChanged();
+}
+
+/*!
+ \internal
+*/
+QGraphicsItemCache *QGraphicsItemPrivate::maybeExtraItemCache() const
+{
+ return (QGraphicsItemCache *)qvariant_cast<void *>(extra(ExtraCacheData));
+}
+
+/*!
+ \internal
+*/
+QGraphicsItemCache *QGraphicsItemPrivate::extraItemCache() const
+{
+ QGraphicsItemCache *c = (QGraphicsItemCache *)qvariant_cast<void *>(extra(ExtraCacheData));
+ if (!c) {
+ QGraphicsItemPrivate *that = const_cast<QGraphicsItemPrivate *>(this);
+ c = new QGraphicsItemCache;
+ that->setExtra(ExtraCacheData, QVariant::fromValue<void *>(c));
+ }
+ return c;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::removeExtraItemCache()
+{
+ QGraphicsItemCache *c = (QGraphicsItemCache *)qvariant_cast<void *>(extra(ExtraCacheData));
+ if (c) {
+ c->purge();
+ delete c;
+ }
+ unsetExtra(ExtraCacheData);
+}
+
+void QGraphicsItemPrivate::updatePaintedViewBoundingRects(bool updateChildren)
+{
+ if (!scene)
+ return;
+
+ for (int i = 0; i < scene->d_func()->views.size(); ++i) {
+ QGraphicsViewPrivate *viewPrivate = scene->d_func()->views.at(i)->d_func();
+ QRect rect = paintedViewBoundingRects.value(viewPrivate->viewport);
+ rect.translate(viewPrivate->dirtyScrollOffset);
+ viewPrivate->updateRect(rect);
+ }
+
+ if (updateChildren) {
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->updatePaintedViewBoundingRects(true);
+ }
+}
+
+// Traverses all the ancestors up to the top-level and updates the pointer to
+// always point to the top-most item that has a dirty scene transform.
+// It then backtracks to the top-most dirty item and start calculating the
+// scene transform by combining the item's transform (+pos) with the parent's
+// cached scene transform (which we at this point know for sure is valid).
+void QGraphicsItemPrivate::ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem)
+{
+ Q_ASSERT(topMostDirtyItem);
+
+ if (dirtySceneTransform)
+ *topMostDirtyItem = q_ptr;
+
+ if (parent)
+ parent->d_ptr->ensureSceneTransformRecursive(topMostDirtyItem);
+
+ if (*topMostDirtyItem == q_ptr) {
+ if (!dirtySceneTransform)
+ return; // OK, neither my ancestors nor I have dirty scene transforms.
+ *topMostDirtyItem = 0;
+ } else if (*topMostDirtyItem) {
+ return; // Continue backtrack.
+ }
+
+ // This item and all its descendants have dirty scene transforms.
+ // We're about to validate this item's scene transform, so we have to
+ // invalidate all the children; otherwise there's no way for the descendants
+ // to detect that the ancestor has changed.
+ invalidateChildrenSceneTransform();
+
+ // COMBINE my transform with the parent's scene transform.
+ updateSceneTransformFromParent();
+ Q_ASSERT(!dirtySceneTransform);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::setSubFocus(QGraphicsItem *rootItem, QGraphicsItem *stopItem)
+{
+ // Update focus child chain. Stop at panels, or if this item
+ // is hidden, stop at the first item with a visible parent.
+ QGraphicsItem *parent = rootItem ? rootItem : q_ptr;
+ if (parent->panel() != q_ptr->panel())
+ return;
+
+ do {
+ // Clear any existing ancestor's subFocusItem.
+ if (parent != q_ptr && parent->d_ptr->subFocusItem) {
+ if (parent->d_ptr->subFocusItem == q_ptr)
+ break;
+ parent->d_ptr->subFocusItem->d_ptr->clearSubFocus(0, stopItem);
+ }
+ parent->d_ptr->subFocusItem = q_ptr;
+ parent->d_ptr->subFocusItemChange();
+ } while (!parent->isPanel() && (parent = parent->d_ptr->parent) && (visible || !parent->d_ptr->visible));
+
+ if (scene && !scene->isActive()) {
+ scene->d_func()->passiveFocusItem = subFocusItem;
+ scene->d_func()->lastFocusItem = subFocusItem;
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::clearSubFocus(QGraphicsItem *rootItem, QGraphicsItem *stopItem)
+{
+ // Reset sub focus chain.
+ QGraphicsItem *parent = rootItem ? rootItem : q_ptr;
+ do {
+ if (parent->d_ptr->subFocusItem != q_ptr)
+ break;
+ parent->d_ptr->subFocusItem = 0;
+ if (parent != stopItem && !parent->isAncestorOf(stopItem))
+ parent->d_ptr->subFocusItemChange();
+ } while (!parent->isPanel() && (parent = parent->d_ptr->parent));
+}
+
+/*!
+ \internal
+
+ Sets the focusProxy pointer to 0 for all items that have this item as their
+ focusProxy. ### Qt 5: Use QPointer instead.
+*/
+void QGraphicsItemPrivate::resetFocusProxy()
+{
+ for (int i = 0; i < focusProxyRefs.size(); ++i)
+ *focusProxyRefs.at(i) = 0;
+ focusProxyRefs.clear();
+}
+
+/*!
+ \internal
+
+ Subclasses can reimplement this function to be notified when subFocusItem
+ changes.
+*/
+void QGraphicsItemPrivate::subFocusItemChange()
+{
+}
+
+/*!
+ \internal
+
+ Subclasses can reimplement this function to be notified when an item
+ becomes a focusScopeItem (or is no longer a focusScopeItem).
+*/
+void QGraphicsItemPrivate::focusScopeItemChange(bool isSubFocusItem)
+{
+ Q_UNUSED(isSubFocusItem);
+}
+
+/*!
+ \internal
+
+ Subclasses can reimplement this function to be notified when its
+ siblingIndex order is changed.
+*/
+void QGraphicsItemPrivate::siblingOrderChange()
+{
+}
+
+/*!
+ \internal
+
+ Tells us if it is a proxy widget
+*/
+bool QGraphicsItemPrivate::isProxyWidget() const
+{
+ return false;
+}
+
+/*!
+ Schedules a redraw of the area covered by \a rect in this item. You can
+ call this function whenever your item needs to be redrawn, such as if it
+ changes appearance or size.
+
+ This function does not cause an immediate paint; instead it schedules a
+ paint request that is processed by QGraphicsView after control reaches the
+ event loop. The item will only be redrawn if it is visible in any
+ associated view.
+
+ As a side effect of the item being repainted, other items that overlap the
+ area \a rect may also be repainted.
+
+ If the item is invisible (i.e., isVisible() returns false), this function
+ does nothing.
+
+ \sa paint(), boundingRect()
+*/
+void QGraphicsItem::update(const QRectF &rect)
+{
+ if (rect.isEmpty() && !rect.isNull())
+ return;
+
+ // Make sure we notify effects about invalidated source.
+#ifndef QT_NO_GRAPHICSEFFECT
+ d_ptr->invalidateParentGraphicsEffectsRecursively();
+#endif //QT_NO_GRAPHICSEFFECT
+
+ if (CacheMode(d_ptr->cacheMode) != NoCache) {
+ // Invalidate cache.
+ QGraphicsItemCache *cache = d_ptr->extraItemCache();
+ if (!cache->allExposed) {
+ if (rect.isNull()) {
+ cache->allExposed = true;
+ cache->exposed.clear();
+ } else {
+ cache->exposed.append(rect);
+ }
+ }
+ // Only invalidate cache; item is already dirty.
+ if (d_ptr->fullUpdatePending)
+ return;
+ }
+
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->markDirty(this, rect);
+}
+
+/*!
+ \since 4.4
+ Scrolls the contents of \a rect by \a dx, \a dy. If \a rect is a null rect
+ (the default), the item's bounding rect is scrolled.
+
+ Scrolling provides a fast alternative to simply redrawing when the
+ contents of the item (or parts of the item) are shifted vertically or
+ horizontally. Depending on the current transformation and the capabilities
+ of the paint device (i.e., the viewport), this operation may consist of
+ simply moving pixels from one location to another using memmove(). In most
+ cases this is faster than rerendering the entire area.
+
+ After scrolling, the item will issue an update for the newly exposed
+ areas. If scrolling is not supported (e.g., you are rendering to an OpenGL
+ viewport, which does not benefit from scroll optimizations), this function
+ is equivalent to calling update(\a rect).
+
+ \bold{Note:} Scrolling is only supported when QGraphicsItem::ItemCoordinateCache
+ is enabled; in all other cases calling this function is equivalent to calling
+ update(\a rect). If you for sure know that the item is opaque and not overlapped
+ by other items, you can map the \a rect to viewport coordinates and scroll the
+ viewport.
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 19
+
+ \sa boundingRect()
+*/
+void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect)
+{
+ Q_D(QGraphicsItem);
+ if (dx == 0.0 && dy == 0.0)
+ return;
+ if (!d->scene)
+ return;
+
+ // Accelerated scrolling means moving pixels from one location to another
+ // and only redraw the newly exposed area. The following requirements must
+ // be fulfilled in order to do that:
+ //
+ // 1) Item is opaque.
+ // 2) Item is not overlapped by other items.
+ //
+ // There's (yet) no way to detect whether an item is opaque or not, which means
+ // we cannot do accelerated scrolling unless the cache is enabled. In case of using
+ // DeviceCoordinate cache we also have to take the device transform into account in
+ // order to determine whether we can do accelerated scrolling or not. That's left out
+ // for simplicity here, but it is definitely something we can consider in the future
+ // as a performance improvement.
+ if (d->cacheMode != QGraphicsItem::ItemCoordinateCache
+ || !qFuzzyIsNull(dx - int(dx)) || !qFuzzyIsNull(dy - int(dy))) {
+ update(rect);
+ return;
+ }
+
+ QGraphicsItemCache *cache = d->extraItemCache();
+ if (cache->allExposed || cache->fixedSize.isValid()) {
+ // Cache is either invalidated or item is scaled (see QGraphicsItem::setCacheMode).
+ update(rect);
+ return;
+ }
+
+ // Find pixmap in cache.
+ QPixmap cachedPixmap;
+ if (!QPixmapCache::find(cache->key, &cachedPixmap)) {
+ update(rect);
+ return;
+ }
+
+ QRect scrollRect = (rect.isNull() ? boundingRect() : rect).toAlignedRect();
+ if (!scrollRect.intersects(cache->boundingRect))
+ return; // Nothing to scroll.
+
+ // Remove from cache to avoid deep copy when modifying.
+ QPixmapCache::remove(cache->key);
+
+ QRegion exposed;
+ cachedPixmap.scroll(dx, dy, scrollRect.translated(-cache->boundingRect.topLeft()), &exposed);
+
+ // Reinsert into cache.
+ cache->key = QPixmapCache::insert(cachedPixmap);
+
+ // Translate the existing expose.
+ for (int i = 0; i < cache->exposed.size(); ++i) {
+ QRectF &e = cache->exposed[i];
+ if (!rect.isNull() && !e.intersects(rect))
+ continue;
+ e.translate(dx, dy);
+ }
+
+ // Append newly exposed areas. Note that the exposed region is currently
+ // in pixmap coordinates, so we have to translate it to item coordinates.
+ exposed.translate(cache->boundingRect.topLeft());
+ const QVector<QRect> exposedRects = exposed.rects();
+ for (int i = 0; i < exposedRects.size(); ++i)
+ cache->exposed += exposedRects.at(i);
+
+ // Trigger update. This will redraw the newly exposed area and make sure
+ // the pixmap is re-blitted in case there are overlapping items.
+ d->scene->d_func()->markDirty(this, rect);
+}
+
+/*!
+ \fn void QGraphicsItem::update(qreal x, qreal y, qreal width, qreal height)
+ \overload
+
+ This convenience function is equivalent to calling update(QRectF(\a x, \a
+ y, \a width, \a height)).
+*/
+
+/*!
+ Maps the point \a point, which is in this item's coordinate system, to \a
+ item's coordinate system, and returns the mapped coordinate.
+
+ If \a item is 0, this function returns the same as mapToScene().
+
+ \sa itemTransform(), mapToParent(), mapToScene(), transform(), mapFromItem(), {The Graphics
+ View Coordinate System}
+*/
+QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPointF &point) const
+{
+ if (item)
+ return itemTransform(item).map(point);
+ return mapToScene(point);
+}
+
+/*!
+ \fn QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, qreal x, qreal y) const
+ \overload
+
+ This convenience function is equivalent to calling mapToItem(\a item,
+ QPointF(\a x, \a y)).
+*/
+
+/*!
+ Maps the point \a point, which is in this item's coordinate system, to its
+ parent's coordinate system, and returns the mapped coordinate. If the item
+ has no parent, \a point will be mapped to the scene's coordinate system.
+
+ \sa mapToItem(), mapToScene(), transform(), mapFromParent(), {The Graphics
+ View Coordinate System}
+*/
+QPointF QGraphicsItem::mapToParent(const QPointF &point) const
+{
+ // COMBINE
+ if (!d_ptr->transformData)
+ return point + d_ptr->pos;
+ return d_ptr->transformToParent().map(point);
+}
+
+/*!
+ \fn QPointF QGraphicsItem::mapToParent(qreal x, qreal y) const
+ \overload
+
+ This convenience function is equivalent to calling mapToParent(QPointF(\a
+ x, \a y)).
+*/
+
+/*!
+ Maps the point \a point, which is in this item's coordinate system, to the
+ scene's coordinate system, and returns the mapped coordinate.
+
+ \sa mapToItem(), mapToParent(), transform(), mapFromScene(), {The Graphics
+ View Coordinate System}
+*/
+QPointF QGraphicsItem::mapToScene(const QPointF &point) const
+{
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return QPointF(point.x() + d_ptr->sceneTransform.dx(), point.y() + d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.map(point);
+}
+
+/*!
+ \fn QPointF QGraphicsItem::mapToScene(qreal x, qreal y) const
+ \overload
+
+ This convenience function is equivalent to calling mapToScene(QPointF(\a
+ x, \a y)).
+*/
+
+/*!
+ Maps the rectangle \a rect, which is in this item's coordinate system, to
+ \a item's coordinate system, and returns the mapped rectangle as a polygon.
+
+ If \a item is 0, this function returns the same as mapToScene().
+
+ \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
+ Graphics View Coordinate System}
+*/
+QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QRectF &rect) const
+{
+ if (item)
+ return itemTransform(item).map(rect);
+ return mapToScene(rect);
+}
+
+/*!
+ \fn QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
+ \since 4.3
+
+ This convenience function is equivalent to calling mapToItem(item, QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ Maps the rectangle \a rect, which is in this item's coordinate system, to
+ its parent's coordinate system, and returns the mapped rectangle as a
+ polygon. If the item has no parent, \a rect will be mapped to the scene's
+ coordinate system.
+
+ \sa mapToScene(), mapToItem(), mapFromParent(), {The Graphics View
+ Coordinate System}
+*/
+QPolygonF QGraphicsItem::mapToParent(const QRectF &rect) const
+{
+ // COMBINE
+ if (!d_ptr->transformData)
+ return rect.translated(d_ptr->pos);
+ return d_ptr->transformToParent().map(rect);
+}
+
+/*!
+ \fn QPolygonF QGraphicsItem::mapToParent(qreal x, qreal y, qreal w, qreal h) const
+ \since 4.3
+
+ This convenience function is equivalent to calling mapToParent(QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ Maps the rectangle \a rect, which is in this item's coordinate system, to
+ the scene's coordinate system, and returns the mapped rectangle as a polygon.
+
+ \sa mapToParent(), mapToItem(), mapFromScene(), {The Graphics View
+ Coordinate System}
+*/
+QPolygonF QGraphicsItem::mapToScene(const QRectF &rect) const
+{
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return rect.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.map(rect);
+}
+
+/*!
+ \fn QPolygonF QGraphicsItem::mapToScene(qreal x, qreal y, qreal w, qreal h) const
+ \since 4.3
+
+ This convenience function is equivalent to calling mapToScene(QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ \since 4.5
+
+ Maps the rectangle \a rect, which is in this item's coordinate system, to
+ \a item's coordinate system, and returns the mapped rectangle as a new
+ rectangle (i.e., the bounding rectangle of the resulting polygon).
+
+ If \a item is 0, this function returns the same as mapRectToScene().
+
+ \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
+ Graphics View Coordinate System}
+*/
+QRectF QGraphicsItem::mapRectToItem(const QGraphicsItem *item, const QRectF &rect) const
+{
+ if (item)
+ return itemTransform(item).mapRect(rect);
+ return mapRectToScene(rect);
+}
+
+/*!
+ \fn QRectF QGraphicsItem::mapRectToItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
+ \since 4.5
+
+ This convenience function is equivalent to calling mapRectToItem(item, QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ \since 4.5
+
+ Maps the rectangle \a rect, which is in this item's coordinate system, to
+ its parent's coordinate system, and returns the mapped rectangle as a new
+ rectangle (i.e., the bounding rectangle of the resulting polygon).
+
+ \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
+ Graphics View Coordinate System}
+*/
+QRectF QGraphicsItem::mapRectToParent(const QRectF &rect) const
+{
+ // COMBINE
+ if (!d_ptr->transformData)
+ return rect.translated(d_ptr->pos);
+ return d_ptr->transformToParent().mapRect(rect);
+}
+
+/*!
+ \fn QRectF QGraphicsItem::mapRectToParent(qreal x, qreal y, qreal w, qreal h) const
+ \since 4.5
+
+ This convenience function is equivalent to calling mapRectToParent(QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ \since 4.5
+
+ Maps the rectangle \a rect, which is in this item's coordinate system, to
+ the scene coordinate system, and returns the mapped rectangle as a new
+ rectangle (i.e., the bounding rectangle of the resulting polygon).
+
+ \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
+ Graphics View Coordinate System}
+*/
+QRectF QGraphicsItem::mapRectToScene(const QRectF &rect) const
+{
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return rect.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.mapRect(rect);
+}
+
+/*!
+ \fn QRectF QGraphicsItem::mapRectToScene(qreal x, qreal y, qreal w, qreal h) const
+ \since 4.5
+
+ This convenience function is equivalent to calling mapRectToScene(QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ \since 4.5
+
+ Maps the rectangle \a rect, which is in \a item's coordinate system, to
+ this item's coordinate system, and returns the mapped rectangle as a new
+ rectangle (i.e., the bounding rectangle of the resulting polygon).
+
+ If \a item is 0, this function returns the same as mapRectFromScene().
+
+ \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
+ Graphics View Coordinate System}
+*/
+QRectF QGraphicsItem::mapRectFromItem(const QGraphicsItem *item, const QRectF &rect) const
+{
+ if (item)
+ return item->itemTransform(this).mapRect(rect);
+ return mapRectFromScene(rect);
+}
+
+/*!
+ \fn QRectF QGraphicsItem::mapRectFromItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
+ \since 4.5
+
+ This convenience function is equivalent to calling mapRectFromItem(item, QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ \since 4.5
+
+ Maps the rectangle \a rect, which is in this item's parent's coordinate
+ system, to this item's coordinate system, and returns the mapped rectangle
+ as a new rectangle (i.e., the bounding rectangle of the resulting
+ polygon).
+
+ \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
+ Graphics View Coordinate System}
+*/
+QRectF QGraphicsItem::mapRectFromParent(const QRectF &rect) const
+{
+ // COMBINE
+ if (!d_ptr->transformData)
+ return rect.translated(-d_ptr->pos);
+ return d_ptr->transformToParent().inverted().mapRect(rect);
+}
+
+/*!
+ \fn QRectF QGraphicsItem::mapRectFromParent(qreal x, qreal y, qreal w, qreal h) const
+ \since 4.5
+
+ This convenience function is equivalent to calling mapRectFromParent(QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ \since 4.5
+
+ Maps the rectangle \a rect, which is in scene coordinates, to this item's
+ coordinate system, and returns the mapped rectangle as a new rectangle
+ (i.e., the bounding rectangle of the resulting polygon).
+
+ \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
+ Graphics View Coordinate System}
+*/
+QRectF QGraphicsItem::mapRectFromScene(const QRectF &rect) const
+{
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return rect.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.inverted().mapRect(rect);
+}
+
+/*!
+ \fn QRectF QGraphicsItem::mapRectFromScene(qreal x, qreal y, qreal w, qreal h) const
+ \since 4.5
+
+ This convenience function is equivalent to calling mapRectFromScene(QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ Maps the polygon \a polygon, which is in this item's coordinate system, to
+ \a item's coordinate system, and returns the mapped polygon.
+
+ If \a item is 0, this function returns the same as mapToScene().
+
+ \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
+ Graphics View Coordinate System}
+*/
+QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPolygonF &polygon) const
+{
+ if (item)
+ return itemTransform(item).map(polygon);
+ return mapToScene(polygon);
+}
+
+/*!
+ Maps the polygon \a polygon, which is in this item's coordinate system, to
+ its parent's coordinate system, and returns the mapped polygon. If the
+ item has no parent, \a polygon will be mapped to the scene's coordinate
+ system.
+
+ \sa mapToScene(), mapToItem(), mapFromParent(), {The Graphics View
+ Coordinate System}
+*/
+QPolygonF QGraphicsItem::mapToParent(const QPolygonF &polygon) const
+{
+ // COMBINE
+ if (!d_ptr->transformData)
+ return polygon.translated(d_ptr->pos);
+ return d_ptr->transformToParent().map(polygon);
+}
+
+/*!
+ Maps the polygon \a polygon, which is in this item's coordinate system, to
+ the scene's coordinate system, and returns the mapped polygon.
+
+ \sa mapToParent(), mapToItem(), mapFromScene(), {The Graphics View
+ Coordinate System}
+*/
+QPolygonF QGraphicsItem::mapToScene(const QPolygonF &polygon) const
+{
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return polygon.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.map(polygon);
+}
+
+/*!
+ Maps the path \a path, which is in this item's coordinate system, to
+ \a item's coordinate system, and returns the mapped path.
+
+ If \a item is 0, this function returns the same as mapToScene().
+
+ \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
+ Graphics View Coordinate System}
+*/
+QPainterPath QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPainterPath &path) const
+{
+ if (item)
+ return itemTransform(item).map(path);
+ return mapToScene(path);
+}
+
+/*!
+ Maps the path \a path, which is in this item's coordinate system, to
+ its parent's coordinate system, and returns the mapped path. If the
+ item has no parent, \a path will be mapped to the scene's coordinate
+ system.
+
+ \sa mapToScene(), mapToItem(), mapFromParent(), {The Graphics View
+ Coordinate System}
+*/
+QPainterPath QGraphicsItem::mapToParent(const QPainterPath &path) const
+{
+ // COMBINE
+ if (!d_ptr->transformData)
+ return path.translated(d_ptr->pos);
+ return d_ptr->transformToParent().map(path);
+}
+
+/*!
+ Maps the path \a path, which is in this item's coordinate system, to
+ the scene's coordinate system, and returns the mapped path.
+
+ \sa mapToParent(), mapToItem(), mapFromScene(), {The Graphics View
+ Coordinate System}
+*/
+QPainterPath QGraphicsItem::mapToScene(const QPainterPath &path) const
+{
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return path.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.map(path);
+}
+
+/*!
+ Maps the point \a point, which is in \a item's coordinate system, to this
+ item's coordinate system, and returns the mapped coordinate.
+
+ If \a item is 0, this function returns the same as mapFromScene().
+
+ \sa itemTransform(), mapFromParent(), mapFromScene(), transform(), mapToItem(), {The Graphics
+ View Coordinate System}
+*/
+QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPointF &point) const
+{
+ if (item)
+ return item->itemTransform(this).map(point);
+ return mapFromScene(point);
+}
+
+/*!
+ \fn QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, qreal x, qreal y) const
+ \overload
+
+ This convenience function is equivalent to calling mapFromItem(\a item,
+ QPointF(\a x, \a y)).
+*/
+
+/*!
+ Maps the point \a point, which is in this item's parent's coordinate
+ system, to this item's coordinate system, and returns the mapped
+ coordinate.
+
+ \sa mapFromItem(), mapFromScene(), transform(), mapToParent(), {The Graphics
+ View Coordinate System}
+*/
+QPointF QGraphicsItem::mapFromParent(const QPointF &point) const
+{
+ // COMBINE
+ if (d_ptr->transformData)
+ return d_ptr->transformToParent().inverted().map(point);
+ return point - d_ptr->pos;
+}
+
+/*!
+ \fn QPointF QGraphicsItem::mapFromParent(qreal x, qreal y) const
+ \overload
+
+ This convenience function is equivalent to calling
+ mapFromParent(QPointF(\a x, \a y)).
+*/
+
+/*!
+ Maps the point \a point, which is in this item's scene's coordinate
+ system, to this item's coordinate system, and returns the mapped
+ coordinate.
+
+ \sa mapFromItem(), mapFromParent(), transform(), mapToScene(), {The Graphics
+ View Coordinate System}
+*/
+QPointF QGraphicsItem::mapFromScene(const QPointF &point) const
+{
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return QPointF(point.x() - d_ptr->sceneTransform.dx(), point.y() - d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.inverted().map(point);
+}
+
+/*!
+ \fn QPointF QGraphicsItem::mapFromScene(qreal x, qreal y) const
+ \overload
+
+ This convenience function is equivalent to calling mapFromScene(QPointF(\a
+ x, \a y)).
+*/
+
+/*!
+ Maps the rectangle \a rect, which is in \a item's coordinate system, to
+ this item's coordinate system, and returns the mapped rectangle as a
+ polygon.
+
+ If \a item is 0, this function returns the same as mapFromScene()
+
+ \sa itemTransform(), mapToItem(), mapFromParent(), transform(), {The Graphics View Coordinate
+ System}
+*/
+QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QRectF &rect) const
+{
+ if (item)
+ return item->itemTransform(this).map(rect);
+ return mapFromScene(rect);
+}
+
+/*!
+ \fn QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
+ \since 4.3
+
+ This convenience function is equivalent to calling mapFromItem(item, QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ Maps the rectangle \a rect, which is in this item's parent's coordinate
+ system, to this item's coordinate system, and returns the mapped rectangle
+ as a polygon.
+
+ \sa mapToParent(), mapFromItem(), transform(), {The Graphics View Coordinate
+ System}
+*/
+QPolygonF QGraphicsItem::mapFromParent(const QRectF &rect) const
+{
+ // COMBINE
+ if (!d_ptr->transformData)
+ return rect.translated(-d_ptr->pos);
+ return d_ptr->transformToParent().inverted().map(rect);
+}
+
+/*!
+ \fn QPolygonF QGraphicsItem::mapFromParent(qreal x, qreal y, qreal w, qreal h) const
+ \since 4.3
+
+ This convenience function is equivalent to calling mapFromItem(QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ Maps the rectangle \a rect, which is in this item's scene's coordinate
+ system, to this item's coordinate system, and returns the mapped rectangle
+ as a polygon.
+
+ \sa mapToScene(), mapFromItem(), transform(), {The Graphics View Coordinate
+ System}
+*/
+QPolygonF QGraphicsItem::mapFromScene(const QRectF &rect) const
+{
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return rect.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.inverted().map(rect);
+}
+
+/*!
+ \fn QPolygonF QGraphicsItem::mapFromScene(qreal x, qreal y, qreal w, qreal h) const
+ \since 4.3
+
+ This convenience function is equivalent to calling mapFromScene(QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ Maps the polygon \a polygon, which is in \a item's coordinate system, to
+ this item's coordinate system, and returns the mapped polygon.
+
+ If \a item is 0, this function returns the same as mapFromScene().
+
+ \sa itemTransform(), mapToItem(), mapFromParent(), transform(), {The
+ Graphics View Coordinate System}
+*/
+QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPolygonF &polygon) const
+{
+ if (item)
+ return item->itemTransform(this).map(polygon);
+ return mapFromScene(polygon);
+}
+
+/*!
+ Maps the polygon \a polygon, which is in this item's parent's coordinate
+ system, to this item's coordinate system, and returns the mapped polygon.
+
+ \sa mapToParent(), mapToItem(), transform(), {The Graphics View Coordinate
+ System}
+*/
+QPolygonF QGraphicsItem::mapFromParent(const QPolygonF &polygon) const
+{
+ // COMBINE
+ if (!d_ptr->transformData)
+ return polygon.translated(-d_ptr->pos);
+ return d_ptr->transformToParent().inverted().map(polygon);
+}
+
+/*!
+ Maps the polygon \a polygon, which is in this item's scene's coordinate
+ system, to this item's coordinate system, and returns the mapped polygon.
+
+ \sa mapToScene(), mapFromParent(), transform(), {The Graphics View Coordinate
+ System}
+*/
+QPolygonF QGraphicsItem::mapFromScene(const QPolygonF &polygon) const
+{
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return polygon.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.inverted().map(polygon);
+}
+
+/*!
+ Maps the path \a path, which is in \a item's coordinate system, to
+ this item's coordinate system, and returns the mapped path.
+
+ If \a item is 0, this function returns the same as mapFromScene().
+
+ \sa itemTransform(), mapFromParent(), mapFromScene(), mapToItem(), {The
+ Graphics View Coordinate System}
+*/
+QPainterPath QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPainterPath &path) const
+{
+ if (item)
+ return item->itemTransform(this).map(path);
+ return mapFromScene(path);
+}
+
+/*!
+ Maps the path \a path, which is in this item's parent's coordinate
+ system, to this item's coordinate system, and returns the mapped path.
+
+ \sa mapFromScene(), mapFromItem(), mapToParent(), {The Graphics View
+ Coordinate System}
+*/
+QPainterPath QGraphicsItem::mapFromParent(const QPainterPath &path) const
+{
+ // COMBINE
+ if (!d_ptr->transformData)
+ return path.translated(-d_ptr->pos);
+ return d_ptr->transformToParent().inverted().map(path);
+}
+
+/*!
+ Maps the path \a path, which is in this item's scene's coordinate
+ system, to this item's coordinate system, and returns the mapped path.
+
+ \sa mapFromParent(), mapFromItem(), mapToScene(), {The Graphics View
+ Coordinate System}
+*/
+QPainterPath QGraphicsItem::mapFromScene(const QPainterPath &path) const
+{
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return path.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.inverted().map(path);
+}
+
+/*!
+ Returns true if this item is an ancestor of \a child (i.e., if this item
+ is \a child's parent, or one of \a child's parent's ancestors).
+
+ \sa parentItem()
+*/
+bool QGraphicsItem::isAncestorOf(const QGraphicsItem *child) const
+{
+ if (!child || child == this)
+ return false;
+ if (child->d_ptr->depth() < d_ptr->depth())
+ return false;
+ const QGraphicsItem *ancestor = child;
+ while ((ancestor = ancestor->d_ptr->parent)) {
+ if (ancestor == this)
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \since 4.4
+
+ Returns the closest common ancestor item of this item and \a other, or 0
+ if either \a other is 0, or there is no common ancestor.
+
+ \sa isAncestorOf()
+*/
+QGraphicsItem *QGraphicsItem::commonAncestorItem(const QGraphicsItem *other) const
+{
+ if (!other)
+ return 0;
+ if (other == this)
+ return const_cast<QGraphicsItem *>(this);
+ const QGraphicsItem *thisw = this;
+ const QGraphicsItem *otherw = other;
+ int thisDepth = d_ptr->depth();
+ int otherDepth = other->d_ptr->depth();
+ while (thisDepth > otherDepth) {
+ thisw = thisw->d_ptr->parent;
+ --thisDepth;
+ }
+ while (otherDepth > thisDepth) {
+ otherw = otherw->d_ptr->parent;
+ --otherDepth;
+ }
+ while (thisw && thisw != otherw) {
+ thisw = thisw->d_ptr->parent;
+ otherw = otherw->d_ptr->parent;
+ }
+ return const_cast<QGraphicsItem *>(thisw);
+}
+
+/*!
+ \since 4,4
+ Returns true if this item is currently under the mouse cursor in one of
+ the views; otherwise, false is returned.
+
+ \sa QGraphicsScene::views(), QCursor::pos()
+*/
+bool QGraphicsItem::isUnderMouse() const
+{
+ Q_D(const QGraphicsItem);
+ if (!d->scene)
+ return false;
+
+ QPoint cursorPos = QCursor::pos();
+ foreach (QGraphicsView *view, d->scene->views()) {
+ if (contains(mapFromScene(view->mapToScene(view->mapFromGlobal(cursorPos)))))
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns this item's custom data for the key \a key as a QVariant.
+
+ Custom item data is useful for storing arbitrary properties in any
+ item. Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 11
+
+ Qt does not use this feature for storing data; it is provided solely
+ for the convenience of the user.
+
+ \sa setData()
+*/
+QVariant QGraphicsItem::data(int key) const
+{
+ QGraphicsItemCustomDataStore *store = qt_dataStore();
+ if (!store->data.contains(this))
+ return QVariant();
+ return store->data.value(this).value(key);
+}
+
+/*!
+ Sets this item's custom data for the key \a key to \a value.
+
+ Custom item data is useful for storing arbitrary properties for any
+ item. Qt does not use this feature for storing data; it is provided solely
+ for the convenience of the user.
+
+ \sa data()
+*/
+void QGraphicsItem::setData(int key, const QVariant &value)
+{
+ qt_dataStore()->data[this][key] = value;
+}
+
+/*!
+ \fn T qgraphicsitem_cast(QGraphicsItem *item)
+ \relates QGraphicsItem
+ \since 4.2
+
+ Returns the given \a item cast to type T if \a item is of type T;
+ otherwise, 0 is returned.
+
+ \note To make this function work correctly with custom items, reimplement
+ the \l{QGraphicsItem::}{type()} function for each custom QGraphicsItem
+ subclass.
+
+ \sa QGraphicsItem::type(), QGraphicsItem::UserType
+*/
+
+/*!
+ Returns the type of an item as an int. All standard graphicsitem classes
+ are associated with a unique value; see QGraphicsItem::Type. This type
+ information is used by qgraphicsitem_cast() to distinguish between types.
+
+ The default implementation (in QGraphicsItem) returns UserType.
+
+ To enable use of qgraphicsitem_cast() with a custom item, reimplement this
+ function and declare a Type enum value equal to your custom item's type.
+ Custom items must return a value larger than or equal to UserType (65536).
+
+ For example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp QGraphicsItem type
+
+ \sa UserType
+*/
+int QGraphicsItem::type() const
+{
+ return (int)UserType;
+}
+
+/*!
+ Installs an event filter for this item on \a filterItem, causing
+ all events for this item to first pass through \a filterItem's
+ sceneEventFilter() function.
+
+ To filter another item's events, install this item as an event filter
+ for the other item. Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 12
+
+ An item can only filter events for other items in the same
+ scene. Also, an item cannot filter its own events; instead, you
+ can reimplement sceneEvent() directly.
+
+ Items must belong to a scene for scene event filters to be installed and
+ used.
+
+ \sa removeSceneEventFilter(), sceneEventFilter(), sceneEvent()
+*/
+void QGraphicsItem::installSceneEventFilter(QGraphicsItem *filterItem)
+{
+ if (!d_ptr->scene) {
+ qWarning("QGraphicsItem::installSceneEventFilter: event filters can only be installed"
+ " on items in a scene.");
+ return;
+ }
+ if (d_ptr->scene != filterItem->scene()) {
+ qWarning("QGraphicsItem::installSceneEventFilter: event filters can only be installed"
+ " on items in the same scene.");
+ return;
+ }
+ d_ptr->scene->d_func()->installSceneEventFilter(this, filterItem);
+}
+
+/*!
+ Removes an event filter on this item from \a filterItem.
+
+ \sa installSceneEventFilter()
+*/
+void QGraphicsItem::removeSceneEventFilter(QGraphicsItem *filterItem)
+{
+ if (!d_ptr->scene || d_ptr->scene != filterItem->scene())
+ return;
+ d_ptr->scene->d_func()->removeSceneEventFilter(this, filterItem);
+}
+
+/*!
+ Filters events for the item \a watched. \a event is the filtered
+ event.
+
+ Reimplementing this function in a subclass makes it possible
+ for the item to be used as an event filter for other items,
+ intercepting all the events send to those items before they are
+ able to respond.
+
+ Reimplementations must return true to prevent further processing of
+ a given event, ensuring that it will not be delivered to the watched
+ item, or return false to indicate that the event should be propagated
+ further by the event system.
+
+ \sa installSceneEventFilter()
+*/
+bool QGraphicsItem::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
+{
+ Q_UNUSED(watched);
+ Q_UNUSED(event);
+ return false;
+}
+
+/*!
+ This virtual function receives events to this item. Reimplement
+ this function to intercept events before they are dispatched to
+ the specialized event handlers contextMenuEvent(), focusInEvent(),
+ focusOutEvent(), hoverEnterEvent(), hoverMoveEvent(),
+ hoverLeaveEvent(), keyPressEvent(), keyReleaseEvent(),
+ mousePressEvent(), mouseReleaseEvent(), mouseMoveEvent(), and
+ mouseDoubleClickEvent().
+
+ Returns true if the event was recognized and handled; otherwise, (e.g., if
+ the event type was not recognized,) false is returned.
+
+ \a event is the intercepted event.
+*/
+bool QGraphicsItem::sceneEvent(QEvent *event)
+{
+ if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents) {
+ if (event->type() == QEvent::HoverEnter || event->type() == QEvent::HoverLeave
+ || event->type() == QEvent::DragEnter || event->type() == QEvent::DragLeave) {
+ // Hover enter and hover leave events for children are ignored;
+ // hover move events are forwarded.
+ return true;
+ }
+
+ QGraphicsItem *handler = this;
+ do {
+ handler = handler->d_ptr->parent;
+ Q_ASSERT(handler);
+ } while (handler->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents);
+ // Forward the event to the closest parent that handles child
+ // events, mapping existing item-local coordinates to its
+ // coordinate system.
+ d_ptr->remapItemPos(event, handler);
+ handler->sceneEvent(event);
+ return true;
+ }
+
+ if (event->type() == QEvent::FocusOut) {
+ focusOutEvent(static_cast<QFocusEvent *>(event));
+ return true;
+ }
+
+ if (!d_ptr->visible) {
+ // Eaten
+ return true;
+ }
+
+ switch (event->type()) {
+ case QEvent::FocusIn:
+ focusInEvent(static_cast<QFocusEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneContextMenu:
+ contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneDragEnter:
+ dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneDragMove:
+ dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneDragLeave:
+ dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneDrop:
+ dropEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneHoverEnter:
+ hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneHoverMove:
+ hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneHoverLeave:
+ hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneMouseMove:
+ mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneWheel:
+ wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event));
+ break;
+ case QEvent::KeyPress: {
+ QKeyEvent *k = static_cast<QKeyEvent *>(event);
+ if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
+ if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
+ bool res = false;
+ if (k->key() == Qt::Key_Backtab
+ || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) {
+ if (d_ptr->isWidget) {
+ res = static_cast<QGraphicsWidget *>(this)->focusNextPrevChild(false);
+ } else if (d_ptr->scene) {
+ res = d_ptr->scene->focusNextPrevChild(false);
+ }
+ } else if (k->key() == Qt::Key_Tab) {
+ if (d_ptr->isWidget) {
+ res = static_cast<QGraphicsWidget *>(this)->focusNextPrevChild(true);
+ } else if (d_ptr->scene) {
+ res = d_ptr->scene->focusNextPrevChild(true);
+ }
+ }
+ if (!res)
+ event->ignore();
+ return true;
+ }
+ }
+ keyPressEvent(static_cast<QKeyEvent *>(event));
+ break;
+ }
+ case QEvent::KeyRelease:
+ keyReleaseEvent(static_cast<QKeyEvent *>(event));
+ break;
+ case QEvent::InputMethod:
+ inputMethodEvent(static_cast<QInputMethodEvent *>(event));
+ break;
+ case QEvent::WindowActivate:
+ case QEvent::WindowDeactivate:
+ // Propagate panel activation.
+ if (d_ptr->scene) {
+ for (int i = 0; i < d_ptr->children.size(); ++i) {
+ QGraphicsItem *child = d_ptr->children.at(i);
+ if (child->isVisible() && !child->isPanel()) {
+ if (!(child->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents))
+ d_ptr->scene->sendEvent(child, event);
+ }
+ }
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ This event handler can be reimplemented in a subclass to process context
+ menu events. The \a event parameter contains details about the event to
+ be handled.
+
+ If you ignore the event, (i.e., by calling QEvent::ignore(),) \a event
+ will propagate to any item beneath this item. If no items accept the
+ event, it will be ignored by the scene, and propagate to the view.
+
+ It's common to open a QMenu in response to receiving a context menu
+ event. Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 13
+
+ The default implementation ignores the event.
+
+ \sa sceneEvent()
+*/
+void QGraphicsItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
+{
+ event->ignore();
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ drag enter events for this item. Drag enter events are generated as the
+ cursor enters the item's area.
+
+ By accepting the event, (i.e., by calling QEvent::accept(),) the item will
+ accept drop events, in addition to receiving drag move and drag
+ leave. Otherwise, the event will be ignored and propagate to the item
+ beneath. If the event is accepted, the item will receive a drag move event
+ before control goes back to the event loop.
+
+ A common implementation of dragEnterEvent accepts or ignores \a event
+ depending on the associated mime data in \a event. Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 14
+
+ Items do not receive drag and drop events by default; to enable this
+ feature, call \c setAcceptDrops(true).
+
+ The default implementation does nothing.
+
+ \sa dropEvent(), dragMoveEvent(), dragLeaveEvent()
+*/
+void QGraphicsItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
+{
+ Q_D(QGraphicsItem);
+ // binary compatibility workaround between 4.4 and 4.5
+ if (d->isProxyWidget())
+ static_cast<QGraphicsProxyWidget*>(this)->dragEnterEvent(event);
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ drag leave events for this item. Drag leave events are generated as the
+ cursor leaves the item's area. Most often you will not need to reimplement
+ this function, but it can be useful for resetting state in your item
+ (e.g., highlighting).
+
+ Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
+
+ Items do not receive drag and drop events by default; to enable this
+ feature, call \c setAcceptDrops(true).
+
+ The default implementation does nothing.
+
+ \sa dragEnterEvent(), dropEvent(), dragMoveEvent()
+*/
+void QGraphicsItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
+{
+ Q_D(QGraphicsItem);
+ // binary compatibility workaround between 4.4 and 4.5
+ if (d->isProxyWidget())
+ static_cast<QGraphicsProxyWidget*>(this)->dragLeaveEvent(event);
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ drag move events for this item. Drag move events are generated as the
+ cursor moves around inside the item's area. Most often you will not need
+ to reimplement this function; it is used to indicate that only parts of
+ the item can accept drops.
+
+ Calling QEvent::ignore() or QEvent::accept() on \a event toggles whether
+ or not the item will accept drops at the position from the event. By
+ default, \a event is accepted, indicating that the item allows drops at
+ the specified position.
+
+ Items do not receive drag and drop events by default; to enable this
+ feature, call \c setAcceptDrops(true).
+
+ The default implementation does nothing.
+
+ \sa dropEvent(), dragEnterEvent(), dragLeaveEvent()
+*/
+void QGraphicsItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
+{
+ Q_D(QGraphicsItem);
+ // binary compatibility workaround between 4.4 and 4.5
+ if (d->isProxyWidget())
+ static_cast<QGraphicsProxyWidget*>(this)->dragMoveEvent(event);
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ drop events for this item. Items can only receive drop events if the last
+ drag move event was accepted.
+
+ Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
+
+ Items do not receive drag and drop events by default; to enable this
+ feature, call \c setAcceptDrops(true).
+
+ The default implementation does nothing.
+
+ \sa dragEnterEvent(), dragMoveEvent(), dragLeaveEvent()
+*/
+void QGraphicsItem::dropEvent(QGraphicsSceneDragDropEvent *event)
+{
+ Q_D(QGraphicsItem);
+ // binary compatibility workaround between 4.4 and 4.5
+ if (d->isProxyWidget())
+ static_cast<QGraphicsProxyWidget*>(this)->dropEvent(event);
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ focus in events for this item. The default implementation calls
+ ensureVisible().
+
+ \sa focusOutEvent(), sceneEvent(), setFocus()
+*/
+void QGraphicsItem::focusInEvent(QFocusEvent *event)
+{
+ Q_UNUSED(event);
+ update();
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ focus out events for this item. The default implementation does nothing.
+
+ \sa focusInEvent(), sceneEvent(), setFocus()
+*/
+void QGraphicsItem::focusOutEvent(QFocusEvent *event)
+{
+ Q_UNUSED(event);
+ update();
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ hover enter events for this item. The default implementation calls
+ update(); otherwise it does nothing.
+
+ Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
+
+ \sa hoverMoveEvent(), hoverLeaveEvent(), sceneEvent(), setAcceptHoverEvents()
+*/
+void QGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+ update();
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ hover move events for this item. The default implementation does nothing.
+
+ Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
+
+ \sa hoverEnterEvent(), hoverLeaveEvent(), sceneEvent(), setAcceptHoverEvents()
+*/
+void QGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ hover leave events for this item. The default implementation calls
+ update(); otherwise it does nothing.
+
+ Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
+
+ \sa hoverEnterEvent(), hoverMoveEvent(), sceneEvent(), setAcceptHoverEvents()
+*/
+void QGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+ update();
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to
+ receive key press events for this item. The default implementation
+ ignores the event. If you reimplement this handler, the event will by
+ default be accepted.
+
+ Note that key events are only received for items that set the
+ ItemIsFocusable flag, and that have keyboard input focus.
+
+ \sa keyReleaseEvent(), setFocus(), QGraphicsScene::setFocusItem(),
+ sceneEvent()
+*/
+void QGraphicsItem::keyPressEvent(QKeyEvent *event)
+{
+ event->ignore();
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ key release events for this item. The default implementation
+ ignores the event. If you reimplement this handler, the event will by
+ default be accepted.
+
+ Note that key events are only received for items that set the
+ ItemIsFocusable flag, and that have keyboard input focus.
+
+ \sa keyPressEvent(), setFocus(), QGraphicsScene::setFocusItem(),
+ sceneEvent()
+*/
+void QGraphicsItem::keyReleaseEvent(QKeyEvent *event)
+{
+ event->ignore();
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to
+ receive mouse press events for this item. Mouse press events are
+ only delivered to items that accept the mouse button that is
+ pressed. By default, an item accepts all mouse buttons, but you
+ can change this by calling setAcceptedMouseButtons().
+
+ The mouse press event decides which item should become the mouse
+ grabber (see QGraphicsScene::mouseGrabberItem()). If you do not
+ reimplement this function, the press event will propagate to any
+ topmost item beneath this item, and no other mouse events will be
+ delivered to this item.
+
+ If you do reimplement this function, \a event will by default be
+ accepted (see QEvent::accept()), and this item is then the mouse
+ grabber. This allows the item to receive future move, release and
+ doubleclick events. If you call QEvent::ignore() on \a event, this
+ item will lose the mouse grab, and \a event will propagate to any
+ topmost item beneath. No further mouse events will be delivered to
+ this item unless a new mouse press event is received.
+
+ The default implementation handles basic item interaction, such as
+ selection and moving. If you want to keep the base implementation
+ when reimplementing this function, call
+ QGraphicsItem::mousePressEvent() in your reimplementation.
+
+ The event is \l{QEvent::ignore()}d for items that are neither
+ \l{QGraphicsItem::ItemIsMovable}{movable} nor
+ \l{QGraphicsItem::ItemIsSelectable}{selectable}.
+
+ \sa mouseMoveEvent(), mouseReleaseEvent(),
+ mouseDoubleClickEvent(), sceneEvent()
+*/
+void QGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton && (flags() & ItemIsSelectable)) {
+ bool multiSelect = (event->modifiers() & Qt::ControlModifier) != 0;
+ if (!multiSelect) {
+ if (!d_ptr->selected) {
+ if (QGraphicsScene *scene = d_ptr->scene) {
+ ++scene->d_func()->selectionChanging;
+ scene->clearSelection();
+ --scene->d_func()->selectionChanging;
+ }
+ setSelected(true);
+ }
+ }
+ } else if (!(flags() & ItemIsMovable)) {
+ event->ignore();
+ }
+ if (d_ptr->isWidget) {
+ // Qt::Popup closes when you click outside.
+ QGraphicsWidget *w = static_cast<QGraphicsWidget *>(this);
+ if ((w->windowFlags() & Qt::Popup) == Qt::Popup) {
+ event->accept();
+ if (!w->rect().contains(event->pos()))
+ w->close();
+ }
+ }
+}
+
+/*!
+ obsolete
+*/
+bool _qt_movableAncestorIsSelected(const QGraphicsItem *item)
+{
+ const QGraphicsItem *parent = item->parentItem();
+ return parent && (((parent->flags() & QGraphicsItem::ItemIsMovable) && parent->isSelected()) || _qt_movableAncestorIsSelected(parent));
+}
+
+bool QGraphicsItemPrivate::movableAncestorIsSelected(const QGraphicsItem *item)
+{
+ const QGraphicsItem *parent = item->d_ptr->parent;
+ return parent && (((parent->flags() & QGraphicsItem::ItemIsMovable) && parent->isSelected()) || _qt_movableAncestorIsSelected(parent));
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to
+ receive mouse move events for this item. If you do receive this
+ event, you can be certain that this item also received a mouse
+ press event, and that this item is the current mouse grabber.
+
+ Calling QEvent::ignore() or QEvent::accept() on \a event has no
+ effect.
+
+ The default implementation handles basic item interaction, such as
+ selection and moving. If you want to keep the base implementation
+ when reimplementing this function, call
+ QGraphicsItem::mouseMoveEvent() in your reimplementation.
+
+ Please note that mousePressEvent() decides which graphics item it
+ is that receives mouse events. See the mousePressEvent()
+ description for details.
+
+ \sa mousePressEvent(), mouseReleaseEvent(),
+ mouseDoubleClickEvent(), sceneEvent()
+*/
+void QGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ if ((event->buttons() & Qt::LeftButton) && (flags() & ItemIsMovable)) {
+ // Determine the list of items that need to be moved.
+ QList<QGraphicsItem *> selectedItems;
+ QMap<QGraphicsItem *, QPointF> initialPositions;
+ if (d_ptr->scene) {
+ selectedItems = d_ptr->scene->selectedItems();
+ initialPositions = d_ptr->scene->d_func()->movingItemsInitialPositions;
+ if (initialPositions.isEmpty()) {
+ foreach (QGraphicsItem *item, selectedItems)
+ initialPositions[item] = item->pos();
+ initialPositions[this] = pos();
+ }
+ d_ptr->scene->d_func()->movingItemsInitialPositions = initialPositions;
+ }
+
+ // Find the active view.
+ QGraphicsView *view = 0;
+ if (event->widget())
+ view = qobject_cast<QGraphicsView *>(event->widget()->parentWidget());
+
+ // Move all selected items
+ int i = 0;
+ bool movedMe = false;
+ while (i <= selectedItems.size()) {
+ QGraphicsItem *item = 0;
+ if (i < selectedItems.size())
+ item = selectedItems.at(i);
+ else
+ item = this;
+ if (item == this) {
+ // Slightly clumsy-looking way to ensure that "this" is part
+ // of the list of items to move, this is to avoid allocations
+ // (appending this item to the list of selected items causes a
+ // detach).
+ if (movedMe)
+ break;
+ movedMe = true;
+ }
+
+ if ((item->flags() & ItemIsMovable) && !QGraphicsItemPrivate::movableAncestorIsSelected(item)) {
+ QPointF currentParentPos;
+ QPointF buttonDownParentPos;
+ if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations) {
+ // Items whose ancestors ignore transformations need to
+ // map screen coordinates to local coordinates, then map
+ // those to the parent.
+ QTransform viewToItemTransform = (item->deviceTransform(view->viewportTransform())).inverted();
+ currentParentPos = mapToParent(viewToItemTransform.map(QPointF(view->mapFromGlobal(event->screenPos()))));
+ buttonDownParentPos = mapToParent(viewToItemTransform.map(QPointF(view->mapFromGlobal(event->buttonDownScreenPos(Qt::LeftButton)))));
+ } else if (item->flags() & ItemIgnoresTransformations) {
+ // Root items that ignore transformations need to
+ // calculate their diff by mapping viewport coordinates
+ // directly to parent coordinates.
+ // COMBINE
+ QTransform itemTransform;
+ if (item->d_ptr->transformData)
+ itemTransform = item->d_ptr->transformData->computedFullTransform();
+ itemTransform.translate(item->d_ptr->pos.x(), item->d_ptr->pos.y());
+ QTransform viewToParentTransform = itemTransform
+ * (item->sceneTransform() * view->viewportTransform()).inverted();
+ currentParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->screenPos())));
+ buttonDownParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->buttonDownScreenPos(Qt::LeftButton))));
+ } else {
+ // All other items simply map from the scene.
+ currentParentPos = item->mapToParent(item->mapFromScene(event->scenePos()));
+ buttonDownParentPos = item->mapToParent(item->mapFromScene(event->buttonDownScenePos(Qt::LeftButton)));
+ }
+
+ item->setPos(initialPositions.value(item) + currentParentPos - buttonDownParentPos);
+
+ if (item->flags() & ItemIsSelectable)
+ item->setSelected(true);
+ }
+ ++i;
+ }
+
+ } else {
+ event->ignore();
+ }
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to
+ receive mouse release events for this item.
+
+ Calling QEvent::ignore() or QEvent::accept() on \a event has no
+ effect.
+
+ The default implementation handles basic item interaction, such as
+ selection and moving. If you want to keep the base implementation
+ when reimplementing this function, call
+ QGraphicsItem::mouseReleaseEvent() in your reimplementation.
+
+ Please note that mousePressEvent() decides which graphics item it
+ is that receives mouse events. See the mousePressEvent()
+ description for details.
+
+ \sa mousePressEvent(), mouseMoveEvent(), mouseDoubleClickEvent(),
+ sceneEvent()
+*/
+void QGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (flags() & ItemIsSelectable) {
+ bool multiSelect = (event->modifiers() & Qt::ControlModifier) != 0;
+ if (event->scenePos() == event->buttonDownScenePos(Qt::LeftButton)) {
+ // The item didn't move
+ if (multiSelect) {
+ setSelected(!isSelected());
+ } else {
+ bool selectionChanged = false;
+ if (QGraphicsScene *scene = d_ptr->scene) {
+ ++scene->d_func()->selectionChanging;
+ // Clear everything but this item. Bypass
+ // QGraphicsScene::clearSelection()'s default behavior by
+ // temporarily removing this item from the selection list.
+ if (d_ptr->selected) {
+ scene->d_func()->selectedItems.remove(this);
+ foreach (QGraphicsItem *item, scene->d_func()->selectedItems) {
+ if (item->isSelected()) {
+ selectionChanged = true;
+ break;
+ }
+ }
+ }
+ scene->clearSelection();
+ if (d_ptr->selected)
+ scene->d_func()->selectedItems.insert(this);
+ --scene->d_func()->selectionChanging;
+ if (selectionChanged)
+ emit d_ptr->scene->selectionChanged();
+ }
+ setSelected(true);
+ }
+ }
+ }
+ if (d_ptr->scene && !event->buttons())
+ d_ptr->scene->d_func()->movingItemsInitialPositions.clear();
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to
+ receive mouse doubleclick events for this item.
+
+ When doubleclicking an item, the item will first receive a mouse
+ press event, followed by a release event (i.e., a click), then a
+ doubleclick event, and finally a release event.
+
+ Calling QEvent::ignore() or QEvent::accept() on \a event has no
+ effect.
+
+ The default implementation calls mousePressEvent(). If you want to
+ keep the base implementation when reimplementing this function,
+ call QGraphicsItem::mouseDoubleClickEvent() in your
+ reimplementation.
+
+ Note that an item will not receive double click events if it is
+ neither \l {QGraphicsItem::ItemIsSelectable}{selectable} nor
+ \l{QGraphicsItem::ItemIsMovable}{movable} (single mouse clicks are
+ ignored in this case, and that stops the generation of double
+ clicks).
+
+ \sa mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(), sceneEvent()
+*/
+void QGraphicsItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ mousePressEvent(event);
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ wheel events for this item. If you reimplement this function, \a event
+ will be accepted by default.
+
+ If you ignore the event, (i.e., by calling QEvent::ignore(),) it will
+ propagate to any item beneath this item. If no items accept the event, it
+ will be ignored by the scene, and propagate to the view (e.g., the view's
+ vertical scroll bar).
+
+ The default implementation ignores the event.
+
+ \sa sceneEvent()
+*/
+void QGraphicsItem::wheelEvent(QGraphicsSceneWheelEvent *event)
+{
+ event->ignore();
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented to receive
+ input method events for this item. The default implementation ignores the
+ event.
+
+ \sa inputMethodQuery(), sceneEvent()
+*/
+void QGraphicsItem::inputMethodEvent(QInputMethodEvent *event)
+{
+ event->ignore();
+}
+
+/*!
+ This method is only relevant for input items. It is used by the
+ input method to query a set of properties of the item to be able
+ to support complex input method operations, such as support for
+ surrounding text and reconversions. \a query specifies which
+ property is queried.
+
+ \sa inputMethodEvent(), QInputMethodEvent, QInputContext
+*/
+QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ if (isWidget()) {
+ // ### Qt 5: Remove. The reimplementation in
+ // QGraphicsProxyWidget solves this problem (but requires a
+ // recompile to take effect).
+ return d_ptr->inputMethodQueryHelper(query);
+ }
+
+ Q_UNUSED(query);
+ return QVariant();
+}
+
+/*!
+ Returns the current input method hints of this item.
+
+ Input method hints are only relevant for input items.
+ The hints are used by the input method to indicate how it should operate.
+ For example, if the Qt::ImhNumbersOnly flag is set, the input method may change
+ its visual components to reflect that only numbers can be entered.
+
+ The effect may vary between input method implementations.
+
+ \since 4.6
+
+ \sa setInputMethodHints(), inputMethodQuery(), QInputContext
+*/
+Qt::InputMethodHints QGraphicsItem::inputMethodHints() const
+{
+ Q_D(const QGraphicsItem);
+ return d->imHints;
+}
+
+/*!
+ Sets the current input method hints of this item to \a hints.
+
+ \since 4.6
+
+ \sa inputMethodHints(), inputMethodQuery(), QInputContext
+*/
+void QGraphicsItem::setInputMethodHints(Qt::InputMethodHints hints)
+{
+ Q_D(QGraphicsItem);
+ d->imHints = hints;
+ if (!hasFocus())
+ return;
+ d->scene->d_func()->updateInputMethodSensitivityInViews();
+#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN))
+ QWidget *fw = QApplication::focusWidget();
+ if (!fw)
+ return;
+ for (int i = 0 ; i < scene()->views().count() ; ++i)
+ if (scene()->views().at(i) == fw)
+ if (QInputContext *inputContext = fw->inputContext())
+ inputContext->update();
+#endif
+}
+
+/*!
+ Updates the item's micro focus.
+
+ \since 4.7
+
+ \sa QInputContext
+*/
+void QGraphicsItem::updateMicroFocus()
+{
+#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN))
+ if (QWidget *fw = QApplication::focusWidget()) {
+ if (scene()) {
+ for (int i = 0 ; i < scene()->views().count() ; ++i) {
+ if (scene()->views().at(i) == fw)
+ if (QInputContext *inputContext = fw->inputContext())
+ inputContext->update();
+ }
+ }
+#ifndef QT_NO_ACCESSIBILITY
+ // ##### is this correct
+ QAccessible::updateAccessibility(fw, 0, QAccessible::StateChanged);
+#endif
+ }
+#endif
+}
+
+/*!
+ This virtual function is called by QGraphicsItem to notify custom items
+ that some part of the item's state changes. By reimplementing this
+ function, your can react to a change, and in some cases, (depending on \a
+ change,) adjustments can be made.
+
+ \a change is the parameter of the item that is changing. \a value is the
+ new value; the type of the value depends on \a change.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 15
+
+ The default implementation does nothing, and returns \a value.
+
+ Note: Certain QGraphicsItem functions cannot be called in a
+ reimplementation of this function; see the GraphicsItemChange
+ documentation for details.
+
+ \sa GraphicsItemChange
+*/
+QVariant QGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ Q_UNUSED(change);
+ return value;
+}
+
+/*!
+ \internal
+
+ Note: This is provided as a hook to avoid future problems related
+ to adding virtual functions.
+*/
+bool QGraphicsItem::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension);
+ return false;
+}
+
+/*!
+ \internal
+
+ Note: This is provided as a hook to avoid future problems related
+ to adding virtual functions.
+*/
+void QGraphicsItem::setExtension(Extension extension, const QVariant &variant)
+{
+ Q_UNUSED(extension);
+ Q_UNUSED(variant);
+}
+
+/*!
+ \internal
+
+ Note: This is provided as a hook to avoid future problems related
+ to adding virtual functions.
+*/
+QVariant QGraphicsItem::extension(const QVariant &variant) const
+{
+ Q_UNUSED(variant);
+ return QVariant();
+}
+
+/*!
+ \internal
+
+ Adds this item to the scene's index. Called in conjunction with
+ removeFromIndex() to ensure the index bookkeeping is correct when
+ the item's position, transformation or shape changes.
+*/
+void QGraphicsItem::addToIndex()
+{
+ if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) {
+ // ### add to child index only if applicable
+ return;
+ }
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->index->addItem(this);
+}
+
+/*!
+ \internal
+
+ Removes this item from the scene's index. Called in conjunction
+ with addToIndex() to ensure the index bookkeeping is correct when
+ the item's position, transformation or shape changes.
+*/
+void QGraphicsItem::removeFromIndex()
+{
+ if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) {
+ // ### remove from child index only if applicable
+ return;
+ }
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->index->removeItem(this);
+}
+
+/*!
+ Prepares the item for a geometry change. Call this function before
+ changing the bounding rect of an item to keep QGraphicsScene's index up to
+ date.
+
+ prepareGeometryChange() will call update() if this is necessary.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 16
+
+ \sa boundingRect()
+*/
+void QGraphicsItem::prepareGeometryChange()
+{
+ if (d_ptr->inDestructor)
+ return;
+ if (d_ptr->scene) {
+ d_ptr->scene->d_func()->dirtyGrowingItemsBoundingRect = true;
+ d_ptr->geometryChanged = 1;
+ d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
+ d_ptr->notifyBoundingRectChanged = !d_ptr->inSetPosHelper;
+
+ QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func();
+ scenePrivate->index->prepareBoundingRectChange(this);
+ scenePrivate->markDirty(this, QRectF(), /*invalidateChildren=*/true, /*force=*/false,
+ /*ignoreOpacity=*/ false, /*removingItemFromScene=*/ false,
+ /*updateBoundingRect=*/true);
+
+ // For compatibility reasons, we have to update the item's old geometry
+ // if someone is connected to the changed signal or the scene has no views.
+ // Note that this has to be done *after* markDirty to ensure that
+ // _q_processDirtyItems is called before _q_emitUpdated.
+ if (scenePrivate->isSignalConnected(scenePrivate->changedSignalIndex)
+ || scenePrivate->views.isEmpty()) {
+ if (d_ptr->hasTranslateOnlySceneTransform()) {
+ d_ptr->scene->update(boundingRect().translated(d_ptr->sceneTransform.dx(),
+ d_ptr->sceneTransform.dy()));
+ } else {
+ d_ptr->scene->update(d_ptr->sceneTransform.mapRect(boundingRect()));
+ }
+ }
+ }
+
+ d_ptr->markParentDirty(/*updateBoundingRect=*/true);
+}
+
+/*!
+ \internal
+
+ Highlights \a item as selected.
+
+ NOTE: This function is a duplicate of qt_graphicsItem_highlightSelected() in
+ qgraphicssvgitem.cpp!
+*/
+static void qt_graphicsItem_highlightSelected(
+ QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *option)
+{
+ const QRectF murect = painter->transform().mapRect(QRectF(0, 0, 1, 1));
+ if (qFuzzyIsNull(qMax(murect.width(), murect.height())))
+ return;
+
+ const QRectF mbrect = painter->transform().mapRect(item->boundingRect());
+ if (qMin(mbrect.width(), mbrect.height()) < qreal(1.0))
+ return;
+
+ qreal itemPenWidth;
+ switch (item->type()) {
+ case QGraphicsEllipseItem::Type:
+ itemPenWidth = static_cast<QGraphicsEllipseItem *>(item)->pen().widthF();
+ break;
+ case QGraphicsPathItem::Type:
+ itemPenWidth = static_cast<QGraphicsPathItem *>(item)->pen().widthF();
+ break;
+ case QGraphicsPolygonItem::Type:
+ itemPenWidth = static_cast<QGraphicsPolygonItem *>(item)->pen().widthF();
+ break;
+ case QGraphicsRectItem::Type:
+ itemPenWidth = static_cast<QGraphicsRectItem *>(item)->pen().widthF();
+ break;
+ case QGraphicsSimpleTextItem::Type:
+ itemPenWidth = static_cast<QGraphicsSimpleTextItem *>(item)->pen().widthF();
+ break;
+ case QGraphicsLineItem::Type:
+ itemPenWidth = static_cast<QGraphicsLineItem *>(item)->pen().widthF();
+ break;
+ default:
+ itemPenWidth = 1.0;
+ }
+ const qreal pad = itemPenWidth / 2;
+
+ const qreal penWidth = 0; // cosmetic pen
+
+ const QColor fgcolor = option->palette.windowText().color();
+ const QColor bgcolor( // ensure good contrast against fgcolor
+ fgcolor.red() > 127 ? 0 : 255,
+ fgcolor.green() > 127 ? 0 : 255,
+ fgcolor.blue() > 127 ? 0 : 255);
+
+ painter->setPen(QPen(bgcolor, penWidth, Qt::SolidLine));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad));
+
+ painter->setPen(QPen(option->palette.windowText(), 0, Qt::DashLine));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad));
+}
+
+/*!
+ \class QGraphicsObject
+ \brief The QGraphicsObject class provides a base class for all graphics items that
+ require signals, slots and properties.
+ \since 4.6
+ \ingroup graphicsview-api
+
+ The class extends a QGraphicsItem with QObject's signal/slot and property mechanisms.
+ It maps many of QGraphicsItem's basic setters and getters to properties and adds notification
+ signals for many of them.
+
+ \section1 Parents and Children
+
+ Each graphics object can be constructed with a parent item. This ensures that the
+ item will be destroyed when its parent item is destroyed. Although QGraphicsObject
+ inherits from both QObject and QGraphicsItem, you should use the functions provided
+ by QGraphicsItem, \e not QObject, to manage the relationships between parent and
+ child items.
+
+ The relationships between items can be explored using the parentItem() and childItems()
+ functions. In the hierarchy of items in a scene, the parentObject() and parentWidget()
+ functions are the equivalent of the QWidget::parent() and QWidget::parentWidget()
+ functions for QWidget subclasses.
+
+ \sa QGraphicsWidget
+*/
+
+/*!
+ Constructs a QGraphicsObject with \a parent.
+*/
+QGraphicsObject::QGraphicsObject(QGraphicsItem *parent)
+ : QGraphicsItem(parent)
+{
+ QGraphicsItem::d_ptr->isObject = true;
+}
+
+/*!
+ \internal
+*/
+QGraphicsObject::QGraphicsObject(QGraphicsItemPrivate &dd, QGraphicsItem *parent, QGraphicsScene *scene)
+ : QGraphicsItem(dd, parent, scene)
+{
+ QGraphicsItem::d_ptr->isObject = true;
+}
+
+#ifndef QT_NO_GESTURES
+/*!
+ Subscribes the graphics object to the given \a gesture with specific \a flags.
+
+ \sa ungrabGesture(), QGestureEvent
+*/
+void QGraphicsObject::grabGesture(Qt::GestureType gesture, Qt::GestureFlags flags)
+{
+ bool contains = QGraphicsItem::d_ptr->gestureContext.contains(gesture);
+ QGraphicsItem::d_ptr->gestureContext.insert(gesture, flags);
+ if (!contains && QGraphicsItem::d_ptr->scene)
+ QGraphicsItem::d_ptr->scene->d_func()->grabGesture(this, gesture);
+}
+
+/*!
+ Unsubscribes the graphics object from the given \a gesture.
+
+ \sa grabGesture(), QGestureEvent
+*/
+void QGraphicsObject::ungrabGesture(Qt::GestureType gesture)
+{
+ if (QGraphicsItem::d_ptr->gestureContext.remove(gesture) && QGraphicsItem::d_ptr->scene)
+ QGraphicsItem::d_ptr->scene->d_func()->ungrabGesture(this, gesture);
+}
+#endif // QT_NO_GESTURES
+
+/*!
+ Updates the item's micro focus. This is slot for convenience.
+
+ \since 4.7
+
+ \sa QInputContext
+*/
+void QGraphicsObject::updateMicroFocus()
+{
+ QGraphicsItem::updateMicroFocus();
+}
+
+void QGraphicsItemPrivate::children_append(QDeclarativeListProperty<QGraphicsObject> *list, QGraphicsObject *item)
+{
+ if (item) {
+ QGraphicsObject *graphicsObject = static_cast<QGraphicsObject *>(list->object);
+ if (QGraphicsItemPrivate::get(graphicsObject)->sendParentChangeNotification) {
+ item->setParentItem(graphicsObject);
+ } else {
+ QGraphicsItemPrivate::get(item)->setParentItemHelper(graphicsObject, 0, 0);
+ }
+ }
+}
+
+int QGraphicsItemPrivate::children_count(QDeclarativeListProperty<QGraphicsObject> *list)
+{
+ QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(list->object));
+ return d->children.count();
+}
+
+QGraphicsObject *QGraphicsItemPrivate::children_at(QDeclarativeListProperty<QGraphicsObject> *list, int index)
+{
+ QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(list->object));
+ if (index >= 0 && index < d->children.count())
+ return d->children.at(index)->toGraphicsObject();
+ else
+ return 0;
+}
+
+void QGraphicsItemPrivate::children_clear(QDeclarativeListProperty<QGraphicsObject> *list)
+{
+ QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(list->object));
+ int childCount = d->children.count();
+ if (d->sendParentChangeNotification) {
+ for (int index = 0; index < childCount; index++)
+ d->children.at(0)->setParentItem(0);
+ } else {
+ for (int index = 0; index < childCount; index++)
+ QGraphicsItemPrivate::get(d->children.at(0))->setParentItemHelper(0, 0, 0);
+ }
+}
+
+/*!
+ Returns a list of this item's children.
+
+ The items are sorted by stacking order. This takes into account both the
+ items' insertion order and their Z-values.
+
+*/
+QDeclarativeListProperty<QGraphicsObject> QGraphicsItemPrivate::childrenList()
+{
+ Q_Q(QGraphicsItem);
+ if (isObject) {
+ QGraphicsObject *that = static_cast<QGraphicsObject *>(q);
+ return QDeclarativeListProperty<QGraphicsObject>(that, &children, children_append,
+ children_count, children_at, children_clear);
+ } else {
+ //QGraphicsItem is not supported for this property
+ return QDeclarativeListProperty<QGraphicsObject>();
+ }
+}
+
+/*!
+ \internal
+ Returns the width of the item
+ Reimplemented by QGraphicsWidget
+*/
+qreal QGraphicsItemPrivate::width() const
+{
+ return 0;
+}
+
+/*!
+ \internal
+ Set the width of the item
+ Reimplemented by QGraphicsWidget
+*/
+void QGraphicsItemPrivate::setWidth(qreal w)
+{
+ Q_UNUSED(w);
+}
+
+/*!
+ \internal
+ Reset the width of the item
+ Reimplemented by QGraphicsWidget
+*/
+void QGraphicsItemPrivate::resetWidth()
+{
+}
+
+/*!
+ \internal
+ Returns the height of the item
+ Reimplemented by QGraphicsWidget
+*/
+qreal QGraphicsItemPrivate::height() const
+{
+ return 0;
+}
+
+/*!
+ \internal
+ Set the height of the item
+ Reimplemented by QGraphicsWidget
+*/
+void QGraphicsItemPrivate::setHeight(qreal h)
+{
+ Q_UNUSED(h);
+}
+
+/*!
+ \internal
+ Reset the height of the item
+ Reimplemented by QGraphicsWidget
+*/
+void QGraphicsItemPrivate::resetHeight()
+{
+}
+
+/*!
+ \property QGraphicsObject::children
+ \since 4.7
+ \internal
+*/
+
+/*!
+ \property QGraphicsObject::width
+ \since 4.7
+ \internal
+*/
+
+/*!
+ \property QGraphicsObject::height
+ \since 4.7
+ \internal
+*/
+
+/*!
+ \property QGraphicsObject::parent
+ \brief the parent of the item
+
+ \note The item's parent is set independently of the parent object returned
+ by QObject::parent().
+
+ \sa QGraphicsItem::setParentItem(), QGraphicsItem::parentObject()
+*/
+
+/*!
+ \property QGraphicsObject::opacity
+ \brief the opacity of the item
+
+ \sa QGraphicsItem::setOpacity(), QGraphicsItem::opacity()
+*/
+
+/*!
+ \fn QGraphicsObject::opacityChanged()
+
+ This signal gets emitted whenever the opacity of the item changes
+
+ \sa QGraphicsItem::opacity()
+*/
+
+/*!
+ \fn QGraphicsObject::parentChanged()
+
+ This signal gets emitted whenever the parent of the item changes
+*/
+
+/*!
+ \property QGraphicsObject::pos
+ \brief the position of the item
+
+ Describes the items position.
+
+ \sa QGraphicsItem::setPos(), QGraphicsItem::pos()
+*/
+
+/*!
+ \property QGraphicsObject::x
+ \brief the x position of the item
+
+ Describes the items x position.
+
+ \sa QGraphicsItem::setX(), setPos(), xChanged()
+*/
+
+/*!
+ \fn QGraphicsObject::xChanged()
+
+ This signal gets emitted whenever the x position of the item changes
+
+ \sa pos()
+*/
+
+/*!
+ \property QGraphicsObject::y
+ \brief the y position of the item
+
+ Describes the items y position.
+
+ \sa QGraphicsItem::setY(), setPos(), yChanged()
+*/
+
+/*!
+ \fn QGraphicsObject::yChanged()
+
+ This signal gets emitted whenever the y position of the item changes.
+
+ \sa pos()
+*/
+
+/*!
+ \property QGraphicsObject::z
+ \brief the z value of the item
+
+ Describes the items z value.
+
+ \sa QGraphicsItem::setZValue(), zValue(), zChanged()
+*/
+
+/*!
+ \fn QGraphicsObject::zChanged()
+
+ This signal gets emitted whenever the z value of the item changes.
+
+ \sa pos()
+*/
+
+/*!
+ \property QGraphicsObject::rotation
+ This property holds the rotation of the item in degrees.
+
+ This specifies how many degrees to rotate the item around its transformOrigin.
+ The default rotation is 0 degrees (i.e. not rotated at all).
+*/
+
+/*!
+ \fn QGraphicsObject::rotationChanged()
+
+ This signal gets emitted whenever the roation of the item changes.
+*/
+
+/*!
+ \property QGraphicsObject::scale
+ This property holds the scale of the item.
+
+ A scale of less than 1 means the item will be displayed smaller than
+ normal, and a scale of greater than 1 means the item will be
+ displayed larger than normal. A negative scale means the item will
+ be mirrored.
+
+ By default, items are displayed at a scale of 1 (i.e. at their
+ normal size).
+
+ Scaling is from the item's transformOrigin.
+*/
+
+/*!
+ \fn void QGraphicsObject::scaleChanged()
+
+ This signal is emitted when the scale of the item changes.
+*/
+
+
+/*!
+ \property QGraphicsObject::enabled
+ \brief whether the item is enabled or not
+
+ This property is declared in QGraphicsItem.
+
+ By default, this property is true.
+
+ \sa QGraphicsItem::isEnabled(), QGraphicsItem::setEnabled()
+ \sa QGraphicsObject::enabledChanged()
+*/
+
+/*!
+ \fn void QGraphicsObject::enabledChanged()
+
+ This signal gets emitted whenever the item get's enabled or disabled.
+
+ \sa isEnabled()
+*/
+
+/*!
+ \property QGraphicsObject::visible
+ \brief whether the item is visible or not
+
+ This property is declared in QGraphicsItem.
+
+ By default, this property is true.
+
+ \sa QGraphicsItem::isVisible(), QGraphicsItem::setVisible(), visibleChanged()
+*/
+
+/*!
+ \fn QGraphicsObject::visibleChanged()
+
+ This signal gets emitted whenever the visibility of the item changes
+
+ \sa visible
+*/
+
+/*!
+ \fn const QObjectList &QGraphicsObject::children() const
+ \internal
+
+ This function returns the same value as QObject::children(). It's
+ provided to differentiate between the obsolete member
+ QGraphicsItem::children() and QObject::children(). QGraphicsItem now
+ provides childItems() instead.
+*/
+
+/*!
+ \property QGraphicsObject::transformOriginPoint
+ \brief the transformation origin
+
+ This property sets a specific point in the items coordiante system as the
+ origin for scale and rotation.
+
+ \sa scale, rotation, QGraphicsItem::transformOriginPoint()
+*/
+
+/*!
+ \fn void QGraphicsObject::widthChanged()
+ \internal
+*/
+
+/*!
+ \fn void QGraphicsObject::heightChanged()
+ \internal
+*/
+
+/*!
+
+ \fn QGraphicsObject::childrenChanged()
+
+ This signal gets emitted whenever the children list changes
+ \internal
+*/
+
+/*!
+ \property QGraphicsObject::effect
+ \since 4.7
+ \brief the effect attached to this item
+
+ \sa QGraphicsItem::setGraphicsEffect(), QGraphicsItem::graphicsEffect()
+*/
+
+/*!
+ \class QAbstractGraphicsShapeItem
+ \brief The QAbstractGraphicsShapeItem class provides a common base for
+ all path items.
+ \since 4.2
+ \ingroup graphicsview-api
+
+ This class does not fully implement an item by itself; in particular, it
+ does not implement boundingRect() and paint(), which are inherited by
+ QGraphicsItem.
+
+ You can subclass this item to provide a simple base implementation of
+ accessors for the item's pen and brush.
+
+ \sa QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsPathItem,
+ QGraphicsPolygonItem, QGraphicsTextItem, QGraphicsLineItem,
+ QGraphicsPixmapItem, {Graphics View Framework}
+*/
+
+class QAbstractGraphicsShapeItemPrivate : public QGraphicsItemPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractGraphicsShapeItem)
+public:
+
+ QBrush brush;
+ QPen pen;
+
+ // Cached bounding rectangle
+ mutable QRectF boundingRect;
+};
+
+/*!
+ Constructs a QAbstractGraphicsShapeItem. \a parent is passed to
+ QGraphicsItem's constructor.
+*/
+QAbstractGraphicsShapeItem::QAbstractGraphicsShapeItem(QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QGraphicsItem(*new QAbstractGraphicsShapeItemPrivate, parent, scene)
+{
+}
+
+/*!
+ \internal
+*/
+QAbstractGraphicsShapeItem::QAbstractGraphicsShapeItem(QAbstractGraphicsShapeItemPrivate &dd,
+ QGraphicsItem *parent,
+ QGraphicsScene *scene)
+ : QGraphicsItem(dd, parent, scene)
+{
+}
+
+/*!
+ Destroys a QAbstractGraphicsShapeItem.
+*/
+QAbstractGraphicsShapeItem::~QAbstractGraphicsShapeItem()
+{
+}
+
+/*!
+ Returns the item's pen. If no pen has been set, this function returns
+ QPen(), a default black solid line pen with 0 width.
+*/
+QPen QAbstractGraphicsShapeItem::pen() const
+{
+ Q_D(const QAbstractGraphicsShapeItem);
+ return d->pen;
+}
+
+/*!
+ Sets the pen for this item to \a pen.
+
+ The pen is used to draw the item's outline.
+
+ \sa pen()
+*/
+void QAbstractGraphicsShapeItem::setPen(const QPen &pen)
+{
+ Q_D(QAbstractGraphicsShapeItem);
+ if (d->pen == pen)
+ return;
+ prepareGeometryChange();
+ d->pen = pen;
+ d->boundingRect = QRectF();
+ update();
+}
+
+/*!
+ Returns the item's brush, or an empty brush if no brush has been set.
+
+ \sa setBrush()
+*/
+QBrush QAbstractGraphicsShapeItem::brush() const
+{
+ Q_D(const QAbstractGraphicsShapeItem);
+ return d->brush;
+}
+
+/*!
+ Sets the item's brush to \a brush.
+
+ The item's brush is used to fill the item.
+
+ If you use a brush with a QGradient, the gradient
+ is relative to the item's coordinate system.
+
+ \sa brush()
+*/
+void QAbstractGraphicsShapeItem::setBrush(const QBrush &brush)
+{
+ Q_D(QAbstractGraphicsShapeItem);
+ if (d->brush == brush)
+ return;
+ d->brush = brush;
+ update();
+}
+
+/*!
+ \reimp
+*/
+bool QAbstractGraphicsShapeItem::isObscuredBy(const QGraphicsItem *item) const
+{
+ return QGraphicsItem::isObscuredBy(item);
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QAbstractGraphicsShapeItem::opaqueArea() const
+{
+ Q_D(const QAbstractGraphicsShapeItem);
+ if (d->brush.isOpaque())
+ return isClipped() ? clipPath() : shape();
+ return QGraphicsItem::opaqueArea();
+}
+
+/*!
+ \class QGraphicsPathItem
+ \brief The QGraphicsPathItem class provides a path item that you
+ can add to a QGraphicsScene.
+ \since 4.2
+ \ingroup graphicsview-api
+
+ To set the item's path, pass a QPainterPath to QGraphicsPathItem's
+ constructor, or call the setPath() function. The path() function
+ returns the current path.
+
+ \image graphicsview-pathitem.png
+
+ QGraphicsPathItem uses the path to provide a reasonable
+ implementation of boundingRect(), shape(), and contains(). The
+ paint() function draws the path using the item's associated pen
+ and brush, which you can set by calling the setPen() and
+ setBrush() functions.
+
+ \sa QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsPolygonItem,
+ QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
+ View Framework}
+*/
+
+class QGraphicsPathItemPrivate : public QAbstractGraphicsShapeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsPathItem)
+public:
+ QPainterPath path;
+};
+
+/*!
+ Constructs a QGraphicsPath item using \a path as the default path. \a
+ parent is passed to QAbstractGraphicsShapeItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsPathItem::QGraphicsPathItem(const QPainterPath &path,
+ QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsPathItemPrivate, parent, scene)
+{
+ if (!path.isEmpty())
+ setPath(path);
+}
+
+/*!
+ Constructs a QGraphicsPath. \a parent is passed to
+ QAbstractGraphicsShapeItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsPathItem::QGraphicsPathItem(QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsPathItemPrivate, parent, scene)
+{
+}
+
+/*!
+ Destroys the QGraphicsPathItem.
+*/
+QGraphicsPathItem::~QGraphicsPathItem()
+{
+}
+
+/*!
+ Returns the item's path as a QPainterPath. If no item has been set, an
+ empty QPainterPath is returned.
+
+ \sa setPath()
+*/
+QPainterPath QGraphicsPathItem::path() const
+{
+ Q_D(const QGraphicsPathItem);
+ return d->path;
+}
+
+/*!
+ Sets the item's path to be the given \a path.
+
+ \sa path()
+*/
+void QGraphicsPathItem::setPath(const QPainterPath &path)
+{
+ Q_D(QGraphicsPathItem);
+ if (d->path == path)
+ return;
+ prepareGeometryChange();
+ d->path = path;
+ d->boundingRect = QRectF();
+ update();
+}
+
+/*!
+ \reimp
+*/
+QRectF QGraphicsPathItem::boundingRect() const
+{
+ Q_D(const QGraphicsPathItem);
+ if (d->boundingRect.isNull()) {
+ qreal pw = pen().widthF();
+ if (pw == 0.0)
+ d->boundingRect = d->path.controlPointRect();
+ else {
+ d->boundingRect = shape().controlPointRect();
+ }
+ }
+ return d->boundingRect;
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsPathItem::shape() const
+{
+ Q_D(const QGraphicsPathItem);
+ return qt_graphicsItem_shapeFromPath(d->path, d->pen);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsPathItem::contains(const QPointF &point) const
+{
+ return QAbstractGraphicsShapeItem::contains(point);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsPathItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
+{
+ Q_D(QGraphicsPathItem);
+ Q_UNUSED(widget);
+ painter->setPen(d->pen);
+ painter->setBrush(d->brush);
+ painter->drawPath(d->path);
+
+ if (option->state & QStyle::State_Selected)
+ qt_graphicsItem_highlightSelected(this, painter, option);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsPathItem::isObscuredBy(const QGraphicsItem *item) const
+{
+ return QAbstractGraphicsShapeItem::isObscuredBy(item);
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsPathItem::opaqueArea() const
+{
+ return QAbstractGraphicsShapeItem::opaqueArea();
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsPathItem::type() const
+{
+ return Type;
+}
+
+/*!
+ \internal
+*/
+bool QGraphicsPathItem::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension);
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsPathItem::setExtension(Extension extension, const QVariant &variant)
+{
+ Q_UNUSED(extension);
+ Q_UNUSED(variant);
+}
+
+/*!
+ \internal
+*/
+QVariant QGraphicsPathItem::extension(const QVariant &variant) const
+{
+ Q_UNUSED(variant);
+ return QVariant();
+}
+
+/*!
+ \class QGraphicsRectItem
+ \brief The QGraphicsRectItem class provides a rectangle item that you
+ can add to a QGraphicsScene.
+ \since 4.2
+ \ingroup graphicsview-api
+
+ To set the item's rectangle, pass a QRectF to QGraphicsRectItem's
+ constructor, or call the setRect() function. The rect() function
+ returns the current rectangle.
+
+ \image graphicsview-rectitem.png
+
+ QGraphicsRectItem uses the rectangle and the pen width to provide
+ a reasonable implementation of boundingRect(), shape(), and
+ contains(). The paint() function draws the rectangle using the
+ item's associated pen and brush, which you can set by calling the
+ setPen() and setBrush() functions.
+
+ \note The rendering of invalid rectangles, such as those with negative
+ widths or heights, is undefined. If you cannot be sure that you are
+ using valid rectangles (for example, if you are creating
+ rectangles using data from an unreliable source) then you should
+ use QRectF::normalized() to create normalized rectangles, and use
+ those instead.
+
+ \sa QGraphicsPathItem, QGraphicsEllipseItem, QGraphicsPolygonItem,
+ QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
+ View Framework}
+*/
+
+class QGraphicsRectItemPrivate : public QAbstractGraphicsShapeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsRectItem)
+public:
+ QRectF rect;
+};
+
+/*!
+ Constructs a QGraphicsRectItem, using \a rect as the default rectangle.
+ \a parent is passed to QAbstractGraphicsShapeItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsRectItem::QGraphicsRectItem(const QRectF &rect, QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsRectItemPrivate, parent, scene)
+{
+ setRect(rect);
+}
+
+/*!
+ \fn QGraphicsRectItem::QGraphicsRectItem(qreal x, qreal y, qreal width, qreal height,
+ QGraphicsItem *parent)
+
+ Constructs a QGraphicsRectItem with a default rectangle defined
+ by (\a x, \a y) and the given \a width and \a height.
+
+ \a parent is passed to QAbstractGraphicsShapeItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsRectItem::QGraphicsRectItem(qreal x, qreal y, qreal w, qreal h,
+ QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsRectItemPrivate, parent, scene)
+{
+ setRect(QRectF(x, y, w, h));
+}
+
+/*!
+ Constructs a QGraphicsRectItem. \a parent is passed to
+ QAbstractGraphicsShapeItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsRectItem::QGraphicsRectItem(QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsRectItemPrivate, parent, scene)
+{
+}
+
+/*!
+ Destroys the QGraphicsRectItem.
+*/
+QGraphicsRectItem::~QGraphicsRectItem()
+{
+}
+
+/*!
+ Returns the item's rectangle.
+
+ \sa setRect()
+*/
+QRectF QGraphicsRectItem::rect() const
+{
+ Q_D(const QGraphicsRectItem);
+ return d->rect;
+}
+
+/*!
+ \fn void QGraphicsRectItem::setRect(const QRectF &rectangle)
+
+ Sets the item's rectangle to be the given \a rectangle.
+
+ \sa rect()
+*/
+void QGraphicsRectItem::setRect(const QRectF &rect)
+{
+ Q_D(QGraphicsRectItem);
+ if (d->rect == rect)
+ return;
+ prepareGeometryChange();
+ d->rect = rect;
+ d->boundingRect = QRectF();
+ update();
+}
+
+/*!
+ \fn void QGraphicsRectItem::setRect(qreal x, qreal y, qreal width, qreal height)
+ \fn void QGraphicsEllipseItem::setRect(qreal x, qreal y, qreal width, qreal height)
+
+ Sets the item's rectangle to the rectangle defined by (\a x, \a y)
+ and the given \a width and \a height.
+
+ This convenience function is equivalent to calling \c
+ {setRect(QRectF(x, y, width, height))}
+
+ \sa rect()
+*/
+
+/*!
+ \reimp
+*/
+QRectF QGraphicsRectItem::boundingRect() const
+{
+ Q_D(const QGraphicsRectItem);
+ if (d->boundingRect.isNull()) {
+ qreal halfpw = pen().widthF() / 2;
+ d->boundingRect = d->rect;
+ if (halfpw > 0.0)
+ d->boundingRect.adjust(-halfpw, -halfpw, halfpw, halfpw);
+ }
+ return d->boundingRect;
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsRectItem::shape() const
+{
+ Q_D(const QGraphicsRectItem);
+ QPainterPath path;
+ path.addRect(d->rect);
+ return qt_graphicsItem_shapeFromPath(path, d->pen);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsRectItem::contains(const QPointF &point) const
+{
+ return QAbstractGraphicsShapeItem::contains(point);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
+{
+ Q_D(QGraphicsRectItem);
+ Q_UNUSED(widget);
+ painter->setPen(d->pen);
+ painter->setBrush(d->brush);
+ painter->drawRect(d->rect);
+
+ if (option->state & QStyle::State_Selected)
+ qt_graphicsItem_highlightSelected(this, painter, option);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsRectItem::isObscuredBy(const QGraphicsItem *item) const
+{
+ return QAbstractGraphicsShapeItem::isObscuredBy(item);
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsRectItem::opaqueArea() const
+{
+ return QAbstractGraphicsShapeItem::opaqueArea();
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsRectItem::type() const
+{
+ return Type;
+}
+
+/*!
+ \internal
+*/
+bool QGraphicsRectItem::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension);
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsRectItem::setExtension(Extension extension, const QVariant &variant)
+{
+ Q_UNUSED(extension);
+ Q_UNUSED(variant);
+}
+
+/*!
+ \internal
+*/
+QVariant QGraphicsRectItem::extension(const QVariant &variant) const
+{
+ Q_UNUSED(variant);
+ return QVariant();
+}
+
+/*!
+ \class QGraphicsEllipseItem
+ \brief The QGraphicsEllipseItem class provides an ellipse item that you
+ can add to a QGraphicsScene.
+ \since 4.2
+ \ingroup graphicsview-api
+
+ QGraphicsEllipseItem respresents an ellipse with a fill and an outline,
+ and you can also use it for ellipse segments (see startAngle(),
+ spanAngle()).
+
+ \table
+ \row
+ \o \inlineimage graphicsview-ellipseitem.png
+ \o \inlineimage graphicsview-ellipseitem-pie.png
+ \endtable
+
+ To set the item's ellipse, pass a QRectF to QGraphicsEllipseItem's
+ constructor, or call setRect(). The rect() function returns the
+ current ellipse geometry.
+
+ QGraphicsEllipseItem uses the rect and the pen width to provide a
+ reasonable implementation of boundingRect(), shape(), and contains(). The
+ paint() function draws the ellipse using the item's associated pen and
+ brush, which you can set by calling setPen() and setBrush().
+
+ \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsPolygonItem,
+ QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
+ View Framework}
+*/
+
+class QGraphicsEllipseItemPrivate : public QAbstractGraphicsShapeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsEllipseItem)
+public:
+ inline QGraphicsEllipseItemPrivate()
+ : startAngle(0), spanAngle(360 * 16)
+ { }
+
+ QRectF rect;
+ int startAngle;
+ int spanAngle;
+};
+
+/*!
+ Constructs a QGraphicsEllipseItem using \a rect as the default rectangle.
+ \a parent is passed to QAbstractGraphicsShapeItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsEllipseItem::QGraphicsEllipseItem(const QRectF &rect, QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsEllipseItemPrivate, parent, scene)
+{
+ setRect(rect);
+}
+
+/*!
+ \fn QGraphicsEllipseItem::QGraphicsEllipseItem(qreal x, qreal y, qreal width, qreal height, QGraphicsItem *parent)
+ \since 4.3
+
+ Constructs a QGraphicsEllipseItem using the rectangle defined by (\a x, \a
+ y) and the given \a width and \a height, as the default rectangle. \a
+ parent is passed to QAbstractGraphicsShapeItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsEllipseItem::QGraphicsEllipseItem(qreal x, qreal y, qreal w, qreal h,
+ QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsEllipseItemPrivate, parent, scene)
+{
+ setRect(x,y,w,h);
+}
+
+
+
+/*!
+ Constructs a QGraphicsEllipseItem. \a parent is passed to
+ QAbstractGraphicsShapeItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsEllipseItem::QGraphicsEllipseItem(QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsEllipseItemPrivate, parent, scene)
+{
+}
+
+/*!
+ Destroys the QGraphicsEllipseItem.
+*/
+QGraphicsEllipseItem::~QGraphicsEllipseItem()
+{
+}
+
+/*!
+ Returns the item's ellipse geometry as a QRectF.
+
+ \sa setRect(), QPainter::drawEllipse()
+*/
+QRectF QGraphicsEllipseItem::rect() const
+{
+ Q_D(const QGraphicsEllipseItem);
+ return d->rect;
+}
+
+/*!
+ Sets the item's ellipse geometry to \a rect. The rectangle's left edge
+ defines the left edge of the ellipse, and the rectangle's top edge
+ describes the top of the ellipse. The height and width of the rectangle
+ describe the height and width of the ellipse.
+
+ \sa rect(), QPainter::drawEllipse()
+*/
+void QGraphicsEllipseItem::setRect(const QRectF &rect)
+{
+ Q_D(QGraphicsEllipseItem);
+ if (d->rect == rect)
+ return;
+ prepareGeometryChange();
+ d->rect = rect;
+ d->boundingRect = QRectF();
+ update();
+}
+
+/*!
+ Returns the start angle for an ellipse segment in 16ths of a degree. This
+ angle is used together with spanAngle() for representing an ellipse
+ segment (a pie). By default, the start angle is 0.
+
+ \sa setStartAngle(), spanAngle()
+*/
+int QGraphicsEllipseItem::startAngle() const
+{
+ Q_D(const QGraphicsEllipseItem);
+ return d->startAngle;
+}
+
+/*!
+ Sets the start angle for an ellipse segment to \a angle, which is in 16ths
+ of a degree. This angle is used together with spanAngle() for representing
+ an ellipse segment (a pie). By default, the start angle is 0.
+
+ \sa startAngle(), setSpanAngle(), QPainter::drawPie()
+*/
+void QGraphicsEllipseItem::setStartAngle(int angle)
+{
+ Q_D(QGraphicsEllipseItem);
+ if (angle != d->startAngle) {
+ prepareGeometryChange();
+ d->boundingRect = QRectF();
+ d->startAngle = angle;
+ update();
+ }
+}
+
+/*!
+ Returns the span angle of an ellipse segment in 16ths of a degree. This
+ angle is used together with startAngle() for representing an ellipse
+ segment (a pie). By default, this function returns 5760 (360 * 16, a full
+ ellipse).
+
+ \sa setSpanAngle(), startAngle()
+*/
+int QGraphicsEllipseItem::spanAngle() const
+{
+ Q_D(const QGraphicsEllipseItem);
+ return d->spanAngle;
+}
+
+/*!
+ Sets the span angle for an ellipse segment to \a angle, which is in 16ths
+ of a degree. This angle is used together with startAngle() to represent an
+ ellipse segment (a pie). By default, the span angle is 5760 (360 * 16, a
+ full ellipse).
+
+ \sa spanAngle(), setStartAngle(), QPainter::drawPie()
+*/
+void QGraphicsEllipseItem::setSpanAngle(int angle)
+{
+ Q_D(QGraphicsEllipseItem);
+ if (angle != d->spanAngle) {
+ prepareGeometryChange();
+ d->boundingRect = QRectF();
+ d->spanAngle = angle;
+ update();
+ }
+}
+
+/*!
+ \reimp
+*/
+QRectF QGraphicsEllipseItem::boundingRect() const
+{
+ Q_D(const QGraphicsEllipseItem);
+ if (d->boundingRect.isNull()) {
+ qreal pw = pen().widthF();
+ if (pw == 0.0 && d->spanAngle == 360 * 16)
+ d->boundingRect = d->rect;
+ else
+ d->boundingRect = shape().controlPointRect();
+ }
+ return d->boundingRect;
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsEllipseItem::shape() const
+{
+ Q_D(const QGraphicsEllipseItem);
+ QPainterPath path;
+ if (d->rect.isNull())
+ return path;
+ if (d->spanAngle != 360 * 16) {
+ path.moveTo(d->rect.center());
+ path.arcTo(d->rect, d->startAngle / 16.0, d->spanAngle / 16.0);
+ } else {
+ path.addEllipse(d->rect);
+ }
+
+ return qt_graphicsItem_shapeFromPath(path, d->pen);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsEllipseItem::contains(const QPointF &point) const
+{
+ return QAbstractGraphicsShapeItem::contains(point);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsEllipseItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
+{
+ Q_D(QGraphicsEllipseItem);
+ Q_UNUSED(widget);
+ painter->setPen(d->pen);
+ painter->setBrush(d->brush);
+ if ((d->spanAngle != 0) && (qAbs(d->spanAngle) % (360 * 16) == 0))
+ painter->drawEllipse(d->rect);
+ else
+ painter->drawPie(d->rect, d->startAngle, d->spanAngle);
+
+ if (option->state & QStyle::State_Selected)
+ qt_graphicsItem_highlightSelected(this, painter, option);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsEllipseItem::isObscuredBy(const QGraphicsItem *item) const
+{
+ return QAbstractGraphicsShapeItem::isObscuredBy(item);
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsEllipseItem::opaqueArea() const
+{
+ return QAbstractGraphicsShapeItem::opaqueArea();
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsEllipseItem::type() const
+{
+ return Type;
+}
+
+
+/*!
+ \internal
+*/
+bool QGraphicsEllipseItem::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension);
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsEllipseItem::setExtension(Extension extension, const QVariant &variant)
+{
+ Q_UNUSED(extension);
+ Q_UNUSED(variant);
+}
+
+/*!
+ \internal
+*/
+QVariant QGraphicsEllipseItem::extension(const QVariant &variant) const
+{
+ Q_UNUSED(variant);
+ return QVariant();
+}
+
+/*!
+ \class QGraphicsPolygonItem
+ \brief The QGraphicsPolygonItem class provides a polygon item that you
+ can add to a QGraphicsScene.
+ \since 4.2
+ \ingroup graphicsview-api
+
+ To set the item's polygon, pass a QPolygonF to
+ QGraphicsPolygonItem's constructor, or call the setPolygon()
+ function. The polygon() function returns the current polygon.
+
+ \image graphicsview-polygonitem.png
+
+ QGraphicsPolygonItem uses the polygon and the pen width to provide
+ a reasonable implementation of boundingRect(), shape(), and
+ contains(). The paint() function draws the polygon using the
+ item's associated pen and brush, which you can set by calling the
+ setPen() and setBrush() functions.
+
+ \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem,
+ QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
+ View Framework}
+*/
+
+class QGraphicsPolygonItemPrivate : public QAbstractGraphicsShapeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsPolygonItem)
+public:
+ inline QGraphicsPolygonItemPrivate()
+ : fillRule(Qt::OddEvenFill)
+ { }
+
+ QPolygonF polygon;
+ Qt::FillRule fillRule;
+};
+
+/*!
+ Constructs a QGraphicsPolygonItem with \a polygon as the default
+ polygon. \a parent is passed to QAbstractGraphicsShapeItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsPolygonItem::QGraphicsPolygonItem(const QPolygonF &polygon,
+ QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsPolygonItemPrivate, parent, scene)
+{
+ setPolygon(polygon);
+}
+
+/*!
+ Constructs a QGraphicsPolygonItem. \a parent is passed to
+ QAbstractGraphicsShapeItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsPolygonItem::QGraphicsPolygonItem(QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsPolygonItemPrivate, parent, scene)
+{
+}
+
+/*!
+ Destroys the QGraphicsPolygonItem.
+*/
+QGraphicsPolygonItem::~QGraphicsPolygonItem()
+{
+}
+
+/*!
+ Returns the item's polygon, or an empty polygon if no polygon
+ has been set.
+
+ \sa setPolygon()
+*/
+QPolygonF QGraphicsPolygonItem::polygon() const
+{
+ Q_D(const QGraphicsPolygonItem);
+ return d->polygon;
+}
+
+/*!
+ Sets the item's polygon to be the given \a polygon.
+
+ \sa polygon()
+*/
+void QGraphicsPolygonItem::setPolygon(const QPolygonF &polygon)
+{
+ Q_D(QGraphicsPolygonItem);
+ if (d->polygon == polygon)
+ return;
+ prepareGeometryChange();
+ d->polygon = polygon;
+ d->boundingRect = QRectF();
+ update();
+}
+
+/*!
+ Returns the fill rule of the polygon. The default fill rule is
+ Qt::OddEvenFill.
+
+ \sa setFillRule(), QPainterPath::fillRule(), QPainter::drawPolygon()
+*/
+Qt::FillRule QGraphicsPolygonItem::fillRule() const
+{
+ Q_D(const QGraphicsPolygonItem);
+ return d->fillRule;
+}
+
+/*!
+ Sets the fill rule of the polygon to \a rule. The default fill rule is
+ Qt::OddEvenFill.
+
+ \sa fillRule(), QPainterPath::fillRule(), QPainter::drawPolygon()
+*/
+void QGraphicsPolygonItem::setFillRule(Qt::FillRule rule)
+{
+ Q_D(QGraphicsPolygonItem);
+ if (rule != d->fillRule) {
+ d->fillRule = rule;
+ update();
+ }
+}
+
+/*!
+ \reimp
+*/
+QRectF QGraphicsPolygonItem::boundingRect() const
+{
+ Q_D(const QGraphicsPolygonItem);
+ if (d->boundingRect.isNull()) {
+ qreal pw = pen().widthF();
+ if (pw == 0.0)
+ d->boundingRect = d->polygon.boundingRect();
+ else
+ d->boundingRect = shape().controlPointRect();
+ }
+ return d->boundingRect;
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsPolygonItem::shape() const
+{
+ Q_D(const QGraphicsPolygonItem);
+ QPainterPath path;
+ path.addPolygon(d->polygon);
+ return qt_graphicsItem_shapeFromPath(path, d->pen);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsPolygonItem::contains(const QPointF &point) const
+{
+ return QAbstractGraphicsShapeItem::contains(point);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsPolygonItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_D(QGraphicsPolygonItem);
+ Q_UNUSED(widget);
+ painter->setPen(d->pen);
+ painter->setBrush(d->brush);
+ painter->drawPolygon(d->polygon, d->fillRule);
+
+ if (option->state & QStyle::State_Selected)
+ qt_graphicsItem_highlightSelected(this, painter, option);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsPolygonItem::isObscuredBy(const QGraphicsItem *item) const
+{
+ return QAbstractGraphicsShapeItem::isObscuredBy(item);
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsPolygonItem::opaqueArea() const
+{
+ return QAbstractGraphicsShapeItem::opaqueArea();
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsPolygonItem::type() const
+{
+ return Type;
+}
+
+/*!
+ \internal
+*/
+bool QGraphicsPolygonItem::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension);
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsPolygonItem::setExtension(Extension extension, const QVariant &variant)
+{
+ Q_UNUSED(extension);
+ Q_UNUSED(variant);
+}
+
+/*!
+ \internal
+*/
+QVariant QGraphicsPolygonItem::extension(const QVariant &variant) const
+{
+ Q_UNUSED(variant);
+ return QVariant();
+}
+
+/*!
+ \class QGraphicsLineItem
+ \brief The QGraphicsLineItem class provides a line item that you can add to a
+ QGraphicsScene.
+ \since 4.2
+ \ingroup graphicsview-api
+
+ To set the item's line, pass a QLineF to QGraphicsLineItem's
+ constructor, or call the setLine() function. The line() function
+ returns the current line. By default the line is black with a
+ width of 0, but you can change this by calling setPen().
+
+ \img graphicsview-lineitem.png
+
+ QGraphicsLineItem uses the line and the pen width to provide a reasonable
+ implementation of boundingRect(), shape(), and contains(). The paint()
+ function draws the line using the item's associated pen.
+
+ \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem,
+ QGraphicsTextItem, QGraphicsPolygonItem, QGraphicsPixmapItem,
+ {Graphics View Framework}
+*/
+
+class QGraphicsLineItemPrivate : public QGraphicsItemPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsLineItem)
+public:
+ QLineF line;
+ QPen pen;
+};
+
+/*!
+ Constructs a QGraphicsLineItem, using \a line as the default line. \a
+ parent is passed to QGraphicsItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsLineItem::QGraphicsLineItem(const QLineF &line, QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QGraphicsItem(*new QGraphicsLineItemPrivate, parent, scene)
+{
+ setLine(line);
+}
+
+/*!
+ Constructs a QGraphicsLineItem, using the line between (\a x1, \a y1) and
+ (\a x2, \a y2) as the default line. \a parent is passed to
+ QGraphicsItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsLineItem::QGraphicsLineItem(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QGraphicsItem(*new QGraphicsLineItemPrivate, parent, scene)
+{
+ setLine(x1, y1, x2, y2);
+}
+
+
+
+/*!
+ Constructs a QGraphicsLineItem. \a parent is passed to QGraphicsItem's
+ constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsLineItem::QGraphicsLineItem(QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QGraphicsItem(*new QGraphicsLineItemPrivate, parent, scene)
+{
+}
+
+/*!
+ Destroys the QGraphicsLineItem.
+*/
+QGraphicsLineItem::~QGraphicsLineItem()
+{
+}
+
+/*!
+ Returns the item's pen, or a black solid 0-width pen if no pen has
+ been set.
+
+ \sa setPen()
+*/
+QPen QGraphicsLineItem::pen() const
+{
+ Q_D(const QGraphicsLineItem);
+ return d->pen;
+}
+
+/*!
+ Sets the item's pen to \a pen. If no pen is set, the line will be painted
+ using a black solid 0-width pen.
+
+ \sa pen()
+*/
+void QGraphicsLineItem::setPen(const QPen &pen)
+{
+ Q_D(QGraphicsLineItem);
+ if (d->pen == pen)
+ return;
+ prepareGeometryChange();
+ d->pen = pen;
+ update();
+}
+
+/*!
+ Returns the item's line, or a null line if no line has been set.
+
+ \sa setLine()
+*/
+QLineF QGraphicsLineItem::line() const
+{
+ Q_D(const QGraphicsLineItem);
+ return d->line;
+}
+
+/*!
+ Sets the item's line to be the given \a line.
+
+ \sa line()
+*/
+void QGraphicsLineItem::setLine(const QLineF &line)
+{
+ Q_D(QGraphicsLineItem);
+ if (d->line == line)
+ return;
+ prepareGeometryChange();
+ d->line = line;
+ update();
+}
+
+/*!
+ \fn void QGraphicsLineItem::setLine(qreal x1, qreal y1, qreal x2, qreal y2)
+ \overload
+
+ Sets the item's line to be the line between (\a x1, \a y1) and (\a
+ x2, \a y2).
+
+ This is the same as calling \c {setLine(QLineF(x1, y1, x2, y2))}.
+*/
+
+/*!
+ \reimp
+*/
+QRectF QGraphicsLineItem::boundingRect() const
+{
+ Q_D(const QGraphicsLineItem);
+ if (d->pen.widthF() == 0.0) {
+ const qreal x1 = d->line.p1().x();
+ const qreal x2 = d->line.p2().x();
+ const qreal y1 = d->line.p1().y();
+ const qreal y2 = d->line.p2().y();
+ qreal lx = qMin(x1, x2);
+ qreal rx = qMax(x1, x2);
+ qreal ty = qMin(y1, y2);
+ qreal by = qMax(y1, y2);
+ return QRectF(lx, ty, rx - lx, by - ty);
+ }
+ return shape().controlPointRect();
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsLineItem::shape() const
+{
+ Q_D(const QGraphicsLineItem);
+ QPainterPath path;
+ if (d->line == QLineF())
+ return path;
+
+ path.moveTo(d->line.p1());
+ path.lineTo(d->line.p2());
+ return qt_graphicsItem_shapeFromPath(path, d->pen);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsLineItem::contains(const QPointF &point) const
+{
+ return QGraphicsItem::contains(point);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsLineItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_D(QGraphicsLineItem);
+ Q_UNUSED(widget);
+ painter->setPen(d->pen);
+ painter->drawLine(d->line);
+
+ if (option->state & QStyle::State_Selected)
+ qt_graphicsItem_highlightSelected(this, painter, option);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsLineItem::isObscuredBy(const QGraphicsItem *item) const
+{
+ return QGraphicsItem::isObscuredBy(item);
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsLineItem::opaqueArea() const
+{
+ return QGraphicsItem::opaqueArea();
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsLineItem::type() const
+{
+ return Type;
+}
+
+/*!
+ \internal
+*/
+bool QGraphicsLineItem::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension);
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsLineItem::setExtension(Extension extension, const QVariant &variant)
+{
+ Q_UNUSED(extension);
+ Q_UNUSED(variant);
+}
+
+/*!
+ \internal
+*/
+QVariant QGraphicsLineItem::extension(const QVariant &variant) const
+{
+ Q_UNUSED(variant);
+ return QVariant();
+}
+
+/*!
+ \class QGraphicsPixmapItem
+ \brief The QGraphicsPixmapItem class provides a pixmap item that you can add to
+ a QGraphicsScene.
+ \since 4.2
+ \ingroup graphicsview-api
+
+ To set the item's pixmap, pass a QPixmap to QGraphicsPixmapItem's
+ constructor, or call the setPixmap() function. The pixmap()
+ function returns the current pixmap.
+
+ QGraphicsPixmapItem uses pixmap's optional alpha mask to provide a
+ reasonable implementation of boundingRect(), shape(), and contains().
+
+ \image graphicsview-pixmapitem.png
+
+ The pixmap is drawn at the item's (0, 0) coordinate, as returned by
+ offset(). You can change the drawing offset by calling setOffset().
+
+ You can set the pixmap's transformation mode by calling
+ setTransformationMode(). By default, Qt::FastTransformation is used, which
+ provides fast, non-smooth scaling. Qt::SmoothTransformation enables
+ QPainter::SmoothPixmapTransform on the painter, and the quality depends on
+ the platform and viewport. The result is usually not as good as calling
+ QPixmap::scale() directly. Call transformationMode() to get the current
+ transformation mode for the item.
+
+ \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem,
+ QGraphicsTextItem, QGraphicsPolygonItem, QGraphicsLineItem,
+ {Graphics View Framework}
+*/
+
+/*!
+ \enum QGraphicsPixmapItem::ShapeMode
+
+ This enum describes how QGraphicsPixmapItem calculates its shape and
+ opaque area.
+
+ The default value is MaskShape.
+
+ \value MaskShape The shape is determined by calling QPixmap::mask().
+ This shape includes only the opaque pixels of the pixmap.
+ Because the shape is more complex, however, it can be slower than the other modes,
+ and uses more memory.
+
+ \value BoundingRectShape The shape is determined by tracing the outline of
+ the pixmap. This is the fastest shape mode, but it does not take into account
+ any transparent areas on the pixmap.
+
+ \value HeuristicMaskShape The shape is determine by calling
+ QPixmap::createHeuristicMask(). The performance and memory consumption
+ is similar to MaskShape.
+*/
+extern QPainterPath qt_regionToPath(const QRegion &region);
+
+class QGraphicsPixmapItemPrivate : public QGraphicsItemPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsPixmapItem)
+public:
+ QGraphicsPixmapItemPrivate()
+ : transformationMode(Qt::FastTransformation),
+ shapeMode(QGraphicsPixmapItem::MaskShape),
+ hasShape(false)
+ {}
+
+ QPixmap pixmap;
+ Qt::TransformationMode transformationMode;
+ QPointF offset;
+ QGraphicsPixmapItem::ShapeMode shapeMode;
+ QPainterPath shape;
+ bool hasShape;
+
+ void updateShape()
+ {
+ shape = QPainterPath();
+ switch (shapeMode) {
+ case QGraphicsPixmapItem::MaskShape: {
+ QBitmap mask = pixmap.mask();
+ if (!mask.isNull()) {
+ shape = qt_regionToPath(QRegion(mask).translated(offset.toPoint()));
+ break;
+ }
+ // FALL THROUGH
+ }
+ case QGraphicsPixmapItem::BoundingRectShape:
+ shape.addRect(QRectF(offset.x(), offset.y(), pixmap.width(), pixmap.height()));
+ break;
+ case QGraphicsPixmapItem::HeuristicMaskShape:
+#ifndef QT_NO_IMAGE_HEURISTIC_MASK
+ shape = qt_regionToPath(QRegion(pixmap.createHeuristicMask()).translated(offset.toPoint()));
+#else
+ shape.addRect(QRectF(offset.x(), offset.y(), pixmap.width(), pixmap.height()));
+#endif
+ break;
+ }
+ }
+};
+
+/*!
+ Constructs a QGraphicsPixmapItem, using \a pixmap as the default pixmap.
+ \a parent is passed to QGraphicsItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsPixmapItem::QGraphicsPixmapItem(const QPixmap &pixmap,
+ QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QGraphicsItem(*new QGraphicsPixmapItemPrivate, parent, scene)
+{
+ setPixmap(pixmap);
+}
+
+/*!
+ Constructs a QGraphicsPixmapItem. \a parent is passed to QGraphicsItem's
+ constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsPixmapItem::QGraphicsPixmapItem(QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QGraphicsItem(*new QGraphicsPixmapItemPrivate, parent, scene)
+{
+}
+
+/*!
+ Destroys the QGraphicsPixmapItem.
+*/
+QGraphicsPixmapItem::~QGraphicsPixmapItem()
+{
+}
+
+/*!
+ Sets the item's pixmap to \a pixmap.
+
+ \sa pixmap()
+*/
+void QGraphicsPixmapItem::setPixmap(const QPixmap &pixmap)
+{
+ Q_D(QGraphicsPixmapItem);
+ prepareGeometryChange();
+ d->pixmap = pixmap;
+ d->hasShape = false;
+ update();
+}
+
+/*!
+ Returns the item's pixmap, or an invalid QPixmap if no pixmap has been
+ set.
+
+ \sa setPixmap()
+*/
+QPixmap QGraphicsPixmapItem::pixmap() const
+{
+ Q_D(const QGraphicsPixmapItem);
+ return d->pixmap;
+}
+
+/*!
+ Returns the transformation mode of the pixmap. The default mode is
+ Qt::FastTransformation, which provides quick transformation with no
+ smoothing.
+
+ \sa setTransformationMode()
+*/
+Qt::TransformationMode QGraphicsPixmapItem::transformationMode() const
+{
+ Q_D(const QGraphicsPixmapItem);
+ return d->transformationMode;
+}
+
+/*!
+ Sets the pixmap item's transformation mode to \a mode, and toggles an
+ update of the item. The default mode is Qt::FastTransformation, which
+ provides quick transformation with no smoothing.
+
+ Qt::SmoothTransformation enables QPainter::SmoothPixmapTransform on the
+ painter, and the quality depends on the platform and viewport. The result
+ is usually not as good as calling QPixmap::scale() directly.
+
+ \sa transformationMode()
+*/
+void QGraphicsPixmapItem::setTransformationMode(Qt::TransformationMode mode)
+{
+ Q_D(QGraphicsPixmapItem);
+ if (mode != d->transformationMode) {
+ d->transformationMode = mode;
+ update();
+ }
+}
+
+/*!
+ Returns the pixmap item's \e offset, which defines the point of the
+ top-left corner of the pixmap, in local coordinates.
+
+ \sa setOffset()
+*/
+QPointF QGraphicsPixmapItem::offset() const
+{
+ Q_D(const QGraphicsPixmapItem);
+ return d->offset;
+}
+
+/*!
+ Sets the pixmap item's offset to \a offset. QGraphicsPixmapItem will draw
+ its pixmap using \a offset for its top-left corner.
+
+ \sa offset()
+*/
+void QGraphicsPixmapItem::setOffset(const QPointF &offset)
+{
+ Q_D(QGraphicsPixmapItem);
+ if (d->offset == offset)
+ return;
+ prepareGeometryChange();
+ d->offset = offset;
+ d->hasShape = false;
+ update();
+}
+
+/*!
+ \fn void QGraphicsPixmapItem::setOffset(qreal x, qreal y)
+ \since 4.3
+
+ This convenience function is equivalent to calling setOffset(QPointF(\a x, \a y)).
+*/
+
+/*!
+ \reimp
+*/
+QRectF QGraphicsPixmapItem::boundingRect() const
+{
+ Q_D(const QGraphicsPixmapItem);
+ if (d->pixmap.isNull())
+ return QRectF();
+ if (d->flags & ItemIsSelectable) {
+ qreal pw = 1.0;
+ return QRectF(d->offset, d->pixmap.size()).adjusted(-pw/2, -pw/2, pw/2, pw/2);
+ } else {
+ return QRectF(d->offset, d->pixmap.size());
+ }
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsPixmapItem::shape() const
+{
+ Q_D(const QGraphicsPixmapItem);
+ if (!d->hasShape) {
+ QGraphicsPixmapItemPrivate *thatD = const_cast<QGraphicsPixmapItemPrivate *>(d);
+ thatD->updateShape();
+ thatD->hasShape = true;
+ }
+ return d_func()->shape;
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsPixmapItem::contains(const QPointF &point) const
+{
+ return QGraphicsItem::contains(point);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
+{
+ Q_D(QGraphicsPixmapItem);
+ Q_UNUSED(widget);
+
+ painter->setRenderHint(QPainter::SmoothPixmapTransform,
+ (d->transformationMode == Qt::SmoothTransformation));
+
+ painter->drawPixmap(d->offset, d->pixmap);
+
+ if (option->state & QStyle::State_Selected)
+ qt_graphicsItem_highlightSelected(this, painter, option);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsPixmapItem::isObscuredBy(const QGraphicsItem *item) const
+{
+ return QGraphicsItem::isObscuredBy(item);
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsPixmapItem::opaqueArea() const
+{
+ return shape();
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsPixmapItem::type() const
+{
+ return Type;
+}
+
+/*!
+ Returns the item's shape mode. The shape mode describes how
+ QGraphicsPixmapItem calculates its shape. The default mode is MaskShape.
+
+ \sa setShapeMode(), ShapeMode
+*/
+QGraphicsPixmapItem::ShapeMode QGraphicsPixmapItem::shapeMode() const
+{
+ return d_func()->shapeMode;
+}
+
+/*!
+ Sets the item's shape mode to \a mode. The shape mode describes how
+ QGraphicsPixmapItem calculates its shape. The default mode is MaskShape.
+
+ \sa shapeMode(), ShapeMode
+*/
+void QGraphicsPixmapItem::setShapeMode(ShapeMode mode)
+{
+ Q_D(QGraphicsPixmapItem);
+ if (d->shapeMode == mode)
+ return;
+ d->shapeMode = mode;
+ d->hasShape = false;
+}
+
+/*!
+ \internal
+*/
+bool QGraphicsPixmapItem::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension);
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsPixmapItem::setExtension(Extension extension, const QVariant &variant)
+{
+ Q_UNUSED(extension);
+ Q_UNUSED(variant);
+}
+
+/*!
+ \internal
+*/
+QVariant QGraphicsPixmapItem::extension(const QVariant &variant) const
+{
+ Q_UNUSED(variant);
+ return QVariant();
+}
+
+/*!
+ \class QGraphicsTextItem
+ \brief The QGraphicsTextItem class provides a text item that you can add to
+ a QGraphicsScene to display formatted text.
+ \since 4.2
+ \ingroup graphicsview-api
+
+ If you only need to show plain text in an item, consider using QGraphicsSimpleTextItem
+ instead.
+
+ To set the item's text, pass a QString to QGraphicsTextItem's
+ constructor, or call setHtml()/setPlainText().
+
+ QGraphicsTextItem uses the text's formatted size and the associated font
+ to provide a reasonable implementation of boundingRect(), shape(),
+ and contains(). You can set the font by calling setFont().
+
+ It is possible to make the item editable by setting the Qt::TextEditorInteraction flag
+ using setTextInteractionFlags().
+
+ The item's preferred text width can be set using setTextWidth() and obtained
+ using textWidth().
+
+ \note In order to align HTML text in the center, the item's text width must be set.
+
+ \img graphicsview-textitem.png
+
+ \note QGraphicsTextItem accepts \l{QGraphicsItem::acceptHoverEvents()}{hover events}
+ by default. You can change this with \l{QGraphicsItem::}{setAcceptHoverEvents()}.
+
+ \sa QGraphicsSimpleTextItem, QGraphicsPathItem, QGraphicsRectItem,
+ QGraphicsEllipseItem, QGraphicsPixmapItem, QGraphicsPolygonItem,
+ QGraphicsLineItem, {Graphics View Framework}
+*/
+
+class QGraphicsTextItemPrivate
+{
+public:
+ QGraphicsTextItemPrivate()
+ : control(0), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false), clickCausedFocus(0)
+ { }
+
+ mutable QTextControl *control;
+ QTextControl *textControl() const;
+
+ inline QPointF controlOffset() const
+ { return QPointF(0., pageNumber * control->document()->pageSize().height()); }
+ inline void sendControlEvent(QEvent *e)
+ { if (control) control->processEvent(e, controlOffset()); }
+
+ void _q_updateBoundingRect(const QSizeF &);
+ void _q_update(QRectF);
+ void _q_ensureVisible(QRectF);
+ bool _q_mouseOnEdge(QGraphicsSceneMouseEvent *);
+
+ QRectF boundingRect;
+ int pageNumber;
+ bool useDefaultImpl;
+ bool tabChangesFocus;
+
+ uint clickCausedFocus : 1;
+
+ QGraphicsTextItem *qq;
+};
+
+
+/*!
+ Constructs a QGraphicsTextItem, using \a text as the default plain
+ text. \a parent is passed to QGraphicsItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsTextItem::QGraphicsTextItem(const QString &text, QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QGraphicsObject(*new QGraphicsItemPrivate, parent, scene), dd(new QGraphicsTextItemPrivate)
+{
+ dd->qq = this;
+ if (!text.isEmpty())
+ setPlainText(text);
+ setAcceptDrops(true);
+ setAcceptHoverEvents(true);
+ setFlags(ItemUsesExtendedStyleOption);
+}
+
+/*!
+ Constructs a QGraphicsTextItem. \a parent is passed to QGraphicsItem's
+ constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsTextItem::QGraphicsTextItem(QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QGraphicsObject(*new QGraphicsItemPrivate, parent, scene), dd(new QGraphicsTextItemPrivate)
+{
+ dd->qq = this;
+ setAcceptDrops(true);
+ setAcceptHoverEvents(true);
+ setFlag(ItemUsesExtendedStyleOption);
+}
+
+/*!
+ Destroys the QGraphicsTextItem.
+*/
+QGraphicsTextItem::~QGraphicsTextItem()
+{
+ delete dd;
+}
+
+/*!
+ Returns the item's text converted to HTML, or an empty QString if no text has been set.
+
+ \sa setHtml()
+*/
+QString QGraphicsTextItem::toHtml() const
+{
+#ifndef QT_NO_TEXTHTMLPARSER
+ if (dd->control)
+ return dd->control->toHtml();
+#endif
+ return QString();
+}
+
+/*!
+ Sets the item's text to \a text, assuming that text is HTML formatted. If
+ the item has keyboard input focus, this function will also call
+ ensureVisible() to ensure that the text is visible in all viewports.
+
+ \sa toHtml(), hasFocus(), QGraphicsSimpleTextItem
+*/
+void QGraphicsTextItem::setHtml(const QString &text)
+{
+ dd->textControl()->setHtml(text);
+}
+
+/*!
+ Returns the item's text converted to plain text, or an empty QString if no text has been set.
+
+ \sa setPlainText()
+*/
+QString QGraphicsTextItem::toPlainText() const
+{
+ if (dd->control)
+ return dd->control->toPlainText();
+ return QString();
+}
+
+/*!
+ Sets the item's text to \a text. If the item has keyboard input focus,
+ this function will also call ensureVisible() to ensure that the text is
+ visible in all viewports.
+
+ \sa toHtml(), hasFocus()
+*/
+void QGraphicsTextItem::setPlainText(const QString &text)
+{
+ dd->textControl()->setPlainText(text);
+}
+
+/*!
+ Returns the item's font, which is used to render the text.
+
+ \sa setFont()
+*/
+QFont QGraphicsTextItem::font() const
+{
+ if (!dd->control)
+ return QFont();
+ return dd->control->document()->defaultFont();
+}
+
+/*!
+ Sets the font used to render the text item to \a font.
+
+ \sa font()
+*/
+void QGraphicsTextItem::setFont(const QFont &font)
+{
+ dd->textControl()->document()->setDefaultFont(font);
+}
+
+/*!
+ Sets the color for unformatted text to \a col.
+*/
+void QGraphicsTextItem::setDefaultTextColor(const QColor &col)
+{
+ QTextControl *c = dd->textControl();
+ QPalette pal = c->palette();
+ QColor old = pal.color(QPalette::Text);
+ pal.setColor(QPalette::Text, col);
+ c->setPalette(pal);
+ if (old != col)
+ update();
+}
+
+/*!
+ Returns the default text color that is used to for unformatted text.
+*/
+QColor QGraphicsTextItem::defaultTextColor() const
+{
+ return dd->textControl()->palette().color(QPalette::Text);
+}
+
+/*!
+ \reimp
+*/
+QRectF QGraphicsTextItem::boundingRect() const
+{
+ return dd->boundingRect;
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsTextItem::shape() const
+{
+ if (!dd->control)
+ return QPainterPath();
+ QPainterPath path;
+ path.addRect(dd->boundingRect);
+ return path;
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsTextItem::contains(const QPointF &point) const
+{
+ return dd->boundingRect.contains(point);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
+{
+ Q_UNUSED(widget);
+ if (dd->control) {
+ painter->save();
+ QRectF r = option->exposedRect;
+ painter->translate(-dd->controlOffset());
+ r.translate(dd->controlOffset());
+
+ QTextDocument *doc = dd->control->document();
+ QTextDocumentLayout *layout = qobject_cast<QTextDocumentLayout *>(doc->documentLayout());
+
+ // the layout might need to expand the root frame to
+ // the viewport if NoWrap is set
+ if (layout)
+ layout->setViewport(dd->boundingRect);
+
+ dd->control->drawContents(painter, r);
+
+ if (layout)
+ layout->setViewport(QRect());
+
+ painter->restore();
+ }
+
+ if (option->state & (QStyle::State_Selected | QStyle::State_HasFocus))
+ qt_graphicsItem_highlightSelected(this, painter, option);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsTextItem::isObscuredBy(const QGraphicsItem *item) const
+{
+ return QGraphicsItem::isObscuredBy(item);
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsTextItem::opaqueArea() const
+{
+ return QGraphicsItem::opaqueArea();
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsTextItem::type() const
+{
+ return Type;
+}
+
+/*!
+ Sets the preferred width for the item's text. If the actual text
+ is wider than the specified width then it will be broken into
+ multiple lines.
+
+ If \a width is set to -1 then the text will not be broken into
+ multiple lines unless it is enforced through an explicit line
+ break or a new paragraph.
+
+ The default value is -1.
+
+ Note that QGraphicsTextItem keeps a QTextDocument internally,
+ which is used to calculate the text width.
+
+ \sa textWidth(), QTextDocument::setTextWidth()
+*/
+void QGraphicsTextItem::setTextWidth(qreal width)
+{
+ dd->textControl()->setTextWidth(width);
+}
+
+/*!
+ Returns the text width.
+
+ The width is calculated with the QTextDocument that
+ QGraphicsTextItem keeps internally.
+
+ \sa setTextWidth(), QTextDocument::textWidth()
+*/
+qreal QGraphicsTextItem::textWidth() const
+{
+ if (!dd->control)
+ return -1;
+ return dd->control->textWidth();
+}
+
+/*!
+ Adjusts the text item to a reasonable size.
+*/
+void QGraphicsTextItem::adjustSize()
+{
+ if (dd->control)
+ dd->control->adjustSize();
+}
+
+/*!
+ Sets the text document \a document on the item.
+*/
+void QGraphicsTextItem::setDocument(QTextDocument *document)
+{
+ dd->textControl()->setDocument(document);
+ dd->_q_updateBoundingRect(dd->control->size());
+}
+
+/*!
+ Returns the item's text document.
+*/
+QTextDocument *QGraphicsTextItem::document() const
+{
+ return dd->textControl()->document();
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsTextItem::sceneEvent(QEvent *event)
+{
+ QEvent::Type t = event->type();
+ if (!dd->tabChangesFocus && (t == QEvent::KeyPress || t == QEvent::KeyRelease)) {
+ int k = ((QKeyEvent *)event)->key();
+ if (k == Qt::Key_Tab || k == Qt::Key_Backtab) {
+ dd->sendControlEvent(event);
+ return true;
+ }
+ }
+ bool result = QGraphicsItem::sceneEvent(event);
+
+ // Ensure input context is updated.
+ switch (event->type()) {
+ case QEvent::ContextMenu:
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ case QEvent::GraphicsSceneDragEnter:
+ case QEvent::GraphicsSceneDragLeave:
+ case QEvent::GraphicsSceneDragMove:
+ case QEvent::GraphicsSceneDrop:
+ case QEvent::GraphicsSceneHoverEnter:
+ case QEvent::GraphicsSceneHoverLeave:
+ case QEvent::GraphicsSceneHoverMove:
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ // Reset the focus widget's input context, regardless
+ // of how this item gained or lost focus.
+ if (QWidget *fw = qApp->focusWidget()) {
+#ifndef QT_NO_IM
+ if (QInputContext *qic = fw->inputContext()) {
+ if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut)
+ qic->reset();
+ else
+ qic->update();
+ }
+#endif //QT_NO_IM
+ }
+ break;
+ case QEvent::ShortcutOverride:
+ dd->sendControlEvent(event);
+ return true;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ if ((QGraphicsItem::d_ptr->flags & (ItemIsSelectable | ItemIsMovable))
+ && (event->buttons() & Qt::LeftButton) && dd->_q_mouseOnEdge(event)) {
+ // User left-pressed on edge of selectable/movable item, use
+ // base impl.
+ dd->useDefaultImpl = true;
+ } else if (event->buttons() == event->button()
+ && dd->control->textInteractionFlags() == Qt::NoTextInteraction) {
+ // User pressed first button on non-interactive item.
+ dd->useDefaultImpl = true;
+ }
+ if (dd->useDefaultImpl) {
+ QGraphicsItem::mousePressEvent(event);
+ if (!event->isAccepted())
+ dd->useDefaultImpl = false;
+ return;
+ }
+
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (dd->useDefaultImpl) {
+ QGraphicsItem::mouseMoveEvent(event);
+ return;
+ }
+
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (dd->useDefaultImpl) {
+ QGraphicsItem::mouseReleaseEvent(event);
+ if (dd->control->textInteractionFlags() == Qt::NoTextInteraction
+ && !event->buttons()) {
+ // User released last button on non-interactive item.
+ dd->useDefaultImpl = false;
+ } else if ((event->buttons() & Qt::LeftButton) == 0) {
+ // User released the left button on an interactive item.
+ dd->useDefaultImpl = false;
+ }
+ return;
+ }
+
+ QWidget *widget = event->widget();
+ if (widget && (dd->control->textInteractionFlags() & Qt::TextEditable) && boundingRect().contains(event->pos())) {
+ qt_widget_private(widget)->handleSoftwareInputPanel(event->button(), dd->clickCausedFocus);
+ }
+ dd->clickCausedFocus = 0;
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (dd->useDefaultImpl) {
+ QGraphicsItem::mouseDoubleClickEvent(event);
+ return;
+ }
+
+ if (!hasFocus()) {
+ QGraphicsItem::mouseDoubleClickEvent(event);
+ return;
+ }
+
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
+{
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::keyPressEvent(QKeyEvent *event)
+{
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::keyReleaseEvent(QKeyEvent *event)
+{
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::focusInEvent(QFocusEvent *event)
+{
+ dd->sendControlEvent(event);
+ if (event->reason() == Qt::MouseFocusReason) {
+ dd->clickCausedFocus = 1;
+ }
+ update();
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::focusOutEvent(QFocusEvent *event)
+{
+ dd->sendControlEvent(event);
+ update();
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
+{
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
+{
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
+{
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::dropEvent(QGraphicsSceneDragDropEvent *event)
+{
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::inputMethodEvent(QInputMethodEvent *event)
+{
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsTextItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ dd->sendControlEvent(event);
+}
+
+/*!
+ \reimp
+*/
+QVariant QGraphicsTextItem::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ QVariant v;
+ if (dd->control)
+ v = dd->control->inputMethodQuery(query);
+ if (v.type() == QVariant::RectF)
+ v = v.toRectF().translated(-dd->controlOffset());
+ else if (v.type() == QVariant::PointF)
+ v = v.toPointF() - dd->controlOffset();
+ else if (v.type() == QVariant::Rect)
+ v = v.toRect().translated(-dd->controlOffset().toPoint());
+ else if (v.type() == QVariant::Point)
+ v = v.toPoint() - dd->controlOffset().toPoint();
+ return v;
+}
+
+/*!
+ \internal
+*/
+bool QGraphicsTextItem::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension);
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsTextItem::setExtension(Extension extension, const QVariant &variant)
+{
+ Q_UNUSED(extension);
+ Q_UNUSED(variant);
+}
+
+/*!
+ \internal
+*/
+QVariant QGraphicsTextItem::extension(const QVariant &variant) const
+{
+ Q_UNUSED(variant);
+ return QVariant();
+}
+
+/*!
+ \internal
+*/
+void QGraphicsTextItemPrivate::_q_update(QRectF rect)
+{
+ if (rect.isValid()) {
+ rect.translate(-controlOffset());
+ } else {
+ rect = boundingRect;
+ }
+ if (rect.intersects(boundingRect))
+ qq->update(rect);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsTextItemPrivate::_q_updateBoundingRect(const QSizeF &size)
+{
+ if (!control) return; // can't happen
+ const QSizeF pageSize = control->document()->pageSize();
+ // paged items have a constant (page) size
+ if (size == boundingRect.size() || pageSize.height() != -1)
+ return;
+ qq->prepareGeometryChange();
+ boundingRect.setSize(size);
+ qq->update();
+}
+
+/*!
+ \internal
+*/
+void QGraphicsTextItemPrivate::_q_ensureVisible(QRectF rect)
+{
+ if (qq->hasFocus()) {
+ rect.translate(-controlOffset());
+ qq->ensureVisible(rect, /*xmargin=*/0, /*ymargin=*/0);
+ }
+}
+
+QTextControl *QGraphicsTextItemPrivate::textControl() const
+{
+ if (!control) {
+ QGraphicsTextItem *that = const_cast<QGraphicsTextItem *>(qq);
+ control = new QTextControl(that);
+ control->setTextInteractionFlags(Qt::NoTextInteraction);
+
+ QObject::connect(control, SIGNAL(updateRequest(QRectF)),
+ qq, SLOT(_q_update(QRectF)));
+ QObject::connect(control, SIGNAL(documentSizeChanged(QSizeF)),
+ qq, SLOT(_q_updateBoundingRect(QSizeF)));
+ QObject::connect(control, SIGNAL(visibilityRequest(QRectF)),
+ qq, SLOT(_q_ensureVisible(QRectF)));
+ QObject::connect(control, SIGNAL(linkActivated(QString)),
+ qq, SIGNAL(linkActivated(QString)));
+ QObject::connect(control, SIGNAL(linkHovered(QString)),
+ qq, SIGNAL(linkHovered(QString)));
+
+ const QSizeF pgSize = control->document()->pageSize();
+ if (pgSize.height() != -1) {
+ qq->prepareGeometryChange();
+ that->dd->boundingRect.setSize(pgSize);
+ qq->update();
+ } else {
+ that->dd->_q_updateBoundingRect(control->size());
+ }
+ }
+ return control;
+}
+
+/*!
+ \internal
+*/
+bool QGraphicsTextItemPrivate::_q_mouseOnEdge(QGraphicsSceneMouseEvent *event)
+{
+ QPainterPath path;
+ path.addRect(qq->boundingRect());
+
+ QPainterPath docPath;
+ const QTextFrameFormat format = control->document()->rootFrame()->frameFormat();
+ docPath.addRect(
+ qq->boundingRect().adjusted(
+ format.leftMargin(),
+ format.topMargin(),
+ -format.rightMargin(),
+ -format.bottomMargin()));
+
+ return path.subtracted(docPath).contains(event->pos());
+}
+
+/*!
+ \fn QGraphicsTextItem::linkActivated(const QString &link)
+
+ This signal is emitted when the user clicks on a link on a text item
+ that enables Qt::LinksAccessibleByMouse or Qt::LinksAccessibleByKeyboard.
+ \a link is the link that was clicked.
+
+ \sa setTextInteractionFlags()
+*/
+
+/*!
+ \fn QGraphicsTextItem::linkHovered(const QString &link)
+
+ This signal is emitted when the user hovers over a link on a text item
+ that enables Qt::LinksAccessibleByMouse. \a link is
+ the link that was hovered over.
+
+ \sa setTextInteractionFlags()
+*/
+
+/*!
+ Sets the flags \a flags to specify how the text item should react to user
+ input.
+
+ The default for a QGraphicsTextItem is Qt::NoTextInteraction. This function
+ also affects the ItemIsFocusable QGraphicsItem flag by setting it if \a flags
+ is different from Qt::NoTextInteraction and clearing it otherwise.
+
+ By default, the text is read-only. To transform the item into an editor,
+ set the Qt::TextEditable flag.
+*/
+void QGraphicsTextItem::setTextInteractionFlags(Qt::TextInteractionFlags flags)
+{
+ if (flags == Qt::NoTextInteraction)
+ setFlags(this->flags() & ~(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod));
+ else
+ setFlags(this->flags() | QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod);
+
+ dd->textControl()->setTextInteractionFlags(flags);
+}
+
+/*!
+ Returns the current text interaction flags.
+
+ \sa setTextInteractionFlags()
+*/
+Qt::TextInteractionFlags QGraphicsTextItem::textInteractionFlags() const
+{
+ if (!dd->control)
+ return Qt::NoTextInteraction;
+ return dd->control->textInteractionFlags();
+}
+
+/*!
+ \since 4.5
+
+ If \a b is true, the \gui Tab key will cause the widget to change focus;
+ otherwise, the tab key will insert a tab into the document.
+
+ In some occasions text edits should not allow the user to input tabulators
+ or change indentation using the \gui Tab key, as this breaks the focus
+ chain. The default is false.
+
+ \sa tabChangesFocus(), ItemIsFocusable, textInteractionFlags()
+*/
+void QGraphicsTextItem::setTabChangesFocus(bool b)
+{
+ dd->tabChangesFocus = b;
+}
+
+/*!
+ \since 4.5
+
+ Returns true if the \gui Tab key will cause the widget to change focus;
+ otherwise, false is returned.
+
+ By default, this behavior is disabled, and this function will return false.
+
+ \sa setTabChangesFocus()
+*/
+bool QGraphicsTextItem::tabChangesFocus() const
+{
+ return dd->tabChangesFocus;
+}
+
+/*!
+ \property QGraphicsTextItem::openExternalLinks
+
+ Specifies whether QGraphicsTextItem should automatically open links using
+ QDesktopServices::openUrl() instead of emitting the
+ linkActivated signal.
+
+ The default value is false.
+*/
+void QGraphicsTextItem::setOpenExternalLinks(bool open)
+{
+ dd->textControl()->setOpenExternalLinks(open);
+}
+
+bool QGraphicsTextItem::openExternalLinks() const
+{
+ if (!dd->control)
+ return false;
+ return dd->control->openExternalLinks();
+}
+
+/*!
+ \property QGraphicsTextItem::textCursor
+
+ This property represents the visible text cursor in an editable
+ text item.
+
+ By default, if the item's text has not been set, this property
+ contains a null text cursor; otherwise it contains a text cursor
+ placed at the start of the item's document.
+*/
+void QGraphicsTextItem::setTextCursor(const QTextCursor &cursor)
+{
+ dd->textControl()->setTextCursor(cursor);
+}
+
+QTextCursor QGraphicsTextItem::textCursor() const
+{
+ if (!dd->control)
+ return QTextCursor();
+ return dd->control->textCursor();
+}
+
+class QGraphicsSimpleTextItemPrivate : public QAbstractGraphicsShapeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsSimpleTextItem)
+public:
+ inline QGraphicsSimpleTextItemPrivate() {
+ pen.setStyle(Qt::NoPen);
+ brush.setStyle(Qt::SolidPattern);
+ }
+ QString text;
+ QFont font;
+ QRectF boundingRect;
+
+ void updateBoundingRect();
+};
+
+static QRectF setupTextLayout(QTextLayout *layout)
+{
+ layout->setCacheEnabled(true);
+ layout->beginLayout();
+ while (layout->createLine().isValid())
+ ;
+ layout->endLayout();
+ qreal maxWidth = 0;
+ qreal y = 0;
+ for (int i = 0; i < layout->lineCount(); ++i) {
+ QTextLine line = layout->lineAt(i);
+ maxWidth = qMax(maxWidth, line.naturalTextWidth());
+ line.setPosition(QPointF(0, y));
+ y += line.height();
+ }
+ return QRectF(0, 0, maxWidth, y);
+}
+
+void QGraphicsSimpleTextItemPrivate::updateBoundingRect()
+{
+ Q_Q(QGraphicsSimpleTextItem);
+ QRectF br;
+ if (text.isEmpty()) {
+ br = QRectF();
+ } else {
+ QString tmp = text;
+ tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ QStackTextEngine engine(tmp, font);
+ QTextLayout layout(&engine);
+ br = setupTextLayout(&layout);
+ }
+ if (br != boundingRect) {
+ q->prepareGeometryChange();
+ boundingRect = br;
+ q->update();
+ }
+}
+
+/*!
+ \class QGraphicsSimpleTextItem
+ \brief The QGraphicsSimpleTextItem class provides a simple text path item
+ that you can add to a QGraphicsScene.
+ \since 4.2
+ \ingroup graphicsview-api
+
+ To set the item's text, you can either pass a QString to
+ QGraphicsSimpleTextItem's constructor, or call setText() to change the
+ text later. To set the text fill color, call setBrush().
+
+ The simple text item can have both a fill and an outline; setBrush() will
+ set the text fill (i.e., text color), and setPen() sets the pen that will
+ be used to draw the text outline. (The latter can be slow, especially for
+ complex pens, and items with long text content.) If all you want is to
+ draw a simple line of text, you should call setBrush() only, and leave the
+ pen unset; QGraphicsSimpleTextItem's pen is by default Qt::NoPen.
+
+ QGraphicsSimpleTextItem uses the text's formatted size and the associated
+ font to provide a reasonable implementation of boundingRect(), shape(),
+ and contains(). You can set the font by calling setFont().
+
+ QGraphicsSimpleText does not display rich text; instead, you can use
+ QGraphicsTextItem, which provides full text control capabilities.
+
+ \img graphicsview-simpletextitem.png
+
+ \sa QGraphicsTextItem, QGraphicsPathItem, QGraphicsRectItem,
+ QGraphicsEllipseItem, QGraphicsPixmapItem, QGraphicsPolygonItem,
+ QGraphicsLineItem, {Graphics View Framework}
+*/
+
+/*!
+ Constructs a QGraphicsSimpleTextItem.
+
+ \a parent is passed to QGraphicsItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsSimpleTextItem::QGraphicsSimpleTextItem(QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsSimpleTextItemPrivate, parent, scene)
+{
+}
+
+/*!
+ Constructs a QGraphicsSimpleTextItem, using \a text as the default plain text.
+
+ \a parent is passed to QGraphicsItem's constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsSimpleTextItem::QGraphicsSimpleTextItem(const QString &text, QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QAbstractGraphicsShapeItem(*new QGraphicsSimpleTextItemPrivate, parent, scene)
+{
+ setText(text);
+}
+
+/*!
+ Destroys the QGraphicsSimpleTextItem.
+*/
+QGraphicsSimpleTextItem::~QGraphicsSimpleTextItem()
+{
+}
+
+/*!
+ Sets the item's text to \a text. The text will be displayed as
+ plain text. Newline characters ('\n') as well as characters of
+ type QChar::LineSeparator will cause item to break the text into
+ multiple lines.
+*/
+void QGraphicsSimpleTextItem::setText(const QString &text)
+{
+ Q_D(QGraphicsSimpleTextItem);
+ if (d->text == text)
+ return;
+ d->text = text;
+ d->updateBoundingRect();
+ update();
+}
+
+/*!
+ Returns the item's text.
+*/
+QString QGraphicsSimpleTextItem::text() const
+{
+ Q_D(const QGraphicsSimpleTextItem);
+ return d->text;
+}
+
+/*!
+ Sets the font that is used to draw the item's text to \a font.
+*/
+void QGraphicsSimpleTextItem::setFont(const QFont &font)
+{
+ Q_D(QGraphicsSimpleTextItem);
+ d->font = font;
+ d->updateBoundingRect();
+}
+
+/*!
+ Returns the font that is used to draw the item's text.
+*/
+QFont QGraphicsSimpleTextItem::font() const
+{
+ Q_D(const QGraphicsSimpleTextItem);
+ return d->font;
+}
+
+/*!
+ \reimp
+*/
+QRectF QGraphicsSimpleTextItem::boundingRect() const
+{
+ Q_D(const QGraphicsSimpleTextItem);
+ return d->boundingRect;
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsSimpleTextItem::shape() const
+{
+ Q_D(const QGraphicsSimpleTextItem);
+ QPainterPath path;
+ path.addRect(d->boundingRect);
+ return path;
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsSimpleTextItem::contains(const QPointF &point) const
+{
+ Q_D(const QGraphicsSimpleTextItem);
+ return d->boundingRect.contains(point);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsSimpleTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(widget);
+ Q_D(QGraphicsSimpleTextItem);
+
+ painter->setFont(d->font);
+
+ QString tmp = d->text;
+ tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ QStackTextEngine engine(tmp, d->font);
+ QTextLayout layout(&engine);
+ setupTextLayout(&layout);
+
+ QPen p;
+ p.setBrush(d->brush);
+ painter->setPen(p);
+ if (d->pen.style() == Qt::NoPen && d->brush.style() == Qt::SolidPattern) {
+ painter->setBrush(Qt::NoBrush);
+ } else {
+ QTextLayout::FormatRange range;
+ range.start = 0;
+ range.length = layout.text().length();
+ range.format.setTextOutline(d->pen);
+ QList<QTextLayout::FormatRange> formats;
+ formats.append(range);
+ layout.setAdditionalFormats(formats);
+ }
+
+ layout.draw(painter, QPointF(0, 0));
+
+ if (option->state & (QStyle::State_Selected | QStyle::State_HasFocus))
+ qt_graphicsItem_highlightSelected(this, painter, option);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsSimpleTextItem::isObscuredBy(const QGraphicsItem *item) const
+{
+ return QAbstractGraphicsShapeItem::isObscuredBy(item);
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsSimpleTextItem::opaqueArea() const
+{
+ return QAbstractGraphicsShapeItem::opaqueArea();
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsSimpleTextItem::type() const
+{
+ return Type;
+}
+
+/*!
+ \internal
+*/
+bool QGraphicsSimpleTextItem::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension);
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSimpleTextItem::setExtension(Extension extension, const QVariant &variant)
+{
+ Q_UNUSED(extension);
+ Q_UNUSED(variant);
+}
+
+/*!
+ \internal
+*/
+QVariant QGraphicsSimpleTextItem::extension(const QVariant &variant) const
+{
+ Q_UNUSED(variant);
+ return QVariant();
+}
+
+/*!
+ \class QGraphicsItemGroup
+ \brief The QGraphicsItemGroup class provides a container that treats
+ a group of items as a single item.
+ \since 4.2
+ \ingroup graphicsview-api
+
+ A QGraphicsItemGroup is a special type of compound item that
+ treats itself and all its children as one item (i.e., all events
+ and geometries for all children are merged together). It's common
+ to use item groups in presentation tools, when the user wants to
+ group several smaller items into one big item in order to simplify
+ moving and copying of items.
+
+ If all you want is to store items inside other items, you can use
+ any QGraphicsItem directly by passing a suitable parent to
+ setParentItem().
+
+ The boundingRect() function of QGraphicsItemGroup returns the
+ bounding rectangle of all items in the item group.
+ QGraphicsItemGroup ignores the ItemIgnoresTransformations flag on
+ its children (i.e., with respect to the geometry of the group
+ item, the children are treated as if they were transformable).
+
+ There are two ways to construct an item group. The easiest and
+ most common approach is to pass a list of items (e.g., all
+ selected items) to QGraphicsScene::createItemGroup(), which
+ returns a new QGraphicsItemGroup item. The other approach is to
+ manually construct a QGraphicsItemGroup item, add it to the scene
+ calling QGraphicsScene::addItem(), and then add items to the group
+ manually, one at a time by calling addToGroup(). To dismantle
+ ("ungroup") an item group, you can either call
+ QGraphicsScene::destroyItemGroup(), or you can manually remove all
+ items from the group by calling removeFromGroup().
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 17
+
+ The operation of adding and removing items preserves the items'
+ scene-relative position and transformation, as opposed to calling
+ setParentItem(), where only the child item's parent-relative
+ position and transformation are kept.
+
+ The addtoGroup() function reparents the target item to this item
+ group, keeping the item's position and transformation intact
+ relative to the scene. Visually, this means that items added via
+ addToGroup() will remain completely unchanged as a result of this
+ operation, regardless of the item or the group's current position
+ or transformation; although the item's position and matrix are
+ likely to change.
+
+ The removeFromGroup() function has similar semantics to
+ setParentItem(); it reparents the item to the parent item of the
+ item group. As with addToGroup(), the item's scene-relative
+ position and transformation remain intact.
+
+ \sa QGraphicsItem, {Graphics View Framework}
+*/
+
+class QGraphicsItemGroupPrivate : public QGraphicsItemPrivate
+{
+public:
+ QRectF itemsBoundingRect;
+};
+
+/*!
+ Constructs a QGraphicsItemGroup. \a parent is passed to QGraphicsItem's
+ constructor.
+
+ \sa QGraphicsScene::addItem()
+*/
+QGraphicsItemGroup::QGraphicsItemGroup(QGraphicsItem *parent
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene
+#endif
+ )
+ : QGraphicsItem(*new QGraphicsItemGroupPrivate, parent, scene)
+{
+ setHandlesChildEvents(true);
+}
+
+/*!
+ Destroys the QGraphicsItemGroup.
+*/
+QGraphicsItemGroup::~QGraphicsItemGroup()
+{
+}
+
+/*!
+ Adds the given \a item to this item group. The item will be
+ reparented to this group, but its position and transformation
+ relative to the scene will stay intact.
+
+ \sa removeFromGroup(), QGraphicsScene::createItemGroup()
+*/
+void QGraphicsItemGroup::addToGroup(QGraphicsItem *item)
+{
+ Q_D(QGraphicsItemGroup);
+ if (!item) {
+ qWarning("QGraphicsItemGroup::addToGroup: cannot add null item");
+ return;
+ }
+ if (item == this) {
+ qWarning("QGraphicsItemGroup::addToGroup: cannot add a group to itself");
+ return;
+ }
+
+ // COMBINE
+ bool ok;
+ QTransform itemTransform = item->itemTransform(this, &ok);
+
+ if (!ok) {
+ qWarning("QGraphicsItemGroup::addToGroup: could not find a valid transformation from item to group coordinates");
+ return;
+ }
+
+ QTransform newItemTransform(itemTransform);
+ item->setPos(mapFromItem(item, 0, 0));
+ item->setParentItem(this);
+
+ // removing position from translation component of the new transform
+ if (!item->pos().isNull())
+ newItemTransform *= QTransform::fromTranslate(-item->x(), -item->y());
+
+ // removing additional transformations properties applied with itemTransform()
+ QPointF origin = item->transformOriginPoint();
+ QMatrix4x4 m;
+ QList<QGraphicsTransform*> transformList = item->transformations();
+ for (int i = 0; i < transformList.size(); ++i)
+ transformList.at(i)->applyTo(&m);
+ newItemTransform *= m.toTransform().inverted();
+ newItemTransform.translate(origin.x(), origin.y());
+ newItemTransform.rotate(-item->rotation());
+ newItemTransform.scale(1/item->scale(), 1/item->scale());
+ newItemTransform.translate(-origin.x(), -origin.y());
+
+ // ### Expensive, we could maybe use dirtySceneTransform bit for optimization
+
+ item->setTransform(newItemTransform);
+ item->d_func()->setIsMemberOfGroup(true);
+ prepareGeometryChange();
+ d->itemsBoundingRect |= itemTransform.mapRect(item->boundingRect() | item->childrenBoundingRect());
+ update();
+}
+
+/*!
+ Removes the specified \a item from this group. The item will be
+ reparented to this group's parent item, or to 0 if this group has
+ no parent. Its position and transformation relative to the scene
+ will stay intact.
+
+ \sa addToGroup(), QGraphicsScene::destroyItemGroup()
+*/
+void QGraphicsItemGroup::removeFromGroup(QGraphicsItem *item)
+{
+ Q_D(QGraphicsItemGroup);
+ if (!item) {
+ qWarning("QGraphicsItemGroup::removeFromGroup: cannot remove null item");
+ return;
+ }
+
+ QGraphicsItem *newParent = d_ptr->parent;
+
+ // COMBINE
+ bool ok;
+ QTransform itemTransform;
+ if (newParent)
+ itemTransform = item->itemTransform(newParent, &ok);
+ else
+ itemTransform = item->sceneTransform();
+
+ QPointF oldPos = item->mapToItem(newParent, 0, 0);
+ item->setParentItem(newParent);
+ item->setPos(oldPos);
+
+ // removing position from translation component of the new transform
+ if (!item->pos().isNull())
+ itemTransform *= QTransform::fromTranslate(-item->x(), -item->y());
+
+ // removing additional transformations properties applied
+ // with itemTransform() or sceneTransform()
+ QPointF origin = item->transformOriginPoint();
+ QMatrix4x4 m;
+ QList<QGraphicsTransform*> transformList = item->transformations();
+ for (int i = 0; i < transformList.size(); ++i)
+ transformList.at(i)->applyTo(&m);
+ itemTransform *= m.toTransform().inverted();
+ itemTransform.translate(origin.x(), origin.y());
+ itemTransform.rotate(-item->rotation());
+ itemTransform.scale(1 / item->scale(), 1 / item->scale());
+ itemTransform.translate(-origin.x(), -origin.y());
+
+ // ### Expensive, we could maybe use dirtySceneTransform bit for optimization
+
+ item->setTransform(itemTransform);
+ item->d_func()->setIsMemberOfGroup(item->group() != 0);
+
+ // ### Quite expensive. But removeFromGroup() isn't called very often.
+ prepareGeometryChange();
+ d->itemsBoundingRect = childrenBoundingRect();
+}
+
+/*!
+ \reimp
+
+ Returns the bounding rect of this group item, and all its children.
+*/
+QRectF QGraphicsItemGroup::boundingRect() const
+{
+ Q_D(const QGraphicsItemGroup);
+ return d->itemsBoundingRect;
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsItemGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
+{
+ Q_UNUSED(widget);
+ if (option->state & QStyle::State_Selected) {
+ Q_D(QGraphicsItemGroup);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRect(d->itemsBoundingRect);
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsItemGroup::isObscuredBy(const QGraphicsItem *item) const
+{
+ return QGraphicsItem::isObscuredBy(item);
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsItemGroup::opaqueArea() const
+{
+ return QGraphicsItem::opaqueArea();
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsItemGroup::type() const
+{
+ return Type;
+}
+
+#ifndef QT_NO_GRAPHICSEFFECT
+QRectF QGraphicsItemEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const
+{
+ const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
+ if (!info && deviceCoordinates) {
+ // Device coordinates without info not yet supported.
+ qWarning("QGraphicsEffectSource::boundingRect: Not yet implemented, lacking device context");
+ return QRectF();
+ }
+
+ QRectF rect = item->boundingRect();
+ if (!item->d_ptr->children.isEmpty())
+ rect |= item->childrenBoundingRect();
+
+ if (deviceCoordinates) {
+ Q_ASSERT(info->painter);
+ rect = info->painter->worldTransform().mapRect(rect);
+ }
+
+ return rect;
+}
+
+void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter)
+{
+ if (!info) {
+ qWarning("QGraphicsEffectSource::draw: Can only begin as a result of QGraphicsEffect::draw");
+ return;
+ }
+
+ Q_ASSERT(item->d_ptr->scene);
+ QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
+ if (painter == info->painter) {
+ scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
+ info->widget, info->opacity, info->effectTransform, info->wasDirtySceneTransform,
+ info->drawItem);
+ } else {
+ QTransform effectTransform = info->painter->worldTransform().inverted();
+ effectTransform *= painter->worldTransform();
+ scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
+ info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
+ info->drawItem);
+ }
+}
+
+// sourceRect must be in the given coordinate system
+QRect QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded) const
+{
+ QRectF effectRectF;
+
+ if (unpadded)
+ *unpadded = false;
+
+ if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) {
+ if (info) {
+ QRectF deviceRect = system == Qt::DeviceCoordinates ? sourceRect : info->painter->worldTransform().mapRect(sourceRect);
+ effectRectF = item->graphicsEffect()->boundingRectFor(deviceRect);
+ if (unpadded)
+ *unpadded = (effectRectF.size() == sourceRect.size());
+ if (info && system == Qt::LogicalCoordinates)
+ effectRectF = info->painter->worldTransform().inverted().mapRect(effectRectF);
+ } else {
+ // no choice but to send a logical coordinate bounding rect to boundingRectFor
+ effectRectF = item->graphicsEffect()->boundingRectFor(sourceRect);
+ }
+ } else if (mode == QGraphicsEffect::PadToTransparentBorder) {
+ // adjust by 1.5 to account for cosmetic pens
+ effectRectF = sourceRect.adjusted(-1.5, -1.5, 1.5, 1.5);
+ } else {
+ effectRectF = sourceRect;
+ if (unpadded)
+ *unpadded = true;
+ }
+
+ return effectRectF.toAlignedRect();
+}
+
+QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset,
+ QGraphicsEffect::PixmapPadMode mode) const
+{
+ const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
+ if (!info && deviceCoordinates) {
+ // Device coordinates without info not yet supported.
+ qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context");
+ return QPixmap();
+ }
+ if (!item->d_ptr->scene)
+ return QPixmap();
+ QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
+
+ bool unpadded;
+ const QRectF sourceRect = boundingRect(system);
+ QRect effectRect = paddedEffectRect(system, mode, sourceRect, &unpadded);
+
+ if (offset)
+ *offset = effectRect.topLeft();
+
+ bool untransformed = !deviceCoordinates
+ || info->painter->worldTransform().type() <= QTransform::TxTranslate;
+ if (untransformed && unpadded && isPixmap()) {
+ if (offset)
+ *offset = boundingRect(system).topLeft().toPoint();
+ return static_cast<QGraphicsPixmapItem *>(item)->pixmap();
+ }
+
+ if (effectRect.isEmpty())
+ return QPixmap();
+
+ QPixmap pixmap(effectRect.size());
+ pixmap.fill(Qt::transparent);
+ QPainter pixmapPainter(&pixmap);
+ pixmapPainter.setRenderHints(info ? info->painter->renderHints() : QPainter::TextAntialiasing);
+
+ QTransform effectTransform = QTransform::fromTranslate(-effectRect.x(), -effectRect.y());
+ if (deviceCoordinates && info->effectTransform)
+ effectTransform *= *info->effectTransform;
+
+ if (!info) {
+ // Logical coordinates without info.
+ QTransform sceneTransform = item->sceneTransform();
+ QTransform newEffectTransform = sceneTransform.inverted();
+ newEffectTransform *= effectTransform;
+ scened->draw(item, &pixmapPainter, 0, &sceneTransform, 0, 0, qreal(1.0),
+ &newEffectTransform, false, true);
+ } else if (deviceCoordinates) {
+ // Device coordinates with info.
+ scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, 0,
+ info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
+ info->drawItem);
+ } else {
+ // Item coordinates with info.
+ QTransform newEffectTransform = info->transformPtr->inverted();
+ newEffectTransform *= effectTransform;
+ scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, 0,
+ info->widget, info->opacity, &newEffectTransform, info->wasDirtySceneTransform,
+ info->drawItem);
+ }
+
+ pixmapPainter.end();
+
+ return pixmap;
+}
+#endif //QT_NO_GRAPHICSEFFECT
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, QGraphicsItem *item)
+{
+ if (!item) {
+ debug << "QGraphicsItem(0)";
+ return debug;
+ }
+
+ if (QGraphicsObject *o = item->toGraphicsObject())
+ debug << o->metaObject()->className();
+ else
+ debug << "QGraphicsItem";
+ debug << "(this =" << (void*)item
+ << ", parent =" << (void*)item->parentItem()
+ << ", pos =" << item->pos()
+ << ", z =" << item->zValue() << ", flags = "
+ << item->flags() << ")";
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, QGraphicsObject *item)
+{
+ if (!item) {
+ debug << "QGraphicsObject(0)";
+ return debug;
+ }
+
+ debug.nospace() << item->metaObject()->className() << '(' << (void*)item;
+ if (!item->objectName().isEmpty())
+ debug << ", name = " << item->objectName();
+ debug.nospace() << ", parent = " << ((void*)item->parentItem())
+ << ", pos = " << item->pos()
+ << ", z = " << item->zValue() << ", flags = "
+ << item->flags() << ')';
+ return debug.space();
+}
+
+QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemChange change)
+{
+ const char *str = "UnknownChange";
+ switch (change) {
+ case QGraphicsItem::ItemChildAddedChange:
+ str = "ItemChildAddedChange";
+ break;
+ case QGraphicsItem::ItemChildRemovedChange:
+ str = "ItemChildRemovedChange";
+ break;
+ case QGraphicsItem::ItemCursorChange:
+ str = "ItemCursorChange";
+ break;
+ case QGraphicsItem::ItemCursorHasChanged:
+ str = "ItemCursorHasChanged";
+ break;
+ case QGraphicsItem::ItemEnabledChange:
+ str = "ItemEnabledChange";
+ break;
+ case QGraphicsItem::ItemEnabledHasChanged:
+ str = "ItemEnabledHasChanged";
+ break;
+ case QGraphicsItem::ItemFlagsChange:
+ str = "ItemFlagsChange";
+ break;
+ case QGraphicsItem::ItemFlagsHaveChanged:
+ str = "ItemFlagsHaveChanged";
+ break;
+ case QGraphicsItem::ItemMatrixChange:
+ str = "ItemMatrixChange";
+ break;
+ case QGraphicsItem::ItemParentChange:
+ str = "ItemParentChange";
+ break;
+ case QGraphicsItem::ItemParentHasChanged:
+ str = "ItemParentHasChanged";
+ break;
+ case QGraphicsItem::ItemPositionChange:
+ str = "ItemPositionChange";
+ break;
+ case QGraphicsItem::ItemPositionHasChanged:
+ str = "ItemPositionHasChanged";
+ break;
+ case QGraphicsItem::ItemSceneChange:
+ str = "ItemSceneChange";
+ break;
+ case QGraphicsItem::ItemSceneHasChanged:
+ str = "ItemSceneHasChanged";
+ break;
+ case QGraphicsItem::ItemSelectedChange:
+ str = "ItemSelectedChange";
+ break;
+ case QGraphicsItem::ItemSelectedHasChanged:
+ str = "ItemSelectedHasChanged";
+ break;
+ case QGraphicsItem::ItemToolTipChange:
+ str = "ItemToolTipChange";
+ break;
+ case QGraphicsItem::ItemToolTipHasChanged:
+ str = "ItemToolTipHasChanged";
+ break;
+ case QGraphicsItem::ItemTransformChange:
+ str = "ItemTransformChange";
+ break;
+ case QGraphicsItem::ItemTransformHasChanged:
+ str = "ItemTransformHasChanged";
+ break;
+ case QGraphicsItem::ItemVisibleChange:
+ str = "ItemVisibleChange";
+ break;
+ case QGraphicsItem::ItemVisibleHasChanged:
+ str = "ItemVisibleHasChanged";
+ break;
+ case QGraphicsItem::ItemZValueChange:
+ str = "ItemZValueChange";
+ break;
+ case QGraphicsItem::ItemZValueHasChanged:
+ str = "ItemZValueHasChanged";
+ break;
+ case QGraphicsItem::ItemOpacityChange:
+ str = "ItemOpacityChange";
+ break;
+ case QGraphicsItem::ItemOpacityHasChanged:
+ str = "ItemOpacityHasChanged";
+ break;
+ case QGraphicsItem::ItemScenePositionHasChanged:
+ str = "ItemScenePositionHasChanged";
+ break;
+ case QGraphicsItem::ItemRotationChange:
+ str = "ItemRotationChange";
+ break;
+ case QGraphicsItem::ItemRotationHasChanged:
+ str = "ItemRotationHasChanged";
+ break;
+ case QGraphicsItem::ItemScaleChange:
+ str = "ItemScaleChange";
+ break;
+ case QGraphicsItem::ItemScaleHasChanged:
+ str = "ItemScaleHasChanged";
+ break;
+ case QGraphicsItem::ItemTransformOriginPointChange:
+ str = "ItemTransformOriginPointChange";
+ break;
+ case QGraphicsItem::ItemTransformOriginPointHasChanged:
+ str = "ItemTransformOriginPointHasChanged";
+ break;
+ }
+ debug << str;
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag)
+{
+ const char *str = "UnknownFlag";
+ switch (flag) {
+ case QGraphicsItem::ItemIsMovable:
+ str = "ItemIsMovable";
+ break;
+ case QGraphicsItem::ItemIsSelectable:
+ str = "ItemIsSelectable";
+ break;
+ case QGraphicsItem::ItemIsFocusable:
+ str = "ItemIsFocusable";
+ break;
+ case QGraphicsItem::ItemClipsToShape:
+ str = "ItemClipsToShape";
+ break;
+ case QGraphicsItem::ItemClipsChildrenToShape:
+ str = "ItemClipsChildrenToShape";
+ break;
+ case QGraphicsItem::ItemIgnoresTransformations:
+ str = "ItemIgnoresTransformations";
+ break;
+ case QGraphicsItem::ItemIgnoresParentOpacity:
+ str = "ItemIgnoresParentOpacity";
+ break;
+ case QGraphicsItem::ItemDoesntPropagateOpacityToChildren:
+ str = "ItemDoesntPropagateOpacityToChildren";
+ break;
+ case QGraphicsItem::ItemStacksBehindParent:
+ str = "ItemStacksBehindParent";
+ break;
+ case QGraphicsItem::ItemUsesExtendedStyleOption:
+ str = "ItemUsesExtendedStyleOption";
+ break;
+ case QGraphicsItem::ItemHasNoContents:
+ str = "ItemHasNoContents";
+ break;
+ case QGraphicsItem::ItemSendsGeometryChanges:
+ str = "ItemSendsGeometryChanges";
+ break;
+ case QGraphicsItem::ItemAcceptsInputMethod:
+ str = "ItemAcceptsInputMethod";
+ break;
+ case QGraphicsItem::ItemNegativeZStacksBehindParent:
+ str = "ItemNegativeZStacksBehindParent";
+ break;
+ case QGraphicsItem::ItemIsPanel:
+ str = "ItemIsPanel";
+ break;
+ case QGraphicsItem::ItemIsFocusScope:
+ str = "ItemIsFocusScope";
+ break;
+ case QGraphicsItem::ItemSendsScenePositionChanges:
+ str = "ItemSendsScenePositionChanges";
+ break;
+ case QGraphicsItem::ItemStopsClickFocusPropagation:
+ str = "ItemStopsClickFocusPropagation";
+ break;
+ case QGraphicsItem::ItemStopsFocusHandling:
+ str = "ItemStopsFocusHandling";
+ break;
+ }
+ debug << str;
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlags flags)
+{
+ debug << '(';
+ bool f = false;
+ for (int i = 0; i < 17; ++i) {
+ if (flags & (1 << i)) {
+ if (f)
+ debug << '|';
+ f = true;
+ debug << QGraphicsItem::GraphicsItemFlag(int(flags & (1 << i)));
+ }
+ }
+ debug << ')';
+ return debug;
+}
+
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qgraphicsitem.cpp"
+
+#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/widgets/graphicsview/qgraphicsitem.h b/src/widgets/graphicsview/qgraphicsitem.h
new file mode 100644
index 0000000000..67c9cd3e2a
--- /dev/null
+++ b/src/widgets/graphicsview/qgraphicsitem.h
@@ -0,0 +1,1172 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSITEM_H
+#define QGRAPHICSITEM_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qscopedpointer.h>
+#include <QtGui/qpainterpath.h>
+#include <QtGui/qpixmap.h>
+
+class tst_QGraphicsItem;
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+class QBrush;
+class QCursor;
+class QFocusEvent;
+class QGraphicsEffect;
+class QGraphicsItemGroup;
+class QGraphicsObject;
+class QGraphicsSceneContextMenuEvent;
+class QGraphicsSceneDragDropEvent;
+class QGraphicsSceneEvent;
+class QGraphicsSceneHoverEvent;
+class QGraphicsSceneMouseEvent;
+class QGraphicsSceneWheelEvent;
+class QGraphicsScene;
+class QGraphicsTransform;
+class QGraphicsWidget;
+class QInputMethodEvent;
+class QKeyEvent;
+class QMatrix;
+class QMenu;
+class QPainter;
+class QPen;
+class QPointF;
+class QRectF;
+class QStyleOptionGraphicsItem;
+
+class QGraphicsItemPrivate;
+class Q_GUI_EXPORT QGraphicsItem
+{
+public:
+ enum GraphicsItemFlag {
+ ItemIsMovable = 0x1,
+ ItemIsSelectable = 0x2,
+ ItemIsFocusable = 0x4,
+ ItemClipsToShape = 0x8,
+ ItemClipsChildrenToShape = 0x10,
+ ItemIgnoresTransformations = 0x20,
+ ItemIgnoresParentOpacity = 0x40,
+ ItemDoesntPropagateOpacityToChildren = 0x80,
+ ItemStacksBehindParent = 0x100,
+ ItemUsesExtendedStyleOption = 0x200,
+ ItemHasNoContents = 0x400,
+ ItemSendsGeometryChanges = 0x800,
+ ItemAcceptsInputMethod = 0x1000,
+ ItemNegativeZStacksBehindParent = 0x2000,
+ ItemIsPanel = 0x4000,
+ ItemIsFocusScope = 0x8000, // internal
+ ItemSendsScenePositionChanges = 0x10000,
+ ItemStopsClickFocusPropagation = 0x20000,
+ ItemStopsFocusHandling = 0x40000
+ // NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag.
+ };
+ Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag)
+
+ enum GraphicsItemChange {
+ ItemPositionChange,
+ ItemMatrixChange,
+ ItemVisibleChange,
+ ItemEnabledChange,
+ ItemSelectedChange,
+ ItemParentChange,
+ ItemChildAddedChange,
+ ItemChildRemovedChange,
+ ItemTransformChange,
+ ItemPositionHasChanged,
+ ItemTransformHasChanged,
+ ItemSceneChange,
+ ItemVisibleHasChanged,
+ ItemEnabledHasChanged,
+ ItemSelectedHasChanged,
+ ItemParentHasChanged,
+ ItemSceneHasChanged,
+ ItemCursorChange,
+ ItemCursorHasChanged,
+ ItemToolTipChange,
+ ItemToolTipHasChanged,
+ ItemFlagsChange,
+ ItemFlagsHaveChanged,
+ ItemZValueChange,
+ ItemZValueHasChanged,
+ ItemOpacityChange,
+ ItemOpacityHasChanged,
+ ItemScenePositionHasChanged,
+ ItemRotationChange,
+ ItemRotationHasChanged,
+ ItemScaleChange,
+ ItemScaleHasChanged,
+ ItemTransformOriginPointChange,
+ ItemTransformOriginPointHasChanged
+ };
+
+ enum CacheMode {
+ NoCache,
+ ItemCoordinateCache,
+ DeviceCoordinateCache
+ };
+
+ enum PanelModality
+ {
+ NonModal,
+ PanelModal,
+ SceneModal
+ };
+
+ QGraphicsItem(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // ### obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ virtual ~QGraphicsItem();
+
+ QGraphicsScene *scene() const;
+
+ QGraphicsItem *parentItem() const;
+ QGraphicsItem *topLevelItem() const;
+ QGraphicsObject *parentObject() const;
+ QGraphicsWidget *parentWidget() const;
+ QGraphicsWidget *topLevelWidget() const;
+ QGraphicsWidget *window() const;
+ QGraphicsItem *panel() const;
+ void setParentItem(QGraphicsItem *parent);
+ QList<QGraphicsItem *> children() const; // ### obsolete
+ QList<QGraphicsItem *> childItems() const;
+ bool isWidget() const;
+ bool isWindow() const;
+ bool isPanel() const;
+
+ QGraphicsObject *toGraphicsObject();
+ const QGraphicsObject *toGraphicsObject() const;
+
+ QGraphicsItemGroup *group() const;
+ void setGroup(QGraphicsItemGroup *group);
+
+ GraphicsItemFlags flags() const;
+ void setFlag(GraphicsItemFlag flag, bool enabled = true);
+ void setFlags(GraphicsItemFlags flags);
+
+ CacheMode cacheMode() const;
+ void setCacheMode(CacheMode mode, const QSize &cacheSize = QSize());
+
+ PanelModality panelModality() const;
+ void setPanelModality(PanelModality panelModality);
+ bool isBlockedByModalPanel(QGraphicsItem **blockingPanel = 0) const;
+
+#ifndef QT_NO_TOOLTIP
+ QString toolTip() const;
+ void setToolTip(const QString &toolTip);
+#endif
+
+#ifndef QT_NO_CURSOR
+ QCursor cursor() const;
+ void setCursor(const QCursor &cursor);
+ bool hasCursor() const;
+ void unsetCursor();
+#endif
+
+ bool isVisible() const;
+ bool isVisibleTo(const QGraphicsItem *parent) const;
+ void setVisible(bool visible);
+ inline void hide() { setVisible(false); }
+ inline void show() { setVisible(true); }
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ bool isSelected() const;
+ void setSelected(bool selected);
+
+ bool acceptDrops() const;
+ void setAcceptDrops(bool on);
+
+ qreal opacity() const;
+ qreal effectiveOpacity() const;
+ void setOpacity(qreal opacity);
+
+#ifndef QT_NO_GRAPHICSEFFECT
+ // Effect
+ QGraphicsEffect *graphicsEffect() const;
+ void setGraphicsEffect(QGraphicsEffect *effect);
+#endif //QT_NO_GRAPHICSEFFECT
+
+ Qt::MouseButtons acceptedMouseButtons() const;
+ void setAcceptedMouseButtons(Qt::MouseButtons buttons);
+
+ bool acceptsHoverEvents() const; // ### obsolete
+ void setAcceptsHoverEvents(bool enabled); // ### obsolete
+ bool acceptHoverEvents() const;
+ void setAcceptHoverEvents(bool enabled);
+ bool acceptTouchEvents() const;
+ void setAcceptTouchEvents(bool enabled);
+
+ bool filtersChildEvents() const;
+ void setFiltersChildEvents(bool enabled);
+
+ bool handlesChildEvents() const;
+ void setHandlesChildEvents(bool enabled);
+
+ bool isActive() const;
+ void setActive(bool active);
+
+ bool hasFocus() const;
+ void setFocus(Qt::FocusReason focusReason = Qt::OtherFocusReason);
+ void clearFocus();
+
+ QGraphicsItem *focusProxy() const;
+ void setFocusProxy(QGraphicsItem *item);
+
+ QGraphicsItem *focusItem() const;
+ QGraphicsItem *focusScopeItem() const;
+
+ void grabMouse();
+ void ungrabMouse();
+ void grabKeyboard();
+ void ungrabKeyboard();
+
+ // Positioning in scene coordinates
+ QPointF pos() const;
+ inline qreal x() const { return pos().x(); }
+ void setX(qreal x);
+ inline qreal y() const { return pos().y(); }
+ void setY(qreal y);
+ QPointF scenePos() const;
+ void setPos(const QPointF &pos);
+ inline void setPos(qreal x, qreal y);
+ inline void moveBy(qreal dx, qreal dy) { setPos(pos().x() + dx, pos().y() + dy); }
+
+ void ensureVisible(const QRectF &rect = QRectF(), int xmargin = 50, int ymargin = 50);
+ inline void ensureVisible(qreal x, qreal y, qreal w, qreal h, int xmargin = 50, int ymargin = 50);
+
+ // Local transformation
+ QMatrix matrix() const;
+ QMatrix sceneMatrix() const;
+ void setMatrix(const QMatrix &matrix, bool combine = false);
+ void resetMatrix();
+ QTransform transform() const;
+ QTransform sceneTransform() const;
+ QTransform deviceTransform(const QTransform &viewportTransform) const;
+ QTransform itemTransform(const QGraphicsItem *other, bool *ok = 0) const;
+ void setTransform(const QTransform &matrix, bool combine = false);
+ void resetTransform();
+
+ void rotate(qreal angle); // ### obsolete
+ void scale(qreal sx, qreal sy); // ### obsolete
+ void shear(qreal sh, qreal sv); // ### obsolete
+ void translate(qreal dx, qreal dy); // ### obsolete
+
+ void setRotation(qreal angle);
+ qreal rotation() const;
+
+ void setScale(qreal scale);
+ qreal scale() const;
+
+ QList<QGraphicsTransform *> transformations() const;
+ void setTransformations(const QList<QGraphicsTransform *> &transformations);
+
+ QPointF transformOriginPoint() const;
+ void setTransformOriginPoint(const QPointF &origin);
+ inline void setTransformOriginPoint(qreal ax, qreal ay)
+ { setTransformOriginPoint(QPointF(ax,ay)); }
+
+ virtual void advance(int phase);
+
+ // Stacking order
+ qreal zValue() const;
+ void setZValue(qreal z);
+ void stackBefore(const QGraphicsItem *sibling);
+
+ // Hit test
+ virtual QRectF boundingRect() const = 0;
+ QRectF childrenBoundingRect() const;
+ QRectF sceneBoundingRect() const;
+ virtual QPainterPath shape() const;
+ bool isClipped() const;
+ QPainterPath clipPath() const;
+ virtual bool contains(const QPointF &point) const;
+ virtual bool collidesWithItem(const QGraphicsItem *other, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ virtual bool collidesWithPath(const QPainterPath &path, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ QList<QGraphicsItem *> collidingItems(Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ bool isObscured() const;
+ bool isObscured(const QRectF &rect) const; // ### Qt 5: merge with isObscured(), add QRectF arg to isObscuredBy()
+ inline bool isObscured(qreal x, qreal y, qreal w, qreal h) const;
+ virtual bool isObscuredBy(const QGraphicsItem *item) const;
+ virtual QPainterPath opaqueArea() const;
+
+ QRegion boundingRegion(const QTransform &itemToDeviceTransform) const;
+ qreal boundingRegionGranularity() const;
+ void setBoundingRegionGranularity(qreal granularity);
+
+ // Drawing
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) = 0;
+ void update(const QRectF &rect = QRectF());
+ inline void update(qreal x, qreal y, qreal width, qreal height);
+ void scroll(qreal dx, qreal dy, const QRectF &rect = QRectF());
+
+ // Coordinate mapping
+ QPointF mapToItem(const QGraphicsItem *item, const QPointF &point) const;
+ QPointF mapToParent(const QPointF &point) const;
+ QPointF mapToScene(const QPointF &point) const;
+ QPolygonF mapToItem(const QGraphicsItem *item, const QRectF &rect) const;
+ QPolygonF mapToParent(const QRectF &rect) const;
+ QPolygonF mapToScene(const QRectF &rect) const;
+ QRectF mapRectToItem(const QGraphicsItem *item, const QRectF &rect) const;
+ QRectF mapRectToParent(const QRectF &rect) const;
+ QRectF mapRectToScene(const QRectF &rect) const;
+ QPolygonF mapToItem(const QGraphicsItem *item, const QPolygonF &polygon) const;
+ QPolygonF mapToParent(const QPolygonF &polygon) const;
+ QPolygonF mapToScene(const QPolygonF &polygon) const;
+ QPainterPath mapToItem(const QGraphicsItem *item, const QPainterPath &path) const;
+ QPainterPath mapToParent(const QPainterPath &path) const;
+ QPainterPath mapToScene(const QPainterPath &path) const;
+ QPointF mapFromItem(const QGraphicsItem *item, const QPointF &point) const;
+ QPointF mapFromParent(const QPointF &point) const;
+ QPointF mapFromScene(const QPointF &point) const;
+ QPolygonF mapFromItem(const QGraphicsItem *item, const QRectF &rect) const;
+ QPolygonF mapFromParent(const QRectF &rect) const;
+ QPolygonF mapFromScene(const QRectF &rect) const;
+ QRectF mapRectFromItem(const QGraphicsItem *item, const QRectF &rect) const;
+ QRectF mapRectFromParent(const QRectF &rect) const;
+ QRectF mapRectFromScene(const QRectF &rect) const;
+ QPolygonF mapFromItem(const QGraphicsItem *item, const QPolygonF &polygon) const;
+ QPolygonF mapFromParent(const QPolygonF &polygon) const;
+ QPolygonF mapFromScene(const QPolygonF &polygon) const;
+ QPainterPath mapFromItem(const QGraphicsItem *item, const QPainterPath &path) const;
+ QPainterPath mapFromParent(const QPainterPath &path) const;
+ QPainterPath mapFromScene(const QPainterPath &path) const;
+
+ inline QPointF mapToItem(const QGraphicsItem *item, qreal x, qreal y) const;
+ inline QPointF mapToParent(qreal x, qreal y) const;
+ inline QPointF mapToScene(qreal x, qreal y) const;
+ inline QPolygonF mapToItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const;
+ inline QPolygonF mapToParent(qreal x, qreal y, qreal w, qreal h) const;
+ inline QPolygonF mapToScene(qreal x, qreal y, qreal w, qreal h) const;
+ inline QRectF mapRectToItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const;
+ inline QRectF mapRectToParent(qreal x, qreal y, qreal w, qreal h) const;
+ inline QRectF mapRectToScene(qreal x, qreal y, qreal w, qreal h) const;
+ inline QPointF mapFromItem(const QGraphicsItem *item, qreal x, qreal y) const;
+ inline QPointF mapFromParent(qreal x, qreal y) const;
+ inline QPointF mapFromScene(qreal x, qreal y) const;
+ inline QPolygonF mapFromItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const;
+ inline QPolygonF mapFromParent(qreal x, qreal y, qreal w, qreal h) const;
+ inline QPolygonF mapFromScene(qreal x, qreal y, qreal w, qreal h) const;
+ inline QRectF mapRectFromItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const;
+ inline QRectF mapRectFromParent(qreal x, qreal y, qreal w, qreal h) const;
+ inline QRectF mapRectFromScene(qreal x, qreal y, qreal w, qreal h) const;
+
+ bool isAncestorOf(const QGraphicsItem *child) const;
+ QGraphicsItem *commonAncestorItem(const QGraphicsItem *other) const;
+ bool isUnderMouse() const;
+
+ // Custom data
+ QVariant data(int key) const;
+ void setData(int key, const QVariant &value);
+
+ Qt::InputMethodHints inputMethodHints() const;
+ void setInputMethodHints(Qt::InputMethodHints hints);
+
+ enum {
+ Type = 1,
+ UserType = 65536
+ };
+ virtual int type() const;
+
+ void installSceneEventFilter(QGraphicsItem *filterItem);
+ void removeSceneEventFilter(QGraphicsItem *filterItem);
+
+protected:
+ void updateMicroFocus();
+ virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event);
+ virtual bool sceneEvent(QEvent *event);
+ virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
+ virtual void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
+ virtual void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
+ virtual void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
+ virtual void dropEvent(QGraphicsSceneDragDropEvent *event);
+ virtual void focusInEvent(QFocusEvent *event);
+ virtual void focusOutEvent(QFocusEvent *event);
+ virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void keyReleaseEvent(QKeyEvent *event);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ virtual void wheelEvent(QGraphicsSceneWheelEvent *event);
+ virtual void inputMethodEvent(QInputMethodEvent *event);
+ virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+
+ virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+
+ enum Extension {
+ UserExtension = 0x80000000
+ };
+ virtual bool supportsExtension(Extension extension) const;
+ virtual void setExtension(Extension extension, const QVariant &variant);
+ virtual QVariant extension(const QVariant &variant) const;
+
+protected:
+ QGraphicsItem(QGraphicsItemPrivate &dd,
+ QGraphicsItem *parent, QGraphicsScene *scene);
+ QScopedPointer<QGraphicsItemPrivate> d_ptr;
+
+ void addToIndex();
+ void removeFromIndex();
+ void prepareGeometryChange();
+
+private:
+ Q_DISABLE_COPY(QGraphicsItem)
+ Q_DECLARE_PRIVATE(QGraphicsItem)
+ friend class QGraphicsItemGroup;
+ friend class QGraphicsScene;
+ friend class QGraphicsScenePrivate;
+ friend class QGraphicsSceneFindItemBspTreeVisitor;
+ friend class QGraphicsSceneBspTree;
+ friend class QGraphicsView;
+ friend class QGraphicsViewPrivate;
+ friend class QGraphicsObject;
+ friend class QGraphicsWidget;
+ friend class QGraphicsWidgetPrivate;
+ friend class QGraphicsProxyWidgetPrivate;
+ friend class QGraphicsSceneIndex;
+ friend class QGraphicsSceneIndexPrivate;
+ friend class QGraphicsSceneBspTreeIndex;
+ friend class QGraphicsSceneBspTreeIndexPrivate;
+ friend class QGraphicsItemEffectSourcePrivate;
+ friend class QGraphicsTransformPrivate;
+#ifndef QT_NO_GESTURES
+ friend class QGestureManager;
+#endif
+ friend class ::tst_QGraphicsItem;
+ friend bool qt_closestLeaf(const QGraphicsItem *, const QGraphicsItem *);
+ friend bool qt_closestItemFirst(const QGraphicsItem *, const QGraphicsItem *);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsItem::GraphicsItemFlags)
+Q_DECLARE_INTERFACE(QGraphicsItem, "com.trolltech.Qt.QGraphicsItem")
+
+inline void QGraphicsItem::setPos(qreal ax, qreal ay)
+{ setPos(QPointF(ax, ay)); }
+inline void QGraphicsItem::ensureVisible(qreal ax, qreal ay, qreal w, qreal h, int xmargin, int ymargin)
+{ ensureVisible(QRectF(ax, ay, w, h), xmargin, ymargin); }
+inline void QGraphicsItem::update(qreal ax, qreal ay, qreal width, qreal height)
+{ update(QRectF(ax, ay, width, height)); }
+inline bool QGraphicsItem::isObscured(qreal ax, qreal ay, qreal w, qreal h) const
+{ return isObscured(QRectF(ax, ay, w, h)); }
+inline QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, qreal ax, qreal ay) const
+{ return mapToItem(item, QPointF(ax, ay)); }
+inline QPointF QGraphicsItem::mapToParent(qreal ax, qreal ay) const
+{ return mapToParent(QPointF(ax, ay)); }
+inline QPointF QGraphicsItem::mapToScene(qreal ax, qreal ay) const
+{ return mapToScene(QPointF(ax, ay)); }
+inline QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, qreal ax, qreal ay) const
+{ return mapFromItem(item, QPointF(ax, ay)); }
+inline QPointF QGraphicsItem::mapFromParent(qreal ax, qreal ay) const
+{ return mapFromParent(QPointF(ax, ay)); }
+inline QPointF QGraphicsItem::mapFromScene(qreal ax, qreal ay) const
+{ return mapFromScene(QPointF(ax, ay)); }
+inline QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapToItem(item, QRectF(ax, ay, w, h)); }
+inline QPolygonF QGraphicsItem::mapToParent(qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapToParent(QRectF(ax, ay, w, h)); }
+inline QPolygonF QGraphicsItem::mapToScene(qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapToScene(QRectF(ax, ay, w, h)); }
+inline QRectF QGraphicsItem::mapRectToItem(const QGraphicsItem *item, qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapRectToItem(item, QRectF(ax, ay, w, h)); }
+inline QRectF QGraphicsItem::mapRectToParent(qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapRectToParent(QRectF(ax, ay, w, h)); }
+inline QRectF QGraphicsItem::mapRectToScene(qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapRectToScene(QRectF(ax, ay, w, h)); }
+inline QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapFromItem(item, QRectF(ax, ay, w, h)); }
+inline QPolygonF QGraphicsItem::mapFromParent(qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapFromParent(QRectF(ax, ay, w, h)); }
+inline QPolygonF QGraphicsItem::mapFromScene(qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapFromScene(QRectF(ax, ay, w, h)); }
+inline QRectF QGraphicsItem::mapRectFromItem(const QGraphicsItem *item, qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapRectFromItem(item, QRectF(ax, ay, w, h)); }
+inline QRectF QGraphicsItem::mapRectFromParent(qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapRectFromParent(QRectF(ax, ay, w, h)); }
+inline QRectF QGraphicsItem::mapRectFromScene(qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapRectFromScene(QRectF(ax, ay, w, h)); }
+
+
+class Q_GUI_EXPORT QGraphicsObject : public QObject, public QGraphicsItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QGraphicsObject * parent READ parentObject WRITE setParentItem NOTIFY parentChanged DESIGNABLE false)
+ Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged FINAL)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(QPointF pos READ pos WRITE setPos FINAL)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged FINAL)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged FINAL)
+ Q_PROPERTY(qreal z READ zValue WRITE setZValue NOTIFY zChanged FINAL)
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged)
+ Q_PROPERTY(QPointF transformOriginPoint READ transformOriginPoint WRITE setTransformOriginPoint)
+#ifndef QT_NO_GRAPHICSEFFECT
+ Q_PROPERTY(QGraphicsEffect *effect READ graphicsEffect WRITE setGraphicsEffect)
+#endif
+ Q_PRIVATE_PROPERTY(QGraphicsItem::d_func(), QDeclarativeListProperty<QGraphicsObject> children READ childrenList DESIGNABLE false NOTIFY childrenChanged)
+ Q_PRIVATE_PROPERTY(QGraphicsItem::d_func(), qreal width READ width WRITE setWidth NOTIFY widthChanged RESET resetWidth FINAL)
+ Q_PRIVATE_PROPERTY(QGraphicsItem::d_func(), qreal height READ height WRITE setHeight NOTIFY heightChanged RESET resetHeight FINAL)
+ Q_CLASSINFO("DefaultProperty", "children")
+ Q_INTERFACES(QGraphicsItem)
+public:
+ QGraphicsObject(QGraphicsItem *parent = 0);
+
+ // ### Qt 5: Disambiguate
+#ifdef Q_NO_USING_KEYWORD
+ const QObjectList &children() const { return QObject::children(); }
+#else
+ using QObject::children;
+#endif
+
+#ifndef QT_NO_GESTURES
+ void grabGesture(Qt::GestureType type, Qt::GestureFlags flags = Qt::GestureFlags());
+ void ungrabGesture(Qt::GestureType type);
+#endif
+
+protected Q_SLOTS:
+ void updateMicroFocus();
+
+Q_SIGNALS:
+ void parentChanged();
+ void opacityChanged();
+ void visibleChanged();
+ void enabledChanged();
+ void xChanged();
+ void yChanged();
+ void zChanged();
+ void rotationChanged();
+ void scaleChanged();
+ void childrenChanged();
+ void widthChanged();
+ void heightChanged();
+
+protected:
+ QGraphicsObject(QGraphicsItemPrivate &dd, QGraphicsItem *parent, QGraphicsScene *scene);
+private:
+ friend class QGraphicsItem;
+ friend class QGraphicsItemPrivate;
+};
+
+
+class QAbstractGraphicsShapeItemPrivate;
+class Q_GUI_EXPORT QAbstractGraphicsShapeItem : public QGraphicsItem
+{
+public:
+ QAbstractGraphicsShapeItem(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // ### obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ ~QAbstractGraphicsShapeItem();
+
+ QPen pen() const;
+ void setPen(const QPen &pen);
+
+ QBrush brush() const;
+ void setBrush(const QBrush &brush);
+
+ bool isObscuredBy(const QGraphicsItem *item) const;
+ QPainterPath opaqueArea() const;
+
+protected:
+ QAbstractGraphicsShapeItem(QAbstractGraphicsShapeItemPrivate &dd,
+ QGraphicsItem *parent, QGraphicsScene *scene);
+
+private:
+ Q_DISABLE_COPY(QAbstractGraphicsShapeItem)
+ Q_DECLARE_PRIVATE(QAbstractGraphicsShapeItem)
+};
+
+class QGraphicsPathItemPrivate;
+class Q_GUI_EXPORT QGraphicsPathItem : public QAbstractGraphicsShapeItem
+{
+public:
+ QGraphicsPathItem(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // ### obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ QGraphicsPathItem(const QPainterPath &path, QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // ### obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ ~QGraphicsPathItem();
+
+ QPainterPath path() const;
+ void setPath(const QPainterPath &path);
+
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+ bool contains(const QPointF &point) const;
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+ bool isObscuredBy(const QGraphicsItem *item) const;
+ QPainterPath opaqueArea() const;
+
+ enum { Type = 2 };
+ int type() const;
+
+protected:
+ bool supportsExtension(Extension extension) const;
+ void setExtension(Extension extension, const QVariant &variant);
+ QVariant extension(const QVariant &variant) const;
+
+private:
+ Q_DISABLE_COPY(QGraphicsPathItem)
+ Q_DECLARE_PRIVATE(QGraphicsPathItem)
+};
+
+class QGraphicsRectItemPrivate;
+class Q_GUI_EXPORT QGraphicsRectItem : public QAbstractGraphicsShapeItem
+{
+public:
+ QGraphicsRectItem(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // ### obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ QGraphicsRectItem(const QRectF &rect, QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // ### obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ QGraphicsRectItem(qreal x, qreal y, qreal w, qreal h, QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // ### obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ ~QGraphicsRectItem();
+
+ QRectF rect() const;
+ void setRect(const QRectF &rect);
+ inline void setRect(qreal x, qreal y, qreal w, qreal h);
+
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+ bool contains(const QPointF &point) const;
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+ bool isObscuredBy(const QGraphicsItem *item) const;
+ QPainterPath opaqueArea() const;
+
+ enum { Type = 3 };
+ int type() const;
+
+protected:
+ bool supportsExtension(Extension extension) const;
+ void setExtension(Extension extension, const QVariant &variant);
+ QVariant extension(const QVariant &variant) const;
+
+private:
+ Q_DISABLE_COPY(QGraphicsRectItem)
+ Q_DECLARE_PRIVATE(QGraphicsRectItem)
+};
+
+inline void QGraphicsRectItem::setRect(qreal ax, qreal ay, qreal w, qreal h)
+{ setRect(QRectF(ax, ay, w, h)); }
+
+class QGraphicsEllipseItemPrivate;
+class Q_GUI_EXPORT QGraphicsEllipseItem : public QAbstractGraphicsShapeItem
+{
+public:
+ QGraphicsEllipseItem(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // ### obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ QGraphicsEllipseItem(const QRectF &rect, QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // ### obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ QGraphicsEllipseItem(qreal x, qreal y, qreal w, qreal h, QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // ### obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ ~QGraphicsEllipseItem();
+
+ QRectF rect() const;
+ void setRect(const QRectF &rect);