summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview
diff options
context:
space:
mode:
authorAlexis Menard <alexis.menard@nokia.com>2009-04-17 14:06:06 (GMT)
committerAlexis Menard <alexis.menard@nokia.com>2009-04-17 14:06:06 (GMT)
commitf15b8a83e2e51955776a3f07cb85ebfc342dd8ef (patch)
treec5dc684986051654898db11ce73e03b9fec8db99 /src/gui/graphicsview
downloadQt-f15b8a83e2e51955776a3f07cb85ebfc342dd8ef.zip
Qt-f15b8a83e2e51955776a3f07cb85ebfc342dd8ef.tar.gz
Qt-f15b8a83e2e51955776a3f07cb85ebfc342dd8ef.tar.bz2
Initial import of statemachine branch from the old kinetic repository
Diffstat (limited to 'src/gui/graphicsview')
-rw-r--r--src/gui/graphicsview/graphicsview.pri46
-rw-r--r--src/gui/graphicsview/qgraphicsgridlayout.cpp651
-rw-r--r--src/gui/graphicsview/qgraphicsgridlayout.h143
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp9036
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h1032
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h291
-rw-r--r--src/gui/graphicsview/qgraphicsitemanimation.cpp599
-rw-r--r--src/gui/graphicsview/qgraphicsitemanimation.h120
-rw-r--r--src/gui/graphicsview/qgraphicslayout.cpp423
-rw-r--r--src/gui/graphicsview/qgraphicslayout.h95
-rw-r--r--src/gui/graphicsview/qgraphicslayout_p.cpp198
-rw-r--r--src/gui/graphicsview/qgraphicslayout_p.h103
-rw-r--r--src/gui/graphicsview/qgraphicslayoutitem.cpp852
-rw-r--r--src/gui/graphicsview/qgraphicslayoutitem.h152
-rw-r--r--src/gui/graphicsview/qgraphicslayoutitem_p.h91
-rw-r--r--src/gui/graphicsview/qgraphicslinearlayout.cpp547
-rw-r--r--src/gui/graphicsview/qgraphicslinearlayout.h121
-rw-r--r--src/gui/graphicsview/qgraphicsproxywidget.cpp1496
-rw-r--r--src/gui/graphicsview/qgraphicsproxywidget.h147
-rw-r--r--src/gui/graphicsview/qgraphicsproxywidget_p.h125
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp5360
-rw-r--r--src/gui/graphicsview/qgraphicsscene.h301
-rw-r--r--src/gui/graphicsview/qgraphicsscene_bsp.cpp328
-rw-r--r--src/gui/graphicsview/qgraphicsscene_bsp_p.h137
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h265
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.cpp1678
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.h311
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp3887
-rw-r--r--src/gui/graphicsview/qgraphicsview.h314
-rw-r--r--src/gui/graphicsview/qgraphicsview_p.h191
-rw-r--r--src/gui/graphicsview/qgraphicswidget.cpp2273
-rw-r--r--src/gui/graphicsview/qgraphicswidget.h255
-rw-r--r--src/gui/graphicsview/qgraphicswidget_p.cpp740
-rw-r--r--src/gui/graphicsview/qgraphicswidget_p.h232
-rw-r--r--src/gui/graphicsview/qgridlayoutengine.cpp1542
-rw-r--r--src/gui/graphicsview/qgridlayoutengine_p.h449
36 files changed, 34531 insertions, 0 deletions
diff --git a/src/gui/graphicsview/graphicsview.pri b/src/gui/graphicsview/graphicsview.pri
new file mode 100644
index 0000000..02d9bb1
--- /dev/null
+++ b/src/gui/graphicsview/graphicsview.pri
@@ -0,0 +1,46 @@
+# Qt graphicsview module
+
+HEADERS += \
+ graphicsview/qgraphicsitem.h \
+ graphicsview/qgraphicsitem_p.h \
+ graphicsview/qgraphicsitemanimation.h \
+ graphicsview/qgraphicsscene.h \
+ graphicsview/qgraphicsscene_p.h \
+ graphicsview/qgraphicsscene_bsp_p.h \
+ graphicsview/qgraphicssceneevent.h \
+ graphicsview/qgraphicsview_p.h \
+ graphicsview/qgraphicsview.h
+
+SOURCES += \
+ graphicsview/qgraphicsitem.cpp \
+ graphicsview/qgraphicsitemanimation.cpp \
+ graphicsview/qgraphicsscene.cpp \
+ graphicsview/qgraphicsscene_bsp.cpp \
+ graphicsview/qgraphicssceneevent.cpp \
+ graphicsview/qgraphicsview.cpp
+
+# Widgets on the canvas
+
+HEADERS += \
+ graphicsview/qgraphicslayout.h \
+ graphicsview/qgraphicslayout_p.h \
+ graphicsview/qgraphicslayoutitem.h \
+ graphicsview/qgraphicslayoutitem_p.h \
+ graphicsview/qgraphicslinearlayout.h \
+ graphicsview/qgraphicswidget.h \
+ graphicsview/qgraphicswidget_p.h \
+ graphicsview/qgridlayoutengine_p.h \
+ graphicsview/qgraphicsproxywidget.h \
+ graphicsview/qgraphicsgridlayout.h
+
+SOURCES += \
+ graphicsview/qgraphicslayout.cpp \
+ graphicsview/qgraphicslayout_p.cpp \
+ graphicsview/qgraphicslayoutitem.cpp \
+ graphicsview/qgraphicslinearlayout.cpp \
+ graphicsview/qgraphicswidget.cpp \
+ graphicsview/qgraphicswidget_p.cpp \
+ graphicsview/qgridlayoutengine.cpp \
+ graphicsview/qgraphicsproxywidget.cpp \
+ graphicsview/qgraphicsgridlayout.cpp
+
diff --git a/src/gui/graphicsview/qgraphicsgridlayout.cpp b/src/gui/graphicsview/qgraphicsgridlayout.cpp
new file mode 100644
index 0000000..1e21b54
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsgridlayout.cpp
@@ -0,0 +1,651 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 multimedia
+ \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.
+
+ \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
+};
+
+QLayoutStyleInfo QGraphicsGridLayoutPrivate::styleInfo() const
+{
+ static QWidget *wid = 0;
+ if (!wid)
+ wid = new QWidget;
+ QGraphicsItem *item = parentItem();
+ QStyle *style = (item && item->isWidget()) ? static_cast<QGraphicsWidget*>(item)->style() : qApp->style();
+ return QLayoutStyleInfo(style, wid);
+}
+
+/*!
+ 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;
+ }
+
+ 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);
+ delete gridItem;
+ invalidate();
+ }
+}
+
+/*!
+ \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);
+ return d->engine.sizeHint(d->styleInfo(), which , constraint) + QSizeF(left + right, top + bottom);
+}
+
+
+#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/gui/graphicsview/qgraphicsgridlayout.h b/src/gui/graphicsview/qgraphicsgridlayout.h
new file mode 100644
index 0000000..5b40d6b
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsgridlayout.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 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/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
new file mode 100644
index 0000000..d95b194
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -0,0 +1,9036 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 multimedia
+ \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 \l{The Graphics View Framework}
+
+ \img 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
+
+ QGraphicsItem supports affine transformations in addition to its base
+ position, pos(). To change the item's transformation, you can either pass
+ a transformation matrix to setTransform(), or call one of the convenience
+ functions rotate(), scale(), translate(), or shear(). 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().
+
+ 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.
+
+ 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 functionaly is separate from 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().
+
+ 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, {The Graphics View Framework}
+*/
+
+/*!
+ \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
+*/
+
+/*!
+ \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 ts
+ 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.
+*/
+
+/*!
+ \enum QGraphicsItem::GraphicsItemChange
+
+ ItemVisibleHasChanged,
+ ItemEnabledHasChanged,
+ ItemSelectedHasChanged,
+ ItemParentHasChanged,
+ ItemSceneHasChanged
+
+ 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 only sent when the item's local position changes, relative to its
+ parent, has changed (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 only sent 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 only sent when the item's local transformation matrix
+ changes (i.e., as a result of calling setTransform(), or one of the
+ convenience transformation functions, such as rotate()). The value
+ argument is the new matrix (i.e., a QTransform); to get the old matrix,
+ call transform(). Do not call setTransform() or any of the transformation
+ convenience functions in itemChange() as this notification is delivered;
+ instead, you can return the new matrix from itemChange().
+
+ \value ItemTransformHasChanged The item's transformation matrix has
+ changed. This notification is only sent after the item's local
+ trasformation 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 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 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 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.
+*/
+
+/*!
+ \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().
+*/
+
+#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 <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 <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 <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 <math.h>
+
+QT_BEGIN_NAMESPACE
+
+// QRectF::intersects() returns false always if either the source or target
+// rectangle's width or height are 0. This works around that problem.
+static QRectF _q_adjustedRect(const QRectF &rect)
+{
+ static const qreal p = (qreal)0.00001;
+ QRectF r = rect;
+ if (!r.width())
+ r.adjust(-p, 0, p, 0);
+ if (!r.height())
+ r.adjust(0, -p, 0, p);
+ return r;
+}
+
+static QRect _q_adjustedRect(const QRect &rect)
+{
+ QRect r = rect;
+ if (!r.width())
+ r.adjust(0, 0, 1, 0);
+ if (!r.height())
+ r.adjust(0, 0, 0, 1);
+ return r;
+}
+
+/*
+ ### Move this into QGraphicsItemPrivate
+ */
+class QGraphicsItemCustomDataStore
+{
+public:
+ QMap<const QGraphicsItem *, QMap<int, QVariant> > data;
+};
+Q_GLOBAL_STATIC(QGraphicsItemCustomDataStore, qt_dataStore)
+
+/*!
+ \internal
+
+ Removes the first instance of \a child from \a children. This is a
+ heuristic approach that assumes that it's common to remove items from the
+ start or end of the list.
+*/
+static void qt_graphicsitem_removeChild(QGraphicsItem *child, QList<QGraphicsItem *> *children)
+{
+ const int n = children->size();
+ for (int i = 0; i < (n + 1) / 2; ++i) {
+ if (children->at(i) == child) {
+ children->removeAt(i);
+ return;
+ }
+ int j = n - i - 1;
+ if (children->at(j) == child) {
+ children->removeAt(j);
+ return;
+ }
+ }
+}
+
+/*!
+ \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 -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;
+ }
+
+ // Inherit the enabled-state from our parents.
+ if ((parent && ((parent->d_ptr->ancestorFlags & flag)
+ || (int(parent->d_ptr->flags & childFlag) == childFlag)
+ || (childFlag == -1 && parent->d_ptr->handlesChildEvents)))) {
+ enabled = true;
+ ancestorFlags |= flag;
+ }
+
+ // Top-level root items don't have any ancestors, so there are no
+ // ancestor flags either.
+ if (!parent)
+ 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))
+ return;
+ }
+
+ foreach (QGraphicsItem *child, children)
+ child->d_ptr->updateAncestorFlag(childFlag, flag, enabled, false);
+}
+
+/*!
+ \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
+
+ Returns true if this item or any of its ancestors are untransformable.
+*/
+bool QGraphicsItemPrivate::itemIsUntransformable() const
+{
+ return (flags & QGraphicsItem::ItemIgnoresTransformations)
+ || (ancestorFlags & AncestorIgnoresTransformations);
+}
+
+/*!
+ \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
+
+ Empty all cached pixmaps from the pixmap cache.
+*/
+void QGraphicsItemCache::purge()
+{
+ QPixmapCache::remove(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.
+
+ 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.
+*/
+QGraphicsItem::~QGraphicsItem()
+{
+ clearFocus();
+ d_ptr->removeExtraItemCache();
+
+ QVariant variant;
+ foreach (QGraphicsItem *child, d_ptr->children) {
+ if (QGraphicsItem *parent = child->parentItem()) {
+ qVariantSetValue<QGraphicsItem *>(variant, child);
+ parent->itemChange(ItemChildRemovedChange, variant);
+ }
+ delete child;
+ }
+ d_ptr->children.clear();
+
+ if (QGraphicsItem *parent = parentItem()) {
+ qVariantSetValue<QGraphicsItem *>(variant, this);
+ parent->itemChange(ItemChildRemovedChange, variant);
+ qt_graphicsitem_removeChild(this, &parent->d_func()->children);
+ }
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->_q_removeItemLater(this);
+
+ if (d_ptr->hasTransform) {
+ delete static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ }
+
+ delete d_ptr;
+
+ qt_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(), children()
+*/
+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.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
+{
+ if (isWidget() && static_cast<const QGraphicsWidget *>(this)->isWindow())
+ return static_cast<QGraphicsWidget *>(const_cast<QGraphicsItem *>(this));
+ if (QGraphicsWidget *parent = parentWidget())
+ return parent->window();
+ return 0;
+}
+
+/*!
+ Sets this item's parent item to \a parent. If this item already has a
+ parent, it is first removed from the previous parent. If \a parent 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.
+
+ \sa parentItem(), children()
+*/
+void QGraphicsItem::setParentItem(QGraphicsItem *parent)
+{
+ if (parent == this) {
+ qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this);
+ return;
+ }
+ if (parent == d_ptr->parent)
+ return;
+ QVariant variant;
+ qVariantSetValue<QGraphicsItem *>(variant, parent);
+ parent = qVariantValue<QGraphicsItem *>(itemChange(ItemParentChange, variant));
+ if (parent == d_ptr->parent)
+ return;
+
+ if (QGraphicsWidget *w = d_ptr->isWidget ? static_cast<QGraphicsWidget *>(this) : parentWidget()) {
+ // Update the child focus chain; when reparenting a widget that has a
+ // focus child, ensure that that focus child clears its focus child
+ // chain from our parents before it's reparented.
+ if (QGraphicsWidget *focusChild = w->focusWidget())
+ focusChild->clearFocus();
+ }
+
+ // We anticipate geometry changes
+ prepareGeometryChange();
+
+ if (d_ptr->parent) {
+ // Remove from current parent
+ qt_graphicsitem_removeChild(this, &d_ptr->parent->d_func()->children);
+ qVariantSetValue<QGraphicsItem *>(variant, this);
+ d_ptr->parent->itemChange(ItemChildRemovedChange, variant);
+ }
+
+ if ((d_ptr->parent = parent)) {
+ bool implicitUpdate = false;
+ if (parent->d_func()->scene && parent->d_func()->scene != d_ptr->scene) {
+ // Move this item to its new parent's scene
+ parent->d_func()->scene->addItem(this);
+ implicitUpdate = true;
+ } else if (!parent->d_func()->scene && d_ptr->scene) {
+ // Remove this item from its former scene
+ d_ptr->scene->removeItem(this);
+ }
+
+ d_ptr->parent->d_func()->children << this;
+ qVariantSetValue<QGraphicsItem *>(variant, this);
+ d_ptr->parent->itemChange(ItemChildAddedChange, variant);
+ if (!implicitUpdate)
+ d_ptr->updateHelper();
+
+ // Inherit ancestor flags from the new parent.
+ d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
+ d_ptr->updateAncestorFlag(ItemClipsChildrenToShape);
+ d_ptr->updateAncestorFlag(ItemIgnoresTransformations);
+
+ // Update item visible / enabled.
+ if (d_ptr->parent->isVisible() != d_ptr->visible) {
+ if (!d_ptr->parent->isVisible() || !d_ptr->explicitlyHidden)
+ d_ptr->setVisibleHelper(d_ptr->parent->isVisible(), /* explicit = */ false, /* update = */ !implicitUpdate);
+ }
+ if (d_ptr->parent->isEnabled() != d_ptr->enabled) {
+ if (!d_ptr->parent->isEnabled() || !d_ptr->explicitlyDisabled)
+ d_ptr->setEnabledHelper(d_ptr->parent->isEnabled(), /* explicit = */ false, /* update = */ !implicitUpdate);
+ }
+
+ } else {
+ // Inherit ancestor flags from the new parent.
+ d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
+ d_ptr->updateAncestorFlag(ItemClipsChildrenToShape);
+ d_ptr->updateAncestorFlag(ItemIgnoresTransformations);
+
+ // Update item visible / enabled.
+ if (!d_ptr->visible && !d_ptr->explicitlyHidden)
+ d_ptr->setVisibleHelper(true, /* explicit = */ false);
+ if (!d_ptr->enabled && !d_ptr->explicitlyDisabled)
+ d_ptr->setEnabledHelper(true, /* explicit = */ false);
+
+ d_ptr->updateHelper();
+ }
+
+ if (d_ptr->scene) {
+ // Invalidate any sort caching; arrival of a new item means we need to
+ // resort.
+ d_ptr->scene->d_func()->invalidateSortCache();
+ }
+
+ // Resolve opacity.
+ if (QGraphicsItem *p = d_ptr->parent)
+ d_ptr->resolveEffectiveOpacity(p->effectiveOpacity());
+ else
+ d_ptr->resolveEffectiveOpacity(1.0);
+
+ // Resolve depth.
+ d_ptr->resolveDepth(parent ? parent->d_ptr->depth : -1);
+
+ // Invalidate transform cache.
+ d_ptr->invalidateSceneTransformCache();
+
+ // Deliver post-change notification
+ itemChange(QGraphicsItem::ItemParentHasChanged, qVariantFromValue<QGraphicsItem *>(parent));
+}
+
+/*!
+ \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 returned in no
+ particular order.
+
+ \sa setParentItem()
+*/
+QList<QGraphicsItem *> QGraphicsItem::childItems() const
+{
+ 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 isWidget() && (static_cast<const QGraphicsWidget *>(this)->windowType() & Qt::Window);
+}
+
+/*!
+ 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(flags() | flag);
+ else
+ setFlags(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.
+
+ \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;
+
+ // Flags that alter the geometry of the item (or its children).
+ int geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations);
+ bool fullUpdate = (flags & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask);
+ if (fullUpdate)
+ d_ptr->fullUpdateHelper();
+
+ // Keep the old flags to compare the diff.
+ GraphicsItemFlags oldFlags = this->flags();
+
+ // Update flags.
+ d_ptr->flags = flags;
+
+ // Reresolve effective opacity if the opacity flags change.
+ static const quint32 opacityFlagsMask = ItemIgnoresParentOpacity | ItemDoesntPropagateOpacityToChildren;
+ if ((flags & opacityFlagsMask) != (oldFlags & opacityFlagsMask)) {
+ if (QGraphicsItem *p = d_ptr->parent)
+ d_ptr->resolveEffectiveOpacity(p->effectiveOpacity());
+ else
+ d_ptr->resolveEffectiveOpacity(1.0);
+ }
+
+ 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);
+ }
+
+ if ((flags & ItemIgnoresTransformations) != (oldFlags & ItemIgnoresTransformations)) {
+ // Item children clipping changes. Propagate the ancestor flag to
+ // all children.
+ d_ptr->updateAncestorFlag(ItemIgnoresTransformations);
+ }
+
+ // ### Why updateHelper?
+ d_ptr->updateHelper();
+
+ // 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);
+ if (mode == NoCache) {
+ d_ptr->removeExtraItemCache();
+ } else {
+ QGraphicsItemCache *cache = d_ptr->extraItemCache();
+
+ // Reset old cache
+ cache->purge();
+
+ if (mode == ItemCoordinateCache) {
+ if (cache->key.isEmpty()) {
+ // Generate new simple pixmap cache key.
+ QString tmp;
+ tmp.sprintf("qgv-%p", this);
+ cache->key = tmp;
+ }
+ if (lastMode == mode && cache->fixedSize == logicalCacheSize)
+ noVisualChange = true;
+ cache->fixedSize = logicalCacheSize;
+ }
+ }
+ if (!noVisualChange)
+ update();
+}
+
+#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)
+{
+ QString newCursor = itemChange(ItemToolTipChange, toolTip).toString();
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraToolTip, toolTip);
+ itemChange(ItemToolTipHasChanged, toolTip);
+}
+#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 parent's cursor is used.
+
+ \sa setCursor(), hasCursor(), unsetCursor(), QWidget::cursor,
+ QApplication::overrideCursor()
+*/
+QCursor QGraphicsItem::cursor() const
+{
+ return qVariantValue<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)
+{
+ QCursor newCursor = qVariantValue<QCursor>(itemChange(ItemCursorChange,
+ qVariantFromValue<QCursor>(cursor)));
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraCursor, newCursor);
+ d_ptr->hasCursor = 1;
+ if (d_ptr->scene) {
+ foreach (QGraphicsView *view, d_ptr->scene->views()) {
+ // 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, qVariantFromValue<QCursor>(newCursor));
+}
+
+/*!
+ 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;
+
+ // Modify the property.
+ newVisible = q_ptr->itemChange(QGraphicsItem::ItemVisibleChange, quint32(newVisible)).toBool();
+ if (visible == quint32(newVisible))
+ return;
+ visible = newVisible;
+
+ // Schedule redrawing
+ if (update)
+ updateHelper(QRectF(), /* force = */ true);
+
+ // Certain properties are dropped as an item becomes invisible.
+ if (!newVisible) {
+ if (scene) {
+ if (scene->d_func()->mouseGrabberItems.contains(q))
+ q->ungrabMouse();
+ if (scene->d_func()->keyboardGrabberItems.contains(q))
+ q->ungrabKeyboard();
+ }
+ if (q_ptr->hasFocus() && scene) {
+ // Hiding the closest non-window ancestor of the focus item
+ QGraphicsItem *focusItem = scene->focusItem();
+ bool clear = true;
+ if (isWidget && !focusItem->isWindow()) {
+ do {
+ if (focusItem == q_ptr) {
+ clear = !static_cast<QGraphicsWidget *>(q_ptr)->focusNextPrevChild(true);
+ break;
+ }
+ } while ((focusItem = focusItem->parentWidget()) && !focusItem->isWindow());
+ }
+ if (clear)
+ q_ptr->clearFocus();
+ }
+ if (q_ptr->isSelected())
+ q_ptr->setSelected(false);
+ } else {
+ if (isWidget && scene) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr);
+ if (widget->windowType() == Qt::Popup)
+ scene->d_func()->addPopup(widget);
+ }
+ }
+
+ // Update children with explicitly = false.
+ foreach (QGraphicsItem *child, children) {
+ if (!newVisible || !child->d_ptr->explicitlyHidden)
+ child->d_ptr->setVisibleHelper(newVisible, false);
+ }
+
+ // Enable subfocus
+ if (newVisible && isWidget) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr);
+ QGraphicsWidget *fw = widget->focusWidget();
+ if (fw && fw != scene->focusItem())
+ scene->setFocusItem(fw);
+ }
+
+ // Deliver post-change notification.
+ q_ptr->itemChange(QGraphicsItem::ItemVisibleHasChanged, quint32(visible));
+}
+
+/*!
+ 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-window 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->isWindow() && q_ptr->isAncestorOf(focusItem)) {
+ do {
+ if (focusItem == q_ptr) {
+ clear = !static_cast<QGraphicsWidget *>(q_ptr)->focusNextPrevChild(true);
+ break;
+ }
+ } while ((focusItem = focusItem->parentWidget()) && !focusItem->isWindow());
+ }
+ if (clear)
+ q_ptr->clearFocus();
+ }
+ if (q_ptr->isSelected())
+ q_ptr->setSelected(false);
+ }
+
+ // Modify the property.
+ enabled = q_ptr->itemChange(QGraphicsItem::ItemEnabledChange, quint32(newEnabled)).toBool();
+
+ // Schedule redraw.
+ if (update)
+ updateHelper();
+
+ 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, quint32(enabled));
+}
+
+/*!
+ 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;
+ bool newSelected = itemChange(ItemSelectedChange, quint32(selected)).toBool();
+ if (d_ptr->selected == newSelected)
+ return;
+ d_ptr->selected = newSelected;
+
+ d_ptr->updateHelper();
+
+ 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, quint32(d_ptr->selected));
+}
+
+/*!
+ \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
+{
+ if (d_ptr->hasOpacity) {
+ QVariant o = d_ptr->extra(QGraphicsItemPrivate::ExtraOpacity);
+ if (!o.isNull())
+ return o.toDouble();
+ }
+ return qreal(1.0);
+}
+
+/*!
+ \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
+{
+ QVariant effectiveOpacity = d_ptr->extra(QGraphicsItemPrivate::ExtraEffectiveOpacity);
+ return effectiveOpacity.isNull() ? qreal(1.0) : qreal(effectiveOpacity.toDouble());
+}
+
+/*!
+ \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.
+ qreal newOpacity = itemChange(ItemOpacityChange, double(opacity)).toDouble();
+
+ // Normalize.
+ newOpacity = qBound<qreal>(0.0, newOpacity, 1.0);
+
+ // No change? Done.
+ if (qFuzzyCompare(newOpacity, this->opacity()))
+ return;
+
+ // Assign local opacity.
+ if (qFuzzyCompare(newOpacity, qreal(1.0))) {
+ // Opaque, unset opacity.
+ d_ptr->hasOpacity = 0;
+ d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraOpacity);
+ } else {
+ d_ptr->hasOpacity = 1;
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraOpacity, double(newOpacity));
+ }
+
+ // Resolve effective opacity.
+ if (QGraphicsItem *p = d_ptr->parent)
+ d_ptr->resolveEffectiveOpacity(p->effectiveOpacity());
+ else
+ d_ptr->resolveEffectiveOpacity(1.0);
+
+ // Notify change.
+ itemChange(ItemOpacityHasChanged, newOpacity);
+
+ // Update.
+ d_ptr->fullUpdateHelper();
+}
+
+/*!
+ 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 (setHandlesChildEvents()), 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)
+{
+ d_ptr->acceptsHover = quint32(enabled);
+}
+
+/*!
+ \obsolete
+
+ Use setAcceptHoverEvents(\a enabled) instead.
+*/
+void QGraphicsItem::setAcceptsHoverEvents(bool enabled)
+{
+ d_ptr->acceptsHover = quint32(enabled);
+}
+
+/*!
+ 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;
+}
+
+/*!
+ 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));
+}
+
+/*!
+ Returns true if this item has keyboard input focus; otherwise, returns
+ false.
+
+ \sa QGraphicsScene::focusItem(), setFocus(), QGraphicsScene::setFocusItem()
+*/
+bool QGraphicsItem::hasFocus() const
+{
+ return (d_ptr->scene && d_ptr->scene->focusItem() == this);
+}
+
+/*!
+ Gives keyboard input focus to this item. The \a focusReason argument will
+ be passed into any focus event generated by this function; it is used to
+ give an explanation of what caused the item to get focus.
+
+ Only items that set the ItemIsFocusable flag can accept keyboard focus.
+
+ If this item is not visible (i.e., isVisible() returns false), not
+ enabled, not associated with a scene, or if it already has input focus,
+ this function will do nothing.
+
+ As a result of calling this function, this item will receive a focus in
+ event with \a focusReason. If another item already has focus, that item
+ will first receive a focus out event indicating that it has lost input
+ focus.
+
+ \sa clearFocus(), hasFocus()
+*/
+void QGraphicsItem::setFocus(Qt::FocusReason focusReason)
+{
+ if (!d_ptr->scene || !isEnabled() || hasFocus() || !(d_ptr->flags & ItemIsFocusable))
+ return;
+ if (isVisible()) {
+ // Visible items immediately gain focus from scene.
+ d_ptr->scene->setFocusItem(this, focusReason);
+ } else if (d_ptr->isWidget) {
+ // Just set up subfocus.
+ static_cast<QGraphicsWidget *>(this)->d_func()->setFocusWidget();
+ }
+}
+
+/*!
+ Takes keyboard input focus from the item.
+
+ If it has focus, a 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(), QGraphicsWidget::focusPolicy
+*/
+void QGraphicsItem::clearFocus()
+{
+ if (!d_ptr->scene)
+ return;
+ if (d_ptr->isWidget) {
+ // Invisible widget items with focus must explicitly clear subfocus.
+ static_cast<QGraphicsWidget *>(this)->d_func()->clearFocusWidget();
+ }
+ if (d_ptr->scene->focusItem() == this) {
+ // If this item has the scene's input focus, clear it.
+ d_ptr->scene->setFocusItem(0);
+ }
+}
+
+/*!
+ \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(), matrix(), {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()
+*/
+
+/*!
+ \fn QGraphicsItem::y() const
+
+ This convenience function is equivalent to calling pos().y().
+
+ \sa x()
+*/
+
+/*!
+ 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 and notifies the change. If \a update is true,
+ the item is also updated; otherwise it is not updated before and after the
+ change.
+*/
+void QGraphicsItemPrivate::setPosHelper(const QPointF &pos, bool update)
+{
+ Q_Q(QGraphicsItem);
+ if (this->pos == pos)
+ return;
+
+ // Notify the item that the position is changing.
+ QPointF newPos = q->itemChange(QGraphicsItem::ItemPositionChange, pos).toPointF();
+ if (newPos == this->pos)
+ return;
+
+ // Update and repositition.
+ if (scene && update) {
+ fullUpdateHelper(true);
+ q->prepareGeometryChange();
+ }
+ this->pos = newPos;
+ invalidateSceneTransformCache();
+
+ // Send post-notification.
+ q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPos);
+}
+
+/*!
+ 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)
+{
+ d_ptr->setPosHelper(pos, /* update = */ true);
+}
+
+/*!
+ \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. If no matrix has been set, the
+ identity matrix is returned.
+
+ \sa setTransform(), sceneTransform()
+*/
+QTransform QGraphicsItem::transform() const
+{
+ if (!d_ptr->hasTransform)
+ return QTransform();
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ Q_ASSERT(transformData);
+ if (transformData->dirty) {
+ QGraphicsItem *that = const_cast<QGraphicsItem *>(this);
+ QTransform newTransform;
+ QPointF center = transformData->transformCenter;
+ newTransform.translate(center.x(), center.y());
+ newTransform.rotate(transformData->rotationZ, Qt::ZAxis);
+ newTransform.rotate(transformData->rotationY, Qt::YAxis);
+ newTransform.rotate(transformData->rotationX, Qt::XAxis);
+ newTransform.scale(transformData->scaleX, transformData->scaleY);
+ newTransform *= transformData->baseTransform;
+ newTransform.translate(-center.x(), -center.y());
+ transformData->transform = newTransform;
+ transformData->dirty = false;
+ }
+ return transformData->transform;
+}
+
+/*!
+ \obsolete
+
+ Use sceneTransform() instead.
+
+ \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}
+*/
+QMatrix QGraphicsItem::sceneMatrix() const
+{
+ return 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.
+
+ \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}
+*/
+QTransform QGraphicsItem::sceneTransform() const
+{
+ // Check if there's any entry in the transform cache.
+ QGraphicsScenePrivate *sd = d_ptr->scene ? d_ptr->scene->d_func() : 0;
+ int index = d_ptr->sceneTransformIndex;
+ if (sd && index != -1 && sd->validTransforms.testBit(index))
+ return sd->sceneTransformCache[index];
+
+ // Calculate local transform.
+ QTransform m;
+ if (d_ptr->hasTransform) {
+ m = transform();
+ m *= QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y());
+ } else {
+ // ### ? QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y())
+ m.translate(d_ptr->pos.x(), d_ptr->pos.y());
+ }
+
+ // Combine with parent and add to cache.
+ if (d_ptr->parent) {
+ m *= d_ptr->parent->sceneTransform();
+ // Don't cache toplevels
+ if (sd) {
+ if (index == -1) {
+ if (!sd->freeSceneTransformSlots.isEmpty()) {
+ index = sd->freeSceneTransformSlots.last();
+ sd->freeSceneTransformSlots.pop_back();
+ } else {
+ index = sd->sceneTransformCache.size();
+ }
+ d_ptr->sceneTransformIndex = index;
+ if (index >= sd->validTransforms.size()) {
+ sd->validTransforms.resize(index + 1);
+ sd->sceneTransformCache.resize(index + 1);
+ }
+ }
+ sd->validTransforms.setBit(index, 1);
+ sd->sceneTransformCache[index] = m;
+ }
+ }
+ return m;
+}
+
+/*!
+ \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
+{
+ // 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.
+ QPointF mappedPoint = (untransformedAncestor->sceneTransform() * viewportTransform).map(QPointF(0, 0));
+ QTransform matrix;
+ matrix.translate(mappedPoint.x(), mappedPoint.y());
+ matrix = untransformedAncestor->transform() * matrix;
+
+ // Then transform and translate all children.
+ for (int i = 0; i < parents.size(); ++i) {
+ const QGraphicsItem *parent = parents.at(i);
+ QPointF pos = parent->pos();
+ QTransform moveMatrix;
+ moveMatrix.translate(pos.x(), pos.y());
+ matrix = (parent->transform() * moveMatrix) * 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;
+ const QPointF &itemPos = d_ptr->pos;
+ if (d_ptr->hasTransform)
+ return transform() * QTransform::fromTranslate(itemPos.x(), itemPos.y());
+ return QTransform::fromTranslate(itemPos.x(), itemPos.y());
+ }
+
+ // This is other's parent
+ if (otherParent == this) {
+ const QPointF &otherPos = other->d_ptr->pos;
+ if (other->d_ptr->hasTransform) {
+ QTransform otherToParent = other->transform();
+ otherToParent *= QTransform::fromTranslate(otherPos.x(), otherPos.y());
+ return otherToParent.inverted(ok);
+ } else {
+ if (ok)
+ *ok = true;
+ return QTransform::fromTranslate(-otherPos.x(), -otherPos.y());
+ }
+ }
+
+ // Siblings
+ if (parent == otherParent) {
+ bool hasTr = d_ptr->hasTransform;
+ bool otherHasTr = other->d_ptr->hasTransform;
+ const QPointF &itemPos = d_ptr->pos;
+ const QPointF &otherPos = other->d_ptr->pos;
+
+ if (!hasTr && !otherHasTr) {
+ QPointF delta = itemPos - otherPos;
+ if (ok)
+ *ok = true;
+ return QTransform::fromTranslate(delta.x(), delta.y());
+ }
+
+ QTransform itemToParent = QTransform::fromTranslate(itemPos.x(), itemPos.y());
+ if (hasTr)
+ itemToParent = transform() * itemToParent;
+
+ QTransform otherToParent = QTransform::fromTranslate(otherPos.x(), otherPos.y());
+ if (otherHasTr)
+ otherToParent = other->transform() * 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)
+ return sceneTransform() * other->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;
+ QTransform otherToScene;
+ thisToScene = itemTransform(commonAncestor, &good);
+ 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 {
+ const QGraphicsItemPrivate *pd = p->d_ptr;
+ if (pd->hasTransform)
+ x *= p->transform();
+ x *= QTransform::fromTranslate(pd->pos.x(), pd->pos.y());
+ } 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(), rotate(), scale(), shear(), translate(), {The Graphics View Coordinate System}
+*/
+void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData) {
+ if (matrix.isIdentity())
+ return;
+ transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue<void *>(transformData));
+ }
+
+ QTransform oldTransform = transformData->baseTransform;
+
+ QTransform newTransform;
+ if (!combine)
+ newTransform = QTransform(matrix);
+ else
+ newTransform = QTransform(matrix) * oldTransform;
+ if (oldTransform == newTransform)
+ return;
+
+ // Notify the item that the transformation matrix is changing.
+ QVariant variant;
+ qVariantSetValue<QMatrix>(variant, newTransform.toAffine());
+ newTransform = QTransform(qVariantValue<QMatrix>(itemChange(ItemMatrixChange, variant)));
+
+ if (oldTransform == newTransform)
+ return;
+
+ // Update and set the new transformation.
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+ transformData->baseTransform = newTransform;
+ transformData->dirty = true;
+ d_ptr->hasTransform = true;
+ d_ptr->invalidateSceneTransformCache();
+
+ // Send post-notification.
+ itemChange(ItemTransformHasChanged, 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.
+
+ \sa transform(), rotate(), scale(), shear(), translate(), {The Graphics View Coordinate System}
+*/
+void QGraphicsItem::setTransform(const QTransform &matrix, bool combine)
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData) {
+ if (matrix.isIdentity())
+ return;
+ transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue<void *>(transformData));
+ }
+
+ QTransform oldTransform = transformData->baseTransform;
+
+ QTransform newTransform;
+ if (!combine)
+ newTransform = matrix;
+ else
+ newTransform = matrix * oldTransform;
+ if (oldTransform == newTransform)
+ return;
+
+ // Notify the item that the transformation matrix is changing.
+ QVariant variant;
+ qVariantSetValue<QTransform>(variant, newTransform);
+ newTransform = qVariantValue<QTransform>(itemChange(ItemTransformChange, variant));
+ if (oldTransform == newTransform)
+ return;
+
+ // Update and set the new transformation.
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+ transformData->baseTransform = newTransform;
+ transformData->dirty = true;
+ d_ptr->hasTransform = true;
+ transform(); // ### update transform, bad!
+ d_ptr->invalidateSceneTransformCache();
+
+ // Send post-notification.
+ itemChange(ItemTransformHasChanged, newTransform);
+}
+
+/*!
+ \obsolete
+
+ Use resetTransform() instead.
+*/
+void QGraphicsItem::resetMatrix()
+{
+ resetTransform();
+}
+
+/*!
+ \since 4.3
+
+ Resets this item's transformation matrix to the identity matrix. This is
+ equivalent to calling \c setTransform(QTransform()).
+
+ \sa setTransform(), transform()
+*/
+void QGraphicsItem::resetTransform()
+{
+ setTransform(QTransform(), false);
+}
+
+/*!
+ 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);
+}
+
+/*!
+ 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(), rotate(), shear(), translate()
+*/
+void QGraphicsItem::scale(qreal sx, qreal sy)
+{
+ setTransform(QTransform::fromScale(sx, sy), true);
+}
+
+/*!
+ Shears the current item transformation by (\a sh, \a sv).
+
+ \sa setTransform(), transform(), rotate(), scale(), translate()
+*/
+void QGraphicsItem::shear(qreal sh, qreal sv)
+{
+ setTransform(QTransform().shear(sh, sv), true);
+}
+
+/*!
+ 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(), rotate(), scale(), shear()
+*/
+void QGraphicsItem::translate(qreal dx, qreal dy)
+{
+ setTransform(QTransform::fromTranslate(dx, dy), true);
+}
+
+QPointF QGraphicsItem::transformOrigin() const
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData)
+ return QPointF();
+
+ return transformData->transformCenter;
+}
+
+/*!
+ Set a center for all transformation
+*/
+void QGraphicsItem::setTransformOrigin(const QPointF &center)
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData) {
+ if (center.isNull())
+ return;
+ transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue<void *>(transformData));
+ }
+ if (transformData->transformCenter == center)
+ return;
+
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+
+ transformData->transformCenter = center;
+
+ transformData->dirty = true;
+ d_ptr->hasTransform = true;
+ d_ptr->fullUpdateHelper();
+
+}
+
+qreal QGraphicsItem::xScale() const
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData)
+ return 1;
+
+ return transformData->scaleX;
+}
+
+void QGraphicsItem::setXScale(qreal factor)
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData) {
+ if (factor == 1)
+ return;
+ transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue<void *>(transformData));
+ }
+ if (transformData->scaleX == factor)
+ return;
+
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+
+ transformData->scaleX = factor;
+ transformData->dirty = true;
+ d_ptr->hasTransform = true;
+ d_ptr->invalidateSceneTransformCache();
+}
+
+qreal QGraphicsItem::yScale() const
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData)
+ return 1;
+
+ return transformData->scaleY;
+}
+
+void QGraphicsItem::setYScale(qreal factor)
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData) {
+ if (factor == 1)
+ return;
+ transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue<void *>(transformData));
+ }
+ if (transformData->scaleY == factor)
+ return;
+
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+
+ transformData->scaleY = factor;
+ transformData->dirty = true;
+ d_ptr->hasTransform = true;
+ d_ptr->invalidateSceneTransformCache();
+}
+
+qreal QGraphicsItem::xRotation() const
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData)
+ return 0;
+ return transformData->rotationX;
+}
+
+void QGraphicsItem::setXRotation(qreal angle)
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData) {
+ if (qFuzzyCompare(angle + 1, 1))
+ return;
+ transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue<void *>(transformData));
+ }
+
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+
+ transformData->rotationX = angle;
+
+ transformData->dirty = true;
+ d_ptr->hasTransform = true;
+ d_ptr->invalidateSceneTransformCache();
+}
+
+qreal QGraphicsItem::yRotation() const
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData)
+ return 0;
+ return transformData->rotationY;
+}
+
+void QGraphicsItem::setYRotation(qreal angle)
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData) {
+ if (qFuzzyCompare(angle + 1, 1))
+ return;
+ transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue<void *>(transformData));
+ }
+
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+
+ transformData->rotationY = angle;
+
+ transformData->dirty = true;
+ d_ptr->hasTransform = true;
+ d_ptr->invalidateSceneTransformCache();
+}
+
+qreal QGraphicsItem::zRotation() const
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData)
+ return 0;
+ return transformData->rotationZ;
+}
+
+void QGraphicsItem::setZRotation(qreal angle)
+{
+ QGraphicsItemPrivate::TransformData *transformData = static_cast<QGraphicsItemPrivate::TransformData *>(
+ qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)));
+ if (!transformData) {
+ if (qFuzzyCompare(angle + 1, 1))
+ return;
+ transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue<void *>(transformData));
+ }
+
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+
+ transformData->rotationZ = angle;
+
+ transformData->dirty = true;
+ d_ptr->hasTransform = true;
+ d_ptr->invalidateSceneTransformCache();
+}
+
+/*!
+ 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, or the elevation, of the item. The Z-value decides
+ the stacking order of sibling (neighboring) items.
+
+ The default Z-value is 0.
+
+ \sa setZValue()
+*/
+qreal QGraphicsItem::zValue() const
+{
+ return d_ptr->z;
+}
+
+/*!
+ Sets the Z-value, or the elevation, of the item, to \a z. The elevation
+ decides the stacking order of sibling (neighboring) items. An item of high
+ Z-value will be drawn on top of an item with a lower Z-value if they
+ share the same parent item. In addition, children of an item will always be drawn
+ on top of the parent, regardless of the child's Z-value. Sibling items
+ that share the same Z-value will be drawn in an undefined order, although
+ the order will stay the same for as long as the items live.
+
+ \img graphicsview-zorder.png
+
+ Children of different parents are stacked according to the Z-value of
+ each item's ancestor item which is an immediate child of the two
+ items' closest common ancestor. For example, a robot item might
+ define a torso item as the parent of a head item, two arm items,
+ and two upper-leg items. The upper-leg items would each be parents
+ of one lower-leg item, and each lower-leg item would be parents of
+ one foot item. The stacking order of the feet is the same as the
+ stacking order of each foot's ancestor that is an immediate child
+ of the two feet's common ancestor (i.e., the torso item); so the
+ feet are stacked in the same order as the upper-leg items,
+ regardless of each foot's Z-value.
+
+ The Z-value does not affect the item's size in any way.
+
+ The default Z-value is 0.
+
+ \sa zValue()
+*/
+void QGraphicsItem::setZValue(qreal z)
+{
+ qreal newZ = qreal(itemChange(ItemZValueChange, double(z)).toDouble());
+ if (newZ == d_ptr->z)
+ return;
+ d_ptr->z = z;
+ d_ptr->fullUpdateHelper();
+
+ if (d_ptr->scene) {
+ // Invalidate any sort caching; arrival of a new item means we need to
+ // resort.
+ d_ptr->scene->d_func()->invalidateSortCache();
+ }
+
+ itemChange(ItemZValueHasChanged, double(newZ));
+}
+
+/*!
+ 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
+{
+ QRectF childRect;
+ foreach (QGraphicsItem *child, children()) {
+ QPointF childPos = child->pos();
+ QTransform matrix = child->transform() * QTransform::fromTranslate(childPos.x(), childPos.y());
+ childRect |= matrix.mapRect(child->boundingRect() | child->childrenBoundingRect());
+ }
+ return childRect;
+}
+
+/*!
+ \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 (scale(), rotate(), etc.).
+
+ 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
+ QPointF offset;
+ const QGraphicsItem *parentItem = this;
+ const QGraphicsItemPrivate *itemd;
+ do {
+ itemd = parentItem->d_ptr;
+ if (itemd->hasTransform)
+ break;
+ offset += itemd->pos;
+ } while ((parentItem = itemd->parent));
+
+ QRectF br = boundingRect();
+ br.translate(offset);
+ return !parentItem ? br : parentItem->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);
+ QPainterPath clip;
+ if (!isClipped())
+ return clip;
+
+ // Start with the item's bounding rect.
+ clip.addRect(boundingRect());
+
+ bool clipAway = false;
+ if (d->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) {
+ // Make list of parents up to the farthest ancestor that clips its
+ // children to its shape.
+ QVarLengthArray<const QGraphicsItem *, 32> clippingAncestors;
+ const QGraphicsItem *parent = parentItem();
+ const QGraphicsItem *clipOwner = 0;
+ do {
+ if (parent->d_ptr->flags & ItemClipsChildrenToShape) {
+ clippingAncestors.append(parent);
+ clipOwner = parent;
+ }
+ } while ((parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) && (parent = parent->parentItem()));
+
+ // Start with the topmost clip.
+ QPainterPath parentClip = clipOwner->shape();
+
+ // Intersect any in-between clips starting at the bottom and moving
+ // upwards.
+ for (int i = clippingAncestors.size() - 2; i >= 0; --i) {
+ const QGraphicsItem *item = clippingAncestors[i];
+ // ### what if itemtransform fails
+ if (clipOwner)
+ parentClip = clipOwner->itemTransform(item).map(parentClip);
+ parentClip = parentClip.intersected(item->shape());
+ if (parentClip.isEmpty()) {
+ clip = parentClip;
+ clipAway = true;
+ break;
+ }
+ clipOwner = item;
+ }
+
+ if (!clipAway) {
+ // ### what if itemtransform fails
+ clip = clip.intersected(clipOwner->itemTransform(this).map(parentClip));
+ if (clip.isEmpty())
+ clipAway = true;
+ }
+ }
+
+ if (!clipAway && 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 ways items collide is determined by \a mode. 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.
+
+ 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.
+
+ \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 = _q_adjustedRect(boundingRect());
+ QRectF rectB = _q_adjustedRect(path.controlPointRect());
+ 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.addPolygon(_q_adjustedRect(boundingRect()));
+ thisShape.closeSubpath();
+ }
+ 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 \a mode. The default
+ value for \a mode is Qt::IntersectsItemShape; All items whose shape
+ intersects or is contained by this item's shape are returned.
+
+ \sa QGraphicsScene::collidingItems(), 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 QGraphicsScenePrivate::closestItemFirst_withoutCache(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 particularily 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 = _q_adjustedRect(itemToDeviceTransform.mapRect(boundingRect()).toRect());
+ 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;
+ unscale.scale(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
+ ? qVariantValue<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,
+ qVariantFromValue<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}
+*/
+
+/*!
+ \internal
+
+ Asks the scene to mark this item's scene rect as dirty, requesting a
+ redraw. This does not invalidate any cache.
+
+ The \a force argument is for the update call in setVisible(), which is the
+ only case where the item's background should be marked as dirty even when
+ the item isn't visible.
+*/
+void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force)
+{
+ // 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.
+ if (dirty)
+ return;
+ if (!scene || (scene && scene->d_func()->updateAll && scene->d_func()->hasSceneRect))
+ return;
+ if (scene && (visible || force)) {
+ if (rect.isNull())
+ dirty = 1;
+ scene->itemUpdated(q_ptr, rect);
+ }
+}
+
+/*!
+ \internal
+
+ Propagates updates to \a item and all its children.
+*/
+void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly)
+{
+ // 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.
+ if (!scene || (scene && scene->d_func()->updateAll && scene->d_func()->hasSceneRect))
+ return;
+ if (!childrenOnly && !dirty)
+ updateHelper();
+ if (children.isEmpty() || dirtyChildren)
+ return;
+ if (flags & QGraphicsItem::ItemClipsChildrenToShape) {
+ // ### mark all children dirty?
+ // Unnecessary to update children as well.
+ return;
+ }
+ if (ancestorFlags & AncestorClipsChildren) {
+ Q_Q(QGraphicsItem);
+ // Check if we can avoid updating all children.
+ QGraphicsItem *p = parent;
+ QRectF br = q->boundingRect();
+ while (p) {
+ if (p->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) {
+ bool ok;
+ QTransform x = q->itemTransform(p, &ok);
+ if (!ok)
+ break;
+ if (x.mapRect(br).contains(p->boundingRect()))
+ return;
+ }
+ p = p->d_ptr->parent;
+ if (!p || !(p->d_ptr->ancestorFlags & AncestorClipsChildren))
+ break;
+ // ### check one level only
+ break;
+ }
+ }
+ foreach (QGraphicsItem *child, children)
+ child->d_ptr->fullUpdateHelper();
+ dirtyChildren = 1;
+}
+
+/*!
+ \internal
+
+ Resolves and propagates this item's effective opacity to its children.
+*/
+void QGraphicsItemPrivate::resolveEffectiveOpacity(qreal parentEffectiveOpacity)
+{
+ Q_Q(QGraphicsItem);
+ QGraphicsItem::GraphicsItemFlags myFlags = q->flags();
+ QGraphicsItem::GraphicsItemFlags parentFlags = parent ? parent->flags() : QGraphicsItem::GraphicsItemFlags(0);
+
+ // My local opacity is always part of my effective opacity.
+ qreal myEffectiveOpacity = q->opacity();
+
+ // If I have a parent, and I don't ignore my parent's opacity, and my
+ // parent propagates to me, then combine my local opacity with my parent's
+ // effective opacity into my effective opacity.
+ if (parent
+ && !(myFlags & QGraphicsItem::ItemIgnoresParentOpacity)
+ && !(parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) {
+ myEffectiveOpacity *= parentEffectiveOpacity;
+ }
+
+ // Set this item's resolved opacity.
+ setExtra(ExtraEffectiveOpacity, myEffectiveOpacity);
+
+ // Resolve children always.
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->resolveEffectiveOpacity(myEffectiveOpacity);
+}
+
+/*!
+ \internal
+
+ Resolves the stacking depth of this object and all its children.
+*/
+void QGraphicsItemPrivate::resolveDepth(int parentDepth)
+{
+ depth = parentDepth + 1;
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->resolveDepth(depth);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::invalidateSceneTransformCache()
+{
+ if (!scene || (parent && sceneTransformIndex == -1))
+ return;
+ if (sceneTransformIndex != -1)
+ scene->d_func()->validTransforms.setBit(sceneTransformIndex, 0);
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->invalidateSceneTransformCache();
+}
+
+QGraphicsItemCache *QGraphicsItemPrivate::extraItemCache() const
+{
+ QGraphicsItemCache *c = (QGraphicsItemCache *)qVariantValue<void *>(extra(ExtraCacheData));
+ if (!c) {
+ QGraphicsItemPrivate *that = const_cast<QGraphicsItemPrivate *>(this);
+ c = new QGraphicsItemCache;
+ that->setExtra(ExtraCacheData, qVariantFromValue<void *>(c));
+ }
+ return c;
+}
+
+void QGraphicsItemPrivate::removeExtraItemCache()
+{
+ QGraphicsItemCache *c = (QGraphicsItemCache *)qVariantValue<void *>(extra(ExtraCacheData));
+ if (c) {
+ c->purge();
+ delete c;
+ }
+ unsetExtra(ExtraCacheData);
+}
+
+/*!
+ \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 (d_ptr->dirty)
+ return;
+ if (d_ptr->scene && isVisible()) {
+ if (CacheMode(d_ptr->cacheMode) != NoCache) {
+ QGraphicsItemCache *cache = d_ptr->extraItemCache();
+ if (rect.isNull()) {
+ cache->allExposed = true;
+ cache->exposed.clear();
+ } else {
+ cache->exposed.append(rect);
+ }
+ }
+ d_ptr->updateHelper(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).
+
+ \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;
+ if (d->cacheMode != NoCache) {
+ // ### This is very slow, and can be done much better. If the cache is
+ // local and matches the below criteria for rotation and scaling, we
+ // can easily scroll. And if the cache is in device coordinates, we
+ // can scroll both the viewport and the cache.
+ update(rect);
+ return;
+ }
+
+ QRectF scrollRect = !rect.isNull() ? rect : boundingRect();
+ int couldntScroll = d->scene->views().size();
+ foreach (QGraphicsView *view, d->scene->views()) {
+ if (view->viewport()->inherits("QGLWidget")) {
+ // ### Please replace with a widget attribute; any widget that
+ // doesn't support partial updates / doesn't support scrolling
+ // should be skipped in this code. Qt::WA_NoPartialUpdates or so.
+ continue;
+ }
+
+ static const QLineF up(0, 0, 0, -1);
+ static const QLineF down(0, 0, 0, 1);
+ static const QLineF left(0, 0, -1, 0);
+ static const QLineF right(0, 0, 1, 0);
+
+ QTransform deviceTr;
+ if (d->itemIsUntransformable()) {
+ deviceTr = deviceTransform(view->viewportTransform());
+ } else {
+ deviceTr = sceneTransform() * view->viewportTransform();
+ }
+
+ QRect deviceScrollRect = deviceTr.mapRect(scrollRect).toRect();
+ QLineF v1 = deviceTr.map(right);
+ QLineF v2 = deviceTr.map(down);
+ QLineF u1 = v1.unitVector(); u1.translate(-v1.p1());
+ QLineF u2 = v2.unitVector(); u2.translate(-v2.p1());
+ bool noScroll = false;
+
+ // Check if the delta resolves to ints in device space.
+ QPointF deviceDelta = deviceTr.map(QPointF(dx, dy));
+ if ((deviceDelta.x() - int(deviceDelta.x()))
+ || (deviceDelta.y() - int(deviceDelta.y()))) {
+ noScroll = true;
+ } else {
+ // Check if the unit vectors have no fraction in device space.
+ qreal v1l = v1.length();
+ if (v1l - int(v1l)) {
+ noScroll = true;
+ } else {
+ dx *= v1.length();
+ }
+ qreal v2l = v2.length();
+ if (v2l - int(v2l)) {
+ noScroll = true;
+ } else {
+ dy *= v2.length();
+ }
+ }
+
+ if (!noScroll) {
+ if (u1 == right) {
+ if (u2 == up) {
+ // flipped
+ dy = -dy;
+ } else if (u2 == down) {
+ // normal
+ } else {
+ noScroll = true;
+ }
+ } else if (u1 == left) {
+ if (u2 == up) {
+ // mirrored & flipped / rotated 180 degrees
+ dx = -dx;
+ dy = -dy;
+ } else if (u2 == down) {
+ // mirrored
+ dx = -dx;
+ } else {
+ noScroll = true;
+ }
+ } else if (u1 == up) {
+ if (u2 == left) {
+ // rotated -90 & mirrored
+ qreal tmp = dy;
+ dy = -dx;
+ dx = -tmp;
+ } else if (u2 == right) {
+ // rotated -90
+ qreal tmp = dy;
+ dy = -dx;
+ dx = tmp;
+ } else {
+ noScroll = true;
+ }
+ } else if (u1 == down) {
+ if (u2 == left) {
+ // rotated 90
+ qreal tmp = dy;
+ dy = dx;
+ dx = -tmp;
+ } else if (u2 == right) {
+ // rotated 90 & mirrored
+ qreal tmp = dy;
+ dy = dx;
+ dx = tmp;
+ } else {
+ noScroll = true;
+ }
+ }
+ }
+
+ if (!noScroll) {
+ view->viewport()->scroll(int(dx), int(dy), deviceScrollRect);
+ --couldntScroll;
+ }
+ }
+ if (couldntScroll)
+ update(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
+{
+ return d_ptr->pos + (d_ptr->hasTransform ? transform().map(point) : 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
+{
+ return 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
+{
+ if (!d_ptr->hasTransform)
+ return QPolygonF(rect.translated(d_ptr->pos));
+ return transform().map(rect.translated(d_ptr->pos));
+}
+
+/*!
+ \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
+{
+ return 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
+{
+ QRectF r = rect.translated(d_ptr->pos.x(), d_ptr->pos.y());
+ return !d_ptr->hasTransform ? r : transform().mapRect(r);
+}
+
+/*!
+ \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
+{
+ return 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
+{
+ QRectF r = rect.translated(-d_ptr->pos);
+ return d_ptr->hasTransform ? transform().inverted().mapRect(r) : r;
+}
+
+/*!
+ \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
+{
+ return 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
+{
+ QPolygonF p = polygon;
+ p.translate(d_ptr->pos);
+ return d_ptr->hasTransform ? transform().map(p) : p;
+}
+
+/*!
+ 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
+{
+ return 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
+{
+ return d_ptr->parent ? itemTransform(d_ptr->parent).map(path) : mapToScene(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
+{
+ return 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
+{
+ if (d_ptr->hasTransform)
+ return transform().inverted().map(point - d_ptr->pos);
+ 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
+{
+ return 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
+{
+ QRectF r = rect.translated(-d_ptr->pos);
+ return d_ptr->hasTransform ? transform().inverted().map(r) : r;
+}
+
+/*!
+ \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
+{
+ return 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
+{
+ QPolygonF p = polygon;
+ p.translate(-d_ptr->pos);
+ return d_ptr->hasTransform ? transform().inverted().map(p) : p;
+}
+
+/*!
+ 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
+{
+ return 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
+{
+ if (d_ptr->parent)
+ return d_ptr->parent->itemTransform(this).map(path);
+ return mapFromScene(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
+{
+ return 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;
+ 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 (!d_ptr->visible) {
+ // Eaten
+ return true;
+ }
+
+ switch (event->type()) {
+ case QEvent::FocusIn:
+ focusInEvent(static_cast<QFocusEvent *>(event));
+ break;
+ case QEvent::FocusOut:
+ focusOutEvent(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;
+ 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()
+*/
+void QGraphicsItem::focusInEvent(QFocusEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ 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()
+*/
+void QGraphicsItem::focusOutEvent(QFocusEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ 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);
+ d_ptr->updateHelper();
+}
+
+/*!
+ 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);
+ d_ptr->updateHelper();
+}
+
+/*!
+ 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) {
+ 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.
+ QTransform viewToParentTransform = (item->transform().translate(item->d_ptr->pos.x(), item->d_ptr->pos.y()))
+ * (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()
+*/
+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();
+}
+
+/*!
+ 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()->addToIndex(this);
+ d_ptr->updateHelper();
+}
+
+/*!
+ \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;
+ }
+ d_ptr->updateHelper();
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->removeFromIndex(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->scene) {
+ d_ptr->updateHelper();
+
+ QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func();
+ scenePrivate->removeFromIndex(this);
+ }
+}
+
+/*!
+ \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 (qFuzzyCompare(qMax(murect.width(), murect.height()) + 1, 1))
+ 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 QAbstractGraphicsShapeItem
+ \brief The QAbstractGraphicsShapeItem class provides a common base for
+ all path items.
+ \since 4.2
+ \ingroup multimedia
+
+ 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, {The 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);
+ 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);
+ 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 multimedia
+ \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, {The 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 multimedia
+ \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, {The 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 multimedia
+ \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, {The 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 multimedia
+ \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, {The 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 multimedia
+ \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, {The
+ 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);
+ 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 multimedia
+ \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, {The
+ 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.
+*/
+
+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()
+ {
+ extern QPainterPath qt_regionToPath(const QRegion &region);
+ 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_ptr->updateHelper();
+ 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);
+ qreal pw = 1.0;
+ if (d->pixmap.isNull())
+ return QRectF();
+ return QRectF(d->offset, d->pixmap.size()).adjusted(-pw/2, -pw/2, pw/2, pw/2);
+}
+
+/*!
+ \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));
+
+ QRectF exposed = option->exposedRect.adjusted(-1, -1, 1, 1);
+ exposed &= QRectF(d->offset.x(), d->offset.y(), d->pixmap.width(), d->pixmap.height());
+ painter->drawPixmap(exposed, d->pixmap, exposed.translated(-d->offset));
+
+ 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 multimedia
+ \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, {The Graphics View Framework}
+*/
+
+class QGraphicsTextItemPrivate
+{
+public:
+ QGraphicsTextItemPrivate()
+ : control(0), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false)
+ { }
+
+ 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;
+
+ 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
+ )
+ : QGraphicsItem(parent, scene), dd(new QGraphicsTextItemPrivate)
+{
+ dd->qq = this;
+ if (!text.isEmpty())
+ setPlainText(text);
+ setAcceptDrops(true);
+ setAcceptHoverEvents(true);
+}
+
+/*!
+ 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
+ )
+ : QGraphicsItem(parent, scene), dd(new QGraphicsTextItemPrivate)
+{
+ dd->qq = this;
+ setAcceptDrops(true);
+ setAcceptHoverEvents(true);
+}
+
+/*!
+ 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();
+ pal.setColor(QPalette::Text, col);
+ c->setPalette(pal);
+}
+
+/*!
+ 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;
+ }
+ }
+ return QGraphicsItem::sceneEvent(event);
+}
+
+/*!
+ \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;
+ }
+ 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);
+ 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. Setting a
+ value different to Qt::NoTextInteraction will also set the ItemIsFocusable
+ QGraphicsItem flag.
+
+ 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);
+ else
+ setFlags(this->flags() | QGraphicsItem::ItemIsFocusable);
+ 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.
+
+ \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 multimedia
+ \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, {The
+ 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();
+}
+
+/*!
+ 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 treating a group of items as
+ one.
+ \since 4.2
+ \ingroup multimedia
+ \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. In addition,
+ item groups have handlesChildEvents() enabled by default, so all
+ events sent to a member of the group go to the item group (i.e.,
+ selecting one item in a group will select them all).
+ 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, {The 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;
+ }
+
+ QTransform oldSceneMatrix = item->sceneTransform();
+ item->setPos(mapFromItem(item, 0, 0));
+ item->setParentItem(this);
+ item->setTransform(oldSceneMatrix
+ * sceneTransform().inverted()
+ * QTransform::fromTranslate(-item->x(), -item->y()));
+ item->d_func()->setIsMemberOfGroup(true);
+ prepareGeometryChange();
+ d->itemsBoundingRect |= (item->transform() * QTransform::fromTranslate(item->x(), item->y()))
+ .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;
+ QPointF oldPos = item->mapToItem(newParent, 0, 0);
+ item->setParentItem(newParent);
+ // ### This function should remap the item's matrix to keep the item's
+ // transformation unchanged relative to the scene.
+ item->setPos(oldPos);
+ 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_DEBUG_STREAM
+QDebug operator<<(QDebug debug, QGraphicsItem *item)
+{
+ if (!item) {
+ debug << "QGraphicsItem(0)";
+ return debug;
+ }
+
+ QStringList flags;
+ if (item->isVisible()) flags << QLatin1String("isVisible");
+ if (item->isEnabled()) flags << QLatin1String("isEnabled");
+ if (item->isSelected()) flags << QLatin1String("isSelected");
+ if (item->hasFocus()) flags << QLatin1String("HasFocus");
+
+ debug << "QGraphicsItem(this =" << ((void*)item)
+ << ", parent =" << ((void*)item->parentItem())
+ << ", pos =" << item->pos()
+ << ", z =" << item->zValue() << ", flags = {"
+ << flags.join(QLatin1String("|")) << " })";
+ return debug;
+}
+
+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;
+ }
+ 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;
+ }
+ debug << str;
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlags flags)
+{
+ debug << "(";
+ bool f = false;
+ for (int i = 0; i < 9; ++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/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
new file mode 100644
index 0000000..1fce3db
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -0,0 +1,1032 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 <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 QGraphicsItemGroup;
+class QGraphicsSceneContextMenuEvent;
+class QGraphicsSceneDragDropEvent;
+class QGraphicsSceneEvent;
+class QGraphicsSceneHoverEvent;
+class QGraphicsSceneMouseEvent;
+class QGraphicsSceneWheelEvent;
+class QGraphicsScene;
+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
+ };
+ 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
+ };
+
+ enum CacheMode {
+ NoCache,
+ ItemCoordinateCache,
+ DeviceCoordinateCache
+ };
+
+ QGraphicsItem(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ virtual ~QGraphicsItem();
+
+ QGraphicsScene *scene() const;
+
+ QGraphicsItem *parentItem() const;
+ QGraphicsItem *topLevelItem() const;
+ QGraphicsWidget *parentWidget() const;
+ QGraphicsWidget *topLevelWidget() const;
+ QGraphicsWidget *window() const;
+ void setParentItem(QGraphicsItem *parent);
+ QList<QGraphicsItem *> children() const; // ### obsolete
+ QList<QGraphicsItem *> childItems() const;
+ bool isWidget() const;
+ bool isWindow() 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());
+
+#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);
+
+ 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 handlesChildEvents() const;
+ void setHandlesChildEvents(bool enabled);
+
+ bool hasFocus() const;
+ void setFocus(Qt::FocusReason focusReason = Qt::OtherFocusReason);
+ void clearFocus();
+
+ void grabMouse();
+ void ungrabMouse();
+ void grabKeyboard();
+ void ungrabKeyboard();
+
+ // Positioning in scene coordinates
+ QPointF pos() const;
+ inline qreal x() const { return pos().x(); }
+ inline qreal y() const { return pos().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();
+
+ // ### obsolete?
+ void rotate(qreal angle);
+ void scale(qreal sx, qreal sy);
+ void shear(qreal sh, qreal sv);
+ void translate(qreal dx, qreal dy);
+
+ // ### experimental
+ QPointF transformOrigin() const;
+ void setTransformOrigin(const QPointF &center);
+ qreal xScale() const;
+ void setXScale(qreal factor);
+ qreal yScale() const;
+ void setYScale(qreal factor);
+ qreal xRotation() const;
+ void setXRotation(qreal angle);
+ qreal yRotation() const;
+ void setYRotation(qreal angle);
+ qreal zRotation() const;
+ void setZRotation(qreal angle);
+
+ virtual void advance(int phase);
+
+ // Stacking order
+ qreal zValue() const;
+ void setZValue(qreal z);
+
+ // 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);
+
+ enum {
+ Type = 1,
+ UserType = 65536
+ };
+ virtual int type() const;
+
+ void installSceneEventFilter(QGraphicsItem *filterItem);
+ void removeSceneEventFilter(QGraphicsItem *filterItem);
+
+protected:
+ 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);
+ 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 QGraphicsView;
+ friend class QGraphicsViewPrivate;
+ friend class QGraphicsWidget;
+ friend class QGraphicsWidgetPrivate;
+ friend class QGraphicsProxyWidgetPrivate;
+ 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)
+
+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 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);
+ inline void setRect(qreal x, qreal y, qreal w, qreal h);
+
+ int startAngle() const;
+ void setStartAngle(int angle);
+
+ int spanAngle() const;
+ void setSpanAngle(int angle);
+
+ 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 = 4 };
+ 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(QGraphicsEllipseItem)
+ Q_DECLARE_PRIVATE(QGraphicsEllipseItem)
+};
+
+inline void QGraphicsEllipseItem::setRect(qreal ax, qreal ay, qreal w, qreal h)
+{ setRect(QRectF(ax, ay, w, h)); }
+
+class QGraphicsPolygonItemPrivate;
+class Q_GUI_EXPORT QGraphicsPolygonItem : public QAbstractGraphicsShapeItem
+{
+public:
+ QGraphicsPolygonItem(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ QGraphicsPolygonItem(const QPolygonF &polygon,
+ QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ ~QGraphicsPolygonItem();
+
+ QPolygonF polygon() const;
+ void setPolygon(const QPolygonF &polygon);
+
+ Qt::FillRule fillRule() const;
+ void setFillRule(Qt::FillRule rule);
+
+ 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 = 5 };
+ 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(QGraphicsPolygonItem)
+ Q_DECLARE_PRIVATE(QGraphicsPolygonItem)
+};
+
+class QGraphicsLineItemPrivate;
+class Q_GUI_EXPORT QGraphicsLineItem : public QGraphicsItem
+{
+public:
+ QGraphicsLineItem(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ QGraphicsLineItem(const QLineF &line, QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ QGraphicsLineItem(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ ~QGraphicsLineItem();
+
+ QPen pen() const;
+ void setPen(const QPen &pen);
+
+ QLineF line() const;
+ void setLine(const QLineF &line);
+ inline void setLine(qreal x1, qreal y1, qreal x2, qreal y2)
+ { setLine(QLineF(x1, y1, x2, y2)); }
+
+ 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 = 6 };
+ 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(QGraphicsLineItem)
+ Q_DECLARE_PRIVATE(QGraphicsLineItem)
+};
+
+class QGraphicsPixmapItemPrivate;
+class Q_GUI_EXPORT QGraphicsPixmapItem : public QGraphicsItem
+{
+public:
+ enum ShapeMode {
+ MaskShape,
+ BoundingRectShape,
+ HeuristicMaskShape
+ };
+
+ QGraphicsPixmapItem(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ QGraphicsPixmapItem(const QPixmap &pixmap, QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ ~QGraphicsPixmapItem();
+
+ QPixmap pixmap() const;
+ void setPixmap(const QPixmap &pixmap);
+
+ Qt::TransformationMode transformationMode() const;
+ void setTransformationMode(Qt::TransformationMode mode);
+
+ QPointF offset() const;
+ void setOffset(const QPointF &offset);
+ inline void setOffset(qreal x, qreal y);
+
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+ bool contains(const QPointF &point) const;
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+
+ bool isObscuredBy(const QGraphicsItem *item) const;
+ QPainterPath opaqueArea() const;
+
+ enum { Type = 7 };
+ int type() const;
+
+ ShapeMode shapeMode() const;
+ void setShapeMode(ShapeMode mode);
+
+protected:
+ bool supportsExtension(Extension extension) const;
+ void setExtension(Extension extension, const QVariant &variant);
+ QVariant extension(const QVariant &variant) const;
+
+private:
+ Q_DISABLE_COPY(QGraphicsPixmapItem)
+ Q_DECLARE_PRIVATE(QGraphicsPixmapItem)
+};
+
+inline void QGraphicsPixmapItem::setOffset(qreal ax, qreal ay)
+{ setOffset(QPointF(ax, ay)); }
+
+class QGraphicsTextItemPrivate;
+class QTextDocument;
+class QTextCursor;
+class Q_GUI_EXPORT QGraphicsTextItem : public QObject, public QGraphicsItem
+{
+ Q_OBJECT
+ QDOC_PROPERTY(bool openExternalLinks READ openExternalLinks WRITE setOpenExternalLinks)
+ QDOC_PROPERTY(QTextCursor textCursor READ textCursor WRITE setTextCursor)
+
+public:
+ QGraphicsTextItem(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ QGraphicsTextItem(const QString &text, QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ ~QGraphicsTextItem();
+
+ QString toHtml() const;
+ void setHtml(const QString &html);
+
+ QString toPlainText() const;
+ void setPlainText(const QString &text);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ void setDefaultTextColor(const QColor &c);
+ QColor defaultTextColor() const;
+
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+ bool contains(const QPointF &point) const;
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+
+ bool isObscuredBy(const QGraphicsItem *item) const;
+ QPainterPath opaqueArea() const;
+
+ enum { Type = 8 };
+ int type() const;
+
+ void setTextWidth(qreal width);
+ qreal textWidth() const;
+
+ void adjustSize();
+
+ void setDocument(QTextDocument *document);
+ QTextDocument *document() const;
+
+ void setTextInteractionFlags(Qt::TextInteractionFlags flags);
+ Qt::TextInteractionFlags textInteractionFlags() const;
+
+ void setTabChangesFocus(bool b);
+ bool tabChangesFocus() const;
+
+ void setOpenExternalLinks(bool open);
+ bool openExternalLinks() const;
+
+ void setTextCursor(const QTextCursor &cursor);
+ QTextCursor textCursor() const;
+
+Q_SIGNALS:
+ void linkActivated(const QString &);
+ void linkHovered(const QString &);
+
+protected:
+ bool sceneEvent(QEvent *event);
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *event);
+ void focusInEvent(QFocusEvent *event);
+ void focusOutEvent(QFocusEvent *event);
+ void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
+ void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
+ void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
+ void dropEvent(QGraphicsSceneDragDropEvent *event);
+ void inputMethodEvent(QInputMethodEvent *event);
+ void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+
+ QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+
+ bool supportsExtension(Extension extension) const;
+ void setExtension(Extension extension, const QVariant &variant);
+ QVariant extension(const QVariant &variant) const;
+
+private:
+ Q_DISABLE_COPY(QGraphicsTextItem)
+ Q_PRIVATE_SLOT(dd, void _q_updateBoundingRect(const QSizeF &))
+ Q_PRIVATE_SLOT(dd, void _q_update(QRectF))
+ Q_PRIVATE_SLOT(dd, void _q_ensureVisible(QRectF))
+ QGraphicsTextItemPrivate *dd;
+ friend class QGraphicsTextItemPrivate;
+};
+
+class QGraphicsSimpleTextItemPrivate;
+class Q_GUI_EXPORT QGraphicsSimpleTextItem : public QAbstractGraphicsShapeItem
+{
+public:
+ QGraphicsSimpleTextItem(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ QGraphicsSimpleTextItem(const QString &text, QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ ~QGraphicsSimpleTextItem();
+
+ void setText(const QString &text);
+ QString text() const;
+
+ void setFont(const QFont &font);
+ QFont font() const;
+
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+ bool contains(const QPointF &point) const;
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+
+ bool isObscuredBy(const QGraphicsItem *item) const;
+ QPainterPath opaqueArea() const;
+
+ enum { Type = 9 };
+ 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(QGraphicsSimpleTextItem)
+ Q_DECLARE_PRIVATE(QGraphicsSimpleTextItem)
+};
+
+class QGraphicsItemGroupPrivate;
+class Q_GUI_EXPORT QGraphicsItemGroup : public QGraphicsItem
+{
+public:
+ QGraphicsItemGroup(QGraphicsItem *parent = 0
+#ifndef Q_QDOC
+ // obsolete argument
+ , QGraphicsScene *scene = 0
+#endif
+ );
+ ~QGraphicsItemGroup();
+
+ void addToGroup(QGraphicsItem *item);
+ void removeFromGroup(QGraphicsItem *item);
+
+ QRectF boundingRect() const;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+ bool isObscuredBy(const QGraphicsItem *item) const;
+ QPainterPath opaqueArea() const;
+
+ enum { Type = 10 };
+ int type() const;
+
+private:
+ Q_DISABLE_COPY(QGraphicsItemGroup)
+ Q_DECLARE_PRIVATE(QGraphicsItemGroup)
+};
+
+template <class T> inline T qgraphicsitem_cast(QGraphicsItem *item)
+{
+ return int(static_cast<T>(0)->Type) == int(QGraphicsItem::Type)
+ || (item && int(static_cast<T>(0)->Type) == item->type()) ? static_cast<T>(item) : 0;
+}
+
+template <class T> inline T qgraphicsitem_cast(const QGraphicsItem *item)
+{
+ return int(static_cast<T>(0)->Type) == int(QGraphicsItem::Type)
+ || (item && int(static_cast<T>(0)->Type) == item->type()) ? static_cast<T>(item) : 0;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem *item);
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemChange change);
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag);
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlags flags);
+#endif
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QGraphicsItem *)
+Q_DECLARE_METATYPE(QGraphicsScene *)
+
+QT_BEGIN_NAMESPACE
+
+#endif // QT_NO_GRAPHICSVIEW
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGRAPHICSITEM_H
+
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
new file mode 100644
index 0000000..c14b978
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -0,0 +1,291 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSITEM_P_H
+#define QGRAPHICSITEM_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qgraphicsitem.h"
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsItemPrivate;
+
+class QGraphicsItemCache
+{
+public:
+ QGraphicsItemCache() : allExposed(false) { }
+
+ // ItemCoordinateCache only
+ QRect boundingRect;
+ QSize fixedSize;
+ QString key;
+
+ // DeviceCoordinateCache only
+ struct DeviceData {
+ QTransform lastTransform;
+ QPoint cacheIndent;
+ QString key;
+ };
+ QMap<QPaintDevice *, DeviceData> deviceData;
+
+ // List of logical exposed rects
+ QVector<QRectF> exposed;
+ bool allExposed;
+
+ // Empty cache
+ void purge();
+};
+
+class Q_AUTOTEST_EXPORT QGraphicsItemPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsItem)
+public:
+ struct TransformData
+ {
+ TransformData() : rotationX(0),rotationY(0),rotationZ(0),scaleX(1),scaleY(1), dirty(true) {}
+ QTransform baseTransform;
+ QTransform transform;
+ QPointF transformCenter;
+ qreal rotationX,rotationY,rotationZ,scaleX,scaleY;
+ bool dirty;
+ };
+ enum Extra {
+ ExtraTransform,
+ ExtraToolTip,
+ ExtraCursor,
+ ExtraCacheData,
+ ExtraMaxDeviceCoordCacheSize,
+ ExtraBoundingRegionGranularity,
+ ExtraOpacity,
+ ExtraEffectiveOpacity
+ };
+
+ enum AncestorFlag {
+ NoFlag = 0,
+ AncestorHandlesChildEvents = 0x1,
+ AncestorClipsChildren = 0x2,
+ AncestorIgnoresTransformations = 0x4
+ };
+
+ inline QGraphicsItemPrivate()
+ : z(0),
+ scene(0),
+ parent(0),
+ index(-1),
+ depth(0),
+ acceptedMouseButtons(0x1f),
+ visible(1),
+ explicitlyHidden(0),
+ enabled(1),
+ explicitlyDisabled(0),
+ selected(0),
+ acceptsHover(0),
+ acceptDrops(0),
+ isMemberOfGroup(0),
+ handlesChildEvents(0),
+ itemDiscovered(0),
+ hasTransform(0),
+ hasCursor(0),
+ ancestorFlags(0),
+ cacheMode(0),
+ hasBoundingRegionGranularity(0),
+ flags(0),
+ hasOpacity(0),
+ isWidget(0),
+ dirty(0),
+ dirtyChildren(0),
+ localCollisionHack(0),
+ globalStackingOrder(-1),
+ sceneTransformIndex(-1),
+ q_ptr(0)
+ {
+ }
+
+ inline virtual ~QGraphicsItemPrivate()
+ { }
+
+ void updateAncestorFlag(QGraphicsItem::GraphicsItemFlag childFlag,
+ AncestorFlag flag = NoFlag, bool enabled = false, bool root = true);
+ void setIsMemberOfGroup(bool enabled);
+ void remapItemPos(QEvent *event, QGraphicsItem *item);
+ QPointF genericMapFromScene(const QPointF &pos, const QWidget *viewport) const;
+ bool itemIsUntransformable() const;
+
+ // ### Qt 5: Remove. Workaround for reimplementation added after Qt 4.4.
+ virtual QVariant inputMethodQueryHelper(Qt::InputMethodQuery query) const;
+ static bool movableAncestorIsSelected(const QGraphicsItem *item);
+
+ void setPosHelper(const QPointF &pos, bool update);
+ void setVisibleHelper(bool newVisible, bool explicitly, bool update = true);
+ void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true);
+ void updateHelper(const QRectF &rect = QRectF(), bool force = false);
+ void fullUpdateHelper(bool childrenOnly = false);
+ void resolveEffectiveOpacity(qreal effectiveParentOpacity);
+ void resolveDepth(int parentDepth);
+ void invalidateSceneTransformCache();
+
+ virtual void resolveFont(uint inheritedMask)
+ {
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->resolveFont(inheritedMask);
+ }
+
+ virtual void resolvePalette(uint inheritedMask)
+ {
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->resolveFont(inheritedMask);
+ }
+
+ virtual bool isProxyWidget() const;
+
+ inline QVariant extra(Extra type) const
+ {
+ for (int i = 0; i < extras.size(); ++i) {
+ const ExtraStruct &extra = extras.at(i);
+ if (extra.type == type)
+ return extra.value;
+ }
+ return QVariant();
+ }
+
+ inline void setExtra(Extra type, const QVariant &value)
+ {
+ int index = -1;
+ for (int i = 0; i < extras.size(); ++i) {
+ if (extras.at(i).type == type) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index == -1) {
+ extras << ExtraStruct(type, value);
+ } else {
+ extras[index].value = value;
+ }
+ }
+
+ inline void unsetExtra(Extra type)
+ {
+ for (int i = 0; i < extras.size(); ++i) {
+ if (extras.at(i).type == type) {
+ extras.removeAt(i);
+ return;
+ }
+ }
+ }
+
+ struct ExtraStruct {
+ ExtraStruct(Extra type, QVariant value)
+ : type(type), value(value)
+ { }
+
+ Extra type;
+ QVariant value;
+
+ bool operator<(Extra extra) const
+ { return type < extra; }
+ };
+
+ QList<ExtraStruct> extras;
+
+ QGraphicsItemCache *extraItemCache() const;
+ void removeExtraItemCache();
+
+ QPointF pos;
+ qreal z;
+ QGraphicsScene *scene;
+ QGraphicsItem *parent;
+ QList<QGraphicsItem *> children;
+ int index;
+ int depth;
+
+ // Packed 32 bytes
+ quint32 acceptedMouseButtons : 5;
+ quint32 visible : 1;
+ quint32 explicitlyHidden : 1;
+ quint32 enabled : 1;
+ quint32 explicitlyDisabled : 1;
+ quint32 selected : 1;
+ quint32 acceptsHover : 1;
+ quint32 acceptDrops : 1;
+ quint32 isMemberOfGroup : 1;
+ quint32 handlesChildEvents : 1;
+ quint32 itemDiscovered : 1;
+ quint32 hasTransform : 1;
+ quint32 hasCursor : 1;
+ quint32 ancestorFlags : 3;
+ quint32 cacheMode : 2;
+ quint32 hasBoundingRegionGranularity : 1;
+ quint32 flags : 9;
+
+ // New 32 bytes
+ quint32 hasOpacity : 1;
+ quint32 isWidget : 1;
+ quint32 dirty : 1;
+ quint32 dirtyChildren : 1;
+ quint32 localCollisionHack : 1;
+
+ // Optional stacking order
+ int globalStackingOrder;
+ int sceneTransformIndex;
+
+ QGraphicsItem *q_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_GRAPHICSVIEW
+
+#endif
diff --git a/src/gui/graphicsview/qgraphicsitemanimation.cpp b/src/gui/graphicsview/qgraphicsitemanimation.cpp
new file mode 100644
index 0000000..1b58b9c
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsitemanimation.cpp
@@ -0,0 +1,599 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QGraphicsItemAnimation
+ \brief The QGraphicsItemAnimation class provides simple animation
+ support for QGraphicsItem.
+ \since 4.2
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ The QGraphicsItemAnimation class animates a QGraphicsItem. You can
+ schedule changes to the item's transformation matrix at
+ specified steps. The QGraphicsItemAnimation class has a
+ current step value. When this value changes the transformations
+ scheduled at that step are performed. The current step of the
+ animation is set with the \c setStep() function.
+
+ QGraphicsItemAnimation will do a simple linear interpolation
+ between the nearest adjacent scheduled changes to calculate the
+ matrix. For instance, if you set the position of an item at values
+ 0.0 and 1.0, the animation will show the item moving in a straight
+ line between these positions. The same is true for scaling and
+ rotation.
+
+ It is usual to use the class with a QTimeLine. The timeline's
+ \l{QTimeLine::}{valueChanged()} signal is then connected to the
+ \c setStep() slot. For example, you can set up an item for rotation
+ by calling \c setRotationAt() for different step values.
+ The animations timeline is set with the setTimeLine() function.
+
+ An example animation with a timeline follows:
+
+ \snippet doc/src/snippets/timeline/main.cpp 0
+
+ Note that steps lie between 0.0 and 1.0. It may be necessary to use
+ \l{QTimeLine::}{setUpdateInterval()}. The default update interval
+ is 40 ms. A scheduled transformation cannot be removed when set,
+ so scheduling several transformations of the same kind (e.g.,
+ rotations) at the same step is not recommended.
+
+ \sa QTimeLine, {The Graphics View Framework}
+*/
+
+#include "qgraphicsitemanimation.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include "qgraphicsitem.h"
+
+#include <QtCore/qtimeline.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qpair.h>
+#include <QtGui/qmatrix.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsItemAnimationPrivate
+{
+public:
+ inline QGraphicsItemAnimationPrivate()
+ : q(0), timeLine(0), item(0), step(0)
+ { }
+
+ QGraphicsItemAnimation *q;
+
+ QPointer<QTimeLine> timeLine;
+ QGraphicsItem *item;
+
+ QPointF startPos;
+ QMatrix startMatrix;
+
+ qreal step;
+
+ struct Pair {
+ Pair(qreal a, qreal b) : step(a), value(b) {}
+ bool operator <(const Pair &other) const
+ { return step < other.step; }
+ bool operator==(const Pair &other) const
+ { return step == other.step; }
+ qreal step;
+ qreal value;
+ };
+ QList<Pair> xPosition;
+ QList<Pair> yPosition;
+ QList<Pair> rotation;
+ QList<Pair> verticalScale;
+ QList<Pair> horizontalScale;
+ QList<Pair> verticalShear;
+ QList<Pair> horizontalShear;
+ QList<Pair> xTranslation;
+ QList<Pair> yTranslation;
+
+ qreal linearValueForStep(qreal step, QList<Pair> *source, qreal defaultValue = 0);
+ void insertUniquePair(qreal step, qreal value, QList<Pair> *binList, const char* method);
+};
+
+qreal QGraphicsItemAnimationPrivate::linearValueForStep(qreal step, QList<Pair> *source, qreal defaultValue)
+{
+ if (source->isEmpty())
+ return defaultValue;
+ step = qMin<qreal>(qMax<qreal>(step, 0), 1);
+
+ if (step == 1)
+ return source->last().value;
+
+ qreal stepBefore = 0;
+ qreal stepAfter = 1;
+ qreal valueBefore = source->first().step == 0 ? source->first().value : defaultValue;
+ qreal valueAfter = source->last().value;
+
+ // Find the closest step and value before the given step.
+ for (int i = 0; i < source->size() && step >= source->at(i).step; ++i) {
+ stepBefore = source->at(i).step;
+ valueBefore = source->at(i).value;
+ }
+
+ // Find the closest step and value after the given step.
+ for (int j = source->size() - 1; j >= 0 && step < source->at(j).step; --j) {
+ stepAfter = source->at(j).step;
+ valueAfter = source->at(j).value;
+ }
+
+ // Do a simple linear interpolation.
+ return valueBefore + (valueAfter - valueBefore) * ((step - stepBefore) / (stepAfter - stepBefore));
+}
+
+void QGraphicsItemAnimationPrivate::insertUniquePair(qreal step, qreal value, QList<Pair> *binList, const char* method)
+{
+ if (step < 0.0 || step > 1.0) {
+ qWarning("QGraphicsItemAnimation::%s: invalid step = %f", method, step);
+ return;
+ }
+
+ Pair pair(step, value);
+
+ QList<Pair>::iterator result = qBinaryFind(binList->begin(), binList->end(), pair);
+ if (result != binList->end())
+ result->value = value;
+ else {
+ *binList << pair;
+ qSort(binList->begin(), binList->end());
+ }
+}
+
+/*!
+ Constructs an animation object with the given \a parent.
+*/
+QGraphicsItemAnimation::QGraphicsItemAnimation(QObject *parent)
+ : QObject(parent), d(new QGraphicsItemAnimationPrivate)
+{
+ d->q = this;
+}
+
+/*!
+ Destroys the animation object.
+*/
+QGraphicsItemAnimation::~QGraphicsItemAnimation()
+{
+ delete d;
+}
+
+/*!
+ Returns the item on which the animation object operates.
+
+ \sa setItem()
+*/
+QGraphicsItem *QGraphicsItemAnimation::item() const
+{
+ return d->item;
+}
+
+/*!
+ Sets the specified \a item to be used in the animation.
+
+ \sa item()
+*/
+void QGraphicsItemAnimation::setItem(QGraphicsItem *item)
+{
+ d->item = item;
+ d->startPos = d->item->pos();
+}
+
+/*!
+ Returns the timeline object used to control the rate at which the animation
+ occurs.
+
+ \sa setTimeLine()
+*/
+QTimeLine *QGraphicsItemAnimation::timeLine() const
+{
+ return d->timeLine;
+}
+
+/*!
+ Sets the timeline object used to control the rate of animation to the \a timeLine
+ specified.
+
+ \sa timeLine()
+*/
+void QGraphicsItemAnimation::setTimeLine(QTimeLine *timeLine)
+{
+ if (d->timeLine == timeLine)
+ return;
+ if (d->timeLine)
+ delete d->timeLine;
+ if (!timeLine)
+ return;
+ d->timeLine = timeLine;
+ connect(timeLine, SIGNAL(valueChanged(qreal)), this, SLOT(setStep(qreal)));
+}
+
+/*!
+ Returns the position of the item at the given \a step value.
+
+ \sa setPosAt()
+*/
+QPointF QGraphicsItemAnimation::posAt(qreal step) const
+{
+ if (step < 0.0 || step > 1.0)
+ qWarning("QGraphicsItemAnimation::posAt: invalid step = %f", step);
+
+ return QPointF(d->linearValueForStep(step, &d->xPosition, d->startPos.x()),
+ d->linearValueForStep(step, &d->yPosition, d->startPos.y()));
+}
+
+/*!
+ \fn void QGraphicsItemAnimation::setPosAt(qreal step, const QPointF &point)
+
+ Sets the position of the item at the given \a step value to the \a point specified.
+
+ \sa posAt()
+*/
+void QGraphicsItemAnimation::setPosAt(qreal step, const QPointF &pos)
+{
+ d->insertUniquePair(step, pos.x(), &d->xPosition, "setPosAt");
+ d->insertUniquePair(step, pos.y(), &d->yPosition, "setPosAt");
+}
+
+/*!
+ Returns all explicitly inserted positions.
+
+ \sa posAt(), setPosAt()
+*/
+QList<QPair<qreal, QPointF> > QGraphicsItemAnimation::posList() const
+{
+ QList<QPair<qreal, QPointF> > list;
+ for (int i = 0; i < d->xPosition.size(); ++i)
+ list << QPair<qreal, QPointF>(d->xPosition.at(i).step, QPointF(d->xPosition.at(i).value, d->yPosition.at(i).value));
+
+ return list;
+}
+
+/*!
+ Returns the matrix used to transform the item at the specified \a step value.
+*/
+QMatrix QGraphicsItemAnimation::matrixAt(qreal step) const
+{
+ if (step < 0.0 || step > 1.0)
+ qWarning("QGraphicsItemAnimation::matrixAt: invalid step = %f", step);
+
+ QMatrix matrix;
+ if (!d->rotation.isEmpty())
+ matrix.rotate(rotationAt(step));
+ if (!d->verticalScale.isEmpty())
+ matrix.scale(horizontalScaleAt(step), verticalScaleAt(step));
+ if (!d->verticalShear.isEmpty())
+ matrix.shear(horizontalShearAt(step), verticalShearAt(step));
+ if (!d->xTranslation.isEmpty())
+ matrix.translate(xTranslationAt(step), yTranslationAt(step));
+ return matrix;
+}
+
+/*!
+ Returns the angle at which the item is rotated at the specified \a step value.
+
+ \sa setRotationAt()
+*/
+qreal QGraphicsItemAnimation::rotationAt(qreal step) const
+{
+ if (step < 0.0 || step > 1.0)
+ qWarning("QGraphicsItemAnimation::rotationAt: invalid step = %f", step);
+
+ return d->linearValueForStep(step, &d->rotation);
+}
+
+/*!
+ Sets the rotation of the item at the given \a step value to the \a angle specified.
+
+ \sa rotationAt()
+*/
+void QGraphicsItemAnimation::setRotationAt(qreal step, qreal angle)
+{
+ d->insertUniquePair(step, angle, &d->rotation, "setRotationAt");
+}
+
+/*!
+ Returns all explicitly inserted rotations.
+
+ \sa rotationAt(), setRotationAt()
+*/
+QList<QPair<qreal, qreal> > QGraphicsItemAnimation::rotationList() const
+{
+ QList<QPair<qreal, qreal> > list;
+ for (int i = 0; i < d->rotation.size(); ++i)
+ list << QPair<qreal, qreal>(d->rotation.at(i).step, d->rotation.at(i).value);
+
+ return list;
+}
+
+/*!
+ Returns the horizontal translation of the item at the specified \a step value.
+
+ \sa setTranslationAt()
+*/
+qreal QGraphicsItemAnimation::xTranslationAt(qreal step) const
+{
+ if (step < 0.0 || step > 1.0)
+ qWarning("QGraphicsItemAnimation::xTranslationAt: invalid step = %f", step);
+
+ return d->linearValueForStep(step, &d->xTranslation);
+}
+
+/*!
+ Returns the vertical translation of the item at the specified \a step value.
+
+ \sa setTranslationAt()
+*/
+qreal QGraphicsItemAnimation::yTranslationAt(qreal step) const
+{
+ if (step < 0.0 || step > 1.0)
+ qWarning("QGraphicsItemAnimation::yTranslationAt: invalid step = %f", step);
+
+ return d->linearValueForStep(step, &d->yTranslation);
+}
+
+/*!
+ Sets the translation of the item at the given \a step value using the horizontal
+ and vertical coordinates specified by \a dx and \a dy.
+
+ \sa xTranslationAt(), yTranslationAt()
+*/
+void QGraphicsItemAnimation::setTranslationAt(qreal step, qreal dx, qreal dy)
+{
+ d->insertUniquePair(step, dx, &d->xTranslation, "setTranslationAt");
+ d->insertUniquePair(step, dy, &d->yTranslation, "setTranslationAt");
+}
+
+/*!
+ Returns all explicitly inserted translations.
+
+ \sa xTranslationAt(), yTranslationAt(), setTranslationAt()
+*/
+QList<QPair<qreal, QPointF> > QGraphicsItemAnimation::translationList() const
+{
+ QList<QPair<qreal, QPointF> > list;
+ for (int i = 0; i < d->xTranslation.size(); ++i)
+ list << QPair<qreal, QPointF>(d->xTranslation.at(i).step, QPointF(d->xTranslation.at(i).value, d->yTranslation.at(i).value));
+
+ return list;
+}
+
+/*!
+ Returns the vertical scale for the item at the specified \a step value.
+
+ \sa setScaleAt()
+*/
+qreal QGraphicsItemAnimation::verticalScaleAt(qreal step) const
+{
+ if (step < 0.0 || step > 1.0)
+ qWarning("QGraphicsItemAnimation::verticalScaleAt: invalid step = %f", step);
+
+ return d->linearValueForStep(step, &d->verticalScale, 1);
+}
+
+/*!
+ Returns the horizontal scale for the item at the specified \a step value.
+
+ \sa setScaleAt()
+*/
+qreal QGraphicsItemAnimation::horizontalScaleAt(qreal step) const
+{
+ if (step < 0.0 || step > 1.0)
+ qWarning("QGraphicsItemAnimation::horizontalScaleAt: invalid step = %f", step);
+
+ return d->linearValueForStep(step, &d->horizontalScale, 1);
+}
+
+/*!
+ Sets the scale of the item at the given \a step value using the horizontal and
+ vertical scale factors specified by \a sx and \a sy.
+
+ \sa verticalScaleAt(), horizontalScaleAt()
+*/
+void QGraphicsItemAnimation::setScaleAt(qreal step, qreal sx, qreal sy)
+{
+ d->insertUniquePair(step, sx, &d->horizontalScale, "setScaleAt");
+ d->insertUniquePair(step, sy, &d->verticalScale, "setScaleAt");
+}
+
+/*!
+ Returns all explicitly inserted scales.
+
+ \sa verticalScaleAt(), horizontalScaleAt(), setScaleAt()
+*/
+QList<QPair<qreal, QPointF> > QGraphicsItemAnimation::scaleList() const
+{
+ QList<QPair<qreal, QPointF> > list;
+ for (int i = 0; i < d->horizontalScale.size(); ++i)
+ list << QPair<qreal, QPointF>(d->horizontalScale.at(i).step, QPointF(d->horizontalScale.at(i).value, d->verticalScale.at(i).value));
+
+ return list;
+}
+
+/*!
+ Returns the vertical shear for the item at the specified \a step value.
+
+ \sa setShearAt()
+*/
+qreal QGraphicsItemAnimation::verticalShearAt(qreal step) const
+{
+ if (step < 0.0 || step > 1.0)
+ qWarning("QGraphicsItemAnimation::verticalShearAt: invalid step = %f", step);
+
+ return d->linearValueForStep(step, &d->verticalShear, 0);
+}
+
+/*!
+ Returns the horizontal shear for the item at the specified \a step value.
+
+ \sa setShearAt()
+*/
+qreal QGraphicsItemAnimation::horizontalShearAt(qreal step) const
+{
+ if (step < 0.0 || step > 1.0)
+ qWarning("QGraphicsItemAnimation::horizontalShearAt: invalid step = %f", step);
+
+ return d->linearValueForStep(step, &d->horizontalShear, 0);
+}
+
+/*!
+ Sets the shear of the item at the given \a step value using the horizontal and
+ vertical shear factors specified by \a sh and \a sv.
+
+ \sa verticalShearAt(), horizontalShearAt()
+*/
+void QGraphicsItemAnimation::setShearAt(qreal step, qreal sh, qreal sv)
+{
+ d->insertUniquePair(step, sh, &d->horizontalShear, "setShearAt");
+ d->insertUniquePair(step, sv, &d->verticalShear, "setShearAt");
+}
+
+/*!
+ Returns all explicitly inserted shears.
+
+ \sa verticalShearAt(), horizontalShearAt(), setShearAt()
+*/
+QList<QPair<qreal, QPointF> > QGraphicsItemAnimation::shearList() const
+{
+ QList<QPair<qreal, QPointF> > list;
+ for (int i = 0; i < d->horizontalShear.size(); ++i)
+ list << QPair<qreal, QPointF>(d->horizontalShear.at(i).step, QPointF(d->horizontalShear.at(i).value, d->verticalShear.at(i).value));
+
+ return list;
+}
+
+/*!
+ Clears the scheduled transformations used for the animation, but
+ retains the item and timeline.
+*/
+void QGraphicsItemAnimation::clear()
+{
+ d->xPosition.clear();
+ d->yPosition.clear();
+ d->rotation.clear();
+ d->verticalScale.clear();
+ d->horizontalScale.clear();
+ d->verticalShear.clear();
+ d->horizontalShear.clear();
+ d->xTranslation.clear();
+ d->yTranslation.clear();
+}
+
+/*!
+ \fn void QGraphicsItemAnimation::setStep(qreal step)
+
+ Sets the current \a step value for the animation, causing the
+ transformations scheduled at this step to be performed.
+*/
+void QGraphicsItemAnimation::setStep(qreal x)
+{
+ if (x < 0.0 || x > 1.0) {
+ qWarning("QGraphicsItemAnimation::setStep: invalid step = %f", x);
+ return;
+ }
+
+ beforeAnimationStep(x);
+
+ d->step = x;
+ if (d->item) {
+ if (!d->xPosition.isEmpty() || !d->yPosition.isEmpty())
+ d->item->setPos(posAt(x));
+ if (!d->rotation.isEmpty()
+ || !d->verticalScale.isEmpty()
+ || !d->horizontalScale.isEmpty()
+ || !d->verticalShear.isEmpty()
+ || !d->horizontalShear.isEmpty()
+ || !d->xTranslation.isEmpty()
+ || !d->yTranslation.isEmpty()) {
+ d->item->setMatrix(d->startMatrix * matrixAt(x));
+ }
+ }
+
+ afterAnimationStep(x);
+}
+
+/*!
+ Resets the item to its starting position and transformation.
+
+ \obsolete
+
+ You can call setStep(0) instead.
+*/
+void QGraphicsItemAnimation::reset()
+{
+ if (!d->item)
+ return;
+ d->startPos = d->item->pos();
+ d->startMatrix = d->item->matrix();
+}
+
+/*!
+ \fn void QGraphicsItemAnimation::beforeAnimationStep(qreal step)
+
+ This method is meant to be overridden by subclassed that needs to
+ execute additional code before a new step takes place. The
+ animation \a step is provided for use in cases where the action
+ depends on its value.
+*/
+void QGraphicsItemAnimation::beforeAnimationStep(qreal step)
+{
+ Q_UNUSED(step);
+}
+
+/*!
+ \fn void QGraphicsItemAnimation::afterAnimationStep(qreal step)
+
+ This method is meant to be overridden in subclasses that need to
+ execute additional code after a new step has taken place. The
+ animation \a step is provided for use in cases where the action
+ depends on its value.
+*/
+void QGraphicsItemAnimation::afterAnimationStep(qreal step)
+{
+ Q_UNUSED(step);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicsitemanimation.h b/src/gui/graphicsview/qgraphicsitemanimation.h
new file mode 100644
index 0000000..c1312d4
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsitemanimation.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSITEMANIMATION_H
+#define QGRAPHICSITEMANIMATION_H
+
+#include <QtCore/qobject.h>
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QGraphicsItem;
+class QMatrix;
+class QPointF;
+class QTimeLine;
+template <class T1, class T2> struct QPair;
+
+class QGraphicsItemAnimationPrivate;
+class Q_GUI_EXPORT QGraphicsItemAnimation : public QObject
+{
+ Q_OBJECT
+public:
+ QGraphicsItemAnimation(QObject *parent = 0);
+ virtual ~QGraphicsItemAnimation();
+
+ QGraphicsItem *item() const;
+ void setItem(QGraphicsItem *item);
+
+ QTimeLine *timeLine() const;
+ void setTimeLine(QTimeLine *timeLine);
+
+ QPointF posAt(qreal step) const;
+ QList<QPair<qreal, QPointF> > posList() const;
+ void setPosAt(qreal step, const QPointF &pos);
+
+ QMatrix matrixAt(qreal step) const;
+
+ qreal rotationAt(qreal step) const;
+ QList<QPair<qreal, qreal> > rotationList() const;
+ void setRotationAt(qreal step, qreal angle);
+
+ qreal xTranslationAt(qreal step) const;
+ qreal yTranslationAt(qreal step) const;
+ QList<QPair<qreal, QPointF> > translationList() const;
+ void setTranslationAt(qreal step, qreal dx, qreal dy);
+
+ qreal verticalScaleAt(qreal step) const;
+ qreal horizontalScaleAt(qreal step) const;
+ QList<QPair<qreal, QPointF> > scaleList() const;
+ void setScaleAt(qreal step, qreal sx, qreal sy);
+
+ qreal verticalShearAt(qreal step) const;
+ qreal horizontalShearAt(qreal step) const;
+ QList<QPair<qreal, QPointF> > shearList() const;
+ void setShearAt(qreal step, qreal sh, qreal sv);
+
+ void clear();
+
+public Q_SLOTS:
+ void setStep(qreal x);
+ void reset();
+
+protected:
+ virtual void beforeAnimationStep(qreal step);
+ virtual void afterAnimationStep(qreal step);
+
+private:
+ Q_DISABLE_COPY(QGraphicsItemAnimation)
+ QGraphicsItemAnimationPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_GRAPHICSVIEW
+#endif
diff --git a/src/gui/graphicsview/qgraphicslayout.cpp b/src/gui/graphicsview/qgraphicslayout.cpp
new file mode 100644
index 0000000..f78b8c8
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicslayout.cpp
@@ -0,0 +1,423 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qapplication.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+#include "qgraphicslayout.h"
+#include "qgraphicslayout_p.h"
+#include "qgraphicslayoutitem.h"
+#include "qgraphicslayoutitem_p.h"
+#include "qgraphicswidget.h"
+#include "qgraphicswidget_p.h"
+#include "qgraphicsscene.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGraphicsLayout
+ \brief The QGraphicsLayout class provides the base class for all layouts
+ in Graphics View.
+ \since 4.4
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ QGraphicsLayout is an abstract class that defines a virtual API for
+ arranging QGraphicsWidget children and other QGraphicsLayoutItem objects
+ for a QGraphicsWidget. QGraphicsWidget assigns responsibility to a
+ QGraphicsLayout through QGraphicsWidget::setLayout(). As the widget
+ is resized, the layout will automatically arrange the widget's children.
+ QGraphicsLayout inherits QGraphicsLayoutItem, so, it can be managed by
+ any layout, including its own subclasses.
+
+ \section1 Writing a Custom Layout
+
+ You can use QGraphicsLayout as a base to write your own custom layout
+ (e.g., a flowlayout), but it is more common to use one of its subclasses
+ instead - QGraphicsLinearLayout or QGraphicsGridLayout. When creating
+ a custom layout, the following functions must be reimplemented as a bare
+ minimum:
+
+ \table
+ \header \o Function \o Description
+ \row \o QGraphicsLayoutItem::setGeometry()
+ \o Notifies you when the geometry of the layout is set. You can
+ store the geometry in your own layout class in a reimplementation
+ of this function.
+ \row \o QGraphicsLayoutItem::sizeHint()
+ \o Returns the layout's size hints.
+ \row \o QGraphicsLayout::count()
+ \o Returns the number of items in your layout.
+ \row \o QGraphicsLayout::itemAt()
+ \o Returns a pointer to an item in your layout.
+ \row \o QGraphicsLayout::removeAt()
+ \o Removes an item from your layout without destroying it.
+ \endtable
+
+ For more details on how to implement each function, refer to the individual
+ function documentation.
+
+ Each layout defines its own API for arranging widgets and layout items.
+ For example, with a grid layout, you require a row and a
+ column index with optional row and column spans, alignment, spacing, and more.
+ A linear layout, however, requires a single row or column index to position its
+ items. For a grid layout, the order of insertion does not affect the layout in
+ any way, but for a linear layout, the order is essential. When writing your own
+ layout subclass, you are free to choose the API that best suits your layout.
+
+ \section1 Activating the Layout
+
+ When the layout's geometry changes, QGraphicsLayout immediately rearranges
+ all of its managed items by calling setGeometry() on each item. This
+ rearrangement is called \e activating the layout.
+
+ QGraphicsLayout updates its own geometry to match the contentsRect() of the
+ QGraphicsLayoutItem it is managing. Thus, it will automatically rearrange all
+ its items when the widget is resized. QGraphicsLayout caches the sizes of all
+ its managed items to avoid calling setGeometry() too often.
+
+ \note A QGraphicsLayout will have the same geometry as the contentsRect()
+ of the widget (not the layout) it is assigned to.
+
+ \section2 Activating the Layout Implicitly
+
+ The layout can be activated implicitly using one of two ways: by calling
+ activate() or by calling invalidate(). Calling activate() activates the layout
+ immediately. In contrast, calling invalidate() is delayed, as it posts a
+ \l{QEvent::LayoutRequest}{LayoutRequest} event to the managed widget. Due
+ to event compression, the activate() will only be called once after control has
+ returned to the event loop. This is referred to as \e invalidating the layout.
+ Invalidating the layout also invalidates any cached information. Also, the
+ invalidate() function is a virtual function. So, you can invalidate your own
+ cache in a subclass of QGraphicsLayout by reimplementing this function.
+
+ \section1 Event Handling
+
+ QGraphicsLayout listens to events for the widget it manages through the
+ virtual widgetEvent() event handler. When the layout is assigned to a
+ widget, all events delivered to the widget are first processed by
+ widgetEvent(). This allows the layout to be aware of any relevant state
+ changes on the widget such as visibility changes or layout direction changes.
+
+ \section1 Margin Handling
+
+ The margins of a QGraphicsLayout can be modified by reimplementing
+ setContentsMargins() and getContentsMargins().
+
+*/
+
+/*!
+ Contructs a QGraphicsLayout object.
+
+ \a parent is passed to QGraphicsLayoutItem's constructor and the
+ QGraphicsLayoutItem's isLayout argument is set to \e true.
+*/
+QGraphicsLayout::QGraphicsLayout(QGraphicsLayoutItem *parent)
+ : QGraphicsLayoutItem(*new QGraphicsLayoutPrivate)
+{
+ setParentLayoutItem(parent);
+ if (parent && !parent->isLayout()) {
+ // If a layout has a parent that is not a layout it must be a QGraphicsWidget.
+ QGraphicsItem *itemParent = parent->graphicsItem();
+ if (itemParent && itemParent->isWidget()) {
+ static_cast<QGraphicsWidget *>(itemParent)->d_func()->setLayout_helper(this);
+ } else {
+ qWarning("QGraphicsLayout::QGraphicsLayout: Attempt to create a layout with a parent that is"
+ " neither a QGraphicsWidget nor QGraphicsLayout");
+ }
+ }
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, QSizePolicy::DefaultType);
+ setOwnedByLayout(true);
+}
+
+/*!
+ \internal
+*/
+QGraphicsLayout::QGraphicsLayout(QGraphicsLayoutPrivate &dd, QGraphicsLayoutItem *parent)
+ : QGraphicsLayoutItem(dd)
+{
+ setParentLayoutItem(parent);
+ if (parent && !parent->isLayout()) {
+ // If a layout has a parent that is not a layout it must be a QGraphicsWidget.
+ QGraphicsItem *itemParent = parent->graphicsItem();
+ if (itemParent && itemParent->isWidget()) {
+ static_cast<QGraphicsWidget *>(itemParent)->d_func()->setLayout_helper(this);
+ } else {
+ qWarning("QGraphicsLayout::QGraphicsLayout: Attempt to create a layout with a parent that is"
+ " neither a QGraphicsWidget nor QGraphicsLayout");
+ }
+ }
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, QSizePolicy::DefaultType);
+ setOwnedByLayout(true);
+}
+
+/*!
+ Destroys the QGraphicsLayout object.
+*/
+QGraphicsLayout::~QGraphicsLayout()
+{
+}
+
+/*!
+ Sets the contents margins to \a left, \a top, \a right and \a bottom. The
+ default contents margins for toplevel layouts are style dependent
+ (by querying the pixelMetric for QStyle::PM_LayoutLeftMargin,
+ QStyle::PM_LayoutTopMargin, QStyle::PM_LayoutRightMargin and
+ QStyle::PM_LayoutBottomMargin).
+
+ For sublayouts the default margins are 0.
+
+ Changing the contents margins automatically invalidates the layout.
+
+ \sa invalidate()
+*/
+void QGraphicsLayout::setContentsMargins(qreal left, qreal top, qreal right, qreal bottom)
+{
+ Q_D(QGraphicsLayout);
+ if (d->left == left && d->top == top && d->right == right && d->bottom == bottom)
+ return;
+ d->left = left;
+ d->right = right;
+ d->top = top;
+ d->bottom = bottom;
+ invalidate();
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsLayout::getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
+{
+ Q_D(const QGraphicsLayout);
+ d->getMargin(left, d->left, QStyle::PM_LayoutLeftMargin);
+ d->getMargin(top, d->top, QStyle::PM_LayoutTopMargin);
+ d->getMargin(right, d->right, QStyle::PM_LayoutRightMargin);
+ d->getMargin(bottom, d->bottom, QStyle::PM_LayoutBottomMargin);
+}
+
+/*!
+ Activates the layout, causing all items in the layout to be immediately
+ rearranged. This function is based on calling count() and itemAt(), and
+ then calling setGeometry() on all items sequentially. When activated,
+ the layout will adjust its geometry to its parent's contentsRect().
+ The parent will then invalidate any layout of its own.
+
+ If called in sequence or recursively, e.g., by one of the arranged items
+ in response to being resized, this function will do nothing.
+
+ Note that the layout is free to use geometry caching to optimize this
+ process. To forcefully invalidate any such cache, you can call
+ invalidate() before calling activate().
+
+ \sa invalidate()
+*/
+void QGraphicsLayout::activate()
+{
+ Q_D(QGraphicsLayout);
+ if (d->activated)
+ return;
+
+ d->activateRecursive(this);
+
+ // we don't call activate on a sublayout, but somebody might.
+ // Therefore, we walk to the parentitem of the toplevel layout.
+ QGraphicsLayoutItem *parentItem = this;
+ while (parentItem && parentItem->isLayout())
+ parentItem = parentItem->parentLayoutItem();
+ if (!parentItem)
+ return;
+ Q_ASSERT(!parentItem->isLayout());
+
+ setGeometry(parentItem->contentsRect()); // relayout children
+
+ // ### bug, should be parentItem ?
+ parentLayoutItem()->updateGeometry(); // bubble up; will set activated to false
+ // ### too many resizes? maybe we should walk up the chain to the
+ // ### top-level layouted layoutItem and call activate there.
+}
+
+/*!
+ Returns true if the layout is currently being activated; otherwise,
+ returns false. If the layout is being activated, this means that it is
+ currently in the process of rearranging its items (i.e., the activate()
+ function has been called, and has not yet returned).
+
+ \sa activate(), invalidate()
+*/
+bool QGraphicsLayout::isActivated() const
+{
+ Q_D(const QGraphicsLayout);
+ return d->activated;
+}
+
+/*!
+ Clears any cached geometry and size hint information in the layout, and
+ posts a \l{QEvent::LayoutRequest}{LayoutRequest} event to the managed
+ parent QGraphicsLayoutItem.
+
+ \sa activate(), setGeometry()
+*/
+void QGraphicsLayout::invalidate()
+{
+ // only mark layouts as invalid (activated = false) if we can post a LayoutRequest event.
+ QGraphicsLayoutItem *layoutItem = this;
+ while (layoutItem && layoutItem->isLayout()) {
+ // we could call updateGeometry(), but what if that method
+ // does not call the base implementation? In addition, updateGeometry()
+ // does more than we need.
+ layoutItem->d_func()->sizeHintCacheDirty = true;
+ layoutItem = layoutItem->parentLayoutItem();
+ }
+ if (layoutItem)
+ layoutItem->d_func()->sizeHintCacheDirty = true;
+
+ bool postIt = layoutItem ? !layoutItem->isLayout() : false;
+ if (postIt) {
+ layoutItem = this;
+ while (layoutItem && layoutItem->isLayout()
+ && static_cast<QGraphicsLayout*>(layoutItem)->d_func()->activated) {
+ static_cast<QGraphicsLayout*>(layoutItem)->d_func()->activated = false;
+ layoutItem = layoutItem->parentLayoutItem();
+ }
+ if (layoutItem && !layoutItem->isLayout()) {
+ // If a layout has a parent that is not a layout it must be a QGraphicsWidget.
+ QApplication::postEvent(static_cast<QGraphicsWidget *>(layoutItem), new QEvent(QEvent::LayoutRequest));
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsLayout::updateGeometry()
+{
+ QGraphicsLayoutItem::updateGeometry();
+ if (QGraphicsLayoutItem *parentItem = parentLayoutItem()) {
+ if (parentItem->isLayout()) {
+ parentItem->updateGeometry();
+ } else {
+ invalidate();
+ }
+ }
+}
+
+/*!
+ This virtual event handler receives all events for the managed
+ widget. QGraphicsLayout uses this event handler to listen for layout
+ related events such as geometry changes, layout changes or layout
+ direction changes.
+
+ \a e is a pointer to the event.
+
+ You can reimplement this event handler to track similar events for your
+ own custom layout.
+
+ \sa QGraphicsWidget::event(), QGraphicsItem::sceneEvent()
+*/
+void QGraphicsLayout::widgetEvent(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::GraphicsSceneResize:
+ if (isActivated()) {
+ setGeometry(parentLayoutItem()->contentsRect());
+ } else {
+ activate(); // relies on that activate() will call updateGeometry()
+ }
+ break;
+ case QEvent::LayoutRequest:
+ activate();
+ break;
+ case QEvent::LayoutDirectionChange:
+ invalidate();
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ \fn virtual int QGraphicsLayout::count() const = 0
+
+ This pure virtual function must be reimplemented in a subclass of
+ QGraphicsLayout to return the number of items in the layout.
+
+ The subclass is free to decide how to store the items.
+
+ \sa itemAt(), removeAt()
+*/
+
+/*!
+ \fn virtual QGraphicsLayoutItem *QGraphicsLayout::itemAt(int i) const = 0
+
+ This pure virtual function must be reimplemented in a subclass of
+ QGraphicsLayout to return a pointer to the item at index \a i. The
+ reimplementation can assume that \a i is valid (i.e., it respects the
+ value of count()).
+
+ The subclass is free to decide how to store the items.
+
+ \sa count(), removeAt()
+*/
+
+/*!
+ \fn virtual void QGraphicsLayout::removeAt(int index) = 0
+
+ This pure virtual function must be reimplemented in a subclass of
+ QGraphicsLayout to remove the item at \a index. The
+ reimplementation can assume that \a index is valid (i.e., it
+ respects the value of count()).
+
+ The implementation must ensure that the parentLayoutItem() of
+ the removed item does not point to this layout, since the item is
+ considered to be removed from the layout hierarchy.
+
+ If the layout is to be reused between applications, we recommend
+ that the layout deletes the item, but the graphics view framework
+ does not depend on this.
+
+ The subclass is free to decide how to store the items.
+
+ \sa itemAt(), count()
+*/
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicslayout.h b/src/gui/graphicsview/qgraphicslayout.h
new file mode 100644
index 0000000..fad6c3bb
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicslayout.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSLAYOUT_H
+#define QGRAPHICSLAYOUT_H
+
+#include <QtGui/qgraphicslayoutitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+class QGraphicsLayoutPrivate;
+class QGraphicsLayoutItem;
+class QGraphicsWidget;
+
+class Q_GUI_EXPORT QGraphicsLayout : public QGraphicsLayoutItem
+{
+public:
+ QGraphicsLayout(QGraphicsLayoutItem *parent = 0);
+ ~QGraphicsLayout();
+
+ void setContentsMargins(qreal left, qreal top, qreal right, qreal bottom);
+ void getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const;
+
+ void activate();
+ bool isActivated() const;
+ virtual void invalidate();
+ virtual void updateGeometry();
+
+ virtual void widgetEvent(QEvent *e);
+
+ virtual int count() const = 0;
+ virtual QGraphicsLayoutItem *itemAt(int i) const = 0;
+ virtual void removeAt(int index) = 0;
+
+protected:
+ QGraphicsLayout(QGraphicsLayoutPrivate &, QGraphicsLayoutItem *);
+
+private:
+ Q_DISABLE_COPY(QGraphicsLayout)
+ Q_DECLARE_PRIVATE(QGraphicsLayout)
+ friend class QGraphicsWidget;
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
+
diff --git a/src/gui/graphicsview/qgraphicslayout_p.cpp b/src/gui/graphicsview/qgraphicslayout_p.cpp
new file mode 100644
index 0000000..f76f4dd
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicslayout_p.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include "qgraphicslayout_p.h"
+#include "qgraphicslayout.h"
+#include "qgraphicswidget.h"
+#include "qapplication.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+
+ \a mw is the new parent. all items in the layout will be a child of \a mw.
+ */
+void QGraphicsLayoutPrivate::reparentChildItems(QGraphicsItem *newParent)
+{
+ Q_Q(QGraphicsLayout);
+ int n = q->count();
+ //bool mwVisible = mw && mw->isVisible();
+ for (int i = 0; i < n; ++i) {
+ QGraphicsLayoutItem *layoutChild = q->itemAt(i);
+ if (!layoutChild) {
+ // Skip stretch items
+ continue;
+ }
+ if (layoutChild->isLayout()) {
+ QGraphicsLayout *l = static_cast<QGraphicsLayout*>(layoutChild);
+ l->d_func()->reparentChildItems(newParent);
+ } else if (QGraphicsItem *itemChild = layoutChild->graphicsItem()){
+ QGraphicsItem *childParent = itemChild->parentItem();
+#ifdef QT_DEBUG
+ if (childParent && childParent != newParent && itemChild->isWidget() && qt_graphicsLayoutDebug()) {
+ QGraphicsWidget *w = static_cast<QGraphicsWidget*>(layoutChild);
+ qWarning("QGraphicsLayout::addChildLayout: widget %s \"%s\" in wrong parent; moved to correct parent",
+ w->metaObject()->className(), w->objectName().toLocal8Bit().constData());
+ }
+#endif
+ if (childParent != newParent)
+ itemChild->setParentItem(newParent);
+ }
+ }
+}
+
+void QGraphicsLayoutPrivate::getMargin(qreal *result, qreal userMargin, QStyle::PixelMetric pm) const
+{
+ if (!result)
+ return;
+ Q_Q(const QGraphicsLayout);
+
+ QGraphicsLayoutItem *parent = q->parentLayoutItem();
+ if (userMargin >= 0.0) {
+ *result = userMargin;
+ } else if (!parent) {
+ *result = 0.0;
+ } else if (parent->isLayout()) { // sublayouts have 0 margin by default
+ *result = 0.0;
+ } else {
+ *result = 0.0;
+ if (QGraphicsItem *layoutParentItem = parentItem()) {
+ if (layoutParentItem->isWidget())
+ *result = (qreal)static_cast<QGraphicsWidget*>(layoutParentItem)->style()->pixelMetric(pm, 0);
+ }
+ }
+}
+
+Qt::LayoutDirection QGraphicsLayoutPrivate::visualDirection() const
+{
+ if (QGraphicsItem *maybeWidget = parentItem()) {
+ if (maybeWidget->isWidget())
+ return static_cast<QGraphicsWidget*>(maybeWidget)->layoutDirection();
+ }
+ return QApplication::layoutDirection();
+}
+
+static bool removeLayoutItemFromLayout(QGraphicsLayout *lay, QGraphicsLayoutItem *layoutItem)
+{
+ if (!lay)
+ return false;
+
+ QGraphicsLayoutItem *child;
+ for (int i = 0; (child = lay->itemAt(i)); ++i) {
+ if (child && child->isLayout()) {
+ if (removeLayoutItemFromLayout(static_cast<QGraphicsLayout*>(child), layoutItem))
+ return true;
+ } else if (child == layoutItem) {
+ lay->removeAt(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+
+ This function is called from subclasses to add a layout item \a layoutItem
+ to a layout.
+
+ It takes care of automatically reparenting graphics items, if needed.
+
+ If \a layoutItem is a is already in a layout, it will remove it from that layout.
+
+*/
+void QGraphicsLayoutPrivate::addChildLayoutItem(QGraphicsLayoutItem *layoutItem)
+{
+ Q_Q(QGraphicsLayout);
+ if (QGraphicsLayoutItem *maybeLayout = layoutItem->parentLayoutItem()) {
+ if (maybeLayout->isLayout())
+ removeLayoutItemFromLayout(static_cast<QGraphicsLayout*>(maybeLayout), layoutItem);
+ }
+ layoutItem->setParentLayoutItem(q);
+ if (layoutItem->isLayout()) {
+ if (QGraphicsItem *parItem = parentItem()) {
+ static_cast<QGraphicsLayout*>(layoutItem)->d_func()->reparentChildItems(parItem);
+ }
+ } else {
+ if (QGraphicsItem *item = layoutItem->graphicsItem()) {
+ QGraphicsItem *newParent = parentItem();
+ QGraphicsItem *oldParent = item->parentItem();
+ if (oldParent == newParent || !newParent)
+ return;
+
+#ifdef QT_DEBUG
+ if (oldParent && item->isWidget()) {
+ QGraphicsWidget *w = static_cast<QGraphicsWidget*>(item);
+ qWarning("QGraphicsLayout::addChildLayoutItem: %s \"%s\" in wrong parent; moved to correct parent",
+ w->metaObject()->className(), w->objectName().toLocal8Bit().constData());
+ }
+#endif
+
+ item->setParentItem(newParent);
+ }
+ }
+}
+
+void QGraphicsLayoutPrivate::activateRecursive(QGraphicsLayoutItem *item)
+{
+ if (item->isLayout()) {
+ QGraphicsLayout *layout = static_cast<QGraphicsLayout *>(item);
+ if (layout->d_func()->activated)
+ layout->invalidate();
+
+ for (int i = layout->count() - 1; i >= 0; --i) {
+ QGraphicsLayoutItem *childItem = layout->itemAt(i);
+ if (childItem)
+ activateRecursive(childItem);
+ }
+ layout->d_func()->activated = true;
+ }
+}
+
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicslayout_p.h b/src/gui/graphicsview/qgraphicslayout_p.h
new file mode 100644
index 0000000..a8895de
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicslayout_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSLAYOUT_P_H
+#define QGRAPHICSLAYOUT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+#include "qgraphicslayout.h"
+#include "qgraphicslayoutitem_p.h"
+#include <QtGui/qstyle.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsLayoutItem;
+class QGraphicsWidget;
+
+#ifdef QT_DEBUG
+inline bool qt_graphicsLayoutDebug()
+{
+ static int checked_env = -1;
+ if(checked_env == -1)
+ checked_env = !!qgetenv("QT_GRAPHICSLAYOUT_DEBUG").toInt();
+ return checked_env;
+}
+#endif
+
+class Q_AUTOTEST_EXPORT QGraphicsLayoutPrivate : public QGraphicsLayoutItemPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsLayout)
+
+public:
+ QGraphicsLayoutPrivate() : QGraphicsLayoutItemPrivate(0, true), left(-1.0), top(-1.0), right(-1.0), bottom(-1.0),
+ activated(true) { }
+
+ void reparentChildItems(QGraphicsItem *newParent);
+ void getMargin(qreal *result, qreal userMargin, QStyle::PixelMetric pm) const;
+ Qt::LayoutDirection visualDirection() const;
+
+ void addChildLayoutItem(QGraphicsLayoutItem *item);
+ void activateRecursive(QGraphicsLayoutItem *item);
+
+ qreal left, top, right, bottom;
+ bool activated;
+};
+
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSVIEW
+
+#endif
diff --git a/src/gui/graphicsview/qgraphicslayoutitem.cpp b/src/gui/graphicsview/qgraphicslayoutitem.cpp
new file mode 100644
index 0000000..0ea7692
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicslayoutitem.cpp
@@ -0,0 +1,852 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include "qgraphicslayout.h"
+#include "qgraphicsscene.h"
+#include "qgraphicslayoutitem.h"
+#include "qgraphicslayoutitem_p.h"
+#include "qwidget.h"
+
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ COMBINE_SIZE() is identical to combineSize(), except that it
+ doesn't evaluate 'size' unless necessary.
+*/
+#define COMBINE_SIZE(result, size) \
+ do { \
+ if ((result).width() < 0 || (result).height() < 0) \
+ combineSize((result), (size)); \
+ } while (false)
+
+static void combineSize(QSizeF &result, const QSizeF &size)
+{
+ if (result.width() < 0)
+ result.setWidth(size.width());
+ if (result.height() < 0)
+ result.setHeight(size.height());
+}
+
+static void boundSize(QSizeF &result, const QSizeF &size)
+{
+ if (size.width() >= 0 && size.width() < result.width())
+ result.setWidth(size.width());
+ if (size.height() >= 0 && size.height() < result.height())
+ result.setHeight(size.height());
+}
+
+static void expandSize(QSizeF &result, const QSizeF &size)
+{
+ if (size.width() >= 0 && size.width() > result.width())
+ result.setWidth(size.width());
+ if (size.height() >= 0 && size.height() > result.height())
+ result.setHeight(size.height());
+}
+
+static void normalizeHints(qreal &minimum, qreal &preferred, qreal &maximum, qreal &descent)
+{
+ if (minimum >= 0 && maximum >= 0 && minimum > maximum)
+ minimum = maximum;
+
+ if (preferred >= 0) {
+ if (minimum >= 0 && preferred < minimum) {
+ preferred = minimum;
+ } else if (maximum >= 0 && preferred > maximum) {
+ preferred = maximum;
+ }
+ }
+
+ if (minimum >= 0 && descent > minimum)
+ descent = minimum;
+}
+
+/*!
+ \internal
+*/
+QGraphicsLayoutItemPrivate::QGraphicsLayoutItemPrivate(QGraphicsLayoutItem *par, bool layout)
+ : parent(par), isLayout(layout), ownedByLayout(false), graphicsItem(0)
+{
+}
+
+/*!
+ \internal
+*/
+void QGraphicsLayoutItemPrivate::init()
+{
+ sizeHintCacheDirty = true;
+ sizePolicy = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+}
+
+/*!
+ \internal
+*/
+QSizeF *QGraphicsLayoutItemPrivate::effectiveSizeHints(const QSizeF &constraint) const
+{
+ Q_Q(const QGraphicsLayoutItem);
+ if (!sizeHintCacheDirty && cachedConstraint == constraint)
+ return cachedSizeHints;
+
+ for (int i = 0; i < Qt::NSizeHints; ++i) {
+ cachedSizeHints[i] = constraint;
+ combineSize(cachedSizeHints[i], userSizeHints[i]);
+ }
+
+ QSizeF &minS = cachedSizeHints[Qt::MinimumSize];
+ QSizeF &prefS = cachedSizeHints[Qt::PreferredSize];
+ QSizeF &maxS = cachedSizeHints[Qt::MaximumSize];
+ QSizeF &descentS = cachedSizeHints[Qt::MinimumDescent];
+
+ normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth());
+ normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight());
+
+ // if the minimum, preferred and maximum sizes contradict each other
+ // (e.g. the minimum is larger than the maximum) we give priority to
+ // the maximum size, then the minimum size and finally the preferred size
+ COMBINE_SIZE(maxS, q->sizeHint(Qt::MaximumSize, maxS));
+ combineSize(maxS, QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
+ expandSize(maxS, prefS);
+ expandSize(maxS, minS);
+ boundSize(maxS, QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
+
+ COMBINE_SIZE(minS, q->sizeHint(Qt::MinimumSize, minS));
+ expandSize(minS, QSizeF(0, 0));
+ boundSize(minS, prefS);
+ boundSize(minS, maxS);
+
+ COMBINE_SIZE(prefS, q->sizeHint(Qt::PreferredSize, prefS));
+ expandSize(prefS, minS);
+ boundSize(prefS, maxS);
+
+ // Not supported yet
+ // COMBINE_SIZE(descentS, q->sizeHint(Qt::MinimumDescent, constraint));
+
+ cachedConstraint = constraint;
+ sizeHintCacheDirty = false;
+ return cachedSizeHints;
+}
+
+
+/*!
+ \internal
+
+ Returns the parent item of this layout, or 0 if this layout is
+ not installed on any widget.
+
+ If this is the item that the layout is installed on, it will return "itself".
+
+ If the layout is a sub-layout, this function returns the parent
+ widget of the parent layout.
+
+ Note that it will traverse up the layout item hierarchy instead of just calling
+ QGraphicsItem::parentItem(). This is on purpose.
+
+ \sa parent()
+*/
+QGraphicsItem *QGraphicsLayoutItemPrivate::parentItem() const
+{
+ Q_Q(const QGraphicsLayoutItem);
+
+ const QGraphicsLayoutItem *parent = q;
+ while (parent && parent->isLayout()) {
+ parent = parent->parentLayoutItem();
+ }
+ return parent ? parent->graphicsItem() : 0;
+}
+
+/*!
+ \class QGraphicsLayoutItem
+ \brief The QGraphicsLayoutItem class can be inherited to allow your custom
+ items to be managed by layouts.
+ \since 4.4
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ QGraphicsLayoutItem is an abstract class that defines a set of virtual
+ functions describing sizes, size policies, and size hints for any object
+ arranged by QGraphicsLayout. The API contains functions relevant
+ for both the item itself and for the user of the item as most of
+ QGraphicsLayoutItem's functions are also part of the subclass' public API.
+
+ In most cases, existing layout-aware classes such as QGraphicsWidget and
+ QGraphicsLayout already provide the functionality you require. However,
+ subclassing these classes will enable you to create both graphical
+ elements that work well with layouts (QGraphicsWidget) or custom layouts
+ (QGraphicsLayout).
+
+ \section1 Subclassing QGraphicsLayoutItem
+
+ If you create a subclass of QGraphicsLayoutItem and reimplement its
+ virtual functions, you will enable the layout to resize and position your
+ item along with other QGraphicsLayoutItems including QGraphicsWidget
+ and QGraphicsLayout.
+
+ You can start by reimplementing important functions: the protected
+ sizeHint() function, as well as the public setGeometry()
+ function. If you want your items to be aware of immediate geometry
+ changes, you can also reimplement updateGeometry().
+
+ The geometry, size hint, and size policy affect the item's size and
+ position. Calling setGeometry() will always resize and reposition the item
+ immediately. Normally, this function is called by QGraphicsLayout after
+ the layout has been activated, but it can also be called by the item's user
+ at any time.
+
+ The sizeHint() function returns the item' minimum, preferred and maximum
+ size hints. You can override these properties by calling setMinimumSize(),
+ setPreferredSize() or setMaximumSize(). You can also use functions such as
+ setMinimumWidth() or setMaximumHeight() to set only the width or height
+ component if desired.
+
+ The effectiveSizeHint() function, on the other hand, returns a size hint
+ for any given Qt::SizeHint, and guarantees that the returned size is bound
+ to the minimum and maximum sizes and size hints. You can set the item's
+ vertical and horizontal size policy by calling setSizePolicy(). The
+ sizePolicy property is used by the layout system to describe how this item
+ prefers to grow or shrink.
+
+ \section1 Nesting QGraphicsLayoutItems
+
+ QGraphicsLayoutItems can be nested within other QGraphicsLayoutItems,
+ similar to layouts that can contain sublayouts. This is done either by
+ passing a QGraphicsLayoutItem pointer to QGraphicsLayoutItem's
+ protected constructor, or by calling setParentLayoutItem(). The
+ parentLayoutItem() function returns a pointer to the item's layoutItem
+ parent. If the item's parent is 0 or if the the parent does not inherit
+ from QGraphicsItem, the parentLayoutItem() function then returns 0.
+ isLayout() returns true if the QGraphicsLayoutItem subclass is itself a
+ layout, or false otherwise.
+
+ Qt uses QGraphicsLayoutItem to provide layout functionality in the
+ \l{The Graphics View Framework}, but in the future its use may spread
+ throughout Qt itself.
+
+ \sa QGraphicsWidget, QGraphicsLayout, QGraphicsLinearLayout,
+ QGraphicsGridLayout
+*/
+
+/*!
+ Constructs the QGraphicsLayoutItem object. \a parent becomes the object's
+ parent. If \a isLayout is true the item is a layout, otherwise
+ \a isLayout is false.
+*/
+QGraphicsLayoutItem::QGraphicsLayoutItem(QGraphicsLayoutItem *parent, bool isLayout)
+ : d_ptr(new QGraphicsLayoutItemPrivate(parent, isLayout))
+{
+ Q_D(QGraphicsLayoutItem);
+ d->init();
+ d->q_ptr = this;
+}
+
+/*!
+ \internal
+*/
+QGraphicsLayoutItem::QGraphicsLayoutItem(QGraphicsLayoutItemPrivate &dd)
+ : d_ptr(&dd)
+{
+ Q_D(QGraphicsLayoutItem);
+ d->q_ptr = this;
+}
+
+/*!
+ Destroys the QGraphicsLayoutItem object.
+*/
+QGraphicsLayoutItem::~QGraphicsLayoutItem()
+{
+ QGraphicsLayoutItem *parentLI = parentLayoutItem();
+ if (parentLI && parentLI->isLayout()) {
+ QGraphicsLayout *lay = static_cast<QGraphicsLayout*>(parentLI);
+ // this is not optimal
+ for (int i = lay->count() - 1; i >= 0; --i) {
+ if (lay->itemAt(i) == this) {
+ lay->removeAt(i);
+ break;
+ }
+ }
+ }
+ delete d_ptr;
+}
+
+/*!
+ \fn virtual QSizeF QGraphicsLayoutItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const = 0;
+
+ This pure virtual function returns the size hint for \a which of the
+ QGraphicsLayoutItem, using the width or height of \a constraint to
+ constrain the output.
+
+ Reimplement this function in a subclass of QGraphicsLayoutItem to
+ provide the necessary size hints for your items.
+
+ \sa effectiveSizeHint()
+*/
+
+/*!
+ Sets the size policy to \a policy. The size policy describes how the item
+ should grow horizontally and vertically when arranged in a layout.
+
+ QGraphicsLayoutItem's default size policy is (QSizePolicy::Fixed,
+ QSizePolicy::Fixed, QSizePolicy::DefaultType), but it is common for
+ subclasses to change the default. For example, QGraphicsWidget defaults
+ to (QSizePolicy::Preferred, QSizePolicy::Preferred,
+ QSizePolicy::DefaultType).
+
+ \sa sizePolicy(), QWidget::sizePolicy()
+*/
+void QGraphicsLayoutItem::setSizePolicy(const QSizePolicy &policy)
+{
+ Q_D(QGraphicsLayoutItem);
+ if (d->sizePolicy == policy)
+ return;
+ d->sizePolicy = policy;
+ updateGeometry();
+}
+
+/*!
+ \overload
+
+ This function is equivalent to calling
+ setSizePolicy(QSizePolicy(\a hPolicy, \a vPolicy, \a controlType)).
+
+ \sa sizePolicy(), QWidget::sizePolicy()
+*/
+void QGraphicsLayoutItem::setSizePolicy(QSizePolicy::Policy hPolicy,
+ QSizePolicy::Policy vPolicy,
+ QSizePolicy::ControlType controlType)
+{
+ setSizePolicy(QSizePolicy(hPolicy, vPolicy, controlType));
+}
+
+/*!
+ Returns the current size policy.
+
+ \sa setSizePolicy(), QWidget::sizePolicy()
+*/
+QSizePolicy QGraphicsLayoutItem::sizePolicy() const
+{
+ Q_D(const QGraphicsLayoutItem);
+ return d->sizePolicy;
+}
+
+/*!
+ Sets the minimum size to \a size. This property overrides sizeHint() for
+ Qt::MinimumSize and ensures that effectiveSizeHint() will never return
+ a size smaller than \a size. In order to unset the minimum size, use an
+ invalid size.
+
+ \sa minimumSize(), maximumSize(), preferredSize(), Qt::MinimumSize,
+ sizeHint(), setMinimumWidth(), setMinimumHeight()
+*/
+void QGraphicsLayoutItem::setMinimumSize(const QSizeF &size)
+{
+ Q_D(QGraphicsLayoutItem);
+ if (size == d->userSizeHints[Qt::MinimumSize])
+ return;
+
+ d->userSizeHints[Qt::MinimumSize] = size;
+ updateGeometry();
+}
+
+/*!
+ \fn QGraphicsLayoutItem::setMinimumSize(qreal w, qreal h)
+
+ This convenience function is equivalent to calling
+ setMinimumSize(QSizeF(\a w, \a h)).
+
+ \sa minimumSize(), setMaximumSize(), setPreferredSize(), sizeHint()
+*/
+
+/*!
+ Returns the minimum size.
+
+ \sa setMinimumSize(), preferredSize(), maximumSize(), Qt::MinimumSize,
+ sizeHint()
+*/
+QSizeF QGraphicsLayoutItem::minimumSize() const
+{
+ return effectiveSizeHint(Qt::MinimumSize);
+}
+
+/*!
+ Sets the minimum width to \a width.
+
+ \sa minimumWidth(), setMinimumSize(), minimumSize()
+*/
+void QGraphicsLayoutItem::setMinimumWidth(qreal width)
+{
+ Q_D(QGraphicsLayoutItem);
+ qreal &userSizeHint = d->userSizeHints[Qt::MinimumSize].rwidth();
+ if (width == userSizeHint)
+ return;
+ userSizeHint = width;
+ updateGeometry();
+}
+
+/*!
+ Sets the minimum height to \a height.
+
+ \sa minimumHeight(), setMinimumSize(), minimumSize()
+*/
+void QGraphicsLayoutItem::setMinimumHeight(qreal height)
+{
+ Q_D(QGraphicsLayoutItem);
+ qreal &userSizeHint = d->userSizeHints[Qt::MinimumSize].rheight();
+ if (height == userSizeHint)
+ return;
+ userSizeHint = height;
+ updateGeometry();
+}
+
+
+/*!
+ Sets the preferred size to \a size. This property overrides sizeHint() for
+ Qt::PreferredSize and provides the default value for effectiveSizeHint().
+ In order to unset the preferred size, use an invalid size.
+
+ \sa preferredSize(), minimumSize(), maximumSize(), Qt::PreferredSize,
+ sizeHint()
+*/
+void QGraphicsLayoutItem::setPreferredSize(const QSizeF &size)
+{
+ Q_D(QGraphicsLayoutItem);
+ if (size == d->userSizeHints[Qt::PreferredSize])
+ return;
+
+ d->userSizeHints[Qt::PreferredSize] = size;
+ updateGeometry();
+}
+
+/*!
+ \fn QGraphicsLayoutItem::setPreferredSize(qreal w, qreal h)
+
+ This convenience function is equivalent to calling
+ setPreferredSize(QSizeF(\a w, \a h)).
+
+ \sa preferredSize(), setMaximumSize(), setMinimumSize(), sizeHint()
+*/
+
+/*!
+ Returns the preferred size.
+
+ \sa setPreferredSize(), minimumSize(), maximumSize(), Qt::PreferredSize,
+ sizeHint()
+*/
+QSizeF QGraphicsLayoutItem::preferredSize() const
+{
+ return effectiveSizeHint(Qt::PreferredSize);
+}
+
+/*!
+ Sets the preferred height to \a height.
+
+ \sa preferredWidth(), setPreferredSize(), preferredSize()
+*/
+void QGraphicsLayoutItem::setPreferredHeight(qreal height)
+{
+ Q_D(QGraphicsLayoutItem);
+ qreal &userSizeHint = d->userSizeHints[Qt::PreferredSize].rheight();
+ if (height == userSizeHint)
+ return;
+ userSizeHint = height;
+ updateGeometry();
+}
+
+/*!
+ Sets the preferred width to \a width.
+
+ \sa preferredHeight(), setPreferredSize(), preferredSize()
+*/
+void QGraphicsLayoutItem::setPreferredWidth(qreal width)
+{
+ Q_D(QGraphicsLayoutItem);
+ qreal &userSizeHint = d->userSizeHints[Qt::PreferredSize].rwidth();
+ if (width == userSizeHint)
+ return;
+ userSizeHint = width;
+ updateGeometry();
+}
+
+/*!
+ Sets the maximum size to \a size. This property overrides sizeHint() for
+ Qt::MaximumSize and ensures that effectiveSizeHint() will never return a
+ size larger than \a size. In order to unset the maximum size, use an
+ invalid size.
+
+ \sa maximumSize(), minimumSize(), preferredSize(), Qt::MaximumSize,
+ sizeHint()
+*/
+void QGraphicsLayoutItem::setMaximumSize(const QSizeF &size)
+{
+ Q_D(QGraphicsLayoutItem);
+ if (size == d->userSizeHints[Qt::MaximumSize])
+ return;
+
+ d->userSizeHints[Qt::MaximumSize] = size;
+ updateGeometry();
+}
+
+/*!
+ \fn QGraphicsLayoutItem::setMaximumSize(qreal w, qreal h)
+
+ This convenience function is equivalent to calling
+ setMaximumSize(QSizeF(\a w, \a h)).
+
+ \sa maximumSize(), setMinimumSize(), setPreferredSize(), sizeHint()
+*/
+
+/*!
+ Returns the maximum size.
+
+ \sa setMaximumSize(), minimumSize(), preferredSize(), Qt::MaximumSize,
+ sizeHint()
+*/
+QSizeF QGraphicsLayoutItem::maximumSize() const
+{
+ return effectiveSizeHint(Qt::MaximumSize);
+}
+
+/*!
+ Sets the maximum width to \a width.
+
+ \sa maximumWidth(), setMaximumSize(), maximumSize()
+*/
+void QGraphicsLayoutItem::setMaximumWidth(qreal width)
+{
+ Q_D(QGraphicsLayoutItem);
+ qreal &userSizeHint = d->userSizeHints[Qt::MaximumSize].rwidth();
+ if (width == userSizeHint)
+ return;
+ userSizeHint = width;
+ updateGeometry();
+}
+
+/*!
+ Sets the maximum height to \a height.
+
+ \sa maximumHeight(), setMaximumSize(), maximumSize()
+*/
+void QGraphicsLayoutItem::setMaximumHeight(qreal height)
+{
+ Q_D(QGraphicsLayoutItem);
+ qreal &userSizeHint = d->userSizeHints[Qt::MaximumSize].rheight();
+ if (height == userSizeHint)
+ return;
+ userSizeHint = height;
+ updateGeometry();
+}
+
+/*!
+ \fn qreal QGraphicsLayoutItem::minimumWidth() const
+
+ Returns the minimum width.
+
+ \sa setMinimumWidth(), setMinimumSize(), minimumSize()
+*/
+
+/*!
+ \fn qreal QGraphicsLayoutItem::minimumHeight() const
+
+ Returns the minimum height.
+
+ \sa setMinimumHeight(), setMinimumSize(), minimumSize()
+*/
+
+/*!
+ \fn qreal QGraphicsLayoutItem::preferredWidth() const
+
+ Returns the preferred width.
+
+ \sa setPreferredWidth(), setPreferredSize(), preferredSize()
+*/
+
+/*!
+ \fn qreal QGraphicsLayoutItem::preferredHeight() const
+
+ Returns the preferred height.
+
+ \sa setPreferredHeight(), setPreferredSize(), preferredSize()
+*/
+
+/*!
+ \fn qreal QGraphicsLayoutItem::maximumWidth() const
+
+ Returns the maximum width.
+
+ \sa setMaximumWidth(), setMaximumSize(), maximumSize()
+*/
+
+/*!
+ \fn qreal QGraphicsLayoutItem::maximumHeight() const
+
+ Returns the maximum height.
+
+ \sa setMaximumHeight(), setMaximumSize(), maximumSize()
+*/
+
+/*!
+ \fn virtual void QGraphicsLayoutItem::setGeometry(const QRectF &rect) = 0
+
+ This pure virtual function sets the geometry of the QGraphicsLayoutItem to
+ \a rect, which is in parent coordinates (e.g., the top-left corner of \a rect
+ is equivalent to the item's position in parent coordinates).
+
+ Reimplement this function in a subclass of QGraphicsLayoutItem to enable
+ your item to receive geometry updates.
+
+ If \a rect is outside of the bounds of minimumSize and maximumSize, it
+ will be adjusted to its closest size so that it is within the legal
+ bounds.
+
+ \sa geometry()
+*/
+void QGraphicsLayoutItem::setGeometry(const QRectF &rect)
+{
+ Q_D(QGraphicsLayoutItem);
+ QSizeF effectiveSize = rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize))
+ .boundedTo(effectiveSizeHint(Qt::MaximumSize));
+ d->geom = QRectF(rect.topLeft(), effectiveSize);
+}
+
+/*!
+ \fn QRectF QGraphicsLayoutItem::geometry() const
+
+ Returns the item's geometry (e.g., position and size) as a
+ QRectF. This function is equivalent to QRectF(pos(), size()).
+
+ \sa setGeometry()
+*/
+QRectF QGraphicsLayoutItem::geometry() const
+{
+ Q_D(const QGraphicsLayoutItem);
+ return d->geom;
+}
+
+/*!
+ This virtual function provides the \a left, \a top, \a right and \a bottom
+ contents margins for this QGraphicsLayoutItem. The default implementation
+ assumes all contents margins are 0. The parameters point to values stored
+ in qreals. If any of the pointers is 0, that value will not be updated.
+
+ \sa QGraphicsWidget::setContentsMargins()
+*/
+void QGraphicsLayoutItem::getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
+{
+ if (left)
+ *left = 0;
+ if (top)
+ *top = 0;
+ if (right)
+ *right = 0;
+ if (bottom)
+ *bottom = 0;
+}
+
+/*!
+ Returns the contents rect in local coordinates.
+
+ The contents rect defines the subrectangle used by an associated layout
+ when arranging subitems. This function is a convenience function that
+ adjusts the item's geometry() by its contents margins. Note that
+ getContentsMargins() is a virtual function that you can reimplement to
+ return the item's contents margins.
+
+ \sa getContentsMargins(), geometry()
+*/
+QRectF QGraphicsLayoutItem::contentsRect() const
+{
+ qreal left, top, right, bottom;
+ getContentsMargins(&left, &top, &right, &bottom);
+ return QRectF(QPointF(), geometry().size()).adjusted(+left, +top, -right, -bottom);
+}
+
+/*!
+ Returns the effective size hint for this QGraphicsLayoutItem.
+
+ \a which is the size hint in question.
+ \a constraint is an optional argument that defines a special constrain
+ when calculating the effective size hint. By default, \a constraint is
+ QSizeF(-1, -1), which means there is no constraint to the size hint.
+
+ If you want to specify the widget's size hint for a given width or height,
+ you can provide the fixed dimension in \a constraint. This is useful for
+ widgets that can grow only either vertically or horizontally, and need to
+ set either their width or their height to a special value.
+
+ For example, a text paragraph item fit into a column width of 200 may
+ grow vertically. You can pass QSizeF(200, -1) as a constraint to get a
+ suitable minimum, preferred and maximum height).
+
+ You can adjust the effective size hint by reimplementing sizeHint()
+ in a QGraphicsLayoutItem subclass, or by calling one of the following
+ functions: setMinimumSize(), setPreferredSize, or setMaximumSize()
+ (or a combination of both).
+
+ This function caches each of the size hints and guarantees that
+ sizeHint() will be called only once for each value of \a which - unless
+ \a constraint is not specified and updateGeometry() has been called.
+
+ \sa sizeHint()
+*/
+QSizeF QGraphicsLayoutItem::effectiveSizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ // ### should respect size policy???
+ return d_ptr->effectiveSizeHints(constraint)[which];
+}
+
+/*!
+ This virtual function discards any cached size hint information. You
+ should always call this function if you change the return value of the
+ sizeHint() function. Subclasses must always call the base implementation
+ when reimplementing this function.
+
+ \sa effectiveSizeHint()
+*/
+void QGraphicsLayoutItem::updateGeometry()
+{
+ Q_D(QGraphicsLayoutItem);
+ d->sizeHintCacheDirty = true;
+}
+
+/*!
+ Returns the parent of this QGraphicsLayoutItem, or 0 if there is no parent,
+ or if the parent does not inherit from QGraphicsLayoutItem
+ (QGraphicsLayoutItem is often used through multiple inheritance with
+ QObject-derived classes).
+
+ \sa setParentLayoutItem()
+*/
+QGraphicsLayoutItem *QGraphicsLayoutItem::parentLayoutItem() const
+{
+ return d_func()->parent;
+}
+
+/*!
+ Sets the parent of this QGraphicsLayoutItem to \a parent.
+
+ \sa parentLayoutItem()
+*/
+void QGraphicsLayoutItem::setParentLayoutItem(QGraphicsLayoutItem *parent)
+{
+ d_func()->parent = parent;
+}
+
+/*!
+ Returns true if this QGraphicsLayoutItem is a layout (e.g., is inherited
+ by an object that arranges other QGraphicsLayoutItem objects); otherwise
+ returns false.
+
+ \sa QGraphicsLayout
+*/
+bool QGraphicsLayoutItem::isLayout() const
+{
+ return d_func()->isLayout;
+}
+
+/*!
+ Returns whether a layout should delete this item in its destructor.
+ If its true, then the layout will delete it. If its false, then it is
+ assumed that another object has the ownership of it, and the layout won't
+ delete this item.
+
+ If the item inherits both QGraphicsItem and QGraphicsLayoutItem (such
+ as QGraphicsWidget does) the item is really part of two ownership
+ hierarchies. This property informs what the layout should do with its
+ child items when it is destructed. In the case of QGraphicsWidget, it
+ is preferred that when the layout is deleted it won't delete its children
+ (since they are also part of the graphics item hierarchy).
+
+ By default this value is initialized to false in QGraphicsLayoutItem,
+ but it is overridden by QGraphicsLayout to return true. This is because
+ QGraphicsLayout is not normally part of the QGraphicsItem hierarchy, so the
+ parent layout should delete it.
+ Subclasses might override this default behaviour by calling
+ setOwnedByLayout(true).
+
+ \sa setOwnedByLayout()
+*/
+bool QGraphicsLayoutItem::ownedByLayout() const
+{
+ return d_func()->ownedByLayout;
+}
+/*!
+ Sets whether a layout should delete this item in its destructor or not.
+ \a ownership must be true to in order for the layout to delete it.
+ \sa ownedByLayout()
+*/
+void QGraphicsLayoutItem::setOwnedByLayout(bool ownership)
+{
+ d_func()->ownedByLayout = ownership;
+}
+
+/*!
+ * Returns the QGraphicsItem that this layout item represents.
+ * For QGraphicsWidget it will return itself. For custom items it can return an
+ * aggregated value.
+ *
+ * \sa setGraphicsItem()
+ */
+QGraphicsItem *QGraphicsLayoutItem::graphicsItem() const
+{
+ return d_func()->graphicsItem;
+}
+
+/*!
+ * If the QGraphicsLayoutItem represents a QGraphicsItem, and it wants to take
+ * advantage of the automatic reparenting capabilities of QGraphicsLayout it
+ * should set this value.
+ * Note that if you delete \a item and not delete the layout item, you are
+ * responsible of calling setGraphicsItem(0) in order to avoid having a
+ * dangling pointer.
+ *
+ * \sa graphicsItem()
+ */
+void QGraphicsLayoutItem::setGraphicsItem(QGraphicsItem *item)
+{
+ d_func()->graphicsItem = item;
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicslayoutitem.h b/src/gui/graphicsview/qgraphicslayoutitem.h
new file mode 100644
index 0000000..31f5d90
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicslayoutitem.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSLAYOUTITEM_H
+#define QGRAPHICSLAYOUTITEM_H
+
+#include <QtGui/qsizepolicy.h>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+class QGraphicsLayoutItemPrivate;
+class QGraphicsItem;
+class Q_GUI_EXPORT QGraphicsLayoutItem
+{
+public:
+ QGraphicsLayoutItem(QGraphicsLayoutItem *parent = 0, bool isLayout = false);
+ virtual ~QGraphicsLayoutItem();
+
+ void setSizePolicy(const QSizePolicy &policy);
+ void setSizePolicy(QSizePolicy::Policy hPolicy, QSizePolicy::Policy vPolicy, QSizePolicy::ControlType controlType = QSizePolicy::DefaultType);
+ QSizePolicy sizePolicy() const;
+
+ void setMinimumSize(const QSizeF &size);
+ inline void setMinimumSize(qreal w, qreal h);
+ QSizeF minimumSize() const;
+ void setMinimumWidth(qreal width);
+ inline qreal minimumWidth() const;
+ void setMinimumHeight(qreal height);
+ inline qreal minimumHeight() const;
+
+ void setPreferredSize(const QSizeF &size);
+ inline void setPreferredSize(qreal w, qreal h);
+ QSizeF preferredSize() const;
+ void setPreferredWidth(qreal width);
+ inline qreal preferredWidth() const;
+ void setPreferredHeight(qreal height);
+ inline qreal preferredHeight() const;
+
+ void setMaximumSize(const QSizeF &size);
+ inline void setMaximumSize(qreal w, qreal h);
+ QSizeF maximumSize() const;
+ void setMaximumWidth(qreal width);
+ inline qreal maximumWidth() const;
+ void setMaximumHeight(qreal height);
+ inline qreal maximumHeight() const;
+
+ virtual void setGeometry(const QRectF &rect);
+ QRectF geometry() const;
+ virtual void getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const;
+ QRectF contentsRect() const;
+
+ QSizeF effectiveSizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+ virtual void updateGeometry(); //### rename to sizeHintChanged()
+
+ QGraphicsLayoutItem *parentLayoutItem() const;
+ void setParentLayoutItem(QGraphicsLayoutItem *parent);
+
+ bool isLayout() const;
+ // ###Qt5: Make automatic reparenting work regardless of item/object/widget type.
+ QGraphicsItem *graphicsItem() const;
+ bool ownedByLayout() const;
+
+protected:
+ void setGraphicsItem(QGraphicsItem *item);
+ void setOwnedByLayout(bool ownedByLayout);
+ QGraphicsLayoutItem(QGraphicsLayoutItemPrivate &dd);
+
+ virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const = 0;
+ QGraphicsLayoutItemPrivate *d_ptr;
+
+private:
+ QSizeF *effectiveSizeHints(const QSizeF &constraint) const;
+ Q_DECLARE_PRIVATE(QGraphicsLayoutItem)
+
+ friend class QGraphicsLayout;
+};
+
+inline void QGraphicsLayoutItem::setMinimumSize(qreal aw, qreal ah)
+{ setMinimumSize(QSizeF(aw, ah)); }
+inline void QGraphicsLayoutItem::setPreferredSize(qreal aw, qreal ah)
+{ setPreferredSize(QSizeF(aw, ah)); }
+inline void QGraphicsLayoutItem::setMaximumSize(qreal aw, qreal ah)
+{ setMaximumSize(QSizeF(aw, ah)); }
+
+inline qreal QGraphicsLayoutItem::minimumWidth() const
+{ return effectiveSizeHint(Qt::MinimumSize).width(); }
+inline qreal QGraphicsLayoutItem::minimumHeight() const
+{ return effectiveSizeHint(Qt::MinimumSize).height(); }
+
+inline qreal QGraphicsLayoutItem::preferredWidth() const
+{ return effectiveSizeHint(Qt::PreferredSize).width(); }
+inline qreal QGraphicsLayoutItem::preferredHeight() const
+{ return effectiveSizeHint(Qt::PreferredSize).height(); }
+
+inline qreal QGraphicsLayoutItem::maximumWidth() const
+{ return effectiveSizeHint(Qt::MaximumSize).width(); }
+inline qreal QGraphicsLayoutItem::maximumHeight() const
+{ return effectiveSizeHint(Qt::MaximumSize).height(); }
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/gui/graphicsview/qgraphicslayoutitem_p.h b/src/gui/graphicsview/qgraphicslayoutitem_p.h
new file mode 100644
index 0000000..fab0f39
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicslayoutitem_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSLAYOUTITEM_P_H
+#define QGRAPHICSLAYOUTITEM_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QSizeF>
+#include <QtGui/QSizePolicy>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsLayoutItem;
+class Q_AUTOTEST_EXPORT QGraphicsLayoutItemPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsLayoutItem)
+public:
+ virtual ~QGraphicsLayoutItemPrivate() {}
+ QGraphicsLayoutItemPrivate(QGraphicsLayoutItem *parent, bool isLayout);
+ void init();
+ QSizeF *effectiveSizeHints(const QSizeF &constraint) const;
+ QGraphicsItem *parentItem() const;
+
+ QSizePolicy sizePolicy;
+ QGraphicsLayoutItem *parent;
+
+ QSizeF userSizeHints[Qt::NSizeHints];
+ mutable QSizeF cachedSizeHints[Qt::NSizeHints];
+ mutable QSizeF cachedConstraint;
+
+ mutable quint32 sizeHintCacheDirty : 1;
+ quint32 isLayout : 1;
+ quint32 ownedByLayout : 1;
+
+ QGraphicsLayoutItem *q_ptr;
+ QRectF geom;
+ QGraphicsItem *graphicsItem;
+};
+
+QT_END_NAMESPACE
+
+#endif //QGRAPHICSLAYOUTITEM_P_H
+
diff --git a/src/gui/graphicsview/qgraphicslinearlayout.cpp b/src/gui/graphicsview/qgraphicslinearlayout.cpp
new file mode 100644
index 0000000..6a2d456
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicslinearlayout.cpp
@@ -0,0 +1,547 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QGraphicsLinearLayout
+ \brief The QGraphicsLinearLayout class provides a horizontal or vertical
+ layout for managing widgets in Graphics View.
+ \since 4.4
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ The default orientation for a linear layout is Qt::Horizontal. You can
+ choose a vertical orientation either by calling setOrientation(), or by
+ passing Qt::Vertical to QGraphicsLinearLayout's constructor.
+
+ The most common way to use QGraphicsLinearLayout 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().
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicslinearlayout.cpp 0
+
+ You can add widgets, layouts, stretches (addStretch(), insertStretch() or
+ setStretchFactor()), and spacings (setItemSpacing()) to a linear
+ layout. 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() or removeItem() will remove an item from the layout, without
+ destroying it.
+
+ \section1 Size Hints and Size Policies in QGraphicsLinearLayout
+
+ QGraphicsLinearLayout respects each item's size hints and size policies,
+ and when the layout contains 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(). By default, items are
+ centered both vertically and horizontally.
+
+ \section1 Spacing within QGraphicsLinearLayout
+
+ Between the items, the layout distributes some space. The actual amount of
+ space depends on the managed widget's current style, but the common
+ spacing is 4. You can also set your own spacing by calling setSpacing(),
+ and get the current spacing value by calling spacing(). If you want to
+ configure individual spacing for your items, you can call setItemSpacing().
+
+ \section1 Stretch Factor in QGraphicsLinearLayout
+
+ You can assign a stretch factor to each item to control how much space it
+ will get compared to the other items. By default, two identical widgets
+ arranged in a linear layout will have the same size, but if the first
+ widget has a stretch factor of 1 and the second widget has a stretch
+ factor of 2, the first widget will get 1/3 of the available space, and the
+ second will get 2/3.
+
+ QGraphicsLinearLayout calculates the distribution of sizes by adding up
+ the stretch factors of all items, and then dividing the available space
+ accordingly. The default stretch factor is 0 for all items; a factor of 0
+ means the item does not have any defined stretch factor; effectively this
+ is the same as setting the stretch factor to 1. The stretch factor only
+ applies to the available space in the lengthwise direction of the layout
+ (following its orientation). If you want to control both the item's
+ horizontal and vertical stretch, you can use QGraphicsGridLayout instead.
+
+ \section1 QGraphicsLinearLayout Compared to Other Layouts
+
+ QGraphicsLinearLayout is very similar to QVBoxLayout and QHBoxLayout, but
+ in contrast to these classes, it is used to manage QGraphicsWidget and
+ QGraphicsLayout instead of QWidget and QLayout.
+
+ \sa QGraphicsGridLayout, QGraphicsWidget
+*/
+
+#include "qapplication.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include "qwidget.h"
+#include "qgraphicslayout_p.h"
+#include "qgraphicslayoutitem.h"
+#include "qgraphicslinearlayout.h"
+#include "qgraphicswidget.h"
+#include "qgridlayoutengine_p.h"
+#ifdef QT_DEBUG
+#include <QtCore/qdebug.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsLinearLayoutPrivate : public QGraphicsLayoutPrivate
+{
+public:
+ QGraphicsLinearLayoutPrivate(Qt::Orientation orientation) : orientation(orientation) { }
+
+ void removeGridItem(QGridLayoutItem *gridItem);
+ QLayoutStyleInfo styleInfo() const;
+ void fixIndex(int *index) const;
+ int gridRow(int index) const;
+ int gridColumn(int index) const;
+
+ Qt::Orientation orientation;
+ QGridLayoutEngine engine;
+};
+
+void QGraphicsLinearLayoutPrivate::removeGridItem(QGridLayoutItem *gridItem)
+{
+ int index = gridItem->firstRow(orientation);
+ engine.removeItem(gridItem);
+ engine.removeRow(index, orientation);
+}
+
+void QGraphicsLinearLayoutPrivate::fixIndex(int *index) const
+{
+ int count = engine.rowCount(orientation);
+ if (uint(*index) > uint(count))
+ *index = count;
+}
+
+int QGraphicsLinearLayoutPrivate::gridRow(int index) const
+{
+ if (orientation == Qt::Horizontal)
+ return 0;
+ return int(qMin(uint(index), uint(engine.rowCount())));
+}
+
+int QGraphicsLinearLayoutPrivate::gridColumn(int index) const
+{
+ if (orientation == Qt::Vertical)
+ return 0;
+ return int(qMin(uint(index), uint(engine.columnCount())));
+}
+
+QLayoutStyleInfo QGraphicsLinearLayoutPrivate::styleInfo() const
+{
+ static QWidget *wid = 0;
+ if (!wid)
+ wid = new QWidget;
+ QGraphicsItem *item = parentItem();
+ QStyle *style = (item && item->isWidget()) ? static_cast<QGraphicsWidget*>(item)->style() : qApp->style();
+ return QLayoutStyleInfo(style, wid);
+}
+
+/*!
+ Constructs a QGraphicsLinearLayout instance. You can pass the
+ \a orientation for the layout, either horizontal or vertical, and
+ \a parent is passed to QGraphicsLayout's constructor.
+*/
+QGraphicsLinearLayout::QGraphicsLinearLayout(Qt::Orientation orientation, QGraphicsLayoutItem *parent)
+ : QGraphicsLayout(*new QGraphicsLinearLayoutPrivate(orientation), parent)
+{
+}
+
+/*!
+ Constructs a QGraphicsLinearLayout instance using Qt::Horizontal
+ orientation. \a parent is passed to QGraphicsLayout's constructor.
+*/
+QGraphicsLinearLayout::QGraphicsLinearLayout(QGraphicsLayoutItem *parent)
+ : QGraphicsLayout(*new QGraphicsLinearLayoutPrivate(Qt::Horizontal), parent)
+{
+}
+
+/*!
+ Destroys the QGraphicsLinearLayout object.
+*/
+QGraphicsLinearLayout::~QGraphicsLinearLayout()
+{
+ 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;
+ }
+ }
+}
+
+/*!
+ Change the layout orientation to \a orientation. Changing the layout
+ orientation will automatically invalidate the layout.
+
+ \sa orientation()
+*/
+void QGraphicsLinearLayout::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QGraphicsLinearLayout);
+ if (orientation != d->orientation) {
+ d->engine.transpose();
+ d->orientation = orientation;
+ invalidate();
+ }
+}
+
+/*!
+ Returns the layout orientation.
+ \sa setOrientation()
+ */
+Qt::Orientation QGraphicsLinearLayout::orientation() const
+{
+ Q_D(const QGraphicsLinearLayout);
+ return d->orientation;
+}
+
+/*!
+ \fn void QGraphicsLinearLayout::addItem(QGraphicsLayoutItem *item)
+
+ This convenience function is equivalent to calling
+ insertItem(-1, \a item).
+*/
+
+/*!
+ \fn void QGraphicsLinearLayout::addStretch(int stretch)
+
+ This convenience function is equivalent to calling
+ insertStretch(-1, \a stretch).
+*/
+
+/*!
+ Inserts \a item into the layout at \a index, or before any item that is
+ currently at \a index.
+
+ \sa addItem(), itemAt(), insertStretch(), setItemSpacing()
+*/
+void QGraphicsLinearLayout::insertItem(int index, QGraphicsLayoutItem *item)
+{
+ Q_D(QGraphicsLinearLayout);
+ if (!item) {
+ qWarning("QGraphicsLinearLayout::insertItem: cannot insert null item");
+ return;
+ }
+ d->addChildLayoutItem(item);
+
+ Q_ASSERT(item);
+ d->fixIndex(&index);
+ d->engine.insertRow(index, d->orientation);
+ new QGridLayoutItem(&d->engine, item, d->gridRow(index), d->gridColumn(index));
+ invalidate();
+}
+
+/*!
+ Inserts a stretch of \a stretch at \a index, or before any item that is
+ currently at \a index.
+
+ \sa addStretch(), setStretchFactor(), setItemSpacing(), insertItem()
+*/
+void QGraphicsLinearLayout::insertStretch(int index, int stretch)
+{
+ Q_D(QGraphicsLinearLayout);
+ d->fixIndex(&index);
+ d->engine.insertRow(index, d->orientation);
+ d->engine.setRowStretchFactor(index, stretch, d->orientation);
+ invalidate();
+}
+
+/*!
+ Removes \a item from the layout without destroying it. Ownership of
+ \a item is transferred to the caller.
+
+ \sa removeAt(), insertItem()
+*/
+void QGraphicsLinearLayout::removeItem(QGraphicsLayoutItem *item)
+{
+ Q_D(QGraphicsLinearLayout);
+ if (QGridLayoutItem *gridItem = d->engine.findLayoutItem(item)) {
+ item->setParentLayoutItem(0);
+ d->removeGridItem(gridItem);
+ delete gridItem;
+ invalidate();
+ }
+}
+
+/*!
+ Removes the item at \a index without destroying it. Ownership of the item
+ is transferred to the caller.
+
+ \sa removeItem(), insertItem()
+*/
+void QGraphicsLinearLayout::removeAt(int index)
+{
+ Q_D(QGraphicsLinearLayout);
+ if (QGridLayoutItem *gridItem = d->engine.itemAt(d->gridRow(index), d->gridColumn(index))) {
+ if (QGraphicsLayoutItem *layoutItem = gridItem->layoutItem())
+ layoutItem->setParentLayoutItem(0);
+ d->removeGridItem(gridItem);
+ delete gridItem;
+ invalidate();
+ }
+}
+
+/*!
+ Sets the layout's spacing to \a spacing. Spacing refers to the
+ vertical and horizontal distances between items.
+
+ \sa setItemSpacing(), setStretchFactor(), QGraphicsGridLayout::setSpacing()
+*/
+void QGraphicsLinearLayout::setSpacing(qreal spacing)
+{
+ Q_D(QGraphicsLinearLayout);
+ if (spacing < 0) {
+ qWarning("QGraphicsLinearLayout::setSpacing: invalid spacing %g", spacing);
+ return;
+ }
+ d->engine.setSpacing(spacing, Qt::Horizontal | Qt::Vertical);
+ invalidate();
+}
+
+/*!
+ Returns the layout's spacing. Spacing refers to the
+ vertical and horizontal distances between items.
+
+ \sa setSpacing()
+ */
+qreal QGraphicsLinearLayout::spacing() const
+{
+ Q_D(const QGraphicsLinearLayout);
+ return d->engine.spacing(d->styleInfo(), d->orientation);
+}
+
+/*!
+ Sets the spacing after item at \a index to \a spacing.
+*/
+void QGraphicsLinearLayout::setItemSpacing(int index, qreal spacing)
+{
+ Q_D(QGraphicsLinearLayout);
+ d->engine.setRowSpacing(index, spacing, d->orientation);
+ invalidate();
+}
+/*!
+ Returns the spacing after item at \a index.
+*/
+qreal QGraphicsLinearLayout::itemSpacing(int index) const
+{
+ Q_D(const QGraphicsLinearLayout);
+ return d->engine.rowSpacing(index, d->orientation);
+}
+
+/*!
+ Sets the stretch factor for \a item to \a stretch. If an item's stretch
+ factor changes, this function will invalidate the layout.
+
+ Setting \a stretch to 0 removes the stretch factor from the item, and is
+ effectively equivalent to setting \a stretch to 1.
+
+ \sa stretchFactor()
+*/
+void QGraphicsLinearLayout::setStretchFactor(QGraphicsLayoutItem *item, int stretch)
+{
+ Q_D(QGraphicsLinearLayout);
+ if (!item) {
+ qWarning("QGraphicsLinearLayout::setStretchFactor: cannot assign"
+ " a stretch factor to a null item");
+ return;
+ }
+ if (stretchFactor(item) == stretch)
+ return;
+ d->engine.setStretchFactor(item, stretch, d->orientation);
+ invalidate();
+}
+
+/*!
+ Returns the stretch factor for \a item. The default stretch factor is 0,
+ meaning that the item has no assigned stretch factor.
+
+ \sa setStretchFactor()
+*/
+int QGraphicsLinearLayout::stretchFactor(QGraphicsLayoutItem *item) const
+{
+ Q_D(const QGraphicsLinearLayout);
+ if (!item) {
+ qWarning("QGraphicsLinearLayout::setStretchFactor: cannot return"
+ " a stretch factor for a null item");
+ return 0;
+ }
+ return d->engine.stretchFactor(item, d->orientation);
+}
+
+/*!
+ Sets the alignment of \a item to \a alignment. If \a item's alignment
+ changes, the layout is automatically invalidated.
+
+ \sa alignment(), invalidate()
+*/
+void QGraphicsLinearLayout::setAlignment(QGraphicsLayoutItem *item, Qt::Alignment alignment)
+{
+ Q_D(QGraphicsLinearLayout);
+ if (this->alignment(item) == alignment)
+ return;
+ d->engine.setAlignment(item, alignment);
+ invalidate();
+}
+
+/*!
+ Returns the alignment for \a item. The default alignment is
+ Qt::AlignCenter.
+
+ The alignment decides how the item is positioned within its assigned space
+ in the case where there's more space available in the layout than the
+ widgets can occupy.
+
+ \sa setAlignment()
+*/
+Qt::Alignment QGraphicsLinearLayout::alignment(QGraphicsLayoutItem *item) const
+{
+ Q_D(const QGraphicsLinearLayout);
+ return d->engine.alignment(item);
+}
+
+#if 0 // ###
+QSizePolicy::ControlTypes QGraphicsLinearLayout::controlTypes(LayoutSide side) const
+{
+ return d->engine.controlTypes(side);
+}
+#endif
+
+/*!
+ \reimp
+*/
+int QGraphicsLinearLayout::count() const
+{
+ Q_D(const QGraphicsLinearLayout);
+ return d->engine.rowCount(d->orientation);
+}
+
+/*!
+ \reimp
+*/
+QGraphicsLayoutItem *QGraphicsLinearLayout::itemAt(int index) const
+{
+ Q_D(const QGraphicsLinearLayout);
+ QGraphicsLayoutItem *item = 0;
+ if (QGridLayoutItem *gridItem = d->engine.itemAt(d->gridRow(index), d->gridColumn(index)))
+ item = gridItem->layoutItem();
+ return item;
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsLinearLayout::setGeometry(const QRectF &rect)
+{
+ Q_D(QGraphicsLinearLayout);
+ 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);
+#ifdef QT_DEBUG
+ if (qt_graphicsLayoutDebug()) {
+ static int counter = 0;
+ qDebug() << counter++ << "QGraphicsLinearLayout::setGeometry - " << rect;
+ dump(1);
+ }
+#endif
+ d->engine.setGeometries(d->styleInfo(), effectiveRect);
+#ifdef QT_DEBUG
+ if (qt_graphicsLayoutDebug()) {
+ qDebug() << "post dump";
+ dump(1);
+ }
+#endif
+}
+
+/*!
+ \reimp
+*/
+QSizeF QGraphicsLinearLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ Q_D(const QGraphicsLinearLayout);
+ qreal left, top, right, bottom;
+ getContentsMargins(&left, &top, &right, &bottom);
+ return d->engine.sizeHint(d->styleInfo(), which , constraint) + QSizeF(left + right, top + bottom);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsLinearLayout::invalidate()
+{
+ Q_D(QGraphicsLinearLayout);
+ d->engine.invalidate();
+ QGraphicsLayout::invalidate();
+}
+
+#ifdef QT_DEBUG
+void QGraphicsLinearLayout::dump(int indent) const
+{
+ if (qt_graphicsLayoutDebug()) {
+ Q_D(const QGraphicsLinearLayout);
+ qDebug("%*s%s layout", indent, "",
+ d->orientation == Qt::Horizontal ? "Horizontal" : "Vertical");
+ d->engine.dump(indent + 1);
+ }
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicslinearlayout.h b/src/gui/graphicsview/qgraphicslinearlayout.h
new file mode 100644
index 0000000..05ad325
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicslinearlayout.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSLINEARLAYOUT_H
+#define QGRAPHICSLINEARLAYOUT_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 QGraphicsLinearLayoutPrivate;
+
+class Q_GUI_EXPORT QGraphicsLinearLayout : public QGraphicsLayout
+{
+public:
+ QGraphicsLinearLayout(QGraphicsLayoutItem *parent = 0);
+ QGraphicsLinearLayout(Qt::Orientation orientation, QGraphicsLayoutItem *parent = 0);
+ virtual ~QGraphicsLinearLayout();
+
+ void setOrientation(Qt::Orientation orientation);
+ Qt::Orientation orientation() const;
+
+ inline void addItem(QGraphicsLayoutItem *item) { insertItem(-1, item); }
+ inline void addStretch(int stretch = 1) { insertStretch(-1, stretch); }
+
+ void insertItem(int index, QGraphicsLayoutItem *item);
+ void insertStretch(int index, int stretch = 1);
+
+ void removeItem(QGraphicsLayoutItem *item);
+ void removeAt(int index);
+
+ void setSpacing(qreal spacing);
+ qreal spacing() const;
+ void setItemSpacing(int index, qreal spacing);
+ qreal itemSpacing(int index) const;
+
+ void setStretchFactor(QGraphicsLayoutItem *item, int stretch);
+ int stretchFactor(QGraphicsLayoutItem *item) const;
+
+ void setAlignment(QGraphicsLayoutItem *item, Qt::Alignment alignment);
+ Qt::Alignment alignment(QGraphicsLayoutItem *item) const;
+
+ void setGeometry(const QRectF &rect);
+
+ int count() const;
+ QGraphicsLayoutItem *itemAt(int index) const;
+
+ void invalidate();
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+#if 0 // ###
+ Q5SizePolicy::ControlTypes controlTypes(LayoutSide side) const;
+#endif
+
+#ifdef QT_DEBUG
+ void dump(int indent = 0) const;
+#endif
+
+protected:
+#if 0
+ QSize contentsSizeHint(Qt::SizeHint which, const QSize &constraint = QSize()) const;
+#endif
+
+private:
+ Q_DISABLE_COPY(QGraphicsLinearLayout)
+ Q_DECLARE_PRIVATE(QGraphicsLinearLayout)
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
+
diff --git a/src/gui/graphicsview/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp
new file mode 100644
index 0000000..1bd2e21
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsproxywidget.cpp
@@ -0,0 +1,1496 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include "qgraphicslayout.h"
+#include "qgraphicsproxywidget.h"
+#include "private/qgraphicsproxywidget_p.h"
+#include "private/qwidget_p.h"
+#include "private/qapplication_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qgraphicsscene.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qlayout.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qstyleoption.h>
+#include <QtGui/qgraphicsview.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define GRAPHICSPROXYWIDGET_DEBUG
+
+/*!
+ \class QGraphicsProxyWidget
+ \brief The QGraphicsProxyWidget class provides a proxy layer for embedding
+ a QWidget in a QGraphicsScene.
+ \since 4.4
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ QGraphicsProxyWidget embeds QWidget-based widgets, for example, a
+ QPushButton, QFontComboBox, or even QFileDialog, into
+ QGraphicsScene. It forwards events between the two objects and
+ translates between QWidget's integer-based geometry and
+ QGraphicsWidget's qreal-based geometry. QGraphicsProxyWidget
+ supports all core features of QWidget, including tab focus,
+ keyboard input, Drag & Drop, and popups. You can also embed
+ complex widgets, e.g., widgets with subwidgets.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 0
+
+ QGraphicsProxyWidget takes care of automatically embedding popup children
+ of embedded widgets through creating a child proxy for each popup. This
+ means that when an embedded QComboBox shows its popup list, a new
+ QGraphicsProxyWidget is created automatically, embedding the popup, and
+ positioning it correctly.
+
+ \section1 Embedding a Widget with QGraphicsProxyWidget
+
+ There are two ways to embed a widget using QGraphicsProxyWidget. The most
+ common way is to pass a widget pointer to QGraphicsScene::addWidget()
+ together with any relevant \l Qt::WindowFlags. This function returns a
+ pointer to a QGraphicsProxyWidget. You can then choose to reparent or
+ position either the proxy, or the embedded widget itself.
+
+ For example, in the code snippet below, we embed a group box into the proxy:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 1
+
+ The image below is the output obtained with its contents margin and
+ contents rect labeled.
+
+ \image qgraphicsproxywidget-embed.png
+
+ Alternatively, you can start by creating a new QGraphicsProxyWidget item,
+ and then call setWidget() to embed a QWidget later. The widget() function
+ returns a pointer to the embedded widget. QGraphicsProxyWidget shares
+ ownership with QWidget, so if either of the two widgets are destroyed, the
+ other widget will be automatically destroyed as well.
+
+ \section1 Synchronizing Widget States
+
+ QGraphicsProxyWidget keeps its state in sync with the embedded widget. For
+ example, if the proxy is hidden or disabled, the embedded widget will be
+ hidden or disabled as well, and vice versa. When the widget is embedded by
+ calling addWidget(), QGraphicsProxyWidget copies the state from the widget
+ into the proxy, and after that, the two will stay synchronized where
+ possible. By default, when you embed a widget into a proxy, both the widget
+ and the proxy will be visible because a QGraphicsWidget is visible when
+ created (you do not have to call show()). If you explicitly hide the
+ embedded widget, the proxy will also become invisible.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 2
+
+ QGraphicsProxyWidget maintains symmetry for the following states:
+
+ \table
+ \header \o QWidget state \o QGraphicsProxyWidget state \o Notes
+ \row \o QWidget::enabled
+ \o QGraphicsProxyWidget::enabled
+ \o
+ \row \o QWidget::visible
+ \o QGraphicsProxyWidget::visible
+ \o The explicit state is also symmetric.
+ \row \o QWidget::geometry
+ \o QGraphicsProxyWidget::geometry
+ \o Geometry is only guaranteed to be symmetric while
+ the embedded widget is visible.
+ \row \o QWidget::layoutDirection
+ \o QGraphicsProxyWidget::layoutDirection
+ \o
+ \row \o QWidget::style
+ \o QGraphicsProxyWidget::style
+ \o
+ \row \o QWidget::palette
+ \o QGraphicsProxyWidget::palette
+ \o
+ \row \o QWidget::font
+ \o QGraphicsProxyWidget::font
+ \o
+ \row \o QWidget::cursor
+ \o QGraphicsProxyWidget::cursor
+ \o The embedded widget overrides the proxy widget
+ cursor. The proxy cursor changes depending on
+ which embedded subwidget is currently under the
+ mouse.
+ \row \o QWidget::sizeHint()
+ \o QGraphicsProxyWidget::sizeHint()
+ \o All size hint functionality from the embedded
+ widget is forwarded by the proxy.
+ \row \o QWidget::getContentsMargins()
+ \o QGraphicsProxyWidget::getContentsMargins()
+ \o Updated once by setWidget().
+ \row \o QWidget::windowTitle
+ \o QGraphicsProxyWidget::windowTitle
+ \o Updated once by setWidget().
+ \endtable
+
+ \note QGraphicsScene keeps the embedded widget in a special state that
+ prevents it from disturbing other widgets (both embedded and not embedded)
+ while the widget is embedded. In this state, the widget may differ slightly
+ in behavior from when it is not embedded.
+
+ \sa QGraphicsScene::addWidget(), QGraphicsWidget
+*/
+
+extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
+
+/*!
+ \internal
+*/
+void QGraphicsProxyWidgetPrivate::init()
+{
+ Q_Q(QGraphicsProxyWidget);
+ q->setFocusPolicy(Qt::WheelFocus);
+ q->setAcceptDrops(true);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneHoverEvent *event)
+{
+ QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
+ mouseEvent.setPos(event->pos());
+ mouseEvent.setScreenPos(event->screenPos());
+ mouseEvent.setButton(Qt::NoButton);
+ mouseEvent.setButtons(0);
+ mouseEvent.setModifiers(event->modifiers());
+ sendWidgetMouseEvent(&mouseEvent);
+ event->setAccepted(mouseEvent.isAccepted());
+}
+
+/*!
+ \internal
+*/
+void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (!event || !widget || !widget->isVisible())
+ return;
+ Q_Q(QGraphicsProxyWidget);
+
+ // Find widget position and receiver.
+ QPointF pos = event->pos();
+ QPointer<QWidget> alienWidget = widget->childAt(pos.toPoint());
+ QPointer<QWidget> receiver = alienWidget ? alienWidget : widget;
+
+ if (QWidgetPrivate::nearestGraphicsProxyWidget(receiver) != q)
+ return; //another proxywidget will handle the events
+
+ // Translate QGraphicsSceneMouse events to QMouseEvents.
+ QEvent::Type type = QEvent::None;
+ switch (event->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ type = QEvent::MouseButtonPress;
+ if (!embeddedMouseGrabber)
+ embeddedMouseGrabber = receiver;
+ else
+ receiver = embeddedMouseGrabber;
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ type = QEvent::MouseButtonRelease;
+ if (embeddedMouseGrabber)
+ receiver = embeddedMouseGrabber;
+ break;
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ type = QEvent::MouseButtonDblClick;
+ if (!embeddedMouseGrabber)
+ embeddedMouseGrabber = receiver;
+ else
+ receiver = embeddedMouseGrabber;
+ break;
+ case QEvent::GraphicsSceneMouseMove:
+ type = QEvent::MouseMove;
+ if (embeddedMouseGrabber)
+ receiver = embeddedMouseGrabber;
+ break;
+ default:
+ Q_ASSERT_X(false, "QGraphicsProxyWidget", "internal error");
+ break;
+ }
+
+ if (!lastWidgetUnderMouse) {
+ QApplicationPrivate::dispatchEnterLeave(embeddedMouseGrabber ? embeddedMouseGrabber : widget, 0);
+ lastWidgetUnderMouse = widget;
+ }
+
+ // Map event position from us to the receiver
+ pos = mapToReceiver(pos, receiver);
+
+ // Send mouse event.
+ QMouseEvent *mouseEvent = QMouseEvent::createExtendedMouseEvent(type, pos,
+ receiver->mapToGlobal(pos.toPoint()), event->button(),
+ event->buttons(), event->modifiers());
+
+ QWidget *embeddedMouseGrabberPtr = (QWidget *)embeddedMouseGrabber;
+ QApplicationPrivate::sendMouseEvent(receiver, mouseEvent, alienWidget, widget,
+ &embeddedMouseGrabberPtr, lastWidgetUnderMouse);
+ embeddedMouseGrabber = embeddedMouseGrabberPtr;
+
+ // Handle enter/leave events when last button is released from mouse
+ // grabber child widget.
+ if (embeddedMouseGrabber && type == QEvent::MouseButtonRelease && !event->buttons()) {
+ Q_Q(QGraphicsProxyWidget);
+ if (q->rect().contains(event->pos()) && q->acceptsHoverEvents())
+ lastWidgetUnderMouse = alienWidget ? alienWidget : widget;
+ else // released on the frame our outside the item, or doesn't accept hover events.
+ lastWidgetUnderMouse = 0;
+
+ QApplicationPrivate::dispatchEnterLeave(lastWidgetUnderMouse, embeddedMouseGrabber);
+ embeddedMouseGrabber = 0;
+
+#ifndef QT_NO_CURSOR
+ // ### Restore the cursor, don't override it.
+ if (!lastWidgetUnderMouse)
+ q->unsetCursor();
+#endif
+ }
+
+ event->setAccepted(mouseEvent->isAccepted());
+ delete mouseEvent;
+}
+
+void QGraphicsProxyWidgetPrivate::sendWidgetKeyEvent(QKeyEvent *event)
+{
+ Q_Q(QGraphicsProxyWidget);
+ if (!event || !widget || !widget->isVisible())
+ return;
+
+ QPointer<QWidget> receiver = widget->focusWidget();
+ if (!receiver)
+ receiver = widget;
+ Q_ASSERT(receiver);
+
+ do {
+ bool res = QApplication::sendEvent(receiver, event);
+ if ((res && event->isAccepted()) || (q->isWindow() && receiver == widget))
+ break;
+ receiver = receiver->parentWidget();
+ } while (receiver);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsProxyWidgetPrivate::removeSubFocusHelper(QWidget *widget, Qt::FocusReason reason)
+{
+ QFocusEvent event(QEvent::FocusOut, reason);
+ QPointer<QWidget> widgetGuard = widget;
+ QApplication::sendEvent(widget, &event);
+ if (widgetGuard && event.isAccepted())
+ QApplication::sendEvent(widget->style(), &event);
+}
+
+/*!
+ \internal
+
+ Reimplemented from QGraphicsItemPrivate. ### Qt 5: Move impl to
+ reimplementation QGraphicsProxyWidget::inputMethodQuery().
+*/
+QVariant QGraphicsProxyWidgetPrivate::inputMethodQueryHelper(Qt::InputMethodQuery query) const
+{
+ Q_Q(const QGraphicsProxyWidget);
+ if (!widget || !q->hasFocus())
+ return QVariant();
+
+ QWidget *focusWidget = widget->focusWidget();
+ if (!focusWidget)
+ focusWidget = widget;
+ QVariant v = focusWidget->inputMethodQuery(query);
+ QPointF focusWidgetPos = q->subWidgetRect(focusWidget).topLeft();
+ switch (v.type()) {
+ case QVariant::RectF:
+ v = v.toRectF().translated(focusWidgetPos);
+ break;
+ case QVariant::PointF:
+ v = v.toPointF() + focusWidgetPos;
+ break;
+ case QVariant::Rect:
+ v = v.toRect().translated(focusWidgetPos.toPoint());
+ break;
+ case QVariant::Point:
+ v = v.toPoint() + focusWidgetPos.toPoint();
+ break;
+ default:
+ break;
+ }
+ return v;
+}
+
+/*!
+ \internal
+*/
+QWidget *QGraphicsProxyWidgetPrivate::findFocusChild(QWidget *child, bool next) const
+{
+ if (!widget)
+ return 0;
+
+ // Run around the focus chain until we find a widget that can take tab focus.
+ if (!child) {
+ child = next ? (QWidget *)widget : widget->d_func()->focus_prev;
+ } else {
+ child = next ? child->d_func()->focus_next : child->d_func()->focus_prev;
+ if ((next && child == widget) || (!next && child == widget->d_func()->focus_prev)) {
+ return 0;
+ }
+ }
+
+ QWidget *oldChild = child;
+ do {
+ if (child->isEnabled()
+ && child->isVisibleTo(widget)
+ && (child->focusPolicy() & Qt::TabFocus)) {
+ return child;
+ }
+ child = next ? child->d_func()->focus_next : child->d_func()->focus_prev;
+ } while (child != oldChild && !(next && child == widget) && !(!next && child == widget->d_func()->focus_prev));
+ return 0;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsProxyWidgetPrivate::_q_removeWidgetSlot()
+{
+ Q_Q(QGraphicsProxyWidget);
+ widget = 0;
+ delete q;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsProxyWidgetPrivate::updateWidgetGeometryFromProxy()
+{
+}
+
+/*!
+ \internal
+*/
+void QGraphicsProxyWidgetPrivate::updateProxyGeometryFromWidget()
+{
+ Q_Q(QGraphicsProxyWidget);
+ if (!widget)
+ return;
+
+ QRectF widgetGeometry = widget->geometry();
+ QWidget *parentWidget = widget->parentWidget();
+ if (widget->isWindow()) {
+ QGraphicsProxyWidget *proxyParent = 0;
+ if (parentWidget && (proxyParent = qobject_cast<QGraphicsProxyWidget *>(q->parentWidget()))) {
+ // Nested window proxy (e.g., combobox popup), map widget to the
+ // parent widget's global coordinates, and map that to the parent
+ // proxy's child coordinates.
+ widgetGeometry.moveTo(proxyParent->subWidgetRect(parentWidget).topLeft()
+ + parentWidget->mapFromGlobal(widget->pos()));
+ }
+ }
+
+ // Adjust to size hint if the widget has never been resized.
+ if (!widget->size().isValid())
+ widgetGeometry.setSize(widget->sizeHint());
+
+ // Assign new geometry.
+ posChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
+ sizeChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
+ q->setGeometry(widgetGeometry);
+ posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+}
+
+/*!
+ \internal
+
+ Embeds \a subWin as a subwindow of this proxy widget. \a subWin must be a top-level
+ widget and a descendant of the widget managed by this proxy. A separate subproxy
+ will be created as a child of this proxy widget to manage \a subWin.
+*/
+void QGraphicsProxyWidgetPrivate::embedSubWindow(QWidget *subWin)
+{
+ QWExtra *extra;
+ if (!((extra = subWin->d_func()->extra) && extra->proxyWidget)) {
+ QGraphicsProxyWidget *subProxy = new QGraphicsProxyWidget(q_func());
+ subProxy->d_func()->setWidget_helper(subWin, false);
+ }
+}
+
+/*!
+ \internal
+
+ Removes ("unembeds") \a subWin and deletes the proxy holder item. This can
+ happen when QWidget::setParent() reparents the embedded window out of
+ "embedded space".
+*/
+void QGraphicsProxyWidgetPrivate::unembedSubWindow(QWidget *subWin)
+{
+ foreach (QGraphicsItem *child, children) {
+ if (child->isWidget()) {
+ if (QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(child))) {
+ if (proxy->widget() == subWin) {
+ proxy->setWidget(0);
+ scene->removeItem(proxy);
+ delete proxy;
+ return;
+ }
+ }
+ }
+ }
+}
+
+bool QGraphicsProxyWidgetPrivate::isProxyWidget() const
+{
+ return true;
+}
+
+/*!
+ \internal
+*/
+QPointF QGraphicsProxyWidgetPrivate::mapToReceiver(const QPointF &pos, const QWidget *receiver) const
+{
+ QPointF p = pos;
+ // Map event position from us to the receiver, preserving its
+ // precision (don't use QWidget::mapFrom here).
+ while (receiver && receiver != widget) {
+ p -= QPointF(receiver->pos());
+ receiver = receiver->parentWidget();
+ }
+ return p;
+}
+
+/*!
+ Constructs a new QGraphicsProxy widget. \a parent and \a wFlags are passed
+ to QGraphicsItem's constructor.
+*/
+QGraphicsProxyWidget::QGraphicsProxyWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags)
+ : QGraphicsWidget(*new QGraphicsProxyWidgetPrivate, parent, 0, wFlags)
+{
+ Q_D(QGraphicsProxyWidget);
+ d->init();
+}
+
+/*!
+ Destroys the proxy widget and any embedded widget.
+*/
+QGraphicsProxyWidget::~QGraphicsProxyWidget()
+{
+ Q_D(QGraphicsProxyWidget);
+ if (d->widget) {
+ QObject::disconnect(d->widget, SIGNAL(destroyed()), this, SLOT(_q_removeWidgetSlot()));
+ delete d->widget;
+ }
+}
+
+/*!
+ Embeds \a widget into this proxy widget. The embedded widget must reside
+ exclusively either inside or outside of Graphics View. You cannot embed a
+ widget as long as it is is visible elsewhere in the UI, at the same time.
+
+ \a widget must be a top-level widget whose parent is 0.
+
+ When the widget is embedded, its state (e.g., visible, enabled, geometry,
+ size hints) is copied into the proxy widget. If the embedded widget is
+ explicitly hidden or disabled, the proxy widget will become explicitly
+ hidden or disabled after embedding is complete. The class documentation
+ has a full overview over the shared state.
+
+ After this function returns, QGraphicsProxyWidget will keep its state
+ synchronized with that of \a widget whenever possible.
+
+ If a widget is already embedded by this proxy when this function is
+ called, that widget will first be automatically unembedded. Passing 0 for
+ the \a widget argument will only unembed the widget, and the ownership of
+ the currently embedded widget will be passed on to the caller.
+ Every child widget that are embedded will also be embedded and their proxy
+ widget destroyed.
+
+ Note that widgets with the Qt::WA_PaintOnScreen widget attribute
+ set and widgets that wrap an external application or controller
+ cannot be embedded. Examples are QGLWidget and QAxWidget.
+
+ \sa widget()
+*/
+void QGraphicsProxyWidget::setWidget(QWidget *widget)
+{
+ Q_D(QGraphicsProxyWidget);
+ d->setWidget_helper(widget, true);
+}
+
+void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool autoShow)
+{
+ Q_Q(QGraphicsProxyWidget);
+ if (newWidget == widget)
+ return;
+ if (widget) {
+ QObject::disconnect(widget, SIGNAL(destroyed()), q, SLOT(_q_removeWidgetSlot()));
+ widget->removeEventFilter(q);
+ widget->setAttribute(Qt::WA_DontShowOnScreen, false);
+ widget->d_func()->extra->proxyWidget = 0;
+ resolveFont(inheritedFontResolveMask);
+ resolvePalette(inheritedPaletteResolveMask);
+ widget->update();
+
+ foreach (QGraphicsItem *child, q->childItems()) {
+ if (child->d_ptr->isProxyWidget()) {
+ QGraphicsProxyWidget *childProxy = static_cast<QGraphicsProxyWidget *>(child);
+ QWidget * parent = childProxy->widget();
+ while (parent->parentWidget() != 0) {
+ if (parent == widget)
+ break;
+ parent = parent->parentWidget();
+ }
+ if (!childProxy->widget() || parent != widget)
+ continue;
+ childProxy->setWidget(0);
+ delete childProxy;
+ }
+ }
+
+ widget = 0;
+#ifndef QT_NO_CURSOR
+ q->unsetCursor();
+#endif
+ q->setAcceptHoverEvents(false);
+ if (!newWidget)
+ q->update();
+ }
+ if (!newWidget)
+ return;
+ if (!newWidget->isWindow()) {
+ QWExtra *extra = newWidget->parentWidget()->d_func()->extra;
+ if (!extra || !extra->proxyWidget) {
+ qWarning("QGraphicsProxyWidget::setWidget: cannot embed widget %p "
+ "which is not a toplevel widget, and is not a child of an embedded widget", newWidget);
+ return;
+ }
+ }
+
+ // Register this proxy within the widget's private.
+ // ### This is a bit backdoorish
+ QWExtra *extra = newWidget->d_func()->extra;
+ if (!extra) {
+ newWidget->d_func()->createExtra();
+ extra = newWidget->d_func()->extra;
+ }
+ QGraphicsProxyWidget **proxyWidget = &extra->proxyWidget;
+ if (*proxyWidget) {
+ if (*proxyWidget != q) {
+ qWarning("QGraphicsProxyWidget::setWidget: cannot embed widget %p"
+ "; already embedded", newWidget);
+ }
+ return;
+ }
+ *proxyWidget = q;
+
+ newWidget->setAttribute(Qt::WA_DontShowOnScreen);
+ newWidget->ensurePolished();
+ // Do not wait for this widget to close before the app closes ###
+ // shouldn't this widget inherit the attribute?
+ newWidget->setAttribute(Qt::WA_QuitOnClose, false);
+ q->setAcceptHoverEvents(true);
+
+ if (newWidget->testAttribute(Qt::WA_NoSystemBackground))
+ q->setAttribute(Qt::WA_NoSystemBackground);
+ if (newWidget->testAttribute(Qt::WA_OpaquePaintEvent))
+ q->setAttribute(Qt::WA_OpaquePaintEvent);
+
+ widget = newWidget;
+
+ // Changes only go from the widget to the proxy.
+ enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
+ visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
+ posChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
+ sizeChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
+
+ if ((autoShow && !newWidget->testAttribute(Qt::WA_WState_ExplicitShowHide)) || !newWidget->testAttribute(Qt::WA_WState_Hidden)) {
+ newWidget->show();
+ }
+
+ // Copy the state from the widget onto the proxy.
+#ifndef QT_NO_CURSOR
+ if (newWidget->testAttribute(Qt::WA_SetCursor))
+ q->setCursor(widget->cursor());
+#endif
+ Qt::WFlags flags = newWidget->windowFlags();
+ if (newWidget->windowType() == Qt::Window)
+ flags &= ~Qt::Window;
+ q->setWindowFlags(flags);
+ q->setEnabled(newWidget->isEnabled());
+ q->setVisible(newWidget->isVisible());
+ q->setLayoutDirection(newWidget->layoutDirection());
+ if (newWidget->testAttribute(Qt::WA_SetStyle))
+ q->setStyle(widget->style());
+
+ resolveFont(inheritedFontResolveMask);
+ resolvePalette(inheritedPaletteResolveMask);
+
+ if (!newWidget->testAttribute(Qt::WA_Resized))
+ newWidget->adjustSize();
+
+ int left, top, right, bottom;
+ newWidget->getContentsMargins(&left, &top, &right, &bottom);
+ q->setContentsMargins(left, top, right, bottom);
+ q->setWindowTitle(newWidget->windowTitle());
+
+ // size policies and constraints..
+ q->setSizePolicy(newWidget->sizePolicy());
+ QSize sz = newWidget->minimumSize();
+ q->setMinimumSize(sz.isNull() ? QSizeF() : QSizeF(sz));
+ sz = newWidget->maximumSize();
+ q->setMaximumSize(sz.isNull() ? QSizeF() : QSizeF(sz));
+
+ updateProxyGeometryFromWidget();
+
+ // Hook up the event filter to keep the state up to date.
+ newWidget->installEventFilter(q);
+ QObject::connect(newWidget, SIGNAL(destroyed()), q, SLOT(_q_removeWidgetSlot()));
+
+ // Changes no longer go only from the widget to the proxy.
+ enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+}
+
+/*!
+ Returns a pointer to the embedded widget.
+
+ \sa setWidget()
+*/
+QWidget *QGraphicsProxyWidget::widget() const
+{
+ Q_D(const QGraphicsProxyWidget);
+ return d->widget;
+}
+
+/*!
+ Returns the rectangle for \a widget, which must be a descendant of
+ widget(), or widget() itself, in this proxy item's local coordinates.
+
+ If no widget is embedded, \a widget is 0, or \a widget is not a
+ descendant of the embedded widget, this function returns an empty QRectF.
+
+ \sa widget()
+*/
+QRectF QGraphicsProxyWidget::subWidgetRect(const QWidget *widget) const
+{
+ Q_D(const QGraphicsProxyWidget);
+ if (!widget || !d->widget)
+ return QRectF();
+ if (d->widget == widget || d->widget->isAncestorOf(widget))
+ return QRectF(widget->mapTo(d->widget, QPoint(0, 0)), widget->size());
+ return QRectF();
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::setGeometry(const QRectF &rect)
+{
+ Q_D(QGraphicsProxyWidget);
+ bool proxyResizesWidget = !d->posChangeMode && !d->sizeChangeMode;
+ if (proxyResizesWidget) {
+ d->posChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
+ d->sizeChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
+ }
+ QGraphicsWidget::setGeometry(rect);
+ if (proxyResizesWidget) {
+ d->posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ d->sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ }
+}
+
+/*!
+ \reimp
+*/
+QVariant QGraphicsProxyWidget::itemChange(GraphicsItemChange change,
+ const QVariant &value)
+{
+ Q_D(QGraphicsProxyWidget);
+
+ switch (change) {
+ case ItemPositionChange:
+ // The item's position is either changed directly on the proxy, in
+ // which case the position change should propagate to the widget,
+ // otherwise it happens as a side effect when filtering QEvent::Move.
+ if (!d->posChangeMode)
+ d->posChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
+ break;
+ case ItemPositionHasChanged:
+ // Move the internal widget if we're in widget-to-proxy
+ // mode. Otherwise the widget has already moved.
+ if (d->widget && d->posChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
+ d->widget->move(value.toPoint());
+ if (d->posChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
+ d->posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ break;
+ case ItemVisibleChange:
+ if (!d->visibleChangeMode)
+ d->visibleChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
+ break;
+ case ItemVisibleHasChanged:
+ if (d->widget && d->visibleChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
+ d->widget->setVisible(isVisible());
+ if (d->visibleChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
+ d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ break;
+ case ItemEnabledChange:
+ if (!d->enabledChangeMode)
+ d->enabledChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
+ break;
+ case ItemEnabledHasChanged:
+ if (d->widget && d->enabledChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
+ d->widget->setEnabled(isEnabled());
+ if (d->enabledChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
+ d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ break;
+ default:
+ break;
+ }
+ return QGraphicsWidget::itemChange(change, value);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsProxyWidget::event(QEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+ if (!d->widget)
+ return QGraphicsWidget::event(event);
+
+ switch (event->type()) {
+ case QEvent::StyleChange:
+ // Propagate style changes to the embedded widget.
+ if (!d->styleChangeMode) {
+ d->styleChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
+ d->widget->setStyle(style());
+ d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ }
+ break;
+ case QEvent::FontChange: {
+ // Propagate to widget.
+ QWidgetPrivate *wd = d->widget->d_func();
+ int mask = d->font.resolve() | d->inheritedFontResolveMask;
+ wd->inheritedFontResolveMask = mask;
+ wd->resolveFont();
+ break;
+ }
+ case QEvent::PaletteChange: {
+ // Propagate to widget.
+ QWidgetPrivate *wd = d->widget->d_func();
+ int mask = d->palette.resolve() | d->inheritedPaletteResolveMask;
+ wd->inheritedPaletteResolveMask = mask;
+ wd->resolvePalette();
+ break;
+ }
+ case QEvent::InputMethod: {
+ // Forward input method events if the focus widget enables
+ // input methods.
+ // ### Qt 4.5: this code must also go into a reimplementation
+ // of inputMethodEvent().
+ QWidget *focusWidget = d->widget->focusWidget();
+ if (focusWidget->testAttribute(Qt::WA_InputMethodEnabled))
+ QApplication::sendEvent(focusWidget, event);
+ break;
+ }
+ case QEvent::ShortcutOverride: {
+ QWidget *focusWidget = d->widget->focusWidget();
+ while (focusWidget) {
+ QApplication::sendEvent(focusWidget, event);
+ if (event->isAccepted())
+ return true;
+ focusWidget = focusWidget->parentWidget();
+ }
+ return false;
+ }
+ 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?
+ QWidget *focusWidget = d->widget->focusWidget();
+ while (focusWidget) {
+ bool res = QApplication::sendEvent(focusWidget, event);
+ if ((res && event->isAccepted()) || (isWindow() && focusWidget == d->widget)) {
+ event->accept();
+ break;
+ }
+ focusWidget = focusWidget->parentWidget();
+ }
+ return true;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return QGraphicsWidget::event(event);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsProxyWidget::eventFilter(QObject *object, QEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+
+ if (object == d->widget) {
+ switch (event->type()) {
+ case QEvent::LayoutRequest:
+ updateGeometry();
+ break;
+ case QEvent::Resize:
+ // If the widget resizes itself, we resize the proxy too.
+ // Prevent feed-back by checking the geometry change mode.
+ if (!d->sizeChangeMode)
+ d->updateProxyGeometryFromWidget();
+ break;
+ case QEvent::Move:
+ // If the widget moves itself, we move the proxy too. Prevent
+ // feed-back by checking the geometry change mode.
+ if (!d->posChangeMode)
+ d->updateProxyGeometryFromWidget();
+ break;
+ case QEvent::Hide:
+ case QEvent::Show:
+ // If the widget toggles its visible state, the proxy will follow.
+ if (!d->visibleChangeMode) {
+ d->visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
+ setVisible(event->type() == QEvent::Show);
+ d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ }
+ break;
+ case QEvent::EnabledChange:
+ // If the widget toggles its enabled state, the proxy will follow.
+ if (!d->enabledChangeMode) {
+ d->enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
+ setEnabled(d->widget->isEnabled());
+ d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ }
+ break;
+ case QEvent::StyleChange:
+ // Propagate style changes to the proxy.
+ if (!d->styleChangeMode) {
+ d->styleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
+ setStyle(d->widget->style());
+ d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return QGraphicsWidget::eventFilter(object, event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::showEvent(QShowEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::hideEvent(QHideEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+#ifndef QT_NO_CONTEXTMENU
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+ if (!event || !d->widget || !d->widget->isVisible())
+ return;
+
+ // Find widget position and receiver.
+ QPointF pos = event->pos();
+ QPointer<QWidget> alienWidget = d->widget->childAt(pos.toPoint());
+ QPointer<QWidget> receiver = alienWidget ? alienWidget : d->widget;
+
+ // Map event position from us to the receiver
+ pos = d->mapToReceiver(pos, receiver);
+
+ // Send mouse event. ### Doesn't propagate the event.
+ QContextMenuEvent contextMenuEvent(QContextMenuEvent::Reason(event->reason()),
+ pos.toPoint(), receiver->mapToGlobal(pos.toPoint()), event->modifiers());
+ QApplication::sendEvent(receiver, &contextMenuEvent);
+
+ event->setAccepted(contextMenuEvent.isAccepted());
+}
+#endif // QT_NO_CONTEXTMENU
+
+#ifndef QT_NO_DRAGANDDROP
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
+{
+#ifdef QT_NO_DRAGANDDROP
+ Q_UNUSED(event);
+#else
+ Q_D(QGraphicsProxyWidget);
+ if (!d->widget)
+ return;
+
+ QDragEnterEvent proxyDragEnter(event->pos().toPoint(), event->dropAction(), event->mimeData(), event->buttons(), event->modifiers());
+ proxyDragEnter.setAccepted(event->isAccepted());
+ QApplication::sendEvent(d->widget, &proxyDragEnter);
+ event->setAccepted(proxyDragEnter.isAccepted());
+ if (proxyDragEnter.isAccepted()) // we discard answerRect
+ event->setDropAction(proxyDragEnter.dropAction());
+#endif
+}
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
+{
+ Q_UNUSED(event);
+#ifndef QT_NO_DRAGANDDROP
+ Q_D(QGraphicsProxyWidget);
+ if (!d->widget || !d->dragDropWidget)
+ return;
+ QDragLeaveEvent proxyDragLeave;
+ QApplication::sendEvent(d->dragDropWidget, &proxyDragLeave);
+ d->dragDropWidget = 0;
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
+{
+#ifdef QT_NO_DRAGANDDROP
+ Q_UNUSED(event);
+#else
+ Q_D(QGraphicsProxyWidget);
+ if (!d->widget)
+ return;
+ QPointF p = event->pos();
+ event->ignore();
+ QPointer<QWidget> subWidget = d->widget->childAt(p.toPoint());
+ QPointer<QWidget> receiver = subWidget ? subWidget : d->widget;
+ bool eventDelivered = false;
+ for (; receiver; receiver = receiver->parentWidget()) {
+ if (!receiver->isEnabled() || !receiver->acceptDrops())
+ continue;
+ // Map event position from us to the receiver
+ QPoint receiverPos = d->mapToReceiver(p, receiver).toPoint();
+ if (receiver != d->dragDropWidget) {
+ // Try to enter before we leave
+ QDragEnterEvent dragEnter(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
+ dragEnter.setDropAction(event->proposedAction());
+ QApplication::sendEvent(receiver, &dragEnter);
+ event->setAccepted(dragEnter.isAccepted());
+ event->setDropAction(dragEnter.dropAction());
+ if (!event->isAccepted()) {
+ // propagate to the parent widget
+ continue;
+ }
+
+ d->lastDropAction = event->dropAction();
+
+ if (d->dragDropWidget) {
+ QDragLeaveEvent dragLeave;
+ QApplication::sendEvent(d->dragDropWidget, &dragLeave);
+ }
+ d->dragDropWidget = receiver;
+ }
+
+ QDragMoveEvent dragMove(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
+ event->setDropAction(d->lastDropAction);
+ QApplication::sendEvent(receiver, &dragMove);
+ event->setAccepted(dragMove.isAccepted());
+ event->setDropAction(dragMove.dropAction());
+ if (event->isAccepted())
+ d->lastDropAction = event->dropAction();
+ eventDelivered = true;
+ break;
+ }
+
+ if (!eventDelivered) {
+ if (d->dragDropWidget) {
+ // Leave the last drag drop item
+ QDragLeaveEvent dragLeave;
+ QApplication::sendEvent(d->dragDropWidget, &dragLeave);
+ d->dragDropWidget = 0;
+ }
+ // Propagate
+ event->setDropAction(Qt::IgnoreAction);
+ }
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::dropEvent(QGraphicsSceneDragDropEvent *event)
+{
+#ifdef QT_NO_DRAGANDDROP
+ Q_UNUSED(event);
+#else
+ Q_D(QGraphicsProxyWidget);
+ if (d->widget && d->dragDropWidget) {
+ QPoint widgetPos = d->mapToReceiver(event->pos(), d->dragDropWidget).toPoint();
+ QDropEvent dropEvent(widgetPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
+ QApplication::sendEvent(d->dragDropWidget, &dropEvent);
+ event->setAccepted(dropEvent.isAccepted());
+ d->dragDropWidget = 0;
+ }
+#endif
+}
+#endif
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+ Q_D(QGraphicsProxyWidget);
+ // If hoverMove was compressed away, make sure we update properly here.
+ if (d->lastWidgetUnderMouse) {
+ QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
+ d->lastWidgetUnderMouse = 0;
+ }
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+#ifdef GRAPHICSPROXYWIDGET_DEBUG
+ qDebug() << "QGraphicsProxyWidget::hoverMoveEvent";
+#endif
+ // Ignore events on the window frame.
+ if (!d->widget || !rect().contains(event->pos())) {
+ if (d->lastWidgetUnderMouse) {
+ QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
+ d->lastWidgetUnderMouse = 0;
+ }
+ return;
+ }
+
+ d->embeddedMouseGrabber = 0;
+ d->sendWidgetMouseEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::grabMouseEvent(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::ungrabMouseEvent(QEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+ Q_UNUSED(event);
+ d->embeddedMouseGrabber = 0;
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+#ifdef GRAPHICSPROXYWIDGET_DEBUG
+ qDebug() << "QGraphicsProxyWidget::mouseMoveEvent";
+#endif
+ d->sendWidgetMouseEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+#ifdef GRAPHICSPROXYWIDGET_DEBUG
+ qDebug() << "QGraphicsProxyWidget::mousePressEvent";
+#endif
+ d->sendWidgetMouseEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+#ifdef GRAPHICSPROXYWIDGET_DEBUG
+ qDebug() << "QGraphicsProxyWidget::mouseDoubleClickEvent";
+#endif
+ d->sendWidgetMouseEvent(event);
+}
+
+/*!
+ \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QGraphicsProxyWidget::wheelEvent(QGraphicsSceneWheelEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+#ifdef GRAPHICSPROXYWIDGET_DEBUG
+ qDebug() << "QGraphicsProxyWidget::wheelEvent";
+#endif
+ if (!d->widget)
+ return;
+
+ QPointF pos = event->pos();
+ QPointer<QWidget> receiver = d->widget->childAt(pos.toPoint());
+ if (!receiver)
+ receiver = d->widget;
+
+ // Map event position from us to the receiver
+ pos = d->mapToReceiver(pos, receiver);
+
+ // Send mouse event.
+ QWheelEvent wheelEvent(pos.toPoint(), event->screenPos(), event->delta(),
+ event->buttons(), event->modifiers(), event->orientation());
+ QPointer<QWidget> focusWidget = d->widget->focusWidget();
+ extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
+ qt_sendSpontaneousEvent(receiver, &wheelEvent);
+ event->setAccepted(wheelEvent.isAccepted());
+
+ // ### Remove, this should be done by proper focusIn/focusOut events.
+ if (focusWidget && !focusWidget->hasFocus()) {
+ focusWidget->update();
+ focusWidget = d->widget->focusWidget();
+ if (focusWidget && focusWidget->hasFocus())
+ focusWidget->update();
+ }
+}
+#endif
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+#ifdef GRAPHICSPROXYWIDGET_DEBUG
+ qDebug() << "QGraphicsProxyWidget::mouseReleaseEvent";
+#endif
+ d->sendWidgetMouseEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+#ifdef GRAPHICSPROXYWIDGET_DEBUG
+ qDebug() << "QGraphicsProxyWidget::keyPressEvent";
+#endif
+ d->sendWidgetKeyEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+#ifdef GRAPHICSPROXYWIDGET_DEBUG
+ qDebug() << "QGraphicsProxyWidget::keyReleaseEvent";
+#endif
+ d->sendWidgetKeyEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::focusInEvent(QFocusEvent *event)
+{
+#ifdef GRAPHICSPROXYWIDGET_DEBUG
+ qDebug() << "QGraphicsProxyWidget::focusInEvent";
+#endif
+ Q_D(QGraphicsProxyWidget);
+
+ if (d->focusFromWidgetToProxy) {
+ // Prevent recursion when the proxy autogains focus through the
+ // embedded widget calling setFocus(). ### Could be done with event
+ // filter on FocusIn instead?
+ return;
+ }
+
+ switch (event->reason()) {
+ case Qt::TabFocusReason: {
+ if (QWidget *focusChild = d->findFocusChild(0, true))
+ focusChild->setFocus(event->reason());
+ break;
+ }
+ case Qt::BacktabFocusReason:
+ if (QWidget *focusChild = d->findFocusChild(0, false))
+ focusChild->setFocus(event->reason());
+ break;
+ default:
+ if (d->widget && d->widget->focusWidget()) {
+ d->widget->focusWidget()->setFocus(event->reason());
+ return;
+ }
+ break;
+ }
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::focusOutEvent(QFocusEvent *event)
+{
+#ifdef GRAPHICSPROXYWIDGET_DEBUG
+ qDebug() << "QGraphicsProxyWidget::focusOutEvent";
+#endif
+ Q_D(QGraphicsProxyWidget);
+ if (d->widget) {
+ // We need to explicitly remove subfocus from the embedded widget's
+ // focus widget.
+ if (QWidget *focusWidget = d->widget->focusWidget())
+ d->removeSubFocusHelper(focusWidget, event->reason());
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsProxyWidget::focusNextPrevChild(bool next)
+{
+ Q_D(QGraphicsProxyWidget);
+ if (!d->widget || !d->scene)
+ return QGraphicsWidget::focusNextPrevChild(next);
+
+ Qt::FocusReason reason = next ? Qt::TabFocusReason : Qt::BacktabFocusReason;
+ QWidget *lastFocusChild = d->widget->focusWidget();
+ if (QWidget *newFocusChild = d->findFocusChild(lastFocusChild, next)) {
+ newFocusChild->setFocus(reason);
+ return true;
+ }
+
+ return QGraphicsWidget::focusNextPrevChild(next);
+}
+
+/*!
+ \reimp
+*/
+QSizeF QGraphicsProxyWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ Q_D(const QGraphicsProxyWidget);
+ if (!d->widget)
+ return QGraphicsWidget::sizeHint(which, constraint);
+
+ QSizeF sh;
+ switch (which) {
+ case Qt::PreferredSize:
+ if (QLayout *l = d->widget->layout())
+ sh = l->sizeHint();
+ else
+ sh = d->widget->sizeHint();
+ break;
+ case Qt::MinimumSize:
+ if (QLayout *l = d->widget->layout())
+ sh = l->minimumSize();
+ else
+ sh = d->widget->minimumSizeHint();
+ break;
+ case Qt::MaximumSize:
+ if (QLayout *l = d->widget->layout())
+ sh = l->maximumSize();
+ else
+ sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+ break;
+ case Qt::MinimumDescent:
+ sh = constraint;
+ break;
+ default:
+ break;
+ }
+ return sh;
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
+{
+ Q_D(QGraphicsProxyWidget);
+ if (d->widget) {
+ if (d->sizeChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
+ d->widget->resize(event->newSize().toSize());
+ }
+ QGraphicsWidget::resizeEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_D(QGraphicsProxyWidget);
+ Q_UNUSED(widget);
+ if (!d->widget || !d->widget->isVisible())
+ return;
+
+ // Filter out repaints on the window frame.
+ const QRect exposedWidgetRect = (option->exposedRect & rect()).toRect();
+ if (exposedWidgetRect.isEmpty())
+ return;
+
+ // Disable QPainter's default pen being cosmetic. This allows widgets and
+ // styles to follow Qt's existing defaults without getting ugly cosmetic
+ // lines when scaled.
+ bool restore = !(painter->renderHints() & QPainter::NonCosmeticDefaultPen);
+ painter->setRenderHints(QPainter::NonCosmeticDefaultPen, true);
+
+ d->widget->render(painter, exposedWidgetRect.topLeft(), exposedWidgetRect);
+
+ // Restore the render hints if necessary.
+ if (restore)
+ painter->setRenderHints(QPainter::NonCosmeticDefaultPen, false);
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsProxyWidget::type() const
+{
+ return Type;
+}
+
+/*!
+ \since 4.5
+
+ Creates a proxy widget for the given \a child of the widget
+ contained in this proxy.
+
+ This function makes it possible to aquire proxies for
+ non top-level widgets. For instance, you can embed a dialog,
+ and then transform only one of its widgets.
+
+ If the widget is already embedded, return the existing proxy widget.
+
+ \sa newProxyWidget(), QGraphicsScene::addWidget()
+*/
+QGraphicsProxyWidget *QGraphicsProxyWidget::createProxyForChildWidget(QWidget *child)
+{
+ QGraphicsProxyWidget *proxy = child->graphicsProxyWidget();
+ if (proxy)
+ return proxy;
+ if (!child->parentWidget()) {
+ qWarning("QGraphicsProxyWidget::createProxyForChildWidget: top-level widget not in a QGraphicsScene");
+ return 0;
+ }
+
+ QGraphicsProxyWidget *parentProxy = createProxyForChildWidget(child->parentWidget());
+ if (!parentProxy)
+ return 0;
+
+ if (!QMetaObject::invokeMethod(parentProxy, "newProxyWidget", Qt::DirectConnection,
+ Q_RETURN_ARG(QGraphicsProxyWidget*, proxy), Q_ARG(const QWidget*, child)))
+ return 0;
+ proxy->setParent(parentProxy);
+ proxy->setWidget(child);
+ return proxy;
+}
+
+/*!
+ \fn QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *child)
+ \since 4.5
+
+ Creates a proxy widget for the given \a child of the widget contained in this
+ proxy.
+
+ You should not call this function directly; use
+ QGraphicsProxyWidget::createProxyForChildWidget() instead.
+
+ This function is a fake virtual slot that you can reimplement in
+ your subclass in order to control how new proxy widgets are
+ created. The default implementation returns a proxy created with
+ the QGraphicsProxyWidget() constructor with this proxy widget as
+ the parent.
+
+ \sa createProxyForChildWidget()
+*/
+QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *)
+{
+ return new QGraphicsProxyWidget(this);
+}
+
+
+
+QT_END_NAMESPACE
+
+#include "moc_qgraphicsproxywidget.cpp"
+
+#endif //QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicsproxywidget.h b/src/gui/graphicsview/qgraphicsproxywidget.h
new file mode 100644
index 0000000..ab8c9da
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsproxywidget.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSPROXYWIDGET_H
+#define QGRAPHICSPROXYWIDGET_H
+
+#include <QtGui/qgraphicswidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+class QGraphicsProxyWidgetPrivate;
+
+class Q_GUI_EXPORT QGraphicsProxyWidget : public QGraphicsWidget
+{
+ Q_OBJECT
+public:
+ QGraphicsProxyWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0);
+ ~QGraphicsProxyWidget();
+
+ void setWidget(QWidget *widget);
+ QWidget *widget() const;
+
+ QRectF subWidgetRect(const QWidget *widget) const;
+
+ void setGeometry(const QRectF &rect);
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+
+ enum {
+ Type = 12
+ };
+ int type() const;
+
+ QGraphicsProxyWidget *createProxyForChildWidget(QWidget *child);
+
+protected:
+ QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+
+ bool event(QEvent *event);
+ bool eventFilter(QObject *object, QEvent *event);
+
+ void showEvent(QShowEvent *event);
+ void hideEvent(QHideEvent *event);
+
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
+#endif
+
+#ifndef QT_NO_DRAGANDDROP
+ void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
+ void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
+ void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
+ void dropEvent(QGraphicsSceneDragDropEvent *event);
+#endif
+
+ void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ void grabMouseEvent(QEvent *event);
+ void ungrabMouseEvent(QEvent *event);
+
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent(QGraphicsSceneWheelEvent *event);
+#endif
+
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *event);
+
+ void focusInEvent(QFocusEvent *event);
+ void focusOutEvent(QFocusEvent *event);
+ bool focusNextPrevChild(bool next);
+ // ### Qt 4.5:
+ // QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+ // void inputMethodEvent(QInputMethodEvent *event);
+
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+ void resizeEvent(QGraphicsSceneResizeEvent *event);
+
+protected Q_SLOTS:
+ QGraphicsProxyWidget *newProxyWidget(const QWidget *);
+
+private:
+ Q_DISABLE_COPY(QGraphicsProxyWidget)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr, QGraphicsProxyWidget)
+ Q_PRIVATE_SLOT(d_func(), void _q_removeWidgetSlot())
+
+ friend class QWidget;
+ friend class QWidgetPrivate;
+ friend class QGraphicsItem;
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
+
diff --git a/src/gui/graphicsview/qgraphicsproxywidget_p.h b/src/gui/graphicsview/qgraphicsproxywidget_p.h
new file mode 100644
index 0000000..5985eed
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsproxywidget_p.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSPROXYWIDGET_P_H
+#define QGRAPHICSPROXYWIDGET_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qgraphicsproxywidget.h"
+#include "private/qgraphicswidget_p.h"
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsProxyWidgetPrivate : public QGraphicsWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsProxyWidget)
+public:
+ QGraphicsProxyWidgetPrivate()
+ : dragDropWidget(0),
+ posChangeMode(NoMode),
+ sizeChangeMode(NoMode),
+ visibleChangeMode(NoMode),
+ enabledChangeMode(NoMode),
+ styleChangeMode(NoMode),
+ paletteChangeMode(NoMode),
+ focusFromWidgetToProxy(0)
+ { }
+ void init();
+ void sendWidgetMouseEvent(QGraphicsSceneMouseEvent *event);
+ void sendWidgetMouseEvent(QGraphicsSceneHoverEvent *event);
+ void sendWidgetKeyEvent(QKeyEvent *event);
+ void setWidget_helper(QWidget *widget, bool autoShow);
+
+ QWidget *findFocusChild(QWidget *child, bool next) const;
+ void removeSubFocusHelper(QWidget *widget, Qt::FocusReason reason);
+
+ // ### Qt 5: Remove. Workaround for reimplementation added after Qt 4.4.
+ QVariant inputMethodQueryHelper(Qt::InputMethodQuery query) const;
+
+ void _q_removeWidgetSlot();
+
+ void embedSubWindow(QWidget *);
+ void unembedSubWindow(QWidget *);
+
+ bool isProxyWidget() const;
+
+ QPointer<QWidget> widget;
+ QPointer<QWidget> lastWidgetUnderMouse;
+ QPointer<QWidget> embeddedMouseGrabber;
+ QWidget *dragDropWidget;
+ Qt::DropAction lastDropAction;
+
+ void updateWidgetGeometryFromProxy();
+ void updateProxyGeometryFromWidget();
+
+ QPointF mapToReceiver(const QPointF &pos, const QWidget *receiver) const;
+
+ enum ChangeMode {
+ NoMode,
+ ProxyToWidgetMode,
+ WidgetToProxyMode
+ };
+ quint32 posChangeMode : 2;
+ quint32 sizeChangeMode : 2;
+ quint32 visibleChangeMode : 2;
+ quint32 enabledChangeMode : 2;
+ quint32 styleChangeMode : 2;
+ quint32 paletteChangeMode : 2;
+ quint32 focusFromWidgetToProxy : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif
+
+#endif
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
new file mode 100644
index 0000000..1f78a18
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -0,0 +1,5360 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;
+
+/*!
+ \class QGraphicsScene
+ \brief The QGraphicsScene class provides a surface for managing a large
+ number of 2D graphical items.
+ \since 4.2
+ \ingroup multimedia
+ \ingroup graphicsview-api
+ \mainclass
+
+ The class serves as a container for QGraphicsItems. It is used together
+ with QGraphicsView for visualizing graphical items, such as lines,
+ rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is
+ part of \l{The Graphics View Framework}.
+
+ QGraphicsScene also provides functionality that lets you efficiently
+ determine both the location of items, and for determining what items are
+ visible within an arbitrary area on the scene. With the QGraphicsView
+ widget, you can either visualize the whole scene, or zoom in and view only
+ parts of the scene.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 0
+
+ Note that QGraphicsScene has no visual appearance of its own; it only
+ manages the items. You need to create a QGraphicsView widget to visualize
+ the scene.
+
+ To add items to a scene, you start off by constructing a QGraphicsScene
+ object. Then, you have two options: either add your existing QGraphicsItem
+ objects by calling addItem(), or you can call one of the convenience
+ functions addEllipse(), addLine(), addPath(), addPixmap(), addPolygon(),
+ addRect(), or addText(), which all return a pointer to the newly added item.
+ The dimensions of the items added with these functions are relative to the
+ item's coordinate system, and the items position is initialized to (0,
+ 0) in the scene.
+
+ You can then visualize the scene using QGraphicsView. When the scene
+ changes, (e.g., when an item moves or is transformed) QGraphicsScene
+ emits the changed() signal. To remove an item, call removeItem().
+
+ QGraphicsScene uses an indexing algorithm to manage the location of items
+ efficiently. By default, a BSP (Binary Space Partitioning) tree is used; an
+ algorithm suitable for large scenes where most items remain static (i.e.,
+ do not move around). You can choose to disable this index by calling
+ setItemIndexMethod(). For more information about the available indexing
+ algorithms, see the itemIndexMethod property.
+
+ The scene's bounding rect is set by calling setSceneRect(). Items can be
+ placed at any position on the scene, and the size of the scene is by
+ default unlimited. The scene rect is used only for internal bookkeeping,
+ maintaining the scene's item index. If the scene rect is unset,
+ QGraphicsScene will use the bounding area of all items, as returned by
+ itemsBoundingRect(), as the scene rect. However, itemsBoundingRect() is a
+ relatively time consuming function, as it operates by collecting
+ positional information for every item on the scene. Because of this, you
+ should always set the scene rect when operating on large scenes.
+
+ One of QGraphicsScene's greatest strengths is its ability to efficiently
+ determine the location of items. Even with millions of items on the scene,
+ the items() functions can determine the location of an item within few
+ milliseconds. There are several overloads to items(): one that finds items
+ at a certain position, one that finds items inside or intersecting with a
+ polygon or a rectangle, and more. The list of returned items is sorted by
+ stacking order, with the topmost item being the first item in the list.
+ For convenience, there is also an itemAt() function that returns the
+ topmost item at a given position.
+
+ QGraphicsScene maintains selection information for the scene. To select
+ items, call setSelectionArea(), and to clear the current selection, call
+ clearSelection(). Call selectedItems() to get the list of all selected
+ items.
+
+ \section1 Event Handling and Propagation
+
+ Another responsibility that QGraphicsScene has, is to propagate events
+ from QGraphicsView. To send an event to a scene, you construct an event
+ that inherits QEvent, and then send it using, for example,
+ QApplication::sendEvent(). event() is responsible for dispatching
+ the event to the individual items. Some common events are handled by
+ convenience event handlers. For example, key press events are handled by
+ keyPressEvent(), and mouse press events are handled by mousePressEvent().
+
+ Key events are delivered to the \e {focus item}. To set the focus item,
+ you can either call setFocusItem(), passing an item that accepts focus, or
+ the item itself can call QGraphicsItem::setFocus(). Call focusItem() to
+ get the current focus item. For compatibility with widgets, the scene also
+ maintains its own focus information. By default, the scene does not have
+ focus, and all key events are discarded. If setFocus() is called, or if an
+ item on the scene gains focus, the scene automatically gains focus. If the
+ scene has focus, hasFocus() will return true, and key events will be
+ forwarded to the focus item, if any. If the scene loses focus, (i.e.,
+ someone calls clearFocus(),) while an item has focus, the scene will
+ maintain its item focus information, and once the scene regains focus, it
+ will make sure the last focus item regains focus.
+
+ For mouse-over effects, QGraphicsScene dispatches \e {hover
+ events}. If an item accepts hover events (see
+ QGraphicsItem::acceptHoverEvents()), it will receive a \l
+ {QEvent::}{GraphicsSceneHoverEnter} event when the mouse enters
+ its area. As the mouse continues moving inside the item's area,
+ QGraphicsScene will send it \l {QEvent::}{GraphicsSceneHoverMove}
+ events. When the mouse leaves the item's area, the item will
+ receive a \l {QEvent::}{GraphicsSceneHoverLeave} event.
+
+ All mouse events are delivered to the current \e {mouse grabber}
+ item. An item becomes the scene's mouse grabber if it accepts
+ mouse events (see QGraphicsItem::acceptedMouseButtons()) and it
+ receives a mouse press. It stays the mouse grabber until it
+ receives a mouse release when no other mouse buttons are
+ pressed. You can call mouseGrabberItem() to determine what item is
+ currently grabbing the mouse.
+
+ \sa QGraphicsItem, QGraphicsView
+*/
+
+/*!
+ \enum QGraphicsScene::SceneLayer
+ \since 4.3
+
+ This enum describes the rendering layers in a QGraphicsScene. When
+ QGraphicsScene draws the scene contents, it renders each of these layers
+ separately, in order.
+
+ Each layer represents a flag that can be OR'ed together when calling
+ functions such as invalidate() or QGraphicsView::invalidateScene().
+
+ \value ItemLayer The item layer. QGraphicsScene renders all items are in
+ this layer by calling the virtual function drawItems(). The item layer is
+ drawn after the background layer, but before the foreground layer.
+
+ \value BackgroundLayer The background layer. QGraphicsScene renders the
+ scene's background in this layer by calling the virtual function
+ drawBackground(). The background layer is drawn first of all layers.
+
+ \value ForegroundLayer The foreground layer. QGraphicsScene renders the
+ scene's foreground in this layer by calling the virtual function
+ drawForeground(). The foreground layer is drawn last of all layers.
+
+ \value AllLayers All layers; this value represents a combination of all
+ three layers.
+
+ \sa invalidate(), QGraphicsView::invalidateScene()
+*/
+
+/*!
+ \enum QGraphicsScene::ItemIndexMethod
+
+ This enum describes the indexing algorithms QGraphicsScene provides for
+ managing positional information about items on the scene.
+
+ \value BspTreeIndex A Binary Space Partitioning tree is applied. All
+ QGraphicsScene's item location algorithms are of an order close to
+ logarithmic complexity, by making use of binary search. Adding, moving and
+ removing items is logarithmic. This approach is best for static scenes
+ (i.e., scenes where most items do not move).
+
+ \value NoIndex No index is applied. Item location is of linear complexity,
+ as all items on the scene are searched. Adding, moving and removing items,
+ however, is done in constant time. This approach is ideal for dynamic
+ scenes, where many items are added, moved or removed continuously.
+
+ \sa setItemIndexMethod(), bspTreeDepth
+*/
+
+#include "qgraphicsscene.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include "qgraphicsitem.h"
+#include "qgraphicsitem_p.h"
+#include "qgraphicslayout.h"
+#include "qgraphicsscene_p.h"
+#include "qgraphicssceneevent.h"
+#include "qgraphicsview.h"
+#include "qgraphicsview_p.h"
+#include "qgraphicswidget.h"
+#include "qgraphicswidget_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qset.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qdesktopwidget.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qgraphicslayout.h>
+#include <QtGui/qgraphicsproxywidget.h>
+#include <QtGui/qgraphicswidget.h>
+#include <QtGui/qmatrix.h>
+#include <QtGui/qpaintengine.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpixmapcache.h>
+#include <QtGui/qpolygon.h>
+#include <QtGui/qstyleoption.h>
+#include <QtGui/qtooltip.h>
+#include <QtGui/qtransform.h>
+#include <private/qapplication_p.h>
+#include <private/qobject_p.h>
+#ifdef Q_WS_X11
+#include <private/qt_x11_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static inline bool QRectF_intersects(const QRectF &s, const QRectF &r)
+{
+ qreal xp = s.left();
+ qreal yp = s.top();
+ qreal w = s.width();
+ qreal h = s.height();
+ qreal l1 = xp;
+ qreal r1 = xp;
+ if (w < 0)
+ l1 += w;
+ else
+ r1 += w;
+
+ qreal l2 = r.left();
+ qreal r2 = r.left();
+ if (w < 0)
+ l2 += r.width();
+ else
+ r2 += r.width();
+
+ if (l1 >= r2 || l2 >= r1)
+ return false;
+
+ qreal t1 = yp;
+ qreal b1 = yp;
+ if (h < 0)
+ t1 += h;
+ else
+ b1 += h;
+
+ qreal t2 = r.top();
+ qreal b2 = r.top();
+ if (r.height() < 0)
+ t2 += r.height();
+ else
+ b2 += r.height();
+
+ return !(t1 >= b2 || t2 >= b1);
+}
+
+// QRectF::intersects() returns false always if either the source or target
+// rectangle's width or height are 0. This works around that problem.
+static QRectF _q_adjustedRect(const QRectF &rect)
+{
+ static const qreal p = (qreal)0.00001;
+ QRectF r = rect;
+ if (!r.width())
+ r.adjust(-p, 0, p, 0);
+ if (!r.height())
+ r.adjust(0, -p, 0, p);
+ return r;
+}
+
+static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent)
+{
+ hover->setWidget(mouseEvent->widget());
+ hover->setPos(mouseEvent->pos());
+ hover->setScenePos(mouseEvent->scenePos());
+ hover->setScreenPos(mouseEvent->screenPos());
+ hover->setLastPos(mouseEvent->lastPos());
+ hover->setLastScenePos(mouseEvent->lastScenePos());
+ hover->setLastScreenPos(mouseEvent->lastScreenPos());
+ hover->setModifiers(mouseEvent->modifiers());
+ hover->setAccepted(mouseEvent->isAccepted());
+}
+
+/*!
+ \internal
+*/
+QGraphicsScenePrivate::QGraphicsScenePrivate()
+ : changedSignalMask(0),
+ indexMethod(QGraphicsScene::BspTreeIndex),
+ bspTreeDepth(0),
+ lastItemCount(0),
+ hasSceneRect(false),
+ updateAll(false),
+ calledEmitUpdated(false),
+ selectionChanging(0),
+ dirtyItemResetPending(false),
+ regenerateIndex(true),
+ purgePending(false),
+ indexTimerId(0),
+ restartIndexTimer(false),
+ stickyFocus(false),
+ hasFocus(false),
+ focusItem(0),
+ lastFocusItem(0),
+ tabFocusFirst(0),
+ activeWindow(0),
+ activationRefCount(0),
+ lastMouseGrabberItem(0),
+ lastMouseGrabberItemHasImplicitMouseGrab(false),
+ dragDropItem(0),
+ enterWidget(0),
+ lastDropAction(Qt::IgnoreAction),
+ painterStateProtection(true),
+ sortCacheEnabled(false),
+ updatingSortCache(false),
+ style(0)
+{
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::init()
+{
+ Q_Q(QGraphicsScene);
+
+ // Keep this index so we can check for connected slots later on.
+ changedSignalMask = (1 << q->metaObject()->indexOfSignal("changed(QList<QRectF>)"));
+ qApp->d_func()->scene_list.append(q);
+ q->update();
+}
+
+/*!
+ \internal
+*/
+QList<QGraphicsItem *> QGraphicsScenePrivate::estimateItemsInRect(const QRectF &rect) const
+{
+ const_cast<QGraphicsScenePrivate *>(this)->purgeRemovedItems();
+ const_cast<QGraphicsScenePrivate *>(this)->_q_updateSortCache();
+
+ if (indexMethod == QGraphicsScene::BspTreeIndex) {
+ // ### Only do this once in a while.
+ QGraphicsScenePrivate *that = const_cast<QGraphicsScenePrivate *>(this);
+
+ // Get items from BSP tree
+ QList<QGraphicsItem *> items = that->bspTree.items(rect);
+
+ // Fill in with any unindexed items
+ for (int i = 0; i < unindexedItems.size(); ++i) {
+ if (QGraphicsItem *item = unindexedItems.at(i)) {
+ if (!item->d_ptr->itemDiscovered && item->d_ptr->visible && !(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
+ QRectF boundingRect = item->sceneBoundingRect();
+ if (QRectF_intersects(boundingRect, rect)) {
+ item->d_ptr->itemDiscovered = 1;
+ items << item;
+ }
+ }
+ }
+ }
+
+ // Reset the discovered state of all discovered items
+ for (int i = 0; i < items.size(); ++i)
+ items.at(i)->d_func()->itemDiscovered = 0;
+ return items;
+ }
+
+ QList<QGraphicsItem *> itemsInRect;
+ for (int i = 0; i < unindexedItems.size(); ++i) {
+ if (QGraphicsItem *item = unindexedItems.at(i)) {
+ if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
+ continue;
+ if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0))
+ itemsInRect << item;
+ }
+ }
+ for (int i = 0; i < indexedItems.size(); ++i) {
+ if (QGraphicsItem *item = indexedItems.at(i)) {
+ if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
+ continue;
+ if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0))
+ itemsInRect << item;
+ }
+ }
+
+ return itemsInRect;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::addToIndex(QGraphicsItem *item)
+{
+ if (indexMethod == QGraphicsScene::BspTreeIndex) {
+ if (item->d_func()->index != -1) {
+ bspTree.insertItem(item, item->sceneBoundingRect());
+ foreach (QGraphicsItem *child, item->children())
+ child->addToIndex();
+ } else {
+ // The BSP tree is regenerated if the number of items grows to a
+ // certain threshold, or if the bounding rect of the graph doubles in
+ // size.
+ startIndexTimer();
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::removeFromIndex(QGraphicsItem *item)
+{
+ if (indexMethod == QGraphicsScene::BspTreeIndex) {
+ int index = item->d_func()->index;
+ if (index != -1) {
+ bspTree.removeItem(item, item->sceneBoundingRect());
+ freeItemIndexes << index;
+ indexedItems[index] = 0;
+ item->d_func()->index = -1;
+ unindexedItems << item;
+
+ foreach (QGraphicsItem *child, item->children())
+ child->removeFromIndex();
+ }
+
+ startIndexTimer();
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::resetIndex()
+{
+ purgeRemovedItems();
+ if (indexMethod == QGraphicsScene::BspTreeIndex) {
+ for (int i = 0; i < indexedItems.size(); ++i) {
+ if (QGraphicsItem *item = indexedItems.at(i)) {
+ item->d_ptr->index = -1;
+ unindexedItems << item;
+ }
+ }
+ indexedItems.clear();
+ freeItemIndexes.clear();
+ regenerateIndex = true;
+ startIndexTimer();
+ }
+}
+
+static inline int intmaxlog(int n)
+{
+ return (n > 0 ? qMax(qCeil(qLn(qreal(n)) / qLn(qreal(2))), 5) : 0);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::_q_updateIndex()
+{
+ if (!indexTimerId)
+ return;
+
+ Q_Q(QGraphicsScene);
+ q->killTimer(indexTimerId);
+ indexTimerId = 0;
+
+ purgeRemovedItems();
+
+ // Add unindexedItems to indexedItems
+ QRectF unindexedItemsBoundingRect;
+ for (int i = 0; i < unindexedItems.size(); ++i) {
+ if (QGraphicsItem *item = unindexedItems.at(i)) {
+ unindexedItemsBoundingRect |= item->sceneBoundingRect();
+ if (!freeItemIndexes.isEmpty()) {
+ int freeIndex = freeItemIndexes.takeFirst();
+ item->d_func()->index = freeIndex;
+ indexedItems[freeIndex] = item;
+ } else {
+ item->d_func()->index = indexedItems.size();
+ indexedItems << item;
+ }
+ }
+ }
+
+ // Update growing scene rect.
+ QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
+ growingItemsBoundingRect |= unindexedItemsBoundingRect;
+
+ // Determine whether we should regenerate the BSP tree.
+ if (indexMethod == QGraphicsScene::BspTreeIndex) {
+ int depth = bspTreeDepth;
+ if (depth == 0) {
+ int oldDepth = intmaxlog(lastItemCount);
+ depth = intmaxlog(indexedItems.size());
+ static const int slack = 100;
+ if (bspTree.leafCount() == 0 || (oldDepth != depth && qAbs(lastItemCount - indexedItems.size()) > slack)) {
+ // ### Crude algorithm.
+ regenerateIndex = true;
+ }
+ }
+
+ // Regenerate the tree.
+ if (regenerateIndex) {
+ regenerateIndex = false;
+ bspTree.initialize(q->sceneRect(), depth);
+ unindexedItems = indexedItems;
+ lastItemCount = indexedItems.size();
+ q->update();
+
+ // Take this opportunity to reset our largest-item counter for
+ // untransformable items. When the items are inserted into the BSP
+ // tree, we'll get an accurate calculation.
+ largestUntransformableItem = QRectF();
+ }
+ }
+
+ // Insert all unindexed items into the tree.
+ for (int i = 0; i < unindexedItems.size(); ++i) {
+ if (QGraphicsItem *item = unindexedItems.at(i)) {
+ QRectF rect = item->sceneBoundingRect();
+ if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
+ continue;
+ if (indexMethod == QGraphicsScene::BspTreeIndex)
+ bspTree.insertItem(item, rect);
+
+ // If the item ignores view transformations, update our
+ // largest-item-counter to ensure that the view can accurately
+ // discover untransformable items when drawing.
+ if (item->d_ptr->itemIsUntransformable()) {
+ QGraphicsItem *topmostUntransformable = item;
+ while (topmostUntransformable && (topmostUntransformable->d_ptr->ancestorFlags
+ & QGraphicsItemPrivate::AncestorIgnoresTransformations)) {
+ topmostUntransformable = topmostUntransformable->parentItem();
+ }
+ // ### Verify that this is the correct largest untransformable rectangle.
+ largestUntransformableItem |= item->mapToItem(topmostUntransformable, item->boundingRect()).boundingRect();
+ }
+ }
+ }
+ unindexedItems.clear();
+
+ // Notify scene rect changes.
+ if (!hasSceneRect && growingItemsBoundingRect != oldGrowingItemsBoundingRect)
+ emit q->sceneRectChanged(growingItemsBoundingRect);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::_q_emitUpdated()
+{
+ Q_Q(QGraphicsScene);
+ calledEmitUpdated = false;
+
+ // Ensure all views are connected if anything is connected. This disables
+ // the optimization that items send updates directly to the views, but it
+ // needs to happen in order to keep compatibility with the behavior from
+ // Qt 4.4 and backward.
+ if (!views.isEmpty() && (connectedSignals & changedSignalMask)) {
+ for (int i = 0; i < views.size(); ++i) {
+ QGraphicsView *view = views.at(i);
+ if (!view->d_func()->connectedToScene) {
+ view->d_func()->connectedToScene = true;
+ q->connect(q, SIGNAL(changed(QList<QRectF>)),
+ views.at(i), SLOT(updateScene(QList<QRectF>)));
+ }
+ }
+ }
+
+ // Ensure all dirty items's current positions are recorded in the list of
+ // updated rects.
+ for (int i = 0; i < dirtyItems.size(); ++i)
+ updatedRects += dirtyItems.at(i)->sceneBoundingRect();
+
+ // Notify the changes to anybody interested.
+ QList<QRectF> oldUpdatedRects;
+ oldUpdatedRects = updateAll ? (QList<QRectF>() << q->sceneRect()) : updatedRects;
+ updateAll = false;
+ updatedRects.clear();
+ emit q->changed(oldUpdatedRects);
+}
+
+/*!
+ \internal
+
+ Updates all items in the pending update list. At this point, the list is
+ unlikely to contain partially constructed items.
+*/
+void QGraphicsScenePrivate::_q_updateLater()
+{
+ foreach (QGraphicsItem *item, pendingUpdateItems)
+ item->update();
+ pendingUpdateItems.clear();
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::_q_polishItems()
+{
+ foreach (QGraphicsItem *item, unpolishedItems) {
+ if (!item->d_ptr->explicitlyHidden) {
+ item->itemChange(QGraphicsItem::ItemVisibleChange, true);
+ item->itemChange(QGraphicsItem::ItemVisibleHasChanged, true);
+ }
+ if (item->isWidget()) {
+ QEvent event(QEvent::Polish);
+ QApplication::sendEvent((QGraphicsWidget *)item, &event);
+ }
+ }
+ unpolishedItems.clear();
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::_q_resetDirtyItems()
+{
+ for (int i = 0; i < dirtyItems.size(); ++i) {
+ QGraphicsItem *item = dirtyItems.at(i);
+ item->d_ptr->dirty = 0;
+ item->d_ptr->dirtyChildren = 0;
+ }
+ dirtyItems.clear();
+ dirtyItemResetPending = false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::resetDirtyItemsLater()
+{
+ Q_Q(QGraphicsScene);
+ if (dirtyItemResetPending)
+ return;
+ // dirtyItems.reserve(indexedItems.size() + unindexedItems.size());
+ dirtyItemResetPending = true;
+ QMetaObject::invokeMethod(q, "_q_resetDirtyItems", Qt::QueuedConnection);
+}
+
+/*!
+ \internal
+
+ Schedules an item for removal. This function leaves some stale indexes
+ around in the BSP tree; these will be cleaned up the next time someone
+ triggers purgeRemovedItems().
+
+ Note: This function is called from QGraphicsItem's destructor. \a item is
+ being destroyed, so we cannot call any pure virtual functions on it (such
+ as boundingRect()). Also, it is unnecessary to update the item's own state
+ in any way.
+
+ ### Refactoring: This function shares much functionality with removeItem()
+*/
+void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item)
+{
+ Q_Q(QGraphicsScene);
+
+ if (QGraphicsItem *parent = item->d_func()->parent) {
+ QVariant variant;
+ qVariantSetValue<QGraphicsItem *>(variant, item);
+ parent->itemChange(QGraphicsItem::ItemChildRemovedChange, variant);
+ parent->d_func()->children.removeAll(item);
+ }
+
+ // Clear focus on the item to remove any reference in the focusWidget
+ // chain.
+ item->clearFocus();
+
+ int index = item->d_func()->index;
+ if (index != -1) {
+ // Important: The index is useless until purgeRemovedItems() is
+ // called.
+ indexedItems[index] = (QGraphicsItem *)0;
+ if (!purgePending) {
+ purgePending = true;
+ q->update();
+ }
+ removedItems << item;
+ } else {
+ // Recently added items are purged immediately. unindexedItems() never
+ // contains stale items.
+ unindexedItems.removeAll(item);
+ q->update();
+ }
+
+ // Reset the mouse grabber and focus item data.
+ if (item == focusItem)
+ focusItem = 0;
+ if (item == lastFocusItem)
+ lastFocusItem = 0;
+ if (item == activeWindow) {
+ // ### deactivate...
+ activeWindow = 0;
+ }
+
+ // Disable selectionChanged() for individual items
+ ++selectionChanging;
+ int oldSelectedItemsSize = selectedItems.size();
+
+ // Update selected & hovered item bookkeeping
+ selectedItems.remove(item);
+ hoverItems.removeAll(item);
+ pendingUpdateItems.removeAll(item);
+ cachedItemsUnderMouse.removeAll(item);
+ unpolishedItems.removeAll(item);
+ dirtyItems.removeAll(item);
+
+ // Remove from scene transform cache
+ int transformIndex = item->d_func()->sceneTransformIndex;
+ if (transformIndex != -1) {
+ validTransforms.setBit(transformIndex, 0);
+ freeSceneTransformSlots.append(transformIndex);
+ }
+
+ // Remove all children recursively.
+ foreach (QGraphicsItem *child, item->children())
+ _q_removeItemLater(child);
+
+ // Reset the mouse grabber
+ if (mouseGrabberItems.contains(item))
+ ungrabMouse(item, /* item is dying */ true);
+
+ // Reset the keyboard grabber
+ if (keyboardGrabberItems.contains(item))
+ ungrabKeyboard(item, /* item is dying */ true);
+
+ // Reset the last mouse grabber item
+ if (item == lastMouseGrabberItem)
+ lastMouseGrabberItem = 0;
+
+ // Reenable selectionChanged() for individual items
+ --selectionChanging;
+ if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize)
+ emit q->selectionChanged();
+}
+
+/*!
+ \internal
+
+ Removes stale pointers from all data structures.
+*/
+void QGraphicsScenePrivate::purgeRemovedItems()
+{
+ Q_Q(QGraphicsScene);
+
+ if (!purgePending && removedItems.isEmpty())
+ return;
+
+ // Remove stale items from the BSP tree.
+ if (indexMethod != QGraphicsScene::NoIndex)
+ bspTree.removeItems(removedItems);
+
+ // Purge this list.
+ removedItems.clear();
+ freeItemIndexes.clear();
+ for (int i = 0; i < indexedItems.size(); ++i) {
+ if (!indexedItems.at(i))
+ freeItemIndexes << i;
+ }
+ purgePending = false;
+
+ // No locality info for the items; update the whole scene.
+ q->update();
+}
+
+/*!
+ \internal
+
+ Starts or restarts the timer used for reindexing unindexed items.
+*/
+void QGraphicsScenePrivate::startIndexTimer()
+{
+ Q_Q(QGraphicsScene);
+ if (indexTimerId) {
+ restartIndexTimer = true;
+ } else {
+ indexTimerId = q->startTimer(QGRAPHICSSCENE_INDEXTIMER_TIMEOUT);
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::addPopup(QGraphicsWidget *widget)
+{
+ Q_ASSERT(widget);
+ Q_ASSERT(!popupWidgets.contains(widget));
+ popupWidgets << widget;
+ if (QGraphicsWidget *focusWidget = widget->focusWidget()) {
+ focusWidget->setFocus(Qt::PopupFocusReason);
+ } else {
+ grabKeyboard((QGraphicsItem *)widget);
+ if (focusItem && popupWidgets.size() == 1) {
+ QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
+ sendEvent(focusItem, &event);
+ }
+ }
+ grabMouse((QGraphicsItem *)widget);
+}
+
+/*!
+ \internal
+
+ Remove \a widget from the popup list. Important notes:
+
+ \a widget is guaranteed to be in the list of popups, but it might not be
+ the last entry; you can hide any item in the pop list before the others,
+ and this must cause all later mouse grabbers to lose the grab.
+*/
+void QGraphicsScenePrivate::removePopup(QGraphicsWidget *widget, bool itemIsDying)
+{
+ Q_ASSERT(widget);
+ int index = popupWidgets.indexOf(widget);
+ Q_ASSERT(index != -1);
+
+ for (int i = popupWidgets.size() - 1; i >= index; --i) {
+ QGraphicsWidget *widget = popupWidgets.takeLast();
+ ungrabMouse(widget, itemIsDying);
+ if (focusItem && popupWidgets.isEmpty()) {
+ QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
+ sendEvent(focusItem, &event);
+ } else {
+ ungrabKeyboard((QGraphicsItem *)widget, itemIsDying);
+ }
+ if (!itemIsDying && widget->isVisible()) {
+ widget->hide();
+ widget->QGraphicsItem::d_ptr->explicitlyHidden = 0;
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::grabMouse(QGraphicsItem *item, bool implicit)
+{
+ // Append to list of mouse grabber items, and send a mouse grab event.
+ if (mouseGrabberItems.contains(item)) {
+ if (mouseGrabberItems.last() == item)
+ qWarning("QGraphicsItem::grabMouse: already a mouse grabber");
+ else
+ qWarning("QGraphicsItem::grabMouse: already blocked by mouse grabber: %p",
+ mouseGrabberItems.last());
+ return;
+ }
+
+ // Send ungrab event to the last grabber.
+ if (!mouseGrabberItems.isEmpty()) {
+ QGraphicsItem *last = mouseGrabberItems.last();
+ if (lastMouseGrabberItemHasImplicitMouseGrab) {
+ // Implicit mouse grab is immediately lost.
+ last->ungrabMouse();
+ } else {
+ // Just send ungrab event to current grabber.
+ QEvent ungrabEvent(QEvent::UngrabMouse);
+ sendEvent(last, &ungrabEvent);
+ }
+ }
+
+ mouseGrabberItems << item;
+ lastMouseGrabberItemHasImplicitMouseGrab = implicit;
+
+ // Send grab event to current grabber.
+ QEvent grabEvent(QEvent::GrabMouse);
+ sendEvent(item, &grabEvent);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::ungrabMouse(QGraphicsItem *item, bool itemIsDying)
+{
+ int index = mouseGrabberItems.indexOf(item);
+ if (index == -1) {
+ qWarning("QGraphicsItem::ungrabMouse: not a mouse grabber");
+ return;
+ }
+
+ if (item != mouseGrabberItems.last()) {
+ // Recursively ungrab the next mouse grabber until we reach this item
+ // to ensure state consistency.
+ ungrabMouse(mouseGrabberItems.at(index + 1), itemIsDying);
+ }
+ if (!popupWidgets.isEmpty() && item == popupWidgets.last()) {
+ // If the item is a popup, go via removePopup to ensure state
+ // consistency and that it gets hidden correctly - beware that
+ // removePopup() reenters this function to continue removing the grab.
+ removePopup((QGraphicsWidget *)item, itemIsDying);
+ return;
+ }
+
+ // Send notification about mouse ungrab.
+ if (!itemIsDying) {
+ QEvent event(QEvent::UngrabMouse);
+ sendEvent(item, &event);
+ }
+
+ // Remove the item from the list of grabbers. Whenever this happens, we
+ // reset the implicitGrab (there can be only ever be one implicit grabber
+ // in a scene, and it is always the latest grabber; if the implicit grab
+ // is lost, it is not automatically regained.
+ mouseGrabberItems.takeLast();
+ lastMouseGrabberItemHasImplicitMouseGrab = false;
+
+ // Send notification about mouse regrab. ### It's unfortunate that all the
+ // items get a GrabMouse event, but this is a rare case with a simple
+ // implementation and it does ensure a consistent state.
+ if (!itemIsDying && !mouseGrabberItems.isEmpty()) {
+ QGraphicsItem *last = mouseGrabberItems.last();
+ QEvent event(QEvent::GrabMouse);
+ sendEvent(last, &event);
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::clearMouseGrabber()
+{
+ if (!mouseGrabberItems.isEmpty())
+ mouseGrabberItems.first()->ungrabMouse();
+ lastMouseGrabberItem = 0;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::grabKeyboard(QGraphicsItem *item)
+{
+ if (keyboardGrabberItems.contains(item)) {
+ if (keyboardGrabberItems.last() == item)
+ qWarning("QGraphicsItem::grabKeyboard: already a keyboard grabber");
+ else
+ qWarning("QGraphicsItem::grabKeyboard: already blocked by keyboard grabber: %p",
+ keyboardGrabberItems.last());
+ return;
+ }
+
+ // Send ungrab event to the last grabber.
+ if (!keyboardGrabberItems.isEmpty()) {
+ // Just send ungrab event to current grabber.
+ QEvent ungrabEvent(QEvent::UngrabKeyboard);
+ sendEvent(keyboardGrabberItems.last(), &ungrabEvent);
+ }
+
+ keyboardGrabberItems << item;
+
+ // Send grab event to current grabber.
+ QEvent grabEvent(QEvent::GrabKeyboard);
+ sendEvent(item, &grabEvent);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::ungrabKeyboard(QGraphicsItem *item, bool itemIsDying)
+{
+ int index = keyboardGrabberItems.lastIndexOf(item);
+ if (index == -1) {
+ qWarning("QGraphicsItem::ungrabKeyboard: not a keyboard grabber");
+ return;
+ }
+ if (item != keyboardGrabberItems.last()) {
+ // Recursively ungrab the topmost keyboard grabber until we reach this
+ // item to ensure state consistency.
+ ungrabKeyboard(keyboardGrabberItems.at(index + 1), itemIsDying);
+ }
+
+ // Send notification about keyboard ungrab.
+ if (!itemIsDying) {
+ QEvent event(QEvent::UngrabKeyboard);
+ sendEvent(item, &event);
+ }
+
+ // Remove the item from the list of grabbers.
+ keyboardGrabberItems.takeLast();
+
+ // Send notification about mouse regrab.
+ if (!itemIsDying && !keyboardGrabberItems.isEmpty()) {
+ QGraphicsItem *last = keyboardGrabberItems.last();
+ QEvent event(QEvent::GrabKeyboard);
+ sendEvent(last, &event);
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::clearKeyboardGrabber()
+{
+ if (!keyboardGrabberItems.isEmpty())
+ ungrabKeyboard(keyboardGrabberItems.first());
+}
+
+/*!
+ Returns all items for the screen position in \a event.
+*/
+QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &screenPos,
+ const QPointF &scenePos,
+ QWidget *widget) const
+{
+ Q_Q(const QGraphicsScene);
+ QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
+ QList<QGraphicsItem *> items;
+ if (view)
+ items = view->items(view->viewport()->mapFromGlobal(screenPos));
+ else
+ items = q->items(scenePos);
+ return items;
+}
+
+/*!
+ \internal
+
+ Checks if item collides with the path and mode, but also checks that if it
+ doesn't collide, maybe its frame rect will.
+*/
+bool QGraphicsScenePrivate::itemCollidesWithPath(QGraphicsItem *item,
+ const QPainterPath &path,
+ Qt::ItemSelectionMode mode)
+{
+ if (item->collidesWithPath(path, mode))
+ return true;
+ if (item->isWidget()) {
+ // Check if this is a window, and if its frame rect collides.
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
+ if (widget->isWindow()) {
+ QRectF frameRect = widget->windowFrameRect();
+ QPainterPath framePath;
+ framePath.addRect(frameRect);
+ bool intersects = path.intersects(frameRect);
+ if (mode == Qt::IntersectsItemShape || mode == Qt::IntersectsItemBoundingRect)
+ return intersects || path.contains(frameRect.topLeft())
+ || framePath.contains(path.elementAt(0));
+ return !intersects && path.contains(frameRect.topLeft());
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event)
+{
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ mouseGrabberButtonDownPos.insert(Qt::MouseButton(i),
+ mouseGrabberItems.last()->d_ptr->genericMapFromScene(event->scenePos(),
+ event->widget()));
+ mouseGrabberButtonDownScenePos.insert(Qt::MouseButton(i), event->scenePos());
+ mouseGrabberButtonDownScreenPos.insert(Qt::MouseButton(i), event->screenPos());
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
+{
+ sceneEventFilters.insert(watched, filter);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
+{
+ if (!sceneEventFilters.contains(watched))
+ return;
+
+ QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(watched);
+ QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(watched);
+ do {
+ if (it.value() == filter)
+ it = sceneEventFilters.erase(it);
+ else
+ ++it;
+ } while (it != end);
+}
+
+/*!
+ \internal
+*/
+bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event)
+{
+ if (item && !sceneEventFilters.contains(item))
+ return false;
+
+ QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(item);
+ QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(item);
+ while (it != end) {
+ // ### The filterer and filteree might both be deleted.
+ if (it.value()->sceneEventFilter(it.key(), event))
+ return true;
+ ++it;
+ }
+ return false;
+}
+
+/*!
+ \internal
+
+ This is the final dispatch point for any events from the scene to the
+ item. It filters the event first - if the filter returns true, the event
+ is considered to have been eaten by the filter, and is therefore stopped
+ (the default filter returns false). Then/otherwise, if the item is
+ enabled, the event is sent; otherwise it is stopped.
+*/
+bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
+{
+ if (filterEvent(item, event))
+ return false;
+ return (item && item->isEnabled()) ? item->sceneEvent(event) : false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::cloneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
+ QGraphicsSceneDragDropEvent *source)
+{
+ dest->setWidget(source->widget());
+ dest->setPos(source->pos());
+ dest->setScenePos(source->scenePos());
+ dest->setScreenPos(source->screenPos());
+ dest->setButtons(source->buttons());
+ dest->setModifiers(source->modifiers());
+ dest->setPossibleActions(source->possibleActions());
+ dest->setProposedAction(source->proposedAction());
+ dest->setDropAction(source->dropAction());
+ dest->setSource(source->source());
+ dest->setMimeData(source->mimeData());
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::sendDragDropEvent(QGraphicsItem *item,
+ QGraphicsSceneDragDropEvent *dragDropEvent)
+{
+ dragDropEvent->setPos(item->d_ptr->genericMapFromScene(dragDropEvent->scenePos(), dragDropEvent->widget()));
+ sendEvent(item, dragDropEvent);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::sendHoverEvent(QEvent::Type type, QGraphicsItem *item,
+ QGraphicsSceneHoverEvent *hoverEvent)
+{
+ QGraphicsSceneHoverEvent event(type);
+ event.setWidget(hoverEvent->widget());
+ event.setPos(item->d_ptr->genericMapFromScene(hoverEvent->scenePos(), hoverEvent->widget()));
+ event.setScenePos(hoverEvent->scenePos());
+ event.setScreenPos(hoverEvent->screenPos());
+ event.setLastPos(item->d_ptr->genericMapFromScene(hoverEvent->lastScenePos(), hoverEvent->widget()));
+ event.setLastScenePos(hoverEvent->lastScenePos());
+ event.setLastScreenPos(hoverEvent->lastScreenPos());
+ event.setModifiers(hoverEvent->modifiers());
+ sendEvent(item, &event);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent)
+{
+ if (mouseEvent->button() == 0 && mouseEvent->buttons() == 0 && lastMouseGrabberItemHasImplicitMouseGrab) {
+ // ### This is a temporary fix for until we get proper mouse
+ // grab events.
+ clearMouseGrabber();
+ return;
+ }
+
+ QGraphicsItem *item = mouseGrabberItems.last();
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent->setButtonDownPos(button, mouseGrabberButtonDownPos.value(button, item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget())));
+ mouseEvent->setButtonDownScenePos(button, mouseGrabberButtonDownScenePos.value(button, mouseEvent->scenePos()));
+ mouseEvent->setButtonDownScreenPos(button, mouseGrabberButtonDownScreenPos.value(button, mouseEvent->screenPos()));
+ }
+ mouseEvent->setPos(item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget()));
+ mouseEvent->setLastPos(item->d_ptr->genericMapFromScene(mouseEvent->lastScenePos(), mouseEvent->widget()));
+ sendEvent(item, mouseEvent);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent)
+{
+ Q_Q(QGraphicsScene);
+
+ // Ignore by default, unless we find a mouse grabber that accepts it.
+ mouseEvent->ignore();
+
+ // Deliver to any existing mouse grabber.
+ if (!mouseGrabberItems.isEmpty()) {
+ // The event is ignored by default, but we disregard the event's
+ // accepted state after delivery; the mouse is grabbed, after all.
+ sendMouseEvent(mouseEvent);
+ return;
+ }
+
+ // Start by determining the number of items at the current position.
+ // Reuse value from earlier calculations if possible.
+ if (cachedItemsUnderMouse.isEmpty()) {
+ cachedItemsUnderMouse = itemsAtPosition(mouseEvent->screenPos(),
+ mouseEvent->scenePos(),
+ mouseEvent->widget());
+ }
+
+ // Update window activation.
+ QGraphicsWidget *newActiveWindow = windowForItem(cachedItemsUnderMouse.value(0));
+ if (newActiveWindow != activeWindow)
+ q->setActiveWindow(newActiveWindow);
+
+ // Set focus on the topmost enabled item that can take focus.
+ bool setFocus = false;
+ foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
+ if (item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) {
+ if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
+ setFocus = true;
+ if (item != q->focusItem())
+ q->setFocusItem(item, Qt::MouseFocusReason);
+ break;
+ }
+ }
+ }
+
+ // If nobody could take focus, clear it.
+ if (!stickyFocus && !setFocus)
+ q->setFocusItem(0, Qt::MouseFocusReason);
+
+ // Find a mouse grabber by sending mouse press events to all mouse grabber
+ // candidates one at a time, until the event is accepted. It's accepted by
+ // default, so the receiver has to explicitly ignore it for it to pass
+ // through.
+ foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
+ if (!(item->acceptedMouseButtons() & mouseEvent->button())) {
+ // Skip items that don't accept the event's mouse button.
+ continue;
+ }
+
+ grabMouse(item, /* implicit = */ true);
+ mouseEvent->accept();
+
+ // check if the item we are sending to are disabled (before we send the event)
+ bool disabled = !item->isEnabled();
+ bool isWindow = item->isWindow();
+ if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick && item != lastMouseGrabberItem) {
+ // If this item is different from the item that received the last
+ // mouse event, and mouseEvent is a doubleclick event, then the
+ // event is converted to a press. Known limitation:
+ // Triple-clicking will not generate a doubleclick, though.
+ QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
+ mousePress.accept();
+ mousePress.setButton(mouseEvent->button());
+ mousePress.setButtons(mouseEvent->buttons());
+ mousePress.setScreenPos(mouseEvent->screenPos());
+ mousePress.setScenePos(mouseEvent->scenePos());
+ mousePress.setModifiers(mouseEvent->modifiers());
+ mousePress.setWidget(mouseEvent->widget());
+ mousePress.setButtonDownPos(mouseEvent->button(),
+ mouseEvent->buttonDownPos(mouseEvent->button()));
+ mousePress.setButtonDownScenePos(mouseEvent->button(),
+ mouseEvent->buttonDownScenePos(mouseEvent->button()));
+ mousePress.setButtonDownScreenPos(mouseEvent->button(),
+ mouseEvent->buttonDownScreenPos(mouseEvent->button()));
+ sendMouseEvent(&mousePress);
+ mouseEvent->setAccepted(mousePress.isAccepted());
+ } else {
+ sendMouseEvent(mouseEvent);
+ }
+
+ bool dontSendUngrabEvents = mouseGrabberItems.isEmpty() || mouseGrabberItems.last() != item;
+ if (disabled) {
+ ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
+ break;
+ }
+ if (mouseEvent->isAccepted()) {
+ if (!mouseGrabberItems.isEmpty())
+ storeMouseButtonsForMouseGrabber(mouseEvent);
+ lastMouseGrabberItem = item;
+ return;
+ }
+ ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
+
+ // Don't propagate through windows.
+ if (isWindow)
+ break;
+ }
+
+ // Is the event still ignored? Then the mouse press goes to the scene.
+ // Reset the mouse grabber, clear the selection, clear focus, and leave
+ // the event ignored so that it can propagate through the originating
+ // view.
+ if (!mouseEvent->isAccepted()) {
+ clearMouseGrabber();
+
+ QGraphicsView *view = mouseEvent->widget() ? qobject_cast<QGraphicsView *>(mouseEvent->widget()->parentWidget()) : 0;
+ bool dontClearSelection = view && view->dragMode() == QGraphicsView::ScrollHandDrag;
+ if (!dontClearSelection) {
+ // Clear the selection if the originating view isn't in scroll
+ // hand drag mode. The view will clear the selection if no drag
+ // happened.
+ q->clearSelection();
+ }
+ }
+}
+
+QGraphicsWidget *QGraphicsScenePrivate::windowForItem(const QGraphicsItem *item) const
+{
+ if (!item)
+ return 0;
+ do {
+ if (item->isWidget())
+ return static_cast<const QGraphicsWidget *>(item)->window();
+ item = item->parentItem();
+ } while (item);
+ return 0;
+}
+
+QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QRectF &rect,
+ Qt::ItemSelectionMode mode,
+ Qt::SortOrder order) const
+{
+ QList<QGraphicsItem *> items;
+
+ QPainterPath path;
+
+ // The index returns a rough estimate of what items are inside the rect.
+ // Refine it by iterating through all returned items.
+ QRectF adjustedRect = _q_adjustedRect(rect);
+ foreach (QGraphicsItem *item, estimateItemsInRect(adjustedRect)) {
+ // Find the item's scene transform in a clever way.
+ QTransform x = item->sceneTransform();
+ bool keep = false;
+
+ // ### _q_adjustedRect is only needed because QRectF::intersects,
+ // QRectF::contains and QTransform::map() and friends don't work with
+ // flat rectangles.
+ QRectF br = _q_adjustedRect(item->boundingRect());
+ if (mode >= Qt::ContainsItemBoundingRect) {
+ // Rect intersects/contains item's bounding rect
+ QRectF mbr = x.mapRect(br);
+ if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr))
+ || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(mbr))) {
+ items << item;
+ keep = true;
+ }
+ } else {
+ // Rect intersects/contains item's shape
+ if (QRectF_intersects(adjustedRect, x.mapRect(br))) {
+ bool ok;
+ QTransform xinv = x.inverted(&ok);
+ if (ok) {
+ if (path == QPainterPath())
+ path.addRect(rect);
+ if (itemCollidesWithPath(item, xinv.map(path), mode)) {
+ items << item;
+ keep = true;
+ }
+ }
+ }
+ }
+
+ if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
+ // Recurse into children that clip children.
+ bool ok;
+ QTransform xinv = x.inverted(&ok);
+ if (ok) {
+ if (x.type() <= QTransform::TxScale) {
+ // Rect
+ childItems_helper(&items, item, xinv.mapRect(rect), mode);
+ } else {
+ // Polygon
+ childItems_helper(&items, item, xinv.map(rect), mode);
+ }
+ }
+ }
+ }
+
+ if (order != Qt::SortOrder(-1))
+ sortItems(&items, order, sortCacheEnabled);
+ return items;
+}
+
+QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPolygonF &polygon,
+ Qt::ItemSelectionMode mode,
+ Qt::SortOrder order) const
+{
+ QList<QGraphicsItem *> items;
+
+ QRectF polyRect = _q_adjustedRect(polygon.boundingRect());
+ QPainterPath path;
+
+ // The index returns a rough estimate of what items are inside the rect.
+ // Refine it by iterating through all returned items.
+ foreach (QGraphicsItem *item, estimateItemsInRect(polyRect)) {
+ // Find the item's scene transform in a clever way.
+ QTransform x = item->sceneTransform();
+ bool keep = false;
+
+ // ### _q_adjustedRect is only needed because QRectF::intersects,
+ // QRectF::contains and QTransform::map() and friends don't work with
+ // flat rectangles.
+ QRectF br = _q_adjustedRect(item->boundingRect());
+ if (mode >= Qt::ContainsItemBoundingRect) {
+ // Polygon contains/intersects item's bounding rect
+ if (path == QPainterPath())
+ path.addPolygon(polygon);
+ if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(x.mapRect(br)))
+ || (mode == Qt::ContainsItemBoundingRect && path.contains(x.mapRect(br)))) {
+ items << item;
+ keep = true;
+ }
+ } else {
+ // Polygon contains/intersects item's shape
+ if (QRectF_intersects(polyRect, x.mapRect(br))) {
+ bool ok;
+ QTransform xinv = x.inverted(&ok);
+ if (ok) {
+ if (path == QPainterPath())
+ path.addPolygon(polygon);
+ if (itemCollidesWithPath(item, xinv.map(path), mode)) {
+ items << item;
+ keep = true;
+ }
+ }
+ }
+ }
+
+ if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
+ // Recurse into children that clip children.
+ bool ok;
+ QTransform xinv = x.inverted(&ok);
+ if (ok)
+ childItems_helper(&items, item, xinv.map(polygon), mode);
+ }
+ }
+
+ if (order != Qt::SortOrder(-1))
+ sortItems(&items, order, sortCacheEnabled);
+ return items;
+}
+
+QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPainterPath &path,
+ Qt::ItemSelectionMode mode,
+ Qt::SortOrder order) const
+{
+ QList<QGraphicsItem *> items;
+ // The index returns a rough estimate of what items are inside the rect.
+ // Refine it by iterating through all returned items.
+ foreach (QGraphicsItem *item, estimateItemsInRect(_q_adjustedRect(path.controlPointRect()))) {
+ // Find the item's scene transform in a clever way.
+ QTransform x = item->sceneTransform();
+ bool ok;
+ QTransform xinv = x.inverted(&ok);
+ if (ok) {
+ QPainterPath mappedPath = xinv.map(path);
+ if (itemCollidesWithPath(item, mappedPath, mode)) {
+ items << item;
+ if (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)
+ childItems_helper(&items, item, mappedPath, mode);
+ }
+ }
+ }
+
+ if (order != Qt::SortOrder(-1))
+ sortItems(&items, order, sortCacheEnabled);
+ return items;
+}
+
+void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
+ const QGraphicsItem *parent,
+ const QRectF &rect,
+ Qt::ItemSelectionMode mode) const
+{
+ QPainterPath path;
+ bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
+ QRectF r = !parentClip ? _q_adjustedRect(rect) : _q_adjustedRect(rect).intersected(_q_adjustedRect(parent->boundingRect()));
+ if (r.isEmpty())
+ return;
+
+ QList<QGraphicsItem *> &children = parent->d_ptr->children;
+ for (int i = 0; i < children.size(); ++i) {
+ QGraphicsItem *item = children.at(i);
+ if (item->d_ptr->hasTransform && !item->transform().isInvertible())
+ continue;
+
+ // Skip invisible items and all their children.
+ if (!item->d_ptr->visible || qFuzzyCompare(item->effectiveOpacity(), qreal(0.0)))
+ continue;
+
+ // ### _q_adjustedRect is only needed because QRectF::intersects,
+ // QRectF::contains and QTransform::map() and friends don't work with
+ // flat rectangles.
+ QRectF br = _q_adjustedRect(item->boundingRect());
+ QRectF mbr = item->mapRectToParent(br);
+ bool keep = false;
+ if (mode >= Qt::ContainsItemBoundingRect) {
+ // Rect intersects/contains item's bounding rect
+ if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr))
+ || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(br))) {
+ items->append(item);
+ keep = true;
+ }
+ } else {
+ // Rect intersects/contains item's shape
+ if (QRectF_intersects(rect, mbr)) {
+ if (path == QPainterPath())
+ path.addRect(rect);
+ if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {
+ items->append(item);
+ keep = true;
+ }
+ }
+ }
+
+ if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
+ // Recurse into children.
+ if (!item->d_ptr->hasTransform || item->transform().type() <= QTransform::TxScale) {
+ // Rect
+ childItems_helper(items, item, item->mapRectFromParent(rect), mode);
+ } else {
+ // Polygon
+ childItems_helper(items, item, item->mapFromParent(rect), mode);
+ }
+ }
+ }
+}
+
+void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
+ const QGraphicsItem *parent,
+ const QPolygonF &polygon,
+ Qt::ItemSelectionMode mode) const
+{
+ QPainterPath path;
+ bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
+ QRectF polyRect = _q_adjustedRect(polygon.boundingRect());
+ QRectF r = !parentClip ? polyRect : polyRect.intersected(_q_adjustedRect(parent->boundingRect()));
+ if (r.isEmpty())
+ return;
+
+ QList<QGraphicsItem *> &children = parent->d_ptr->children;
+ for (int i = 0; i < children.size(); ++i) {
+ QGraphicsItem *item = children.at(i);
+ if (item->d_ptr->hasTransform && !item->transform().isInvertible())
+ continue;
+
+ // Skip invisible items.
+ if (!item->d_ptr->visible || qFuzzyCompare(item->effectiveOpacity() + 1, qreal(1.0)))
+ continue;
+
+ // ### _q_adjustedRect is only needed because QRectF::intersects,
+ // QRectF::contains and QTransform::map() and friends don't work with
+ // flat rectangles.
+ QRectF br = _q_adjustedRect(item->boundingRect());
+ bool keep = false;
+ if (mode >= Qt::ContainsItemBoundingRect) {
+ // Polygon contains/intersects item's bounding rect
+ if (path == QPainterPath())
+ path.addPolygon(polygon);
+ if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br)))
+ || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) {
+ items->append(item);
+ keep = true;
+ }
+ } else {
+ // Polygon contains/intersects item's shape
+ if (QRectF_intersects(polyRect, item->mapRectToParent(br))) {
+ if (path == QPainterPath())
+ path.addPolygon(polygon);
+ if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {
+ items->append(item);
+ keep = true;
+ }
+ }
+ }
+
+ if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
+ // Recurse into children that clip children.
+ childItems_helper(items, item, item->mapFromParent(polygon), mode);
+ }
+ }
+}
+
+void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
+ const QGraphicsItem *parent,
+ const QPainterPath &path,
+ Qt::ItemSelectionMode mode) const
+{
+ bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
+ QPainterPath intersectedPath = !parentClip ? path : path.intersected(parent->shape());
+ if (intersectedPath.isEmpty())
+ return;
+
+ QList<QGraphicsItem *> &children = parent->d_ptr->children;
+ for (int i = 0; i < children.size(); ++i) {
+ QGraphicsItem *item = children.at(i);
+
+ // Skip invisible items.
+ if (!item->d_ptr->visible || qFuzzyCompare(item->effectiveOpacity(), qreal(0.0)))
+ continue;
+
+ QTransform x = item->sceneTransform();
+
+ bool ok;
+ QTransform xinv = x.inverted(&ok);
+ if (ok) {
+ QPainterPath mappedPath = xinv.map(path);
+ if (itemCollidesWithPath(item, mappedPath, mode)) {
+ items->append(item);
+ if (!item->d_ptr->children.isEmpty())
+ childItems_helper(items, item, mappedPath, mode);
+ }
+ }
+ }
+}
+
+void QGraphicsScenePrivate::invalidateSortCache()
+{
+ Q_Q(QGraphicsScene);
+ if (!sortCacheEnabled || updatingSortCache)
+ return;
+
+ updatingSortCache = true;
+ QMetaObject::invokeMethod(q, "_q_updateSortCache", Qt::QueuedConnection);
+}
+
+/*!
+ \internal
+
+ Should not be exported, but we can't change that now.
+ ### Qt 5: Remove symbol / make static
+*/
+inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
+{
+ // Return true if sibling item1 is on top of item2.
+ const QGraphicsItemPrivate *d1 = item1->d_ptr;
+ const QGraphicsItemPrivate *d2 = item2->d_ptr;
+ bool f1 = d1->flags & QGraphicsItem::ItemStacksBehindParent;
+ bool f2 = d2->flags & QGraphicsItem::ItemStacksBehindParent;
+ if (f1 != f2) return f2;
+ qreal z1 = d1->z;
+ qreal z2 = d2->z;
+ return z1 != z2 ? z1 > z2 : item1 > item2;
+}
+
+/*!
+ \internal
+
+ Should not be exported, but we can't change that now.
+*/
+inline bool qt_closestItemFirst(const QGraphicsItem *item1, const QGraphicsItem *item2)
+{
+ return QGraphicsScenePrivate::closestItemFirst_withoutCache(item1, item2);
+}
+
+/*!
+ Returns true if \a item1 is on top of \a item2.
+
+ \internal
+*/
+bool QGraphicsScenePrivate::closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
+{
+ // Siblings? Just check their z-values.
+ const QGraphicsItemPrivate *d1 = item1->d_ptr;
+ const QGraphicsItemPrivate *d2 = item2->d_ptr;
+ if (d1->parent == d2->parent)
+ return qt_closestLeaf(item1, item2);
+
+ // Find common ancestor, and each item's ancestor closest to the common
+ // ancestor.
+ int item1Depth = d1->depth;
+ int item2Depth = d2->depth;
+ const QGraphicsItem *p = item1;
+ const QGraphicsItem *t1 = item1;
+ while (item1Depth > item2Depth && (p = p->d_ptr->parent)) {
+ if (p == item2) {
+ // item2 is one of item1's ancestors; item1 is on top
+ return !(t1->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
+ }
+ t1 = p;
+ --item1Depth;
+ }
+ p = item2;
+ const QGraphicsItem *t2 = item2;
+ while (item2Depth > item1Depth && (p = p->d_ptr->parent)) {
+ if (p == item1) {
+ // item1 is one of item2's ancestors; item1 is not on top
+ return (t2->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
+ }
+ t2 = p;
+ --item2Depth;
+ }
+
+ // item1Ancestor is now at the same level as item2Ancestor, but not the same.
+ const QGraphicsItem *a1 = t1;
+ const QGraphicsItem *a2 = t2;
+ while (a1) {
+ const QGraphicsItem *p1 = a1;
+ const QGraphicsItem *p2 = a2;
+ a1 = a1->parentItem();
+ a2 = a2->parentItem();
+ if (a1 && a1 == a2)
+ return qt_closestLeaf(p1, p2);
+ }
+
+ // No common ancestor? Then just compare the items' toplevels directly.
+ return qt_closestLeaf(t1->topLevelItem(), t2->topLevelItem());
+}
+
+/*!
+ Returns true if \a item2 is on top of \a item1.
+
+ \internal
+*/
+bool QGraphicsScenePrivate::closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
+{
+ return closestItemFirst_withoutCache(item2, item1);
+}
+
+void QGraphicsScenePrivate::climbTree(QGraphicsItem *item, int *stackingOrder)
+{
+ if (!item->d_ptr->children.isEmpty()) {
+ QList<QGraphicsItem *> childList = item->d_ptr->children;
+ qSort(childList.begin(), childList.end(), qt_closestLeaf);
+ for (int i = 0; i < childList.size(); ++i) {
+ QGraphicsItem *item = childList.at(i);
+ if (!(item->flags() & QGraphicsItem::ItemStacksBehindParent))
+ climbTree(childList.at(i), stackingOrder);
+ }
+ item->d_ptr->globalStackingOrder = (*stackingOrder)++;
+ for (int i = 0; i < childList.size(); ++i) {
+ QGraphicsItem *item = childList.at(i);
+ if (item->flags() & QGraphicsItem::ItemStacksBehindParent)
+ climbTree(childList.at(i), stackingOrder);
+ }
+ } else {
+ item->d_ptr->globalStackingOrder = (*stackingOrder)++;
+ }
+}
+
+void QGraphicsScenePrivate::_q_updateSortCache()
+{
+ _q_updateIndex();
+
+ if (!sortCacheEnabled || !updatingSortCache)
+ return;
+
+ updatingSortCache = false;
+ int stackingOrder = 0;
+
+ QList<QGraphicsItem *> topLevels;
+
+ for (int i = 0; i < indexedItems.size(); ++i) {
+ QGraphicsItem *item = indexedItems.at(i);
+ if (item && item->parentItem() == 0)
+ topLevels << item;
+ }
+ for (int i = 0; i < unindexedItems.size(); ++i) {
+ QGraphicsItem *item = unindexedItems.at(i);
+ if (item->parentItem() == 0)
+ topLevels << item;
+ }
+
+ qSort(topLevels.begin(), topLevels.end(), qt_closestLeaf);
+ for (int i = 0; i < topLevels.size(); ++i)
+ climbTree(topLevels.at(i), &stackingOrder);
+}
+
+void QGraphicsScenePrivate::sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order,
+ bool sortCacheEnabled)
+{
+ if (sortCacheEnabled) {
+ if (order == Qt::AscendingOrder) {
+ qSort(itemList->begin(), itemList->end(), closestItemFirst_withCache);
+ } else if (order == Qt::DescendingOrder) {
+ qSort(itemList->begin(), itemList->end(), closestItemLast_withCache);
+ }
+ } else {
+ if (order == Qt::AscendingOrder) {
+ qSort(itemList->begin(), itemList->end(), closestItemFirst_withoutCache);
+ } else if (order == Qt::DescendingOrder) {
+ qSort(itemList->begin(), itemList->end(), closestItemLast_withoutCache);
+ }
+ }
+}
+
+/*!
+ \internal
+
+ Set the font and propagate the changes if the font is different from the
+ current font.
+*/
+void QGraphicsScenePrivate::setFont_helper(const QFont &font)
+{
+ if (this->font == font && this->font.resolve() == font.resolve())
+ return;
+ updateFont(font);
+}
+
+/*!
+ \internal
+
+ Resolve the scene's font against the application font, and propagate the
+ changes too all items in the scene.
+*/
+void QGraphicsScenePrivate::resolveFont()
+{
+ QFont naturalFont = qApp->font();
+ naturalFont.resolve(0);
+ QFont resolvedFont = font.resolve(naturalFont);
+ updateFont(resolvedFont);
+}
+
+/*!
+ \internal
+
+ Update the font, and whether or not it has changed, reresolve all fonts in
+ the scene.
+*/
+void QGraphicsScenePrivate::updateFont(const QFont &font)
+{
+ Q_Q(QGraphicsScene);
+
+ // Update local font setting.
+ this->font = font;
+
+ // Resolve the fonts of all top-level widget items, or widget items
+ // whose parent is not a widget.
+ foreach (QGraphicsItem *item, q->items()) {
+ if (!item->parentItem()) {
+ // Resolvefont for an item is a noop operation, but
+ // every item can be a widget, or can have a widget
+ // childre.
+ item->d_ptr->resolveFont(font.resolve());
+ }
+ }
+
+ // Send the scene a FontChange event.
+ QEvent event(QEvent::FontChange);
+ QApplication::sendEvent(q, &event);
+}
+
+/*!
+ \internal
+
+ Set the palette and propagate the changes if the palette is different from
+ the current palette.
+*/
+void QGraphicsScenePrivate::setPalette_helper(const QPalette &palette)
+{
+ if (this->palette == palette && this->palette.resolve() == palette.resolve())
+ return;
+ updatePalette(palette);
+}
+
+/*!
+ \internal
+
+ Resolve the scene's palette against the application palette, and propagate
+ the changes too all items in the scene.
+*/
+void QGraphicsScenePrivate::resolvePalette()
+{
+ QPalette naturalPalette = qApp->palette();
+ naturalPalette.resolve(0);
+ QPalette resolvedPalette = palette.resolve(naturalPalette);
+ updatePalette(resolvedPalette);
+}
+
+/*!
+ \internal
+
+ Update the palette, and whether or not it has changed, reresolve all
+ palettes in the scene.
+*/
+void QGraphicsScenePrivate::updatePalette(const QPalette &palette)
+{
+ Q_Q(QGraphicsScene);
+
+ // Update local palette setting.
+ this->palette = palette;
+
+ // Resolve the palettes of all top-level widget items, or widget items
+ // whose parent is not a widget.
+ foreach (QGraphicsItem *item, q->items()) {
+ if (!item->parentItem()) {
+ // Resolvefont for an item is a noop operation, but
+ // every item can be a widget, or can have a widget
+ // childre.
+ item->d_ptr->resolvePalette(palette.resolve());
+ }
+ }
+
+ // Send the scene a PaletteChange event.
+ QEvent event(QEvent::PaletteChange);
+ QApplication::sendEvent(q, &event);
+}
+
+/*!
+ Constructs a QGraphicsScene object. The \a parent parameter is
+ passed to QObject's constructor.
+*/
+QGraphicsScene::QGraphicsScene(QObject *parent)
+ : QObject(*new QGraphicsScenePrivate, parent)
+{
+ d_func()->init();
+}
+
+/*!
+ Constructs a QGraphicsScene object, using \a sceneRect for its
+ scene rectangle. The \a parent parameter is passed to QObject's
+ constructor.
+
+ \sa sceneRect
+*/
+QGraphicsScene::QGraphicsScene(const QRectF &sceneRect, QObject *parent)
+ : QObject(*new QGraphicsScenePrivate, parent)
+{
+ setSceneRect(sceneRect);
+ d_func()->init();
+}
+
+/*!
+ Constructs a QGraphicsScene object, using the rectangle specified
+ by (\a x, \a y), and the given \a width and \a height for its
+ scene rectangle. The \a parent parameter is passed to QObject's
+ constructor.
+
+ \sa sceneRect
+*/
+QGraphicsScene::QGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObject *parent)
+ : QObject(*new QGraphicsScenePrivate, parent)
+{
+ setSceneRect(x, y, width, height);
+ d_func()->init();
+}
+
+/*!
+ Destroys the QGraphicsScene object.
+*/
+QGraphicsScene::~QGraphicsScene()
+{
+ Q_D(QGraphicsScene);
+ // Remove this scene from qApp's global scene list.
+ qApp->d_func()->scene_list.removeAll(this);
+
+ clear();
+
+ // Remove this scene from all associated views.
+ for (int j = 0; j < d->views.size(); ++j)
+ d->views.at(j)->setScene(0);
+}
+
+/*!
+ \property QGraphicsScene::sceneRect
+ \brief the scene rectangle; the bounding rectangle of the scene
+
+ The scene rectangle defines the extent of the scene. It is
+ primarily used by QGraphicsView to determine the view's default
+ scrollable area, and by QGraphicsScene to manage item indexing.
+
+ If unset, or if set to a null QRectF, sceneRect() will return the largest
+ bounding rect of all items on the scene since the scene was created (i.e.,
+ a rectangle that grows when items are added to or moved in the scene, but
+ never shrinks).
+
+ \sa width(), height(), QGraphicsView::sceneRect
+*/
+QRectF QGraphicsScene::sceneRect() const
+{
+ Q_D(const QGraphicsScene);
+ const_cast<QGraphicsScenePrivate *>(d)->_q_updateIndex();
+ return d->hasSceneRect ? d->sceneRect : d->growingItemsBoundingRect;
+}
+void QGraphicsScene::setSceneRect(const QRectF &rect)
+{
+ Q_D(QGraphicsScene);
+ if (rect != d->sceneRect) {
+ d->hasSceneRect = !rect.isNull();
+ d->sceneRect = rect;
+ d->resetIndex();
+ emit sceneRectChanged(rect);
+ }
+}
+
+/*!
+ \fn qreal QGraphicsScene::width() const
+
+ This convenience function is equivalent to calling sceneRect().width().
+
+ \sa height()
+*/
+
+/*!
+ \fn qreal QGraphicsScene::height() const
+
+ This convenience function is equivalent to calling \c sceneRect().height().
+
+ \sa width()
+*/
+
+/*!
+ Renders the \a source rect from scene into \a target, using \a painter. This
+ function is useful for capturing the contents of the scene onto a paint
+ device, such as a QImage (e.g., to take a screenshot), or for printing
+ with QPrinter. For example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 1
+
+ If \a source is a null rect, this function will use sceneRect() to
+ determine what to render. If \a target is a null rect, the dimensions of \a
+ painter's paint device will be used.
+
+ The source rect contents will be transformed according to \a
+ aspectRatioMode to fit into the target rect. By default, the aspect ratio
+ is kept, and \a source is scaled to fit in \a target.
+
+ \sa QGraphicsView::render()
+*/
+void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRectF &source,
+ Qt::AspectRatioMode aspectRatioMode)
+{
+ Q_D(QGraphicsScene);
+
+ // Default source rect = scene rect
+ QRectF sourceRect = source;
+ if (sourceRect.isNull())
+ sourceRect = sceneRect();
+
+ // Default target rect = device rect
+ QRectF targetRect = target;
+ if (targetRect.isNull()) {
+ if (painter->device()->devType() == QInternal::Picture)
+ targetRect = sourceRect;
+ else
+ targetRect.setRect(0, 0, painter->device()->width(), painter->device()->height());
+ }
+
+ // Find the ideal x / y scaling ratio to fit \a source into \a target.
+ qreal xratio = targetRect.width() / sourceRect.width();
+ qreal yratio = targetRect.height() / sourceRect.height();
+
+ // Scale according to the aspect ratio mode.
+ switch (aspectRatioMode) {
+ case Qt::KeepAspectRatio:
+ xratio = yratio = qMin(xratio, yratio);
+ break;
+ case Qt::KeepAspectRatioByExpanding:
+ xratio = yratio = qMax(xratio, yratio);
+ break;
+ case Qt::IgnoreAspectRatio:
+ break;
+ }
+
+ // Find all items to draw, and reverse the list (we want to draw
+ // in reverse order).
+ QList<QGraphicsItem *> itemList = items(sourceRect, Qt::IntersectsItemBoundingRect);
+ QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
+ int numItems = itemList.size();
+ for (int i = 0; i < numItems; ++i)
+ itemArray[numItems - i - 1] = itemList.at(i);
+ itemList.clear();
+
+ painter->save();
+
+ // Transform the painter.
+ painter->setClipRect(targetRect);
+ QTransform painterTransform;
+ painterTransform *= QTransform()
+ .translate(targetRect.left(), targetRect.top())
+ .scale(xratio, yratio)
+ .translate(-sourceRect.left(), -sourceRect.top());
+ painter->setWorldTransform(painterTransform, true);
+
+ // Two unit vectors.
+ QLineF v1(0, 0, 1, 0);
+ QLineF v2(0, 0, 0, 1);
+
+ // Generate the style options
+ QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems];
+ for (int i = 0; i < numItems; ++i) {
+ QGraphicsItem *item = itemArray[i];
+
+ QStyleOptionGraphicsItem option;
+ option.state = QStyle::State_None;
+ option.rect = item->boundingRect().toRect();
+ if (item->isSelected())
+ option.state |= QStyle::State_Selected;
+ if (item->isEnabled())
+ option.state |= QStyle::State_Enabled;
+ if (item->hasFocus())
+ option.state |= QStyle::State_HasFocus;
+ if (d->hoverItems.contains(item))
+ option.state |= QStyle::State_MouseOver;
+ if (item == mouseGrabberItem())
+ option.state |= QStyle::State_Sunken;
+
+ // Calculate a simple level-of-detail metric.
+ // ### almost identical code in QGraphicsView::paintEvent()
+ // and QGraphicsView::render() - consider refactoring
+ QTransform itemToDeviceTransform;
+ if (item->d_ptr->itemIsUntransformable()) {
+ itemToDeviceTransform = item->deviceTransform(painterTransform);
+ } else {
+ itemToDeviceTransform = item->sceneTransform() * painterTransform;
+ }
+
+ option.levelOfDetail = qSqrt(itemToDeviceTransform.map(v1).length() * itemToDeviceTransform.map(v2).length());
+ option.matrix = itemToDeviceTransform.toAffine(); //### discards perspective
+
+ option.exposedRect = item->boundingRect();
+ option.exposedRect &= itemToDeviceTransform.inverted().mapRect(targetRect);
+
+ styleOptionArray[i] = option;
+ }
+
+ // Render the scene.
+ drawBackground(painter, sourceRect);
+ drawItems(painter, numItems, itemArray, styleOptionArray);
+ drawForeground(painter, sourceRect);
+
+ delete [] itemArray;
+ delete [] styleOptionArray;
+
+ painter->restore();
+}
+
+/*!
+ \property QGraphicsScene::itemIndexMethod
+ \brief the item indexing method.
+
+ QGraphicsScene applies an indexing algorithm to the scene, to speed up
+ item discovery functions like items() and itemAt(). Indexing is most
+ efficient for static scenes (i.e., where items don't move around). For
+ dynamic scenes, or scenes with many animated items, the index bookkeeping
+ can outweight the fast lookup speeds.
+
+ For the common case, the default index method BspTreeIndex works fine. If
+ your scene uses many animations and you are experiencing slowness, you can
+ disable indexing by calling \c setItemIndexMethod(NoIndex).
+
+ \sa bspTreeDepth
+*/
+QGraphicsScene::ItemIndexMethod QGraphicsScene::itemIndexMethod() const
+{
+ Q_D(const QGraphicsScene);
+ return d->indexMethod;
+}
+void QGraphicsScene::setItemIndexMethod(ItemIndexMethod method)
+{
+ Q_D(QGraphicsScene);
+ d->resetIndex();
+ d->indexMethod = method;
+}
+
+/*!
+ \property QGraphicsScene::bspTreeDepth
+ \brief the depth of QGraphicsScene's BSP index tree
+ \since 4.3
+
+ This property has no effect when NoIndex is used.
+
+ This value determines the depth of QGraphicsScene's BSP tree. The depth
+ directly affects QGraphicsScene's performance and memory usage; the latter
+ growing exponentially with the depth of the tree. With an optimal tree
+ depth, QGraphicsScene can instantly determine the locality of items, even
+ for scenes with thousands or millions of items. This also greatly improves
+ rendering performance.
+
+ By default, the value is 0, in which case Qt will guess a reasonable
+ default depth based on the size, location and number of items in the
+ scene. If these parameters change frequently, however, you may experience
+ slowdowns as QGraphicsScene retunes the depth internally. You can avoid
+ potential slowdowns by fixating the tree depth through setting this
+ property.
+
+ The depth of the tree and the size of the scene rectangle decide the
+ granularity of the scene's partitioning. The size of each scene segment is
+ determined by the following algorithm:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 2
+
+ The BSP tree has an optimal size when each segment contains between 0 and
+ 10 items.
+
+ \sa itemIndexMethod
+*/
+int QGraphicsScene::bspTreeDepth() const
+{
+ Q_D(const QGraphicsScene);
+ return d->bspTreeDepth;
+}
+void QGraphicsScene::setBspTreeDepth(int depth)
+{
+ Q_D(QGraphicsScene);
+ if (d->bspTreeDepth == depth)
+ return;
+
+ if (depth < 0) {
+ qWarning("QGraphicsScene::setBspTreeDepth: invalid depth %d ignored; must be >= 0", depth);
+ return;
+ }
+
+ d->bspTreeDepth = depth;
+ d->resetIndex();
+}
+
+/*!
+ \property QGraphicsScene::sortCacheEnabled
+ \brief whether sort caching is enabled
+ \since 4.5
+
+ When enabled, this property adds a cache that speeds up sorting and
+ transformations for scenes with deep hierarchies (i.e., items with many
+ levels of descendents), at the cost of using more memory (approx. 100 more
+ bytes of memory per item).
+
+ Items that are not part of a deep hierarchy suffer no penalty from this
+ cache.
+*/
+bool QGraphicsScene::isSortCacheEnabled() const
+{
+ Q_D(const QGraphicsScene);
+ return d->sortCacheEnabled;
+}
+void QGraphicsScene::setSortCacheEnabled(bool enabled)
+{
+ Q_D(QGraphicsScene);
+ if (enabled == d->sortCacheEnabled)
+ return;
+ if ((d->sortCacheEnabled = enabled))
+ d->invalidateSortCache();
+}
+
+/*!
+ Calculates and returns the bounding rect of all items on the scene. This
+ function works by iterating over all items, and because if this, it can
+ be slow for large scenes.
+
+ \sa sceneRect()
+*/
+QRectF QGraphicsScene::itemsBoundingRect() const
+{
+ QRectF boundingRect;
+ foreach (QGraphicsItem *item, items())
+ boundingRect |= item->sceneBoundingRect();
+ return boundingRect;
+}
+
+/*!
+ Returns a list of all items on the scene, in no particular order.
+
+ \sa addItem(), removeItem()
+*/
+QList<QGraphicsItem *> QGraphicsScene::items() const
+{
+ Q_D(const QGraphicsScene);
+ const_cast<QGraphicsScenePrivate *>(d)->purgeRemovedItems();
+
+ // If freeItemIndexes is empty, we know there are no holes in indexedItems and
+ // unindexedItems.
+ if (d->freeItemIndexes.isEmpty()) {
+ if (d->unindexedItems.isEmpty())
+ return d->indexedItems;
+ return d->indexedItems + d->unindexedItems;
+ }
+
+ // Rebuild the list of items to avoid holes. ### We could also just
+ // compress the item lists at this point.
+ QList<QGraphicsItem *> itemList;
+ foreach (QGraphicsItem *item, d->indexedItems + d->unindexedItems) {
+ if (item)
+ itemList << item;
+ }
+ return itemList;
+}
+
+/*!
+ Returns all visible items at position \a pos in the scene. The items are
+ listed in descending Z order (i.e., the first item in the list is the
+ top-most item, and the last item is the bottom-most item).
+
+ \sa itemAt()
+*/
+QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const
+{
+ QList<QGraphicsItem *> itemsAtPoint;
+
+ // Find all items within a 1x1 rect area starting at pos. This can be
+ // inefficient for scenes that use small coordinates (like unity
+ // coordinates), or for detailed graphs. ### The index should support
+ // fetching items at a pos to avoid this limitation.
+ foreach (QGraphicsItem *item, items(QRectF(pos, QSizeF(1, 1)), Qt::IntersectsItemBoundingRect)) {
+ if (item->contains(item->mapFromScene(pos)))
+ itemsAtPoint << item;
+ }
+ return itemsAtPoint;
+}
+
+
+/*!
+ \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const
+
+ \overload
+
+ Returns all visible items that, depending on \a mode, are either inside or
+ intersect with the specified \a rectangle.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a rectangle are returned.
+
+ \sa itemAt()
+*/
+QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode) const
+{
+ Q_D(const QGraphicsScene);
+ return d->items_helper(rect, mode, Qt::AscendingOrder);
+}
+
+/*!
+ \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const
+ \since 4.3
+
+ This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode).
+*/
+
+/*!
+ \overload
+
+ Returns all visible items that, depending on \a mode, are either inside or
+ intersect with the polygon \a polygon.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a polygon are returned.
+
+ \sa itemAt()
+*/
+QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const
+{
+ Q_D(const QGraphicsScene);
+ return d->items_helper(polygon, mode, Qt::AscendingOrder);
+}
+
+/*!
+ \overload
+
+ Returns all visible items that, depending on \a path, are either inside or
+ intersect with the path \a path.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a path are returned.
+
+ \sa itemAt()
+*/
+QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
+{
+ Q_D(const QGraphicsScene);
+ return d->items_helper(path, mode, Qt::AscendingOrder);
+}
+
+/*!
+ Returns a list of all items that collide with \a item. Collisions are
+ determined by calling QGraphicsItem::collidesWithItem(); the collision
+ detection is determined by \a mode. By default, all items whose shape
+ intersects \a item or is contained inside \a item's shape are returned.
+
+ The items are returned in descending Z order (i.e., the first item in the
+ list is the top-most item, and the last item is the bottom-most item).
+
+ \sa items(), itemAt(), QGraphicsItem::collidesWithItem()
+*/
+QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item,
+ Qt::ItemSelectionMode mode) const
+{
+ Q_D(const QGraphicsScene);
+ if (!item) {
+ qWarning("QGraphicsScene::collidingItems: cannot find collisions for null item");
+ return QList<QGraphicsItem *>();
+ }
+
+ QList<QGraphicsItem *> tmp;
+ foreach (QGraphicsItem *itemInVicinity, d->estimateItemsInRect(item->sceneBoundingRect())) {
+ if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode))
+ tmp << itemInVicinity;
+ }
+ d->sortItems(&tmp, Qt::AscendingOrder, d->sortCacheEnabled);
+ return tmp;
+}
+
+/*!
+ \fn QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const
+
+ Returns the topmost visible item at the specified \a position, or 0 if
+ there are no items at this position.
+
+ \note The topmost item is the one with the highest Z-value.
+
+ \sa items(), collidingItems(), QGraphicsItem::setZValue()
+*/
+QGraphicsItem *QGraphicsScene::itemAt(const QPointF &pos) const
+{
+ QList<QGraphicsItem *> itemsAtPoint = items(pos);
+ return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
+}
+
+/*!
+ \fn QGraphicsScene::itemAt(qreal x, qreal y) const
+ \overload
+
+ Returns the topmost item at the position specified by (\a x, \a
+ y), or 0 if there are no items at this position.
+
+ This convenience function is equivalent to calling \c
+ {itemAt(QPointF(x, y))}.
+
+ \note The topmost item is the one with the highest Z-value.
+*/
+
+/*!
+ Returns a list of all currently selected items. The items are
+ returned in no particular order.
+
+ \sa setSelectionArea()
+*/
+QList<QGraphicsItem *> QGraphicsScene::selectedItems() const
+{
+ Q_D(const QGraphicsScene);
+
+ // Optimization: Lazily removes items that are not selected.
+ QGraphicsScene *that = const_cast<QGraphicsScene *>(this);
+ QSet<QGraphicsItem *> actuallySelectedSet;
+ foreach (QGraphicsItem *item, that->d_func()->selectedItems) {
+ if (item->isSelected())
+ actuallySelectedSet << item;
+ }
+
+ that->d_func()->selectedItems = actuallySelectedSet;
+
+ return d->selectedItems.values();
+}
+
+/*!
+ Returns the selection area that was previously set with
+ setSelectionArea(), or an empty QPainterPath if no selection area has been
+ set.
+
+ \sa setSelectionArea()
+*/
+QPainterPath QGraphicsScene::selectionArea() const
+{
+ Q_D(const QGraphicsScene);
+ return d->selectionArea;
+}
+
+/*!
+ Sets the selection area to \a path. All items within this area are
+ immediately selected, and all items outside are unselected. You can get
+ the list of all selected items by calling selectedItems().
+
+ For an item to be selected, it must be marked as \e selectable
+ (QGraphicsItem::ItemIsSelectable).
+
+ \sa clearSelection(), selectionArea()
+*/
+void QGraphicsScene::setSelectionArea(const QPainterPath &path)
+{
+ setSelectionArea(path, Qt::IntersectsItemShape);
+}
+
+/*!
+ \overload
+ \since 4.3
+
+ Sets the selection area to \a path using \a mode to determine if items are
+ included in the selection area.
+
+ \sa clearSelection(), selectionArea()
+*/
+void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode)
+{
+ Q_D(QGraphicsScene);
+
+ // Note: with boolean path operations, we can improve performance here
+ // quite a lot by "growing" the old path instead of replacing it. That
+ // allows us to only check the intersect area for changes, instead of
+ // reevaluating the whole path over again.
+ d->selectionArea = path;
+
+ QSet<QGraphicsItem *> unselectItems = d->selectedItems;
+
+ // Disable emitting selectionChanged() for individual items.
+ ++d->selectionChanging;
+ bool changed = false;
+
+ // Set all items in path to selected.
+ foreach (QGraphicsItem *item, items(path, mode)) {
+ if (item->flags() & QGraphicsItem::ItemIsSelectable) {
+ if (!item->isSelected())
+ changed = true;
+ unselectItems.remove(item);
+ item->setSelected(true);
+ }
+ }
+
+ // Unselect all items outside path.
+ foreach (QGraphicsItem *item, unselectItems) {
+ item->setSelected(false);
+ changed = true;
+ }
+
+ // Reenable emitting selectionChanged() for individual items.
+ --d->selectionChanging;
+
+ if (!d->selectionChanging && changed)
+ emit selectionChanged();
+}
+
+/*!
+ Clears the current selection.
+
+ \sa setSelectionArea(), selectedItems()
+*/
+void QGraphicsScene::clearSelection()
+{
+ Q_D(QGraphicsScene);
+
+ // Disable emitting selectionChanged
+ ++d->selectionChanging;
+ bool changed = !d->selectedItems.isEmpty();
+
+ foreach (QGraphicsItem *item, d->selectedItems)
+ item->setSelected(false);
+ d->selectedItems.clear();
+
+ // Reenable emitting selectionChanged() for individual items.
+ --d->selectionChanging;
+
+ if (!d->selectionChanging && changed)
+ emit selectionChanged();
+}
+
+/*!
+ \since 4.4
+
+ Removes and deletes all items from the scene, but otherwise leaves the
+ state of the scene unchanged.
+
+ \sa addItem()
+*/
+void QGraphicsScene::clear()
+{
+ Q_D(QGraphicsScene);
+ // Recursive descent delete
+ for (int i = 0; i < d->indexedItems.size(); ++i) {
+ if (QGraphicsItem *item = d->indexedItems.at(i)) {
+ if (!item->parentItem())
+ delete item;
+ }
+ }
+ QList<QGraphicsItem *> unindexedParents;
+ for (int i = 0; i < d->unindexedItems.size(); ++i) {
+ QGraphicsItem *item = d->unindexedItems.at(i);
+ if (!item->parentItem())
+ unindexedParents << item;
+ }
+ d->unindexedItems.clear();
+ qDeleteAll(unindexedParents);
+
+ d->indexedItems.clear();
+ d->freeItemIndexes.clear();
+ d->lastItemCount = 0;
+ d->bspTree.clear();
+ d->largestUntransformableItem = QRectF();
+}
+
+/*!
+ Groups all items in \a items into a new QGraphicsItemGroup, and returns a
+ pointer to the group. The group is created with the common ancestor of \a
+ items as its parent, and with position (0, 0). The items are all
+ reparented to the group, and their positions and transformations are
+ mapped to the group. If \a items is empty, this function will return an
+ empty top-level QGraphicsItemGroup.
+
+ QGraphicsScene has ownership of the group item; you do not need to delete
+ it. To dismantle (ungroup) a group, call destroyItemGroup().
+
+ \sa destroyItemGroup(), QGraphicsItemGroup::addToGroup()
+*/
+QGraphicsItemGroup *QGraphicsScene::createItemGroup(const QList<QGraphicsItem *> &items)
+{
+ // Build a list of the first item's ancestors
+ QList<QGraphicsItem *> ancestors;
+ int n = 0;
+ if (!items.isEmpty()) {
+ QGraphicsItem *parent = items.at(n++);
+ while ((parent = parent->parentItem()))
+ ancestors.append(parent);
+ }
+
+ // Find the common ancestor for all items
+ QGraphicsItem *commonAncestor = 0;
+ if (!ancestors.isEmpty()) {
+ while (n < items.size()) {
+ int commonIndex = -1;
+ QGraphicsItem *parent = items.at(n++);
+ do {
+ int index = ancestors.indexOf(parent, qMax(0, commonIndex));
+ if (index != -1) {
+ commonIndex = index;
+ break;
+ }
+ } while ((parent = parent->parentItem()));
+
+ if (commonIndex == -1) {
+ commonAncestor = 0;
+ break;
+ }
+
+ commonAncestor = ancestors.at(commonIndex);
+ }
+ }
+
+ // Create a new group at that level
+ QGraphicsItemGroup *group = new QGraphicsItemGroup(commonAncestor);
+ if (!commonAncestor)
+ addItem(group);
+ foreach (QGraphicsItem *item, items)
+ group->addToGroup(item);
+ return group;
+}
+
+/*!
+ Reparents all items in \a group to \a group's parent item, then removes \a
+ group from the scene, and finally deletes it. The items' positions and
+ transformations are mapped from the group to the group's parent.
+
+ \sa createItemGroup(), QGraphicsItemGroup::removeFromGroup()
+*/
+void QGraphicsScene::destroyItemGroup(QGraphicsItemGroup *group)
+{
+ foreach (QGraphicsItem *item, group->children())
+ group->removeFromGroup(item);
+ removeItem(group);
+ delete group;
+}
+
+/*!
+ Adds or moves the item \a item and all its childen to the scene.
+
+ If the item is visible (i.e., QGraphicsItem::isVisible() returns
+ true), QGraphicsScene will emit changed() once control goes back
+ to the event loop.
+
+ If the item is already in a different scene, it will first be removed from
+ its old scene, and then added to this scene as a top-level.
+
+ QGraphicsScene will send ItemSceneChange notifications to \a item while
+ it is added to the scene. If item does not currently belong to a scene, only one
+ notification is sent. If it does belong to scene already (i.e., it is
+ moved to this scene), QGraphicsScene will send an addition notification as
+ the item is removed from its previous scene.
+
+ \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(),
+ addRect(), addText(), addWidget()
+*/
+void QGraphicsScene::addItem(QGraphicsItem *item)
+{
+ Q_D(QGraphicsScene);
+ if (!item) {
+ qWarning("QGraphicsScene::addItem: cannot add null item");
+ return;
+ }
+ if (item->scene() == this) {
+ qWarning("QGraphicsScene::addItem: item has already been added to this scene");
+ return;
+ }
+
+ // Remove this item from its existing scene
+ if (QGraphicsScene *oldScene = item->scene())
+ oldScene->removeItem(item);
+
+ // Notify the item that its scene is changing, and allow the item to
+ // react.
+ QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(item->itemChange(QGraphicsItem::ItemSceneChange,
+ qVariantFromValue<QGraphicsScene *>(this)));
+ if (targetScene != this) {
+ if (targetScene && item->scene() != targetScene)
+ targetScene->addItem(item);
+ return;
+ }
+
+ // Prevent reusing a recently deleted pointer: purge all removed items
+ // from our lists.
+ d->purgeRemovedItems();
+
+ // Invalidate any sort caching; arrival of a new item means we need to
+ // resort.
+ d->invalidateSortCache();
+
+ // Detach this item from its parent if the parent's scene is different
+ // from this scene.
+ if (QGraphicsItem *itemParent = item->parentItem()) {
+ if (itemParent->scene() != this)
+ item->setParentItem(0);
+ }
+
+ // Add the item to this scene
+ item->d_func()->scene = targetScene;
+
+ // Indexing requires sceneBoundingRect(), but because \a item might
+ // not be completely constructed at this point, we need to store it in
+ // a temporary list and schedule an indexing for later.
+ d->unindexedItems << item;
+ item->d_func()->index = -1;
+ d->startIndexTimer();
+
+ // Update the scene's sort cache settings.
+ item->d_ptr->globalStackingOrder = -1;
+ d->invalidateSortCache();
+
+ // Add to list of items that require an update. We cannot assume that the
+ // item is fully constructed, so calling item->update() can lead to a pure
+ // virtual function call to boundingRect().
+ if (!d->updateAll) {
+ if (d->pendingUpdateItems.isEmpty())
+ QMetaObject::invokeMethod(this, "_q_updateLater", Qt::QueuedConnection);
+ d->pendingUpdateItems << item;
+ }
+
+ // Disable selectionChanged() for individual items
+ ++d->selectionChanging;
+ int oldSelectedItemSize = d->selectedItems.size();
+
+ // Update selection lists
+ if (item->isSelected())
+ d->selectedItems << item;
+ if (item->isWidget() && item->isVisible() && static_cast<QGraphicsWidget *>(item)->windowType() == Qt::Popup)
+ d->addPopup(static_cast<QGraphicsWidget *>(item));
+
+ // Update creation order focus chain. Make sure to leave the widget's
+ // internal tab order intact.
+ if (item->isWidget()) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
+ if (!d->tabFocusFirst) {
+ // No first tab focus widget - make this the first tab focus
+ // widget.
+ d->tabFocusFirst = widget;
+ } else if (!widget->parentWidget()) {
+ // Adding a widget that is not part of a tab focus chain.
+ QGraphicsWidget *last = d->tabFocusFirst->d_func()->focusPrev;
+ QGraphicsWidget *lastNew = widget->d_func()->focusPrev;
+ last->d_func()->focusNext = widget;
+ widget->d_func()->focusPrev = last;
+ d->tabFocusFirst->d_func()->focusPrev = lastNew;
+ lastNew->d_func()->focusNext = d->tabFocusFirst;
+ }
+ }
+
+ // Add all children recursively
+ foreach (QGraphicsItem *child, item->children())
+ addItem(child);
+
+ // Resolve font and palette.
+ item->d_ptr->resolveFont(d->font.resolve());
+ item->d_ptr->resolvePalette(d->palette.resolve());
+
+ if (!item->d_ptr->explicitlyHidden) {
+ if (d->unpolishedItems.isEmpty())
+ QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection);
+ d->unpolishedItems << item;
+ }
+
+ // Reenable selectionChanged() for individual items
+ --d->selectionChanging;
+ if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemSize)
+ emit selectionChanged();
+
+ // Deliver post-change notification
+ item->itemChange(QGraphicsItem::ItemSceneHasChanged, qVariantFromValue<QGraphicsScene *>(this));
+}
+
+/*!
+ Creates and adds an ellipse item to the scene, and returns the item
+ pointer. The geometry of the ellipse is defined by \a rect, and its pen
+ and brush are initialized to \a pen and \a brush.
+
+ Note that the item's geometry is provided in item coordinates, and its
+ position is initialized to (0, 0).
+
+ If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
+ QGraphicsScene will emit changed() once control goes back to the event
+ loop.
+
+ \sa addLine(), addPath(), addPixmap(), addRect(), addText(), addItem(),
+ addWidget()
+*/
+QGraphicsEllipseItem *QGraphicsScene::addEllipse(const QRectF &rect, const QPen &pen, const QBrush &brush)
+{
+ QGraphicsEllipseItem *item = new QGraphicsEllipseItem(rect);
+ item->setPen(pen);
+ item->setBrush(brush);
+ addItem(item);
+ return item;
+}
+
+/*!
+ \fn QGraphicsEllipseItem *QGraphicsScene::addEllipse(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
+ \since 4.3
+
+ This convenience function is equivalent to calling addEllipse(QRectF(\a x,
+ \a y, \a w, \a h), \a pen, \a brush).
+*/
+
+/*!
+ Creates and adds a line item to the scene, and returns the item
+ pointer. The geometry of the line is defined by \a line, and its pen
+ is initialized to \a pen.
+
+ Note that the item's geometry is provided in item coordinates, and its
+ position is initialized to (0, 0).
+
+ If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
+ QGraphicsScene will emit changed() once control goes back to the event
+ loop.
+
+ \sa addEllipse(), addPath(), addPixmap(), addRect(), addText(), addItem(),
+ addWidget()
+*/
+QGraphicsLineItem *QGraphicsScene::addLine(const QLineF &line, const QPen &pen)
+{
+ QGraphicsLineItem *item = new QGraphicsLineItem(line);
+ item->setPen(pen);
+ addItem(item);
+ return item;
+}
+
+/*!
+ \fn QGraphicsLineItem *QGraphicsScene::addLine(qreal x1, qreal y1, qreal x2, qreal y2, const QPen &pen)
+ \since 4.3
+
+ This convenience function is equivalent to calling addLine(QLineF(\a x1,
+ \a y1, \a x2, \a y2), \a pen).
+*/
+
+/*!
+ Creates and adds a path item to the scene, and returns the item
+ pointer. The geometry of the path is defined by \a path, and its pen and
+ brush are initialized to \a pen and \a brush.
+
+ Note that the item's geometry is provided in item coordinates, and its
+ position is initialized to (0, 0).
+
+ If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
+ QGraphicsScene will emit changed() once control goes back to the event
+ loop.
+
+ \sa addEllipse(), addLine(), addPixmap(), addRect(), addText(), addItem(),
+ addWidget()
+*/
+QGraphicsPathItem *QGraphicsScene::addPath(const QPainterPath &path, const QPen &pen, const QBrush &brush)
+{
+ QGraphicsPathItem *item = new QGraphicsPathItem(path);
+ item->setPen(pen);
+ item->setBrush(brush);
+ addItem(item);
+ return item;
+}
+
+/*!
+ Creates and adds a pixmap item to the scene, and returns the item
+ pointer. The pixmap is defined by \a pixmap.
+
+ Note that the item's geometry is provided in item coordinates, and its
+ position is initialized to (0, 0).
+
+ If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
+ QGraphicsScene will emit changed() once control goes back to the event
+ loop.
+
+ \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
+ addWidget()
+*/
+QGraphicsPixmapItem *QGraphicsScene::addPixmap(const QPixmap &pixmap)
+{
+ QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
+ addItem(item);
+ return item;
+}
+
+/*!
+ Creates and adds a polygon item to the scene, and returns the item
+ pointer. The polygon is defined by \a polygon, and its pen and
+ brush are initialized to \a pen and \a brush.
+
+ Note that the item's geometry is provided in item coordinates, and its
+ position is initialized to (0, 0).
+
+ If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
+ QGraphicsScene will emit changed() once control goes back to the event
+ loop.
+
+ \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
+ addWidget()
+*/
+QGraphicsPolygonItem *QGraphicsScene::addPolygon(const QPolygonF &polygon,
+ const QPen &pen, const QBrush &brush)
+{
+ QGraphicsPolygonItem *item = new QGraphicsPolygonItem(polygon);
+ item->setPen(pen);
+ item->setBrush(brush);
+ addItem(item);
+ return item;
+}
+
+/*!
+ Creates and adds a rectangle item to the scene, and returns the item
+ pointer. The geometry of the rectangle is defined by \a rect, and its pen
+ and brush are initialized to \a pen and \a brush.
+
+ Note that the item's geometry is provided in item coordinates, and its
+ position is initialized to (0, 0). For example, if a QRect(50, 50, 100,
+ 100) is added, its top-left corner will be at (50, 50) relative to the
+ origin in the items coordinate system.
+
+ If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
+ QGraphicsScene will emit changed() once control goes back to the event
+ loop.
+
+ \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addText(),
+ addItem(), addWidget()
+*/
+QGraphicsRectItem *QGraphicsScene::addRect(const QRectF &rect, const QPen &pen, const QBrush &brush)
+{
+ QGraphicsRectItem *item = new QGraphicsRectItem(rect);
+ item->setPen(pen);
+ item->setBrush(brush);
+ addItem(item);
+ return item;
+}
+
+/*!
+ \fn QGraphicsRectItem *QGraphicsScene::addRect(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
+ \since 4.3
+
+ This convenience function is equivalent to calling addRect(QRectF(\a x,
+ \a y, \a w, \a h), \a pen, \a brush).
+*/
+
+/*!
+ Creates and adds a text item to the scene, and returns the item
+ pointer. The text string is initialized to \a text, and its font
+ is initialized to \a font.
+
+ The item's position is initialized to (0, 0).
+
+ If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
+ QGraphicsScene will emit changed() once control goes back to the event
+ loop.
+
+ \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
+ addItem(), addWidget()
+*/
+QGraphicsTextItem *QGraphicsScene::addText(const QString &text, const QFont &font)
+{
+ QGraphicsTextItem *item = new QGraphicsTextItem(text);
+ item->setFont(font);
+ addItem(item);
+ return item;
+}
+
+/*!
+ Creates and adds a QGraphicsSimpleTextItem to the scene, and returns the
+ item pointer. The text string is initialized to \a text, and its font is
+ initialized to \a font.
+
+ The item's position is initialized to (0, 0).
+
+ If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
+ QGraphicsScene will emit changed() once control goes back to the event
+ loop.
+
+ \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
+ addItem(), addWidget()
+*/
+QGraphicsSimpleTextItem *QGraphicsScene::addSimpleText(const QString &text, const QFont &font)
+{
+ QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem(text);
+ item->setFont(font);
+ addItem(item);
+ return item;
+}
+
+/*!
+ Creates a new QGraphicsProxyWidget for \a widget, adds it to the scene,
+ and returns a pointer to the proxy. \a wFlags set the default window flags
+ for the embedding proxy widget.
+
+ The item's position is initialized to (0, 0).
+
+ If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
+ QGraphicsScene will emit changed() once control goes back to the event
+ loop.
+
+ Note that widgets with the Qt::WA_PaintOnScreen widget attribute
+ set and widgets that wrap an external application or controller
+ are not supported. Examples are QGLWidget and QAxWidget.
+
+ \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
+ addText(), addSimpleText(), addItem()
+*/
+QGraphicsProxyWidget *QGraphicsScene::addWidget(QWidget *widget, Qt::WindowFlags wFlags)
+{
+ QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(0, wFlags);
+ proxy->setWidget(widget);
+ addItem(proxy);
+ return proxy;
+}
+
+/*!
+ Removes the item \a item and all its children from the scene. The
+ ownership of \a item is passed on to the caller (i.e.,
+ QGraphicsScene will no longer delete \a item when destroyed).
+
+ \sa addItem()
+*/
+void QGraphicsScene::removeItem(QGraphicsItem *item)
+{
+ // ### Refactoring: This function shares much functionality with _q_removeItemLater()
+ Q_D(QGraphicsScene);
+ if (!item) {
+ qWarning("QGraphicsScene::removeItem: cannot remove 0-item");
+ return;
+ }
+ if (item->scene() != this) {
+ qWarning("QGraphicsScene::removeItem: item %p's scene (%p)"
+ " is different from this scene (%p)",
+ item, item->scene(), this);
+ return;
+ }
+
+ // Notify the item that it's scene is changing to 0, allowing the item to
+ // react.
+ QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(item->itemChange(QGraphicsItem::ItemSceneChange,
+ qVariantFromValue<QGraphicsScene *>(0)));
+ if (targetScene != 0 && targetScene != this) {
+ targetScene->addItem(item);
+ return;
+ }
+
+ // If the item has focus, remove it (and any focusWidget reference).
+ item->clearFocus();
+
+ // Clear its background
+ item->update();
+
+ // Note: This will access item's sceneBoundingRect(), which (as this is
+ // C++) is why we cannot call removeItem() from QGraphicsItem's
+ // destructor.
+ d->removeFromIndex(item);
+
+ if (item == d->tabFocusFirst) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
+ widget->d_func()->fixFocusChainBeforeReparenting(0, 0);
+ }
+ // Set the item's scene ptr to 0.
+ item->d_func()->scene = 0;
+
+ // Detach the item from its parent.
+ if (QGraphicsItem *parentItem = item->parentItem()) {
+ if (parentItem->scene()) {
+ Q_ASSERT_X(parentItem->scene() == this, "QGraphicsScene::removeItem",
+ "Parent item's scene is different from this item's scene");
+ item->setParentItem(0);
+ }
+ }
+
+ // Remove from our item lists.
+ int index = item->d_func()->index;
+ if (index != -1) {
+ d->freeItemIndexes << index;
+ d->indexedItems[index] = 0;
+ } else {
+ d->unindexedItems.removeAll(item);
+ }
+
+ // Remove from scene transform cache
+ int transformIndex = item->d_func()->sceneTransformIndex;
+ if (transformIndex != -1) {
+ d->validTransforms.setBit(transformIndex, 0);
+ d->freeSceneTransformSlots.append(transformIndex);
+ item->d_func()->sceneTransformIndex = -1;
+ }
+
+ if (item == d->focusItem)
+ d->focusItem = 0;
+ if (item == d->lastFocusItem)
+ d->lastFocusItem = 0;
+ if (item == d->activeWindow) {
+ // ### deactivate...
+ d->activeWindow = 0;
+ }
+
+ // Disable selectionChanged() for individual items
+ ++d->selectionChanging;
+ int oldSelectedItemsSize = d->selectedItems.size();
+
+ // Update selected & hovered item bookkeeping
+ d->selectedItems.remove(item);
+ d->hoverItems.removeAll(item);
+ d->pendingUpdateItems.removeAll(item);
+ d->cachedItemsUnderMouse.removeAll(item);
+ d->unpolishedItems.removeAll(item);
+ d->dirtyItems.removeAll(item);
+
+ //Ensure dirty flag have the correct default value so the next time it will be added it will receive updates
+ item->d_func()->dirty = 0;
+ item->d_func()->dirtyChildren = 0;
+
+ // Remove all children recursively
+ foreach (QGraphicsItem *child, item->children())
+ removeItem(child);
+
+ // Reset the mouse grabber and focus item data.
+ if (d->mouseGrabberItems.contains(item))
+ d->ungrabMouse(item);
+
+ // Reset the keyboard grabber
+ if (d->keyboardGrabberItems.contains(item))
+ item->ungrabKeyboard();
+
+ // Reset the last mouse grabber item
+ if (item == d->lastMouseGrabberItem)
+ d->lastMouseGrabberItem = 0;
+
+ // Reenable selectionChanged() for individual items
+ --d->selectionChanging;
+
+ if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemsSize)
+ emit selectionChanged();
+
+ // Deliver post-change notification
+ item->itemChange(QGraphicsItem::ItemSceneHasChanged, qVariantFromValue<QGraphicsScene *>(0));
+}
+
+/*!
+ Returns the scene's current focus item, or 0 if no item currently has
+ focus.
+
+ The focus item receives keyboard input when the scene receives a
+ key event.
+
+ \sa setFocusItem(), QGraphicsItem::hasFocus()
+*/
+QGraphicsItem *QGraphicsScene::focusItem() const
+{
+ Q_D(const QGraphicsScene);
+ return d->focusItem;
+}
+
+/*!
+ Sets the scene's focus item to \a item, with the focus reason \a
+ focusReason, after removing focus from any previous item that may have had
+ focus.
+
+ If \a item is 0, or if it either does not accept focus (i.e., it does not
+ have the QGraphicsItem::ItemIsFocusable flag enabled), or is not visible
+ or not enabled, this function only removes focus from any previous
+ focusitem.
+
+ If item is not 0, and the scene does not currently have focus (i.e.,
+ hasFocus() returns false), this function will call setFocus()
+ automatically.
+
+ \sa focusItem(), hasFocus(), setFocus()
+*/
+void QGraphicsScene::setFocusItem(QGraphicsItem *item, Qt::FocusReason focusReason)
+{
+ Q_D(QGraphicsScene);
+ if (item == d->focusItem)
+ return;
+ if (item && (!(item->flags() & QGraphicsItem::ItemIsFocusable)
+ || !item->isVisible() || !item->isEnabled())) {
+ item = 0;
+ }
+
+ if (item) {
+ setFocus(focusReason);
+ if (item == d->focusItem)
+ return;
+ }
+
+ if (d->focusItem) {
+ QFocusEvent event(QEvent::FocusOut, focusReason);
+ d->lastFocusItem = d->focusItem;
+ d->focusItem = 0;
+ d->sendEvent(d->lastFocusItem, &event);
+ }
+
+ if (item) {
+ if (item->isWidget()) {
+ // Update focus child chain.
+ static_cast<QGraphicsWidget *>(item)->d_func()->setFocusWidget();
+ }
+
+ d->focusItem = item;
+ QFocusEvent event(QEvent::FocusIn, focusReason);
+ d->sendEvent(item, &event);
+ }
+}
+
+/*!
+ Returns true if the scene has focus; otherwise returns false. If the scene
+ has focus, it will will forward key events from QKeyEvent to any item that
+ has focus.
+
+ \sa setFocus(), setFocusItem()
+*/
+bool QGraphicsScene::hasFocus() const
+{
+ Q_D(const QGraphicsScene);
+ return d->hasFocus;
+}
+
+/*!
+ Sets focus on the scene by sending a QFocusEvent to the scene, passing \a
+ focusReason as the reason. If the scene regains focus after having
+ previously lost it while an item had focus, the last focus item will
+ receive focus with \a focusReason as the reason.
+
+ If the scene already has focus, this function does nothing.
+
+ \sa hasFocus(), clearFocus(), setFocusItem()
+*/
+void QGraphicsScene::setFocus(Qt::FocusReason focusReason)
+{
+ Q_D(QGraphicsScene);
+ if (d->hasFocus)
+ return;
+ QFocusEvent event(QEvent::FocusIn, focusReason);
+ QCoreApplication::sendEvent(this, &event);
+}
+
+/*!
+ Clears focus from the scene. If any item has focus when this function is
+ called, it will lose focus, and regain focus again once the scene regains
+ focus.
+
+ A scene that does not have focus ignores key events.
+
+ \sa hasFocus(), setFocus(), setFocusItem()
+*/
+void QGraphicsScene::clearFocus()
+{
+ Q_D(QGraphicsScene);
+ if (d->hasFocus) {
+ d->hasFocus = false;
+ setFocusItem(0, Qt::OtherFocusReason);
+ }
+}
+
+/*!
+ \property QGraphicsScene::stickyFocus
+ \brief whether or not clicking the scene will clear focus
+
+ If this property is false (the default), then clicking on the scene
+ background or on an item that does not accept focus, will clear
+ focus. Otherwise, focus will remain unchanged.
+
+ The focus change happens in response to a mouse press. You can reimplement
+ mousePressEvent() in a subclass of QGraphicsScene to toggle this property
+ based on where the user has clicked.
+
+ \sa clearFocus(), setFocusItem()
+*/
+void QGraphicsScene::setStickyFocus(bool enabled)
+{
+ Q_D(QGraphicsScene);
+ d->stickyFocus = enabled;
+}
+bool QGraphicsScene::stickyFocus() const
+{
+ Q_D(const QGraphicsScene);
+ return d->stickyFocus;
+}
+
+/*!
+ Returns the current mouse grabber item, or 0 if no item is currently
+ grabbing the mouse. The mouse grabber item is the item that receives all
+ mouse events sent to the scene.
+
+ An item becomes a mouse grabber when it receives and accepts a
+ mouse press event, and it stays the mouse grabber until either of
+ the following events occur:
+
+ \list
+ \o If the item receives a mouse release event when there are no other
+ buttons pressed, it loses the mouse grab.
+ \o If the item becomes invisible (i.e., someone calls \c {item->setVisible(false))},
+ or if it becomes disabled (i.e., someone calls \c {item->setEnabled(false))},
+ it loses the mouse grab.
+ \o If the item is removed from the scene, it loses the mouse grab.
+ \endlist
+
+ If the item loses its mouse grab, the scene will ignore all mouse events
+ until a new item grabs the mouse (i.e., until a new item receives a mouse
+ press event).
+*/
+QGraphicsItem *QGraphicsScene::mouseGrabberItem() const
+{
+ Q_D(const QGraphicsScene);
+ return !d->mouseGrabberItems.isEmpty() ? d->mouseGrabberItems.last() : 0;
+}
+
+/*!
+ \property QGraphicsScene::backgroundBrush
+ \brief the background brush of the scene.
+
+ Set this property to changes the scene's background to a different color,
+ gradient or texture. The default background brush is Qt::NoBrush. The
+ background is drawn before (behind) the items.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 3
+
+ QGraphicsScene::render() calls drawBackground() to draw the scene
+ background. For more detailed control over how the background is drawn,
+ you can reimplement drawBackground() in a subclass of QGraphicsScene.
+*/
+QBrush QGraphicsScene::backgroundBrush() const
+{
+ Q_D(const QGraphicsScene);
+ return d->backgroundBrush;
+}
+void QGraphicsScene::setBackgroundBrush(const QBrush &brush)
+{
+ Q_D(QGraphicsScene);
+ d->backgroundBrush = brush;
+ foreach (QGraphicsView *view, d->views) {
+ view->resetCachedContent();
+ view->viewport()->update();
+ }
+ update();
+}
+
+/*!
+ \property QGraphicsScene::foregroundBrush
+ \brief the foreground brush of the scene.
+
+ Change this property to set the scene's foreground to a different
+ color, gradient or texture.
+
+ The foreground is drawn after (on top of) the items. The default
+ foreground brush is Qt::NoBrush ( i.e. the foreground is not
+ drawn).
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 4
+
+ QGraphicsScene::render() calls drawForeground() to draw the scene
+ foreground. For more detailed control over how the foreground is
+ drawn, you can reimplement the drawForeground() function in a
+ QGraphicsScene subclass.
+*/
+QBrush QGraphicsScene::foregroundBrush() const
+{
+ Q_D(const QGraphicsScene);
+ return d->foregroundBrush;
+}
+void QGraphicsScene::setForegroundBrush(const QBrush &brush)
+{
+ Q_D(QGraphicsScene);
+ d->foregroundBrush = brush;
+ foreach (QGraphicsView *view, views())
+ view->viewport()->update();
+ update();
+}
+
+/*!
+ This method is used by input methods to query a set of properties of
+ the scene to be able to support complex input method operations as support
+ for surrounding text and reconversions.
+
+ The \a query parameter specifies which property is queried.
+
+ \sa QWidget::inputMethodQuery()
+*/
+QVariant QGraphicsScene::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QGraphicsScene);
+ if (!d->focusItem)
+ return QVariant();
+ const QTransform matrix = d->focusItem->sceneTransform();
+ QVariant value = d->focusItem->inputMethodQuery(query);
+ if (value.type() == QVariant::RectF)
+ value = matrix.mapRect(value.toRectF());
+ else if (value.type() == QVariant::PointF)
+ value = matrix.map(value.toPointF());
+ else if (value.type() == QVariant::Rect)
+ value = matrix.mapRect(value.toRect());
+ else if (value.type() == QVariant::Point)
+ value = matrix.map(value.toPoint());
+ return value;
+}
+
+/*!
+ \fn void QGraphicsScene::update(const QRectF &rect)
+ Schedules a redraw of the area \a rect on the scene.
+
+ \sa sceneRect(), changed()
+*/
+void QGraphicsScene::update(const QRectF &rect)
+{
+ Q_D(QGraphicsScene);
+ if (d->updateAll)
+ return;
+
+ // Check if anyone's connected; if not, we can send updates directly to
+ // the views. Otherwise or if there are no views, use old behavior.
+ bool directUpdates = !(d->connectedSignals & d->changedSignalMask) && !d->views.isEmpty();
+ if (rect.isNull()) {
+ d->updateAll = true;
+ d->updatedRects.clear();
+ if (directUpdates) {
+ // Update all views.
+ for (int i = 0; i < d->views.size(); ++i)
+ d->views.at(i)->d_func()->updateAll();
+ }
+ } else {
+ if (directUpdates) {
+ // Update all views.
+ for (int i = 0; i < d->views.size(); ++i) {
+ QGraphicsView *view = d->views.at(i);
+ view->d_func()->updateRegion(QRegion(view->mapFromScene(rect).boundingRect()));
+ }
+ } else {
+ d->updatedRects << rect;
+ }
+ }
+
+ if (!directUpdates && !d->calledEmitUpdated) {
+ d->calledEmitUpdated = true;
+ QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection);
+ }
+}
+
+/*!
+ \fn void QGraphicsScene::update(qreal x, qreal y, qreal w, qreal h)
+ \overload
+ \since 4.3
+
+ This function is equivalent to calling update(QRectF(\a x, \a y, \a w,
+ \a h));
+*/
+
+/*!
+ Invalidates and schedules a redraw of the \a layers in \a rect on the
+ scene. Any cached content in \a layers is unconditionally invalidated and
+ redrawn.
+
+ You can use this function overload to notify QGraphicsScene of changes to
+ the background or the foreground of the scene. This function is commonly
+ used for scenes with tile-based backgrounds to notify changes when
+ QGraphicsView has enabled
+ \l{QGraphicsView::CacheBackground}{CacheBackground}.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 5
+
+ Note that QGraphicsView currently supports background caching only (see
+ QGraphicsView::CacheBackground). This function is equivalent to calling
+ update() if any layer but BackgroundLayer is passed.
+
+ \sa QGraphicsView::resetCachedContent()
+*/
+void QGraphicsScene::invalidate(const QRectF &rect, SceneLayers layers)
+{
+ foreach (QGraphicsView *view, views())
+ view->invalidateScene(rect, layers);
+ update(rect);
+}
+
+/*!
+ \fn void QGraphicsScene::invalidate(qreal x, qreal y, qreal w, qreal h, SceneLayers layers)
+ \overload
+ \since 4.3
+
+ This convenience function is equivalent to calling invalidate(QRectF(\a x, \a
+ y, \a w, \a h), \a layers);
+*/
+
+/*!
+ Returns a list of all the views that display this scene.
+
+ \sa QGraphicsView::scene()
+*/
+QList <QGraphicsView *> QGraphicsScene::views() const
+{
+ Q_D(const QGraphicsScene);
+ return d->views;
+}
+
+/*!
+ This slot \e advances the scene by one step, by calling
+ QGraphicsItem::advance() for all items on the scene. This is done in two
+ phases: in the first phase, all items are notified that the scene is about
+ to change, and in the second phase all items are notified that they can
+ move. In the first phase, QGraphicsItem::advance() is called passing a
+ value of 0 as an argument, and 1 is passed in the second phase.
+
+ \sa QGraphicsItem::advance(), QGraphicsItemAnimation, QTimeLine
+*/
+void QGraphicsScene::advance()
+{
+ for (int i = 0; i < 2; ++i) {
+ foreach (QGraphicsItem *item, items())
+ item->advance(i);
+ }
+}
+
+/*!
+ Processes the event \a event, and dispatches it to the respective
+ event handlers.
+
+ In addition to calling the convenience event handlers, this
+ function is responsible for converting mouse move events to hover
+ events for when there is no mouse grabber item. Hover events are
+ delivered directly to items; there is no convenience function for
+ them.
+
+ Unlike QWidget, QGraphicsScene does not have the convenience functions
+ \l{QWidget::}{enterEvent()} and \l{QWidget::}{leaveEvent()}. Use this
+ function to obtain those events instead.
+
+ \sa contextMenuEvent(), keyPressEvent(), keyReleaseEvent(),
+ mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(),
+ mouseDoubleClickEvent(), focusInEvent(), focusOutEvent()
+*/
+bool QGraphicsScene::event(QEvent *event)
+{
+ Q_D(QGraphicsScene);
+
+ switch (event->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ case QEvent::GraphicsSceneHoverEnter:
+ case QEvent::GraphicsSceneHoverLeave:
+ case QEvent::GraphicsSceneHoverMove:
+ // Reset the under-mouse list to ensure that this event gets fresh
+ // item-under-mouse data. Be careful about this list; if people delete
+ // items from inside event handlers, this list can quickly end up
+ // having stale pointers in it. We need to clear it before dispatching
+ // events that use it.
+ d->cachedItemsUnderMouse.clear();
+ default:
+ break;
+ }
+
+ switch (event->type()) {
+ 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::GraphicsSceneContextMenu:
+ contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent *>(event));
+ break;
+ case QEvent::KeyPress:
+ if (!d->focusItem) {
+ 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))) {
+ res = focusNextPrevChild(false);
+ } else if (k->key() == Qt::Key_Tab) {
+ res = 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::ShortcutOverride: {
+ QGraphicsItem *parent = focusItem();
+ while (parent) {
+ d->sendEvent(parent, event);
+ if (event->isAccepted())
+ return true;
+ parent = parent->parentItem();
+ }
+ }
+ return false;
+ 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::FocusIn:
+ focusInEvent(static_cast<QFocusEvent *>(event));
+ break;
+ case QEvent::FocusOut:
+ focusOutEvent(static_cast<QFocusEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneHoverEnter:
+ case QEvent::GraphicsSceneHoverLeave:
+ case QEvent::GraphicsSceneHoverMove:
+ d->dispatchHoverEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
+ break;
+ case QEvent::Leave:
+ d->leaveScene();
+ break;
+ case QEvent::GraphicsSceneHelp:
+ helpEvent(static_cast<QGraphicsSceneHelpEvent *>(event));
+ break;
+ case QEvent::InputMethod:
+ inputMethodEvent(static_cast<QInputMethodEvent *>(event));
+ break;
+ case QEvent::WindowActivate: {
+ if (!d->activationRefCount++) {
+ // Notify all non-window widgets.
+ foreach (QGraphicsItem *item, items()) {
+ if (item->isWidget() && item->isVisible() && !item->isWindow() && !item->parentWidget()) {
+ QEvent event(QEvent::WindowActivate);
+ QApplication::sendEvent(static_cast<QGraphicsWidget *>(item), &event);
+ }
+ }
+
+ // Restore window activation.
+ QGraphicsItem *nextFocusItem = d->focusItem ? d->focusItem : d->lastFocusItem;
+ if (nextFocusItem && nextFocusItem->window())
+ setActiveWindow(static_cast<QGraphicsWidget *>(nextFocusItem));
+ else if (d->tabFocusFirst && d->tabFocusFirst->isWindow())
+ setActiveWindow(d->tabFocusFirst);
+ }
+ break;
+ }
+ case QEvent::WindowDeactivate: {
+ if (!--d->activationRefCount) {
+ // Remove window activation.
+ setActiveWindow(0);
+
+ // Notify all non-window widgets.
+ foreach (QGraphicsItem *item, items()) {
+ if (item->isWidget() && item->isVisible() && !item->isWindow() && !item->parentWidget()) {
+ QEvent event(QEvent::WindowDeactivate);
+ QApplication::sendEvent(static_cast<QGraphicsWidget *>(item), &event);
+ }
+ }
+ }
+ break;
+ }
+ case QEvent::ApplicationFontChange: {
+ // Resolve the existing scene font.
+ d->resolveFont();
+ break;
+ }
+ case QEvent::FontChange:
+ // Update the entire scene when the font changes.
+ update();
+ break;
+ case QEvent::ApplicationPaletteChange: {
+ // Resolve the existing scene palette.
+ d->resolvePalette();
+ break;
+ }
+ case QEvent::PaletteChange:
+ // Update the entire scene when the palette changes.
+ update();
+ break;
+ case QEvent::StyleChange:
+ // Reresolve all widgets' styles. Update all top-level widgets'
+ // geometries that do not have an explicit style set.
+ update();
+ break;
+ case QEvent::Timer:
+ if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) {
+ if (d->restartIndexTimer) {
+ d->restartIndexTimer = false;
+ } else {
+ // this call will kill the timer
+ d->_q_updateIndex();
+ }
+ }
+ // Fallthrough intended - support timers in subclasses.
+ default:
+ return QObject::event(event);
+ }
+ return true;
+}
+
+/*!
+ \reimp
+
+ QGraphicsScene filters QApplication's events to detect palette and font
+ changes.
+*/
+bool QGraphicsScene::eventFilter(QObject *watched, QEvent *event)
+{
+ if (watched != qApp)
+ return false;
+
+ switch (event->type()) {
+ case QEvent::ApplicationPaletteChange:
+ qApp->postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
+ break;
+ case QEvent::ApplicationFontChange:
+ qApp->postEvent(this, new QEvent(QEvent::ApplicationFontChange));
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+/*!
+ This event handler, for event \a contextMenuEvent, can be reimplemented in
+ a subclass to receive context menu events. The default implementation
+ forwards the event to the topmost item that accepts context menu events at
+ the position of the event. If no items accept context menu events at this
+ position, the event is ignored.
+
+ \sa QGraphicsItem::contextMenuEvent()
+*/
+void QGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *contextMenuEvent)
+{
+ Q_D(QGraphicsScene);
+ // Ignore by default.
+ contextMenuEvent->ignore();
+
+ // Send the event to all items at this position until one item accepts the
+ // event.
+ foreach (QGraphicsItem *item, d->itemsAtPosition(contextMenuEvent->screenPos(),
+ contextMenuEvent->scenePos(),
+ contextMenuEvent->widget())) {
+ contextMenuEvent->setPos(item->d_ptr->genericMapFromScene(contextMenuEvent->scenePos(),
+ contextMenuEvent->widget()));
+ contextMenuEvent->accept();
+ if (!d->sendEvent(item, contextMenuEvent))
+ break;
+
+ if (contextMenuEvent->isAccepted())
+ break;
+ }
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented in a subclass
+ to receive drag enter events for the scene.
+
+ The default implementation accepts the event and prepares the scene to
+ accept drag move events.
+
+ \sa QGraphicsItem::dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(),
+ dropEvent()
+*/
+void QGraphicsScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
+{
+ Q_D(QGraphicsScene);
+ d->dragDropItem = 0;
+ d->lastDropAction = Qt::IgnoreAction;
+ event->accept();
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented in a subclass
+ to receive drag move events for the scene.
+
+ \sa QGraphicsItem::dragMoveEvent(), dragEnterEvent(), dragLeaveEvent(),
+ dropEvent()
+*/
+void QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
+{
+ Q_D(QGraphicsScene);
+ event->ignore();
+
+ if (!d->mouseGrabberItems.isEmpty()) {
+ // Mouse grabbers that start drag events lose the mouse grab.
+ d->clearMouseGrabber();
+ d->mouseGrabberButtonDownPos.clear();
+ d->mouseGrabberButtonDownScenePos.clear();
+ d->mouseGrabberButtonDownScreenPos.clear();
+ }
+
+ bool eventDelivered = false;
+
+ // Find the topmost enabled items under the cursor. They are all
+ // candidates for accepting drag & drop events.
+ foreach (QGraphicsItem *item, d->itemsAtPosition(event->screenPos(),
+ event->scenePos(),
+ event->widget())) {
+ if (!item->isEnabled() || !item->acceptDrops())
+ continue;
+
+ if (item != d->dragDropItem) {
+ // Enter the new drag drop item. If it accepts the event, we send
+ // the leave to the parent item.
+ QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);
+ d->cloneDragDropEvent(&dragEnter, event);
+ dragEnter.setDropAction(event->proposedAction());
+ d->sendDragDropEvent(item, &dragEnter);
+ event->setAccepted(dragEnter.isAccepted());
+ event->setDropAction(dragEnter.dropAction());
+ if (!event->isAccepted()) {
+ // Propagate to the item under
+ continue;
+ }
+
+ d->lastDropAction = event->dropAction();
+
+ if (d->dragDropItem) {
+ // Leave the last drag drop item. A perfect implementation
+ // would set the position of this event to the point where
+ // this event and the last event intersect with the item's
+ // shape, but that's not easy to do. :-)
+ QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
+ d->cloneDragDropEvent(&dragLeave, event);
+ d->sendDragDropEvent(d->dragDropItem, &dragLeave);
+ }
+
+ // We've got a new drag & drop item
+ d->dragDropItem = item;
+ }
+
+ // Send the move event.
+ event->setDropAction(d->lastDropAction);
+ event->accept();
+ d->sendDragDropEvent(item, event);
+ if (event->isAccepted())
+ d->lastDropAction = event->dropAction();
+ eventDelivered = true;
+ break;
+ }
+
+ if (!eventDelivered) {
+ if (d->dragDropItem) {
+ // Leave the last drag drop item
+ QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
+ d->cloneDragDropEvent(&dragLeave, event);
+ d->sendDragDropEvent(d->dragDropItem, &dragLeave);
+ d->dragDropItem = 0;
+ }
+ // Propagate
+ event->setDropAction(Qt::IgnoreAction);
+ }
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented in a subclass
+ to receive drag leave events for the scene.
+
+ \sa QGraphicsItem::dragLeaveEvent(), dragEnterEvent(), dragMoveEvent(),
+ dropEvent()
+*/
+void QGraphicsScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
+{
+ Q_D(QGraphicsScene);
+ if (d->dragDropItem) {
+ // Leave the last drag drop item
+ d->sendDragDropEvent(d->dragDropItem, event);
+ d->dragDropItem = 0;
+ }
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented in a subclass
+ to receive drop events for the scene.
+
+ \sa QGraphicsItem::dropEvent(), dragEnterEvent(), dragMoveEvent(),
+ dragLeaveEvent()
+*/
+void QGraphicsScene::dropEvent(QGraphicsSceneDragDropEvent *event)
+{
+ Q_UNUSED(event);
+ Q_D(QGraphicsScene);
+ if (d->dragDropItem) {
+ // Drop on the last drag drop item
+ d->sendDragDropEvent(d->dragDropItem, event);
+ d->dragDropItem = 0;
+ }
+}
+
+/*!
+ This event handler, for event \a focusEvent, can be reimplemented in a
+ subclass to receive focus in events.
+
+ The default implementation sets focus on the scene, and then on the last
+ focus item.
+
+ \sa QGraphicsItem::focusOutEvent()
+*/
+void QGraphicsScene::focusInEvent(QFocusEvent *focusEvent)
+{
+ Q_D(QGraphicsScene);
+
+ d->hasFocus = true;
+ switch (focusEvent->reason()) {
+ case Qt::TabFocusReason:
+ if (!focusNextPrevChild(true))
+ focusEvent->ignore();
+ break;
+ case Qt::BacktabFocusReason:
+ if (!focusNextPrevChild(false))
+ focusEvent->ignore();
+ break;
+ default:
+ if (d->lastFocusItem) {
+ // Set focus on the last focus item
+ setFocusItem(d->lastFocusItem, focusEvent->reason());
+ }
+ break;
+ }
+}
+
+/*!
+ This event handler, for event \a focusEvent, can be reimplemented in a
+ subclass to receive focus out events.
+
+ The default implementation removes focus from any focus item, then removes
+ focus from the scene.
+
+ \sa QGraphicsItem::focusInEvent()
+*/
+void QGraphicsScene::focusOutEvent(QFocusEvent *focusEvent)
+{
+ Q_D(QGraphicsScene);
+ d->hasFocus = false;
+ setFocusItem(0, focusEvent->reason());
+
+ // Remove all popups when the scene loses focus.
+ if (!d->popupWidgets.isEmpty())
+ d->removePopup(d->popupWidgets.first());
+}
+
+/*!
+ This event handler, for event \a helpEvent, can be
+ reimplemented in a subclass to receive help events. The events
+ are of type QEvent::ToolTip, which are created when a tooltip is
+ requested.
+
+ The default implementation shows the tooltip of the topmost
+ item, i.e., the item with the highest z-value, at the mouse
+ cursor position. If no item has a tooltip set, this function
+ does nothing.
+
+ \sa QGraphicsItem::toolTip(), QGraphicsSceneHelpEvent
+*/
+void QGraphicsScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent)
+{
+#ifdef QT_NO_TOOLTIP
+ Q_UNUSED(helpEvent);
+#else
+ // Find the first item that does tooltips
+ Q_D(QGraphicsScene);
+ QList<QGraphicsItem *> itemsAtPos = d->itemsAtPosition(helpEvent->screenPos(),
+ helpEvent->scenePos(),
+ helpEvent->widget());
+ QGraphicsItem *toolTipItem = 0;
+ for (int i = 0; i < itemsAtPos.size(); ++i) {
+ QGraphicsItem *tmp = itemsAtPos.at(i);
+ if (!tmp->toolTip().isEmpty()) {
+ toolTipItem = tmp;
+ break;
+ }
+ }
+
+ // Show or hide the tooltip
+ QString text;
+ QPoint point;
+ if (toolTipItem && !toolTipItem->toolTip().isEmpty()) {
+ text = toolTipItem->toolTip();
+ point = helpEvent->screenPos();
+ }
+ QToolTip::showText(point, text);
+ helpEvent->setAccepted(!text.isEmpty());
+#endif
+}
+
+bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const
+{
+ return item->acceptHoverEvents()
+ || (item->isWidget() && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration());
+}
+
+/*!
+ This event handler, for event \a hoverEvent, can be reimplemented in a
+ subclass to receive hover enter events. The default implementation
+ forwards the event to the topmost item that accepts hover events at the
+ scene position from the event.
+
+ \sa QGraphicsItem::hoverEvent(), QGraphicsItem::setAcceptHoverEvents()
+*/
+bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent)
+{
+ // Find the first item that accepts hover events, reusing earlier
+ // calculated data is possible.
+ if (cachedItemsUnderMouse.isEmpty()) {
+ cachedItemsUnderMouse = itemsAtPosition(hoverEvent->screenPos(),
+ hoverEvent->scenePos(),
+ hoverEvent->widget());
+ }
+
+ QGraphicsItem *item = 0;
+ for (int i = 0; i < cachedItemsUnderMouse.size(); ++i) {
+ QGraphicsItem *tmp = cachedItemsUnderMouse.at(i);
+ if (itemAcceptsHoverEvents_helper(tmp)) {
+ item = tmp;
+ break;
+ }
+ }
+
+ // Find the common ancestor item for the new topmost hoverItem and the
+ // last item in the hoverItem list.
+ QGraphicsItem *commonAncestorItem = (item && !hoverItems.isEmpty()) ? item->commonAncestorItem(hoverItems.last()) : 0;
+ while (commonAncestorItem && !itemAcceptsHoverEvents_helper(commonAncestorItem))
+ commonAncestorItem = commonAncestorItem->parentItem();
+ if (commonAncestorItem && commonAncestorItem->window() != item->window()) {
+ // The common ancestor isn't in the same window as the two hovered
+ // items.
+ commonAncestorItem = 0;
+ }
+
+ // Check if the common ancestor item is known.
+ int index = commonAncestorItem ? hoverItems.indexOf(commonAncestorItem) : -1;
+ // Send hover leaves to any existing hovered children of the common
+ // ancestor item.
+ for (int i = hoverItems.size() - 1; i > index; --i) {
+ QGraphicsItem *lastItem = hoverItems.takeLast();
+ if (itemAcceptsHoverEvents_helper(lastItem))
+ sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, hoverEvent);
+ }
+
+ // Item is a child of a known item. Generate enter events for the
+ // missing links.
+ QList<QGraphicsItem *> parents;
+ QGraphicsItem *parent = item;
+ while (parent && parent != commonAncestorItem) {
+ parents.prepend(parent);
+ if (parent->isWindow()) {
+ // Stop at the window - we don't deliver beyond this point.
+ break;
+ }
+ parent = parent->parentItem();
+ }
+ for (int i = 0; i < parents.size(); ++i) {
+ parent = parents.at(i);
+ hoverItems << parent;
+ if (itemAcceptsHoverEvents_helper(parent))
+ sendHoverEvent(QEvent::GraphicsSceneHoverEnter, parent, hoverEvent);
+ }
+
+ // Generate a move event for the item itself
+ if (item && !hoverItems.isEmpty() && item == hoverItems.last()) {
+ sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, hoverEvent);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \internal
+
+ Handles all actions necessary to clean up the scene when the mouse leaves
+ the view.
+*/
+void QGraphicsScenePrivate::leaveScene()
+{
+ Q_Q(QGraphicsScene);
+#ifndef QT_NO_TOOLTIP
+ // Remove any tooltips
+ QToolTip::showText(QPoint(), QString());
+#endif
+ // Send HoverLeave events to all existing hover items, topmost first.
+ QGraphicsView *senderWidget = qobject_cast<QGraphicsView *>(q->sender());
+ QGraphicsSceneHoverEvent hoverEvent;
+ hoverEvent.setWidget(senderWidget);
+
+ if (senderWidget) {
+ QPoint cursorPos = QCursor::pos();
+ hoverEvent.setScenePos(senderWidget->mapToScene(senderWidget->mapFromGlobal(cursorPos)));
+ hoverEvent.setLastScenePos(hoverEvent.scenePos());
+ hoverEvent.setScreenPos(cursorPos);
+ hoverEvent.setLastScreenPos(hoverEvent.screenPos());
+ }
+
+ while (!hoverItems.isEmpty()) {
+ QGraphicsItem *lastItem = hoverItems.takeLast();
+ if (lastItem->acceptHoverEvents()
+ || (lastItem->isWidget() && static_cast<QGraphicsWidget*>(lastItem)->d_func()->hasDecoration()))
+ sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, &hoverEvent);
+ }
+}
+
+/*!
+ This event handler, for event \a keyEvent, can be reimplemented in a
+ subclass to receive keypress events. The default implementation forwards
+ the event to current focus item.
+
+ \sa QGraphicsItem::keyPressEvent(), focusItem()
+*/
+void QGraphicsScene::keyPressEvent(QKeyEvent *keyEvent)
+{
+ // ### Merge this function with keyReleaseEvent; they are identical
+ // ### (except this comment).
+ Q_D(QGraphicsScene);
+ QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
+ if (!item)
+ item = focusItem();
+ if (item) {
+ QGraphicsItem *p = item;
+ do {
+ // Accept the event by default
+ keyEvent->accept();
+ // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
+ // is filtered out, stop propagating it.
+ if (!d->sendEvent(p, keyEvent))
+ break;
+ } while (!keyEvent->isAccepted() && !p->isWindow() && (p = p->parentItem()));
+ } else {
+ keyEvent->ignore();
+ }
+}
+
+/*!
+ This event handler, for event \a keyEvent, can be reimplemented in a
+ subclass to receive key release events. The default implementation
+ forwards the event to current focus item.
+
+ \sa QGraphicsItem::keyReleaseEvent(), focusItem()
+*/
+void QGraphicsScene::keyReleaseEvent(QKeyEvent *keyEvent)
+{
+ // ### Merge this function with keyPressEvent; they are identical (except
+ // ### this comment).
+ Q_D(QGraphicsScene);
+ QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
+ if (!item)
+ item = focusItem();
+ if (item) {
+ QGraphicsItem *p = item;
+ do {
+ // Accept the event by default
+ keyEvent->accept();
+ // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
+ // is filtered out, stop propagating it.
+ if (!d->sendEvent(p, keyEvent))
+ break;
+ } while (!keyEvent->isAccepted() && !p->isWindow() && (p = p->parentItem()));
+ } else {
+ keyEvent->ignore();
+ }
+}
+
+/*!
+ This event handler, for event \a mouseEvent, can be reimplemented
+ in a subclass to receive mouse press events for the scene.
+
+ The default implementation depends on the state of the scene. If
+ there is a mouse grabber item, then the event is sent to the mouse
+ grabber. Otherwise, it is forwarded to the topmost item that
+ accepts mouse events at the scene position from the event, and
+ that item promptly becomes the mouse grabber item.
+
+ If there is no item at the given position on the scene, the
+ selection area is reset, any focus item loses its input focus, and
+ the event is then ignored.
+
+ \sa QGraphicsItem::mousePressEvent(),
+ QGraphicsItem::setAcceptedMouseButtons()
+*/
+void QGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
+{
+ Q_D(QGraphicsScene);
+ d->mousePressEventHandler(mouseEvent);
+}
+
+/*!
+ This event handler, for event \a mouseEvent, can be reimplemented
+ in a subclass to receive mouse move events for the scene.
+
+ The default implementation depends on the mouse grabber state. If there is
+ a mouse grabber item, the event is sent to the mouse grabber. If there
+ are any items that accept hover events at the current position, the event
+ is translated into a hover event and accepted; otherwise it's ignored.
+
+ \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseReleaseEvent(),
+ QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
+*/
+void QGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
+{
+ Q_D(QGraphicsScene);
+ if (d->mouseGrabberItems.isEmpty()) {
+ if (mouseEvent->buttons())
+ return;
+ QGraphicsSceneHoverEvent hover;
+ _q_hoverFromMouseEvent(&hover, mouseEvent);
+ mouseEvent->setAccepted(d->dispatchHoverEvent(&hover));
+ return;
+ }
+
+ // Forward the event to the mouse grabber
+ d->sendMouseEvent(mouseEvent);
+ mouseEvent->accept();
+}
+
+/*!
+ This event handler, for event \a mouseEvent, can be reimplemented
+ in a subclass to receive mouse release events for the scene.
+
+ The default implementation depends on the mouse grabber state. If
+ there is no mouse grabber, the event is ignored. Otherwise, if
+ there is a mouse grabber item, the event is sent to the mouse
+ grabber. If this mouse release represents the last pressed button
+ on the mouse, the mouse grabber item then loses the mouse grab.
+
+ \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
+ QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
+*/
+void QGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
+{
+ Q_D(QGraphicsScene);
+ if (d->mouseGrabberItems.isEmpty()) {
+ mouseEvent->ignore();
+ return;
+ }
+
+ // Forward the event to the mouse grabber
+ d->sendMouseEvent(mouseEvent);
+ mouseEvent->accept();
+
+ // Reset the mouse grabber when the last mouse button has been released.
+ if (!mouseEvent->buttons()) {
+ if (!d->mouseGrabberItems.isEmpty()) {
+ d->lastMouseGrabberItem = d->mouseGrabberItems.last();
+ if (d->lastMouseGrabberItemHasImplicitMouseGrab)
+ d->mouseGrabberItems.last()->ungrabMouse();
+ } else {
+ d->lastMouseGrabberItem = 0;
+ }
+
+ // Generate a hoverevent
+ QGraphicsSceneHoverEvent hoverEvent;
+ _q_hoverFromMouseEvent(&hoverEvent, mouseEvent);
+ d->dispatchHoverEvent(&hoverEvent);
+ }
+}
+
+/*!
+ This event handler, for event \a mouseEvent, can be reimplemented
+ in a subclass to receive mouse doubleclick events for the scene.
+
+ If someone doubleclicks on the scene, the scene 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. If the
+ doubleclick event is delivered to a different item than the one
+ that received the first press and release, it will be delivered as
+ a press event. However, tripleclick events are not delivered as
+ doubleclick events in this case.
+
+ The default implementation is similar to mousePressEvent().
+
+ \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
+ QGraphicsItem::mouseReleaseEvent(), QGraphicsItem::setAcceptedMouseButtons()
+*/
+void QGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
+{
+ Q_D(QGraphicsScene);
+ d->mousePressEventHandler(mouseEvent);
+}
+
+/*!
+ This event handler, for event \a wheelEvent, can be reimplemented in a
+ subclass to receive mouse wheel events for the scene.
+
+ By default, the event is delivered to the topmost visible item under the
+ cursor. If ignored, the event propagates to the item beneath, and again
+ until the event is accepted, or it reaches the scene. If no items accept
+ the event, it is ignored.
+
+ \sa QGraphicsItem::wheelEvent()
+*/
+void QGraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *wheelEvent)
+{
+ Q_D(QGraphicsScene);
+ QList<QGraphicsItem *> wheelCandidates = d->itemsAtPosition(wheelEvent->screenPos(),
+ wheelEvent->scenePos(),
+ wheelEvent->widget());
+
+ bool hasSetFocus = false;
+ foreach (QGraphicsItem *item, wheelCandidates) {
+ if (!hasSetFocus && item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) {
+ if (item->isWidget() && static_cast<QGraphicsWidget *>(item)->focusPolicy() == Qt::WheelFocus) {
+ hasSetFocus = true;
+ if (item != focusItem())
+ setFocusItem(item, Qt::MouseFocusReason);
+ }
+ }
+
+ wheelEvent->setPos(item->d_ptr->genericMapFromScene(wheelEvent->scenePos(),
+ wheelEvent->widget()));
+ wheelEvent->accept();
+ bool isWindow = item->isWindow();
+ d->sendEvent(item, wheelEvent);
+ if (isWindow || wheelEvent->isAccepted())
+ break;
+ }
+}
+
+/*!
+ This event handler, for event \a event, can be reimplemented in a
+ subclass to receive input method events for the scene.
+
+ The default implementation forwards the event to the focusItem().
+ If no item currently has focus, this function does nothing.
+
+ \sa QGraphicsItem::inputMethodEvent()
+*/
+void QGraphicsScene::inputMethodEvent(QInputMethodEvent *event)
+{
+ Q_D(QGraphicsScene);
+ if (!d->focusItem)
+ return;
+ d->sendEvent(d->focusItem, event);
+}
+
+/*!
+ Draws the background of the scene using \a painter, before any items and
+ the foreground are drawn. Reimplement this function to provide a custom
+ background for the scene.
+
+ All painting is done in \e scene coordinates. The \a rect
+ parameter is the exposed rectangle.
+
+ If all you want is to define a color, texture, or gradient for the
+ background, you can call setBackgroundBrush() instead.
+
+ \sa drawForeground(), drawItems()
+*/
+void QGraphicsScene::drawBackground(QPainter *painter, const QRectF &rect)
+{
+ Q_D(QGraphicsScene);
+
+ if (d->backgroundBrush.style() != Qt::NoBrush) {
+ if (d->painterStateProtection)
+ painter->save();
+ painter->setBrushOrigin(0, 0);
+ painter->fillRect(rect, backgroundBrush());
+ if (d->painterStateProtection)
+ painter->restore();
+ }
+}
+
+/*!
+ Draws the foreground of the scene using \a painter, after the background
+ and all items have been drawn. Reimplement this function to provide a
+ custom foreground for the scene.
+
+ All painting is done in \e scene coordinates. The \a rect
+ parameter is the exposed rectangle.
+
+ If all you want is to define a color, texture or gradient for the
+ foreground, you can call setForegroundBrush() instead.
+
+ \sa drawBackground(), drawItems()
+*/
+void QGraphicsScene::drawForeground(QPainter *painter, const QRectF &rect)
+{
+ Q_D(QGraphicsScene);
+
+ if (d->foregroundBrush.style() != Qt::NoBrush) {
+ if (d->painterStateProtection)
+ painter->save();
+ painter->setBrushOrigin(0, 0);
+ painter->fillRect(rect, foregroundBrush());
+ if (d->painterStateProtection)
+ painter->restore();
+ }
+}
+
+static void _q_paintItem(QGraphicsItem *item, QPainter *painter,
+ const QStyleOptionGraphicsItem *option, QWidget *widget,
+ bool useWindowOpacity, bool painterStateProtection)
+{
+ if (!item->isWidget()) {
+ item->paint(painter, option, widget);
+ return;
+ }
+ QGraphicsWidget *widgetItem = static_cast<QGraphicsWidget *>(item);
+ QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(widgetItem);
+ const qreal windowOpacity = (proxy && proxy->widget() && useWindowOpacity)
+ ? proxy->widget()->windowOpacity() : 1.0;
+ const qreal oldPainterOpacity = painter->opacity();
+
+ if (qFuzzyCompare(windowOpacity + 1, qreal(1.0)))
+ return;
+ // Set new painter opacity.
+ if (windowOpacity < 1.0)
+ painter->setOpacity(oldPainterOpacity * windowOpacity);
+
+ // set layoutdirection on the painter
+ Qt::LayoutDirection oldLayoutDirection = painter->layoutDirection();
+ painter->setLayoutDirection(widgetItem->layoutDirection());
+
+ if (widgetItem->isWindow() && widgetItem->windowType() != Qt::Popup && widgetItem->windowType() != Qt::ToolTip
+ && !(widgetItem->windowFlags() & Qt::FramelessWindowHint)) {
+ if (painterStateProtection)
+ painter->save();
+ widgetItem->paintWindowFrame(painter, option, widget);
+ if (painterStateProtection)
+ painter->restore();
+ }
+
+ widgetItem->paint(painter, option, widget);
+
+ // Restore layoutdirection on the painter.
+ painter->setLayoutDirection(oldLayoutDirection);
+ // Restore painter opacity.
+ if (windowOpacity < 1.0)
+ painter->setOpacity(oldPainterOpacity);
+}
+
+static void _q_paintIntoCache(QPixmap *pix, QGraphicsItem *item, const QRegion &pixmapExposed,
+ const QTransform &itemToPixmap, QPainter::RenderHints renderHints,
+ const QStyleOptionGraphicsItem *option, bool painterStateProtection)
+{
+ QPixmap subPix;
+ QPainter pixmapPainter;
+ QRect br = pixmapExposed.boundingRect();
+
+ // Don't use subpixmap if we get a full update.
+ if (pixmapExposed.isEmpty() || (pixmapExposed.numRects() == 1 && br.contains(pix->rect()))) {
+ pix->fill(Qt::transparent);
+ pixmapPainter.begin(pix);
+ } else {
+ subPix = QPixmap(br.size());
+ subPix.fill(Qt::transparent);
+ pixmapPainter.begin(&subPix);
+ pixmapPainter.translate(-br.topLeft());
+ if (!pixmapExposed.isEmpty()) {
+ // Applied to subPix; paint is adjusted to the coordinate space is
+ // correct.
+ pixmapPainter.setClipRegion(pixmapExposed);
+ }
+ }
+
+ pixmapPainter.setRenderHints(pixmapPainter.renderHints(), false);
+ pixmapPainter.setRenderHints(renderHints, true);
+ pixmapPainter.setWorldTransform(itemToPixmap, true);
+
+ // Render.
+ _q_paintItem(item, &pixmapPainter, option, 0, false, painterStateProtection);
+ pixmapPainter.end();
+
+ if (!subPix.isNull()) {
+ // Blit the subpixmap into the main pixmap.
+ pixmapPainter.begin(pix);
+ pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ pixmapPainter.setClipRegion(pixmapExposed);
+ pixmapPainter.drawPixmap(br.topLeft(), subPix);
+ pixmapPainter.end();
+ }
+}
+
+/*!
+ \internal
+
+ Draws items directly, or using cache.
+*/
+void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painter,
+ const QStyleOptionGraphicsItem *option, QWidget *widget,
+ bool painterStateProtection)
+{
+ QGraphicsItemPrivate *itemd = item->d_ptr;
+ QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode);
+
+ // Render directly, using no cache.
+ if (cacheMode == QGraphicsItem::NoCache
+#ifdef Q_WS_X11
+ || !X11->use_xrender
+#endif
+ ) {
+ _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget, true, painterStateProtection);
+ return;
+ }
+
+ const qreal oldPainterOpacity = painter->opacity();
+ qreal newPainterOpacity = oldPainterOpacity;
+ QGraphicsProxyWidget *proxy = item->isWidget() ? qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(item)) : 0;
+ if (proxy && proxy->widget()) {
+ const qreal windowOpacity = proxy->widget()->windowOpacity();
+ if (windowOpacity < 1.0)
+ newPainterOpacity *= windowOpacity;
+ }
+
+ // Item's (local) bounding rect
+ QRectF brect = item->boundingRect();
+ if (_q_adjustedRect(brect).isEmpty())
+ return;
+
+ // Fetch the off-screen transparent buffer and exposed area info.
+ QString pixmapKey;
+ QPixmap pix;
+ QGraphicsItemCache *itemCache = itemd->extraItemCache();
+ if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
+ if (itemCache->boundingRect != brect.toRect()) {
+ itemCache->boundingRect = brect.toRect();
+ itemCache->allExposed = true;
+ itemCache->exposed.clear();
+ }
+ pixmapKey = itemCache->key;
+ } else {
+ if ((pixmapKey = itemCache->deviceData.value(widget).key).isEmpty()) {
+ pixmapKey.sprintf("qgv-%p-%p", item, widget);
+ QGraphicsItemCache::DeviceData data;
+ data.key = pixmapKey;
+ itemCache->deviceData.insert(widget, data);
+ }
+ }
+
+ // Find pixmap in cache.
+ if (!itemCache->allExposed)
+ QPixmapCache::find(pixmapKey, pix);
+
+ // Render using item coordinate cache mode.
+ if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
+ QSize pixmapSize;
+ bool fixedCacheSize = false;
+ if ((fixedCacheSize = itemCache->fixedSize.isValid())) {
+ pixmapSize = itemCache->fixedSize;
+ } else {
+ pixmapSize = brect.toAlignedRect().size();
+ }
+
+ // Create or recreate the pixmap.
+ int adjust = itemCache->fixedSize.isValid() ? 0 : 2;
+ QSize adjustSize(adjust*2, adjust*2);
+ QRectF br = brect.adjusted(-adjust, -adjust, adjust, adjust);
+ if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) {
+ pix = QPixmap(pixmapSize + adjustSize);
+ itemCache->exposed.clear();
+ itemCache->allExposed = true;
+ }
+
+ // Redraw any newly exposed areas.
+ if (itemCache->allExposed || !itemCache->exposed.isEmpty()) {
+ // Fit the item's bounding rect into the pixmap's coordinates.
+ const QPointF scale(pixmapSize.width() / brect.width(), pixmapSize.height() / brect.height());
+ QTransform itemToPixmap;
+ itemToPixmap.scale(scale.x(), scale.y());
+ itemToPixmap.translate(-br.x(), -br.y());
+
+ // Generate the item's exposedRect and map its list of expose
+ // rects to device coordinates.
+ QStyleOptionGraphicsItem cacheOption = *option;
+ QRegion pixmapExposed;
+ QRectF exposedRect;
+ if (!itemCache->allExposed) {
+ for (int i = 0; i < itemCache->exposed.size(); ++i) {
+ QRectF r = itemCache->exposed.at(i);
+ exposedRect |= r;
+ pixmapExposed += itemToPixmap.mapRect(r).toAlignedRect();
+ }
+ } else {
+ exposedRect = brect;
+ }
+ cacheOption.exposedRect = exposedRect;
+
+ // Render.
+ _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
+ &cacheOption, painterStateProtection);
+
+ // Reinsert this pixmap into the cache.
+ QPixmapCache::insert(pixmapKey, pix);
+
+ // Reset expose data.
+ itemCache->allExposed = false;
+ itemCache->exposed.clear();
+ }
+
+ // Redraw the exposed area using the transformed painter. Depending on
+ // the hardware, this may be a server-side operation, or an expensive
+ // qpixmap-image-transform-pixmap roundtrip.
+ if (newPainterOpacity != oldPainterOpacity) {
+ painter->setOpacity(newPainterOpacity);
+ painter->drawPixmap(br, pix, QRectF(QPointF(), pix.size()));
+ painter->setOpacity(oldPainterOpacity);
+ } else {
+ painter->drawPixmap(br, pix, QRectF(QPointF(), pix.size()));
+ }
+ return;
+ }
+
+ // Render using device coordinate cache mode.
+ if (cacheMode == QGraphicsItem::DeviceCoordinateCache) {
+ // Find the item's bounds in device coordinates.
+ QRectF deviceBounds = painter->worldTransform().mapRect(brect);
+ QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
+ if (deviceRect.isEmpty())
+ return;
+ QRect viewRect = widget ? widget->rect() : QRect();
+ if (widget && !viewRect.intersects(deviceRect))
+ return;
+
+ // Resort to direct rendering if the device rect exceeds the
+ // (optional) maximum bounds. (QGraphicsSvgItem uses this).
+ QSize maximumCacheSize =
+ itemd->extra(QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize).toSize();
+ if (!maximumCacheSize.isEmpty()
+ && (deviceRect.width() > maximumCacheSize.width()
+ || deviceRect.height() > maximumCacheSize.height())) {
+ _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget,
+ oldPainterOpacity != newPainterOpacity, painterStateProtection);
+ return;
+ }
+
+ // Create or reuse offscreen pixmap, possibly scroll/blit from the old one.
+ bool pixModified = false;
+ QGraphicsItemCache::DeviceData *deviceData = &itemCache->deviceData[widget];
+ bool invertable = true;
+ QTransform diff = deviceData->lastTransform.inverted(&invertable);
+ if (invertable)
+ diff *= painter->worldTransform();
+ deviceData->lastTransform = painter->worldTransform();
+ if (!invertable || diff.type() > QTransform::TxTranslate) {
+ pixModified = true;
+ itemCache->allExposed = true;
+ itemCache->exposed.clear();
+ pix = QPixmap();
+ }
+
+ // ### This is a pretty bad way to determine when to start partial
+ // exposure for DeviceCoordinateCache but it's the least intrusive
+ // approach for now.
+#if 0
+ // Only if the device rect isn't fully contained.
+ bool allowPartialCacheExposure = !viewRect.contains(deviceRect);
+#else
+ // Only if deviceRect is 20% taller or wider than the desktop.
+ QRect desktopRect = qApp->desktop()->availableGeometry(widget);
+ bool allowPartialCacheExposure = (desktopRect.width() * 1.2 < deviceRect.width()
+ || desktopRect.height() * 1.2 < deviceRect.height());
+#endif
+ QRegion scrollExposure;
+ if (deviceData->cacheIndent != QPoint() || allowPartialCacheExposure) {
+ // Part of pixmap is drawn. Either device contains viewrect (big
+ // item covers whole screen) or parts of device are outside the
+ // viewport. In either case the device rect must be the intersect
+ // between the two.
+ int dx = deviceRect.left() < viewRect.left() ? viewRect.left() - deviceRect.left() : 0;
+ int dy = deviceRect.top() < viewRect.top() ? viewRect.top() - deviceRect.top() : 0;
+ QPoint newCacheIndent(dx, dy);
+ deviceRect &= viewRect;
+
+ if (pix.isNull()) {
+ deviceData->cacheIndent = QPoint();
+ itemCache->allExposed = true;
+ itemCache->exposed.clear();
+ pixModified = true;
+ }
+
+ // Copy / "scroll" the old pixmap onto the new ole and calculate
+ // scrolled exposure.
+ if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size()) {
+ QPoint diff = newCacheIndent - deviceData->cacheIndent;
+ QPixmap newPix(deviceRect.size());
+ // ### Investigate removing this fill (test with Plasma and
+ // graphicssystem raster).
+ newPix.fill(Qt::transparent);
+ if (!pix.isNull()) {
+ QPainter newPixPainter(&newPix);
+ newPixPainter.drawPixmap(-diff, pix);
+ newPixPainter.end();
+ }
+ QRegion exposed;
+ exposed += newPix.rect();
+ if (!pix.isNull())
+ exposed -= QRect(-diff, pix.size());
+ scrollExposure = exposed;
+
+ pix = newPix;
+ pixModified = true;
+ }
+ deviceData->cacheIndent = newCacheIndent;
+ } else {
+ // Full pixmap is drawn.
+ deviceData->cacheIndent = QPoint();
+
+ // Auto-adjust the pixmap size.
+ if (deviceRect.size() != pix.size()) {
+ // exposed needs to cover the whole pixmap
+ pix = QPixmap(deviceRect.size());
+ pixModified = true;
+ itemCache->allExposed = true;
+ itemCache->exposed.clear();
+ }
+ }
+
+ // Check for newly invalidated areas.
+ if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) {
+ // Construct an item-to-pixmap transform.
+ QPointF p = deviceRect.topLeft();
+ QTransform itemToPixmap = QTransform::fromTranslate(-p.x(), -p.y());
+ itemToPixmap = painter->worldTransform() * itemToPixmap;
+
+ // Map the item's logical expose to pixmap coordinates.
+ QRegion pixmapExposed = scrollExposure;
+ if (!itemCache->allExposed) {
+ const QVector<QRectF> &exposed = itemCache->exposed;
+ for (int i = 0; i < exposed.size(); ++i)
+ pixmapExposed += itemToPixmap.mapRect(exposed.at(i)).toRect().adjusted(-1, -1, 1, 1);
+ }
+
+ // Calculate the style option's exposedRect.
+ QRectF br;
+ if (itemCache->allExposed) {
+ br = item->boundingRect();
+ } else {
+ const QVector<QRectF> &exposed = itemCache->exposed;
+ for (int i = 0; i < exposed.size(); ++i)
+ br |= exposed.at(i);
+ QTransform pixmapToItem = itemToPixmap.inverted();
+ foreach (QRect r, scrollExposure.rects())
+ br |= pixmapToItem.mapRect(r);
+ }
+ QStyleOptionGraphicsItem cacheOption = *option;
+ cacheOption.exposedRect = br.adjusted(-1, -1, 1, 1);
+
+ // Render the exposed areas.
+ _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
+ &cacheOption, painterStateProtection);
+
+ // Reset expose data.
+ pixModified = true;
+ itemCache->allExposed = false;
+ itemCache->exposed.clear();
+ }
+
+ if (pixModified) {
+ // Reinsert this pixmap into the cache
+ QPixmapCache::insert(pixmapKey, pix);
+ }
+
+ // Redraw the exposed area using an untransformed painter. This
+ // effectively becomes a bitblit that does not transform the cache.
+ QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+ if (newPainterOpacity != oldPainterOpacity) {
+ painter->setOpacity(newPainterOpacity);
+ painter->drawPixmap(deviceRect.topLeft(), pix);
+ painter->setOpacity(oldPainterOpacity);
+ } else {
+ painter->drawPixmap(deviceRect.topLeft(), pix);
+ }
+ painter->setWorldTransform(restoreTransform);
+ return;
+ }
+}
+
+/*!
+ Paints the given \a items using the provided \a painter, after the
+ background has been drawn, and before the foreground has been
+ drawn. All painting is done in \e scene coordinates. Before
+ drawing each item, the painter must be transformed using
+ QGraphicsItem::sceneMatrix().
+
+ The \a options parameter is the list of style option objects for
+ each item in \a items. The \a numItems parameter is the number of
+ items in \a items and options in \a options. The \a widget
+ parameter is optional; if specified, it should point to the widget
+ that is being painted on.
+
+ The default implementation prepares the painter matrix, and calls
+ QGraphicsItem::paint() on all items. Reimplement this function to
+ provide custom painting of all items for the scene; gaining
+ complete control over how each item is drawn. In some cases this
+ can increase drawing performance significantly.
+
+ Example:
+
+ \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0
+
+ \sa drawBackground(), drawForeground()
+*/
+void QGraphicsScene::drawItems(QPainter *painter,
+ int numItems,
+ QGraphicsItem *items[],
+ const QStyleOptionGraphicsItem options[], QWidget *widget)
+{
+ Q_D(QGraphicsScene);
+
+ // Detect if painter state protection is disabled.
+ QTransform viewTransform = painter->worldTransform();
+ QVarLengthArray<QGraphicsItem *, 16> childClippers;
+
+ for (int i = 0; i < numItems; ++i) {
+ QGraphicsItem *item = items[i];
+ if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
+ if (!childClippers.isEmpty()) {
+ // Item is not clipped to any ancestor: pop all current clippers.
+ for (int i = 0; i < childClippers.size(); ++i)
+ painter->restore();
+ childClippers.clear();
+ }
+ } else {
+ // Item is clipped to an ancestor, which may or may not be in our
+ // child clipper list. Let's start by finding the item's closest
+ // clipping ancestor.
+ QGraphicsItem *clipParent = item->parentItem();
+ while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape))
+ clipParent = clipParent->parentItem();
+
+ // Pop any in-between clippers. If the clipper is unknown, pop
+ // them all. ### QVarLengthArray::lastIndexOf().
+ int index = -1;
+ for (int n = childClippers.size() - 1; n >= 0; --n) {
+ if (childClippers[n] == clipParent) {
+ index = n;
+ break;
+ }
+ }
+ if (index != -1) {
+ int toPop = childClippers.size() - index - 1;
+ if (toPop > 0) {
+ for (int i = 0; i < toPop; ++i)
+ painter->restore();
+ childClippers.resize(index + 1);
+ }
+ }
+
+ // Sanity check
+ if (!childClippers.isEmpty())
+ Q_ASSERT(childClippers[childClippers.size() - 1] == clipParent);
+
+ // If the clipper list is empty at this point, but we're still
+ // clipped to an ancestor, then we need to build the clip chain
+ // ourselves. There is only one case that can produce this issue:
+ // This item is stacked behind an ancestor:
+ // ItemStacksBehindParent.
+ if (childClippers.isEmpty()) {
+ Q_ASSERT(clipParent != 0);
+ // Build a stack of clippers.
+ QVarLengthArray<QGraphicsItem *, 16> clippers;
+ QGraphicsItem *p = clipParent;
+ do {
+ if (p->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)
+ clippers.append(p);
+ } while ((p = p->parentItem()) && (p->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren));
+
+ // ### This code path can also use the itemTransform
+ // optimization, but it's hit very rarely.
+ for (int i = clippers.size() - 1; i >= 0; --i) {
+ QGraphicsItem *clipper = clippers[i];
+ if (clipper->d_ptr->itemIsUntransformable()) {
+ painter->setWorldTransform(clipper->deviceTransform(viewTransform), false);
+ } else {
+ painter->setWorldTransform(clipper->sceneTransform() * viewTransform, false);
+ }
+
+ childClippers.append(clipper);
+ painter->save();
+ painter->setClipPath(clipper->shape(), Qt::IntersectClip);
+ }
+ Q_ASSERT(childClippers[childClippers.size() - 1] == clipParent);
+ }
+ }
+
+ // Set up the painter transform
+ if (item->d_ptr->itemIsUntransformable()) {
+ painter->setWorldTransform(item->deviceTransform(viewTransform), false);
+ } else {
+ painter->setWorldTransform(item->sceneTransform() * viewTransform, false);
+ }
+
+ // Save painter
+ bool saveState = (d->painterStateProtection || (item->flags() & QGraphicsItem::ItemClipsToShape));
+ if (saveState)
+ painter->save();
+
+ // Set local clip
+ if (item->flags() & QGraphicsItem::ItemClipsToShape)
+ painter->setClipPath(item->shape(), Qt::IntersectClip);
+
+ // Setup opacity
+ painter->setOpacity(item->effectiveOpacity());
+
+ // Draw the item
+ d->drawItemHelper(item, painter, &options[i], widget, d->painterStateProtection);
+
+ if (saveState)
+ painter->restore();
+
+ if (item->flags() & QGraphicsItem::ItemClipsChildrenToShape) {
+ // Clip descendents to this item's shape, and keep the painter
+ // saved.
+ childClippers.append(item);
+ painter->save();
+ painter->setClipPath(item->shape(), Qt::IntersectClip);
+ }
+ }
+
+ for (int i = 0; i < childClippers.size(); ++i)
+ painter->restore();
+
+ painter->setWorldTransform(viewTransform);
+}
+
+/*!
+ \since 4.4
+
+ Finds a new widget to give the keyboard focus to, as appropriate for Tab
+ and Shift+Tab, and returns true if it can find a new widget, or false if
+ it cannot. If \a next is true, this function searches forward; if \a next
+ is false, it searches backward.
+
+ You can reimplement this function in a subclass of QGraphicsScene to
+ provide fine-grained control over how tab focus passes inside your
+ scene. The default implementation is based on the tab focus chain defined
+ by QGraphicsWidget::setTabOrder().
+*/
+bool QGraphicsScene::focusNextPrevChild(bool next)
+{
+ Q_D(QGraphicsScene);
+
+ QGraphicsItem *item = focusItem();
+ if (item && !item->isWidget()) {
+ // Tab out of the scene.
+ return false;
+ }
+ if (!item) {
+ if (d->lastFocusItem && !d->lastFocusItem->isWidget()) {
+ // Restore focus to the last focusable non-widget item that had
+ // focus.
+ setFocusItem(d->lastFocusItem, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
+ return true;
+ }
+ }
+ if (!d->tabFocusFirst) {
+ // No widgets...
+ return false;
+ }
+
+ // The item must be a widget.
+ QGraphicsWidget *widget = 0;
+ if (!item) {
+ widget = next ? d->tabFocusFirst : d->tabFocusFirst->d_func()->focusPrev;
+ } else {
+ QGraphicsWidget *test = static_cast<QGraphicsWidget *>(item);
+ widget = next ? test->d_func()->focusNext : test->d_func()->focusPrev;
+ if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
+ return false;
+ }
+ QGraphicsWidget *widgetThatHadFocus = widget;
+
+ // Run around the focus chain until we find a widget that can take tab focus.
+ do {
+ if (widget->flags() & QGraphicsItem::ItemIsFocusable
+ && widget->isEnabled() && widget->isVisibleTo(0)
+ && (widget->focusPolicy() & Qt::TabFocus)
+ && (!item || !item->isWindow() || item->isAncestorOf(widget))
+ ) {
+ setFocusItem(widget, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
+ return true;
+ }
+ widget = next ? widget->d_func()->focusNext : widget->d_func()->focusPrev;
+ if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
+ return false;
+ } while (widget != widgetThatHadFocus);
+
+ return false;
+}
+
+/*!
+ \fn QGraphicsScene::changed(const QList<QRectF> &region)
+
+ This signal is emitted by QGraphicsScene when control reaches the
+ event loop, if the scene content changes. The \a region parameter
+ contains a list of scene rectangles that indicate the area that
+ has been changed.
+
+ \sa QGraphicsView::updateScene()
+*/
+
+/*!
+ \fn QGraphicsScene::sceneRectChanged(const QRectF &rect)
+
+ This signal is emitted by QGraphicsScene whenever the scene rect changes.
+ The \a rect parameter is the new scene rectangle.
+
+ \sa QGraphicsView::updateSceneRect()
+*/
+
+/*!
+ \fn QGraphicsScene::selectionChanged()
+ \since 4.3
+
+ This signal is emitted by QGraphicsScene whenever the selection
+ changes. You can call selectedItems() to get the new list of selected
+ items.
+
+ The selection changes whenever an item is selected or unselected, a
+ selection area is set, cleared or otherwise changed, if a preselected item
+ is added to the scene, or if a selected item is removed from the scene.
+
+ QGraphicsScene emits this signal only once for group selection operations.
+ For example, if you set a selection area, select or unselect a
+ QGraphicsItemGroup, or if you add or remove from the scene a parent item
+ that contains several selected items, selectionChanged() is emitted only
+ once after the operation has completed (instead of once for each item).
+
+ \sa setSelectionArea(), selectedItems(), QGraphicsItem::setSelected()
+*/
+
+/*!
+ \internal
+
+ This private function is called by QGraphicsItem, which is a friend of
+ QGraphicsScene. It is used by QGraphicsScene to record the rectangles that
+ need updating. It also launches a single-shot timer to ensure that
+ updated() will be emitted later.
+
+ The \a item parameter is the item that changed, and \a rect is the
+ area of the item that changed given in item coordinates.
+*/
+void QGraphicsScene::itemUpdated(QGraphicsItem *item, const QRectF &rect)
+{
+ Q_D(QGraphicsScene);
+ // Deliver the actual update.
+ if (!d->updateAll) {
+ if (d->views.isEmpty() || ((d->connectedSignals & d->changedSignalMask) && !item->d_ptr->itemIsUntransformable()
+ && qFuzzyCompare(item->boundingRegionGranularity(), qreal(0.0)))) {
+ // This block of code is kept for compatibility. Since 4.5, by default
+ // QGraphicsView does not connect the signal and we use the below
+ // method of delivering updates.
+ update(item->sceneBoundingRect());
+ } else {
+ // ### Remove _q_adjustedRects().
+ QRectF boundingRect = _q_adjustedRect(item->boundingRect());
+ if (!rect.isNull())
+ boundingRect &= _q_adjustedRect(rect);
+
+ // Update each view directly.
+ for (int i = 0; i < d->views.size(); ++i)
+ d->views.at(i)->d_func()->itemUpdated(item, boundingRect);
+ }
+ }
+ if (item->d_ptr->dirty) {
+ d->dirtyItems << item;
+ d->resetDirtyItemsLater();
+ }
+
+ // Update d->largestUntransformableItem by mapping this item's bounding
+ // rect back to the topmost untransformable item's untransformed
+ // coordinate system (which sort of equals the 1:1 coordinate system of an
+ // untransformed view).
+ if (item->d_ptr->itemIsUntransformable()) {
+ QGraphicsItem *parent = item;
+ while (parent && (parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations))
+ parent = parent->parentItem();
+ d->largestUntransformableItem |= item->mapToItem(parent, item->boundingRect()).boundingRect();
+ }
+
+ // Only track the automatically growing scene rect if the scene has no
+ // defined scene rect.
+ if (!d->hasSceneRect) {
+ QRectF oldGrowingItemsBoundingRect = d->growingItemsBoundingRect;
+ d->growingItemsBoundingRect |= _q_adjustedRect(item->sceneBoundingRect());
+ if (d->growingItemsBoundingRect != oldGrowingItemsBoundingRect)
+ emit sceneRectChanged(d->growingItemsBoundingRect);
+ }
+}
+
+/*!
+ \since 4.4
+
+ Returns the scene's style, or the same as QApplication::style() if the
+ scene has not been explicitly assigned a style.
+
+ \sa setStyle()
+*/
+QStyle *QGraphicsScene::style() const
+{
+ Q_D(const QGraphicsScene);
+ // ### This function, and the use of styles in general, is non-reentrant.
+ return d->style ? d->style : qApp->style();
+}
+
+/*!
+ \since 4.4
+
+ Sets or replaces the style of the scene to \a style, and reparents the
+ style to this scene. Any previously assigned style is deleted. The scene's
+ style defaults to QApplication::style(), and serves as the default for all
+ QGraphicsWidget items in the scene.
+
+ Changing the style, either directly by calling this function, or
+ indirectly by calling QApplication::setStyle(), will automatically update
+ the style for all widgets in the scene that do not have a style explicitly
+ assigned to them.
+
+ If \a style is 0, QGraphicsScene will revert to QApplication::style().
+
+ \sa style()
+*/
+void QGraphicsScene::setStyle(QStyle *style)
+{
+ Q_D(QGraphicsScene);
+ // ### This function, and the use of styles in general, is non-reentrant.
+ if (style == d->style)
+ return;
+
+ // Delete the old style,
+ delete d->style;
+ if ((d->style = style))
+ d->style->setParent(this);
+
+ // Notify the scene.
+ QEvent event(QEvent::StyleChange);
+ QApplication::sendEvent(this, &event);
+
+ // Notify all widgets that don't have a style explicitly set.
+ foreach (QGraphicsItem *item, items()) {
+ if (item->isWidget()) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
+ if (!widget->testAttribute(Qt::WA_SetStyle))
+ QApplication::sendEvent(widget, &event);
+ }
+ }
+}
+
+/*!
+ \property QGraphicsScene::font
+ \since 4.4
+ \brief the scene's default font
+
+ This property provides the scene's font. The scene font defaults to,
+ and resolves all its entries from, QApplication::font.
+
+ If the scene's font changes, either directly through setFont() or
+ indirectly when the application font changes, QGraphicsScene first
+ sends itself a \l{QEvent::FontChange}{FontChange} event, and it then
+ sends \l{QEvent::FontChange}{FontChange} events to all top-level
+ widget items in the scene. These items respond by resolving their own
+ fonts to the scene, and they then notify their children, who again
+ notify their children, and so on, until all widget items have updated
+ their fonts.
+
+ Changing the scene font, (directly or indirectly through
+ QApplication::setFont(),) automatically schedules a redraw the entire
+ scene.
+
+ \sa QWidget::font, QApplication::setFont(), palette, style()
+*/
+QFont QGraphicsScene::font() const
+{
+ Q_D(const QGraphicsScene);
+ return d->font;
+}
+void QGraphicsScene::setFont(const QFont &font)
+{
+ Q_D(QGraphicsScene);
+ QFont naturalFont = qApp->font();
+ naturalFont.resolve(0);
+ QFont resolvedFont = font.resolve(naturalFont);
+ d->setFont_helper(resolvedFont);
+}
+
+/*!
+ \property QGraphicsScene::palette
+ \since 4.4
+ \brief the scene's default palette
+
+ This property provides the scene's palette. The scene palette defaults to,
+ and resolves all its entries from, QApplication::palette.
+
+ If the scene's palette changes, either directly through setPalette() or
+ indirectly when the application palette changes, QGraphicsScene first
+ sends itself a \l{QEvent::PaletteChange}{PaletteChange} event, and it then
+ sends \l{QEvent::PaletteChange}{PaletteChange} events to all top-level
+ widget items in the scene. These items respond by resolving their own
+ palettes to the scene, and they then notify their children, who again
+ notify their children, and so on, until all widget items have updated
+ their palettes.
+
+ Changing the scene palette, (directly or indirectly through
+ QApplication::setPalette(),) automatically schedules a redraw the entire
+ scene.
+
+ \sa QWidget::palette, QApplication::setPalette(), font, style()
+*/
+QPalette QGraphicsScene::palette() const
+{
+ Q_D(const QGraphicsScene);
+ return d->palette;
+}
+void QGraphicsScene::setPalette(const QPalette &palette)
+{
+ Q_D(QGraphicsScene);
+ QPalette naturalPalette = qApp->palette();
+ naturalPalette.resolve(0);
+ QPalette resolvedPalette = palette.resolve(naturalPalette);
+ d->setPalette_helper(resolvedPalette);
+}
+
+/*!
+ \since 4.4
+
+ Returns the current active window, or 0 if there is no window is currently
+ active.
+
+ \sa QGraphicsScene::setActiveWindow()
+*/
+QGraphicsWidget *QGraphicsScene::activeWindow() const
+{
+ Q_D(const QGraphicsScene);
+ return d->activeWindow;
+}
+
+/*!
+ \since 4.4
+ Activates \a widget, which must be a widget in this scene. You can also
+ pass 0 for \a widget, in which case QGraphicsScene will deactivate any
+ currently active window.
+
+ \sa activeWindow(), QGraphicsWidget::isActiveWindow()
+*/
+void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
+{
+ Q_D(QGraphicsScene);
+ if (widget && widget->scene() != this) {
+ qWarning("QGraphicsScene::setActiveWindow: widget %p must be part of this scene",
+ widget);
+ return;
+ }
+
+ // Activate the widget's window.
+ QGraphicsWidget *window = widget ? widget->window() : 0;
+ if (window == d->activeWindow)
+ return;
+
+ // Deactivate the last active window.
+ if (d->activeWindow) {
+ if (QGraphicsWidget *fw = d->activeWindow->focusWidget()) {
+ // Remove focus from the current focus item.
+ if (fw == focusItem())
+ setFocusItem(0, Qt::ActiveWindowFocusReason);
+ }
+
+ QEvent event(QEvent::WindowDeactivate);
+ QApplication::sendEvent(d->activeWindow, &event);
+ }
+
+ // Update activate state.
+ d->activeWindow = window;
+ QEvent event(QEvent::ActivationChange);
+ QApplication::sendEvent(this, &event);
+
+ // Activate
+ if (window) {
+ QEvent event(QEvent::WindowActivate);
+ QApplication::sendEvent(window, &event);
+
+ QList<QGraphicsItem *> siblingWindows;
+ QGraphicsItem *parent = window->parentItem();
+ // Raise ### inefficient for toplevels
+ foreach (QGraphicsItem *sibling, parent ? parent->children() : items()) {
+ if (sibling != window && sibling->isWidget()
+ && static_cast<QGraphicsWidget *>(sibling)->isWindow()) {
+ siblingWindows << sibling;
+ }
+ }
+
+ // Find the highest z value.
+ qreal z = window->zValue();
+ for (int i = 0; i < siblingWindows.size(); ++i)
+ z = qMax(z, siblingWindows.at(i)->zValue());
+
+ // This will probably never overflow.
+ const qreal litt = qreal(0.001);
+ window->setZValue(z + litt);
+
+ if (QGraphicsWidget *focusChild = window->focusWidget())
+ focusChild->setFocus(Qt::ActiveWindowFocusReason);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qgraphicsscene.cpp"
+
+#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h
new file mode 100644
index 0000000..9802f87
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsscene.h
@@ -0,0 +1,301 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSSCENE_H
+#define QGRAPHICSSCENE_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qbrush.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qtransform.h>
+#include <QtGui/qmatrix.h>
+#include <QtGui/qpen.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+template<typename T> class QList;
+class QFocusEvent;
+class QFont;
+class QFontMetrics;
+class QGraphicsEllipseItem;
+class QGraphicsItem;
+class QGraphicsItemGroup;
+class QGraphicsLineItem;
+class QGraphicsPathItem;
+class QGraphicsPixmapItem;
+class QGraphicsPolygonItem;
+class QGraphicsProxyWidget;
+class QGraphicsRectItem;
+class QGraphicsSceneContextMenuEvent;
+class QGraphicsSceneDragDropEvent;
+class QGraphicsSceneEvent;
+class QGraphicsSceneHelpEvent;
+class QGraphicsSceneHoverEvent;
+class QGraphicsSceneMouseEvent;
+class QGraphicsSceneWheelEvent;
+class QGraphicsSimpleTextItem;
+class QGraphicsTextItem;
+class QGraphicsView;
+class QGraphicsWidget;
+class QHelpEvent;
+class QInputMethodEvent;
+class QKeyEvent;
+class QLineF;
+class QPainterPath;
+class QPixmap;
+class QPointF;
+class QPolygonF;
+class QRectF;
+class QSizeF;
+class QStyle;
+class QStyleOptionGraphicsItem;
+
+class QGraphicsScenePrivate;
+class Q_GUI_EXPORT QGraphicsScene : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QBrush backgroundBrush READ backgroundBrush WRITE setBackgroundBrush)
+ Q_PROPERTY(QBrush foregroundBrush READ foregroundBrush WRITE setForegroundBrush)
+ Q_PROPERTY(ItemIndexMethod itemIndexMethod READ itemIndexMethod WRITE setItemIndexMethod)
+ Q_PROPERTY(QRectF sceneRect READ sceneRect WRITE setSceneRect)
+ Q_PROPERTY(int bspTreeDepth READ bspTreeDepth WRITE setBspTreeDepth)
+ Q_PROPERTY(QPalette palette READ palette WRITE setPalette)
+ Q_PROPERTY(QFont font READ font WRITE setFont)
+ Q_PROPERTY(bool sortCacheEnabled READ isSortCacheEnabled WRITE setSortCacheEnabled)
+ Q_PROPERTY(bool stickyFocus READ stickyFocus WRITE setStickyFocus)
+
+public:
+ enum ItemIndexMethod {
+ BspTreeIndex,
+ NoIndex = -1
+ };
+
+ enum SceneLayer {
+ ItemLayer = 0x1,
+ BackgroundLayer = 0x2,
+ ForegroundLayer = 0x4,
+ AllLayers = 0xffff
+ };
+ Q_DECLARE_FLAGS(SceneLayers, SceneLayer)
+
+ QGraphicsScene(QObject *parent = 0);
+ QGraphicsScene(const QRectF &sceneRect, QObject *parent = 0);
+ QGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObject *parent = 0);
+ virtual ~QGraphicsScene();
+
+ QRectF sceneRect() const;
+ inline qreal width() const { return sceneRect().width(); }
+ inline qreal height() const { return sceneRect().height(); }
+ void setSceneRect(const QRectF &rect);
+ inline void setSceneRect(qreal x, qreal y, qreal w, qreal h)
+ { setSceneRect(QRectF(x, y, w, h)); }
+
+ void render(QPainter *painter,
+ const QRectF &target = QRectF(), const QRectF &source = QRectF(),
+ Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio);
+
+ ItemIndexMethod itemIndexMethod() const;
+ void setItemIndexMethod(ItemIndexMethod method);
+
+ bool isSortCacheEnabled() const;
+ void setSortCacheEnabled(bool enabled);
+
+ int bspTreeDepth() const;
+ void setBspTreeDepth(int depth);
+
+ QRectF itemsBoundingRect() const;
+
+ QList<QGraphicsItem *> items() const;
+ QList<QGraphicsItem *> items(const QPointF &pos) const;
+ QList<QGraphicsItem *> items(const QRectF &rect, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ QList<QGraphicsItem *> items(const QPolygonF &polygon, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ QList<QGraphicsItem *> items(const QPainterPath &path, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ QList<QGraphicsItem *> collidingItems(const QGraphicsItem *item, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ QGraphicsItem *itemAt(const QPointF &pos) const;
+
+ inline QList<QGraphicsItem *> items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const
+ { return items(QRectF(x, y, w, h), mode); }
+ inline QGraphicsItem *itemAt(qreal x, qreal y) const
+ { return itemAt(QPointF(x, y)); }
+
+ QList<QGraphicsItem *> selectedItems() const;
+ QPainterPath selectionArea() const;
+ void setSelectionArea(const QPainterPath &path);
+ void setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode);
+
+ QGraphicsItemGroup *createItemGroup(const QList<QGraphicsItem *> &items);
+ void destroyItemGroup(QGraphicsItemGroup *group);
+
+ void addItem(QGraphicsItem *item);
+ QGraphicsEllipseItem *addEllipse(const QRectF &rect, const QPen &pen = QPen(), const QBrush &brush = QBrush());
+ QGraphicsLineItem *addLine(const QLineF &line, const QPen &pen = QPen());
+ QGraphicsPathItem *addPath(const QPainterPath &path, const QPen &pen = QPen(), const QBrush &brush = QBrush());
+ QGraphicsPixmapItem *addPixmap(const QPixmap &pixmap);
+ QGraphicsPolygonItem *addPolygon(const QPolygonF &polygon, const QPen &pen = QPen(), const QBrush &brush = QBrush());
+ QGraphicsRectItem *addRect(const QRectF &rect, const QPen &pen = QPen(), const QBrush &brush = QBrush());
+ QGraphicsTextItem *addText(const QString &text, const QFont &font = QFont());
+ QGraphicsSimpleTextItem *addSimpleText(const QString &text, const QFont &font = QFont());
+ QGraphicsProxyWidget *addWidget(QWidget *widget, Qt::WindowFlags wFlags = 0);
+ inline QGraphicsEllipseItem *addEllipse(qreal x, qreal y, qreal w, qreal h, const QPen &pen = QPen(), const QBrush &brush = QBrush())
+ { return addEllipse(QRectF(x, y, w, h), pen, brush); }
+ inline QGraphicsLineItem *addLine(qreal x1, qreal y1, qreal x2, qreal y2, const QPen &pen = QPen())
+ { return addLine(QLineF(x1, y1, x2, y2), pen); }
+ inline QGraphicsRectItem *addRect(qreal x, qreal y, qreal w, qreal h, const QPen &pen = QPen(), const QBrush &brush = QBrush())
+ { return addRect(QRectF(x, y, w, h), pen, brush); }
+ void removeItem(QGraphicsItem *item);
+
+ QGraphicsItem *focusItem() const;
+ void setFocusItem(QGraphicsItem *item, Qt::FocusReason focusReason = Qt::OtherFocusReason);
+ bool hasFocus() const;
+ void setFocus(Qt::FocusReason focusReason = Qt::OtherFocusReason);
+ void clearFocus();
+
+ void setStickyFocus(bool enabled);
+ bool stickyFocus() const;
+
+ QGraphicsItem *mouseGrabberItem() const;
+
+ QBrush backgroundBrush() const;
+ void setBackgroundBrush(const QBrush &brush);
+
+ QBrush foregroundBrush() const;
+ void setForegroundBrush(const QBrush &brush);
+
+ virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+
+ QList <QGraphicsView *> views() const;
+
+ inline void update(qreal x, qreal y, qreal w, qreal h)
+ { update(QRectF(x, y, w, h)); }
+ inline void invalidate(qreal x, qreal y, qreal w, qreal h, SceneLayers layers = AllLayers)
+ { invalidate(QRectF(x, y, w, h), layers); }
+
+ QStyle *style() const;
+ void setStyle(QStyle *style);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QPalette palette() const;
+ void setPalette(const QPalette &palette);
+
+ QGraphicsWidget *activeWindow() const;
+ void setActiveWindow(QGraphicsWidget *widget);
+
+public Q_SLOTS:
+ void update(const QRectF &rect = QRectF());
+ void invalidate(const QRectF &rect = QRectF(), SceneLayers layers = AllLayers);
+ void advance();
+ void clearSelection();
+ void clear();
+
+protected:
+ bool event(QEvent *event);
+ bool eventFilter(QObject *watched, QEvent *event);
+ virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
+ virtual void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
+ virtual void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
+ virtual void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
+ virtual void dropEvent(QGraphicsSceneDragDropEvent *event);
+ virtual void focusInEvent(QFocusEvent *event);
+ virtual void focusOutEvent(QFocusEvent *event);
+ virtual void helpEvent(QGraphicsSceneHelpEvent *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 void drawBackground(QPainter *painter, const QRectF &rect);
+ virtual void drawForeground(QPainter *painter, const QRectF &rect);
+ virtual void drawItems(QPainter *painter, int numItems,
+ QGraphicsItem *items[],
+ const QStyleOptionGraphicsItem options[],
+ QWidget *widget = 0);
+
+protected Q_SLOTS:
+ bool focusNextPrevChild(bool next);
+
+Q_SIGNALS:
+ void changed(const QList<QRectF> &region);
+ void sceneRectChanged(const QRectF &rect);
+ void selectionChanged();
+
+private:
+ void itemUpdated(QGraphicsItem *item, const QRectF &rect);
+
+ Q_DECLARE_PRIVATE(QGraphicsScene)
+ Q_DISABLE_COPY(QGraphicsScene)
+ Q_PRIVATE_SLOT(d_func(), void _q_updateIndex())
+ Q_PRIVATE_SLOT(d_func(), void _q_emitUpdated())
+ Q_PRIVATE_SLOT(d_func(), void _q_removeItemLater(QGraphicsItem *item))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateLater())
+ Q_PRIVATE_SLOT(d_func(), void _q_polishItems())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateSortCache())
+ Q_PRIVATE_SLOT(d_func(), void _q_resetDirtyItems())
+ friend class QGraphicsItem;
+ friend class QGraphicsItemPrivate;
+ friend class QGraphicsView;
+ friend class QGraphicsViewPrivate;
+ friend class QGraphicsWidget;
+ friend class QGraphicsWidgetPrivate;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsScene::SceneLayers)
+
+#endif // QT_NO_GRAPHICSVIEW
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/gui/graphicsview/qgraphicsscene_bsp.cpp b/src/gui/graphicsview/qgraphicsscene_bsp.cpp
new file mode 100644
index 0000000..f8fa450
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsscene_bsp.cpp
@@ -0,0 +1,328 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgraphicsscene_bsp_p.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include <QtCore/qstring.h>
+#include <private/qgraphicsitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsSceneInsertItemBspTreeVisitor : public QGraphicsSceneBspTreeVisitor
+{
+public:
+ QGraphicsItem *item;
+
+ void visit(QList<QGraphicsItem *> *items)
+ { items->prepend(item); }
+};
+
+class QGraphicsSceneRemoveItemBspTreeVisitor : public QGraphicsSceneBspTreeVisitor
+{
+public:
+ QGraphicsItem *item;
+
+ void visit(QList<QGraphicsItem *> *items)
+ { items->removeAll(item); }
+};
+
+class QGraphicsSceneFindItemBspTreeVisitor : public QGraphicsSceneBspTreeVisitor
+{
+public:
+ QList<QGraphicsItem *> *foundItems;
+
+ void visit(QList<QGraphicsItem *> *items)
+ {
+ for (int i = 0; i < items->size(); ++i) {
+ QGraphicsItem *item = items->at(i);
+ if (!item->d_func()->itemDiscovered && item->isVisible()) {
+ item->d_func()->itemDiscovered = 1;
+ foundItems->prepend(item);
+ }
+ }
+ }
+};
+
+QGraphicsSceneBspTree::QGraphicsSceneBspTree()
+ : leafCnt(0)
+{
+ insertVisitor = new QGraphicsSceneInsertItemBspTreeVisitor;
+ removeVisitor = new QGraphicsSceneRemoveItemBspTreeVisitor;
+ findVisitor = new QGraphicsSceneFindItemBspTreeVisitor;
+}
+
+QGraphicsSceneBspTree::~QGraphicsSceneBspTree()
+{
+ delete insertVisitor;
+ delete removeVisitor;
+ delete findVisitor;
+}
+
+void QGraphicsSceneBspTree::initialize(const QRectF &rect, int depth)
+{
+ this->rect = rect;
+ leafCnt = 0;
+ nodes.resize((1 << (depth + 1)) - 1);
+ nodes.fill(Node());
+ leaves.resize(1 << depth);
+ leaves.fill(QList<QGraphicsItem *>());
+
+ initialize(rect, depth, 0);
+}
+
+void QGraphicsSceneBspTree::clear()
+{
+ leafCnt = 0;
+ nodes.clear();
+ leaves.clear();
+}
+
+void QGraphicsSceneBspTree::insertItem(QGraphicsItem *item, const QRectF &rect)
+{
+ insertVisitor->item = item;
+ climbTree(insertVisitor, rect);
+}
+
+void QGraphicsSceneBspTree::removeItem(QGraphicsItem *item, const QRectF &rect)
+{
+ removeVisitor->item = item;
+ climbTree(removeVisitor, rect);
+}
+
+void QGraphicsSceneBspTree::removeItems(const QSet<QGraphicsItem *> &items)
+{
+ for (int i = 0; i < leaves.size(); ++i) {
+ QList<QGraphicsItem *> newItemList;
+ const QList<QGraphicsItem *> &oldItemList = leaves[i];
+ for (int j = 0; j < oldItemList.size(); ++j) {
+ QGraphicsItem *item = oldItemList.at(j);
+ if (!items.contains(item))
+ newItemList << item;
+ }
+ leaves[i] = newItemList;
+ }
+}
+
+QList<QGraphicsItem *> QGraphicsSceneBspTree::items(const QRectF &rect)
+{
+ QList<QGraphicsItem *> tmp;
+ findVisitor->foundItems = &tmp;
+ climbTree(findVisitor, rect);
+ return tmp;
+}
+
+QList<QGraphicsItem *> QGraphicsSceneBspTree::items(const QPointF &pos)
+{
+ QList<QGraphicsItem *> tmp;
+ findVisitor->foundItems = &tmp;
+ climbTree(findVisitor, pos);
+ return tmp;
+}
+
+int QGraphicsSceneBspTree::leafCount() const
+{
+ return leafCnt;
+}
+
+QString QGraphicsSceneBspTree::debug(int index) const
+{
+ const Node *node = &nodes.at(index);
+
+ QString tmp;
+ if (node->type == Node::Leaf) {
+ QRectF rect = rectForIndex(index);
+ if (!leaves[node->leafIndex].isEmpty()) {
+ tmp += QString::fromLatin1("[%1, %2, %3, %4] contains %5 items\n")
+ .arg(rect.left()).arg(rect.top())
+ .arg(rect.width()).arg(rect.height())
+ .arg(leaves[node->leafIndex].size());
+ }
+ } else {
+ if (node->type == Node::Horizontal) {
+ tmp += debug(firstChildIndex(index));
+ tmp += debug(firstChildIndex(index) + 1);
+ } else {
+ tmp += debug(firstChildIndex(index));
+ tmp += debug(firstChildIndex(index) + 1);
+ }
+ }
+
+ return tmp;
+}
+
+void QGraphicsSceneBspTree::initialize(const QRectF &rect, int depth, int index)
+{
+ Node *node = &nodes[index];
+ if (index == 0) {
+ node->type = Node::Horizontal;
+ node->offset = rect.center().x();
+ }
+
+ if (depth) {
+ Node::Type type;
+ QRectF rect1, rect2;
+ qreal offset1, offset2;
+
+ if (node->type == Node::Horizontal) {
+ type = Node::Vertical;
+ rect1.setRect(rect.left(), rect.top(), rect.width(), rect.height() / 2);
+ rect2.setRect(rect1.left(), rect1.bottom(), rect1.width(), rect.height() - rect1.height());
+ offset1 = rect1.center().x();
+ offset2 = rect2.center().x();
+ } else {
+ type = Node::Horizontal;
+ rect1.setRect(rect.left(), rect.top(), rect.width() / 2, rect.height());
+ rect2.setRect(rect1.right(), rect1.top(), rect.width() - rect1.width(), rect1.height());
+ offset1 = rect1.center().y();
+ offset2 = rect2.center().y();
+ }
+
+ int childIndex = firstChildIndex(index);
+
+ Node *child = &nodes[childIndex];
+ child->offset = offset1;
+ child->type = type;
+
+ child = &nodes[childIndex + 1];
+ child->offset = offset2;
+ child->type = type;
+
+ initialize(rect1, depth - 1, childIndex);
+ initialize(rect2, depth - 1, childIndex + 1);
+ } else {
+ node->type = Node::Leaf;
+ node->leafIndex = leafCnt++;
+ }
+}
+
+void QGraphicsSceneBspTree::climbTree(QGraphicsSceneBspTreeVisitor *visitor, const QPointF &pos, int index)
+{
+ if (nodes.isEmpty())
+ return;
+
+ const Node &node = nodes.at(index);
+ int childIndex = firstChildIndex(index);
+
+ switch (node.type) {
+ case Node::Leaf: {
+ visitor->visit(&leaves[node.leafIndex]);
+ break;
+ }
+ case Node::Vertical:
+ if (pos.x() < node.offset) {
+ climbTree(visitor, pos, childIndex);
+ } else {
+ climbTree(visitor, pos, childIndex + 1);
+ }
+ break;
+ case Node::Horizontal:
+ if (pos.y() < node.offset) {
+ climbTree(visitor, pos, childIndex);
+ } else {
+ climbTree(visitor, pos, childIndex + 1);
+ }
+ break;
+ }
+}
+
+void QGraphicsSceneBspTree::climbTree(QGraphicsSceneBspTreeVisitor *visitor, const QRectF &rect, int index)
+{
+ if (nodes.isEmpty())
+ return;
+
+ const Node &node = nodes.at(index);
+ int childIndex = firstChildIndex(index);
+
+ switch (node.type) {
+ case Node::Leaf: {
+ visitor->visit(&leaves[node.leafIndex]);
+ break;
+ }
+ case Node::Vertical:
+ if (rect.left() < node.offset) {
+ climbTree(visitor, rect, childIndex);
+ if (rect.right() >= node.offset)
+ climbTree(visitor, rect, childIndex + 1);
+ } else {
+ climbTree(visitor, rect, childIndex + 1);
+ }
+ break;
+ case Node::Horizontal:
+ int childIndex = firstChildIndex(index);
+ if (rect.top() < node.offset) {
+ climbTree(visitor, rect, childIndex);
+ if (rect.bottom() >= node.offset)
+ climbTree(visitor, rect, childIndex + 1);
+ } else {
+ climbTree(visitor, rect, childIndex + 1);
+ }
+ }
+}
+
+QRectF QGraphicsSceneBspTree::rectForIndex(int index) const
+{
+ if (index <= 0)
+ return rect;
+
+ int parentIdx = parentIndex(index);
+ QRectF rect = rectForIndex(parentIdx);
+ const Node *parent = &nodes.at(parentIdx);
+
+ if (parent->type == Node::Horizontal) {
+ if (index & 1)
+ rect.setRight(parent->offset);
+ else
+ rect.setLeft(parent->offset);
+ } else {
+ if (index & 1)
+ rect.setBottom(parent->offset);
+ else
+ rect.setTop(parent->offset);
+ }
+
+ return rect;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicsscene_bsp_p.h b/src/gui/graphicsview/qgraphicsscene_bsp_p.h
new file mode 100644
index 0000000..e6ceb78
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsscene_bsp_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSSCENEBSPTREE_P_H
+#define QGRAPHICSSCENEBSPTREE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qlist.h>
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+#include <QtCore/qrect.h>
+#include <QtCore/qset.h>
+#include <QtCore/qvector.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsItem;
+class QGraphicsSceneBspTreeVisitor;
+class QGraphicsSceneInsertItemBspTreeVisitor;
+class QGraphicsSceneRemoveItemBspTreeVisitor;
+class QGraphicsSceneFindItemBspTreeVisitor;
+
+class QGraphicsSceneBspTree
+{
+public:
+ struct Node
+ {
+ enum Type { Horizontal, Vertical, Leaf };
+ union {
+ qreal offset;
+ int leafIndex;
+ };
+ Type type;
+ };
+
+ QGraphicsSceneBspTree();
+ ~QGraphicsSceneBspTree();
+
+ void initialize(const QRectF &rect, int depth);
+ void clear();
+
+ void insertItem(QGraphicsItem *item, const QRectF &rect);
+ void removeItem(QGraphicsItem *item, const QRectF &rect);
+ void removeItems(const QSet<QGraphicsItem *> &items);
+
+ QList<QGraphicsItem *> items(const QRectF &rect);
+ QList<QGraphicsItem *> items(const QPointF &pos);
+ int leafCount() const;
+
+ inline int firstChildIndex(int index) const
+ { return index * 2 + 1; }
+
+ inline int parentIndex(int index) const
+ { return index > 0 ? ((index & 1) ? ((index - 1) / 2) : ((index - 2) / 2)) : -1; }
+
+ QString debug(int index) const;
+
+private:
+ void initialize(const QRectF &rect, int depth, int index);
+ void climbTree(QGraphicsSceneBspTreeVisitor *visitor, const QPointF &pos, int index = 0);
+ void climbTree(QGraphicsSceneBspTreeVisitor *visitor, const QRectF &rect, int index = 0);
+
+ void findItems(QList<QGraphicsItem *> *foundItems, const QRectF &rect, int index);
+ void findItems(QList<QGraphicsItem *> *foundItems, const QPointF &pos, int index);
+ QRectF rectForIndex(int index) const;
+
+ QVector<Node> nodes;
+ QVector<QList<QGraphicsItem *> > leaves;
+ int leafCnt;
+ QRectF rect;
+
+ QGraphicsSceneInsertItemBspTreeVisitor *insertVisitor;
+ QGraphicsSceneRemoveItemBspTreeVisitor *removeVisitor;
+ QGraphicsSceneFindItemBspTreeVisitor *findVisitor;
+};
+
+class QGraphicsSceneBspTreeVisitor
+{
+public:
+ virtual ~QGraphicsSceneBspTreeVisitor() { }
+ virtual void visit(QList<QGraphicsItem *> *items) = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_GRAPHICSVIEW
+
+#endif // QGRAPHICSSCENEBSPTREE_P_H
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
new file mode 100644
index 0000000..9c165d1
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -0,0 +1,265 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSSCENE_P_H
+#define QGRAPHICSSCENE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qgraphicsscene.h"
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+#include "qgraphicsscene_bsp_p.h"
+#include "qgraphicsitem_p.h"
+
+#include <private/qobject_p.h>
+#include <QtCore/qbitarray.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qset.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/qstyle.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsView;
+class QGraphicsWidget;
+
+class QGraphicsScenePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsScene)
+public:
+ QGraphicsScenePrivate();
+ void init();
+
+ quint32 changedSignalMask;
+
+ QGraphicsScene::ItemIndexMethod indexMethod;
+ int bspTreeDepth;
+
+ QList<QGraphicsItem *> estimateItemsInRect(const QRectF &rect) const;
+ void addToIndex(QGraphicsItem *item);
+ void removeFromIndex(QGraphicsItem *item);
+ void resetIndex();
+
+ QGraphicsSceneBspTree bspTree;
+ void _q_updateIndex();
+ int lastItemCount;
+
+ QRectF sceneRect;
+ bool hasSceneRect;
+ QRectF growingItemsBoundingRect;
+ QRectF largestUntransformableItem;
+
+ void _q_emitUpdated();
+ QList<QRectF> updatedRects;
+ bool updateAll;
+ bool calledEmitUpdated;
+
+ QPainterPath selectionArea;
+ int selectionChanging;
+ QSet<QGraphicsItem *> selectedItems;
+ QList<QGraphicsItem *> unindexedItems;
+ QList<QGraphicsItem *> indexedItems;
+ QList<QGraphicsItem *> dirtyItems;
+ QList<QGraphicsItem *> pendingUpdateItems;
+ QList<QGraphicsItem *> unpolishedItems;
+ QMap<QGraphicsItem *, QPointF> movingItemsInitialPositions;
+ void _q_updateLater();
+ void _q_polishItems();
+
+ void _q_resetDirtyItems();
+ void resetDirtyItemsLater();
+ bool dirtyItemResetPending;
+
+ QList<int> freeItemIndexes;
+ bool regenerateIndex;
+
+ bool purgePending;
+ void _q_removeItemLater(QGraphicsItem *item);
+ QSet<QGraphicsItem *> removedItems;
+ void purgeRemovedItems();
+
+ QBrush backgroundBrush;
+ QBrush foregroundBrush;
+
+ int indexTimerId;
+ bool restartIndexTimer;
+ void startIndexTimer();
+
+ bool stickyFocus;
+ bool hasFocus;
+ QGraphicsItem *focusItem;
+ QGraphicsItem *lastFocusItem;
+ QGraphicsWidget *tabFocusFirst;
+ QGraphicsWidget *activeWindow;
+ int activationRefCount;
+
+ QList<QGraphicsWidget *> popupWidgets;
+ void addPopup(QGraphicsWidget *widget);
+ void removePopup(QGraphicsWidget *widget, bool itemIsDying = false);
+
+ QGraphicsItem *lastMouseGrabberItem;
+ bool lastMouseGrabberItemHasImplicitMouseGrab;
+ QList<QGraphicsItem *> mouseGrabberItems;
+ void grabMouse(QGraphicsItem *item, bool implicit = false);
+ void ungrabMouse(QGraphicsItem *item, bool itemIsDying = false);
+ void clearMouseGrabber();
+
+ QList<QGraphicsItem *> keyboardGrabberItems;
+ void grabKeyboard(QGraphicsItem *item);
+ void ungrabKeyboard(QGraphicsItem *item, bool itemIsDying = false);
+ void clearKeyboardGrabber();
+
+ QGraphicsItem *dragDropItem;
+ QGraphicsWidget *enterWidget;
+ Qt::DropAction lastDropAction;
+ QList<QGraphicsItem *> cachedItemsUnderMouse;
+ QList<QGraphicsItem *> hoverItems;
+ QMap<Qt::MouseButton, QPointF> mouseGrabberButtonDownPos;
+ QMap<Qt::MouseButton, QPointF> mouseGrabberButtonDownScenePos;
+ QMap<Qt::MouseButton, QPoint> mouseGrabberButtonDownScreenPos;
+ QList<QGraphicsItem *> itemsAtPosition(const QPoint &screenPos,
+ const QPointF &scenePos,
+ QWidget *widget) const;
+ static bool itemCollidesWithPath(QGraphicsItem *item, const QPainterPath &path, Qt::ItemSelectionMode mode);
+ void storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event);
+
+ QList<QGraphicsView *> views;
+ bool painterStateProtection;
+
+ QMultiMap<QGraphicsItem *, QGraphicsItem *> sceneEventFilters;
+ void installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter);
+ void removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter);
+ bool filterEvent(QGraphicsItem *item, QEvent *event);
+ bool sendEvent(QGraphicsItem *item, QEvent *event);
+
+ bool dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent);
+ bool itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const;
+ void leaveScene();
+
+ void cloneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
+ QGraphicsSceneDragDropEvent *source);
+ void sendDragDropEvent(QGraphicsItem *item,
+ QGraphicsSceneDragDropEvent *dragDropEvent);
+ void sendHoverEvent(QEvent::Type type, QGraphicsItem *item,
+ QGraphicsSceneHoverEvent *hoverEvent);
+ void sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent);
+ void mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent);
+ QGraphicsWidget *windowForItem(const QGraphicsItem *item) const;
+
+ QList<QGraphicsItem *> items_helper(const QRectF &rect,
+ Qt::ItemSelectionMode mode,
+ Qt::SortOrder order) const;
+ QList<QGraphicsItem *> items_helper(const QPolygonF &rect,
+ Qt::ItemSelectionMode mode,
+ Qt::SortOrder order) const;
+ QList<QGraphicsItem *> items_helper(const QPainterPath &rect,
+ Qt::ItemSelectionMode mode,
+ Qt::SortOrder order) const;
+ void childItems_helper(QList<QGraphicsItem *> *items,
+ const QGraphicsItem *parent,
+ const QRectF &rect,
+ Qt::ItemSelectionMode mode) const;
+ void childItems_helper(QList<QGraphicsItem *> *items,
+ const QGraphicsItem *parent,
+ const QPolygonF &polygon,
+ Qt::ItemSelectionMode mode) const;
+ void childItems_helper(QList<QGraphicsItem *> *items,
+ const QGraphicsItem *parent,
+ const QPainterPath &path,
+ Qt::ItemSelectionMode mode) const;
+
+ bool sortCacheEnabled;
+ bool updatingSortCache;
+ void invalidateSortCache();
+ static void climbTree(QGraphicsItem *item, int *stackingOrder);
+ void _q_updateSortCache();
+
+ static bool closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2);
+ static bool closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2);
+
+ static inline bool closestItemFirst_withCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
+ {
+ return item1->d_ptr->globalStackingOrder < item2->d_ptr->globalStackingOrder;
+ }
+ static inline bool closestItemLast_withCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
+ {
+ return item1->d_ptr->globalStackingOrder >= item2->d_ptr->globalStackingOrder;
+ }
+
+ static void sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order, bool cached);
+
+ void drawItemHelper(QGraphicsItem *item, QPainter *painter,
+ const QStyleOptionGraphicsItem *option, QWidget *widget,
+ bool painterStateProtection);
+
+ QStyle *style;
+ QFont font;
+ void setFont_helper(const QFont &font);
+ void resolveFont();
+ void updateFont(const QFont &font);
+ QPalette palette;
+ void setPalette_helper(const QPalette &palette);
+ void resolvePalette();
+ void updatePalette(const QPalette &palette);
+
+ mutable QVector<QTransform> sceneTransformCache;
+ mutable QBitArray validTransforms;
+ mutable QVector<int> freeSceneTransformSlots;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_GRAPHICSVIEW
+
+#endif
diff --git a/src/gui/graphicsview/qgraphicssceneevent.cpp b/src/gui/graphicsview/qgraphicssceneevent.cpp
new file mode 100644
index 0000000..57c79db
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicssceneevent.cpp
@@ -0,0 +1,1678 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QGraphicsSceneEvent
+ \brief The QGraphicsSceneEvent class provides a base class for all
+ graphics view related events.
+ \since 4.2
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ When a QGraphicsView receives Qt mouse, keyboard, and drag and
+ drop events (QMouseEvent, QKeyEvent, QDragEvent, etc.), it
+ translates them into instances of QGraphicsSceneEvent subclasses
+ and forwards them to the QGraphicsScene it displays. The scene
+ then forwards the events to the relevant items.
+
+ For example, when a QGraphicsView receives a QMouseEvent of type
+ MousePress as a response to a user click, the view sends a
+ QGraphicsSceneMouseEvent of type GraphicsSceneMousePress to the
+ underlying QGraphicsScene through its
+ \l{QGraphicsScene::}{mousePressEvent()} function. The default
+ QGraphicsScene::mousePressEvent() implementation determines which
+ item was clicked and forwards the event to
+ QGraphicsItem::mousePressEvent().
+
+ \omit ### Beskrive widget() \endomit
+
+ Subclasses such as QGraphicsSceneMouseEvent and
+ QGraphicsSceneContextMenuEvent provide the coordinates from the
+ original QEvent in screen, scene, and item coordinates (see
+ \l{QGraphicsSceneMouseEvent::}{screenPos()},
+ \l{QGraphicsSceneMouseEvent::}{scenePos()}, and
+ \l{QGraphicsSceneMouseEvent::}{pos()}). The item coordinates are
+ set by the QGraphicsScene before it forwards the event to the
+ event to a QGraphicsItem. The mouse events also add the
+ possibility to retrieve the coordinates from the last event
+ received by the view (see
+ \l{QGraphicsSceneMouseEvent::}{lastScreenPos()},
+ \l{QGraphicsSceneMouseEvent::}{lastScenePos()}, and
+ \l{QGraphicsSceneMouseEvent::}{lastPos()}).
+
+ \sa QEvent
+*/
+
+/*!
+ \class QGraphicsSceneMouseEvent
+ \brief The QGraphicsSceneMouseEvent class provides mouse events
+ in the graphics view framework.
+ \since 4.2
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ When a QGraphicsView receives a QMouseEvent, it translates it to
+ a QGraphicsSceneMouseEvent. The event is then forwarded to the
+ QGraphicsScene associated with the view.
+
+ In addition to containing the item, scene, and screen coordinates
+ of the event (as pos(), scenePos(), and screenPos()), mouse
+ events also contain the coordinates of the previous mouse
+ event received by the view. These can be retrieved with
+ lastPos(), lastScreenPos(), and lastScenePos().
+
+ \sa QGraphicsSceneContextMenuEvent,
+ QGraphicsSceneHoverEvent, QGraphicsSceneWheelEvent,
+ QMouseEvent
+*/
+
+/*!
+ \class QGraphicsSceneWheelEvent
+ \brief The QGraphicsSceneWheelEvent class provides wheel events
+ in the graphics view framework.
+ \brief The QGraphicsSceneWheelEvent class provides wheel events in the
+ graphics view framework.
+ \since 4.2
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ \l{QWheelEvent}{QWheelEvent}s received by a QGraphicsView are translated
+ into QGraphicsSceneWheelEvents; it translates the QWheelEvent::globalPos()
+ into item, scene, and screen coordinates (pos(), scenePos(), and
+ screenPos()).
+
+ \sa QGraphicsSceneMouseEvent, QGraphicsSceneContextMenuEvent,
+ QGraphicsSceneHoverEvent, QWheelEvent
+*/
+
+/*!
+ \class QGraphicsSceneContextMenuEvent
+ \brief The QGraphicsSceneContextMenuEvent class provides context
+ menu events in the graphics view framework.
+ \since 4.2
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ A QContextMenuEvent received by a QGraphicsView is translated
+ into a QGraphicsSceneContextMenuEvent. The
+ QWheelEvent::globalPos() is translated into item, scene, and
+ screen coordinates (pos(), scenePos(), and screenPos()).
+
+ \sa QGraphicsSceneMouseEvent, QGraphicsSceneWheelEvent,
+ QContextMenuEvent
+*/
+
+/*!
+ \enum QGraphicsSceneContextMenuEvent::Reason
+
+ This enum describes the reason why the context event was sent.
+
+ \value Mouse The mouse caused the event to be sent. On most
+ platforms, this means the right mouse button was clicked.
+
+ \value Keyboard The keyboard caused this event to be sent. On
+ Windows and Mac OS X, this means the menu button was pressed.
+
+ \value Other The event was sent by some other means (i.e. not
+ by the mouse or keyboard).
+*/
+
+/*!
+ \class QGraphicsSceneHoverEvent
+ \brief The QGraphicsSceneHoverEvent class provides hover events
+ in the graphics view framework.
+ \since 4.2
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ When a QGraphicsView receives a QHoverEvent event, it translates
+ it into QGraphicsSceneHoverEvent. The event is then forwarded to
+ the QGraphicsScene associated with the view.
+
+ \sa QGraphicsSceneMouseEvent, QGraphicsSceneContextMenuEvent,
+ QGraphicsSceneWheelEvent, QHoverEvent
+*/
+
+/*!
+ \class QGraphicsSceneHelpEvent
+ \brief The QGraphicsSceneHelpEvent class provides events when a
+ tooltip is requested.
+ \since 4.2
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ When a QGraphicsView receives a QEvent of type
+ QEvent::ToolTip, it creates a QGraphicsSceneHelpEvent, which is
+ forwarded to the scene. You can set a tooltip on a QGraphicsItem
+ with \l{QGraphicsItem::}{setToolTip()}; by default QGraphicsScene
+ displays the tooltip of the QGraphicsItem with the highest
+ z-value (i.e, the top-most item) under the mouse position.
+
+ QGraphicsView does not forward events when
+ \l{QWhatsThis}{"What's This"} and \l{QStatusTipEvent}{status tip}
+ help is requested. If you need this, you can reimplement
+ QGraphicsView::viewportEvent() and forward QStatusTipEvent
+ events and \l{QEvent}{QEvents} of type QEvent::WhatsThis to the
+ scene.
+
+ \sa QEvent
+*/
+
+/*!
+ \class QGraphicsSceneDragDropEvent
+ \brief The QGraphicsSceneDragDropEvent class provides events for
+ drag and drop in the graphics view framework.
+ \since 4.2
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ QGraphicsView inherits the drag and drop functionality provided
+ by QWidget. When it receives a drag and drop event, it translates
+ it to a QGraphicsSceneDragDropEvent.
+
+ QGraphicsSceneDragDropEvent stores events of type
+ GraphicsSceneDragEnter, GraphicsSceneDragLeave,
+ GraphicsSceneDragMove, or GraphicsSceneDrop.
+
+ QGraphicsSceneDragDropEvent contains the position of the mouse
+ cursor in both item, scene, and screen coordinates; this can be
+ retrieved with pos(), scenePos(), and screenPos().
+
+ The scene sends the event to the first QGraphicsItem under the
+ mouse cursor that accepts drops; a graphics item is set to accept
+ drops with \l{QGraphicsItem::}{setAcceptDrops()}.
+*/
+
+/*!
+ \class QGraphicsSceneResizeEvent
+ \brief The QGraphicsSceneResizeEvent class provides events for widget
+ resizing in the graphics view framework.
+ \since 4.4
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ A QGraphicsWidget sends itself a QGraphicsSceneResizeEvent immediately
+ when its geometry changes.
+
+ It's similar to QResizeEvent, but its sizes, oldSize() and newSize(), use
+ QSizeF instead of QSize.
+
+ \sa QGraphicsWidget::setGeometry(), QGraphicsWidget::resize()
+*/
+
+/*!
+ \class QGraphicsSceneMoveEvent
+ \brief The QGraphicsSceneMoveEvent class provides events for widget
+ moving in the graphics view framework.
+ \since 4.4
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ A QGraphicsWidget sends itself a QGraphicsSceneMoveEvent immediately when
+ its local position changes. The delivery is implemented as part of
+ QGraphicsItem::itemChange().
+
+ It's similar to QMoveEvent, but its positions, oldPos() and newPos(), use
+ QPointF instead of QPoint.
+
+ \sa QGraphicsItem::setPos(), QGraphicsItem::ItemPositionChange,
+ QGraphicsItem::ItemPositionHasChanged
+*/
+
+#include "qgraphicssceneevent.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#ifndef QT_NO_DEBUG
+#include <QtCore/qdebug.h>
+#endif
+#include <QtCore/qmap.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsSceneEventPrivate
+{
+public:
+ inline QGraphicsSceneEventPrivate()
+ : widget(0),
+ q_ptr(0)
+ { }
+
+ inline virtual ~QGraphicsSceneEventPrivate()
+ { }
+
+ QWidget *widget;
+ QGraphicsSceneEvent *q_ptr;
+};
+
+/*!
+ \internal
+
+ Constructs a generic graphics scene event of the specified \a type.
+*/
+QGraphicsSceneEvent::QGraphicsSceneEvent(Type type)
+ : QEvent(type), d_ptr(new QGraphicsSceneEventPrivate)
+{
+ d_ptr->q_ptr = this;
+}
+
+/*!
+ \internal
+
+ Constructs a generic graphics scene event.
+*/
+QGraphicsSceneEvent::QGraphicsSceneEvent(QGraphicsSceneEventPrivate &dd, Type type)
+ : QEvent(type), d_ptr(&dd)
+{
+ d_ptr->q_ptr = this;
+}
+
+/*!
+ Destroys the event.
+*/
+QGraphicsSceneEvent::~QGraphicsSceneEvent()
+{
+ delete d_ptr;
+}
+
+/*!
+ Returns the widget where the event originated, or 0 if the event
+ originates from another application.
+*/
+QWidget *QGraphicsSceneEvent::widget() const
+{
+ return d_ptr->widget;
+}
+
+/*!
+ \internal
+
+ Sets the \a widget related to this event.
+
+ \sa widget()
+*/
+void QGraphicsSceneEvent::setWidget(QWidget *widget)
+{
+ d_ptr->widget = widget;
+}
+
+class QGraphicsSceneMouseEventPrivate : public QGraphicsSceneEventPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsSceneMouseEvent)
+public:
+ inline QGraphicsSceneMouseEventPrivate()
+ : button(Qt::NoButton),
+ buttons(0), modifiers(0)
+ { }
+
+ QPointF pos;
+ QPointF scenePos;
+ QPoint screenPos;
+ QPointF lastPos;
+ QPointF lastScenePos;
+ QPoint lastScreenPos;
+ QMap<Qt::MouseButton, QPointF> buttonDownPos;
+ QMap<Qt::MouseButton, QPointF> buttonDownScenePos;
+ QMap<Qt::MouseButton, QPoint> buttonDownScreenPos;
+ Qt::MouseButton button;
+ Qt::MouseButtons buttons;
+ Qt::KeyboardModifiers modifiers;
+};
+
+/*!
+ \internal
+
+ Constructs a generic graphics scene mouse event of the specified \a type.
+*/
+QGraphicsSceneMouseEvent::QGraphicsSceneMouseEvent(Type type)
+ : QGraphicsSceneEvent(*new QGraphicsSceneMouseEventPrivate, type)
+{
+}
+
+/*!
+ Destroys the event.
+*/
+QGraphicsSceneMouseEvent::~QGraphicsSceneMouseEvent()
+{
+}
+
+/*!
+ Returns the mouse cursor position in item coordinates.
+
+ \sa scenePos(), screenPos(), lastPos()
+*/
+QPointF QGraphicsSceneMouseEvent::pos() const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->pos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setPos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->pos = pos;
+}
+
+/*!
+ Returns the mouse cursor position in scene coordinates.
+
+ \sa pos(), screenPos(), lastScenePos()
+*/
+QPointF QGraphicsSceneMouseEvent::scenePos() const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->scenePos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setScenePos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->scenePos = pos;
+}
+
+/*!
+ Returns the mouse cursor position in screen coordinates.
+
+ \sa pos(), scenePos(), lastScreenPos()
+*/
+QPoint QGraphicsSceneMouseEvent::screenPos() const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->screenPos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setScreenPos(const QPoint &pos)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->screenPos = pos;
+}
+
+/*!
+ Returns the mouse cursor position in item coordinates where the specified
+ \a button was clicked.
+
+ \sa buttonDownScenePos(), buttonDownScreenPos(), pos()
+*/
+QPointF QGraphicsSceneMouseEvent::buttonDownPos(Qt::MouseButton button) const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->buttonDownPos.value(button);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setButtonDownPos(Qt::MouseButton button, const QPointF &pos)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->buttonDownPos.insert(button, pos);
+}
+
+/*!
+ Returns the mouse cursor position in scene coordinates where the
+ specified \a button was clicked.
+
+ \sa buttonDownPos(), buttonDownScreenPos(), scenePos()
+*/
+QPointF QGraphicsSceneMouseEvent::buttonDownScenePos(Qt::MouseButton button) const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->buttonDownScenePos.value(button);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setButtonDownScenePos(Qt::MouseButton button, const QPointF &pos)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->buttonDownScenePos.insert(button, pos);
+}
+
+/*!
+ Returns the mouse cursor position in screen coordinates where the
+ specified \a button was clicked.
+
+ \sa screenPos(), buttonDownPos(), buttonDownScenePos()
+*/
+QPoint QGraphicsSceneMouseEvent::buttonDownScreenPos(Qt::MouseButton button) const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->buttonDownScreenPos.value(button);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setButtonDownScreenPos(Qt::MouseButton button, const QPoint &pos)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->buttonDownScreenPos.insert(button, pos);
+}
+
+/*!
+ Returns the last recorded mouse cursor position in item
+ coordinates.
+
+ \sa lastScenePos(), lastScreenPos(), pos()
+*/
+QPointF QGraphicsSceneMouseEvent::lastPos() const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->lastPos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setLastPos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->lastPos = pos;
+}
+
+/*!
+ Returns the last recorded mouse cursor position in scene
+ coordinates. The last recorded position is the position of
+ the previous mouse event received by the view that created
+ the event.
+
+ \sa lastPos(), lastScreenPos(), scenePos()
+*/
+QPointF QGraphicsSceneMouseEvent::lastScenePos() const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->lastScenePos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setLastScenePos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->lastScenePos = pos;
+}
+
+/*!
+ Returns the last recorded mouse cursor position in screen
+ coordinates. The last recorded position is the position of
+ the previous mouse event received by the view that created
+ the event.
+
+ \sa lastPos(), lastScenePos(), screenPos()
+*/
+QPoint QGraphicsSceneMouseEvent::lastScreenPos() const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->lastScreenPos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setLastScreenPos(const QPoint &pos)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->lastScreenPos = pos;
+}
+
+/*!
+ Returns the combination of mouse buttons that were pressed at the
+ time the event was sent.
+
+ \sa button(), modifiers()
+*/
+Qt::MouseButtons QGraphicsSceneMouseEvent::buttons() const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->buttons;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setButtons(Qt::MouseButtons buttons)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->buttons = buttons;
+}
+
+/*!
+ Returns the mouse button (if any) that caused the event.
+
+ \sa buttons(), modifiers()
+*/
+Qt::MouseButton QGraphicsSceneMouseEvent::button() const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->button;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setButton(Qt::MouseButton button)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->button = button;
+}
+
+/*!
+ Returns the keyboard modifiers in use at the time the event was
+ sent.
+
+ \sa buttons(), button()
+*/
+Qt::KeyboardModifiers QGraphicsSceneMouseEvent::modifiers() const
+{
+ Q_D(const QGraphicsSceneMouseEvent);
+ return d->modifiers;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMouseEvent::setModifiers(Qt::KeyboardModifiers modifiers)
+{
+ Q_D(QGraphicsSceneMouseEvent);
+ d->modifiers = modifiers;
+}
+
+class QGraphicsSceneWheelEventPrivate : public QGraphicsSceneEventPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsSceneWheelEvent)
+public:
+ inline QGraphicsSceneWheelEventPrivate()
+ : buttons(0), modifiers(0), delta(0), orientation(Qt::Horizontal)
+ { }
+
+ QPointF pos;
+ QPointF scenePos;
+ QPoint screenPos;
+ Qt::MouseButtons buttons;
+ Qt::KeyboardModifiers modifiers;
+ int delta;
+ Qt::Orientation orientation;
+};
+
+/*!
+ \internal
+
+ Constructs a QGraphicsSceneWheelEvent of type \a type, which
+ is always QEvent::GraphicsSceneWheel.
+*/
+QGraphicsSceneWheelEvent::QGraphicsSceneWheelEvent(Type type)
+ : QGraphicsSceneEvent(*new QGraphicsSceneWheelEventPrivate, type)
+{
+}
+
+/*!
+ Destroys the QGraphicsSceneWheelEvent.
+*/
+QGraphicsSceneWheelEvent::~QGraphicsSceneWheelEvent()
+{
+}
+
+/*!
+ Returns the position of the cursor in item coordinates when the
+ wheel event occurred.
+
+ \sa scenePos(), screenPos()
+*/
+QPointF QGraphicsSceneWheelEvent::pos() const
+{
+ Q_D(const QGraphicsSceneWheelEvent);
+ return d->pos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneWheelEvent::setPos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneWheelEvent);
+ d->pos = pos;
+}
+
+/*!
+ Returns the position of the cursor in scene coordinates when the wheel
+ event occurred.
+
+ \sa pos(), screenPos()
+*/
+QPointF QGraphicsSceneWheelEvent::scenePos() const
+{
+ Q_D(const QGraphicsSceneWheelEvent);
+ return d->scenePos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneWheelEvent::setScenePos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneWheelEvent);
+ d->scenePos = pos;
+}
+
+/*!
+ Returns the position of the cursor in screen coordinates when the wheel
+ event occurred.
+
+ \sa pos(), scenePos()
+*/
+QPoint QGraphicsSceneWheelEvent::screenPos() const
+{
+ Q_D(const QGraphicsSceneWheelEvent);
+ return d->screenPos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneWheelEvent::setScreenPos(const QPoint &pos)
+{
+ Q_D(QGraphicsSceneWheelEvent);
+ d->screenPos = pos;
+}
+
+/*!
+ Returns the mouse buttons that were pressed when the wheel event occurred.
+
+ \sa modifiers()
+*/
+Qt::MouseButtons QGraphicsSceneWheelEvent::buttons() const
+{
+ Q_D(const QGraphicsSceneWheelEvent);
+ return d->buttons;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneWheelEvent::setButtons(Qt::MouseButtons buttons)
+{
+ Q_D(QGraphicsSceneWheelEvent);
+ d->buttons = buttons;
+}
+
+/*!
+ Returns the keyboard modifiers that were active when the wheel event
+ occurred.
+
+ \sa buttons()
+*/
+Qt::KeyboardModifiers QGraphicsSceneWheelEvent::modifiers() const
+{
+ Q_D(const QGraphicsSceneWheelEvent);
+ return d->modifiers;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneWheelEvent::setModifiers(Qt::KeyboardModifiers modifiers)
+{
+ Q_D(QGraphicsSceneWheelEvent);
+ d->modifiers = modifiers;
+}
+
+/*!
+ Returns the distance that the wheel is rotated, in eighths (1/8s)
+ of a degree. A positive value indicates that the wheel was
+ rotated forwards away from the user; a negative value indicates
+ that the wheel was rotated backwards toward the user.
+
+ Most mouse types work in steps of 15 degrees, in which case the delta
+ value is a multiple of 120 (== 15 * 8).
+*/
+int QGraphicsSceneWheelEvent::delta() const
+{
+ Q_D(const QGraphicsSceneWheelEvent);
+ return d->delta;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneWheelEvent::setDelta(int delta)
+{
+ Q_D(QGraphicsSceneWheelEvent);
+ d->delta = delta;
+}
+
+/*!
+ Returns the wheel orientation.
+*/
+Qt::Orientation QGraphicsSceneWheelEvent::orientation() const
+{
+ Q_D(const QGraphicsSceneWheelEvent);
+ return d->orientation;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneWheelEvent::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QGraphicsSceneWheelEvent);
+ d->orientation = orientation;
+}
+
+class QGraphicsSceneContextMenuEventPrivate : public QGraphicsSceneEventPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsSceneContextMenuEvent)
+ public:
+ inline QGraphicsSceneContextMenuEventPrivate()
+ : modifiers(0), reason(QGraphicsSceneContextMenuEvent::Other)
+ { }
+
+ QPointF pos;
+ QPointF scenePos;
+ QPoint screenPos;
+ Qt::KeyboardModifiers modifiers;
+ QGraphicsSceneContextMenuEvent::Reason reason;
+};
+
+/*!
+ \internal
+
+ Constructs a graphics scene context menu event of the specified \a type.
+*/
+QGraphicsSceneContextMenuEvent::QGraphicsSceneContextMenuEvent(Type type)
+ : QGraphicsSceneEvent(*new QGraphicsSceneContextMenuEventPrivate, type)
+{
+}
+
+/*!
+ Destroys the event.
+*/
+QGraphicsSceneContextMenuEvent::~QGraphicsSceneContextMenuEvent()
+{
+}
+
+/*!
+ Returns the position of the mouse cursor in item coordinates at the moment
+ the the context menu was requested.
+
+ \sa scenePos(), screenPos()
+*/
+QPointF QGraphicsSceneContextMenuEvent::pos() const
+{
+ Q_D(const QGraphicsSceneContextMenuEvent);
+ return d->pos;
+}
+
+/*!
+ \fn void QGraphicsSceneContextMenuEvent::setPos(const QPointF &point)
+ \internal
+
+ Sets the position associated with the context menu to the given \a point
+ in item coordinates.
+*/
+void QGraphicsSceneContextMenuEvent::setPos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneContextMenuEvent);
+ d->pos = pos;
+}
+
+/*!
+ Returns the position of the mouse cursor in scene coordinates at the moment the
+ the context menu was requested.
+
+ \sa pos(), screenPos()
+*/
+QPointF QGraphicsSceneContextMenuEvent::scenePos() const
+{
+ Q_D(const QGraphicsSceneContextMenuEvent);
+ return d->scenePos;
+}
+
+/*!
+ \fn void QGraphicsSceneContextMenuEvent::setScenePos(const QPointF &point)
+ \internal
+
+ Sets the position associated with the context menu to the given \a point
+ in scene coordinates.
+*/
+void QGraphicsSceneContextMenuEvent::setScenePos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneContextMenuEvent);
+ d->scenePos = pos;
+}
+
+/*!
+ Returns the position of the mouse cursor in screen coordinates at the moment the
+ the context menu was requested.
+
+ \sa pos(), scenePos()
+*/
+QPoint QGraphicsSceneContextMenuEvent::screenPos() const
+{
+ Q_D(const QGraphicsSceneContextMenuEvent);
+ return d->screenPos;
+}
+
+/*!
+ \fn void QGraphicsSceneContextMenuEvent::setScreenPos(const QPoint &point)
+ \internal
+
+ Sets the position associated with the context menu to the given \a point
+ in screen coordinates.
+*/
+void QGraphicsSceneContextMenuEvent::setScreenPos(const QPoint &pos)
+{
+ Q_D(QGraphicsSceneContextMenuEvent);
+ d->screenPos = pos;
+}
+
+/*!
+ Returns the keyboard modifiers in use when the context menu was requested.
+*/
+Qt::KeyboardModifiers QGraphicsSceneContextMenuEvent::modifiers() const
+{
+ Q_D(const QGraphicsSceneContextMenuEvent);
+ return d->modifiers;
+}
+
+/*!
+ \internal
+
+ Sets the keyboard modifiers associated with the context menu to the \a
+ modifiers specified.
+*/
+void QGraphicsSceneContextMenuEvent::setModifiers(Qt::KeyboardModifiers modifiers)
+{
+ Q_D(QGraphicsSceneContextMenuEvent);
+ d->modifiers = modifiers;
+}
+
+/*!
+ Returns the reason for the context menu event.
+
+ \sa QGraphicsSceneContextMenuEvent::Reason
+*/
+QGraphicsSceneContextMenuEvent::Reason QGraphicsSceneContextMenuEvent::reason() const
+{
+ Q_D(const QGraphicsSceneContextMenuEvent);
+ return d->reason;
+}
+
+/*!
+ \internal
+ Sets the reason for the context menu event to \a reason.
+
+ \sa reason()
+*/
+void QGraphicsSceneContextMenuEvent::setReason(Reason reason)
+{
+ Q_D(QGraphicsSceneContextMenuEvent);
+ d->reason = reason;
+}
+
+class QGraphicsSceneHoverEventPrivate : public QGraphicsSceneEventPrivate
+{
+public:
+ QPointF pos;
+ QPointF scenePos;
+ QPoint screenPos;
+ QPointF lastPos;
+ QPointF lastScenePos;
+ QPoint lastScreenPos;
+ Qt::KeyboardModifiers modifiers;
+};
+
+/*!
+ \internal
+
+ Constructs a graphics scene hover event of the specified \a type.
+*/
+QGraphicsSceneHoverEvent::QGraphicsSceneHoverEvent(Type type)
+ : QGraphicsSceneEvent(*new QGraphicsSceneHoverEventPrivate, type)
+{
+}
+
+/*!
+ Destroys the event.
+*/
+QGraphicsSceneHoverEvent::~QGraphicsSceneHoverEvent()
+{
+}
+
+/*!
+ Returns the position of the mouse cursor in item coordinates at the moment
+ the the hover event was sent.
+
+ \sa scenePos(), screenPos()
+*/
+QPointF QGraphicsSceneHoverEvent::pos() const
+{
+ Q_D(const QGraphicsSceneHoverEvent);
+ return d->pos;
+}
+
+/*!
+ \fn void QGraphicsSceneHoverEvent::setPos(const QPointF &point)
+ \internal
+
+ Sets the position associated with the hover event to the given \a point in
+ item coordinates.
+*/
+void QGraphicsSceneHoverEvent::setPos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneHoverEvent);
+ d->pos = pos;
+}
+
+/*!
+ Returns the position of the mouse cursor in scene coordinates at the
+ moment the the hover event was sent.
+
+ \sa pos(), screenPos()
+*/
+QPointF QGraphicsSceneHoverEvent::scenePos() const
+{
+ Q_D(const QGraphicsSceneHoverEvent);
+ return d->scenePos;
+}
+
+/*!
+ \fn void QGraphicsSceneHoverEvent::setScenePos(const QPointF &point)
+ \internal
+
+ Sets the position associated with the hover event to the given \a point in
+ scene coordinates.
+*/
+void QGraphicsSceneHoverEvent::setScenePos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneHoverEvent);
+ d->scenePos = pos;
+}
+
+/*!
+ Returns the position of the mouse cursor in screen coordinates at the
+ moment the the hover event was sent.
+
+ \sa pos(), scenePos()
+*/
+QPoint QGraphicsSceneHoverEvent::screenPos() const
+{
+ Q_D(const QGraphicsSceneHoverEvent);
+ return d->screenPos;
+}
+
+/*!
+ \fn void QGraphicsSceneHoverEvent::setScreenPos(const QPoint &point)
+ \internal
+
+ Sets the position associated with the hover event to the given \a point in
+ screen coordinates.
+*/
+void QGraphicsSceneHoverEvent::setScreenPos(const QPoint &pos)
+{
+ Q_D(QGraphicsSceneHoverEvent);
+ d->screenPos = pos;
+}
+
+/*!
+ \since 4.4
+
+ Returns the last recorded mouse cursor position in item coordinates.
+
+ \sa lastScenePos(), lastScreenPos(), pos()
+*/
+QPointF QGraphicsSceneHoverEvent::lastPos() const
+{
+ Q_D(const QGraphicsSceneHoverEvent);
+ return d->lastPos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneHoverEvent::setLastPos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneHoverEvent);
+ d->lastPos = pos;
+}
+
+/*!
+ \since 4.4
+
+ Returns the last recorded, the scene coordinates of the previous mouse or
+ hover event received by the view, that created the event mouse cursor
+ position in scene coordinates.
+
+ \sa lastPos(), lastScreenPos(), scenePos()
+*/
+QPointF QGraphicsSceneHoverEvent::lastScenePos() const
+{
+ Q_D(const QGraphicsSceneHoverEvent);
+ return d->lastScenePos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneHoverEvent::setLastScenePos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneHoverEvent);
+ d->lastScenePos = pos;
+}
+
+/*!
+ \since 4.4
+
+ Returns the last recorded mouse cursor position in screen coordinates. The
+ last recorded position is the position of the previous mouse or hover
+ event received by the view that created the event.
+
+ \sa lastPos(), lastScenePos(), screenPos()
+*/
+QPoint QGraphicsSceneHoverEvent::lastScreenPos() const
+{
+ Q_D(const QGraphicsSceneHoverEvent);
+ return d->lastScreenPos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneHoverEvent::setLastScreenPos(const QPoint &pos)
+{
+ Q_D(QGraphicsSceneHoverEvent);
+ d->lastScreenPos = pos;
+}
+
+/*!
+ \since 4.4
+
+ Returns the keyboard modifiers at the moment the the hover event was sent.
+*/
+Qt::KeyboardModifiers QGraphicsSceneHoverEvent::modifiers() const
+{
+ Q_D(const QGraphicsSceneHoverEvent);
+ return d->modifiers;
+}
+
+/*!
+ \fn void QGraphicsSceneHoverEvent::setModifiers(Qt::KeyboardModifiers modifiers)
+ \internal
+
+ Sets the modifiers for the current hover event to \a modifiers.
+*/
+void QGraphicsSceneHoverEvent::setModifiers(Qt::KeyboardModifiers modifiers)
+{
+ Q_D(QGraphicsSceneHoverEvent);
+ d->modifiers = modifiers;
+}
+
+class QGraphicsSceneHelpEventPrivate : public QGraphicsSceneEventPrivate
+{
+public:
+ QPointF scenePos;
+ QPoint screenPos;
+};
+
+/*!
+ \internal
+
+ Constructs a graphics scene help event of the specified \a type.
+*/
+QGraphicsSceneHelpEvent::QGraphicsSceneHelpEvent(Type type)
+ : QGraphicsSceneEvent(*new QGraphicsSceneHelpEventPrivate, type)
+{
+}
+
+/*!
+ Destroys the event.
+*/
+QGraphicsSceneHelpEvent::~QGraphicsSceneHelpEvent()
+{
+}
+
+/*!
+ Returns the position of the mouse cursor in scene coordinates at the
+ moment the the help event was sent.
+
+ \sa screenPos()
+*/
+QPointF QGraphicsSceneHelpEvent::scenePos() const
+{
+ Q_D(const QGraphicsSceneHelpEvent);
+ return d->scenePos;
+}
+
+/*!
+ \fn void QGraphicsSceneHelpEvent::setScenePos(const QPointF &point)
+ \internal
+
+ Sets the position associated with the context menu to the given \a point
+ in scene coordinates.
+*/
+void QGraphicsSceneHelpEvent::setScenePos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneHelpEvent);
+ d->scenePos = pos;
+}
+
+/*!
+ Returns the position of the mouse cursor in screen coordinates at the
+ moment the the help event was sent.
+
+ \sa scenePos()
+*/
+QPoint QGraphicsSceneHelpEvent::screenPos() const
+{
+ Q_D(const QGraphicsSceneHelpEvent);
+ return d->screenPos;
+}
+
+/*!
+ \fn void QGraphicsSceneHelpEvent::setScreenPos(const QPoint &point)
+ \internal
+
+ Sets the position associated with the context menu to the given \a point
+ in screen coordinates.
+*/
+void QGraphicsSceneHelpEvent::setScreenPos(const QPoint &pos)
+{
+ Q_D(QGraphicsSceneHelpEvent);
+ d->screenPos = pos;
+}
+
+class QGraphicsSceneDragDropEventPrivate : public QGraphicsSceneEventPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsSceneDragDropEvent)
+public:
+ inline QGraphicsSceneDragDropEventPrivate()
+ : source(0), mimeData(0)
+ { }
+
+ QPointF pos;
+ QPointF scenePos;
+ QPoint screenPos;
+ Qt::MouseButtons buttons;
+ Qt::KeyboardModifiers modifiers;
+ Qt::DropActions possibleActions;
+ Qt::DropAction proposedAction;
+ Qt::DropAction dropAction;
+ QWidget *source;
+ const QMimeData *mimeData;
+};
+
+/*!
+ \internal
+
+ Constructs a new QGraphicsSceneDragDropEvent of the
+ specified \a type. The type can be either
+ QEvent::GraphicsSceneDragEnter, QEvent::GraphicsSceneDragLeave,
+ QEvent::GraphicsSceneDragMove, or QEvent::GraphicsSceneDrop.
+*/
+QGraphicsSceneDragDropEvent::QGraphicsSceneDragDropEvent(Type type)
+ : QGraphicsSceneEvent(*new QGraphicsSceneDragDropEventPrivate, type)
+{
+}
+
+/*!
+ Destroys the object.
+*/
+QGraphicsSceneDragDropEvent::~QGraphicsSceneDragDropEvent()
+{
+}
+
+/*!
+ Returns the mouse position of the event relative to the
+ view that sent the event.
+
+ \sa QGraphicsView, screenPos(), scenePos()
+*/
+QPointF QGraphicsSceneDragDropEvent::pos() const
+{
+ Q_D(const QGraphicsSceneDragDropEvent);
+ return d->pos;
+}
+
+/*!
+ \internal
+ Sets the position of the mouse to \a pos; this should be
+ relative to the widget that generated the event, which normally
+ is a QGraphicsView.
+
+ \sa pos(), setScenePos(), setScreenPos()
+*/
+
+void QGraphicsSceneDragDropEvent::setPos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneDragDropEvent);
+ d->pos = pos;
+}
+
+/*!
+ Returns the position of the mouse in scene coordinates.
+
+ \sa pos(), screenPos()
+*/
+QPointF QGraphicsSceneDragDropEvent::scenePos() const
+{
+ Q_D(const QGraphicsSceneDragDropEvent);
+ return d->scenePos;
+}
+
+/*!
+ \internal
+ Sets the scene position of the mouse to \a pos.
+
+ \sa scenePos(), setScreenPos(), setPos()
+*/
+void QGraphicsSceneDragDropEvent::setScenePos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneDragDropEvent);
+ d->scenePos = pos;
+}
+
+/*!
+ Returns the position of the mouse relative to the screen.
+
+ \sa pos(), scenePos()
+*/
+QPoint QGraphicsSceneDragDropEvent::screenPos() const
+{
+ Q_D(const QGraphicsSceneDragDropEvent);
+ return d->screenPos;
+}
+
+/*!
+ \internal
+ Sets the mouse position relative to the screen to \a pos.
+
+ \sa screenPos(), setScenePos(), setPos()
+*/
+void QGraphicsSceneDragDropEvent::setScreenPos(const QPoint &pos)
+{
+ Q_D(QGraphicsSceneDragDropEvent);
+ d->screenPos = pos;
+}
+
+/*!
+ Returns a Qt::MouseButtons value indicating which buttons
+ were pressed on the mouse when this mouse event was
+ generated.
+
+ \sa Qt::MouseButtons
+*/
+Qt::MouseButtons QGraphicsSceneDragDropEvent::buttons() const
+{
+ Q_D(const QGraphicsSceneDragDropEvent);
+ return d->buttons;
+}
+
+/*!
+ \internal
+ Sets the mouse buttons that were pressed when the event was
+ created to \a buttons.
+
+ \sa Qt::MouseButtons, buttons()
+*/
+void QGraphicsSceneDragDropEvent::setButtons(Qt::MouseButtons buttons)
+{
+ Q_D(QGraphicsSceneDragDropEvent);
+ d->buttons = buttons;
+}
+
+/*!
+ Returns the keyboard modifiers that were pressed when the drag
+ and drop event was created.
+
+ \sa Qt::KeyboardModifiers
+*/
+Qt::KeyboardModifiers QGraphicsSceneDragDropEvent::modifiers() const
+{
+ Q_D(const QGraphicsSceneDragDropEvent);
+ return d->modifiers;
+}
+
+/*!
+ \internal
+ Sets the keyboard modifiers that were pressed when the event
+ was created to \a modifiers.
+
+ \sa Qt::KeyboardModifiers, modifiers()
+*/
+
+void QGraphicsSceneDragDropEvent::setModifiers(Qt::KeyboardModifiers modifiers)
+{
+ Q_D(QGraphicsSceneDragDropEvent);
+ d->modifiers = modifiers;
+}
+
+/*!
+ Returns the possible drop actions that the drag and
+ drop can result in.
+
+ \sa Qt::DropActions
+*/
+
+Qt::DropActions QGraphicsSceneDragDropEvent::possibleActions() const
+{
+ Q_D(const QGraphicsSceneDragDropEvent);
+ return d->possibleActions;
+}
+
+/*!
+ \internal
+ Sets the possible drop actions that the drag can
+ result in to \a actions.
+
+ \sa Qt::DropActions, possibleActions()
+*/
+void QGraphicsSceneDragDropEvent::setPossibleActions(Qt::DropActions actions)
+{
+ Q_D(QGraphicsSceneDragDropEvent);
+ d->possibleActions = actions;
+}
+
+/*!
+ Returns the drop action that is proposed, i.e., preferred.
+ The action must be one of the possible actions as defined by
+ \c possibleActions().
+
+ \sa Qt::DropAction, possibleActions()
+*/
+
+Qt::DropAction QGraphicsSceneDragDropEvent::proposedAction() const
+{
+ Q_D(const QGraphicsSceneDragDropEvent);
+ return d->proposedAction;
+}
+
+/*!
+ \internal
+ Sets the proposed action to \a action. The proposed action
+ is a Qt::DropAction that is one of the possible actions as
+ given by \c possibleActions().
+
+ \sa proposedAction(), Qt::DropAction, possibleActions()
+*/
+
+void QGraphicsSceneDragDropEvent::setProposedAction(Qt::DropAction action)
+{
+ Q_D(QGraphicsSceneDragDropEvent);
+ d->proposedAction = action;
+}
+
+/*!
+ Sets the proposed action as accepted, i.e, the drop action
+ is set to the proposed action. This is equal to:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicssceneevent.cpp 0
+
+ When using this function, one should not call \c accept().
+
+ \sa dropAction(), setDropAction(), proposedAction()
+*/
+
+void QGraphicsSceneDragDropEvent::acceptProposedAction()
+{
+ Q_D(QGraphicsSceneDragDropEvent);
+ d->dropAction = d->proposedAction;
+}
+
+/*!
+ Returns the action that was performed in this drag and drop.
+ This should be set by the receiver of the drop and is
+ returned by QDrag::start().
+
+ \sa setDropAction(), acceptProposedAction()
+*/
+
+Qt::DropAction QGraphicsSceneDragDropEvent::dropAction() const
+{
+ Q_D(const QGraphicsSceneDragDropEvent);
+ return d->dropAction;
+}
+
+/*!
+ This function lets the receiver of the drop set the drop
+ action that was performed to \a action, which should be one
+ of the
+ \l{QGraphicsSceneDragDropEvent::possibleActions()}{possible
+ actions}. Call \c accept() in stead of \c
+ acceptProposedAction() if you use this function.
+
+ \sa dropAction(), accept(), possibleActions()
+*/
+void QGraphicsSceneDragDropEvent::setDropAction(Qt::DropAction action)
+{
+ Q_D(QGraphicsSceneDragDropEvent);
+ d->dropAction = action;
+}
+
+/*!
+ This function returns the QGraphicsView that created the
+ QGraphicsSceneDragDropEvent.
+*/
+QWidget *QGraphicsSceneDragDropEvent::source() const
+{
+ Q_D(const QGraphicsSceneDragDropEvent);
+ return d->source;
+}
+
+/*!
+ \internal
+ This function set the source widget, i.e., the widget that
+ created the drop event, to \a source.
+*/
+void QGraphicsSceneDragDropEvent::setSource(QWidget *source)
+{
+ Q_D(QGraphicsSceneDragDropEvent);
+ d->source = source;
+}
+
+/*!
+ This function returns the MIME data of the event.
+*/
+const QMimeData *QGraphicsSceneDragDropEvent::mimeData() const
+{
+ Q_D(const QGraphicsSceneDragDropEvent);
+ return d->mimeData;
+}
+
+/*!
+ \internal
+ This function sets the MIME data for the event.
+*/
+void QGraphicsSceneDragDropEvent::setMimeData(const QMimeData *data)
+{
+ Q_D(QGraphicsSceneDragDropEvent);
+ d->mimeData = data;
+}
+
+class QGraphicsSceneResizeEventPrivate : public QGraphicsSceneEventPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsSceneResizeEvent)
+public:
+ inline QGraphicsSceneResizeEventPrivate()
+ { }
+
+ QSizeF oldSize;
+ QSizeF newSize;
+};
+
+/*!
+ Constructs a QGraphicsSceneResizeEvent.
+*/
+QGraphicsSceneResizeEvent::QGraphicsSceneResizeEvent()
+ : QGraphicsSceneEvent(*new QGraphicsSceneResizeEventPrivate, QEvent::GraphicsSceneResize)
+{
+}
+
+/*!
+ Destroys the QGraphicsSceneResizeEvent.
+*/
+QGraphicsSceneResizeEvent::~QGraphicsSceneResizeEvent()
+{
+}
+
+/*!
+ Returns the old size (i.e., the size immediately before the widget was
+ resized).
+
+ \sa newSize(), QGraphicsWidget::resize()
+*/
+QSizeF QGraphicsSceneResizeEvent::oldSize() const
+{
+ Q_D(const QGraphicsSceneResizeEvent);
+ return d->oldSize;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneResizeEvent::setOldSize(const QSizeF &size)
+{
+ Q_D(QGraphicsSceneResizeEvent);
+ d->oldSize = size;
+}
+
+/*!
+ Returns the new size (i.e., the current size).
+
+ \sa oldSize(), QGraphicsWidget::resize()
+*/
+QSizeF QGraphicsSceneResizeEvent::newSize() const
+{
+ Q_D(const QGraphicsSceneResizeEvent);
+ return d->newSize;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneResizeEvent::setNewSize(const QSizeF &size)
+{
+ Q_D(QGraphicsSceneResizeEvent);
+ d->newSize = size;
+}
+
+class QGraphicsSceneMoveEventPrivate : public QGraphicsSceneEventPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsSceneMoveEvent)
+public:
+ inline QGraphicsSceneMoveEventPrivate()
+ { }
+
+ QPointF oldPos;
+ QPointF newPos;
+};
+
+/*!
+ Constructs a QGraphicsSceneMoveEvent.
+*/
+QGraphicsSceneMoveEvent::QGraphicsSceneMoveEvent()
+ : QGraphicsSceneEvent(*new QGraphicsSceneMoveEventPrivate, QEvent::GraphicsSceneMove)
+{
+}
+
+/*!
+ Destroys the QGraphicsSceneMoveEvent.
+*/
+QGraphicsSceneMoveEvent::~QGraphicsSceneMoveEvent()
+{
+}
+
+/*!
+ Returns the old position (i.e., the position immediatly before the widget
+ was moved).
+
+ \sa newPos(), QGraphicsItem::setPos()
+*/
+QPointF QGraphicsSceneMoveEvent::oldPos() const
+{
+ Q_D(const QGraphicsSceneMoveEvent);
+ return d->oldPos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMoveEvent::setOldPos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneMoveEvent);
+ d->oldPos = pos;
+}
+
+/*!
+ Returns the new position (i.e., the current position).
+
+ \sa oldPos(), QGraphicsItem::setPos()
+*/
+QPointF QGraphicsSceneMoveEvent::newPos() const
+{
+ Q_D(const QGraphicsSceneMoveEvent);
+ return d->newPos;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneMoveEvent::setNewPos(const QPointF &pos)
+{
+ Q_D(QGraphicsSceneMoveEvent);
+ d->newPos = pos;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicssceneevent.h b/src/gui/graphicsview/qgraphicssceneevent.h
new file mode 100644
index 0000000..be50e96
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicssceneevent.h
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSSCENEEVENT_H
+#define QGRAPHICSSCENEEVENT_H
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qpoint.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+class QMimeData;
+class QPointF;
+class QSizeF;
+class QWidget;
+
+class QGraphicsSceneEventPrivate;
+class Q_GUI_EXPORT QGraphicsSceneEvent : public QEvent
+{
+public:
+ QGraphicsSceneEvent(Type type);
+ ~QGraphicsSceneEvent();
+
+ QWidget *widget() const;
+ void setWidget(QWidget *widget);
+
+protected:
+ QGraphicsSceneEvent(QGraphicsSceneEventPrivate &dd, Type type = None);
+ QGraphicsSceneEventPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(QGraphicsSceneEvent)
+};
+
+class QGraphicsSceneMouseEventPrivate;
+class Q_GUI_EXPORT QGraphicsSceneMouseEvent : public QGraphicsSceneEvent
+{
+public:
+ QGraphicsSceneMouseEvent(Type type = None);
+ ~QGraphicsSceneMouseEvent();
+
+ QPointF pos() const;
+ void setPos(const QPointF &pos);
+
+ QPointF scenePos() const;
+ void setScenePos(const QPointF &pos);
+
+ QPoint screenPos() const;
+ void setScreenPos(const QPoint &pos);
+
+ QPointF buttonDownPos(Qt::MouseButton button) const;
+ void setButtonDownPos(Qt::MouseButton button, const QPointF &pos);
+
+ QPointF buttonDownScenePos(Qt::MouseButton button) const;
+ void setButtonDownScenePos(Qt::MouseButton button, const QPointF &pos);
+
+ QPoint buttonDownScreenPos(Qt::MouseButton button) const;
+ void setButtonDownScreenPos(Qt::MouseButton button, const QPoint &pos);
+
+ QPointF lastPos() const;
+ void setLastPos(const QPointF &pos);
+
+ QPointF lastScenePos() const;
+ void setLastScenePos(const QPointF &pos);
+
+ QPoint lastScreenPos() const;
+ void setLastScreenPos(const QPoint &pos);
+
+ Qt::MouseButtons buttons() const;
+ void setButtons(Qt::MouseButtons buttons);
+
+ Qt::MouseButton button() const;
+ void setButton(Qt::MouseButton button);
+
+ Qt::KeyboardModifiers modifiers() const;
+ void setModifiers(Qt::KeyboardModifiers modifiers);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsSceneMouseEvent)
+};
+
+class QGraphicsSceneWheelEventPrivate;
+class Q_GUI_EXPORT QGraphicsSceneWheelEvent : public QGraphicsSceneEvent
+{
+public:
+ QGraphicsSceneWheelEvent(Type type = None);
+ ~QGraphicsSceneWheelEvent();
+
+ QPointF pos() const;
+ void setPos(const QPointF &pos);
+
+ QPointF scenePos() const;
+ void setScenePos(const QPointF &pos);
+
+ QPoint screenPos() const;
+ void setScreenPos(const QPoint &pos);
+
+ Qt::MouseButtons buttons() const;
+ void setButtons(Qt::MouseButtons buttons);
+
+ Qt::KeyboardModifiers modifiers() const;
+ void setModifiers(Qt::KeyboardModifiers modifiers);
+
+ int delta() const;
+ void setDelta(int delta);
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsSceneWheelEvent)
+};
+
+class QGraphicsSceneContextMenuEventPrivate;
+class Q_GUI_EXPORT QGraphicsSceneContextMenuEvent : public QGraphicsSceneEvent
+{
+public:
+ enum Reason { Mouse, Keyboard, Other };
+
+ QGraphicsSceneContextMenuEvent(Type type = None);
+ ~QGraphicsSceneContextMenuEvent();
+
+ QPointF pos() const;
+ void setPos(const QPointF &pos);
+
+ QPointF scenePos() const;
+ void setScenePos(const QPointF &pos);
+
+ QPoint screenPos() const;
+ void setScreenPos(const QPoint &pos);
+
+ Qt::KeyboardModifiers modifiers() const;
+ void setModifiers(Qt::KeyboardModifiers modifiers);
+
+ Reason reason() const;
+ void setReason(Reason reason);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsSceneContextMenuEvent)
+};
+
+class QGraphicsSceneHoverEventPrivate;
+class Q_GUI_EXPORT QGraphicsSceneHoverEvent : public QGraphicsSceneEvent
+{
+public:
+ QGraphicsSceneHoverEvent(Type type = None);
+ ~QGraphicsSceneHoverEvent();
+
+ QPointF pos() const;
+ void setPos(const QPointF &pos);
+
+ QPointF scenePos() const;
+ void setScenePos(const QPointF &pos);
+
+ QPoint screenPos() const;
+ void setScreenPos(const QPoint &pos);
+
+ QPointF lastPos() const;
+ void setLastPos(const QPointF &pos);
+
+ QPointF lastScenePos() const;
+ void setLastScenePos(const QPointF &pos);
+
+ QPoint lastScreenPos() const;
+ void setLastScreenPos(const QPoint &pos);
+
+ Qt::KeyboardModifiers modifiers() const;
+ void setModifiers(Qt::KeyboardModifiers modifiers);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsSceneHoverEvent)
+};
+
+class QGraphicsSceneHelpEventPrivate;
+class Q_GUI_EXPORT QGraphicsSceneHelpEvent : public QGraphicsSceneEvent
+{
+public:
+ QGraphicsSceneHelpEvent(Type type = None);
+ ~QGraphicsSceneHelpEvent();
+
+ QPointF scenePos() const;
+ void setScenePos(const QPointF &pos);
+
+ QPoint screenPos() const;
+ void setScreenPos(const QPoint &pos);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsSceneHelpEvent)
+};
+
+class QGraphicsSceneDragDropEventPrivate;
+class Q_GUI_EXPORT QGraphicsSceneDragDropEvent : public QGraphicsSceneEvent
+{
+public:
+ QGraphicsSceneDragDropEvent(Type type = None);
+ ~QGraphicsSceneDragDropEvent();
+
+ QPointF pos() const;
+ void setPos(const QPointF &pos);
+
+ QPointF scenePos() const;
+ void setScenePos(const QPointF &pos);
+
+ QPoint screenPos() const;
+ void setScreenPos(const QPoint &pos);
+
+ Qt::MouseButtons buttons() const;
+ void setButtons(Qt::MouseButtons buttons);
+
+ Qt::KeyboardModifiers modifiers() const;
+ void setModifiers(Qt::KeyboardModifiers modifiers);
+
+ Qt::DropActions possibleActions() const;
+ void setPossibleActions(Qt::DropActions actions);
+
+ Qt::DropAction proposedAction() const;
+ void setProposedAction(Qt::DropAction action);
+ void acceptProposedAction();
+
+ Qt::DropAction dropAction() const;
+ void setDropAction(Qt::DropAction action);
+
+ QWidget *source() const;
+ void setSource(QWidget *source);
+
+ const QMimeData *mimeData() const;
+ void setMimeData(const QMimeData *data);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsSceneDragDropEvent)
+};
+
+class QGraphicsSceneResizeEventPrivate;
+class Q_GUI_EXPORT QGraphicsSceneResizeEvent : public QGraphicsSceneEvent
+{
+ Q_DECLARE_PRIVATE(QGraphicsSceneResizeEvent)
+public:
+ QGraphicsSceneResizeEvent();
+ ~QGraphicsSceneResizeEvent();
+
+ QSizeF oldSize() const;
+ void setOldSize(const QSizeF &size);
+
+ QSizeF newSize() const;
+ void setNewSize(const QSizeF &size);
+};
+
+class QGraphicsSceneMoveEventPrivate;
+class Q_GUI_EXPORT QGraphicsSceneMoveEvent : public QGraphicsSceneEvent
+{
+ Q_DECLARE_PRIVATE(QGraphicsSceneMoveEvent)
+public:
+ QGraphicsSceneMoveEvent();
+ ~QGraphicsSceneMoveEvent();
+
+ QPointF oldPos() const;
+ void setOldPos(const QPointF &pos);
+
+ QPointF newPos() const;
+ void setNewPos(const QPointF &pos);
+};
+
+#endif // QT_NO_GRAPHICSVIEW
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
new file mode 100644
index 0000000..15c0e25
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -0,0 +1,3887 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QGRAPHICSVIEW_DEBUG
+
+static const int QGRAPHICSVIEW_REGION_RECT_THRESHOLD = 50;
+
+static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < 2^9
+
+/*!
+ \class QGraphicsView
+ \brief The QGraphicsView class provides a widget for displaying the
+ contents of a QGraphicsScene.
+ \since 4.2
+ \ingroup multimedia
+ \ingroup graphicsview-api
+ \mainclass
+
+ QGraphicsView visualizes the contents of a QGraphicsScene in a scrollable
+ viewport. To create a scene with geometrical items, see QGraphicsScene's
+ documentation. QGraphicsView is part of \l{The Graphics View Framework}.
+
+ To visualize a scene, you start by constructing a QGraphicsView object,
+ passing the address of the scene you want to visualize to QGraphicsView's
+ constructor. Alternatively, you can call setScene() to set the scene at a
+ later point. After you call show(), the view will by default scroll to the
+ center of the scene and display any items that are visible at this
+ point. For example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 0
+
+ You can explicitly scroll to any position on the scene by using the
+ scroll bars, or by calling centerOn(). By passing a point to centerOn(),
+ QGraphicsView will scroll its viewport to ensure that the point is
+ centered in the view. An overload is provided for scrolling to a
+ QGraphicsItem, in which case QGraphicsView will see to that the center of
+ the item is centered in the view. If all you want is to ensure that a
+ certain area is visible, (but not necessarily centered,) you can call
+ ensureVisible() instead.
+
+ QGraphicsView can be used to visualize a whole scene, or only parts of it.
+ The visualized area is by default detected automatically when the view is
+ displayed for the first time (by calling
+ QGraphicsScene::itemsBoundingRect()). To set the visualized area rectangle
+ yourself, you can call setSceneRect(). This will adjust the scroll bars'
+ ranges appropriately. Note that although the scene supports a virtually
+ unlimited size, the range of the scroll bars will never exceed the range of
+ an integer (INT_MIN, INT_MAX). When the scene is larger than the scroll
+ bars' values, you can choose to use translate() to navigate the scene
+ instead.
+
+ QGraphicsView visualizes the scene by calling render(). By default, the
+ items are drawn onto the viewport by using a regular QPainter, and using
+ default render hints. To change the default render hints that
+ QGraphicsView passes to QPainter when painting items, you can call
+ setRenderHints().
+
+ By default, QGraphicsView provides a regular QWidget for the viewport
+ widget. You can access this widget by calling viewport(), or you can
+ replace it by calling setViewport(). To render using OpenGL, simply call
+ setViewport(new QGLWidget). QGraphicsView takes ownership of the viewport
+ widget.
+
+ QGraphicsView supports affine transformations, using QMatrix. You can
+ either pass a matrix to setMatrix(), or you can call one of the
+ convenience functions rotate(), scale(), translate() or shear(). The most
+ two common transformations are scaling, which is used to implement
+ zooming, and rotation. QGraphicsView keeps the center of the view fixed
+ during a transformation.
+
+ You can interact with the items on the scene by using the mouse and
+ keyboard. QGraphicsView translates the mouse and key events into \e scene
+ events, (events that inherit QGraphicsSceneEvent,), and forward them to
+ the visualized scene. In the end, it's the individual item that handles
+ the events and reacts to them. For example, if you click on a selectable
+ item, the item will typically let the scene know that it has been
+ selected, and it will also redraw itself to display a selection
+ rectangle. Similiary, if you click and drag the mouse to move a movable
+ item, it's the item that handles the mouse moves and moves itself. Item
+ interaction is enabled by default, and you can toggle it by calling
+ setInteractive().
+
+ You can also provide your own custom scene interaction, by creating a
+ subclass of QGraphicsView, and reimplementing the mouse and key event
+ handlers. To simplify how you programmatically interact with items in the
+ view, QGraphicsView provides the mapping functions mapToScene() and
+ mapFromScene(), and the item accessors items() and itemAt(). These
+ functions allow you to map points, rectangles, polygons and paths between
+ view coordinates and scene coordinates, and to find items on the scene
+ using view coordinates.
+
+ \img graphicsview-view.png
+
+ \sa QGraphicsScene, QGraphicsItem, QGraphicsSceneEvent
+*/
+
+/*!
+ \enum QGraphicsView::ViewportAnchor
+
+ This enums describe the possible anchors that QGraphicsView can
+ use when the user resizes the view or when the view is
+ transformed.
+
+ \value NoAnchor No anchor, i.e. the view leaves the scene's
+ position unchanged.
+ \value AnchorViewCenter The scene point at the center of the view
+ is used as the anchor.
+ \value AnchorUnderMouse The point under the mouse is used as the anchor.
+
+ \sa resizeAnchor, transformationAnchor
+*/
+
+/*!
+ \enum QGraphicsView::ViewportUpdateMode
+
+ \since 4.3
+
+ This enum describes how QGraphicsView updates its viewport when the scene
+ contents change or are exposed.
+
+ \value FullViewportUpdate When any visible part of the scene changes or is
+ reexposed, QGraphicsView will update the entire viewport. This approach is
+ fastest when QGraphicsView spends more time figuring out what to draw than
+ it would spend drawing (e.g., when very many small items are repeatedly
+ updated). This is the preferred update mode for viewports that do not
+ support partial updates, such as QGLWidget, and for viewports that need to
+ disable scroll optimization.
+
+ \value MinimalViewportUpdate QGraphicsView will determine the minimal
+ viewport region that requires a redraw, minimizing the time spent drawing
+ by avoiding a redraw of areas that have not changed. This is
+ QGraphicsView's default mode. Although this approach provides the best
+ performance in general, if there are many small visible changes on the
+ scene, QGraphicsView might end up spending more time finding the minimal
+ approach than it will spend drawing.
+
+ \value SmartViewportUpdate QGraphicsView will attempt to find an optimal
+ update mode by analyzing the areas that require a redraw.
+
+ \value BoundingRectViewportUpdate The bounding rectangle of all changes in
+ the viewport will be redrawn. This mode has the advantage that
+ QGraphicsView searches only one region for changes, minimizing time spent
+ determining what needs redrawing. The disadvantage is that areas that have
+ not changed also need to be redrawn.
+
+ \value NoViewportUpdate QGraphicsView will never update its viewport when
+ the scene changes; the user is expected to control all updates. This mode
+ disables all (potentially slow) item visibility testing in QGraphicsView,
+ and is suitable for scenes that either require a fixed frame rate, or where
+ the viewport is otherwise updated externally.
+
+ \sa viewportUpdateMode
+*/
+
+/*!
+ \enum QGraphicsView::OptimizationFlag
+
+ \since 4.3
+
+ This enum describes flags that you can enable to improve rendering
+ performance in QGraphicsView. By default, none of these flags are set.
+ Note that setting a flag usually imposes a side effect, and this effect
+ can vary between paint devices and platforms.
+
+ \value DontClipPainter QGraphicsView sometimes clips the painter when
+ rendering the scene contents. This can generally improve performance
+ (e.g., rendering only small parts of a large pixmap), and protects against
+ rendering mistakes (e.g., drawing outside bounding rectangles, or outside
+ the exposed area). In some situations, however, the painter clip can slow
+ down rendering; especially when all painting is restricted to inside
+ exposed areas. By enabling this flag, QGraphicsView will completely
+ disable its implicit clipping. Note that rendering artifacts from using a
+ semi-transparent foreground or background brush can occur if clipping is
+ disabled.
+
+ \value DontSavePainterState When rendering, QGraphicsView protects the
+ painter state (see QPainter::save()) when rendering the background or
+ foreground, and when rendering each item. This allows you to leave the
+ painter in an altered state (i.e., you can call QPainter::setPen() or
+ QPainter::setBrush() without restoring the state after painting). However,
+ if the items consistently do restore the state, you should enable this
+ flag to prevent QGraphicsView from doing the same.
+
+ \value DontAdjustForAntialiasing Disables QGraphicsView's antialiasing
+ auto-adjustment of exposed areas. Items that render antialiased lines on
+ the boundaries of their QGraphicsItem::boundingRect() can end up rendering
+ parts of the line outside. To prevent rendering artifacts, QGraphicsView
+ expands all exposed regions by 2 pixels in all directions. If you enable
+ this flag, QGraphicsView will no longer perform these adjustments,
+ minimizing the areas that require redrawing, which improves performance. A
+ common side effect is that items that do draw with antialiasing can leave
+ painting traces behind on the scene as they are moved.
+*/
+
+/*!
+ \enum QGraphicsView::CacheModeFlag
+
+ This enum describes the flags that you can set for a QGraphicsView's cache
+ mode.
+
+ \value CacheNone All painting is done directly onto the viewport.
+
+ \value CacheBackground The background is cached. This affects both custom
+ backgrounds, and backgrounds based on the backgroundBrush property. When
+ this flag is enabled, QGraphicsView will allocate one pixmap with the full
+ size of the viewport.
+
+ \sa cacheMode
+*/
+
+/*!
+ \enum QGraphicsView::DragMode
+
+ This enum describes the default action for the view when pressing and
+ dragging the mouse over the viewport.
+
+ \value NoDrag Nothing happens; the mouse event is ignored.
+
+ \value ScrollHandDrag The cursor changes into a pointing hand, and
+ dragging the mouse around will scroll the scrolbars. This mode works both
+ in \l{QGraphicsView::interactive}{interactive} and non-interactive mode.
+
+ \value RubberBandDrag A rubber band will appear. Dragging the mouse will
+ set the rubber band geometry, and all items covered by the rubber band are
+ selected. This mode is disabled for non-interactive views.
+
+ \sa dragMode, QGraphicsScene::setSelectionArea()
+*/
+
+#include "qgraphicsview.h"
+#include "qgraphicsview_p.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include "qgraphicsitem.h"
+#include "qgraphicsitem_p.h"
+#include "qgraphicsscene.h"
+#include "qgraphicsscene_p.h"
+#include "qgraphicssceneevent.h"
+#include "qgraphicswidget.h"
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qmath.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qdesktopwidget.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qlayout.h>
+#include <QtGui/qtransform.h>
+#include <QtGui/qmatrix.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qscrollbar.h>
+#include <QtGui/qstyleoption.h>
+#ifdef Q_WS_X11
+#include <private/qt_x11_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+inline int q_round_bound(qreal d) //### (int)(qreal) INT_MAX != INT_MAX for single precision
+{
+ if (d <= (qreal) INT_MIN)
+ return INT_MIN;
+ else if (d >= (qreal) INT_MAX)
+ return INT_MAX;
+ return d >= 0.0 ? int(d + 0.5) : int(d - int(d-1) + 0.5) + int(d-1);
+}
+
+/*!
+ \internal
+*/
+QGraphicsViewPrivate::QGraphicsViewPrivate()
+ : renderHints(QPainter::TextAntialiasing),
+ dragMode(QGraphicsView::NoDrag),
+ sceneInteractionAllowed(true), hasSceneRect(false),
+ connectedToScene(false),
+ mousePressButton(Qt::NoButton),
+ identityMatrix(true),
+ dirtyScroll(true),
+ accelerateScrolling(true),
+ leftIndent(0), topIndent(0),
+ lastMouseEvent(QEvent::None, QPoint(), Qt::NoButton, 0, 0),
+ useLastMouseEvent(false),
+ keepLastCenterPoint(true),
+ alignment(Qt::AlignCenter),
+ transforming(false),
+ transformationAnchor(QGraphicsView::AnchorViewCenter), resizeAnchor(QGraphicsView::NoAnchor),
+ viewportUpdateMode(QGraphicsView::MinimalViewportUpdate),
+ optimizationFlags(0),
+ scene(0),
+#ifndef QT_NO_RUBBERBAND
+ rubberBanding(false),
+ rubberBandSelectionMode(Qt::IntersectsItemShape),
+#endif
+ handScrolling(false), handScrollMotions(0), cacheMode(0),
+ mustAllocateStyleOptions(false),
+ mustResizeBackgroundPixmap(true),
+#ifndef QT_NO_CURSOR
+ hasStoredOriginalCursor(false),
+#endif
+ lastDragDropEvent(0),
+ fullUpdatePending(true),
+ dirtyRectCount(0),
+ updatingLater(false),
+ updateSceneSlotReimplementedChecked(false)
+{
+ styleOptions.reserve(QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsViewPrivate::recalculateContentSize()
+{
+ Q_Q(QGraphicsView);
+
+ QSize maxSize = q->maximumViewportSize();
+ int width = maxSize.width();
+ int height = maxSize.height();
+ QRectF viewRect = matrix.mapRect(q->sceneRect());
+
+ bool frameOnlyAround = (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, q));
+ if (frameOnlyAround) {
+ if (hbarpolicy == Qt::ScrollBarAlwaysOn)
+ height -= frameWidth * 2;
+ if (vbarpolicy == Qt::ScrollBarAlwaysOn)
+ width -= frameWidth * 2;
+ }
+
+ // Adjust the maximum width and height of the viewport based on the width
+ // of visible scroll bars.
+ int scrollBarExtent = q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, q);
+ if (frameOnlyAround)
+ scrollBarExtent += frameWidth * 2;
+
+ bool useHorizontalScrollBar = (viewRect.width() > width) && hbarpolicy != Qt::ScrollBarAlwaysOff;
+ bool useVerticalScrollBar = (viewRect.height() > height) && vbarpolicy != Qt::ScrollBarAlwaysOff;
+ if (useHorizontalScrollBar && !useVerticalScrollBar) {
+ if (viewRect.height() > height - scrollBarExtent)
+ useVerticalScrollBar = true;
+ }
+ if (useVerticalScrollBar && !useHorizontalScrollBar) {
+ if (viewRect.width() > width - scrollBarExtent)
+ useHorizontalScrollBar = true;
+ }
+ if (useHorizontalScrollBar && hbarpolicy != Qt::ScrollBarAlwaysOn)
+ height -= scrollBarExtent;
+ if (useVerticalScrollBar && vbarpolicy != Qt::ScrollBarAlwaysOn)
+ width -= scrollBarExtent;
+
+ // Setting the ranges of these scroll bars can/will cause the values to
+ // change, and scrollContentsBy() will be called correspondingly. This
+ // will reset the last center point.
+ QPointF savedLastCenterPoint = lastCenterPoint;
+
+ // Remember the former indent settings
+ qreal oldLeftIndent = leftIndent;
+ qreal oldTopIndent = topIndent;
+
+ // If the whole scene fits horizontally, we center the scene horizontally,
+ // and ignore the horizontal scroll bars.
+ int left = q_round_bound(viewRect.left());
+ int right = q_round_bound(viewRect.right() - width);
+ if (left >= right) {
+ q->horizontalScrollBar()->setRange(0, 0);
+
+ switch (alignment & Qt::AlignHorizontal_Mask) {
+ case Qt::AlignLeft:
+ leftIndent = -viewRect.left();
+ break;
+ case Qt::AlignRight:
+ leftIndent = width - viewRect.width() - viewRect.left() - 1;
+ break;
+ case Qt::AlignHCenter:
+ default:
+ leftIndent = width / 2 - (viewRect.left() + viewRect.right()) / 2;
+ break;
+ }
+ } else {
+ q->horizontalScrollBar()->setRange(left, right);
+ q->horizontalScrollBar()->setPageStep(width);
+ q->horizontalScrollBar()->setSingleStep(width / 20);
+ leftIndent = 0;
+ }
+
+ // If the whole scene fits vertically, we center the scene vertically, and
+ // ignore the vertical scroll bars.
+ int top = q_round_bound(viewRect.top());
+ int bottom = q_round_bound(viewRect.bottom() - height);
+ if (top >= bottom) {
+ q->verticalScrollBar()->setRange(0, 0);
+
+ switch (alignment & Qt::AlignVertical_Mask) {
+ case Qt::AlignTop:
+ topIndent = -viewRect.top();
+ break;
+ case Qt::AlignBottom:
+ topIndent = height - viewRect.height() - viewRect.top() - 1;
+ break;
+ case Qt::AlignVCenter:
+ default:
+ topIndent = height / 2 - (viewRect.top() + viewRect.bottom()) / 2;
+ break;
+ }
+ } else {
+ q->verticalScrollBar()->setRange(top, bottom);
+ q->verticalScrollBar()->setPageStep(height);
+ q->verticalScrollBar()->setSingleStep(height / 20);
+ topIndent = 0;
+ }
+
+ // Restorethe center point from before the ranges changed.
+ lastCenterPoint = savedLastCenterPoint;
+
+ // Issue a full update if the indents change.
+ // ### If the transform is still the same, we can get away with just a
+ // scroll instead.
+ if (oldLeftIndent != leftIndent || oldTopIndent != topIndent) {
+ dirtyScroll = true;
+ q->viewport()->update();
+ } else if (q->isRightToLeft() && !leftIndent) {
+ // In reverse mode, the horizontal scroll always changes after the content
+ // size has changed, as the scroll is calculated by summing the min and
+ // max values of the range and subtracting the current value. In normal
+ // mode the scroll remains unchanged unless the indent has changed.
+ dirtyScroll = true;
+ }
+
+ if (cacheMode & QGraphicsView::CacheBackground) {
+ // Invalidate the background pixmap
+ mustResizeBackgroundPixmap = true;
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsViewPrivate::centerView(QGraphicsView::ViewportAnchor anchor)
+{
+ Q_Q(QGraphicsView);
+ switch (anchor) {
+ case QGraphicsView::AnchorUnderMouse: {
+ if (q->underMouse()) {
+ // Last scene pos: lastMouseMoveScenePoint
+ // Current mouse pos:
+ QPointF transformationDiff = q->mapToScene(q->viewport()->rect().center())
+ - q->mapToScene(q->mapFromGlobal(QCursor::pos()));
+ q->centerOn(lastMouseMoveScenePoint + transformationDiff);;
+ } else {
+ q->centerOn(lastCenterPoint);
+ }
+ break;
+ }
+ case QGraphicsView::AnchorViewCenter:
+ q->centerOn(lastCenterPoint);
+ break;
+ case QGraphicsView::NoAnchor:
+ break;
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsViewPrivate::updateLastCenterPoint()
+{
+ Q_Q(QGraphicsView);
+ lastCenterPoint = q->mapToScene(q->viewport()->rect().center());
+}
+
+/*!
+ \internal
+
+ Returns the horizontal scroll value (the X value of the left edge of the
+ viewport).
+*/
+qint64 QGraphicsViewPrivate::horizontalScroll() const
+{
+ if (dirtyScroll)
+ const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
+ return scrollX;
+}
+
+/*!
+ \internal
+
+ Returns the vertical scroll value (the X value of the top edge of the
+ viewport).
+*/
+qint64 QGraphicsViewPrivate::verticalScroll() const
+{
+ if (dirtyScroll)
+ const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
+ return scrollY;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsViewPrivate::updateScroll()
+{
+ Q_Q(QGraphicsView);
+ scrollX = qint64(-leftIndent);
+ if (q->isRightToLeft()) {
+ if (!leftIndent) {
+ scrollX += q->horizontalScrollBar()->minimum();
+ scrollX += q->horizontalScrollBar()->maximum();
+ scrollX -= q->horizontalScrollBar()->value();
+ }
+ } else {
+ scrollX += q->horizontalScrollBar()->value();
+ }
+
+ scrollY = qint64(q->verticalScrollBar()->value() - topIndent);
+
+ dirtyScroll = false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsViewPrivate::replayLastMouseEvent()
+{
+ if (!useLastMouseEvent || !scene)
+ return;
+ mouseMoveEventHandler(&lastMouseEvent);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsViewPrivate::storeMouseEvent(QMouseEvent *event)
+{
+ useLastMouseEvent = true;
+ lastMouseEvent = QMouseEvent(QEvent::MouseMove, event->pos(), event->globalPos(),
+ event->button(), event->buttons(), event->modifiers());
+}
+
+void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event)
+{
+ Q_Q(QGraphicsView);
+
+ storeMouseEvent(event);
+ lastMouseEvent.setAccepted(false);
+
+ if (!sceneInteractionAllowed)
+ return;
+ if (handScrolling)
+ return;
+ if (!scene)
+ return;
+
+ QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
+ mouseEvent.setWidget(q->viewport());
+ mouseEvent.setButtonDownScenePos(mousePressButton, mousePressScenePoint);
+ mouseEvent.setButtonDownScreenPos(mousePressButton, mousePressScreenPoint);
+ mouseEvent.setScenePos(q->mapToScene(event->pos()));
+ mouseEvent.setScreenPos(event->globalPos());
+ mouseEvent.setLastScenePos(lastMouseMoveScenePoint);
+ mouseEvent.setLastScreenPos(lastMouseMoveScreenPoint);
+ mouseEvent.setButtons(event->buttons());
+ mouseEvent.setButton(event->button());
+ mouseEvent.setModifiers(event->modifiers());
+ lastMouseMoveScenePoint = mouseEvent.scenePos();
+ lastMouseMoveScreenPoint = mouseEvent.screenPos();
+ mouseEvent.setAccepted(false);
+ QApplication::sendEvent(scene, &mouseEvent);
+
+ // Remember whether the last event was accepted or not.
+ lastMouseEvent.setAccepted(mouseEvent.isAccepted());
+
+ if (mouseEvent.isAccepted() && mouseEvent.buttons() != 0) {
+ // The event was delivered to a mouse grabber; the press is likely to
+ // have set a cursor, and we must not change it.
+ return;
+ }
+
+#ifndef QT_NO_CURSOR
+ // Find the topmost item under the mouse with a cursor.
+ foreach (QGraphicsItem *item, scene->d_func()->cachedItemsUnderMouse) {
+ if (item->hasCursor()) {
+ _q_setViewportCursor(item->cursor());
+ return;
+ }
+ }
+
+ // No items with cursors found; revert to the view cursor.
+ if (hasStoredOriginalCursor) {
+ // Restore the original viewport cursor.
+ hasStoredOriginalCursor = false;
+ q->viewport()->setCursor(originalCursor);
+ }
+#endif
+}
+
+/*!
+ \internal
+*/
+#ifndef QT_NO_RUBBERBAND
+QRegion QGraphicsViewPrivate::rubberBandRegion(const QWidget *widget, const QRect &rect) const
+{
+ QStyleHintReturnMask mask;
+ QStyleOptionRubberBand option;
+ option.initFrom(widget);
+ option.rect = rect;
+ option.opaque = false;
+ option.shape = QRubberBand::Rectangle;
+
+ QRegion tmp;
+ tmp += rect;
+ if (widget->style()->styleHint(QStyle::SH_RubberBand_Mask, &option, widget, &mask))
+ tmp &= mask.region;
+ return tmp;
+}
+#endif
+
+/*!
+ \internal
+*/
+#ifndef QT_NO_CURSOR
+void QGraphicsViewPrivate::_q_setViewportCursor(const QCursor &cursor)
+{
+ Q_Q(QGraphicsView);
+ QWidget *viewport = q->viewport();
+ if (!hasStoredOriginalCursor) {
+ hasStoredOriginalCursor = true;
+ originalCursor = viewport->cursor();
+ }
+ viewport->setCursor(cursor);
+}
+#endif
+
+/*!
+ \internal
+*/
+#ifndef QT_NO_CURSOR
+void QGraphicsViewPrivate::_q_unsetViewportCursor()
+{
+ Q_Q(QGraphicsView);
+ foreach (QGraphicsItem *item, q->items(lastMouseEvent.pos())) {
+ if (item->hasCursor()) {
+ _q_setViewportCursor(item->cursor());
+ return;
+ }
+ }
+
+ // Restore the original viewport cursor.
+ hasStoredOriginalCursor = false;
+ if (dragMode == QGraphicsView::ScrollHandDrag)
+ q->viewport()->setCursor(Qt::OpenHandCursor);
+ else
+ q->viewport()->setCursor(originalCursor);
+}
+#endif
+
+/*!
+ \internal
+*/
+void QGraphicsViewPrivate::storeDragDropEvent(const QGraphicsSceneDragDropEvent *event)
+{
+ delete lastDragDropEvent;
+ lastDragDropEvent = new QGraphicsSceneDragDropEvent(event->type());
+ lastDragDropEvent->setScenePos(event->scenePos());
+ lastDragDropEvent->setScreenPos(event->screenPos());
+ lastDragDropEvent->setButtons(event->buttons());
+ lastDragDropEvent->setModifiers(event->modifiers());
+ lastDragDropEvent->setPossibleActions(event->possibleActions());
+ lastDragDropEvent->setProposedAction(event->proposedAction());
+ lastDragDropEvent->setDropAction(event->dropAction());
+ lastDragDropEvent->setMimeData(event->mimeData());
+ lastDragDropEvent->setWidget(event->widget());
+ lastDragDropEvent->setSource(event->source());
+}
+
+/*!
+ \internal
+*/
+void QGraphicsViewPrivate::populateSceneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
+ QDropEvent *source)
+{
+#ifndef QT_NO_DRAGANDDROP
+ Q_Q(QGraphicsView);
+ dest->setScenePos(q->mapToScene(source->pos()));
+ dest->setScreenPos(q->mapToGlobal(source->pos()));
+ dest->setButtons(source->mouseButtons());
+ dest->setModifiers(source->keyboardModifiers());
+ dest->setPossibleActions(source->possibleActions());
+ dest->setProposedAction(source->proposedAction());
+ dest->setDropAction(source->dropAction());
+ dest->setMimeData(source->mimeData());
+ dest->setWidget(q->viewport());
+ dest->setSource(source->source());
+#else
+ Q_UNUSED(dest)
+ Q_UNUSED(source)
+#endif
+}
+
+/*!
+ \internal
+*/
+QRect QGraphicsViewPrivate::mapToViewRect(const QGraphicsItem *item, const QRectF &rect) const
+{
+ Q_Q(const QGraphicsView);
+ if (dirtyScroll)
+ const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
+
+ if (item->d_ptr->itemIsUntransformable()) {
+ QTransform itv = item->deviceTransform(q->viewportTransform());
+ return itv.mapRect(rect).toAlignedRect();
+ }
+
+ // Translate-only
+ QPointF offset;
+ const QGraphicsItem *parentItem = item;
+ const QGraphicsItemPrivate *itemd;
+ do {
+ itemd = parentItem->d_ptr;
+ if (itemd->hasTransform)
+ break;
+ offset += itemd->pos;
+ } while ((parentItem = itemd->parent));
+
+ QRectF baseRect = rect.translated(offset.x(), offset.y());
+ if (!parentItem) {
+ if (identityMatrix) {
+ baseRect.translate(-scrollX, -scrollY);
+ return baseRect.toAlignedRect();
+ }
+ return matrix.mapRect(baseRect).translated(-scrollX, -scrollY).toAlignedRect();
+ }
+
+ QTransform tr = parentItem->sceneTransform();
+ if (!identityMatrix)
+ tr *= matrix;
+ QRectF r = tr.mapRect(baseRect);
+ r.translate(-scrollX, -scrollY);
+ return r.toAlignedRect();
+}
+
+/*!
+ \internal
+*/
+QRegion QGraphicsViewPrivate::mapToViewRegion(const QGraphicsItem *item, const QRectF &rect) const
+{
+ Q_Q(const QGraphicsView);
+ if (dirtyScroll)
+ const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
+
+ // Accurate bounding region
+ QTransform itv = item->sceneTransform() * q->viewportTransform();
+ return item->boundingRegion(itv) & itv.mapRect(rect).toAlignedRect();
+}
+
+/*!
+ \internal
+*/
+void QGraphicsViewPrivate::itemUpdated(QGraphicsItem *item, const QRectF &rect)
+{
+ if (fullUpdatePending || viewportUpdateMode == QGraphicsView::NoViewportUpdate)
+ return;
+ if (item->d_ptr->dirty)
+ updateLater();
+
+ QRectF updateRect = rect;
+ if (item->isClipped()) {
+ // Minimize unnecessary redraw.
+ QGraphicsItem *p = item;
+ while ((p = p->d_ptr->parent)) {
+ if (p->flags() & QGraphicsItem::ItemClipsChildrenToShape) {
+ updateRect &= p->itemTransform(item).mapRect(p->boundingRect());
+ if (updateRect.isNull())
+ return;
+ }
+
+ if (!(p->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren))
+ break;
+ }
+
+ if (updateRect.isNull())
+ return;
+ }
+
+ // Map the rect to view coordinates.
+ QRect vr = viewport->rect();
+
+ if (!item->d_ptr->hasBoundingRegionGranularity) {
+ QRect r = mapToViewRect(item, updateRect) & vr;
+ if (r.isNull())
+ return;
+ this->updateRect(r);
+ } else {
+ QRegion r = mapToViewRegion(item, updateRect) & vr;
+ if (r.isEmpty())
+ return;
+ updateRegion(r);
+ }
+}
+
+void QGraphicsViewPrivate::updateLater()
+{
+ Q_Q(QGraphicsView);
+ if (updatingLater)
+ return;
+ updatingLater = true;
+ QMetaObject::invokeMethod(q, "_q_updateLaterSlot", Qt::QueuedConnection);
+}
+
+void QGraphicsViewPrivate::_q_updateLaterSlot()
+{
+ Q_Q(QGraphicsView);
+ if (!scene)
+ return;
+
+ QRect vr = viewport->rect();
+ QTransform viewTransform = q->viewportTransform();
+ const QList<QGraphicsItem *> &dirtyItems = scene->d_func()->dirtyItems;
+ for (int i = 0; i < dirtyItems.size(); ++i) {
+ const QGraphicsItem *item = dirtyItems.at(i);
+ QTransform x = item->sceneTransform() * viewTransform;
+ QRect viewRect = x.mapRect(item->boundingRect()).toAlignedRect() & vr;
+ if (!viewRect.isNull())
+ updateRect(viewRect);
+ }
+
+ dirtyRectCount += dirtyRects.size();
+
+ bool noUpdate = !fullUpdatePending && viewportUpdateMode == QGraphicsView::FullViewportUpdate;
+ if ((dirtyRectCount > 0 || !dirtyBoundingRect.isNull()) && !fullUpdatePending && !noUpdate) {
+ if (viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate
+ || (viewportUpdateMode == QGraphicsView::SmartViewportUpdate
+ && dirtyRectCount >= QGRAPHICSVIEW_REGION_RECT_THRESHOLD)) {
+ if (!(optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)) {
+ viewport->update(dirtyBoundingRect.adjusted(-2, -2, 2, 2));
+ } else {
+ viewport->update(dirtyBoundingRect);
+ }
+ } else {
+ // ### Improve this block, which is very slow for complex regions. We
+ // need to strike the balance between having an accurate update
+ // region, and running fast. The below approach is the simplest way to
+ // create a region from a bunch of rects, but we might want to use
+ // other approaches; e.g., a grid of a fixed size representing
+ // quadrants of the viewport, which we mark as dirty depending on the
+ // rectangles in the list. Perhaps this should go into a
+ // QRegion::fromRects(rects, how) function.
+ QRegion region;
+ if (!(optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)) {
+ for (int i = 0; i < dirtyRegions.size(); ++i) {
+ QVector<QRect> rects = dirtyRegions.at(i).rects();
+ for (int j = 0; j < rects.size(); ++j)
+ region += rects.at(j).adjusted(-2, -2, 2, 2);
+ }
+ for (int i = 0; i < dirtyRects.size(); ++i)
+ region += dirtyRects.at(i).adjusted(-2, -2, 2, 2);
+ } else {
+ for (int i = 0; i < dirtyRegions.size(); ++i)
+ region += dirtyRegions.at(i);
+ for (int i = 0; i < dirtyRects.size(); ++i)
+ region += dirtyRects.at(i);
+ }
+
+ viewport->update(region);
+ }
+ }
+
+ dirtyRegions.clear();
+ dirtyRects.clear();
+ dirtyRectCount = 0;
+ dirtyBoundingRect = QRect();
+ updatingLater = false;
+}
+
+void QGraphicsViewPrivate::updateAll()
+{
+ Q_Q(QGraphicsView);
+ q->viewport()->update();
+ fullUpdatePending = true;
+ dirtyRectCount = 0;
+ dirtyBoundingRect = QRect();
+ updatingLater = false;
+}
+
+void QGraphicsViewPrivate::updateRegion(const QRegion &r)
+{
+ Q_Q(QGraphicsView);
+
+ // Rect intersects viewport - update everything?
+ switch (viewportUpdateMode) {
+ case QGraphicsView::FullViewportUpdate:
+ fullUpdatePending = true;
+ q->viewport()->update();
+ break;
+ case QGraphicsView::BoundingRectViewportUpdate:
+ dirtyBoundingRect |= r.boundingRect();
+ if (dirtyBoundingRect == q->viewport()->rect()) {
+ fullUpdatePending = true;
+ q->viewport()->update();
+ } else {
+ updateLater();
+ }
+ break;
+ case QGraphicsView::SmartViewportUpdate:
+ dirtyBoundingRect |= r.boundingRect();
+ if ((dirtyRectCount + r.numRects()) < QGRAPHICSVIEW_REGION_RECT_THRESHOLD)
+ dirtyRegions << r;
+ dirtyRectCount += r.numRects();
+ updateLater();
+ break;
+ case QGraphicsView::MinimalViewportUpdate:
+ dirtyRegions << r;
+ dirtyRectCount += r.numRects();
+ updateLater();
+ break;
+ case QGraphicsView::NoViewportUpdate:
+ // Unreachable
+ break;
+ }
+
+ // Compress the regions...
+ if (dirtyRectCount > QGRAPHICSVIEW_REGION_RECT_THRESHOLD && dirtyRegions.size() > 1) {
+ QRegion masterRegion;
+ for (int i=0; i<dirtyRegions.size(); ++i) {
+ masterRegion |= dirtyRegions.at(i);
+ }
+ dirtyRectCount = masterRegion.numRects();
+ dirtyRegions.clear();
+ dirtyRegions << masterRegion;
+ }
+}
+
+void QGraphicsViewPrivate::updateRect(const QRect &r)
+{
+ Q_Q(QGraphicsView);
+
+ // Rect intersects viewport - update everything?
+ switch (viewportUpdateMode) {
+ case QGraphicsView::FullViewportUpdate:
+ fullUpdatePending = true;
+ q->viewport()->update();
+ break;
+ case QGraphicsView::BoundingRectViewportUpdate:
+ dirtyBoundingRect |= r;
+ if (dirtyBoundingRect == q->viewport()->rect()) {
+ fullUpdatePending = true;
+ q->viewport()->update();
+ } else {
+ updateLater();
+ }
+ break;
+ case QGraphicsView::SmartViewportUpdate:
+ dirtyBoundingRect |= r;
+ if ((dirtyRectCount + dirtyRects.size()) < QGRAPHICSVIEW_REGION_RECT_THRESHOLD)
+ dirtyRects << r;
+ updateLater();
+ break;
+ case QGraphicsView::MinimalViewportUpdate:
+ dirtyRects << r;
+ updateLater();
+ break;
+ case QGraphicsView::NoViewportUpdate:
+ // Unreachable
+ break;
+ }
+}
+
+QStyleOptionGraphicsItem *QGraphicsViewPrivate::allocStyleOptionsArray(int numItems)
+{
+ if (mustAllocateStyleOptions || (numItems > styleOptions.capacity()))
+ // too many items, let's allocate on-the-fly
+ return new QStyleOptionGraphicsItem[numItems];
+
+ // expand only whenever necessary
+ if (numItems > styleOptions.size())
+ styleOptions.resize(numItems);
+
+ mustAllocateStyleOptions = true;
+ return styleOptions.data();
+}
+
+void QGraphicsViewPrivate::freeStyleOptionsArray(QStyleOptionGraphicsItem *array)
+{
+ mustAllocateStyleOptions = false;
+ if (array != styleOptions.data())
+ delete [] array;
+}
+
+
+QList<QGraphicsItem *> QGraphicsViewPrivate::findItems(const QRegion &exposedRegion,
+ const QTransform &worldTransform,
+ bool *allItems) const
+{
+ Q_Q(const QGraphicsView);
+ QList<QGraphicsItem *> itemList;
+ QSet<QGraphicsItem *> tmp;
+ bool simpleTransform = worldTransform.type() <= QTransform::TxScale;
+
+ extern QPainterPath qt_regionToPath(const QRegion &region);
+ QPainterPath path = qt_regionToPath(exposedRegion);
+ *allItems = path.contains(q->mapFromScene(scene->d_func()->growingItemsBoundingRect).boundingRect());
+ QList<QRectF> exposedRects;
+ QList<QPolygonF> exposedPolys;
+
+ // Transform the exposed viewport rects to scene rects or polygons
+ foreach (const QRect &rect, exposedRegion.rects()) {
+ QPolygonF exposedPoly = q->mapToScene(rect.adjusted(-1, -1, 1, 1));
+ QRectF exposedRect = exposedPoly.boundingRect();
+ if (!simpleTransform)
+ exposedPolys << exposedPoly;
+ exposedRects << exposedRect;
+ }
+
+ // Find which items need to be drawn.
+ if (*allItems) {
+ // All items are guaranteed within the exposed region, don't bother using the index.
+ foreach (QGraphicsItem *item, scene->items()) {
+ // But we only want to include items that are visible
+ if (item->isVisible())
+ itemList << item;
+ }
+ } else if (simpleTransform) {
+ // Simple rect lookups will do.
+ if (exposedRects.size() > 1) {
+ foreach (const QRectF &rect, exposedRects) {
+ foreach (QGraphicsItem *item, scene->d_func()->items_helper(rect, Qt::IntersectsItemBoundingRect, Qt::SortOrder(-1) /* don't sort */)) {
+ if (!tmp.contains(item)) {
+ tmp << item;
+ itemList << item;
+ }
+ }
+ }
+ } else {
+ itemList += scene->d_func()->items_helper(exposedRects[0], Qt::IntersectsItemBoundingRect, Qt::SortOrder(-1) /* don't sort */);
+ }
+ } else {
+ // Polygon lookup is necessary.
+ if (exposedRects.size() > 1) {
+ foreach (const QPolygonF &poly, exposedPolys) {
+ foreach (QGraphicsItem *item, scene->d_func()->items_helper(poly, Qt::IntersectsItemBoundingRect, Qt::SortOrder(-1) /* don't sort */)) {
+ if (!tmp.contains(item)) {
+ tmp << item;
+ itemList << item;
+ }
+ }
+ }
+ } else {
+ itemList += scene->d_func()->items_helper(exposedPolys[0], Qt::IntersectsItemBoundingRect, Qt::SortOrder(-1) /* don't sort */);
+ }
+ }
+
+ // Check for items that ignore inherited transformations, and add them if
+ // necessary.
+ QRectF untr = scene->d_func()->largestUntransformableItem;
+ if (!*allItems && !untr.isNull()) {
+ // Map the largest untransformable item subtree boundingrect from view
+ // to scene coordinates, and use this to expand all exposed rects in
+ // search for untransformable items.
+ QRectF ltri = matrix.inverted().mapRect(untr);
+ ltri.adjust(-untr.width(), -untr.height(), untr.width(), untr.height());
+
+ foreach (const QRect &rect, exposedRegion.rects()) {
+ QRectF exposed = q->mapToScene(rect.adjusted(-1, -1, 1, 1)).boundingRect();
+ exposed.adjust(-ltri.width(), -ltri.height(), ltri.width(), ltri.height());
+
+ foreach (QGraphicsItem *item, scene->d_func()->estimateItemsInRect(exposed)) {
+ if (item->d_ptr->itemIsUntransformable()) {
+ if (!tmp.contains(item)) {
+ QPainterPath rectPath;
+ rectPath.addRect(rect);
+ QPainterPath path = item->deviceTransform(q->viewportTransform()).inverted().map(rectPath);
+ if (item->collidesWithPath(path, Qt::IntersectsItemBoundingRect)) {
+ itemList << item;
+ tmp << item;
+ }
+ }
+ }
+ }
+ }
+ }
+ tmp.clear();
+
+ // Sort the items.
+ QGraphicsScenePrivate::sortItems(&itemList, Qt::DescendingOrder,
+ scene->d_func()->sortCacheEnabled);
+
+ return itemList;
+}
+
+void QGraphicsViewPrivate::generateStyleOptions(const QList<QGraphicsItem *> &itemList,
+ QGraphicsItem **itemArray,
+ QStyleOptionGraphicsItem *styleOptionArray,
+ const QTransform &worldTransform,
+ bool allItems,
+ const QRegion &exposedRegion) const
+{
+ // Two unit vectors.
+ QLineF v1(0, 0, 1, 0);
+ QLineF v2(0, 0, 0, 1);
+ QTransform itemToViewportTransform;
+ QRectF brect;
+ QTransform reverseMap;
+
+ for (int i = 0; i < itemList.size(); ++i) {
+ QGraphicsItem *item = itemArray[i] = itemList[i];
+
+ QStyleOptionGraphicsItem &option = styleOptionArray[i];
+ brect = item->boundingRect();
+ option.state = QStyle::State_None;
+ option.rect = brect.toRect();
+ option.exposedRect = QRectF();
+ if (item->d_ptr->selected)
+ option.state |= QStyle::State_Selected;
+ if (item->d_ptr->enabled)
+ option.state |= QStyle::State_Enabled;
+ if (item->hasFocus())
+ option.state |= QStyle::State_HasFocus;
+ if (scene->d_func()->hoverItems.contains(item))
+ option.state |= QStyle::State_MouseOver;
+ if (item == scene->mouseGrabberItem())
+ option.state |= QStyle::State_Sunken;
+
+ // Calculate a simple level-of-detail metric.
+ // ### almost identical code in QGraphicsScene::render()
+ // and QGraphicsView::render() - consider refactoring
+ if (item->d_ptr->itemIsUntransformable()) {
+ itemToViewportTransform = item->deviceTransform(worldTransform);
+ } else {
+ itemToViewportTransform = item->sceneTransform() * worldTransform;
+ }
+
+ if (itemToViewportTransform.type() <= QTransform::TxTranslate) {
+ // Translation and rotation only? The LOD is 1.
+ option.levelOfDetail = 1;
+ } else {
+ // LOD is the transformed area of a 1x1 rectangle.
+ option.levelOfDetail = qSqrt(itemToViewportTransform.map(v1).length() * itemToViewportTransform.map(v2).length());
+ }
+ option.matrix = itemToViewportTransform.toAffine(); //### discards perspective
+
+ if (!allItems) {
+ // Determine the item's exposed area
+ reverseMap = itemToViewportTransform.inverted();
+ foreach (const QRect &rect, exposedRegion.rects()) {
+ option.exposedRect |= reverseMap.mapRect(QRectF(rect.adjusted(-1, -1, 1, 1)));
+ if (option.exposedRect.contains(brect))
+ break;
+ }
+ option.exposedRect &= brect;
+ } else {
+ // The whole item is exposed
+ option.exposedRect = brect;
+ }
+ }
+}
+
+/*!
+ Constructs a QGraphicsView. \a parent is passed to QWidget's constructor.
+*/
+QGraphicsView::QGraphicsView(QWidget *parent)
+ : QAbstractScrollArea(*new QGraphicsViewPrivate, parent)
+{
+ setViewport(0);
+ setAcceptDrops(true);
+ setBackgroundRole(QPalette::Base);
+
+ // ### Ideally this would be enabled/disabled depending on whether any
+ // widgets in the current scene enabled input methods. We could do that
+ // using a simple reference count. The same goes for acceptDrops and mouse
+ // tracking.
+ setAttribute(Qt::WA_InputMethodEnabled);
+}
+
+/*!
+ Constructs a QGraphicsView and sets the visualized scene to \a
+ scene. \a parent is passed to QWidget's constructor.
+*/
+QGraphicsView::QGraphicsView(QGraphicsScene *scene, QWidget *parent)
+ : QAbstractScrollArea(*new QGraphicsViewPrivate, parent)
+{
+ setScene(scene);
+ setViewport(0);
+ setAcceptDrops(true);
+ setBackgroundRole(QPalette::Base);
+ setAttribute(Qt::WA_InputMethodEnabled);
+}
+
+/*!
+ \internal
+ */
+QGraphicsView::QGraphicsView(QGraphicsViewPrivate &dd, QWidget *parent)
+ : QAbstractScrollArea(dd, parent)
+{
+ setViewport(0);
+ setAcceptDrops(true);
+ setBackgroundRole(QPalette::Base);
+ setAttribute(Qt::WA_InputMethodEnabled);
+}
+
+/*!
+ Destructs the QGraphicsView object.
+*/
+QGraphicsView::~QGraphicsView()
+{
+ Q_D(QGraphicsView);
+ if (d->scene)
+ d->scene->d_func()->views.removeAll(this);
+ delete d->lastDragDropEvent;
+}
+
+/*!
+ \reimp
+*/
+QSize QGraphicsView::sizeHint() const
+{
+ Q_D(const QGraphicsView);
+ if (d->scene) {
+ QSizeF baseSize = d->matrix.mapRect(sceneRect()).size();
+ baseSize += QSizeF(d->frameWidth * 2, d->frameWidth * 2);
+ return baseSize.boundedTo((3 * QApplication::desktop()->size()) / 4).toSize();
+ }
+ return QAbstractScrollArea::sizeHint();
+}
+
+/*!
+ \property QGraphicsView::renderHints
+ \brief the default render hints for the view
+
+ These hints are
+ used to initialize QPainter before each visible item is drawn. QPainter
+ uses render hints to toggle rendering features such as antialiasing and
+ smooth pixmap transformation.
+
+ QPainter::TextAntialiasing is enabled by default.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 1
+*/
+QPainter::RenderHints QGraphicsView::renderHints() const
+{
+ Q_D(const QGraphicsView);
+ return d->renderHints;
+}
+void QGraphicsView::setRenderHints(QPainter::RenderHints hints)
+{
+ Q_D(QGraphicsView);
+ if (hints == d->renderHints)
+ return;
+ d->renderHints = hints;
+ viewport()->update();
+}
+
+/*!
+ If \a enabled is true, the render hint \a hint is enabled; otherwise it
+ is disabled.
+
+ \sa renderHints
+*/
+void QGraphicsView::setRenderHint(QPainter::RenderHint hint, bool enabled)
+{
+ Q_D(QGraphicsView);
+ QPainter::RenderHints oldHints = d->renderHints;
+ if (enabled)
+ d->renderHints |= hint;
+ else
+ d->renderHints &= ~hint;
+ if (oldHints != d->renderHints)
+ viewport()->update();
+}
+
+/*!
+ \property QGraphicsView::alignment
+ \brief the alignment of the scene in the view when the whole
+ scene is visible.
+
+ If the whole scene is visible in the view, (i.e., there are no visible
+ scroll bars,) the view's alignment will decide where the scene will be
+ rendered in the view. For example, if the alignment is Qt::AlignCenter,
+ which is default, the scene will be centered in the view, and if the
+ alignment is (Qt::AlignLeft | Qt::AlignTop), the scene will be rendered in
+ the top-left corner of the view.
+*/
+Qt::Alignment QGraphicsView::alignment() const
+{
+ Q_D(const QGraphicsView);
+ return d->alignment;
+}
+void QGraphicsView::setAlignment(Qt::Alignment alignment)
+{
+ Q_D(QGraphicsView);
+ if (d->alignment != alignment) {
+ d->alignment = alignment;
+ d->recalculateContentSize();
+ }
+}
+
+/*!
+ \property QGraphicsView::transformationAnchor
+ \brief how the view should position the scene during transformations.
+
+ QGraphicsView uses this property to decide how to position the scene in
+ the viewport when the transformation matrix changes, and the coordinate
+ system of the view is transformed. The default behavior, AnchorViewCenter,
+ ensures that the scene point at the center of the view remains unchanged
+ during transformations (e.g., when rotating, the scene will appear to
+ rotate around the center of the view).
+
+ Note that the effect of this property is noticeable when only a part of the
+ scene is visible (i.e., when there are scroll bars). Otherwise, if the
+ whole scene fits in the view, QGraphicsScene uses the view \l alignment to
+ position the scene in the view.
+
+ \sa alignment, resizeAnchor
+*/
+QGraphicsView::ViewportAnchor QGraphicsView::transformationAnchor() const
+{
+ Q_D(const QGraphicsView);
+ return d->transformationAnchor;
+}
+void QGraphicsView::setTransformationAnchor(ViewportAnchor anchor)
+{
+ Q_D(QGraphicsView);
+ d->transformationAnchor = anchor;
+}
+
+/*!
+ \property QGraphicsView::resizeAnchor
+ \brief how the view should position the scene when the view is resized.
+
+ QGraphicsView uses this property to decide how to position the scene in
+ the viewport when the viewport widget's size changes. The default
+ behavior, NoAnchor, leaves the scene's position unchanged during a resize;
+ the top-left corner of the view will appear to be anchored while resizing.
+
+ Note that the effect of this property is noticeable when only a part of the
+ scene is visible (i.e., when there are scroll bars). Otherwise, if the
+ whole scene fits in the view, QGraphicsScene uses the view \l alignment to
+ position the scene in the view.
+
+ \sa alignment, transformationAnchor, Qt::WNorthWestGravity
+*/
+QGraphicsView::ViewportAnchor QGraphicsView::resizeAnchor() const
+{
+ Q_D(const QGraphicsView);
+ return d->resizeAnchor;
+}
+void QGraphicsView::setResizeAnchor(ViewportAnchor anchor)
+{
+ Q_D(QGraphicsView);
+ d->resizeAnchor = anchor;
+}
+
+/*!
+ \property QGraphicsView::viewportUpdateMode
+ \brief how the viewport should update its contents.
+
+ \since 4.3
+
+ QGraphicsView uses this property to decide how to update areas of the
+ scene that have been reexposed or changed. Usually you do not need to
+ modify this property, but there are some cases where doing so can improve
+ rendering performance. See the ViewportUpdateMode documentation for
+ specific details.
+
+ The default value is MinimalViewportUpdate, where QGraphicsView will
+ update as small an area of the viewport as possible when the contents
+ change.
+
+ \sa ViewportUpdateMode, cacheMode
+*/
+QGraphicsView::ViewportUpdateMode QGraphicsView::viewportUpdateMode() const
+{
+ Q_D(const QGraphicsView);
+ return d->viewportUpdateMode;
+}
+void QGraphicsView::setViewportUpdateMode(ViewportUpdateMode mode)
+{
+ Q_D(QGraphicsView);
+ d->viewportUpdateMode = mode;
+}
+
+/*!
+ \property QGraphicsView::optimizationFlags
+ \brief flags that can be used to tune QGraphicsView's performance.
+
+ \since 4.3
+
+ QGraphicsView uses clipping, extra bounding rect adjustments, and certain
+ other aids to improve rendering quality and performance for the common
+ case graphics scene. However, depending on the target platform, the scene,
+ and the viewport in use, some of these operations can degrade performance.
+
+ The effect varies from flag to flag; see the OptimizationFlags
+ documentation for details.
+
+ By default, no optimization flags are enabled.
+
+ \sa setOptimizationFlag()
+*/
+QGraphicsView::OptimizationFlags QGraphicsView::optimizationFlags() const
+{
+ Q_D(const QGraphicsView);
+ return d->optimizationFlags;
+}
+void QGraphicsView::setOptimizationFlags(OptimizationFlags flags)
+{
+ Q_D(QGraphicsView);
+ d->optimizationFlags = flags;
+}
+
+/*!
+ Enables \a flag if \a enabled is true; otherwise disables \a flag.
+
+ \sa optimizationFlags
+*/
+void QGraphicsView::setOptimizationFlag(OptimizationFlag flag, bool enabled)
+{
+ Q_D(QGraphicsView);
+ if (enabled)
+ d->optimizationFlags |= flag;
+ else
+ d->optimizationFlags &= ~flag;
+}
+
+/*!
+ \property QGraphicsView::dragMode
+ \brief the behavior for dragging the mouse over the scene while
+ the left mouse button is pressed.
+
+ This property defines what should happen when the user clicks on the scene
+ background and drags the mouse (e.g., scrolling the viewport contents
+ using a pointing hand cursor, or selecting multiple items with a rubber
+ band). The default value, NoDrag, does nothing.
+
+ This behavior only affects mouse clicks that are not handled by any item.
+ You can define a custom behavior by creating a subclass of QGraphicsView
+ and reimplementing mouseMoveEvent().
+*/
+QGraphicsView::DragMode QGraphicsView::dragMode() const
+{
+ Q_D(const QGraphicsView);
+ return d->dragMode;
+}
+void QGraphicsView::setDragMode(DragMode mode)
+{
+ Q_D(QGraphicsView);
+ if (d->dragMode == mode)
+ return;
+
+#ifndef QT_NO_CURSOR
+ if (d->dragMode == ScrollHandDrag)
+ viewport()->unsetCursor();
+#endif
+
+ // If dragMode is unset while dragging, e.g. via a keyEvent, we
+ // don't unset the handScrolling state. When enabling scrolling
+ // again the mouseMoveEvent will automatically start scrolling,
+ // without a mousePress
+ if (d->dragMode == ScrollHandDrag && mode == NoDrag && d->handScrolling)
+ d->handScrolling = false;
+
+ d->dragMode = mode;
+
+#ifndef QT_NO_CURSOR
+ if (d->dragMode == ScrollHandDrag) {
+ // Forget the stored viewport cursor when we enter scroll hand drag mode.
+ d->hasStoredOriginalCursor = false;
+ viewport()->setCursor(Qt::OpenHandCursor);
+ }
+#endif
+}
+
+#ifndef QT_NO_RUBBERBAND
+/*!
+ \property QGraphicsView::rubberBandSelectionMode
+ \brief the behavior for selecting items with a rubber band selection rectangle.
+ \since 4.3
+
+ This property defines how items are selected when using the RubberBandDrag
+ drag mode.
+
+ The default value is Qt::IntersectsItemShape; all items whose shape
+ intersects with or is contained by the rubber band are selected.
+
+ \sa dragMode, items()
+*/
+Qt::ItemSelectionMode QGraphicsView::rubberBandSelectionMode() const
+{
+ Q_D(const QGraphicsView);
+ return d->rubberBandSelectionMode;
+}
+void QGraphicsView::setRubberBandSelectionMode(Qt::ItemSelectionMode mode)
+{
+ Q_D(QGraphicsView);
+ d->rubberBandSelectionMode = mode;
+}
+#endif
+
+/*!
+ \property QGraphicsView::cacheMode
+ \brief which parts of the view are cached
+
+ QGraphicsView can cache pre-rendered content in a QPixmap, which is then
+ drawn onto the viewport. The purpose of such caching is to speed up the
+ total rendering time for areas that are slow to render. Texture, gradient
+ and alpha blended backgrounds, for example, can be notibly slow to render;
+ especially with a transformed view. The CacheBackground flag enables
+ caching of the view's background. For example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 2
+
+ The cache is invalidated every time the view is transformed. However, when
+ scrolling, only partial invalidation is required.
+
+ By default, nothing is cached.
+
+ \sa resetCachedContent(), QPixmapCache
+*/
+QGraphicsView::CacheMode QGraphicsView::cacheMode() const
+{
+ Q_D(const QGraphicsView);
+ return d->cacheMode;
+}
+void QGraphicsView::setCacheMode(CacheMode mode)
+{
+ Q_D(QGraphicsView);
+ if (mode == d->cacheMode)
+ return;
+ d->cacheMode = mode;
+ resetCachedContent();
+}
+
+/*!
+ Resets any cached content. Calling this function will clear
+ QGraphicsView's cache. If the current cache mode is \l CacheNone, this
+ function does nothing.
+
+ This function is called automatically for you when the backgroundBrush or
+ QGraphicsScene::backgroundBrush properties change; you only need to call
+ this function if you have reimplemented QGraphicsScene::drawBackground()
+ or QGraphicsView::drawBackground() to draw a custom background, and need
+ to trigger a full redraw.
+
+ \sa cacheMode()
+*/
+void QGraphicsView::resetCachedContent()
+{
+ Q_D(QGraphicsView);
+ if (d->cacheMode == CacheNone)
+ return;
+
+ if (d->cacheMode & CacheBackground) {
+ // Background caching is enabled.
+ d->mustResizeBackgroundPixmap = true;
+ viewport()->update();
+ } else if (d->mustResizeBackgroundPixmap) {
+ // Background caching is disabled.
+ // Cleanup, free some resources.
+ d->mustResizeBackgroundPixmap = false;
+ d->backgroundPixmap = QPixmap();
+ d->backgroundPixmapExposed = QRegion();
+ }
+}
+
+/*!
+ Invalidates and schedules a redraw of \a layers inside \a rect. \a rect is
+ in scene coordinates. Any cached content for \a layers inside \a rect is
+ unconditionally invalidated and redrawn.
+
+ You can call this function to notify QGraphicsView of changes to the
+ background or the foreground of the scene. It is commonly used for scenes
+ with tile-based backgrounds to notify changes when QGraphicsView has
+ enabled background caching.
+
+ Note that QGraphicsView currently supports background caching only (see
+ QGraphicsView::CacheBackground). This function is equivalent to calling update() if any
+ layer but QGraphicsScene::BackgroundLayer is passed.
+
+ \sa QGraphicsScene::invalidate(), update()
+*/
+void QGraphicsView::invalidateScene(const QRectF &rect, QGraphicsScene::SceneLayers layers)
+{
+ Q_D(QGraphicsView);
+ if ((layers & QGraphicsScene::BackgroundLayer) && !d->mustResizeBackgroundPixmap) {
+ QRect viewRect = mapFromScene(rect).boundingRect();
+ if (viewport()->rect().intersects(viewRect)) {
+ // The updated background area is exposed; schedule this area for
+ // redrawing.
+ d->backgroundPixmapExposed += viewRect;
+ if (d->scene)
+ d->scene->update(rect);
+ }
+ }
+}
+
+/*!
+ \property QGraphicsView::interactive
+ \brief whether the view allowed scene interaction.
+
+ If enabled, this view is set to allow scene interaction. Otherwise, this
+ view will not allow interaction, and any mouse or key events are ignored
+ (i.e., it will act as a read-only view).
+
+ By default, this property is true.
+*/
+bool QGraphicsView::isInteractive() const
+{
+ Q_D(const QGraphicsView);
+ return d->sceneInteractionAllowed;
+}
+void QGraphicsView::setInteractive(bool allowed)
+{
+ Q_D(QGraphicsView);
+ d->sceneInteractionAllowed = allowed;
+}
+
+/*!
+ Returns a pointer to the scene that is currently visualized in the
+ view. If no scene is currently visualized, 0 is returned.
+
+ \sa setScene()
+*/
+QGraphicsScene *QGraphicsView::scene() const
+{
+ Q_D(const QGraphicsView);
+ return d->scene;
+}
+
+/*!
+ Sets the current scene to \a scene. If \a scene is already being
+ viewed, this function does nothing.
+
+ When a scene is set on a view, the QGraphicsScene::changed() signal
+ is automatically connected to this view's updateScene() slot, and the
+ view's scroll bars are adjusted to fit the size of the scene.
+*/
+void QGraphicsView::setScene(QGraphicsScene *scene)
+{
+ Q_D(QGraphicsView);
+ if (d->scene == scene)
+ return;
+
+ // Always update the viewport when the scene changes.
+ viewport()->update();
+
+ // Remove the previously assigned scene.
+ if (d->scene) {
+ disconnect(d->scene, SIGNAL(changed(QList<QRectF>)),
+ this, SLOT(updateScene(QList<QRectF>)));
+ disconnect(d->scene, SIGNAL(sceneRectChanged(QRectF)),
+ this, SLOT(updateSceneRect(QRectF)));
+ d->scene->d_func()->views.removeAll(this);
+ }
+
+ // Assign the new scene and update the contents (scrollbars, etc.)).
+ if ((d->scene = scene)) {
+ connect(d->scene, SIGNAL(sceneRectChanged(QRectF)),
+ this, SLOT(updateSceneRect(QRectF)));
+ d->updateSceneSlotReimplementedChecked = false;
+ d->scene->d_func()->views << this;
+ d->recalculateContentSize();
+ d->lastCenterPoint = sceneRect().center();
+ d->keepLastCenterPoint = true;
+ } else {
+ d->recalculateContentSize();
+ }
+}
+
+/*!
+ \property QGraphicsView::sceneRect
+ \brief the area of the scene visualized by this view.
+
+ The scene rectangle defines the extent of the scene, and in the view's case,
+ this means the area of the scene that you can navigate using the scroll
+ bars.
+
+ If unset, or if a null QRectF is set, this property has the same value as
+ QGraphicsScene::sceneRect, and it changes with
+ QGraphicsScene::sceneRect. Otherwise, the view's scene rect is unaffected
+ by the scene.
+
+ Note that, although the scene supports a virtually unlimited size, the
+ range of the scroll bars will never exceed the range of an integer
+ (INT_MIN, INT_MAX). When the scene is larger than the scroll bars' values,
+ you can choose to use translate() to navigate the scene instead.
+
+ By default, this property contains a rectangle at the origin with zero
+ width and height.
+
+ \sa QGraphicsScene::sceneRect
+*/
+QRectF QGraphicsView::sceneRect() const
+{
+ Q_D(const QGraphicsView);
+ if (d->hasSceneRect)
+ return d->sceneRect;
+ if (d->scene)
+ return d->scene->sceneRect();
+ return QRectF();
+}
+void QGraphicsView::setSceneRect(const QRectF &rect)
+{
+ Q_D(QGraphicsView);
+ d->hasSceneRect = !rect.isNull();
+ d->sceneRect = rect;
+ d->recalculateContentSize();
+}
+
+/*!
+ Returns the current transformation matrix for the view. If no current
+ transformation is set, the identity matrix is returned.
+
+ \sa setMatrix(), rotate(), scale(), shear(), translate()
+*/
+QMatrix QGraphicsView::matrix() const
+{
+ Q_D(const QGraphicsView);
+ return d->matrix.toAffine();
+}
+
+/*!
+ Sets the view'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.
+
+ The transformation matrix tranforms the scene into view coordinates. Using
+ the default transformation, provided by the identity matrix, one pixel in
+ the view represents one unit in the scene (e.g., a 10x10 rectangular item
+ is drawn using 10x10 pixels in the view). If a 2x2 scaling matrix is
+ applied, the scene will be drawn in 1:2 (e.g., a 10x10 rectangular item is
+ then drawn using 20x20 pixels in the view).
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 3
+
+ To simplify interation with items using a transformed view, QGraphicsView
+ provides mapTo... and mapFrom... functions that can translate between
+ scene and view coordinates. For example, you can call mapToScene() to map
+ a view coordinate to a floating point scene coordinate, or mapFromScene()
+ to map from floating point scene coordinates to view coordinates.
+
+ \sa matrix(), rotate(), scale(), shear(), translate()
+*/
+void QGraphicsView::setMatrix(const QMatrix &matrix, bool combine)
+{
+ setTransform(QTransform(matrix), combine);
+}
+
+/*!
+ Resets the view transformation matrix to the identity matrix.
+*/
+void QGraphicsView::resetMatrix()
+{
+ resetTransform();
+}
+
+/*!
+ Rotates the current view transformation \a angle degrees clockwise.
+
+ \sa setMatrix(), matrix(), scale(), shear(), translate()
+*/
+void QGraphicsView::rotate(qreal angle)
+{
+ Q_D(QGraphicsView);
+ QTransform matrix = d->matrix;
+ matrix.rotate(angle);
+ setTransform(matrix);
+}
+
+/*!
+ Scales the current view transformation by (\a sx, \a sy).
+
+ \sa setMatrix(), matrix(), rotate(), shear(), translate()
+*/
+void QGraphicsView::scale(qreal sx, qreal sy)
+{
+ Q_D(QGraphicsView);
+ QTransform matrix = d->matrix;
+ matrix.scale(sx, sy);
+ setTransform(matrix);
+}
+
+/*!
+ Shears the current view transformation by (\a sh, \a sv).
+
+ \sa setMatrix(), matrix(), rotate(), scale(), translate()
+*/
+void QGraphicsView::shear(qreal sh, qreal sv)
+{
+ Q_D(QGraphicsView);
+ QTransform matrix = d->matrix;
+ matrix.shear(sh, sv);
+ setTransform(matrix);
+}
+
+/*!
+ Translates the current view transformation by (\a dx, \a dy).
+
+ \sa setMatrix(), matrix(), rotate(), shear()
+*/
+void QGraphicsView::translate(qreal dx, qreal dy)
+{
+ Q_D(QGraphicsView);
+ QTransform matrix = d->matrix;
+ matrix.translate(dx, dy);
+ setTransform(matrix);
+}
+
+/*!
+ Scrolls the contents of the viewport to ensure that the scene
+ coordinate \a pos, is centered in the view.
+
+ Because \a pos is a floating point coordinate, and the scroll bars operate
+ on integer coordinates, the centering is only an approximation.
+
+ \note If the item is close to or outside the border, it will be visible
+ in the view, but not centered.
+
+ \sa ensureVisible()
+*/
+void QGraphicsView::centerOn(const QPointF &pos)
+{
+ Q_D(QGraphicsView);
+ qreal width = viewport()->width();
+ qreal height = viewport()->height();
+ QPointF viewPoint = d->matrix.map(pos);
+ QPointF oldCenterPoint = pos;
+
+ if (!d->leftIndent) {
+ if (isRightToLeft()) {
+ qint64 horizontal = 0;
+ horizontal += horizontalScrollBar()->minimum();
+ horizontal += horizontalScrollBar()->maximum();
+ horizontal -= int(viewPoint.x() - width / 2.0);
+ horizontalScrollBar()->setValue(horizontal);
+ } else {
+ horizontalScrollBar()->setValue(int(viewPoint.x() - width / 2.0));
+ }
+ }
+ if (!d->topIndent)
+ verticalScrollBar()->setValue(int(viewPoint.y() - height / 2.0));
+ d->lastCenterPoint = oldCenterPoint;
+}
+
+/*!
+ \fn QGraphicsView::centerOn(qreal x, qreal y)
+ \overload
+
+ This function is provided for convenience. It's equivalent to calling
+ centerOn(QPointF(\a x, \a y)).
+*/
+
+/*!
+ \overload
+
+ Scrolls the contents of the viewport to ensure that \a item
+ is centered in the view.
+
+ \sa ensureVisible()
+*/
+void QGraphicsView::centerOn(const QGraphicsItem *item)
+{
+ centerOn(item->sceneBoundingRect().center());
+}
+
+/*!
+ Scrolls the contents of the viewport so that the scene rectangle \a rect
+ is visible, with margins specified in pixels by \a xmargin and \a
+ ymargin. If the specified rect cannot be reached, the contents are
+ scrolled to the nearest valid position. The default value for both margins
+ is 50 pixels.
+
+ \sa centerOn()
+*/
+void QGraphicsView::ensureVisible(const QRectF &rect, int xmargin, int ymargin)
+{
+ Q_D(QGraphicsView);
+ Q_UNUSED(xmargin);
+ Q_UNUSED(ymargin);
+ qreal width = viewport()->width();
+ qreal height = viewport()->height();
+ QRectF viewRect = d->matrix.mapRect(rect);
+
+ qreal left = d->horizontalScroll();
+ qreal right = left + width;
+ qreal top = d->verticalScroll();
+ qreal bottom = top + height;
+
+ if (viewRect.left() <= left + xmargin) {
+ // need to scroll from the left
+ if (!d->leftIndent)
+ horizontalScrollBar()->setValue(int(viewRect.left() - xmargin - 0.5));
+ }
+ if (viewRect.right() >= right - xmargin) {
+ // need to scroll from the right
+ if (!d->leftIndent)
+ horizontalScrollBar()->setValue(int(viewRect.right() - width + xmargin + 0.5));
+ }
+ if (viewRect.top() <= top + ymargin) {
+ // need to scroll from the top
+ if (!d->topIndent)
+ verticalScrollBar()->setValue(int(viewRect.top() - ymargin - 0.5));
+ }
+ if (viewRect.bottom() >= bottom - ymargin) {
+ // need to scroll from the bottom
+ if (!d->topIndent)
+ verticalScrollBar()->setValue(int(viewRect.bottom() - height + ymargin + 0.5));
+ }
+}
+
+/*!
+ \fn QGraphicsView::ensureVisible(qreal x, qreal y, qreal w, qreal h,
+ int xmargin, int ymargin)
+ \overload
+
+ This function is provided for convenience. It's equivalent to calling
+ ensureVisible(QRectF(\a x, \a y, \a w, \a h), \a xmargin, \a ymargin).
+*/
+
+/*!
+ \overload
+
+ Scrolls the contents of the viewport so that the center of item \a item is
+ visible, with margins specified in pixels by \a xmargin and \a ymargin. If
+ the specified point cannot be reached, the contents are scrolled to the
+ nearest valid position. The default value for both margins is 50 pixels.
+
+ \sa centerOn()
+*/
+void QGraphicsView::ensureVisible(const QGraphicsItem *item, int xmargin, int ymargin)
+{
+ ensureVisible(item->sceneBoundingRect(), xmargin, ymargin);
+}
+
+/*!
+ Scales the view matrix and scrolls the scroll bars to ensure that the
+ scene rectangle \a rect fits inside the viewport. \a rect must be inside
+ the scene rect; otherwise, fitInView() cannot guarantee that the whole
+ rect is visible.
+
+ This function keeps the view's rotation, translation, or shear. The view
+ is scaled according to \a aspectRatioMode. \a rect will be centered in the
+ view if it does not fit tightly.
+
+ It's common to call fitInView() from inside a reimplementation of
+ resizeEvent(), to ensure that the whole scene, or parts of the scene,
+ scales automatically to fit the new size of the viewport as the view is
+ resized. Note though, that calling fitInView() from inside resizeEvent()
+ can lead to unwanted resize recursion, if the new transformation toggles
+ the automatic state of the scrollbars. You can toggle the scrollbar
+ policies to always on or always off to prevent this (see
+ horizontalScrollBarPolicy() and verticalScrollBarPolicy()).
+
+ If \a rect is empty, or if the viewport is too small, this
+ function will do nothing.
+
+ \sa setMatrix(), ensureVisible(), centerOn()
+*/
+void QGraphicsView::fitInView(const QRectF &rect, Qt::AspectRatioMode aspectRatioMode)
+{
+ Q_D(QGraphicsView);
+ if (!d->scene || rect.isNull())
+ return;
+
+ // Reset the view scale to 1:1.
+ QRectF unity = d->matrix.mapRect(QRectF(0, 0, 1, 1));
+ if (unity.isEmpty())
+ return;
+ scale(1 / unity.width(), 1 / unity.height());
+
+ // Find the ideal x / y scaling ratio to fit \a rect in the view.
+ int margin = 2;
+ QRectF viewRect = viewport()->rect().adjusted(margin, margin, -margin, -margin);
+ if (viewRect.isEmpty())
+ return;
+ QRectF sceneRect = d->matrix.mapRect(rect);
+ if (sceneRect.isEmpty())
+ return;
+ qreal xratio = viewRect.width() / sceneRect.width();
+ qreal yratio = viewRect.height() / sceneRect.height();
+
+ // Respect the aspect ratio mode.
+ switch (aspectRatioMode) {
+ case Qt::KeepAspectRatio:
+ xratio = yratio = qMin(xratio, yratio);
+ break;
+ case Qt::KeepAspectRatioByExpanding:
+ xratio = yratio = qMax(xratio, yratio);
+ break;
+ case Qt::IgnoreAspectRatio:
+ break;
+ }
+
+ // Scale and center on the center of \a rect.
+ scale(xratio, yratio);
+ centerOn(rect.center());
+}
+
+/*!
+ \fn void QGraphicsView::fitInView(qreal x, qreal y, qreal w, qreal h,
+ Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio)
+
+ \overload
+
+ This convenience function is equivalent to calling
+ fitInView(QRectF(\a x, \a y, \a w, \a h), \a aspectRatioMode).
+
+ \sa ensureVisible(), centerOn()
+*/
+
+/*!
+ \overload
+
+ Ensures that \a item fits tightly inside the view, scaling the view
+ according to \a aspectRatioMode.
+
+ \sa ensureVisible(), centerOn()
+*/
+void QGraphicsView::fitInView(const QGraphicsItem *item, Qt::AspectRatioMode aspectRatioMode)
+{
+ QPainterPath path = item->isClipped() ? item->clipPath() : item->shape();
+ fitInView(item->sceneTransform().map(path).boundingRect(), aspectRatioMode);
+}
+
+/*!
+ Renders the \a source rect, which is in view coordinates, from the scene
+ into \a target, which is in paint device coordinates, using \a
+ painter. This function is useful for capturing the contents of the view
+ onto a paint device, such as a QImage (e.g., to take a screenshot), or for
+ printing to QPrinter. For example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 4
+
+ If \a source is a null rect, this function will use viewport()->rect() to
+ determine what to draw. If \a target is a null rect, the full dimensions
+ of \a painter's paint device (e.g., for a QPrinter, the page size) will be
+ used.
+
+ The source rect contents will be transformed according to \a
+ aspectRatioMode to fit into the target rect. By default, the aspect ratio
+ is kept, and \a source is scaled to fit in \a target.
+
+ \sa QGraphicsScene::render()
+*/
+void QGraphicsView::render(QPainter *painter, const QRectF &target, const QRect &source,
+ Qt::AspectRatioMode aspectRatioMode)
+{
+ Q_D(QGraphicsView);
+ if (!d->scene || !(painter && painter->isActive()))
+ return;
+
+ // Default source rect = viewport rect
+ QRect sourceRect = source;
+ if (source.isNull())
+ sourceRect = viewport()->rect();
+
+ // Default target rect = device rect
+ QRectF targetRect = target;
+ if (target.isNull()) {
+ if (painter->device()->devType() == QInternal::Picture)
+ targetRect = sourceRect;
+ else
+ targetRect.setRect(0, 0, painter->device()->width(), painter->device()->height());
+ }
+
+ // Find the ideal x / y scaling ratio to fit \a source into \a target.
+ qreal xratio = targetRect.width() / sourceRect.width();
+ qreal yratio = targetRect.height() / sourceRect.height();
+
+ // Scale according to the aspect ratio mode.
+ switch (aspectRatioMode) {
+ case Qt::KeepAspectRatio:
+ xratio = yratio = qMin(xratio, yratio);
+ break;
+ case Qt::KeepAspectRatioByExpanding:
+ xratio = yratio = qMax(xratio, yratio);
+ break;
+ case Qt::IgnoreAspectRatio:
+ break;
+ }
+
+ // Find all items to draw, and reverse the list (we want to draw
+ // in reverse order).
+ QPolygonF sourceScenePoly = mapToScene(sourceRect.adjusted(-1, -1, 1, 1));
+ QList<QGraphicsItem *> itemList = d->scene->items(sourceScenePoly,
+ Qt::IntersectsItemBoundingRect);
+ QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
+ int numItems = itemList.size();
+ for (int i = 0; i < numItems; ++i)
+ itemArray[numItems - i - 1] = itemList.at(i);
+ itemList.clear();
+
+ // Setup painter matrix.
+ QTransform moveMatrix;
+ moveMatrix.translate(-d->horizontalScroll(), -d->verticalScroll());
+ QTransform painterMatrix = d->matrix * moveMatrix;
+ painterMatrix *= QTransform()
+ .translate(targetRect.left(), targetRect.top())
+ .scale(xratio, yratio)
+ .translate(-sourceRect.left(), -sourceRect.top());
+
+ // Two unit vectors.
+ QLineF v1(0, 0, 1, 0);
+ QLineF v2(0, 0, 0, 1);
+
+ // Generate the style options
+ QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems);
+ QStyleOptionGraphicsItem* option = styleOptionArray;
+ for (int i = 0; i < numItems; ++i, ++option) {
+ QGraphicsItem *item = itemArray[i];
+
+ option->state = QStyle::State_None;
+ option->rect = item->boundingRect().toRect();
+ if (item->isSelected())
+ option->state |= QStyle::State_Selected;
+ if (item->isEnabled())
+ option->state |= QStyle::State_Enabled;
+ if (item->hasFocus())
+ option->state |= QStyle::State_HasFocus;
+ if (d->scene->d_func()->hoverItems.contains(item))
+ option->state |= QStyle::State_MouseOver;
+ if (item == d->scene->mouseGrabberItem())
+ option->state |= QStyle::State_Sunken;
+
+ // Calculate a simple level-of-detail metric.
+ // ### almost identical code in QGraphicsScene::render()
+ // and QGraphicsView::paintEvent() - consider refactoring
+ QTransform itemToViewportTransform;
+ if (item->d_ptr->itemIsUntransformable()) {
+ itemToViewportTransform = item->deviceTransform(painterMatrix);
+ } else {
+ itemToViewportTransform = item->sceneTransform() * painterMatrix;
+ }
+
+ option->levelOfDetail = qSqrt(itemToViewportTransform.map(v1).length() * itemToViewportTransform.map(v2).length());
+ option->matrix = itemToViewportTransform.toAffine();
+
+ option->exposedRect = item->boundingRect();
+ option->exposedRect &= itemToViewportTransform.inverted().mapRect(targetRect);
+ }
+
+ painter->save();
+
+ // Clip in device coordinates to avoid QRegion transformations.
+ painter->setClipRect(targetRect);
+ QPainterPath path;
+ path.addPolygon(sourceScenePoly);
+ path.closeSubpath();
+ painter->setClipPath(painterMatrix.map(path), Qt::IntersectClip);
+
+ // Transform the painter.
+ painter->setTransform(painterMatrix, true);
+
+ // Render the scene.
+ QRectF sourceSceneRect = sourceScenePoly.boundingRect();
+ drawBackground(painter, sourceSceneRect);
+ drawItems(painter, numItems, itemArray, styleOptionArray);
+ drawForeground(painter, sourceSceneRect);
+
+ delete [] itemArray;
+ d->freeStyleOptionsArray(styleOptionArray);
+
+ painter->restore();
+}
+
+/*!
+ Returns a list of all the items in the associated scene.
+
+ \sa QGraphicsScene::items()
+*/
+QList<QGraphicsItem *> QGraphicsView::items() const
+{
+ Q_D(const QGraphicsView);
+ if (!d->scene)
+ return QList<QGraphicsItem *>();
+ return d->scene->items();
+}
+
+/*!
+ Returns all items in the area \a path, which is in viewport coordinates,
+ also taking untransformable items into consideration. This function is
+ considerably slower than just checking the scene directly. There is
+ certainly room for improvement.
+*/
+QList<QGraphicsItem *> QGraphicsViewPrivate::itemsInArea(const QPainterPath &path,
+ Qt::ItemSelectionMode mode) const
+{
+ Q_Q(const QGraphicsView);
+
+ // Determine the size of the largest untransformable subtree of children
+ // mapped to scene coordinates.
+ QRectF untr = scene->d_func()->largestUntransformableItem;
+ QRectF ltri = matrix.inverted().mapRect(untr);
+ ltri.adjust(-untr.width(), -untr.height(), untr.width(), untr.height());
+
+ QRectF rect = path.controlPointRect();
+
+ // Find all possible items in the relevant area.
+ // ### Improve this algorithm; it might be searching a too large area.
+ QRectF adjustedRect = q->mapToScene(rect.adjusted(-1, -1, 1, 1).toRect()).boundingRect();
+ adjustedRect.adjust(-ltri.width(), -ltri.height(), ltri.width(), ltri.height());
+
+ // First build a (potentially large) list of all items in the vicinity
+ // that might be untransformable.
+ QList<QGraphicsItem *> allCandidates = scene->d_func()->estimateItemsInRect(adjustedRect);
+
+ // Then find the minimal list of items that are inside \a path, and
+ // convert it to a set.
+ QList<QGraphicsItem *> regularCandidates = scene->items(q->mapToScene(path), mode);
+ QSet<QGraphicsItem *> candSet = QSet<QGraphicsItem *>::fromList(regularCandidates);
+
+ QTransform viewMatrix = q->viewportTransform();
+
+ QList<QGraphicsItem *> result;
+
+ // Run through all candidates and keep all items that are in candSet, or
+ // are untransformable and collide with \a path. ### We can improve this
+ // algorithm.
+ QList<QGraphicsItem *>::Iterator it = allCandidates.begin();
+ while (it != allCandidates.end()) {
+ QGraphicsItem *item = *it;
+ if (item->d_ptr->itemIsUntransformable()) {
+ // Check if this untransformable item collides with the
+ // original selection rect.
+ QTransform itemTransform = item->deviceTransform(viewMatrix);
+ if (QGraphicsScenePrivate::itemCollidesWithPath(item, itemTransform.inverted().map(path), mode))
+ result << item;
+ } else {
+ if (candSet.contains(item))
+ result << item;
+ }
+ ++it;
+ }
+
+ // ### Insertion sort would be faster.
+ QGraphicsScenePrivate::sortItems(&result, Qt::AscendingOrder,
+ scene->d_func()->sortCacheEnabled);
+ return result;
+}
+
+/*!
+ Returns a list of all the items at the position \a pos in the view. The
+ items are listed in descending Z order (i.e., the first item in the list
+ is the top-most item, and the last item is the bottom-most item). \a pos
+ is in viewport coordinates.
+
+ This function is most commonly called from within mouse event handlers in
+ a subclass in QGraphicsView. \a pos is in untransformed viewport
+ coordinates, just like QMouseEvent::pos().
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 5
+
+ \sa QGraphicsScene::items(), QGraphicsItem::zValue()
+*/
+QList<QGraphicsItem *> QGraphicsView::items(const QPoint &pos) const
+{
+ Q_D(const QGraphicsView);
+ if (!d->scene)
+ return QList<QGraphicsItem *>();
+ if (d->scene->d_func()->largestUntransformableItem.isNull()) {
+ if ((d->identityMatrix || d->matrix.type() <= QTransform::TxScale)) {
+ QTransform xinv = viewportTransform().inverted();
+ return d->scene->items(xinv.mapRect(QRectF(pos.x(), pos.y(), 1, 1)));
+ }
+ return d->scene->items(mapToScene(pos.x(), pos.y(), 2, 2));
+ }
+
+ QPainterPath path;
+ path.addRect(QRectF(pos.x(), pos.y(), 1, 1));
+ return d->itemsInArea(path);
+}
+
+/*!
+ \fn QGraphicsView::items(int x, int y) const
+
+ This function is provided for convenience. It's equivalent to calling
+ items(QPoint(\a x, \a y)).
+*/
+
+/*!
+ \overload
+
+ Returns a list of all the items that, depending on \a mode, are either
+ contained by or intersect with \a rect. \a rect is in viewport
+ coordinates.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a rect are returned.
+
+ \sa itemAt(), items(), mapToScene()
+*/
+QList<QGraphicsItem *> QGraphicsView::items(const QRect &rect, Qt::ItemSelectionMode mode) const
+{
+ Q_D(const QGraphicsView);
+ if (!d->scene)
+ return QList<QGraphicsItem *>();
+ if (d->scene->d_func()->largestUntransformableItem.isNull())
+ return d->scene->items(mapToScene(rect), mode);
+
+ QPainterPath path;
+ path.addRect(rect);
+ return d->itemsInArea(path);
+}
+
+/*!
+ \fn QList<QGraphicsItem *> QGraphicsView::items(int x, int y, int w, int h, Qt::ItemSelectionMode mode) const
+ \since 4.3
+
+ This convenience function is equivalent to calling items(QRectF(\a x, \a
+ y, \a w, \a h), \a mode).
+*/
+
+/*!
+ \overload
+
+ Returns a list of all the items that, depending on \a mode, are either
+ contained by or intersect with \a polygon. \a polygon is in viewport
+ coordinates.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a polygon are returned.
+
+ \sa itemAt(), items(), mapToScene()
+*/
+QList<QGraphicsItem *> QGraphicsView::items(const QPolygon &polygon, Qt::ItemSelectionMode mode) const
+{
+ Q_D(const QGraphicsView);
+ if (!d->scene)
+ return QList<QGraphicsItem *>();
+ if (d->scene->d_func()->largestUntransformableItem.isNull())
+ return d->scene->items(mapToScene(polygon), mode);
+
+ QPainterPath path;
+ path.addPolygon(polygon);
+ path.closeSubpath();
+ return d->itemsInArea(path);
+}
+
+/*!
+ \overload
+
+ Returns a list of all the items that, depending on \a mode, are either
+ contained by or intersect with \a path. \a path is in viewport
+ coordinates.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a path are returned.
+
+ \sa itemAt(), items(), mapToScene()
+*/
+QList<QGraphicsItem *> QGraphicsView::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
+{
+ Q_D(const QGraphicsView);
+ if (!d->scene)
+ return QList<QGraphicsItem *>();
+ if (d->scene->d_func()->largestUntransformableItem.isNull())
+ return d->scene->items(mapToScene(path), mode);
+ return d->itemsInArea(path);
+}
+
+/*!
+ Returns the item at position \a pos, which is in viewport coordinates.
+ If there are several items at this position, this function returns
+ the topmost item.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 6
+
+ \sa items()
+*/
+QGraphicsItem *QGraphicsView::itemAt(const QPoint &pos) const
+{
+ Q_D(const QGraphicsView);
+ if (!d->scene)
+ return 0;
+ QList<QGraphicsItem *> itemsAtPos = items(pos);
+ return itemsAtPos.isEmpty() ? 0 : itemsAtPos.first();
+}
+
+/*!
+ \overload
+ \fn QGraphicsItem *QGraphicsView::itemAt(int x, int y) const
+
+ This function is provided for convenience. It's equivalent to
+ calling itemAt(QPoint(\a x, \a y)).
+*/
+
+/*!
+ Returns the viewport coordinate \a point mapped to scene coordinates.
+
+ Note: It can be useful to map the whole rectangle covered by the pixel at
+ \a point instead of the point itself. To do this, you can call
+ mapToScene(QRect(\a point, QSize(2, 2))).
+
+ \sa mapFromScene()
+*/
+QPointF QGraphicsView::mapToScene(const QPoint &point) const
+{
+ Q_D(const QGraphicsView);
+ QPointF p = point;
+ p.rx() += d->horizontalScroll();
+ p.ry() += d->verticalScroll();
+ return d->identityMatrix ? p : d->matrix.inverted().map(p);
+}
+
+/*!
+ \fn QGraphicsView::mapToScene(int x, int y) const
+
+ This function is provided for convenience. It's equivalent to calling
+ mapToScene(QPoint(\a x, \a y)).
+*/
+
+/*!
+ Returns the viewport rectangle \a rect mapped to a scene coordinate
+ polygon.
+
+ \sa mapFromScene()
+*/
+QPolygonF QGraphicsView::mapToScene(const QRect &rect) const
+{
+ Q_D(const QGraphicsView);
+ if (!rect.isValid())
+ return QPolygonF();
+
+ QPointF scrollOffset(d->horizontalScroll(), d->verticalScroll());
+ QPointF tl = scrollOffset + rect.topLeft();
+ QPointF tr = scrollOffset + rect.topRight();
+ QPointF br = scrollOffset + rect.bottomRight();
+ QPointF bl = scrollOffset + rect.bottomLeft();
+
+ QPolygonF poly;
+ poly.resize(4);
+ if (!d->identityMatrix) {
+ QTransform x = d->matrix.inverted();
+ poly[0] = x.map(tl);
+ poly[1] = x.map(tr);
+ poly[2] = x.map(br);
+ poly[3] = x.map(bl);
+ } else {
+ poly[0] = tl;
+ poly[1] = tr;
+ poly[2] = br;
+ poly[3] = bl;
+ }
+ return poly;
+}
+
+/*!
+ \fn QGraphicsView::mapToScene(int x, int y, int w, int h) const
+
+ This function is provided for convenience. It's equivalent to calling
+ mapToScene(QRect(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ Returns the viewport polygon \a polygon mapped to a scene coordinate
+ polygon.
+
+ \sa mapFromScene()
+*/
+QPolygonF QGraphicsView::mapToScene(const QPolygon &polygon) const
+{
+ QPolygonF poly;
+ foreach (const QPoint &point, polygon)
+ poly << mapToScene(point);
+ return poly;
+}
+
+/*!
+ Returns the viewport painter path \a path mapped to a scene coordinate
+ painter path.
+
+ \sa mapFromScene()
+*/
+QPainterPath QGraphicsView::mapToScene(const QPainterPath &path) const
+{
+ Q_D(const QGraphicsView);
+ QTransform moveMatrix;
+ moveMatrix.translate(d->horizontalScroll(), d->verticalScroll());
+ return (moveMatrix * d->matrix.inverted()).map(path);
+}
+
+/*!
+ Returns the scene coordinate \a point to viewport coordinates.
+
+ \sa mapToScene()
+*/
+QPoint QGraphicsView::mapFromScene(const QPointF &point) const
+{
+ Q_D(const QGraphicsView);
+ QPointF p = d->identityMatrix ? point : d->matrix.map(point);
+ p.rx() -= d->horizontalScroll();
+ p.ry() -= d->verticalScroll();
+ return p.toPoint();
+}
+
+/*!
+ \fn QGraphicsView::mapFromScene(qreal x, qreal y) const
+
+ This function is provided for convenience. It's equivalent to
+ calling mapFromScene(QPointF(\a x, \a y)).
+*/
+
+/*!
+ Returns the scene rectangle \a rect to a viewport coordinate
+ polygon.
+
+ \sa mapToScene()
+*/
+QPolygon QGraphicsView::mapFromScene(const QRectF &rect) const
+{
+ Q_D(const QGraphicsView);
+ QPointF tl;
+ QPointF tr;
+ QPointF br;
+ QPointF bl;
+ if (!d->identityMatrix) {
+ const QTransform &x = d->matrix;
+ tl = x.map(rect.topLeft());
+ tr = x.map(rect.topRight());
+ br = x.map(rect.bottomRight());
+ bl = x.map(rect.bottomLeft());
+ } else {
+ tl = rect.topLeft();
+ tr = rect.topRight();
+ br = rect.bottomRight();
+ bl = rect.bottomLeft();
+ }
+ QPointF scrollOffset(d->horizontalScroll(), d->verticalScroll());
+ tl -= scrollOffset;
+ tr -= scrollOffset;
+ br -= scrollOffset;
+ bl -= scrollOffset;
+
+ QPolygon poly;
+ poly.resize(4);
+ poly[0] = tl.toPoint();
+ poly[1] = tr.toPoint();
+ poly[2] = br.toPoint();
+ poly[3] = bl.toPoint();
+ return poly;
+}
+
+/*!
+ \fn QGraphicsView::mapFromScene(qreal x, qreal y, qreal w, qreal h) const
+
+ This function is provided for convenience. It's equivalent to
+ calling mapFromScene(QRectF(\a x, \a y, \a w, \a h)).
+*/
+
+/*!
+ Returns the scene coordinate polygon \a polygon to a viewport coordinate
+ polygon.
+
+ \sa mapToScene()
+*/
+QPolygon QGraphicsView::mapFromScene(const QPolygonF &polygon) const
+{
+ QPolygon poly;
+ foreach (const QPointF &point, polygon)
+ poly << mapFromScene(point);
+ return poly;
+}
+
+/*!
+ Returns the scene coordinate painter path \a path to a viewport coordinate
+ painter path.
+
+ \sa mapToScene()
+*/
+QPainterPath QGraphicsView::mapFromScene(const QPainterPath &path) const
+{
+ Q_D(const QGraphicsView);
+ QTransform moveMatrix;
+ moveMatrix.translate(-d->horizontalScroll(), -d->verticalScroll());
+ return (d->matrix * moveMatrix).map(path);
+}
+
+/*!
+ \reimp
+*/
+QVariant QGraphicsView::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QGraphicsView);
+ if (!d->scene)
+ return QVariant();
+
+ QVariant value = d->scene->inputMethodQuery(query);
+ if (value.type() == QVariant::RectF)
+ value = mapFromScene(value.toRectF()).boundingRect();
+ else if (value.type() == QVariant::PointF)
+ value = mapFromScene(value.toPointF());
+ else if (value.type() == QVariant::Rect)
+ value = mapFromScene(value.toRect()).boundingRect();
+ else if (value.type() == QVariant::Point)
+ value = mapFromScene(value.toPoint());
+ return value;
+}
+
+/*!
+ \property QGraphicsView::backgroundBrush
+ \brief the background brush of the scene.
+
+ This property sets the background brush for the scene in this view. It is
+ used to override the scene's own background, and defines the behavior of
+ drawBackground(). To provide custom background drawing for this view, you
+ can reimplement drawBackground() instead.
+
+ By default, this property contains a brush with the Qt::NoBrush pattern.
+
+ \sa QGraphicsScene::backgroundBrush, foregroundBrush
+*/
+QBrush QGraphicsView::backgroundBrush() const
+{
+ Q_D(const QGraphicsView);
+ return d->backgroundBrush;
+}
+void QGraphicsView::setBackgroundBrush(const QBrush &brush)
+{
+ Q_D(QGraphicsView);
+ d->backgroundBrush = brush;
+ viewport()->update();
+
+ if (d->cacheMode & CacheBackground) {
+ // Invalidate the background pixmap
+ d->mustResizeBackgroundPixmap = true;
+ }
+}
+
+/*!
+ \property QGraphicsView::foregroundBrush
+ \brief the foreground brush of the scene.
+
+ This property sets the foreground brush for the scene in this view. It is
+ used to override the scene's own foreground, and defines the behavior of
+ drawForeground(). To provide custom foreground drawing for this view, you
+ can reimplement drawForeground() instead.
+
+ By default, this property contains a brush with the Qt::NoBrush pattern.
+
+ \sa QGraphicsScene::foregroundBrush, backgroundBrush
+*/
+QBrush QGraphicsView::foregroundBrush() const
+{
+ Q_D(const QGraphicsView);
+ return d->foregroundBrush;
+}
+void QGraphicsView::setForegroundBrush(const QBrush &brush)
+{
+ Q_D(QGraphicsView);
+ d->foregroundBrush = brush;
+ viewport()->update();
+}
+
+/*!
+ Schedules an update of the scene rectangles \a rects.
+
+ \sa QGraphicsScene::changed()
+*/
+void QGraphicsView::updateScene(const QList<QRectF> &rects)
+{
+ // ### Note: Since 4.5, this slot is only called if the user explicitly
+ // establishes a connection between the scene and the view, as the scene
+ // and view are no longer connected. We need to keep it working (basically
+ // leave it as it is), but the new delivery path is through
+ // QGraphicsScenePrivate::itemUpdate().
+ Q_D(QGraphicsView);
+ if (d->fullUpdatePending || d->viewportUpdateMode == QGraphicsView::NoViewportUpdate)
+ return;
+
+ // Extract and reset dirty scene rect info.
+ QVector<QRect> dirtyViewportRects;
+ for (int i = 0; i < d->dirtyRegions.size(); ++i)
+ dirtyViewportRects += d->dirtyRegions.at(i).rects();
+ d->dirtyRegions.clear();
+
+ bool fullUpdate = !d->accelerateScrolling || d->viewportUpdateMode == QGraphicsView::FullViewportUpdate;
+ bool boundingRectUpdate = (d->viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate)
+ || (d->viewportUpdateMode == QGraphicsView::SmartViewportUpdate
+ && ((dirtyViewportRects.size() + rects.size()) >= QGRAPHICSVIEW_REGION_RECT_THRESHOLD));
+
+ QRegion updateRegion;
+ QRect boundingRect;
+ QRect viewportRect = viewport()->rect();
+ bool redraw = false;
+ QTransform transform = viewportTransform();
+
+ // Convert scene rects to viewport rects.
+ foreach (const QRectF &rect, rects) {
+ QRect xrect = transform.mapRect(rect).toRect();
+ if (!(d->optimizationFlags & DontAdjustForAntialiasing))
+ xrect.adjust(-2, -2, 2, 2);
+ if (!viewportRect.intersects(xrect))
+ continue;
+ dirtyViewportRects << xrect;
+ }
+
+ foreach (const QRect &rect, dirtyViewportRects) {
+ // Add the exposed rect to the update region. In rect update
+ // mode, we only count the bounding rect of items.
+ if (!boundingRectUpdate) {
+ updateRegion += rect;
+ } else {
+ boundingRect |= rect;
+ }
+ redraw = true;
+ if (fullUpdate) {
+ // If fullUpdate is true and we found a visible dirty rect,
+ // we're done.
+ break;
+ }
+ }
+
+ if (!redraw)
+ return;
+
+ if (fullUpdate)
+ viewport()->update();
+ else if (boundingRectUpdate)
+ viewport()->update(boundingRect);
+ else
+ viewport()->update(updateRegion);
+}
+
+/*!
+ Notifies QGraphicsView that the scene's scene rect has changed. \a rect
+ is the new scene rect. If the view already has an explicitly set scene
+ rect, this function does nothing.
+
+ \sa sceneRect, QGraphicsScene::sceneRectChanged()
+*/
+void QGraphicsView::updateSceneRect(const QRectF &rect)
+{
+ Q_D(QGraphicsView);
+ if (!d->hasSceneRect) {
+ d->sceneRect = rect;
+ d->recalculateContentSize();
+ }
+}
+
+/*!
+ This slot is called by QAbstractScrollArea after setViewport() has been
+ called. Reimplement this function in a subclass of QGraphicsView to
+ initialize the new viewport \a widget before it is used.
+
+ \sa setViewport()
+*/
+void QGraphicsView::setupViewport(QWidget *widget)
+{
+ Q_D(QGraphicsView);
+
+ if (!widget) {
+ qWarning("QGraphicsView::setupViewport: cannot initialize null widget");
+ return;
+ }
+
+ const bool isGLWidget = widget->inherits("QGLWidget");
+
+ d->accelerateScrolling = !(isGLWidget
+ || widget->testAttribute(Qt::WA_MSWindowsUseDirect3D)
+ || qApp->testAttribute(Qt::AA_MSWindowsUseDirect3DByDefault));
+
+ widget->setFocusPolicy(Qt::StrongFocus);
+
+ if (!isGLWidget) {
+ // autoFillBackground enables scroll acceleration.
+ widget->setAutoFillBackground(true);
+ }
+
+ widget->setMouseTracking(true);
+ widget->setAcceptDrops(acceptDrops());
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsView::event(QEvent *event)
+{
+ Q_D(QGraphicsView);
+
+ if (d->sceneInteractionAllowed) {
+ switch (event->type()) {
+ case QEvent::ShortcutOverride:
+ if (d->scene)
+ return QApplication::sendEvent(d->scene, event);
+ break;
+ case QEvent::KeyPress:
+ if (d->scene) {
+ QKeyEvent *k = static_cast<QKeyEvent *>(event);
+ if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
+ // Send the key events to the scene. This will invoke the
+ // scene's tab focus handling, and if the event is
+ // accepted, we return (prevent further event delivery),
+ // and the base implementation will call QGraphicsView's
+ // focusNextPrevChild() function. If the event is ignored,
+ // we fall back to standard tab focus handling.
+ QApplication::sendEvent(d->scene, event);
+ if (event->isAccepted())
+ return true;
+ // Ensure the event doesn't propagate just because the
+ // scene ignored it. If the event propagates, then tab
+ // handling will be called twice (this and parent).
+ event->accept();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return QAbstractScrollArea::event(event);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsView::viewportEvent(QEvent *event)
+{
+ Q_D(QGraphicsView);
+
+ if (!d->scene)
+ return QAbstractScrollArea::viewportEvent(event);
+
+ switch (event->type()) {
+ case QEvent::Enter:
+ QApplication::sendEvent(d->scene, event);
+ break;
+ case QEvent::WindowActivate:
+ QApplication::sendEvent(d->scene, event);
+ break;
+ case QEvent::WindowDeactivate:
+ // ### This is a temporary fix for until we get proper mouse
+ // grab events. mouseGrabberItem should be set to 0 if we lose
+ // the mouse grab.
+ // Remove all popups when the scene loses focus.
+ if (!d->scene->d_func()->popupWidgets.isEmpty())
+ d->scene->d_func()->removePopup(d->scene->d_func()->popupWidgets.first());
+ QApplication::sendEvent(d->scene, event);
+ break;
+ case QEvent::Leave:
+ // ### This is a temporary fix for until we get proper mouse grab
+ // events. activeMouseGrabberItem should be set to 0 if we lose the
+ // mouse grab.
+ if ((QApplication::activePopupWidget() && QApplication::activePopupWidget() != window())
+ || (QApplication::activeModalWidget() && QApplication::activeModalWidget() != window())
+ || (QApplication::activeWindow() != window())) {
+ if (!d->scene->d_func()->popupWidgets.isEmpty())
+ d->scene->d_func()->removePopup(d->scene->d_func()->popupWidgets.first());
+ }
+ d->useLastMouseEvent = false;
+ QApplication::sendEvent(d->scene, event);
+ break;
+#ifndef QT_NO_TOOLTIP
+ case QEvent::ToolTip: {
+ QHelpEvent *toolTip = static_cast<QHelpEvent *>(event);
+ QGraphicsSceneHelpEvent helpEvent(QEvent::GraphicsSceneHelp);
+ helpEvent.setWidget(viewport());
+ helpEvent.setScreenPos(toolTip->globalPos());
+ helpEvent.setScenePos(mapToScene(toolTip->pos()));
+ QApplication::sendEvent(d->scene, &helpEvent);
+ toolTip->setAccepted(helpEvent.isAccepted());
+ return true;
+ }
+#endif
+ case QEvent::Paint:
+ // Reset full update
+ d->fullUpdatePending = false;
+ if (d->scene) {
+ // Check if this view reimplements the updateScene slot; if it
+ // does, we can't do direct update delivery and have to fall back
+ // to connecting the changed signal.
+ if (!d->updateSceneSlotReimplementedChecked) {
+ d->updateSceneSlotReimplementedChecked = true;
+ const QMetaObject *mo = metaObject();
+ if (mo != &QGraphicsView::staticMetaObject) {
+ if (mo->indexOfSlot("updateScene(QList<QRectF>)")
+ != QGraphicsView::staticMetaObject.indexOfSlot("updateScene(QList<QRectF>)")) {
+ connect(d->scene, SIGNAL(changed(QList<QRectF>)),
+ this, SLOT(updateScene(QList<QRectF>)));
+ }
+ }
+ }
+ d->scene->d_func()->updateAll = false;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return QAbstractScrollArea::viewportEvent(event);
+}
+
+#ifndef QT_NO_CONTEXTMENU
+/*!
+ \reimp
+*/
+void QGraphicsView::contextMenuEvent(QContextMenuEvent *event)
+{
+ Q_D(QGraphicsView);
+ if (!d->scene || !d->sceneInteractionAllowed)
+ return;
+
+ d->mousePressViewPoint = event->pos();
+ d->mousePressScenePoint = mapToScene(d->mousePressViewPoint);
+ d->mousePressScreenPoint = event->globalPos();
+ d->lastMouseMoveScenePoint = d->mousePressScenePoint;
+ d->lastMouseMoveScreenPoint = d->mousePressScreenPoint;
+
+ QGraphicsSceneContextMenuEvent contextEvent(QEvent::GraphicsSceneContextMenu);
+ contextEvent.setWidget(viewport());
+ contextEvent.setScenePos(d->mousePressScenePoint);
+ contextEvent.setScreenPos(d->mousePressScreenPoint);
+ contextEvent.setModifiers(event->modifiers());
+ contextEvent.setReason((QGraphicsSceneContextMenuEvent::Reason)(event->reason()));
+ contextEvent.setAccepted(event->isAccepted());
+ QApplication::sendEvent(d->scene, &contextEvent);
+ event->setAccepted(contextEvent.isAccepted());
+}
+#endif // QT_NO_CONTEXTMENU
+
+/*!
+ \reimp
+*/
+void QGraphicsView::dropEvent(QDropEvent *event)
+{
+#ifndef QT_NO_DRAGANDDROP
+ Q_D(QGraphicsView);
+ if (!d->scene || !d->sceneInteractionAllowed)
+ return;
+
+ // Generate a scene event.
+ QGraphicsSceneDragDropEvent sceneEvent(QEvent::GraphicsSceneDrop);
+ d->populateSceneDragDropEvent(&sceneEvent, event);
+
+ // Send it to the scene.
+ QApplication::sendEvent(d->scene, &sceneEvent);
+
+ // Accept the originating event if the scene accepted the scene event.
+ event->setAccepted(sceneEvent.isAccepted());
+ if (sceneEvent.isAccepted())
+ event->setDropAction(sceneEvent.dropAction());
+
+ delete d->lastDragDropEvent;
+ d->lastDragDropEvent = 0;
+
+#else
+ Q_UNUSED(event)
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::dragEnterEvent(QDragEnterEvent *event)
+{
+#ifndef QT_NO_DRAGANDDROP
+ Q_D(QGraphicsView);
+ if (!d->scene || !d->sceneInteractionAllowed)
+ return;
+
+ // Disable replaying of mouse move events.
+ d->useLastMouseEvent = false;
+
+ // Generate a scene event.
+ QGraphicsSceneDragDropEvent sceneEvent(QEvent::GraphicsSceneDragEnter);
+ d->populateSceneDragDropEvent(&sceneEvent, event);
+
+ // Store it for later use.
+ d->storeDragDropEvent(&sceneEvent);
+
+ // Send it to the scene.
+ QApplication::sendEvent(d->scene, &sceneEvent);
+
+ // Accept the originating event if the scene accepted the scene event.
+ if (sceneEvent.isAccepted()) {
+ event->setAccepted(true);
+ event->setDropAction(sceneEvent.dropAction());
+ }
+#else
+ Q_UNUSED(event)
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::dragLeaveEvent(QDragLeaveEvent *event)
+{
+#ifndef QT_NO_DRAGANDDROP
+ Q_D(QGraphicsView);
+ if (!d->scene || !d->sceneInteractionAllowed)
+ return;
+ if (!d->lastDragDropEvent) {
+ qWarning("QGraphicsView::dragLeaveEvent: drag leave received before drag enter");
+ return;
+ }
+
+ // Generate a scene event.
+ QGraphicsSceneDragDropEvent sceneEvent(QEvent::GraphicsSceneDragLeave);
+ sceneEvent.setScenePos(d->lastDragDropEvent->scenePos());
+ sceneEvent.setScreenPos(d->lastDragDropEvent->screenPos());
+ sceneEvent.setButtons(d->lastDragDropEvent->buttons());
+ sceneEvent.setModifiers(d->lastDragDropEvent->modifiers());
+ sceneEvent.setPossibleActions(d->lastDragDropEvent->possibleActions());
+ sceneEvent.setProposedAction(d->lastDragDropEvent->proposedAction());
+ sceneEvent.setDropAction(d->lastDragDropEvent->dropAction());
+ sceneEvent.setMimeData(d->lastDragDropEvent->mimeData());
+ sceneEvent.setWidget(d->lastDragDropEvent->widget());
+ sceneEvent.setSource(d->lastDragDropEvent->source());
+ delete d->lastDragDropEvent;
+ d->lastDragDropEvent = 0;
+
+ // Send it to the scene.
+ QApplication::sendEvent(d->scene, &sceneEvent);
+
+ // Accept the originating event if the scene accepted the scene event.
+ if (sceneEvent.isAccepted())
+ event->setAccepted(true);
+#else
+ Q_UNUSED(event)
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::dragMoveEvent(QDragMoveEvent *event)
+{
+#ifndef QT_NO_DRAGANDDROP
+ Q_D(QGraphicsView);
+ if (!d->scene || !d->sceneInteractionAllowed)
+ return;
+
+ // Generate a scene event.
+ QGraphicsSceneDragDropEvent sceneEvent(QEvent::GraphicsSceneDragMove);
+ d->populateSceneDragDropEvent(&sceneEvent, event);
+
+ // Store it for later use.
+ d->storeDragDropEvent(&sceneEvent);
+
+ // Send it to the scene.
+ QApplication::sendEvent(d->scene, &sceneEvent);
+
+ // Ignore the originating event if the scene ignored the scene event.
+ event->setAccepted(sceneEvent.isAccepted());
+ if (sceneEvent.isAccepted())
+ event->setDropAction(sceneEvent.dropAction());
+#else
+ Q_UNUSED(event)
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::focusInEvent(QFocusEvent *event)
+{
+ Q_D(QGraphicsView);
+ QAbstractScrollArea::focusInEvent(event);
+ if (d->scene)
+ QApplication::sendEvent(d->scene, event);
+ // Pass focus on if the scene cannot accept focus.
+ if (!d->scene || !event->isAccepted())
+ QAbstractScrollArea::focusInEvent(event);
+}
+
+/*!
+ \reimp
+*/
+bool QGraphicsView::focusNextPrevChild(bool next)
+{
+ return QAbstractScrollArea::focusNextPrevChild(next);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::focusOutEvent(QFocusEvent *event)
+{
+ Q_D(QGraphicsView);
+ QAbstractScrollArea::focusOutEvent(event);
+ if (d->scene)
+ QApplication::sendEvent(d->scene, event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QGraphicsView);
+ if (!d->scene || !d->sceneInteractionAllowed) {
+ QAbstractScrollArea::keyPressEvent(event);
+ return;
+ }
+ QApplication::sendEvent(d->scene, event);
+ if (!event->isAccepted())
+ QAbstractScrollArea::keyPressEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QGraphicsView);
+ if (!d->scene || !d->sceneInteractionAllowed)
+ return;
+ QApplication::sendEvent(d->scene, event);
+ if (!event->isAccepted())
+ QAbstractScrollArea::keyReleaseEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ Q_D(QGraphicsView);
+ if (!d->scene || !d->sceneInteractionAllowed)
+ return;
+
+ d->storeMouseEvent(event);
+ d->mousePressViewPoint = event->pos();
+ d->mousePressScenePoint = mapToScene(d->mousePressViewPoint);
+ d->mousePressScreenPoint = event->globalPos();
+ d->lastMouseMoveScenePoint = d->mousePressScenePoint;
+ d->lastMouseMoveScreenPoint = d->mousePressScreenPoint;
+ d->mousePressButton = event->button();
+
+ QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseDoubleClick);
+ mouseEvent.setWidget(viewport());
+ mouseEvent.setButtonDownScenePos(d->mousePressButton, d->mousePressScenePoint);
+ mouseEvent.setButtonDownScreenPos(d->mousePressButton, d->mousePressScreenPoint);
+ mouseEvent.setScenePos(mapToScene(d->mousePressViewPoint));
+ mouseEvent.setScreenPos(d->mousePressScreenPoint);
+ mouseEvent.setLastScenePos(d->lastMouseMoveScenePoint);
+ mouseEvent.setLastScreenPos(d->lastMouseMoveScreenPoint);
+ mouseEvent.setButtons(event->buttons());
+ mouseEvent.setButtons(event->buttons());
+ mouseEvent.setAccepted(false);
+ mouseEvent.setButton(event->button());
+ mouseEvent.setModifiers(event->modifiers());
+ QApplication::sendEvent(d->scene, &mouseEvent);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QGraphicsView);
+
+ // Store this event for replaying, finding deltas, and for
+ // scroll-dragging; even in non-interactive mode, scroll hand dragging is
+ // allowed, so we store the event at the very top of this function.
+ d->storeMouseEvent(event);
+ d->lastMouseEvent.setAccepted(false);
+
+ if (d->sceneInteractionAllowed) {
+ // Store some of the event's button-down data.
+ d->mousePressViewPoint = event->pos();
+ d->mousePressScenePoint = mapToScene(d->mousePressViewPoint);
+ d->mousePressScreenPoint = event->globalPos();
+ d->lastMouseMoveScenePoint = d->mousePressScenePoint;
+ d->lastMouseMoveScreenPoint = d->mousePressScreenPoint;
+ d->mousePressButton = event->button();
+
+ if (d->scene) {
+ // Convert and deliver the mouse event to the scene.
+ QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMousePress);
+ mouseEvent.setWidget(viewport());
+ mouseEvent.setButtonDownScenePos(d->mousePressButton, d->mousePressScenePoint);
+ mouseEvent.setButtonDownScreenPos(d->mousePressButton, d->mousePressScreenPoint);
+ mouseEvent.setScenePos(d->mousePressScenePoint);
+ mouseEvent.setScreenPos(d->mousePressScreenPoint);
+ mouseEvent.setLastScenePos(d->lastMouseMoveScenePoint);
+ mouseEvent.setLastScreenPos(d->lastMouseMoveScreenPoint);
+ mouseEvent.setButtons(event->buttons());
+ mouseEvent.setButton(event->button());
+ mouseEvent.setModifiers(event->modifiers());
+ mouseEvent.setAccepted(false);
+ QApplication::sendEvent(d->scene, &mouseEvent);
+
+ // Update the original mouse event accepted state.
+ bool isAccepted = mouseEvent.isAccepted();
+ event->setAccepted(isAccepted);
+
+ // Update the last mouse event accepted state.
+ d->lastMouseEvent.setAccepted(isAccepted);
+
+ if (isAccepted)
+ return;
+ }
+ }
+
+#ifndef QT_NO_RUBBERBAND
+ if (d->dragMode == QGraphicsView::RubberBandDrag && !d->rubberBanding) {
+ if (d->sceneInteractionAllowed) {
+ // Rubberbanding is only allowed in interactive mode.
+ event->accept();
+ d->rubberBanding = true;
+ d->rubberBandRect = QRect();
+ if (d->scene) {
+ // Initiating a rubber band always clears the selection.
+ d->scene->clearSelection();
+ }
+ }
+ } else
+#endif
+ if (d->dragMode == QGraphicsView::ScrollHandDrag && event->button() == Qt::LeftButton) {
+ // Left-button press in scroll hand mode initiates hand scrolling.
+ event->accept();
+ d->handScrolling = true;
+ d->handScrollMotions = 0;
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor(Qt::ClosedHandCursor);
+#endif
+ }
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QGraphicsView);
+
+#ifndef QT_NO_RUBBERBAND
+ if (d->dragMode == QGraphicsView::RubberBandDrag && d->sceneInteractionAllowed) {
+ d->storeMouseEvent(event);
+ if (d->rubberBanding) {
+ // Check for enough drag distance
+ if ((d->mousePressViewPoint - event->pos()).manhattanLength()
+ < QApplication::startDragDistance()) {
+ return;
+ }
+
+ // Update old rubberband
+ if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate && !d->rubberBandRect.isNull()) {
+ if (d->viewportUpdateMode != FullViewportUpdate)
+ viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect));
+ else
+ viewport()->update();
+ }
+
+ // Stop rubber banding if the user has let go of all buttons (even
+ // if we didn't get the release events).
+ if (!event->buttons()) {
+ d->rubberBanding = false;
+ d->rubberBandRect = QRect();
+ return;
+ }
+
+ // Update rubberband position
+ const QPoint &mp = d->mousePressViewPoint;
+ QPoint ep = event->pos();
+ d->rubberBandRect = QRect(qMin(mp.x(), ep.x()), qMin(mp.y(), ep.y()),
+ qAbs(mp.x() - ep.x()) + 1, qAbs(mp.y() - ep.y()) + 1);
+
+ // Update new rubberband
+ if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate){
+ if (d->viewportUpdateMode != FullViewportUpdate)
+ viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect));
+ else
+ viewport()->update();
+ }
+ // Set the new selection area
+ QPainterPath selectionArea;
+ selectionArea.addPolygon(mapToScene(d->rubberBandRect));
+ selectionArea.closeSubpath();
+ if (d->scene)
+ d->scene->setSelectionArea(selectionArea, d->rubberBandSelectionMode);
+ return;
+ }
+ } else
+#endif // QT_NO_RUBBERBAND
+ if (d->dragMode == QGraphicsView::ScrollHandDrag) {
+ if (d->handScrolling) {
+ QScrollBar *hBar = horizontalScrollBar();
+ QScrollBar *vBar = verticalScrollBar();
+ QPoint delta = event->pos() - d->lastMouseEvent.pos();
+ hBar->setValue(hBar->value() + (isRightToLeft() ? delta.x() : -delta.x()));
+ vBar->setValue(vBar->value() - delta.y());
+
+ // Detect how much we've scrolled to disambiguate scrolling from
+ // clicking.
+ ++d->handScrollMotions;
+ }
+ }
+
+ d->mouseMoveEventHandler(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QGraphicsView);
+
+#ifndef QT_NO_RUBBERBAND
+ if (d->dragMode == QGraphicsView::RubberBandDrag && d->sceneInteractionAllowed && !event->buttons()) {
+ if (d->rubberBanding) {
+ if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate){
+ if (d->viewportUpdateMode != FullViewportUpdate)
+ viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect));
+ else
+ viewport()->update();
+ }
+ d->rubberBanding = false;
+ d->rubberBandRect = QRect();
+ }
+ } else
+#endif
+ if (d->dragMode == QGraphicsView::ScrollHandDrag) {
+#ifndef QT_NO_CURSOR
+ // Restore the open hand cursor. ### There might be items
+ // under the mouse that have a valid cursor at this time, so
+ // we could repeat the steps from mouseMoveEvent().
+ viewport()->setCursor(Qt::OpenHandCursor);
+#endif
+ d->handScrolling = false;
+
+ if (d->scene && d->sceneInteractionAllowed && !d->lastMouseEvent.isAccepted() && d->handScrollMotions <= 6) {
+ // If we've detected very little motion during the hand drag, and
+ // no item accepted the last event, we'll interpret that as a
+ // click to the scene, and reset the selection.
+ d->scene->clearSelection();
+ }
+ }
+
+ d->storeMouseEvent(event);
+
+ if (!d->sceneInteractionAllowed)
+ return;
+
+ if (!d->scene)
+ return;
+
+ QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseRelease);
+ mouseEvent.setWidget(viewport());
+ mouseEvent.setButtonDownScenePos(d->mousePressButton, d->mousePressScenePoint);
+ mouseEvent.setButtonDownScreenPos(d->mousePressButton, d->mousePressScreenPoint);
+ mouseEvent.setScenePos(mapToScene(event->pos()));
+ mouseEvent.setScreenPos(event->globalPos());
+ mouseEvent.setLastScenePos(d->lastMouseMoveScenePoint);
+ mouseEvent.setLastScreenPos(d->lastMouseMoveScreenPoint);
+ mouseEvent.setButtons(event->buttons());
+ mouseEvent.setButton(event->button());
+ mouseEvent.setModifiers(event->modifiers());
+ mouseEvent.setAccepted(false);
+ QApplication::sendEvent(d->scene, &mouseEvent);
+
+ // Update the last mouse event selected state.
+ d->lastMouseEvent.setAccepted(mouseEvent.isAccepted());
+
+#ifndef QT_NO_CURSOR
+ if (mouseEvent.isAccepted() && mouseEvent.buttons() == 0 && viewport()->testAttribute(Qt::WA_SetCursor)) {
+ // The last mouse release on the viewport will trigger clearing the cursor.
+ d->_q_unsetViewportCursor();
+ }
+#endif
+}
+
+#ifndef QT_NO_WHEELEVENT
+/*!
+ \reimp
+*/
+void QGraphicsView::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QGraphicsView);
+ if (!d->scene || !d->sceneInteractionAllowed) {
+ QAbstractScrollArea::wheelEvent(event);
+ return;
+ }
+
+ event->ignore();
+
+ QGraphicsSceneWheelEvent wheelEvent(QEvent::GraphicsSceneWheel);
+ wheelEvent.setWidget(viewport());
+ wheelEvent.setScenePos(mapToScene(event->pos()));
+ wheelEvent.setScreenPos(event->globalPos());
+ wheelEvent.setButtons(event->buttons());
+ wheelEvent.setModifiers(event->modifiers());
+ wheelEvent.setDelta(event->delta());
+ wheelEvent.setOrientation(event->orientation());
+ wheelEvent.setAccepted(false);
+ QApplication::sendEvent(d->scene, &wheelEvent);
+ event->setAccepted(wheelEvent.isAccepted());
+ if (!event->isAccepted())
+ QAbstractScrollArea::wheelEvent(event);
+}
+#endif // QT_NO_WHEELEVENT
+
+/*!
+ \reimp
+*/
+void QGraphicsView::paintEvent(QPaintEvent *event)
+{
+ Q_D(QGraphicsView);
+ if (!d->scene) {
+ QAbstractScrollArea::paintEvent(event);
+ return;
+ }
+
+ // Set up painter state protection.
+ d->scene->d_func()->painterStateProtection = !(d->optimizationFlags & DontSavePainterState);
+
+ // Determine the exposed region
+ QRegion exposedRegion = event->region();
+ if (!d->accelerateScrolling)
+ exposedRegion = viewport()->rect();
+ else if (d->viewportUpdateMode == BoundingRectViewportUpdate)
+ exposedRegion = event->rect();
+ QRectF exposedSceneRect = mapToScene(exposedRegion.boundingRect().adjusted(0, 0, 1, 1)).boundingRect();
+
+ // Set up the painter
+ QPainter painter(viewport());
+ QTransform original = painter.worldTransform();
+#ifndef QT_NO_RUBBERBAND
+ if (d->rubberBanding && !d->rubberBandRect.isNull())
+ painter.save();
+#endif
+ // Set up render hints
+ painter.setRenderHints(painter.renderHints(), false);
+ painter.setRenderHints(d->renderHints, true);
+
+ // Set up viewport transform
+ const QTransform viewTransform = viewportTransform();
+ painter.setTransform(viewTransform, true);
+
+#ifdef QGRAPHICSVIEW_DEBUG
+ QTime stopWatch;
+ stopWatch.start();
+ qDebug() << "QGraphicsView::paintEvent(" << exposedRegion << ")";
+#endif
+
+ // Find all exposed items
+ bool allItems = false;
+ QList<QGraphicsItem *> itemList = d->findItems(exposedRegion, viewTransform, &allItems);
+
+#ifdef QGRAPHICSVIEW_DEBUG
+ int exposedTime = stopWatch.elapsed();
+#endif
+
+ if ((d->cacheMode & CacheBackground)
+#ifdef Q_WS_X11
+ && X11->use_xrender
+#endif
+ ) {
+ // Recreate the background pixmap, and flag the whole background as
+ // exposed.
+ if (d->mustResizeBackgroundPixmap) {
+ d->backgroundPixmap = QPixmap(viewport()->size());
+ QBrush bgBrush = viewport()->palette().brush(viewport()->backgroundRole());
+ if (!bgBrush.isOpaque())
+ d->backgroundPixmap.fill(Qt::transparent);
+ QPainter p(&d->backgroundPixmap);
+ p.fillRect(0, 0, d->backgroundPixmap.width(), d->backgroundPixmap.height(), bgBrush);
+ d->backgroundPixmapExposed = QRegion(viewport()->rect());
+ d->mustResizeBackgroundPixmap = false;
+ }
+
+ // Redraw exposed areas
+ if (!d->backgroundPixmapExposed.isEmpty()) {
+ QPainter backgroundPainter(&d->backgroundPixmap);
+ backgroundPainter.setClipRegion(d->backgroundPixmapExposed, Qt::ReplaceClip);
+ backgroundPainter.setTransform(viewportTransform());
+ drawBackground(&backgroundPainter, exposedSceneRect);
+ d->backgroundPixmapExposed = QRegion();
+ }
+
+ // Blit the background from the background pixmap
+ QTransform oldMatrix = painter.worldTransform();
+ painter.setWorldTransform(original);
+ painter.drawPixmap(QPoint(), d->backgroundPixmap);
+ painter.setWorldTransform(oldMatrix);
+ } else {
+ if (!(d->optimizationFlags & DontSavePainterState))
+ painter.save();
+ drawBackground(&painter, exposedSceneRect);
+ if (!(d->optimizationFlags & DontSavePainterState))
+ painter.restore();
+ }
+
+#ifdef QGRAPHICSVIEW_DEBUG
+ int backgroundTime = stopWatch.elapsed() - exposedTime;
+#endif
+
+ // Generate the style options
+ QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
+ QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(itemList.size());
+
+ d->generateStyleOptions(itemList, itemArray, styleOptionArray, viewTransform,
+ allItems, exposedRegion);
+
+ // Items
+ drawItems(&painter, itemList.size(), itemArray, styleOptionArray);
+
+#ifdef QGRAPHICSVIEW_DEBUG
+ int itemsTime = stopWatch.elapsed() - exposedTime - backgroundTime;
+#endif
+
+ // Foreground
+ drawForeground(&painter, exposedSceneRect);
+
+ delete [] itemArray;
+ d->freeStyleOptionsArray(styleOptionArray);
+
+#ifdef QGRAPHICSVIEW_DEBUG
+ int foregroundTime = stopWatch.elapsed() - exposedTime - backgroundTime - itemsTime;
+#endif
+
+#ifndef QT_NO_RUBBERBAND
+ // Rubberband
+ if (d->rubberBanding && !d->rubberBandRect.isNull()) {
+ painter.restore();
+ QStyleOptionRubberBand option;
+ option.initFrom(viewport());
+ option.rect = d->rubberBandRect;
+ option.shape = QRubberBand::Rectangle;
+
+ QStyleHintReturnMask mask;
+ if (viewport()->style()->styleHint(QStyle::SH_RubberBand_Mask, &option, viewport(), &mask)) {
+ // painter clipping for masked rubberbands
+ painter.setClipRegion(mask.region, Qt::IntersectClip);
+ }
+
+ viewport()->style()->drawControl(QStyle::CE_RubberBand, &option, &painter, viewport());
+ }
+#endif
+
+ painter.end();
+
+#ifdef QGRAPHICSVIEW_DEBUG
+ qDebug() << "\tItem discovery....... " << exposedTime << "msecs (" << itemList.size() << "items,"
+ << (exposedTime > 0 ? (itemList.size() * 1000.0 / exposedTime) : -1) << "/ sec )";
+ qDebug() << "\tDrawing background... " << backgroundTime << "msecs (" << exposedRegion.numRects() << "segments )";
+ qDebug() << "\tDrawing items........ " << itemsTime << "msecs ("
+ << (itemsTime > 0 ? (itemList.size() * 1000.0 / itemsTime) : -1) << "/ sec )";
+ qDebug() << "\tDrawing foreground... " << foregroundTime << "msecs (" << exposedRegion.numRects() << "segments )";
+ qDebug() << "\tTotal rendering time: " << stopWatch.elapsed() << "msecs ("
+ << (stopWatch.elapsed() > 0 ? (1000.0 / stopWatch.elapsed()) : -1.0) << "fps )";
+#endif
+
+ // Restore painter state protection.
+ d->scene->d_func()->painterStateProtection = true;
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::resizeEvent(QResizeEvent *event)
+{
+ Q_D(QGraphicsView);
+ // Save the last center point - the resize may scroll the view, which
+ // changes the center point.
+ QPointF oldLastCenterPoint = d->lastCenterPoint;
+
+ QAbstractScrollArea::resizeEvent(event);
+ d->recalculateContentSize();
+
+ // Restore the center point again.
+ if (d->resizeAnchor == NoAnchor && !d->keepLastCenterPoint) {
+ d->updateLastCenterPoint();
+ } else {
+ d->lastCenterPoint = oldLastCenterPoint;
+ }
+ d->centerView(d->resizeAnchor);
+ d->keepLastCenterPoint = false;
+
+ if (d->cacheMode & CacheBackground) {
+ // Invalidate the background pixmap
+ d->mustResizeBackgroundPixmap = true;
+ }
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::scrollContentsBy(int dx, int dy)
+{
+ Q_D(QGraphicsView);
+ d->dirtyScroll = true;
+ if (d->transforming)
+ return;
+ if (isRightToLeft())
+ dx = -dx;
+
+ if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate
+ && d->viewportUpdateMode != QGraphicsView::FullViewportUpdate) {
+ for (int i = 0; i < d->dirtyRects.size(); ++i)
+ d->dirtyRects[i].translate(dx, dy);
+ for (int i = 0; i < d->dirtyRegions.size(); ++i)
+ d->dirtyRegions[i].translate(dx, dy);
+ }
+
+#ifndef QT_NO_RUBBERBAND
+ // Update old rubberband
+ if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate && !d->rubberBandRect.isNull()) {
+ if (d->viewportUpdateMode != FullViewportUpdate)
+ viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect));
+ else
+ viewport()->update();
+ }
+#endif
+
+ if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate){
+ if (d->accelerateScrolling && d->viewportUpdateMode != FullViewportUpdate)
+ viewport()->scroll(dx, dy);
+ else
+ viewport()->update();
+ }
+ d->updateLastCenterPoint();
+
+ if ((d->cacheMode & CacheBackground)
+#ifdef Q_WS_X11
+ && X11->use_xrender
+#endif
+ ) {
+ // Invalidate the background pixmap
+ d->backgroundPixmapExposed.translate(dx, 0);
+ if (dx > 0) {
+ d->backgroundPixmapExposed += QRect(0, 0, dx, viewport()->height());
+ } else if (dx < 0) {
+ d->backgroundPixmapExposed += QRect(viewport()->width() + dx, 0,
+ -dx, viewport()->height());
+ }
+ d->backgroundPixmapExposed.translate(0, dy);
+ if (dy > 0) {
+ d->backgroundPixmapExposed += QRect(0, 0, viewport()->width(), dy);
+ } else if (dy < 0) {
+ d->backgroundPixmapExposed += QRect(0, viewport()->height() + dy,
+ viewport()->width(), -dy);
+ }
+
+ // Scroll the background pixmap
+ if (!d->backgroundPixmap.isNull()) {
+ QPixmap tmp = d->backgroundPixmap.copy();
+ QBrush bgBrush = viewport()->palette().brush(viewport()->backgroundRole());
+ if (!bgBrush.isOpaque())
+ d->backgroundPixmap.fill(Qt::transparent);
+ QPainter painter(&d->backgroundPixmap);
+ painter.drawPixmap(dx, dy, tmp);
+ }
+ }
+
+ // Always replay on scroll.
+ if (d->sceneInteractionAllowed)
+ d->replayLastMouseEvent();
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::showEvent(QShowEvent *event)
+{
+ Q_D(QGraphicsView);
+ d->recalculateContentSize();
+ d->centerView(d->transformationAnchor);
+ QAbstractScrollArea::showEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsView::inputMethodEvent(QInputMethodEvent *event)
+{
+ Q_D(QGraphicsView);
+ if (d->scene)
+ QApplication::sendEvent(d->scene, event);
+}
+
+/*!
+ Draws the background of the scene using \a painter, before any items and
+ the foreground are drawn. Reimplement this function to provide a custom
+ background for this view.
+
+ If all you want is to define a color, texture or gradient for the
+ background, you can call setBackgroundBrush() instead.
+
+ All painting is done in \e scene coordinates. \a rect is the exposed
+ rectangle.
+
+ The default implementation fills \a rect using the view's backgroundBrush.
+ If no such brush is defined (the default), the scene's drawBackground()
+ function is called instead.
+
+ \sa drawForeground(), QGraphicsScene::drawBackground()
+*/
+void QGraphicsView::drawBackground(QPainter *painter, const QRectF &rect)
+{
+ Q_D(QGraphicsView);
+ if (d->scene && d->backgroundBrush.style() == Qt::NoBrush) {
+ d->scene->drawBackground(painter, rect);
+ return;
+ }
+
+ painter->fillRect(rect, d->backgroundBrush);
+}
+
+/*!
+ Draws the foreground of the scene using \a painter, after the background
+ and all items are drawn. Reimplement this function to provide a custom
+ foreground for this view.
+
+ If all you want is to define a color, texture or gradient for the
+ foreground, you can call setForegroundBrush() instead.
+
+ All painting is done in \e scene coordinates. \a rect is the exposed
+ rectangle.
+
+ The default implementation fills \a rect using the view's foregroundBrush.
+ If no such brush is defined (the default), the scene's drawForeground()
+ function is called instead.
+
+ \sa drawBackground(), QGraphicsScene::drawForeground()
+*/
+void QGraphicsView::drawForeground(QPainter *painter, const QRectF &rect)
+{
+ Q_D(QGraphicsView);
+ if (d->scene && d->foregroundBrush.style() == Qt::NoBrush) {
+ d->scene->drawForeground(painter, rect);
+ return;
+ }
+
+ painter->fillRect(rect, d->foregroundBrush);
+}
+
+/*!
+ Draws the items \a items in the scene using \a painter, after the
+ background and before the foreground are drawn. \a numItems is the number
+ of items in \a items and options in \a options. \a options is a list of
+ styleoptions; one for each item. Reimplement this function to provide
+ custom item drawing for this view.
+
+ The default implementation calls the scene's drawItems() function.
+
+ \sa drawForeground(), drawBackground(), QGraphicsScene::drawItems()
+*/
+void QGraphicsView::drawItems(QPainter *painter, int numItems,
+ QGraphicsItem *items[],
+ const QStyleOptionGraphicsItem options[])
+{
+ Q_D(QGraphicsView);
+ if (d->scene)
+ d->scene->drawItems(painter, numItems, items, options, viewport());
+}
+
+/*!
+ Returns the current transformation matrix for the view. If no current
+ transformation is set, the identity matrix is returned.
+
+ \sa setTransform(), rotate(), scale(), shear(), translate()
+*/
+QTransform QGraphicsView::transform() const
+{
+ Q_D(const QGraphicsView);
+ return d->matrix;
+}
+
+/*!
+ Returns a matrix that maps viewport coordinates to scene coordinates.
+
+ \sa mapToScene(), mapFromScene()
+*/
+QTransform QGraphicsView::viewportTransform() const
+{
+ Q_D(const QGraphicsView);
+ QTransform moveMatrix;
+ moveMatrix.translate(-d->horizontalScroll(), -d->verticalScroll());
+ return d->identityMatrix ? moveMatrix : d->matrix * moveMatrix;
+}
+
+/*!
+ Sets the view'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.
+
+ The transformation matrix tranforms the scene into view coordinates. Using
+ the default transformation, provided by the identity matrix, one pixel in
+ the view represents one unit in the scene (e.g., a 10x10 rectangular item
+ is drawn using 10x10 pixels in the view). If a 2x2 scaling matrix is
+ applied, the scene will be drawn in 1:2 (e.g., a 10x10 rectangular item is
+ then drawn using 20x20 pixels in the view).
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 7
+
+ To simplify interation with items using a transformed view, QGraphicsView
+ provides mapTo... and mapFrom... functions that can translate between
+ scene and view coordinates. For example, you can call mapToScene() to map
+ a view coordiate to a floating point scene coordinate, or mapFromScene()
+ to map from floating point scene coordinates to view coordinates.
+
+ \sa transform(), rotate(), scale(), shear(), translate()
+*/
+void QGraphicsView::setTransform(const QTransform &matrix, bool combine )
+{
+ Q_D(QGraphicsView);
+ QTransform oldMatrix = d->matrix;
+ if (!combine)
+ d->matrix = matrix;
+ else
+ d->matrix = matrix * d->matrix;
+ if (oldMatrix == d->matrix)
+ return;
+
+ d->identityMatrix = d->matrix.isIdentity();
+ d->transforming = true;
+ if (d->scene) {
+ d->recalculateContentSize();
+ d->centerView(d->transformationAnchor);
+ } else {
+ d->updateLastCenterPoint();
+ }
+
+ if (d->sceneInteractionAllowed)
+ d->replayLastMouseEvent();
+ d->transforming = false;
+
+ // Any matrix operation requires a full update.
+ viewport()->update();
+}
+
+/*!
+ Resets the view transformation to the identity matrix.
+
+ \sa transform(), setTransform()
+*/
+void QGraphicsView::resetTransform()
+{
+ setTransform(QTransform());
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qgraphicsview.cpp"
+
+#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicsview.h b/src/gui/graphicsview/qgraphicsview.h
new file mode 100644
index 0000000..e77e45c
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsview.h
@@ -0,0 +1,314 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSVIEW_H
+#define QGRAPHICSVIEW_H
+
+#include <QtCore/qmetatype.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qscrollarea.h>
+#include <QtGui/qgraphicsscene.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+class QGraphicsItem;
+class QPainterPath;
+class QPolygonF;
+class QStyleOptionGraphicsItem;
+
+class QGraphicsViewPrivate;
+class Q_GUI_EXPORT QGraphicsView : public QAbstractScrollArea
+{
+ Q_OBJECT
+ Q_FLAGS(QPainter::RenderHints CacheMode OptimizationFlags)
+ Q_ENUMS(ViewportAnchor DragMode ViewportUpdateMode)
+ Q_PROPERTY(QBrush backgroundBrush READ backgroundBrush WRITE setBackgroundBrush)
+ Q_PROPERTY(QBrush foregroundBrush READ foregroundBrush WRITE setForegroundBrush)
+ Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive)
+ Q_PROPERTY(QRectF sceneRect READ sceneRect WRITE setSceneRect)
+ Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment)
+ Q_PROPERTY(QPainter::RenderHints renderHints READ renderHints WRITE setRenderHints)
+ Q_PROPERTY(DragMode dragMode READ dragMode WRITE setDragMode)
+ Q_PROPERTY(CacheMode cacheMode READ cacheMode WRITE setCacheMode)
+ Q_PROPERTY(ViewportAnchor transformationAnchor READ transformationAnchor WRITE setTransformationAnchor)
+ Q_PROPERTY(ViewportAnchor resizeAnchor READ resizeAnchor WRITE setResizeAnchor)
+ Q_PROPERTY(ViewportUpdateMode viewportUpdateMode READ viewportUpdateMode WRITE setViewportUpdateMode)
+#ifndef QT_NO_RUBBERBAND
+ Q_PROPERTY(Qt::ItemSelectionMode rubberBandSelectionMode READ rubberBandSelectionMode WRITE setRubberBandSelectionMode)
+#endif
+ Q_PROPERTY(OptimizationFlags optimizationFlags READ optimizationFlags WRITE setOptimizationFlags)
+
+public:
+ enum ViewportAnchor {
+ NoAnchor,
+ AnchorViewCenter,
+ AnchorUnderMouse
+ };
+
+ enum CacheModeFlag {
+ CacheNone = 0x0,
+ CacheBackground = 0x1
+ };
+ Q_DECLARE_FLAGS(CacheMode, CacheModeFlag)
+
+ enum DragMode {
+ NoDrag,
+ ScrollHandDrag,
+ RubberBandDrag
+ };
+
+ enum ViewportUpdateMode {
+ FullViewportUpdate,
+ MinimalViewportUpdate,
+ SmartViewportUpdate,
+ NoViewportUpdate,
+ BoundingRectViewportUpdate
+ };
+
+ enum OptimizationFlag {
+ DontClipPainter = 0x1,
+ DontSavePainterState = 0x2,
+ DontAdjustForAntialiasing = 0x4
+ };
+ Q_DECLARE_FLAGS(OptimizationFlags, OptimizationFlag)
+
+ QGraphicsView(QWidget *parent = 0);
+ QGraphicsView(QGraphicsScene *scene, QWidget *parent = 0);
+ ~QGraphicsView();
+
+ QSize sizeHint() const;
+
+ QPainter::RenderHints renderHints() const;
+ void setRenderHint(QPainter::RenderHint hint, bool enabled = true);
+ void setRenderHints(QPainter::RenderHints hints);
+
+ Qt::Alignment alignment() const;
+ void setAlignment(Qt::Alignment alignment);
+
+ ViewportAnchor transformationAnchor() const;
+ void setTransformationAnchor(ViewportAnchor anchor);
+
+ ViewportAnchor resizeAnchor() const;
+ void setResizeAnchor(ViewportAnchor anchor);
+
+ ViewportUpdateMode viewportUpdateMode() const;
+ void setViewportUpdateMode(ViewportUpdateMode mode);
+
+ OptimizationFlags optimizationFlags() const;
+ void setOptimizationFlag(OptimizationFlag flag, bool enabled = true);
+ void setOptimizationFlags(OptimizationFlags flags);
+
+ DragMode dragMode() const;
+ void setDragMode(DragMode mode);
+
+#ifndef QT_NO_RUBBERBAND
+ Qt::ItemSelectionMode rubberBandSelectionMode() const;
+ void setRubberBandSelectionMode(Qt::ItemSelectionMode mode);
+#endif
+
+ CacheMode cacheMode() const;
+ void setCacheMode(CacheMode mode);
+ void resetCachedContent();
+
+ bool isInteractive() const;
+ void setInteractive(bool allowed);
+
+ QGraphicsScene *scene() const;
+ void setScene(QGraphicsScene *scene);
+
+ QRectF sceneRect() const;
+ void setSceneRect(const QRectF &rect);
+ inline void setSceneRect(qreal x, qreal y, qreal w, qreal h);
+
+ QMatrix matrix() const;
+ void setMatrix(const QMatrix &matrix, bool combine = false);
+ void resetMatrix();
+ QTransform transform() const;
+ QTransform viewportTransform() const;
+ void setTransform(const QTransform &matrix, bool combine = false);
+ void resetTransform();
+ void rotate(qreal angle);
+ void scale(qreal sx, qreal sy);
+ void shear(qreal sh, qreal sv);
+ void translate(qreal dx, qreal dy);
+
+ void centerOn(const QPointF &pos);
+ inline void centerOn(qreal x, qreal y);
+ void centerOn(const QGraphicsItem *item);
+ void ensureVisible(const QRectF &rect, int xmargin = 50, int ymargin = 50);
+ inline void ensureVisible(qreal x, qreal y, qreal w, qreal h, int xmargin = 50, int ymargin = 50);
+ void ensureVisible(const QGraphicsItem *item, int xmargin = 50, int ymargin = 50);
+ void fitInView(const QRectF &rect, Qt::AspectRatioMode aspectRadioMode = Qt::IgnoreAspectRatio);
+ inline void fitInView(qreal x, qreal y, qreal w, qreal h,
+ Qt::AspectRatioMode aspectRadioMode = Qt::IgnoreAspectRatio);
+ void fitInView(const QGraphicsItem *item,
+ Qt::AspectRatioMode aspectRadioMode = Qt::IgnoreAspectRatio);
+
+ void render(QPainter *painter, const QRectF &target = QRectF(), const QRect &source = QRect(),
+ Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio);
+
+ QList<QGraphicsItem *> items() const;
+ QList<QGraphicsItem *> items(const QPoint &pos) const;
+ inline QList<QGraphicsItem *> items(int x, int y) const;
+ QList<QGraphicsItem *> items(const QRect &rect, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ inline QList<QGraphicsItem *> items(int x, int y, int w, int h, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ QList<QGraphicsItem *> items(const QPolygon &polygon, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ QList<QGraphicsItem *> items(const QPainterPath &path, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ QGraphicsItem *itemAt(const QPoint &pos) const;
+ inline QGraphicsItem *itemAt(int x, int y) const;
+
+ QPointF mapToScene(const QPoint &point) const;
+ QPolygonF mapToScene(const QRect &rect) const;
+ QPolygonF mapToScene(const QPolygon &polygon) const;
+ QPainterPath mapToScene(const QPainterPath &path) const;
+ QPoint mapFromScene(const QPointF &point) const;
+ QPolygon mapFromScene(const QRectF &rect) const;
+ QPolygon mapFromScene(const QPolygonF &polygon) const;
+ QPainterPath mapFromScene(const QPainterPath &path) const;
+ inline QPointF mapToScene(int x, int y) const;
+ inline QPolygonF mapToScene(int x, int y, int w, int h) const;
+ inline QPoint mapFromScene(qreal x, qreal y) const;
+ inline QPolygon mapFromScene(qreal x, qreal y, qreal w, qreal h) const;
+
+ QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+
+ QBrush backgroundBrush() const;
+ void setBackgroundBrush(const QBrush &brush);
+
+ QBrush foregroundBrush() const;
+ void setForegroundBrush(const QBrush &brush);
+
+public Q_SLOTS:
+ void updateScene(const QList<QRectF> &rects);
+ void invalidateScene(const QRectF &rect = QRectF(), QGraphicsScene::SceneLayers layers = QGraphicsScene::AllLayers);
+ void updateSceneRect(const QRectF &rect);
+
+protected Q_SLOTS:
+ void setupViewport(QWidget *widget);
+
+protected:
+ QGraphicsView(QGraphicsViewPrivate &, QWidget *parent = 0);
+ bool event(QEvent *event);
+ bool viewportEvent(QEvent *event);
+
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuEvent(QContextMenuEvent *event);
+#endif
+ void dragEnterEvent(QDragEnterEvent *event);
+ void dragLeaveEvent(QDragLeaveEvent *event);
+ void dragMoveEvent(QDragMoveEvent *event);
+ void dropEvent(QDropEvent *event);
+ void focusInEvent(QFocusEvent *event);
+ bool focusNextPrevChild(bool next);
+ void focusOutEvent(QFocusEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *event);
+ void mouseDoubleClickEvent(QMouseEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent(QWheelEvent *event);
+#endif
+ void paintEvent(QPaintEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ void scrollContentsBy(int dx, int dy);
+ void showEvent(QShowEvent *event);
+ void inputMethodEvent(QInputMethodEvent *event);
+
+ virtual void drawBackground(QPainter *painter, const QRectF &rect);
+ virtual void drawForeground(QPainter *painter, const QRectF &rect);
+ virtual void drawItems(QPainter *painter, int numItems,
+ QGraphicsItem *items[],
+ const QStyleOptionGraphicsItem options[]);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsView)
+ Q_DISABLE_COPY(QGraphicsView)
+#ifndef QT_NO_CURSOR
+ Q_PRIVATE_SLOT(d_func(), void _q_setViewportCursor(const QCursor &))
+ Q_PRIVATE_SLOT(d_func(), void _q_unsetViewportCursor())
+#endif
+ Q_PRIVATE_SLOT(d_func(), void _q_updateLaterSlot())
+ friend class QGraphicsSceneWidget;
+ friend class QGraphicsScene;
+ friend class QGraphicsScenePrivate;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsView::CacheMode)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsView::OptimizationFlags)
+
+inline void QGraphicsView::setSceneRect(qreal ax, qreal ay, qreal aw, qreal ah)
+{ setSceneRect(QRectF(ax, ay, aw, ah)); }
+inline void QGraphicsView::centerOn(qreal ax, qreal ay)
+{ centerOn(QPointF(ax, ay)); }
+inline void QGraphicsView::ensureVisible(qreal ax, qreal ay, qreal aw, qreal ah, int xmargin, int ymargin)
+{ ensureVisible(QRectF(ax, ay, aw, ah), xmargin, ymargin); }
+inline void QGraphicsView::fitInView(qreal ax, qreal ay, qreal w, qreal h, Qt::AspectRatioMode mode)
+{ fitInView(QRectF(ax, ay, w, h), mode); }
+inline QList<QGraphicsItem *> QGraphicsView::items(int ax, int ay) const
+{ return items(QPoint(ax, ay)); }
+inline QList<QGraphicsItem *> QGraphicsView::items(int ax, int ay, int w, int h, Qt::ItemSelectionMode mode) const
+{ return items(QRect(ax, ay, w, h), mode); }
+inline QGraphicsItem *QGraphicsView::itemAt(int ax, int ay) const
+{ return itemAt(QPoint(ax, ay)); }
+inline QPointF QGraphicsView::mapToScene(int ax, int ay) const
+{ return mapToScene(QPoint(ax, ay)); }
+inline QPolygonF QGraphicsView::mapToScene(int ax, int ay, int w, int h) const
+{ return mapToScene(QRect(ax, ay, w, h)); }
+inline QPoint QGraphicsView::mapFromScene(qreal ax, qreal ay) const
+{ return mapFromScene(QPointF(ax, ay)); }
+inline QPolygon QGraphicsView::mapFromScene(qreal ax, qreal ay, qreal w, qreal h) const
+{ return mapFromScene(QRectF(ax, ay, w, h)); }
+
+#endif // QT_NO_GRAPHICSVIEW
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGRAPHICSVIEW_H
diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h
new file mode 100644
index 0000000..2109673
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsview_p.h
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSVIEW_P_H
+#define QGRAPHICSVIEW_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qgraphicsview.h"
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+#include <QtGui/qevent.h>
+#include "qgraphicssceneevent.h"
+#include <private/qabstractscrollarea_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_GUI_EXPORT QGraphicsViewPrivate : public QAbstractScrollAreaPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsView)
+public:
+ QGraphicsViewPrivate();
+
+ void recalculateContentSize();
+ void centerView(QGraphicsView::ViewportAnchor anchor);
+
+ QPainter::RenderHints renderHints;
+
+ QGraphicsView::DragMode dragMode;
+ bool sceneInteractionAllowed;
+ QRectF sceneRect;
+ bool hasSceneRect;
+ void updateLastCenterPoint();
+ bool connectedToScene;
+
+ qint64 horizontalScroll() const;
+ qint64 verticalScroll() const;
+
+ QList<QGraphicsItem *> itemsInArea(const QPainterPath &path,
+ Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+
+ QPointF mousePressItemPoint;
+ QPointF mousePressScenePoint;
+ QPoint mousePressViewPoint;
+ QPoint mousePressScreenPoint;
+ QPointF lastMouseMoveScenePoint;
+ QPoint lastMouseMoveScreenPoint;
+ Qt::MouseButton mousePressButton;
+ QTransform matrix;
+ bool identityMatrix;
+ qint64 scrollX, scrollY;
+ bool dirtyScroll;
+ void updateScroll();
+
+ bool accelerateScrolling;
+ qreal leftIndent;
+ qreal topIndent;
+
+ // Replaying mouse events
+ QMouseEvent lastMouseEvent;
+ bool useLastMouseEvent;
+ void replayLastMouseEvent();
+ void storeMouseEvent(QMouseEvent *event);
+ void mouseMoveEventHandler(QMouseEvent *event);
+
+ QPointF lastCenterPoint;
+ bool keepLastCenterPoint;
+ Qt::Alignment alignment;
+ bool transforming;
+
+ QGraphicsView::ViewportAnchor transformationAnchor;
+ QGraphicsView::ViewportAnchor resizeAnchor;
+ QGraphicsView::ViewportUpdateMode viewportUpdateMode;
+ QGraphicsView::OptimizationFlags optimizationFlags;
+
+ QPointer<QGraphicsScene> scene;
+#ifndef QT_NO_RUBBERBAND
+ QRect rubberBandRect;
+ QRegion rubberBandRegion(const QWidget *widget, const QRect &rect) const;
+ bool rubberBanding;
+ Qt::ItemSelectionMode rubberBandSelectionMode;
+#endif
+ bool handScrolling;
+ int handScrollMotions;
+
+ QGraphicsView::CacheMode cacheMode;
+
+ QVector<QStyleOptionGraphicsItem> styleOptions;
+ bool mustAllocateStyleOptions;
+ QStyleOptionGraphicsItem *allocStyleOptionsArray(int numItems);
+ void freeStyleOptionsArray(QStyleOptionGraphicsItem *array);
+
+ QBrush backgroundBrush;
+ QBrush foregroundBrush;
+ QPixmap backgroundPixmap;
+ bool mustResizeBackgroundPixmap;
+ QRegion backgroundPixmapExposed;
+
+#ifndef QT_NO_CURSOR
+ QCursor originalCursor;
+ bool hasStoredOriginalCursor;
+ void _q_setViewportCursor(const QCursor &cursor);
+ void _q_unsetViewportCursor();
+#endif
+
+ QGraphicsSceneDragDropEvent *lastDragDropEvent;
+ void storeDragDropEvent(const QGraphicsSceneDragDropEvent *event);
+ void populateSceneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
+ QDropEvent *source);
+
+ QRect mapToViewRect(const QGraphicsItem *item, const QRectF &rect) const;
+ QRegion mapToViewRegion(const QGraphicsItem *item, const QRectF &rect) const;
+ void itemUpdated(QGraphicsItem *item, const QRectF &rect);
+ bool fullUpdatePending;
+ QList<QRect> dirtyRects;
+ QList<QRegion> dirtyRegions;
+ int dirtyRectCount;
+ QRect dirtyBoundingRect;
+ void updateLater();
+ bool updatingLater;
+ void _q_updateLaterSlot();
+ void updateAll();
+ void updateRect(const QRect &rect);
+ void updateRegion(const QRegion &region);
+ bool updateSceneSlotReimplementedChecked;
+
+ QList<QGraphicsItem *> findItems(const QRegion &exposedRegion,
+ const QTransform &worldTransform,
+ bool *allItems) const;
+
+ void generateStyleOptions(const QList<QGraphicsItem *> &itemList,
+ QGraphicsItem **itemArray,
+ QStyleOptionGraphicsItem *styleOptionArray,
+ const QTransform &worldTransform,
+ bool allItems,
+ const QRegion &exposedRegion) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_GRAPHICSVIEW
+
+#endif
diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp
new file mode 100644
index 0000000..5cc18f9
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicswidget.cpp
@@ -0,0 +1,2273 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include "qgraphicswidget.h"
+#include "qgraphicswidget_p.h"
+#include "qgraphicslayout.h"
+#include "qgraphicslayout_p.h"
+#include "qgraphicsscene.h"
+#include "qgraphicssceneevent.h"
+
+#ifndef QT_NO_ACTION
+#include <private/qaction_p.h>
+#endif
+#include <private/qapplication_p.h>
+#include <private/qgraphicsscene_p.h>
+#ifndef QT_NO_SHORTCUT
+#include <private/qshortcutmap_p.h>
+#endif
+#include <QtCore/qmutex.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qgraphicsview.h>
+#include <QtGui/qgraphicsproxywidget.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/qstyleoption.h>
+
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGraphicsWidget
+ \brief The QGraphicsWidget class is the base class for all widget
+ items in a QGraphicsScene.
+ \since 4.4
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ QGraphicsWidget is an extended base item that provides extra functionality
+ over QGraphicsItem. It is similar to QWidget in many ways:
+
+ \list
+ \o Provides a \l palette, a \l font and a \l style().
+ \o Has a defined geometry().
+ \o Supports layouts with setLayout() and layout().
+ \o Supports shortcuts and actions with grabShortcut() and insertAction()
+ \endlist
+
+ Unlike QGraphicsItem, QGraphicsWidget is not an abstract class; you can
+ create instances of a QGraphicsWidget without having to subclass it.
+ This approach is useful for widgets that only serve the purpose of
+ organizing child widgets into a layout.
+
+ QGraphicsWidget can be used as a base item for your own custom item if
+ you require advanced input focus handling, e.g., tab focus and activation, or
+ layouts.
+
+ Since QGraphicsWidget resembles QWidget and has similar API, it is
+ easier to port a widget from QWidget to QGraphicsWidget, instead of
+ QGraphicsItem.
+
+ \note QWidget-based widgets can be directly embedded into a
+ QGraphicsScene using QGraphicsProxyWidget.
+
+ Noticeable differences between QGraphicsWidget and QWidget are:
+
+ \table
+ \header \o QGraphicsWidget
+ \o QWidget
+ \row \o Coordinates and geometry are defined with qreals (doubles or
+ floats, depending on the platform).
+ \o QWidget uses integer geometry (QPoint, QRect).
+ \row \o The widget is already visible by default; you do not have to
+ call show() to display the widget.
+ \o QWidget is hidden by default until you call show().
+ \row \o A subset of widget attributes are supported.
+ \o All widget attributes are supported.
+ \row \o A top-level item's style defaults to QGraphicsScene::style
+ \o A top-level widget's style defaults to QApplication::style
+ \row \o Graphics View provides a custom drag and drop framework, different
+ from QWidget.
+ \o Standard drag and drop framework.
+ \row \o Widget items do not support modality.
+ \o Full modality support.
+ \endtable
+
+ QGraphicsWidget supports a subset of Qt's widget attributes,
+ (Qt::WidgetAttribute), as shown in the table below. Any attributes not
+ listed in this table are unsupported, or otherwise unused.
+
+ \table
+ \header \o Widget Attribute \o Usage
+ \row \o Qt::WA_SetLayoutDirection
+ \o Set by setLayoutDirection(), cleared by
+ unsetLayoutDirection(). You can test this attribute to
+ check if the widget has been explicitly assigned a
+ \l{QGraphicsWidget::layoutDirection()}
+ {layoutDirection}. If the attribute is not set, the
+ \l{QGraphicsWidget::layoutDirection()}
+ {layoutDirection()} is inherited.
+ \row \o Qt::WA_RightToLeft
+ \o Toggled by setLayoutDirection(). Inherited from the
+ parent/scene. If set, the widget's layout will order
+ horizontally arranged widgets from right to left.
+ \row \o Qt::WA_SetStyle
+ \o Set and cleared by setStyle(). If this attribute is
+ set, the widget has been explicitly assigned a style.
+ If it is unset, the widget will use the scene's or the
+ application's style.
+ \row \o Qt::WA_Resized
+ \o Set by setGeometry() and resize().
+ \row \o Qt::WA_SetPalette
+ \o Set by setPalette().
+ \row \o Qt::WA_SetFont
+ \o Set by setPalette().
+ \row \o Qt::WA_WindowPropagation
+ \o Enables propagation to window widgets.
+ \endtable
+
+ Although QGraphicsWidget 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. These functions
+ control the stacking order of items as well as their ownership.
+
+ \note The QObject::parent() should always return 0 for QGraphicsWidgets,
+ but this policy is not strictly defined.
+
+ \sa QGraphicsProxyWidget, QGraphicsItem, {Widgets and Layouts}
+*/
+
+/*!
+ \property QGraphicsWidget::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()
+*/
+
+/*!
+ \property QGraphicsWidget::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(), show(),
+ hide()
+*/
+
+/*!
+ \property QGraphicsWidget::opacity
+ \brief the opacity of the widget
+*/
+
+/*!
+ \property QGraphicsWidget::pos
+ \brief the position of the widget
+*/
+
+/*!
+ Constructs a QGraphicsWidget instance. The optional \a parent argument is
+ passed to QGraphicsItem's constructor. The optional \a wFlags argument
+ specifies the widget's window flags (e.g., whether the widget should be a
+ window, a tool, a popup, etc).
+*/
+QGraphicsWidget::QGraphicsWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags)
+ : QGraphicsItem(*new QGraphicsWidgetPrivate, 0, 0), QGraphicsLayoutItem(0, false)
+{
+ Q_D(QGraphicsWidget);
+ d->init(parent, wFlags);
+}
+
+/*!
+ \internal
+
+ Constructs a new QGraphicsWidget, using \a dd as parent.
+*/
+QGraphicsWidget::QGraphicsWidget(QGraphicsWidgetPrivate &dd, QGraphicsItem *parent, QGraphicsScene *scene, Qt::WindowFlags wFlags)
+ : QGraphicsItem(dd, 0, scene), QGraphicsLayoutItem(0, false)
+{
+ Q_D(QGraphicsWidget);
+ d->init(parent, wFlags);
+}
+
+/*
+ \internal
+ \class QGraphicsWidgetStyles
+
+ We use this thread-safe class to maintain a hash of styles for widgets
+ styles. Note that QApplication::style() itself isn't thread-safe, QStyle
+ isn't thread-safe, and we don't have a thread-safe factory for creating
+ the default style, nor cloning a style.
+*/
+class QGraphicsWidgetStyles
+{
+public:
+ QStyle *styleForWidget(const QGraphicsWidget *widget) const
+ {
+ QMutexLocker locker(&mutex);
+ return styles.value(widget, 0);
+ }
+
+ void setStyleForWidget(QGraphicsWidget *widget, QStyle *style)
+ {
+ QMutexLocker locker(&mutex);
+ if (style)
+ styles[widget] = style;
+ else
+ styles.remove(widget);
+ }
+
+private:
+ QMap<const QGraphicsWidget *, QStyle *> styles;
+ mutable QMutex mutex;
+};
+Q_GLOBAL_STATIC(QGraphicsWidgetStyles, widgetStyles)
+
+/*!
+ Destroys the QGraphicsWidget instance.
+*/
+QGraphicsWidget::~QGraphicsWidget()
+{
+ Q_D(QGraphicsWidget);
+#ifndef QT_NO_ACTION
+ // Remove all actions from this widget
+ for (int i = 0; i < d->actions.size(); ++i) {
+ QActionPrivate *apriv = d->actions.at(i)->d_func();
+ apriv->graphicsWidgets.removeAll(this);
+ }
+ d->actions.clear();
+#endif
+
+ if (QGraphicsScene *scn = scene()) {
+ QGraphicsScenePrivate *sceneD = scn->d_func();
+ if (sceneD->tabFocusFirst == this)
+ sceneD->tabFocusFirst = (d->focusNext == this ? 0 : d->focusNext);
+ }
+ d->focusPrev->d_func()->focusNext = d->focusNext;
+ d->focusNext->d_func()->focusPrev = d->focusPrev;
+
+ // Play it really safe
+ d->focusNext = this;
+ d->focusPrev = this;
+
+ clearFocus();
+
+ //we check if we have a layout previously
+ if (d->layout) {
+ delete d->layout;
+ foreach (QGraphicsItem * item, childItems()) {
+ // In case of a custom layout which doesn't remove and delete items, we ensure that
+ // the parent layout item does not point to the deleted layout. This code is here to
+ // avoid regression from 4.4 to 4.5, because according to 4.5 docs it is not really needed.
+ if (item->isWidget()) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
+ if (widget->parentLayoutItem() == d->layout)
+ widget->setParentLayoutItem(0);
+ }
+ }
+ }
+
+ // Remove this graphics widget from widgetStyles
+ widgetStyles()->setStyleForWidget(this, 0);
+}
+
+/*!
+ \property QGraphicsWidget::size
+ \brief the size of the widget
+
+ Calling resize() resizes the widget to a \a size bounded by minimumSize()
+ and maximumSize(). This property only affects the widget's width and
+ height (e.g., its right and bottom edges); the widget's position and
+ top-left corner remains unaffected.
+
+ Resizing a widget triggers the widget to immediately receive a
+ \l{QEvent::GraphicsSceneResize}{GraphicsSceneResize} event with the
+ widget's old and new size. If the widget has a layout assigned when this
+ event arrives, the layout will be activated and it will automatically
+ update any child widgets's geometry.
+
+ This property does not affect any layout of the parent widget. If the
+ widget itself is managed by a parent layout; e.g., it has a parent widget
+ with a layout assigned, that layout will not activate.
+
+ By default, this property contains a size with zero width and height.
+
+ \sa setGeometry(), QGraphicsSceneResizeEvent, QGraphicsLayout
+*/
+QSizeF QGraphicsWidget::size() const
+{
+ return QGraphicsLayoutItem::geometry().size();
+}
+
+void QGraphicsWidget::resize(const QSizeF &size)
+{
+ setGeometry(QRectF(pos(), size));
+}
+
+/*!
+ \fn void QGraphicsWidget::resize(qreal w, qreal h)
+
+ This convenience function is equivalent to calling resize(QSizeF(w, h)).
+
+ \sa setGeometry(), setTransform()
+*/
+
+/*!
+ \property QGraphicsWidget::geometry
+ \brief the geometry of the widget
+
+ Sets the item's geometry to \a rect. The item's position and size are
+ modified as a result of calling this function. The item is first moved,
+ then resized.
+
+ A side effect of calling this function is that the widget will receive
+ a move event and a resize event. Also, if the widget has a layout
+ assigned, the layout will activate.
+
+ \sa geometry(), resize()
+*/
+void QGraphicsWidget::setGeometry(const QRectF &rect)
+{
+ QGraphicsWidgetPrivate *wd = QGraphicsWidget::d_func();
+ const QGraphicsLayoutItemPrivate *d = QGraphicsLayoutItem::d_ptr;
+ setAttribute(Qt::WA_Resized);
+ QRectF newGeom = rect;
+ newGeom.setSize(rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize))
+ .boundedTo(effectiveSizeHint(Qt::MaximumSize)));
+ if (newGeom == d->geom)
+ return;
+
+ // Update and prepare to change the geometry (remove from index).
+ if (wd->scene) {
+ if (rect.topLeft() != d->geom.topLeft())
+ wd->fullUpdateHelper(true);
+ else
+ update();
+ }
+ prepareGeometryChange();
+
+ // setPos triggers ItemPositionChange, which can adjust position
+ QPointF oldPos = d->geom.topLeft();
+ wd->inSetGeometry = 1;
+ wd->setPosHelper(newGeom.topLeft(), /* update = */ false);
+ wd->inSetGeometry = 0;
+ newGeom.moveTopLeft(pos());
+
+ if (newGeom == d->geom)
+ return;
+
+ // Update the layout item geometry
+ bool moved = oldPos != pos();
+ if (moved) {
+ // Send move event.
+ QGraphicsSceneMoveEvent event;
+ event.setOldPos(oldPos);
+ event.setNewPos(pos());
+ QApplication::sendEvent(this, &event);
+ }
+ QSizeF oldSize = size();
+ QGraphicsLayoutItem::setGeometry(newGeom);
+
+ // Send resize event
+ bool resized = newGeom.size() != oldSize;
+ if (resized) {
+ QGraphicsSceneResizeEvent re;
+ re.setOldSize(oldSize);
+ re.setNewSize(newGeom.size());
+ QApplication::sendEvent(this, &re);
+ }
+}
+
+/*!
+ \fn QRectF QGraphicsWidget::rect() const
+
+ Returns the item's local rect as a QRectF. This function is equivalent
+ to QRectF(QPointF(), size()).
+
+ \sa setGeometry(), resize()
+*/
+
+/*!
+ \fn void QGraphicsWidget::setGeometry(qreal x, qreal y, qreal w, qreal h)
+
+ This convenience function is equivalent to calling setGeometry(QRectF(
+ \a x, \a y, \a w, \a h)).
+
+ \sa geometry(), resize()
+*/
+
+/*!
+ Sets the widget's contents margins to \a left, \a top, \a right and \a
+ bottom.
+
+ Contents margins are used by the assigned layout to define the placement
+ of subwidgets and layouts. Margins are particularily useful for widgets
+ that constrain subwidgets to only a section of its own geometry. For
+ example, a group box with a layout will place subwidgets inside its frame,
+ but below the title.
+
+ Changing a widget's contents margins will always trigger an update(), and
+ any assigned layout will be activated automatically. The widget will then
+ receive a \l{QEvent::ContentsRectChange}{ContentsRectChange} event.
+
+ \sa getContentsMargins(), setGeometry()
+*/
+void QGraphicsWidget::setContentsMargins(qreal left, qreal top, qreal right, qreal bottom)
+{
+ Q_D(QGraphicsWidget);
+
+ if (left == d->leftMargin
+ && top == d->topMargin
+ && right == d->rightMargin
+ && bottom == d->bottomMargin) {
+ return;
+ }
+
+ d->leftMargin = left;
+ d->topMargin = top;
+ d->rightMargin = right;
+ d->bottomMargin = bottom;
+
+ if (QGraphicsLayout *l = d->layout)
+ l->invalidate();
+ else
+ updateGeometry();
+
+ QEvent e(QEvent::ContentsRectChange);
+ QApplication::sendEvent(this, &e);
+}
+
+/*!
+ Gets the widget's contents margins. The margins are stored in \a left, \a
+ top, \a right and \a bottom, as pointers to qreals. Each argument can
+ be \e {omitted} by passing 0.
+
+ \sa setContentsMargins()
+*/
+void QGraphicsWidget::getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
+{
+ Q_D(const QGraphicsWidget);
+ if (left)
+ *left = d->leftMargin;
+ if (top)
+ *top = d->topMargin;
+ if (right)
+ *right = d->rightMargin;
+ if (bottom)
+ *bottom = d->bottomMargin;
+}
+
+/*!
+ Sets the widget's window frame margins to \a left, \a top, \a right and
+ \a bottom. The default frame margins are provided by the style, and they
+ depend on the current window flags.
+
+ If you would like to draw your own window decoration, you can set your
+ own frame margins to override the default margins.
+
+ \sa unsetWindowFrameMargins(), getWindowFrameMargins(), windowFrameRect()
+*/
+void QGraphicsWidget::setWindowFrameMargins(qreal left, qreal top, qreal right, qreal bottom)
+{
+ Q_D(QGraphicsWidget);
+ bool unchanged = left == d->leftWindowFrameMargin && top == d->topWindowFrameMargin
+ && right == d->rightWindowFrameMargin && bottom == d->bottomWindowFrameMargin;
+ if (d->setWindowFrameMargins && unchanged)
+ return;
+ if (!unchanged)
+ prepareGeometryChange();
+ d->leftWindowFrameMargin = left;
+ d->topWindowFrameMargin = top;
+ d->rightWindowFrameMargin = right;
+ d->bottomWindowFrameMargin = bottom;
+ d->setWindowFrameMargins = true;
+}
+
+/*!
+ Gets the widget's window frame margins. The margins are stored in \a left,
+ \a top, \a right and \a bottom as pointers to qreals. Each argument can
+ be \e {omitted} by passing 0.
+
+ \sa setWindowFrameMargins(), windowFrameRect()
+*/
+void QGraphicsWidget::getWindowFrameMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
+{
+ Q_D(const QGraphicsWidget);
+ if (left)
+ *left = d->leftWindowFrameMargin;
+ if (top)
+ *top = d->topWindowFrameMargin;
+ if (right)
+ *right = d->rightWindowFrameMargin;
+ if (bottom)
+ *bottom = d->bottomWindowFrameMargin;
+}
+
+/*!
+ Resets the window frame margins to the default value, provided by the style.
+
+ \sa setWindowFrameMargins(), getWindowFrameMargins(), windowFrameRect()
+*/
+void QGraphicsWidget::unsetWindowFrameMargins()
+{
+ Q_D(QGraphicsWidget);
+ if ((d->windowFlags & Qt::Window) && (d->windowFlags & Qt::WindowType_Mask) != Qt::Popup &&
+ (d->windowFlags & Qt::WindowType_Mask) != Qt::ToolTip && !(d->windowFlags & Qt::FramelessWindowHint)) {
+ QStyleOptionTitleBar bar;
+ d->initStyleOptionTitleBar(&bar);
+ QStyle *style = this->style();
+ qreal margin = style->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth);
+ qreal titleBarHeight = d->titleBarHeight(bar);
+ setWindowFrameMargins(margin, titleBarHeight, margin, margin);
+ } else {
+ setWindowFrameMargins(0, 0, 0, 0);
+ }
+ d->setWindowFrameMargins = false;
+}
+
+/*!
+ Returns the widget's geometry in parent coordinates including any window
+ frame.
+
+ \sa windowFrameRect(), getWindowFrameMargins(), setWindowFrameMargins()
+*/
+QRectF QGraphicsWidget::windowFrameGeometry() const
+{
+ Q_D(const QGraphicsWidget);
+ return geometry().adjusted(-d->leftWindowFrameMargin, -d->topWindowFrameMargin,
+ d->rightWindowFrameMargin, d->bottomWindowFrameMargin);
+}
+
+/*!
+ Returns the widget's local rect including any window frame.
+
+ \sa windowFrameGeometry(), getWindowFrameMargins(), setWindowFrameMargins()
+*/
+QRectF QGraphicsWidget::windowFrameRect() const
+{
+ Q_D(const QGraphicsWidget);
+ return rect().adjusted(-d->leftWindowFrameMargin, -d->topWindowFrameMargin,
+ d->rightWindowFrameMargin, d->bottomWindowFrameMargin);
+}
+
+/*!
+ Populates a style option object for this widget based on its current
+ state, and stores the output in \a option. The default implementation
+ populates \a option with the following properties.
+
+ \table
+ \header
+ \o Style Option Property
+ \o Value
+ \row
+ \o state & QStyle::State_Enabled
+ \o Corresponds to QGraphicsItem::isEnabled().
+ \row
+ \o state & QStyle::State_HasFocus
+ \o Corresponds to QGraphicsItem::hasFocus().
+ \row
+ \o state & QStyle::State_MouseOver
+ \o Corresponds to QGraphicsItem::isUnderMouse().
+ \row
+ \o direction
+ \o Corresponds to QGraphicsWidget::layoutDirection().
+ \row
+ \o rect
+ \o Corresponds to QGraphicsWidget::rect().toRect().
+ \row
+ \o palette
+ \o Corresponds to QGraphicsWidget::palette().
+ \row
+ \o fontMetrics
+ \o Corresponds to QFontMetrics(QGraphicsWidget::font()).
+ \endtable
+
+ Subclasses of QGraphicsWidget should call the base implementation, and
+ then test the type of \a option using qstyleoption_cast<>() or test
+ QStyleOption::Type before storing widget-specific options.
+
+ For example:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicswidget.cpp 0
+
+ \sa QStyleOption::initFrom()
+*/
+void QGraphicsWidget::initStyleOption(QStyleOption *option) const
+{
+ Q_ASSERT(option);
+
+ option->state = QStyle::State_None;
+ if (isEnabled())
+ option->state |= QStyle::State_Enabled;
+ if (hasFocus())
+ option->state |= QStyle::State_HasFocus;
+ // if (window->testAttribute(Qt::WA_KeyboardFocusChange)) // ### Window
+ // option->state |= QStyle::State_KeyboardFocusChange;
+ if (isUnderMouse())
+ option->state |= QStyle::State_MouseOver;
+ if (QGraphicsWidget *w = window()) {
+ if (w->isActiveWindow())
+ option->state |= QStyle::State_Active;
+ }
+ if (isWindow())
+ option->state |= QStyle::State_Window;
+ /*
+ ###
+#ifdef Q_WS_MAC
+ extern bool qt_mac_can_clickThrough(const QGraphicsWidget *w); //qwidget_mac.cpp
+ if (!(option->state & QStyle::State_Active) && !qt_mac_can_clickThrough(widget))
+ option->state &= ~QStyle::State_Enabled;
+
+ switch (QMacStyle::widgetSizePolicy(widget)) {
+ case QMacStyle::SizeSmall:
+ option->state |= QStyle::State_Small;
+ break;
+ case QMacStyle::SizeMini:
+ option->state |= QStyle::State_Mini;
+ break;
+ default:
+ ;
+ }
+#endif
+#ifdef QT_KEYPAD_NAVIGATION
+ if (widget->hasEditFocus())
+ state |= QStyle::State_HasEditFocus;
+#endif
+ */
+ option->direction = layoutDirection();
+ option->rect = rect().toRect(); // ### truncation!
+ option->palette = palette();
+ if (!isEnabled()) {
+ option->palette.setCurrentColorGroup(QPalette::Disabled);
+ } else if (isActiveWindow()) {
+ option->palette.setCurrentColorGroup(QPalette::Active);
+ } else {
+ option->palette.setCurrentColorGroup(QPalette::Inactive);
+ }
+ option->fontMetrics = QFontMetrics(font());
+}
+
+/*!
+ \reimp
+*/
+QSizeF QGraphicsWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ Q_D(const QGraphicsWidget);
+ QSizeF sh;
+ if (d->layout) {
+ sh = d->layout->effectiveSizeHint(which, constraint);
+ sh += QSizeF(d->leftMargin + d->rightMargin, d->topMargin + d->bottomMargin);
+ } else {
+ switch (which) {
+ case Qt::MinimumSize:
+ sh = QSizeF(0, 0);
+ break;
+ case Qt::PreferredSize:
+ sh = QSizeF(50, 50); //rather arbitrary
+ break;
+ case Qt::MaximumSize:
+ sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+ break;
+ default:
+ qWarning("QGraphicsWidget::sizeHint(): Don't know how to handle the value of 'which'");
+ break;
+ }
+ }
+ return sh;
+}
+
+/*!
+ Returns this widget's layout, or 0 if no layout is currently managing this
+ widget.
+
+ \sa setLayout()
+*/
+QGraphicsLayout *QGraphicsWidget::layout() const
+{
+ Q_D(const QGraphicsWidget);
+ return d->layout;
+}
+
+/*!
+ \fn void QGraphicsWidget::setLayout(QGraphicsLayout *layout)
+
+ Sets the layout for this widget to \a layout. Any existing layout manager
+ is deleted before the new layout is assigned. If \a layout is 0, the
+ widget is left without a layout. Existing subwidgets' geometries will
+ remain unaffected.
+
+ All widgets that are currently managed by \a layout or all of its
+ sublayouts, are automatically reparented to this item. The layout is then
+ invalidated, and the child widget geometries are adjusted according to
+ this item's geometry() and contentsMargins(). Children who are not
+ explicitly managed by \a layout remain unaffected by the layout after
+ it has been assigned to this widget.
+
+ QGraphicsWidget takes ownership of \a layout.
+
+ \sa layout(), QGraphicsLinearLayout::addItem(), QGraphicsLayout::invalidate()
+*/
+void QGraphicsWidget::setLayout(QGraphicsLayout *l)
+{
+ Q_D(QGraphicsWidget);
+ if (d->layout == l)
+ return;
+ d->setLayout_helper(l);
+ if (!l)
+ return;
+
+ // Prevent assigning a layout that is already assigned to another widget.
+ QGraphicsLayoutItem *oldParent = l->parentLayoutItem();
+ if (oldParent && oldParent != this) {
+ qWarning("QGraphicsWidget::setLayout: Attempting to set a layout on %s"
+ " \"%s\", when the layout already has a parent",
+ metaObject()->className(), qPrintable(objectName()));
+ return;
+ }
+
+ // Install and activate the layout.
+ l->setParentLayoutItem(this);
+ l->d_func()->reparentChildItems(this);
+ l->invalidate();
+}
+
+/*!
+ Adjusts the size of the widget to its effective preferred size hint.
+
+ This function is called implicitly when the item is shown for the first
+ time.
+
+ \sa effectiveSizeHint(), Qt::MinimumSize
+*/
+void QGraphicsWidget::adjustSize()
+{
+ QSizeF sz = effectiveSizeHint(Qt::PreferredSize);
+ // What if sz is not valid?!
+ if (sz.isValid())
+ resize(sz);
+}
+
+/*!
+ \property QGraphicsWidget::layoutDirection
+ \brief the layout direction for this widget.
+
+ This property modifies this widget's and all of its descendants'
+ Qt::WA_RightToLeft attribute. It also sets this widget's
+ Qt::WA_SetLayoutDirection attribute.
+
+ The widget's layout direction determines the order in which the layout
+ manager horizontally arranges subwidgets of this widget. The default
+ value depends on the language and locale of the application, and is
+ typically in the same direction as words are read and written. With
+ Qt::LeftToRight, the layout starts placing subwidgets from the left
+ side of this widget towards the right. Qt::RightToLeft does the opposite -
+ the layout will place widgets starting from the right edge moving towards
+ the left.
+
+ Subwidgets inherit their layout direction from the parent. Top-level
+ widget items inherit their layout direction from
+ QGraphicsScene::layoutDirection. If you change a widget's layout direction
+ by calling setLayoutDirection(), the widget will send itself a
+ \l{QEvent::LayoutDirectionChange}{LayoutDirectionChange} event, and then
+ propagate the new layout direction to all its descendants.
+
+ \sa QWidget::layoutDirection, QApplication::layoutDirection
+*/
+Qt::LayoutDirection QGraphicsWidget::layoutDirection() const
+{
+ return testAttribute(Qt::WA_RightToLeft) ? Qt::RightToLeft : Qt::LeftToRight;
+}
+void QGraphicsWidget::setLayoutDirection(Qt::LayoutDirection direction)
+{
+ Q_D(QGraphicsWidget);
+ setAttribute(Qt::WA_SetLayoutDirection, true);
+ d->setLayoutDirection_helper(direction);
+}
+void QGraphicsWidget::unsetLayoutDirection()
+{
+ Q_D(QGraphicsWidget);
+ setAttribute(Qt::WA_SetLayoutDirection, false);
+ d->resolveLayoutDirection();
+}
+
+/*!
+ Returns a pointer to the widget's style. If this widget does not have any
+ explicitly assigned style, the scene's style is returned instead. In turn,
+ if the scene does not have any assigned style, this function returns
+ QApplication::style().
+
+ \sa setStyle()
+*/
+QStyle *QGraphicsWidget::style() const
+{
+ if (QStyle *style = widgetStyles()->styleForWidget(this))
+ return style;
+ // ### This is not thread-safe. QApplication::style() is not thread-safe.
+ return scene() ? scene()->style() : QApplication::style();
+}
+
+/*!
+ Sets the widget's style to \a style. QGraphicsWidget does \e not take
+ ownership of \a style.
+
+ If no style is assigned, or \a style is 0, the widget will use
+ QGraphicsScene::style() (if this has been set). Otherwise the widget will
+ use QApplication::style().
+
+ This function sets the Qt::WA_SetStyle attribute if \a style is not 0;
+ otherwise it clears the attribute.
+
+ \sa style()
+*/
+void QGraphicsWidget::setStyle(QStyle *style)
+{
+ setAttribute(Qt::WA_SetStyle, style != 0);
+ widgetStyles()->setStyleForWidget(this, style);
+
+ // Deliver StyleChange to the widget itself (doesn't propagate).
+ QEvent event(QEvent::StyleChange);
+ QApplication::sendEvent(this, &event);
+}
+
+/*!
+ \property QGraphicsWidget::font
+ \brief the widgets' font
+
+ This property provides the widget's font.
+
+ QFont consists of font properties that have been explicitly defined and
+ properties implicitly inherited from the widget's parent. Hence, font()
+ can return a different font compared to the one set with setFont().
+ This scheme allows you to define single entries in a font without
+ affecting the font's inherited entries.
+
+ When a widget's font changes, it resolves its entries against its
+ parent widget. If the widget does not have a parent widget, it resolves
+ its entries against the scene. The widget then sends itself a
+ \l{QEvent::FontChange}{FontChange} event and notifies all its
+ descendants so that they can resolve their fonts as well.
+
+ By default, this property contains the application's default font.
+
+ \sa QApplication::font(), QGraphicsScene::font, QFont::resolve()
+*/
+QFont QGraphicsWidget::font() const
+{
+ Q_D(const QGraphicsWidget);
+ return d->font;
+}
+void QGraphicsWidget::setFont(const QFont &font)
+{
+ Q_D(QGraphicsWidget);
+ setAttribute(Qt::WA_SetFont, font.resolve() != 0);
+
+ QFont naturalFont = d->naturalWidgetFont();
+ QFont resolvedFont = font.resolve(naturalFont);
+ d->setFont_helper(resolvedFont);
+}
+
+/*!
+ \property QGraphicsWidget::palette
+ \brief the widget's palette
+
+ This property provides the widget's palette. The palette provides colors
+ and brushes for color groups (e.g., QPalette::Button) and states (e.g.,
+ QPalette::Inactive), loosely defining the general look of the widget and
+ its children.
+
+ QPalette consists of color groups that have been explicitly defined, and
+ groups that are implicitly inherited from the widget's parent. Because of
+ this, palette() can return a different palette than what has been set with
+ setPalette(). This scheme allows you to define single entries in a palette
+ without affecting the palette's inherited entries.
+
+ When a widget's palette changes, it resolves its entries against its
+ parent widget, or if it doesn't have a parent widget, it resolves against
+ the scene. It then sends itself a \l{QEvent::PaletteChange}{PaletteChange}
+ event, and notifies all its descendants so they can resolve their palettes
+ as well.
+
+ By default, this property contains the application's default palette.
+
+ \sa QApplication::palette(), QGraphicsScene::palette, QPalette::resolve()
+*/
+QPalette QGraphicsWidget::palette() const
+{
+ Q_D(const QGraphicsWidget);
+ return d->palette;
+}
+void QGraphicsWidget::setPalette(const QPalette &palette)
+{
+ Q_D(QGraphicsWidget);
+ setAttribute(Qt::WA_SetPalette, palette.resolve() != 0);
+
+ QPalette naturalPalette = d->naturalWidgetPalette();
+ QPalette resolvedPalette = palette.resolve(naturalPalette);
+ d->setPalette_helper(resolvedPalette);
+}
+
+/*!
+ If this widget is currently managed by a layout, this function notifies
+ the layout that the widget's size hints have changed and the layout
+ may need to resize and reposition the widget accordingly.
+
+ Call this function if the widget's sizeHint() has changed.
+
+ \sa QGraphicsLayout::invalidate()
+*/
+void QGraphicsWidget::updateGeometry()
+{
+ QGraphicsLayoutItem::updateGeometry();
+ QGraphicsLayoutItem *parentItem = parentLayoutItem();
+
+ if (parentItem && parentItem->isLayout()) {
+ parentItem->updateGeometry();
+ } else {
+ if (parentItem) {
+ QGraphicsWidget *parentWid = parentWidget(); //###
+ if (parentWid->isVisible())
+ QApplication::postEvent(parentWid, new QEvent(QEvent::LayoutRequest));
+ }
+ bool wasResized = testAttribute(Qt::WA_Resized);
+ resize(size()); // this will restrict the size
+ setAttribute(Qt::WA_Resized, wasResized);
+ }
+}
+
+/*!
+ \reimp
+
+ QGraphicsWidget uses the base implementation of this function to catch and
+ deliver events related to state changes in the item. Because of this, it is
+ very important that subclasses call the base implementation.
+
+ For example, QGraphicsWidget uses ItemVisibleChange to deliver \l Show and
+ \l Hide events, ItemPositionHasChanged to deliver \l Move events, and
+ ItemParentChange both to deliver \l ParentChange events, and for managing
+ the focus chain.
+
+ \sa propertyChange()
+*/
+QVariant QGraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ Q_D(QGraphicsWidget);
+ switch (change) {
+ case ItemEnabledHasChanged: {
+ // Send EnabledChange after the enabled state has changed.
+ QEvent event(QEvent::EnabledChange);
+ QApplication::sendEvent(this, &event);
+ break;
+ }
+ case ItemVisibleChange:
+ if (value.toBool()) {
+ // Send Show event before the item has been shown.
+ QShowEvent event;
+ QApplication::sendEvent(this, &event);
+ bool resized = testAttribute(Qt::WA_Resized);
+ if (!resized) {
+ adjustSize();
+ setAttribute(Qt::WA_Resized, false);
+ }
+ }
+ break;
+ case ItemVisibleHasChanged:
+ if (!value.toBool()) {
+ // Send Hide event after the item has been hidden.
+ QHideEvent event;
+ QApplication::sendEvent(this, &event);
+ }
+ break;
+ case ItemPositionHasChanged:
+ if (!d->inSetGeometry) {
+ // Ensure setGeometry is called (avoid recursion when setPos is
+ // called from within setGeometry).
+ setGeometry(QRectF(pos(), size()));
+ }
+ break;
+ case ItemParentChange: {
+ QGraphicsItem *parent = qVariantValue<QGraphicsItem *>(value);
+ d->fixFocusChainBeforeReparenting((parent && parent->isWidget()) ? static_cast<QGraphicsWidget *>(parent) : 0);
+
+ // Deliver ParentAboutToChange.
+ QEvent event(QEvent::ParentAboutToChange);
+ QApplication::sendEvent(this, &event);
+ break;
+ }
+ case ItemParentHasChanged: {
+ // reset window type on parent change in order to automagically remove decorations etc.
+ Qt::WindowFlags wflags = d->windowFlags & ~Qt::WindowType_Mask;
+ d->adjustWindowFlags(&wflags);
+ setWindowFlags(wflags);
+ // Deliver ParentChange.
+ QEvent event(QEvent::ParentChange);
+ QApplication::sendEvent(this, &event);
+ break;
+ }
+ case ItemCursorChange: {
+ // Deliver CursorChange.
+ QEvent event(QEvent::CursorChange);
+ QApplication::sendEvent(this, &event);
+ break;
+ }
+ case ItemToolTipChange: {
+ // Deliver ToolTipChange.
+ QEvent event(QEvent::ToolTipChange);
+ QApplication::sendEvent(this, &event);
+ break;
+ }
+ default:
+ break;
+ }
+ return QGraphicsItem::itemChange(change, value);
+}
+
+/*!
+ \internal
+
+ This virtual function is used to notify changes to any property (both
+ dynamic properties, and registered with Q_PROPERTY) in the
+ widget. Depending on the property itself, the notification can be
+ delivered before or after the value has changed.
+
+ \a propertyName is the name of the property (e.g., "size" or "font"), and
+ \a value is the (proposed) new value of the property. The function returns
+ the new value, which may be different from \a value if the notification
+ supports adjusting the property value. The base implementation simply
+ returns \a value for any \a propertyName.
+
+ QGraphicsWidget delivers notifications for the following properties:
+
+ \table \o propertyName \o Property
+ \row \o layoutDirection \o QGraphicsWidget::layoutDirection
+ \row \o size \o QGraphicsWidget::size
+ \row \o font \o QGraphicsWidget::font
+ \row \o palette \o QGraphicsWidget::palette
+ \endtable
+
+ \sa itemChange()
+*/
+QVariant QGraphicsWidget::propertyChange(const QString &propertyName, const QVariant &value)
+{
+ Q_UNUSED(propertyName);
+ return value;
+}
+
+/*!
+ QGraphicsWidget's implementation of sceneEvent() simply passes \a event to
+ QGraphicsWidget::event(). You can handle all events for your widget in
+ event() or in any of the convenience functions; you should not have to
+ reimplement this function in a subclass of QGraphicsWidget.
+
+ \sa QGraphicsItem::sceneEvent()
+*/
+bool QGraphicsWidget::sceneEvent(QEvent *event)
+{
+ return QCoreApplication::sendEvent(this, event) || QGraphicsItem::sceneEvent(event);
+}
+
+/*!
+ This event handler, for \a event, receives events for the window frame if
+ this widget is a window. Its base implementation provides support for
+ default window frame interaction such as moving, resizing, etc.
+
+ You can reimplement this handler in a subclass of QGraphicsWidget to
+ provide your own custom window frame interaction support.
+
+ Returns true if \a event has been recognized and processed; otherwise,
+ returns false.
+
+ \sa event()
+*/
+bool QGraphicsWidget::windowFrameEvent(QEvent *event)
+{
+ Q_D(QGraphicsWidget);
+ switch (event->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ d->windowFrameMousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneMouseMove:
+ if (d->grabbedSection != Qt::NoSection) {
+ d->windowFrameMouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
+ event->accept();
+ }
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ d->windowFrameMouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneHoverMove:
+ d->windowFrameHoverMoveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneHoverLeave:
+ d->windowFrameHoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
+ break;
+ default:
+ break;
+ }
+ return event->isAccepted();
+}
+
+/*!
+ \since 4.4
+
+ Returns the window frame section at position \a pos, or
+ Qt::NoSection if there is no window frame section at this
+ position.
+
+ This function is used in QGraphicsWidget's base implementation for window
+ frame interaction.
+
+ You can reimplement this function if you want to customize how a window
+ can be interactively moved or resized. For instance, if you only want to
+ allow a window to be resized by the bottom right corner, you can
+ reimplement this function to return Qt::NoSection for all sections except
+ Qt::BottomRightSection.
+
+ \sa windowFrameEvent(), paintWindowFrame(), windowFrameGeometry()
+*/
+Qt::WindowFrameSection QGraphicsWidget::windowFrameSectionAt(const QPointF &pos) const
+{
+ Q_D(const QGraphicsWidget);
+
+ const QRectF r = windowFrameRect();
+ if (!r.contains(pos))
+ return Qt::NoSection;
+
+ const qreal left = r.left();
+ const qreal top = r.top();
+ const qreal right = r.right();
+ const qreal bottom = r.bottom();
+ const qreal x = pos.x();
+ const qreal y = pos.y();
+
+ const qreal cornerMargin = 20;
+ //### Not sure of this one, it should be the same value for all edges.
+ const qreal windowFrameWidth = d->leftWindowFrameMargin;
+
+ Qt::WindowFrameSection s = Qt::NoSection;
+ if (x <= left + cornerMargin) {
+ if (y <= top + windowFrameWidth || (x <= left + windowFrameWidth && y <= top + cornerMargin)) {
+ s = Qt::TopLeftSection;
+ } else if (y >= bottom - windowFrameWidth || (x <= left + windowFrameWidth && y >= bottom - windowFrameWidth)) {
+ s = Qt::BottomLeftSection;
+ } else if (x <= left + windowFrameWidth) {
+ s = Qt::LeftSection;
+ }
+ } else if (x >= right - cornerMargin) {
+ if (y <= top + windowFrameWidth || (x >= right - windowFrameWidth && y <= top + cornerMargin)) {
+ s = Qt::TopRightSection;
+ } else if (y >= bottom - windowFrameWidth || (x >= right - windowFrameWidth && y >= bottom - windowFrameWidth)) {
+ s = Qt::BottomRightSection;
+ } else if (x >= right - windowFrameWidth) {
+ s = Qt::RightSection;
+ }
+ } else if (y <= top + windowFrameWidth) {
+ s = Qt::TopSection;
+ } else if (y >= bottom - windowFrameWidth) {
+ s = Qt::BottomSection;
+ }
+ if (s == Qt::NoSection) {
+ QRectF r1 = r;
+ r1.setHeight(d->topWindowFrameMargin);
+ if (r1.contains(pos))
+ s = Qt::TitleBarArea;
+ }
+ return s;
+}
+
+/*!
+ \reimp
+
+ QGraphicsWidget handles the following events:
+
+ \table \o Event \o Usage
+ \row \o Polish
+ \o Delivered to the widget some time after it has been
+ shown.
+ \row \o GraphicsSceneMove
+ \o Delivered to the widget after its local position has
+ changed.
+ \row \o GraphicsSceneResize
+ \o Delivered to the widget after its size has changed.
+ \row \o Show
+ \o Delivered to the widget before it has been shown.
+ \row \o Hide
+ \o Delivered to the widget after it has been hidden.
+ \row \o PaletteChange
+ \o Delivered to the widget after its palette has changed.
+ \row \o FontChange
+ \o Delivered to the widget after its font has changed.
+ \row \o EnabledChange
+ \o Delivered to the widget after its enabled state has
+ changed.
+ \row \o StyleChange
+ \o Delivered to the widget after its style has changed.
+ \row \o LayoutDirectionChange
+ \o Delivered to the widget after its layout direction has
+ changed.
+ \row \o ContentsRectChange
+ \o Delivered to the widget after its contents margins/
+ contents rect has changed.
+ \endtable
+*/
+bool QGraphicsWidget::event(QEvent *event)
+{
+ Q_D(QGraphicsWidget);
+ // Forward the event to the layout first.
+ if (d->layout)
+ d->layout->widgetEvent(event);
+
+ // Handle the event itself.
+ switch (event->type()) {
+ case QEvent::GraphicsSceneMove:
+ moveEvent(static_cast<QGraphicsSceneMoveEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneResize:
+ resizeEvent(static_cast<QGraphicsSceneResizeEvent *>(event));
+ break;
+ case QEvent::Show:
+ showEvent(static_cast<QShowEvent *>(event));
+ break;
+ case QEvent::Hide:
+ hideEvent(static_cast<QHideEvent *>(event));
+ break;
+ case QEvent::Polish:
+ polishEvent();
+ break;
+ case QEvent::WindowActivate:
+ case QEvent::WindowDeactivate:
+ update();
+ foreach (QGraphicsItem *child, childItems()) {
+ if (child->isWidget())
+ QApplication::sendEvent(static_cast<QGraphicsWidget *>(child), event);
+ }
+ break;
+ // Taken from QWidget::event
+ case QEvent::ActivationChange:
+ case QEvent::EnabledChange:
+ case QEvent::FontChange:
+ case QEvent::StyleChange:
+ case QEvent::PaletteChange:
+ case QEvent::ParentChange:
+ case QEvent::ContentsRectChange:
+ case QEvent::LayoutDirectionChange:
+ changeEvent(event);
+ break;
+ case QEvent::Close:
+ closeEvent((QCloseEvent *)event);
+ break;
+ case QEvent::GrabMouse:
+ grabMouseEvent(event);
+ break;
+ case QEvent::UngrabMouse:
+ ungrabMouseEvent(event);
+ break;
+ case QEvent::GrabKeyboard:
+ grabKeyboardEvent(event);
+ break;
+ case QEvent::UngrabKeyboard:
+ ungrabKeyboardEvent(event);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ if (d->hasDecoration() && windowFrameEvent(event))
+ return true;
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ if (d->hasDecoration() && d->grabbedSection != Qt::NoSection)
+ return windowFrameEvent(event);
+ break;
+ case QEvent::GraphicsSceneHoverEnter:
+ case QEvent::GraphicsSceneHoverMove:
+ case QEvent::GraphicsSceneHoverLeave:
+ if (d->hasDecoration()) {
+ windowFrameEvent(event);
+ // Filter out hover events if they were sent to us only because of the
+ // decoration (special case in QGraphicsScenePrivate::dispatchHoverEvent).
+ if (!acceptsHoverEvents())
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return QObject::event(event);
+}
+
+/*!
+ This event handler can be reimplemented to handle state changes.
+
+ The state being changed in this event can be retrieved through \a event.
+
+ Change events include: QEvent::ActivationChange, QEvent::EnabledChange,
+ QEvent::FontChange, QEvent::StyleChange, QEvent::PaletteChange,
+ QEvent::ParentChange, QEvent::LayoutDirectionChange, and
+ QEvent::ContentsRectChange.
+*/
+void QGraphicsWidget::changeEvent(QEvent *event)
+{
+ Q_D(QGraphicsWidget);
+ switch (event->type()) {
+ case QEvent::StyleChange:
+ // ### Don't unset if the margins are explicitly set.
+ unsetWindowFrameMargins();
+ case QEvent::FontChange:
+ update();
+ updateGeometry();
+ break;
+ case QEvent::PaletteChange:
+ update();
+ break;
+ case QEvent::ParentChange:
+ d->resolveFont(d->inheritedFontResolveMask);
+ d->resolvePalette(d->inheritedPaletteResolveMask);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ This event handler, for \a event, can be reimplemented in a subclass to
+ receive widget close events. The default implementation accepts the
+ event.
+
+ \sa close(), QCloseEvent
+*/
+void QGraphicsWidget::closeEvent(QCloseEvent *event)
+{
+ event->accept();
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsWidget::focusInEvent(QFocusEvent *event)
+{
+ Q_UNUSED(event);
+ if (focusPolicy() != Qt::NoFocus)
+ update();
+}
+
+/*!
+ Finds a new widget to give the keyboard focus to, as appropriate for Tab
+ and Shift+Tab, and returns true if it can find a new widget; returns false
+ otherwise. If \a next is true, this function searches forward; if \a next
+ is false, it searches backward.
+
+ Sometimes, you will want to reimplement this function to provide special
+ focus handling for your widget and its subwidgets. For example, a web
+ browser might reimplement it to move its current active link forward or
+ backward, and call the base implementation only when it reaches the last
+ or first link on the page.
+
+ Child widgets call focusNextPrevChild() on their parent widgets, but only
+ the window that contains the child widgets decides where to redirect
+ focus. By reimplementing this function for an object, you gain control of
+ focus traversal for all child widgets.
+
+ \sa focusPolicy()
+*/
+bool QGraphicsWidget::focusNextPrevChild(bool next)
+{
+ Q_D(QGraphicsWidget);
+ // Let the parent's focusNextPrevChild implementation decide what to do.
+ QGraphicsWidget *parent = 0;
+ if (!isWindow() && (parent = parentWidget()))
+ return parent->focusNextPrevChild(next);
+ if (!d->scene)
+ return false;
+ if (d->scene->focusNextPrevChild(next))
+ return true;
+ if (isWindow()) {
+ setFocus(next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
+ if (hasFocus())
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsWidget::focusOutEvent(QFocusEvent *event)
+{
+ Q_UNUSED(event);
+ if (focusPolicy() != Qt::NoFocus)
+ update();
+}
+
+/*!
+ This event handler, for \l{QEvent::Hide}{Hide} events, is delivered after
+ the widget has been hidden, for example, setVisible(false) has been called
+ for the widget or one of its ancestors when the widget was previously
+ shown.
+
+ You can reimplement this event handler to detect when your widget is
+ hidden. Calling QEvent::accept() or QEvent::ignore() on \a event has no
+ effect.
+
+ \sa showEvent(), QWidget::hideEvent(), ItemVisibleChange
+*/
+void QGraphicsWidget::hideEvent(QHideEvent *event)
+{
+ ///### focusNextPrevChild(true), don't lose focus when the focus widget
+ // is hidden.
+ Q_UNUSED(event);
+}
+
+/*!
+ This event handler, for \l{QEvent::GraphicsSceneMove}{GraphicsSceneMove}
+ events, is delivered after the widget has moved (e.g., its local position
+ has changed).
+
+ This event is only delivered when the item is moved locally. Calling
+ setTransform() or moving any of the item's ancestors does not affect the
+ item's local position.
+
+ You can reimplement this event handler to detect when your widget has
+ moved. Calling QEvent::accept() or QEvent::ignore() on \a event has no
+ effect.
+
+ \sa ItemPositionChange, ItemPositionHasChanged
+*/
+void QGraphicsWidget::moveEvent(QGraphicsSceneMoveEvent *event)
+{
+ // ### Last position is always == current position
+ Q_UNUSED(event);
+}
+
+/*!
+ This event is delivered to the item by the scene at some point after it
+ has been constructed, but before it is shown or otherwise accessed through
+ the scene. You can use this event handler to do last-minute initializations
+ of the widget which require the item to be fully constructed.
+
+ The base implementation does nothing.
+*/
+void QGraphicsWidget::polishEvent()
+{
+}
+
+/*!
+ This event handler, for
+ \l{QEvent::GraphicsSceneResize}{GraphicsSceneResize} events, is
+ delivered after the widget has been resized (i.e., its local size has
+ changed). \a event contains both the old and the new size.
+
+ This event is only delivered when the widget is resized locally; calling
+ setTransform() on the widget or any of its ancestors or view, does not
+ affect the widget's local size.
+
+ You can reimplement this event handler to detect when your widget has been
+ resized. Calling QEvent::accept() or QEvent::ignore() on \a event has no
+ effect.
+
+ \sa geometry(), setGeometry()
+*/
+void QGraphicsWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ This event handler, for \l{QEvent::Show}{Show} events, is delivered before
+ the widget has been shown, for example, setVisible(true) has been called
+ for the widget or one of its ancestors when the widget was previously
+ hidden.
+
+ You can reimplement this event handler to detect when your widget is
+ shown. Calling QEvent::accept() or QEvent::ignore() on \a event has no
+ effect.
+
+ \sa hideEvent(), QWidget::showEvent(), ItemVisibleChange
+*/
+void QGraphicsWidget::showEvent(QShowEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ This event handler, for \a event, can be reimplemented in a subclass to
+ receive notifications for Qt::GrabMouse events.
+
+ \sa grabMouse(), grabKeyboard()
+*/
+void QGraphicsWidget::grabMouseEvent(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ This event handler, for \a event, can be reimplemented in a subclass to
+ receive notifications for Qt::UngrabMouse events.
+
+ \sa ungrabMouse(), ungrabKeyboard()
+*/
+void QGraphicsWidget::ungrabMouseEvent(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ This event handler, for \a event, can be reimplemented in a subclass to
+ receive notifications for Qt::GrabKeyboard events.
+
+ \sa grabKeyboard(), grabMouse()
+*/
+void QGraphicsWidget::grabKeyboardEvent(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ This event handler, for \a event, can be reimplemented in a subclass to
+ receive notifications for Qt::UngrabKeyboard events.
+
+ \sa ungrabKeyboard(), ungrabMouse()
+*/
+void QGraphicsWidget::ungrabKeyboardEvent(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ Returns the widgets window type.
+*/
+Qt::WindowType QGraphicsWidget::windowType() const
+{
+ return Qt::WindowType(int(windowFlags()) & Qt::WindowType_Mask);
+}
+
+/*!
+ \property QGraphicsWidget::windowFlags
+ \brief the widget's window flags
+
+ Window flags are a combination of a window type (e.g., Qt::Dialog) and
+ several flags giving hints on the behavior of the window. The behavior
+ is platform-dependent.
+
+ By default, this property contains no window flags.
+*/
+Qt::WindowFlags QGraphicsWidget::windowFlags() const
+{
+ Q_D(const QGraphicsWidget);
+ return d->windowFlags;
+}
+void QGraphicsWidget::setWindowFlags(Qt::WindowFlags wFlags)
+{
+ Q_D(QGraphicsWidget);
+ if (d->windowFlags == wFlags)
+ return;
+ bool wasPopup = (d->windowFlags & Qt::WindowType_Mask) == Qt::Popup;
+
+ d->windowFlags = wFlags;
+ if (!d->setWindowFrameMargins)
+ unsetWindowFrameMargins();
+
+ bool isPopup = (d->windowFlags & Qt::WindowType_Mask) == Qt::Popup;
+ if (d->scene && isVisible() && wasPopup != isPopup) {
+ // Popup state changed; update implicit mouse grab.
+ if (!isPopup)
+ d->scene->d_func()->removePopup(this);
+ else
+ d->scene->d_func()->addPopup(this);
+ }
+}
+
+/*!
+ Returns true if this widget's window is in the active window, or if the
+ widget does not have a window but is in an active scene (i.e., a scene
+ that currently has focus).
+
+ The active window is the window that either contains a child widget that
+ currently has input focus, or that itself has input focus.
+
+ \sa QGraphicsScene::activeWindow(), QGraphicsScene::setActiveWindow()
+*/
+bool QGraphicsWidget::isActiveWindow() const
+{
+ Q_D(const QGraphicsWidget);
+ if (!d->scene)
+ return false;
+ const QGraphicsWidget *w = window();
+ return (!w && d->scene->d_func()->activationRefCount) || (w && d->scene->activeWindow() == w);
+}
+
+/*!
+ \property QGraphicsWidget::windowTitle
+ \brief This property holds the window title (caption).
+
+ This property is only used for windows.
+
+ By default, if no title has been set, this property contains an empty string.
+*/
+void QGraphicsWidget::setWindowTitle(const QString &title)
+{
+ Q_D(QGraphicsWidget);
+ d->windowTitle = title;
+}
+QString QGraphicsWidget::windowTitle() const
+{
+ Q_D(const QGraphicsWidget);
+ return d->windowTitle;
+}
+
+/*!
+ \property QGraphicsWidget::focusPolicy
+ \brief the way the widget accepts keyboard focus
+
+ The focus policy is Qt::TabFocus if the widget accepts keyboard focus by
+ tabbing, Qt::ClickFocus if the widget accepts focus by clicking,
+ Qt::StrongFocus if it accepts both, and Qt::NoFocus (the default) if it
+ does not accept focus at all.
+
+ You must enable keyboard focus for a widget if it processes keyboard
+ events. This is normally done from the widget's constructor. For instance,
+ the QLineEdit constructor calls setFocusPolicy(Qt::StrongFocus).
+
+ If you enable a focus policy (i.e., not Qt::NoFocus), QGraphicsWidget will
+ automatically enable the ItemIsFocusable flag. Setting Qt::NoFocus on a
+ widget will clear the ItemIsFocusable flag. If the widget currently has
+ keyboard focus, the widget will automatically lose focus.
+
+ \sa focusInEvent(), focusOutEvent(), keyPressEvent(), keyReleaseEvent(), enabled
+*/
+Qt::FocusPolicy QGraphicsWidget::focusPolicy() const
+{
+ Q_D(const QGraphicsWidget);
+ return d->focusPolicy;
+}
+void QGraphicsWidget::setFocusPolicy(Qt::FocusPolicy policy)
+{
+ Q_D(QGraphicsWidget);
+ if (d->focusPolicy == policy)
+ return;
+ d->focusPolicy = policy;
+ if (hasFocus() && policy == Qt::NoFocus)
+ clearFocus();
+ setFlag(ItemIsFocusable, policy != Qt::NoFocus);
+}
+
+/*!
+ If this widget, a child or descendant of this widget currently has input
+ focus, this function will return a pointer to that widget. If
+ no descendant has input focus, 0 is returned.
+
+ \sa QWidget::focusWidget()
+*/
+QGraphicsWidget *QGraphicsWidget::focusWidget() const
+{
+ Q_D(const QGraphicsWidget);
+ return d->focusChild;
+}
+
+
+#ifndef QT_NO_SHORTCUT
+/*!
+ \since 4.5
+
+ Adds a shortcut to Qt's shortcut system that watches for the given key \a
+ sequence in the given \a context. If the \a context is
+ Qt::ApplicationShortcut, the shortcut applies to the application as a
+ whole. Otherwise, it is either local to this widget, Qt::WidgetShortcut,
+ or to the window itself, Qt::WindowShortcut. For widgets that are not part
+ of a window (i.e., top-level widgets and their children),
+ Qt::WindowShortcut shortcuts apply to the scene.
+
+ If the same key \a sequence has been grabbed by several widgets,
+ when the key \a sequence occurs a QEvent::Shortcut event is sent
+ to all the widgets to which it applies in a non-deterministic
+ order, but with the ``ambiguous'' flag set to true.
+
+ \warning You should not normally need to use this function;
+ instead create \l{QAction}s with the shortcut key sequences you
+ require (if you also want equivalent menu options and toolbar
+ buttons), or create \l{QShortcut}s if you just need key sequences.
+ Both QAction and QShortcut handle all the event filtering for you,
+ and provide signals which are triggered when the user triggers the
+ key sequence, so are much easier to use than this low-level
+ function.
+
+ \sa releaseShortcut() setShortcutEnabled() QWidget::grabShortcut()
+*/
+int QGraphicsWidget::grabShortcut(const QKeySequence &sequence, Qt::ShortcutContext context)
+{
+ Q_ASSERT(qApp);
+ if (sequence.isEmpty())
+ return 0;
+ // ### setAttribute(Qt::WA_GrabbedShortcut);
+ return qApp->d_func()->shortcutMap.addShortcut(this, sequence, context);
+}
+
+/*!
+ \since 4.5
+
+ Removes the shortcut with the given \a id from Qt's shortcut
+ system. The widget will no longer receive QEvent::Shortcut events
+ for the shortcut's key sequence (unless it has other shortcuts
+ with the same key sequence).
+
+ \warning You should not normally need to use this function since
+ Qt's shortcut system removes shortcuts automatically when their
+ parent widget is destroyed. It is best to use QAction or
+ QShortcut to handle shortcuts, since they are easier to use than
+ this low-level function. Note also that this is an expensive
+ operation.
+
+ \sa grabShortcut() setShortcutEnabled() , QWidget::releaseShortcut()
+*/
+void QGraphicsWidget::releaseShortcut(int id)
+{
+ Q_ASSERT(qApp);
+ if (id)
+ qApp->d_func()->shortcutMap.removeShortcut(id, this, 0);
+}
+
+/*!
+ \since 4.5
+
+ If \a enabled is true, the shortcut with the given \a id is
+ enabled; otherwise the shortcut is disabled.
+
+ \warning You should not normally need to use this function since
+ Qt's shortcut system enables/disables shortcuts automatically as
+ widgets become hidden/visible and gain or lose focus. It is best
+ to use QAction or QShortcut to handle shortcuts, since they are
+ easier to use than this low-level function.
+
+ \sa grabShortcut() releaseShortcut(), QWidget::setShortcutEnabled()
+*/
+void QGraphicsWidget::setShortcutEnabled(int id, bool enabled)
+{
+ Q_ASSERT(qApp);
+ if (id)
+ qApp->d_func()->shortcutMap.setShortcutEnabled(enabled, id, this, 0);
+}
+
+/*!
+ \since 4.5
+
+ If \a enabled is true, auto repeat of the shortcut with the
+ given \a id is enabled; otherwise it is disabled.
+
+ \sa grabShortcut() releaseShortcut() QWidget::setShortcutAutoRepeat()
+*/
+void QGraphicsWidget::setShortcutAutoRepeat(int id, bool enabled)
+{
+ Q_ASSERT(qApp);
+ if (id)
+ qApp->d_func()->shortcutMap.setShortcutAutoRepeat(enabled, id, this, 0);
+}
+#endif
+
+#ifndef QT_NO_ACTION
+/*!
+ \since 4.5
+
+ Appends the action \a action to this widget's list of actions.
+
+ All QGraphicsWidgets have a list of \l{QAction}s, however they can be
+ represented graphically in many different ways. The default use of the
+ QAction list (as returned by actions()) is to create a context QMenu.
+
+ A QGraphicsWidget should only have one of each action and adding an action
+ it already has will not cause the same action to be in the widget twice.
+
+ \sa removeAction(), insertAction(), actions(), QWidget::addAction()
+*/
+void QGraphicsWidget::addAction(QAction *action)
+{
+ insertAction(0, action);
+}
+
+/*!
+ \since 4.5
+
+ Appends the actions \a actions to this widget's list of actions.
+
+ \sa removeAction(), QMenu, addAction(), QWidget::addActions()
+*/
+void QGraphicsWidget::addActions(QList<QAction *> actions)
+{
+ for (int i = 0; i < actions.count(); ++i)
+ insertAction(0, actions.at(i));
+}
+
+/*!
+ \since 4.5
+
+ Inserts the action \a action to this widget's list of actions,
+ before the action \a before. It appends the action if \a before is 0 or
+ \a before is not a valid action for this widget.
+
+ A QGraphicsWidget should only have one of each action.
+
+ \sa removeAction(), addAction(), QMenu, actions(),
+ QWidget::insertActions()
+*/
+void QGraphicsWidget::insertAction(QAction *before, QAction *action)
+{
+ if (!action) {
+ qWarning("QWidget::insertAction: Attempt to insert null action");
+ return;
+ }
+
+ Q_D(QGraphicsWidget);
+ int index = d->actions.indexOf(action);
+ if (index != -1)
+ d->actions.removeAt(index);
+
+ int pos = d->actions.indexOf(before);
+ if (pos < 0) {
+ before = 0;
+ pos = d->actions.size();
+ }
+ d->actions.insert(pos, action);
+
+ QActionPrivate *apriv = action->d_func();
+ apriv->graphicsWidgets.append(this);
+
+ QActionEvent e(QEvent::ActionAdded, action, before);
+ QApplication::sendEvent(this, &e);
+}
+
+/*!
+ \since 4.5
+
+ Inserts the actions \a actions to this widget's list of actions,
+ before the action \a before. It appends the action if \a before is 0 or
+ \a before is not a valid action for this widget.
+
+ A QGraphicsWidget can have at most one of each action.
+
+ \sa removeAction(), QMenu, insertAction(), QWidget::insertActions()
+*/
+void QGraphicsWidget::insertActions(QAction *before, QList<QAction *> actions)
+{
+ for (int i = 0; i < actions.count(); ++i)
+ insertAction(before, actions.at(i));
+}
+
+/*!
+ \since 4.5
+
+ Removes the action \a action from this widget's list of actions.
+
+ \sa insertAction(), actions(), insertAction(), QWidget::removeAction()
+*/
+void QGraphicsWidget::removeAction(QAction *action)
+{
+ if (!action)
+ return;
+
+ Q_D(QGraphicsWidget);
+
+ QActionPrivate *apriv = action->d_func();
+ apriv->graphicsWidgets.removeAll(this);
+
+ if (d->actions.removeAll(action)) {
+ QActionEvent e(QEvent::ActionRemoved, action);
+ QApplication::sendEvent(this, &e);
+ }
+}
+
+/*!
+ \since 4.5
+
+ Returns the (possibly empty) list of this widget's actions.
+
+ \sa insertAction(), removeAction(), QWidget::actions(),
+ QAction::associatedWidgets(), QAction::associatedGraphicsWidgets()
+*/
+QList<QAction *> QGraphicsWidget::actions() const
+{
+ Q_D(const QGraphicsWidget);
+ return d->actions;
+}
+#endif
+
+/*!
+ Moves the \a second widget around the ring of focus widgets so that
+ keyboard focus moves from the \a first widget to the \a second widget when
+ the Tab key is pressed.
+
+ Note that since the tab order of the \a second widget is changed, you
+ should order a chain like this:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicswidget.cpp 1
+
+ \e not like this:
+
+ \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicswidget.cpp 2
+
+ If \a first is 0, this indicates that \a second should be the first widget
+ to receive input focus should the scene gain Tab focus (i.e., the user
+ hits Tab so that focus passes into the scene). If \a second is 0, this
+ indicates that \a first should be the first widget to gain focus if the
+ scene gained BackTab focus.
+
+ By default, tab order is defined implicitly using widget creation order.
+
+ \sa focusPolicy, {Keyboard Focus}
+*/
+void QGraphicsWidget::setTabOrder(QGraphicsWidget *first, QGraphicsWidget *second)
+{
+ if (!first && !second) {
+ qWarning("QGraphicsWidget::setTabOrder(0, 0) is undefined");
+ return;
+ }
+ if ((first && second) && first->scene() != second->scene()) {
+ qWarning("QGraphicsWidget::setTabOrder: scenes %p and %p are different",
+ first->scene(), second->scene());
+ return;
+ }
+ QGraphicsScene *scene = first ? first->scene() : second->scene();
+ if (!scene && (!first || !second)) {
+ qWarning("QGraphicsWidget::setTabOrder: assigning tab order from/to the"
+ " scene requires the item to be in a scene.");
+ return;
+ }
+
+ // If either first or second are 0, the scene's tabFocusFirst is updated
+ // to point to the first item in the scene's focus chain. Then first or
+ // second are set to point to tabFocusFirst.
+ QGraphicsScenePrivate *sceneD = scene->d_func();
+ if (!first) {
+ sceneD->tabFocusFirst = second;
+ return;
+ }
+ if (!second) {
+ sceneD->tabFocusFirst = first->d_func()->focusNext;
+ return;
+ }
+
+ // Both first and second are != 0.
+ QGraphicsWidget *firstFocusNext = first->d_func()->focusNext;
+ if (firstFocusNext == second) {
+ // Nothing to do.
+ return;
+ }
+
+ // Update the focus chain.
+ QGraphicsWidget *secondFocusPrev = second->d_func()->focusPrev;
+ QGraphicsWidget *secondFocusNext = second->d_func()->focusNext;
+ firstFocusNext->d_func()->focusPrev = second;
+ first->d_func()->focusNext = second;
+ second->d_func()->focusNext = firstFocusNext;
+ second->d_func()->focusPrev = first;
+ secondFocusPrev->d_func()->focusNext = secondFocusNext;
+ secondFocusNext->d_func()->focusPrev = secondFocusPrev;
+
+ Q_ASSERT(first->d_func()->focusNext->d_func()->focusPrev == first);
+ Q_ASSERT(first->d_func()->focusPrev->d_func()->focusNext == first);
+
+ Q_ASSERT(second->d_func()->focusNext->d_func()->focusPrev == second);
+ Q_ASSERT(second->d_func()->focusPrev->d_func()->focusNext == second);
+
+}
+
+/*!
+ If \a on is true, this function enables \a attribute; otherwise
+ \a attribute is disabled.
+
+ See the class documentation for QGraphicsWidget for a complete list of
+ which attributes are supported, and what they are for.
+
+ \sa testAttribute(), QWidget::setAttribute()
+*/
+void QGraphicsWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
+{
+ Q_D(QGraphicsWidget);
+ // ### most flags require some immediate action
+ // ### we might want to qWarn use of unsupported attributes
+ // ### we might want to not use Qt::WidgetAttribute, but roll our own instead
+ d->setAttribute(attribute, on);
+}
+
+/*!
+ Returns true if \a attribute is enabled for this widget; otherwise,
+ returns false.
+
+ \sa setAttribute()
+*/
+bool QGraphicsWidget::testAttribute(Qt::WidgetAttribute attribute) const
+{
+ Q_D(const QGraphicsWidget);
+ return d->testAttribute(attribute);
+}
+
+/*!
+ \reimp
+*/
+int QGraphicsWidget::type() const
+{
+ return Type;
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(painter);
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+}
+
+/*!
+ This virtual function is called by QGraphicsScene to draw the window frame
+ for windows using \a painter, \a option, and \a widget, in local
+ coordinates. The base implementation uses the current style to render the
+ frame and title bar.
+
+ You can reimplement this function in a subclass of QGraphicsWidget to
+ provide custom rendering of the widget's window frame.
+
+ \sa QGraphicsItem::paint()
+*/
+void QGraphicsWidget::paintWindowFrame(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
+{
+ const bool fillBackground = !testAttribute(Qt::WA_OpaquePaintEvent)
+ && !testAttribute(Qt::WA_NoSystemBackground);
+ QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(this);
+ const bool embeddedWidgetFillsOwnBackground = proxy && proxy->widget();
+
+ if (rect().contains(option->exposedRect)) {
+ if (fillBackground && !embeddedWidgetFillsOwnBackground)
+ painter->fillRect(option->exposedRect, palette().window());
+ return;
+ }
+
+ Q_D(QGraphicsWidget);
+
+ QRect windowFrameRect = QRect(QPoint(), windowFrameGeometry().size().toSize());
+ QStyleOptionTitleBar bar;
+ bar.QStyleOption::operator=(*option);
+ d->initStyleOptionTitleBar(&bar); // this clear flags in bar.state
+ if (d->buttonMouseOver)
+ bar.state |= QStyle::State_MouseOver;
+ else
+ bar.state &= ~QStyle::State_MouseOver;
+ if (d->buttonSunken)
+ bar.state |= QStyle::State_Sunken;
+ else
+ bar.state &= ~QStyle::State_Sunken;
+
+ bar.rect = windowFrameRect;
+
+ // translate painter to make the style happy
+ const QPointF styleOrigin = this->windowFrameRect().topLeft();
+ painter->translate(styleOrigin);
+
+#ifdef Q_WS_MAC
+ const QSize pixmapSize = windowFrameRect.size();
+ if (pixmapSize.width() <= 0 || pixmapSize.height() <= 0)
+ return;
+ QPainter *realPainter = painter;
+ QPixmap pm(pixmapSize);
+ painter = new QPainter(&pm);
+#endif
+
+ // Fill background
+ QStyleHintReturnMask mask;
+ bool setMask = style()->styleHint(QStyle::SH_WindowFrame_Mask, &bar, widget, &mask) && !mask.region.isEmpty();
+ bool hasBorder = !style()->styleHint(QStyle::SH_TitleBar_NoBorder, &bar, widget);
+ int frameWidth = style()->pixelMetric(QStyle::PM_MDIFrameWidth, &bar, widget);
+ if (setMask) {
+ painter->save();
+ painter->setClipRegion(mask.region, Qt::IntersectClip);
+ }
+ if (fillBackground) {
+ if (embeddedWidgetFillsOwnBackground) {
+ // Don't fill the background twice.
+ QPainterPath windowFrameBackground;
+ windowFrameBackground.addRect(windowFrameRect);
+ // Adjust with 0.5 to avoid border artifacts between
+ // widget background and frame background.
+ windowFrameBackground.addRect(rect().translated(-styleOrigin).adjusted(0.5, 0.5, -0.5, -0.5));
+ painter->fillPath(windowFrameBackground, palette().window());
+ } else {
+ painter->fillRect(windowFrameRect, palette().window());
+ }
+ }
+ painter->setRenderHint(QPainter::NonCosmeticDefaultPen);
+
+ // Draw title
+ int height = (int)d->titleBarHeight(bar);
+ bar.rect.setHeight(height);
+ if (hasBorder) // Frame is painted by PE_FrameWindow
+ bar.rect.adjust(frameWidth, frameWidth, -frameWidth, 0);
+
+ painter->save();
+ painter->setFont(QApplication::font("QWorkspaceTitleBar"));
+ style()->drawComplexControl(QStyle::CC_TitleBar, &bar, painter, widget);
+ painter->restore();
+ if (setMask)
+ painter->restore();
+ // Draw window frame
+ QStyleOptionFrame frameOptions;
+ frameOptions.QStyleOption::operator=(*option);
+ initStyleOption(&frameOptions);
+ if (!hasBorder)
+ painter->setClipRect(windowFrameRect.adjusted(0, +height, 0, 0), Qt::IntersectClip);
+ if (hasFocus()) {
+ frameOptions.state |= QStyle::State_HasFocus;
+ } else {
+ frameOptions.state &= ~QStyle::State_HasFocus;
+ }
+ bool isActive = isActiveWindow();
+ if (isActive) {
+ frameOptions.state |= QStyle::State_Active;
+ } else {
+ frameOptions.state &= ~QStyle::State_Active;
+ }
+
+ frameOptions.palette.setCurrentColorGroup(isActive ? QPalette::Active : QPalette::Normal);
+ frameOptions.rect = windowFrameRect;
+ frameOptions.lineWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, widget);
+ frameOptions.midLineWidth = 1;
+ style()->drawPrimitive(QStyle::PE_FrameWindow, &frameOptions, painter, widget);
+
+#ifdef Q_WS_MAC
+ realPainter->drawPixmap(QPoint(), pm);
+ delete painter;
+#endif
+}
+
+/*!
+ \reimp
+*/
+QRectF QGraphicsWidget::boundingRect() const
+{
+ return windowFrameRect();
+}
+
+/*!
+ \reimp
+*/
+QPainterPath QGraphicsWidget::shape() const
+{
+ QPainterPath path;
+ path.addRect(rect());
+ return path;
+}
+
+/*!
+ Call this function to close the widget.
+
+ Returns true if the widget was closed; otherwise returns false.
+ This slot will first send a QCloseEvent to the widget, which may or may
+ not accept the event. If the event was ignored, nothing happens. If the
+ event was accepted, it will hide() the widget.
+
+ If the widget has the Qt::WA_DeleteOnClose attribute set it will be
+ deleted.
+*/
+bool QGraphicsWidget::close()
+{
+ QCloseEvent closeEvent;
+ QApplication::sendEvent(this, &closeEvent);
+ if (!closeEvent.isAccepted()) {
+ return false;
+ }
+ // hide
+ if (isVisible()) {
+ hide();
+ }
+ if (testAttribute(Qt::WA_DeleteOnClose)) {
+ deleteLater();
+ }
+ return true;
+}
+
+#ifdef Q_NO_USING_KEYWORD
+/*!
+ \fn const QObjectList &QGraphicsWidget::children() const
+
+ 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.
+*/
+#endif
+
+#if 0
+void QGraphicsWidget::dumpFocusChain()
+{
+ qDebug() << "=========== Dumping focus chain ==============";
+ int i = 0;
+ QGraphicsWidget *next = this;
+ QSet<QGraphicsWidget*> visited;
+ do {
+ if (!next) {
+ qWarning("Found a focus chain that is not circular, (next == 0)");
+ break;
+ }
+ qDebug() << i++ << QString::number(uint(next), 16) << next->className() << next->data(0) << QString::fromAscii("focusItem:%1").arg(next->hasFocus() ? "1" : "0") << QLatin1String("next:") << next->d_func()->focusNext->data(0) << QLatin1String("prev:") << next->d_func()->focusPrev->data(0);
+ if (visited.contains(next)) {
+ qWarning("Already visited this node. However, I expected to dump until I found myself.");
+ break;
+ }
+ visited << next;
+ next = next->d_func()->focusNext;
+ } while (next != this);
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicswidget.h b/src/gui/graphicsview/qgraphicswidget.h
new file mode 100644
index 0000000..05195b6
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicswidget.h
@@ -0,0 +1,255 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSWIDGET_H
+#define QGRAPHICSWIDGET_H
+
+#include <QtGui/qfont.h>
+#include <QtGui/qgraphicslayoutitem.h>
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/qpalette.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QFont;
+class QFontMetrics;
+class QGraphicsLayout;
+class QGraphicsSceneMoveEvent;
+class QGraphicsWidgetPrivate;
+class QGraphicsSceneResizeEvent;
+class QGraphicsWidgetAnimator;
+class QStyle;
+class QStyleOption;
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+class QGraphicsWidgetPrivate;
+
+class Q_GUI_EXPORT QGraphicsWidget : public QObject, public QGraphicsItem, public QGraphicsLayoutItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QPalette palette READ palette WRITE setPalette)
+ Q_PROPERTY(QFont font READ font WRITE setFont)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection RESET unsetLayoutDirection)
+ Q_PROPERTY(QSizeF size READ size WRITE resize)
+ Q_PROPERTY(Qt::FocusPolicy focusPolicy READ focusPolicy WRITE setFocusPolicy)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible)
+ Q_PROPERTY(Qt::WindowFlags windowFlags READ windowFlags WRITE setWindowFlags)
+ Q_PROPERTY(QString windowTitle READ windowTitle WRITE setWindowTitle)
+ Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)
+ Q_PROPERTY(QPointF pos READ pos WRITE setPos)
+ Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry)
+ Q_PROPERTY(qreal xScale READ xScale WRITE setXScale)
+ Q_PROPERTY(qreal yScale READ yScale WRITE setYScale)
+ Q_PROPERTY(qreal zRotation READ zRotation WRITE setZRotation)
+ Q_PROPERTY(qreal xRotation READ xRotation WRITE setXRotation)
+ Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation)
+
+public:
+ QGraphicsWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0);
+ ~QGraphicsWidget();
+
+ QGraphicsLayout *layout() const;
+ void setLayout(QGraphicsLayout *layout);
+ void adjustSize();
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection(Qt::LayoutDirection direction);
+ void unsetLayoutDirection();
+
+ QStyle *style() const;
+ void setStyle(QStyle *style);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QPalette palette() const;
+ void setPalette(const QPalette &palette);
+
+ void resize(const QSizeF &size);
+ inline void resize(qreal w, qreal h) { resize(QSizeF(w, h)); }
+ QSizeF size() const;
+
+ void setGeometry(const QRectF &rect);
+ inline void setGeometry(qreal x, qreal y, qreal w, qreal h);
+ inline QRectF rect() const { return QRectF(QPointF(), size()); }
+
+ void setContentsMargins(qreal left, qreal top, qreal right, qreal bottom);
+ void getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const;
+
+ void setWindowFrameMargins(qreal left, qreal top, qreal right, qreal bottom);
+ void getWindowFrameMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const;
+ void unsetWindowFrameMargins();
+ QRectF windowFrameGeometry() const;
+ QRectF windowFrameRect() const;
+
+ // Window handling
+ Qt::WindowFlags windowFlags() const;
+ Qt::WindowType windowType() const;
+ void setWindowFlags(Qt::WindowFlags wFlags);
+ bool isActiveWindow() const;
+ void setWindowTitle(const QString &title);
+ QString windowTitle() const;
+
+ // Focus handling
+ Qt::FocusPolicy focusPolicy() const;
+ void setFocusPolicy(Qt::FocusPolicy policy);
+ static void setTabOrder(QGraphicsWidget *first, QGraphicsWidget *second);
+ QGraphicsWidget *focusWidget() const;
+
+#ifndef QT_NO_SHORTCUT
+ int grabShortcut(const QKeySequence &sequence, Qt::ShortcutContext context = Qt::WindowShortcut);
+ void releaseShortcut(int id);
+ void setShortcutEnabled(int id, bool enabled = true);
+ void setShortcutAutoRepeat(int id, bool enabled = true);
+#endif
+
+#ifndef QT_NO_ACTION
+ //actions
+ void addAction(QAction *action);
+ void addActions(QList<QAction*> actions);
+ void insertAction(QAction *before, QAction *action);
+ void insertActions(QAction *before, QList<QAction*> actions);
+ void removeAction(QAction *action);
+ QList<QAction*> actions() const;
+#endif
+
+ void setAttribute(Qt::WidgetAttribute attribute, bool on = true);
+ bool testAttribute(Qt::WidgetAttribute attribute) const;
+
+ enum {
+ Type = 11
+ };
+ int type() const;
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+ virtual void paintWindowFrame(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+
+#if 0
+ void dumpFocusChain();
+#endif
+
+ // ### Qt 5: Disambiguate
+#ifdef Q_NO_USING_KEYWORD
+ const QObjectList &children() const { return QObject::children(); }
+#else
+ using QObject::children;
+#endif
+
+public Q_SLOTS:
+ bool close();
+
+protected:
+ virtual void initStyleOption(QStyleOption *option) const;
+
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+ void updateGeometry();
+
+ // Notification
+ QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+ virtual QVariant propertyChange(const QString &propertyName, const QVariant &value);
+
+ // Scene events
+ bool sceneEvent(QEvent *event);
+ virtual bool windowFrameEvent(QEvent *e);
+ virtual Qt::WindowFrameSection windowFrameSectionAt(const QPointF& pos) const;
+
+ // Base event handlers
+ bool event(QEvent *event);
+ //virtual void actionEvent(QActionEvent *event);
+ virtual void changeEvent(QEvent *event);
+ virtual void closeEvent(QCloseEvent *event);
+ //void create(WId window = 0, bool initializeWindow = true, bool destroyOldWindow = true);
+ //void destroy(bool destroyWindow = true, bool destroySubWindows = true);
+ void focusInEvent(QFocusEvent *event);
+ virtual bool focusNextPrevChild(bool next);
+ void focusOutEvent(QFocusEvent *event);
+ virtual void hideEvent(QHideEvent *event);
+ //virtual bool macEvent(EventHandlerCallRef caller, EventRef event);
+ //virtual int metric(PaintDeviceMetric m ) const;
+ virtual void moveEvent(QGraphicsSceneMoveEvent *event);
+ virtual void polishEvent();
+ //virtual bool qwsEvent(QWSEvent *event);
+ //void resetInputContext ();
+ virtual void resizeEvent(QGraphicsSceneResizeEvent *event);
+ virtual void showEvent(QShowEvent *event);
+ //virtual void tabletEvent(QTabletEvent *event);
+ //virtual bool winEvent(MSG *message, long *result);
+ //virtual bool x11Event(XEvent *event);
+ virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void grabMouseEvent(QEvent *event);
+ virtual void ungrabMouseEvent(QEvent *event);
+ virtual void grabKeyboardEvent(QEvent *event);
+ virtual void ungrabKeyboardEvent(QEvent *event);
+ QGraphicsWidget(QGraphicsWidgetPrivate &, QGraphicsItem *parent, QGraphicsScene *, Qt::WindowFlags wFlags = 0);
+
+private:
+ Q_DISABLE_COPY(QGraphicsWidget)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr, QGraphicsWidget)
+ friend class QGraphicsScene;
+ friend class QGraphicsScenePrivate;
+ friend class QGraphicsView;
+ friend class QGraphicsItem;
+ friend class QGraphicsItemPrivate;
+ friend class QGraphicsLayout;
+ friend class QWidget;
+ friend class QApplication;
+};
+
+inline void QGraphicsWidget::setGeometry(qreal ax, qreal ay, qreal aw, qreal ah)
+{ setGeometry(QRectF(ax, ay, aw, ah)); }
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
+
diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp
new file mode 100644
index 0000000..641409d
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicswidget_p.cpp
@@ -0,0 +1,740 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include <QtCore/qdebug.h>
+#include "qgraphicswidget_p.h"
+#include "qgraphicslayout.h"
+#include "qgraphicsscene_p.h"
+#include <QtGui/qapplication.h>
+#include <QtGui/qgraphicsscene.h>
+#include <QtGui/qstyleoption.h>
+#include <QtGui/QStyleOptionTitleBar>
+#include <QtGui/QGraphicsSceneMouseEvent>
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+# include <QMacStyle>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+void QGraphicsWidgetPrivate::init(QGraphicsItem *parentItem, Qt::WindowFlags wFlags)
+{
+ Q_Q(QGraphicsWidget);
+
+ attributes = 0;
+ isWidget = 1; // QGraphicsItem::isWidget() returns true.
+ focusNext = focusPrev = q;
+ focusPolicy = Qt::NoFocus;
+ q->setParentItem(parentItem);
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::DefaultType));
+ q->setGraphicsItem(q);
+
+ resolveLayoutDirection();
+
+ if (!parentItem)
+ adjustWindowFlags(&wFlags);
+ windowFlags = wFlags;
+ q->unsetWindowFrameMargins();
+}
+qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const
+{
+ Q_Q(const QGraphicsWidget);
+ int height = q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options);
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ if (qobject_cast<QMacStyle*>(q->style())) {
+ height -=4;
+ }
+#endif
+ return (qreal)height;
+}
+
+void QGraphicsWidgetPrivate::getLayoutItemMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
+{
+ if (left)
+ *left = leftLayoutItemMargin;
+ if (top)
+ *top = topLayoutItemMargin;
+ if (right)
+ *right = rightLayoutItemMargin;
+ if (bottom)
+ *bottom = bottomLayoutItemMargin;
+}
+
+void QGraphicsWidgetPrivate::setLayoutItemMargins(qreal left, qreal top, qreal right, qreal bottom)
+{
+ if (leftLayoutItemMargin == left
+ && topLayoutItemMargin == top
+ && rightLayoutItemMargin == right
+ && bottomLayoutItemMargin == bottom)
+ return;
+
+ Q_Q(QGraphicsWidget);
+ leftLayoutItemMargin = left;
+ topLayoutItemMargin = top;
+ rightLayoutItemMargin = right;
+ bottomLayoutItemMargin = bottom;
+ q->updateGeometry();
+}
+
+void QGraphicsWidgetPrivate::setLayoutItemMargins(QStyle::SubElement element, const QStyleOption *opt)
+{
+ Q_Q(QGraphicsWidget);
+ QStyleOption myOpt;
+ if (!opt) {
+ q->initStyleOption(&myOpt);
+ myOpt.rect.setRect(0, 0, 32768, 32768); // arbitrary
+ opt = &myOpt;
+ }
+
+ QRect liRect = q->style()->subElementRect(element, opt, /* q */ 0);
+ if (liRect.isValid()) {
+ leftLayoutItemMargin = (opt->rect.left() - liRect.left());
+ topLayoutItemMargin = (opt->rect.top() - liRect.top());
+ rightLayoutItemMargin = (liRect.right() - opt->rect.right());
+ bottomLayoutItemMargin = (liRect.bottom() - opt->rect.bottom());
+ } else {
+ leftLayoutItemMargin = 0;
+ topLayoutItemMargin = 0;
+ rightLayoutItemMargin = 0;
+ bottomLayoutItemMargin = 0;
+ }
+}
+
+void QGraphicsWidgetPrivate::setPalette_helper(const QPalette &palette)
+{
+ if (this->palette == palette && this->palette.resolve() == palette.resolve())
+ return;
+ updatePalette(palette);
+}
+
+void QGraphicsWidgetPrivate::resolvePalette(uint inheritedMask)
+{
+ inheritedPaletteResolveMask = inheritedMask;
+ QPalette naturalPalette = naturalWidgetPalette();
+ QPalette resolvedPalette = palette.resolve(naturalPalette);
+ updatePalette(resolvedPalette);
+}
+
+void QGraphicsWidgetPrivate::updatePalette(const QPalette &palette)
+{
+ Q_Q(QGraphicsWidget);
+ // Update local palette setting.
+ this->palette = palette;
+
+ // Calculate new mask.
+ if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation))
+ inheritedPaletteResolveMask = 0;
+ int mask = palette.resolve() | inheritedPaletteResolveMask;
+
+ // Propagate to children.
+ for (int i = 0; i < children.size(); ++i) {
+ QGraphicsItem *item = children.at(i);
+ if (item->isWidget()) {
+ QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item);
+ if (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
+ w->d_func()->resolvePalette(mask);
+ } else {
+ item->d_ptr->resolvePalette(mask);
+ }
+ }
+
+ // Notify change.
+ QEvent event(QEvent::PaletteChange);
+ QApplication::sendEvent(q, &event);
+}
+
+void QGraphicsWidgetPrivate::setLayoutDirection_helper(Qt::LayoutDirection direction)
+{
+ Q_Q(QGraphicsWidget);
+ if ((direction == Qt::RightToLeft) == (testAttribute(Qt::WA_RightToLeft)))
+ return;
+ q->setAttribute(Qt::WA_RightToLeft, (direction == Qt::RightToLeft));
+
+ // Propagate this change to all children.
+ for (int i = 0; i < children.size(); ++i) {
+ QGraphicsItem *item = children.at(i);
+ if (item->isWidget()) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
+ if (widget->parentWidget() && !widget->testAttribute(Qt::WA_SetLayoutDirection))
+ widget->d_func()->setLayoutDirection_helper(direction);
+ }
+ }
+
+ // Send the notification event to this widget item.
+ QEvent e(QEvent::LayoutDirectionChange);
+ QApplication::sendEvent(q, &e);
+}
+
+void QGraphicsWidgetPrivate::resolveLayoutDirection()
+{
+ Q_Q(QGraphicsWidget);
+ if (q->testAttribute(Qt::WA_SetLayoutDirection)) {
+ return;
+ }
+ if (QGraphicsWidget *parentWidget = q->parentWidget()) {
+ setLayoutDirection_helper(parentWidget->layoutDirection());
+ } else if (scene) {
+ // ### shouldn't the scene have a layoutdirection really? how does
+ // ### QGraphicsWidget get changes from QApplication::layoutDirection?
+ setLayoutDirection_helper(QApplication::layoutDirection());
+ } else {
+ setLayoutDirection_helper(QApplication::layoutDirection());
+ }
+}
+
+QPalette QGraphicsWidgetPrivate::naturalWidgetPalette() const
+{
+ Q_Q(const QGraphicsWidget);
+ QPalette palette;
+ if (QGraphicsWidget *parent = q->parentWidget()) {
+ palette = parent->palette();
+ } else if (scene) {
+ palette = scene->palette();
+ }
+ palette.resolve(0);
+ return palette;
+}
+
+void QGraphicsWidgetPrivate::setFont_helper(const QFont &font)
+{
+ if (this->font == font && this->font.resolve() == font.resolve())
+ return;
+ updateFont(font);
+}
+
+void QGraphicsWidgetPrivate::resolveFont(uint inheritedMask)
+{
+ inheritedFontResolveMask = inheritedMask;
+ QFont naturalFont = naturalWidgetFont();
+ QFont resolvedFont = font.resolve(naturalFont);
+ updateFont(resolvedFont);
+}
+
+void QGraphicsWidgetPrivate::updateFont(const QFont &font)
+{
+ Q_Q(QGraphicsWidget);
+ // Update the local font setting.
+ this->font = font;
+
+ // Calculate new mask.
+ if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation))
+ inheritedFontResolveMask = 0;
+ int mask = font.resolve() | inheritedFontResolveMask;
+
+ // Propagate to children.
+ for (int i = 0; i < children.size(); ++i) {
+ QGraphicsItem *item = children.at(i);
+ if (item->isWidget()) {
+ QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item);
+ if (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
+ w->d_func()->resolveFont(mask);
+ } else {
+ item->d_ptr->resolveFont(mask);
+ }
+ }
+
+ // Notify change.
+ QEvent event(QEvent::FontChange);
+ QApplication::sendEvent(q, &event);
+}
+
+QFont QGraphicsWidgetPrivate::naturalWidgetFont() const
+{
+ Q_Q(const QGraphicsWidget);
+ QFont naturalFont; // ### no application font support
+ if (QGraphicsWidget *parent = q->parentWidget()) {
+ naturalFont = parent->font();
+ } else if (scene) {
+ naturalFont = scene->font();
+ }
+ naturalFont.resolve(0);
+ return naturalFont;
+}
+
+void QGraphicsWidgetPrivate::initStyleOptionTitleBar(QStyleOptionTitleBar *option)
+{
+ Q_Q(QGraphicsWidget);
+ q->initStyleOption(option);
+ option->rect.setHeight(titleBarHeight(*option));
+ option->titleBarFlags = windowFlags;
+ option->subControls = QStyle::SC_TitleBarCloseButton | QStyle::SC_TitleBarLabel | QStyle::SC_TitleBarSysMenu;
+ option->activeSubControls = hoveredSubControl;
+ bool isActive = q->isActiveWindow();
+ if (isActive) {
+ option->state |= QStyle::State_Active;
+ option->titleBarState = Qt::WindowActive;
+ option->titleBarState |= QStyle::State_Active;
+ } else {
+ option->state &= ~QStyle::State_Active;
+ option->titleBarState = Qt::WindowNoState;
+ }
+ QFont windowTitleFont = QApplication::font("QWorkspaceTitleBar");
+ QRect textRect = q->style()->subControlRect(QStyle::CC_TitleBar, option, QStyle::SC_TitleBarLabel, 0);
+ option->text = QFontMetrics(windowTitleFont).elidedText(windowTitle, Qt::ElideRight, textRect.width());
+}
+
+void QGraphicsWidgetPrivate::adjustWindowFlags(Qt::WindowFlags *flags)
+{
+ bool customize = (*flags & (Qt::CustomizeWindowHint
+ | Qt::FramelessWindowHint
+ | Qt::WindowTitleHint
+ | Qt::WindowSystemMenuHint
+ | Qt::WindowMinimizeButtonHint
+ | Qt::WindowMaximizeButtonHint
+ | Qt::WindowContextHelpButtonHint));
+
+ uint type = (*flags & Qt::WindowType_Mask);
+ if (customize)
+ ;
+ else if (type == Qt::Dialog || type == Qt::Sheet)
+ *flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowContextHelpButtonHint;
+ else if (type == Qt::Tool)
+ *flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint;
+ else if (type == Qt::Window || type == Qt::SubWindow)
+ *flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
+ | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint;
+}
+
+void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QGraphicsWidget);
+ if (grabbedSection != Qt::NoSection) {
+ if (grabbedSection == Qt::TitleBarArea) {
+ buttonSunken = false;
+ QStyleOptionTitleBar bar;
+ initStyleOptionTitleBar(&bar);
+ // make sure that the coordinates (rect and pos) we send to the style are positive.
+ bar.rect = q->windowFrameRect().toRect();
+ bar.rect.moveTo(0,0);
+ bar.rect.setHeight(q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &bar));
+ QPointF pos = event->pos();
+ pos.rx() += leftWindowFrameMargin;
+ pos.ry() += topWindowFrameMargin;
+ bar.subControls = QStyle::SC_TitleBarCloseButton;
+ if (q->style()->subControlRect(QStyle::CC_TitleBar, &bar,
+ QStyle::SC_TitleBarCloseButton,
+ event->widget()).contains(pos.toPoint())) {
+ q->close();
+ }
+ }
+ if (!(static_cast<QGraphicsSceneMouseEvent *>(event)->buttons()))
+ grabbedSection = Qt::NoSection;
+ event->accept();
+ }
+}
+
+void QGraphicsWidgetPrivate::windowFrameMousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QGraphicsWidget);
+ if (event->button() != Qt::LeftButton)
+ return;
+
+ startGeometry = q->geometry();
+ grabbedSection = q->windowFrameSectionAt(event->pos());
+ switch (grabbedSection) {
+ case Qt::LeftSection:
+ case Qt::TopLeftSection:
+ mouseDelta = event->pos() - q->rect().topLeft();
+ break;
+ case Qt::TopSection:
+ case Qt::TopRightSection:
+ mouseDelta = event->pos() - q->rect().topRight();
+ break;
+ case Qt::RightSection:
+ case Qt::BottomRightSection:
+ mouseDelta = event->pos() - q->rect().bottomRight();
+ break;
+ case Qt::BottomSection:
+ case Qt::BottomLeftSection:
+ mouseDelta = event->pos() - q->rect().bottomLeft();
+ break;
+ case Qt::TitleBarArea:
+ if (hoveredSubControl == QStyle::SC_TitleBarCloseButton) {
+ buttonSunken = true;
+ q->update();
+ }
+ break;
+ case Qt::NoSection:
+ break;
+ }
+ event->setAccepted(grabbedSection != Qt::NoSection);
+}
+
+static void _q_boundGeometryToSizeConstraints(const QRectF &startGeometry,
+ QRectF *rect, Qt::WindowFrameSection section,
+ const QSizeF &min, const QSizeF &max)
+{
+ int height;
+ int width;
+ switch (section) {
+ case Qt::LeftSection:
+ width = qRound(qBound(min.width(), rect->width(), max.width()));
+ rect->setRect(startGeometry.right() - width, startGeometry.top(),
+ width, startGeometry.height());
+ break;
+ case Qt::TopLeftSection:
+ width = qRound(qBound(min.width(), rect->width(), max.width()));
+ height = qRound(qBound(min.height(), rect->height(), max.height()));
+ rect->setRect(startGeometry.right() - width, startGeometry.bottom() - height,
+ width, height);
+ break;
+ case Qt::TopSection:
+ height = qRound(qBound(min.height(), rect->height(), max.height()));
+ rect->setRect(startGeometry.left(), startGeometry.bottom() - height,
+ startGeometry.width(), height);
+ break;
+ case Qt::TopRightSection:
+ height = qRound(qBound(min.height(), rect->height(), max.height()));
+ rect->setTop(rect->bottom() - height);
+ rect->setWidth(qBound(min.width(), rect->width(), max.width()));
+ break;
+ case Qt::RightSection:
+ rect->setWidth(qBound(min.width(), rect->width(), max.width()));
+ break;
+ case Qt::BottomRightSection:
+ rect->setWidth(qBound(min.width(), rect->width(), max.width()));
+ rect->setHeight(qBound(min.height(), rect->height(), max.height()));
+ break;
+ case Qt::BottomSection:
+ rect->setHeight(qBound(min.height(), rect->height(), max.height()));
+ break;
+ case Qt::BottomLeftSection:
+ height = qRound(qBound(min.height(), rect->height(), max.height()));
+ width = qRound(qBound(min.width(), rect->width(), max.width()));
+ rect->setRect(startGeometry.right() - width, startGeometry.top(),
+ width, height);
+ break;
+ default:
+ break;
+ }
+}
+
+void QGraphicsWidgetPrivate::windowFrameMouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QGraphicsWidget);
+ if (!(event->buttons() & Qt::LeftButton) || hoveredSubControl != QStyle::SC_TitleBarLabel)
+ return;
+
+ QLineF delta(q->mapFromScene(event->buttonDownScenePos(Qt::LeftButton)), event->pos());
+ QLineF parentDelta(q->mapToParent(delta.p1()), q->mapToParent(delta.p2()));
+ QLineF parentXDelta(q->mapToParent(QPointF(delta.p1().x(), 0)), q->mapToParent(QPointF(delta.p2().x(), 0)));
+ QLineF parentYDelta(q->mapToParent(QPointF(0, delta.p1().y())), q->mapToParent(QPointF(0, delta.p2().y())));
+
+ QRectF newGeometry;
+ switch (grabbedSection) {
+ case Qt::LeftSection:
+ newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentXDelta.dx(), parentXDelta.dy()),
+ startGeometry.size() - QSizeF(delta.dx(), delta.dy()));
+ break;
+ case Qt::TopLeftSection:
+ newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentDelta.dx(), parentDelta.dy()),
+ startGeometry.size() - QSizeF(delta.dx(), delta.dy()));
+ break;
+ case Qt::TopSection:
+ newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentYDelta.dx(), parentYDelta.dy()),
+ startGeometry.size() - QSizeF(0, delta.dy()));
+ break;
+ case Qt::TopRightSection:
+ newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentYDelta.dx(), parentYDelta.dy()),
+ startGeometry.size() - QSizeF(-delta.dx(), delta.dy()));
+ break;
+ case Qt::RightSection:
+ newGeometry = QRectF(startGeometry.topLeft(),
+ startGeometry.size() + QSizeF(delta.dx(), 0));
+ break;
+ case Qt::BottomRightSection:
+ newGeometry = QRectF(startGeometry.topLeft(),
+ startGeometry.size() + QSizeF(delta.dx(), delta.dy()));
+ break;
+ case Qt::BottomSection:
+ newGeometry = QRectF(startGeometry.topLeft(),
+ startGeometry.size() + QSizeF(0, delta.dy()));
+ break;
+ case Qt::BottomLeftSection:
+ newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentXDelta.dx(), parentXDelta.dy()),
+ startGeometry.size() - QSizeF(delta.dx(), -delta.dy()));
+ break;
+ case Qt::TitleBarArea:
+ newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentDelta.dx(), parentDelta.dy()),
+ startGeometry.size());
+ break;
+ case Qt::NoSection:
+ break;
+ }
+
+ if (grabbedSection != Qt::NoSection) {
+ _q_boundGeometryToSizeConstraints(startGeometry, &newGeometry, grabbedSection,
+ q->effectiveSizeHint(Qt::MinimumSize),
+ q->effectiveSizeHint(Qt::MaximumSize));
+ q->setGeometry(newGeometry);
+ }
+}
+
+void QGraphicsWidgetPrivate::windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_Q(QGraphicsWidget);
+ if (!hasDecoration())
+ return;
+
+ if (q->rect().contains(event->pos())) {
+ if (buttonMouseOver || hoveredSubControl != QStyle::SC_None)
+ windowFrameHoverLeaveEvent(event);
+ return;
+ }
+
+ bool wasMouseOver = buttonMouseOver;
+ QRect oldButtonRect = buttonRect;
+ buttonRect = QRect();
+ buttonMouseOver = false;
+ QPointF pos = event->pos();
+ QStyleOptionTitleBar bar;
+ // make sure that the coordinates (rect and pos) we send to the style are positive.
+ pos.rx() += leftWindowFrameMargin;
+ pos.ry() += topWindowFrameMargin;
+ initStyleOptionTitleBar(&bar);
+ bar.rect = q->windowFrameRect().toRect();
+ bar.rect.moveTo(0,0);
+ bar.rect.setHeight(int(titleBarHeight(bar)));
+
+ Qt::CursorShape cursorShape = Qt::ArrowCursor;
+ bool needsSetCursorCall = true;
+ switch (q->windowFrameSectionAt(event->pos())) {
+ case Qt::TopLeftSection:
+ case Qt::BottomRightSection:
+ cursorShape = Qt::SizeFDiagCursor;
+ break;
+ case Qt::TopRightSection:
+ case Qt::BottomLeftSection:
+ cursorShape = Qt::SizeBDiagCursor;
+ break;
+ case Qt::LeftSection:
+ case Qt::RightSection:
+ cursorShape = Qt::SizeHorCursor;
+ break;
+ case Qt::TopSection:
+ case Qt::BottomSection:
+ cursorShape = Qt::SizeVerCursor;
+ break;
+ case Qt::TitleBarArea:
+ buttonRect = q->style()->subControlRect(QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarCloseButton, 0);
+#ifdef Q_WS_MAC
+ // On mac we should hover if we are in the 'area' of the buttons
+ buttonRect |= q->style()->subControlRect(QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMinButton, 0);
+ buttonRect |= q->style()->subControlRect(QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMaxButton, 0);
+#endif
+ if (buttonRect.contains(pos.toPoint()))
+ buttonMouseOver = true;
+ event->ignore();
+ break;
+ default:
+ needsSetCursorCall = false;
+ event->ignore();
+ }
+#ifndef QT_NO_CURSOR
+ if (needsSetCursorCall)
+ q->setCursor(cursorShape);
+#endif
+ // update buttons if we hover over them
+ hoveredSubControl = q->style()->hitTestComplexControl(QStyle::CC_TitleBar, &bar, pos.toPoint(), 0);
+ if (hoveredSubControl != QStyle::SC_TitleBarCloseButton)
+ hoveredSubControl = QStyle::SC_TitleBarLabel;
+
+ if (buttonMouseOver != wasMouseOver) {
+ if (!oldButtonRect.isNull())
+ q->update(QRectF(oldButtonRect).translated(q->windowFrameRect().topLeft()));
+ if (!buttonRect.isNull())
+ q->update(QRectF(buttonRect).translated(q->windowFrameRect().topLeft()));
+ }
+}
+
+void QGraphicsWidgetPrivate::windowFrameHoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+ Q_Q(QGraphicsWidget);
+ if (hasDecoration()) {
+ // ### restore the cursor, don't override it
+#ifndef QT_NO_CURSOR
+ q->unsetCursor();
+#endif
+
+ bool needsUpdate = false;
+ if (hoveredSubControl == QStyle::SC_TitleBarCloseButton || buttonMouseOver)
+ needsUpdate = true;
+
+ // update the hover state (of buttons etc...)
+ hoveredSubControl = QStyle::SC_None;
+ buttonMouseOver = false;
+ buttonRect = QRect();
+ if (needsUpdate)
+ q->update(buttonRect);
+ }
+}
+
+bool QGraphicsWidgetPrivate::hasDecoration() const
+{
+ return (windowFlags & Qt::Window) && (windowFlags & Qt::WindowTitleHint);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsWidgetPrivate::setFocusWidget()
+{
+ // Update focus child chain.
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr);
+ QGraphicsWidget *parent = widget;
+ bool hidden = !visible;
+ do {
+ parent->d_func()->focusChild = widget;
+ } while (!parent->isWindow() && (parent = parent->parentWidget()) && (!hidden || !parent->d_func()->visible));
+}
+
+/*!
+ \internal
+*/
+void QGraphicsWidgetPrivate::clearFocusWidget()
+{
+ // Reset focus child chain.
+ QGraphicsWidget *parent = static_cast<QGraphicsWidget *>(q_ptr);
+ do {
+ if (parent->d_func()->focusChild != q_ptr)
+ break;
+ parent->d_func()->focusChild = 0;
+ } while (!parent->isWindow() && (parent = parent->parentWidget()));
+}
+
+/**
+ * is called after a reparent has taken place to fix up the focus chain(s)
+ */
+void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *newScene)
+{
+ Q_Q(QGraphicsWidget);
+
+ Q_ASSERT(focusNext && focusPrev);
+
+ QGraphicsWidget *n = q; //last one in 'new' list
+ QGraphicsWidget *o = 0; //last one in 'old' list
+
+ QGraphicsWidget *w = focusNext;
+
+ QGraphicsWidget *firstOld = 0;
+ bool wasPreviousNew = true;
+
+ if (focusChild) {
+ // Ensure that the current focus child doesn't leave pointers around
+ // before reparenting.
+ focusChild->clearFocus();
+ }
+
+ while (w != q) {
+ bool isCurrentNew = q->isAncestorOf(w);
+ if (isCurrentNew) {
+ if (!wasPreviousNew) {
+ n->d_func()->focusNext = w;
+ w->d_func()->focusPrev = n;
+ }
+ n = w;
+ } else /*if (!isCurrentNew)*/ {
+ if (wasPreviousNew) {
+ if (o) {
+ o->d_func()->focusNext = w;
+ w->d_func()->focusPrev = o;
+ } else {
+ firstOld = w;
+ }
+ }
+ o = w;
+ }
+ w = w->d_func()->focusNext;
+ wasPreviousNew = isCurrentNew;
+ }
+
+ // repair the 'old' chain
+ if (firstOld) {
+ o->d_func()->focusNext = firstOld;
+ firstOld->d_func()->focusPrev = o;
+ }
+
+ // update tabFocusFirst for oldScene if the item is going to be removed from oldScene
+ if (newParent)
+ newScene = newParent->scene();
+ QGraphicsScene *oldScene = q->scene();
+ if (oldScene && newScene != oldScene)
+ oldScene->d_func()->tabFocusFirst = firstOld;
+
+ QGraphicsItem *topLevelItem = newParent ? newParent->topLevelItem() : 0;
+ QGraphicsWidget *topLevel = 0;
+ if (topLevelItem && topLevelItem->isWidget())
+ topLevel = static_cast<QGraphicsWidget *>(topLevelItem);
+
+ if (topLevel && newParent) {
+ QGraphicsWidget *last = topLevel->d_func()->focusPrev;
+ // link last with new chain
+ last->d_func()->focusNext = q;
+ focusPrev = last;
+
+ // link last in chain with
+ topLevel->d_func()->focusPrev = n;
+ n->d_func()->focusNext = topLevel;
+ } else {
+ // q is the start of the focus chain
+ n->d_func()->focusNext = q;
+ focusPrev = n;
+ }
+
+}
+
+void QGraphicsWidgetPrivate::setLayout_helper(QGraphicsLayout *l)
+{
+ delete (this->layout);
+ layout = l;
+ if (!l) {
+ Q_Q(QGraphicsWidget);
+ q->updateGeometry();
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicswidget_p.h b/src/gui/graphicsview/qgraphicswidget_p.h
new file mode 100644
index 0000000..afa6812
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicswidget_p.h
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSWIDGET_P_H
+#define QGRAPHICSWIDGET_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qobject_p.h>
+#include "qgraphicsitem_p.h"
+#include "qgraphicswidget.h"
+#include <QtGui/qfont.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/qsizepolicy.h>
+#include <QtGui/qstyle.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsLayout;
+class QStyleOptionTitleBar;
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+class Q_GUI_EXPORT QGraphicsWidgetPrivate : public QGraphicsItemPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsWidget)
+public:
+ QGraphicsWidgetPrivate()
+ : leftMargin(0),
+ topMargin(0),
+ rightMargin(0),
+ bottomMargin(0),
+ leftLayoutItemMargin(0),
+ topLayoutItemMargin(0),
+ rightLayoutItemMargin(0),
+ bottomLayoutItemMargin(0),
+ layout(0),
+ inheritedPaletteResolveMask(0),
+ inheritedFontResolveMask(0),
+ inSetGeometry(0),
+ focusPolicy(Qt::NoFocus),
+ focusNext(0),
+ focusPrev(0),
+ focusChild(0),
+ windowFlags(0),
+ hoveredSubControl(QStyle::SC_None),
+ grabbedSection(Qt::NoSection),
+ buttonMouseOver(false),
+ buttonSunken(false),
+ setWindowFrameMargins(false),
+ leftWindowFrameMargin(0),
+ topWindowFrameMargin(0),
+ rightWindowFrameMargin(0),
+ bottomWindowFrameMargin(0)
+ { }
+
+ void init(QGraphicsItem *parentItem, Qt::WindowFlags wFlags);
+ qreal titleBarHeight(const QStyleOptionTitleBar &options) const;
+
+ // Margins
+ qreal leftMargin;
+ qreal topMargin;
+ qreal rightMargin;
+ qreal bottomMargin;
+ QRectF contentsRect;
+
+ // Layout item margins
+ void getLayoutItemMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const;
+ void setLayoutItemMargins(qreal left, qreal top, qreal right, qreal bottom);
+ void setLayoutItemMargins(QStyle::SubElement element, const QStyleOption *opt = 0);
+
+ void fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *newScene = 0);
+ void setLayout_helper(QGraphicsLayout *l);
+
+ qreal leftLayoutItemMargin;
+ qreal topLayoutItemMargin;
+ qreal rightLayoutItemMargin;
+ qreal bottomLayoutItemMargin;
+
+ // Layouts
+ QGraphicsLayout *layout;
+ void setLayoutDirection_helper(Qt::LayoutDirection direction);
+ void resolveLayoutDirection();
+
+ // Style
+ QPalette palette;
+ uint inheritedPaletteResolveMask;
+ void setPalette_helper(const QPalette &palette);
+ void resolvePalette(uint inheritedMask);
+ void updatePalette(const QPalette &palette);
+ QPalette naturalWidgetPalette() const;
+ QFont font;
+ uint inheritedFontResolveMask;
+ void setFont_helper(const QFont &font);
+ void resolveFont(uint inheritedMask);
+ void updateFont(const QFont &font);
+ QFont naturalWidgetFont() const;
+
+ // Window specific
+ void initStyleOptionTitleBar(QStyleOptionTitleBar *option);
+ void adjustWindowFlags(Qt::WindowFlags *wFlags);
+ void windowFrameMouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void windowFrameMousePressEvent(QGraphicsSceneMouseEvent *event);
+ void windowFrameMouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ void windowFrameHoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ bool hasDecoration() const;
+
+ // State
+ inline int attributeToBitIndex(Qt::WidgetAttribute att) const
+ {
+ int bit = -1;
+ switch (att) {
+ case Qt::WA_SetLayoutDirection: bit = 0; break;
+ case Qt::WA_RightToLeft: bit = 1; break;
+ case Qt::WA_SetStyle: bit = 2; break;
+ case Qt::WA_Resized: bit = 3; break;
+ case Qt::WA_DeleteOnClose: bit = 4; break;
+ case Qt::WA_NoSystemBackground: bit = 5; break;
+ case Qt::WA_OpaquePaintEvent: bit = 6; break;
+ case Qt::WA_SetPalette: bit = 7; break;
+ case Qt::WA_SetFont: bit = 8; break;
+ case Qt::WA_WindowPropagation: bit = 9; break;
+ default: break;
+ }
+ return bit;
+ }
+ inline void setAttribute(Qt::WidgetAttribute att, bool value)
+ {
+ int bit = attributeToBitIndex(att);
+ if (bit == -1) {
+ qWarning("QGraphicsWidget::setAttribute: unsupported attribute %d", int(att));
+ return;
+ }
+ if (value)
+ attributes |= (1 << bit);
+ else
+ attributes &= ~(1 << bit);
+ }
+ inline bool testAttribute(Qt::WidgetAttribute att) const
+ {
+ int bit = attributeToBitIndex(att);
+ if (bit == -1)
+ return false;
+ return (attributes & (1 << bit)) != 0;
+ }
+ quint32 attributes : 10;
+ quint32 inSetGeometry : 1;
+
+ // Focus
+ Qt::FocusPolicy focusPolicy;
+ QGraphicsWidget *focusNext;
+ QGraphicsWidget *focusPrev;
+ QGraphicsWidget *focusChild;
+ void setFocusWidget();
+ void clearFocusWidget();
+
+ // Windows
+ Qt::WindowFlags windowFlags;
+ QString windowTitle;
+ QStyle::SubControl hoveredSubControl;
+ Qt::WindowFrameSection grabbedSection;
+ uint buttonMouseOver : 1;
+ uint buttonSunken : 1;
+ QPointF mouseDelta; // to compensate for small error when interactively resizing
+ QRectF startGeometry;
+ QRect buttonRect;
+
+ bool setWindowFrameMargins;
+ qreal leftWindowFrameMargin;
+ qreal topWindowFrameMargin;
+ qreal rightWindowFrameMargin;
+ qreal bottomWindowFrameMargin;
+
+#ifndef QT_NO_ACTION
+ QList<QAction *> actions;
+#endif
+};
+
+#endif //!defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+QT_END_NAMESPACE
+
+#endif //QGRAPHICSWIDGET_P_H
+
diff --git a/src/gui/graphicsview/qgridlayoutengine.cpp b/src/gui/graphicsview/qgridlayoutengine.cpp
new file mode 100644
index 0000000..dc5ca21
--- /dev/null
+++ b/src/gui/graphicsview/qgridlayoutengine.cpp
@@ -0,0 +1,1542 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include <math.h>
+
+#include "qgraphicslayoutitem.h"
+#include "qgridlayoutengine_p.h"
+#include "qstyleoption.h"
+#include "qvarlengtharray.h"
+
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+template <typename T>
+static void insertOrRemoveItems(QVector<T> &items, int index, int delta)
+{
+ int count = items.count();
+ if (index < count) {
+ if (delta > 0) {
+ items.insert(index, delta, T());
+ } else if (delta < 0) {
+ items.remove(index, qMin(-delta, count - index));
+ }
+ }
+}
+
+static qreal growthFactorBelowPreferredSize(qreal desired, qreal sumAvailable, qreal sumDesired)
+{
+ Q_ASSERT(sumDesired != 0.0);
+ return desired * ::pow(sumAvailable / sumDesired, desired / sumDesired);
+}
+
+static qreal fixedDescent(qreal descent, qreal ascent, qreal targetSize)
+{
+ if (descent < 0.0)
+ return -1.0;
+
+ Q_ASSERT(descent >= 0.0);
+ Q_ASSERT(ascent >= 0.0);
+ Q_ASSERT(targetSize >= ascent + descent);
+
+ qreal extra = targetSize - (ascent + descent);
+ return descent + (extra / 2.0);
+}
+
+static qreal compare(const QGridLayoutBox &box1, const QGridLayoutBox &box2, int which)
+{
+ qreal size1 = box1.q_sizes(which);
+ qreal size2 = box2.q_sizes(which);
+
+ if (which == MaximumSize) {
+ return size2 - size1;
+ } else {
+ return size1 - size2;
+ }
+}
+
+void QGridLayoutBox::add(const QGridLayoutBox &other, int stretch, qreal spacing)
+{
+ Q_ASSERT(q_minimumDescent < 0.0);
+
+ q_minimumSize += other.q_minimumSize + spacing;
+ q_preferredSize += other.q_preferredSize + spacing;
+ q_maximumSize += ((stretch == 0) ? other.q_preferredSize : other.q_maximumSize) + spacing;
+}
+
+void QGridLayoutBox::combine(const QGridLayoutBox &other)
+{
+ q_minimumDescent = qMax(q_minimumDescent, other.q_minimumDescent);
+ q_minimumAscent = qMax(q_minimumAscent, other.q_minimumAscent);
+
+ q_minimumSize = qMax(q_minimumAscent + q_minimumDescent,
+ qMax(q_minimumSize, other.q_minimumSize));
+ qreal maxMax;
+ if (q_maximumSize == FLT_MAX && other.q_maximumSize != FLT_MAX)
+ maxMax = other.q_maximumSize;
+ else if (other.q_maximumSize == FLT_MAX && q_maximumSize != FLT_MAX)
+ maxMax = q_maximumSize;
+ else
+ maxMax = qMax(q_maximumSize, other.q_maximumSize);
+
+ q_maximumSize = qMax(q_minimumSize, maxMax);
+ q_preferredSize = qBound(q_minimumSize, qMax(q_preferredSize, other.q_preferredSize),
+ q_maximumSize);
+}
+
+void QGridLayoutBox::normalize()
+{
+ q_maximumSize = qMax(qreal(0.0), q_maximumSize);
+ q_minimumSize = qBound(qreal(0.0), q_minimumSize, q_maximumSize);
+ q_preferredSize = qBound(q_minimumSize, q_preferredSize, q_maximumSize);
+ q_minimumDescent = qMin(q_minimumDescent, q_minimumSize);
+
+ Q_ASSERT((q_minimumDescent < 0.0) == (q_minimumAscent < 0.0));
+}
+
+#ifdef QT_DEBUG
+void QGridLayoutBox::dump(int indent) const
+{
+ qDebug("%*sBox (%g <= %g <= %g [%g/%g])", indent, "", q_minimumSize, q_preferredSize,
+ q_maximumSize, q_minimumAscent, q_minimumDescent);
+}
+#endif
+
+bool operator==(const QGridLayoutBox &box1, const QGridLayoutBox &box2)
+{
+ for (int i = 0; i < NSizes; ++i) {
+ if (box1.q_sizes(i) != box2.q_sizes(i))
+ return false;
+ }
+ return box1.q_minimumDescent == box2.q_minimumDescent
+ && box1.q_minimumAscent == box2.q_minimumAscent;
+}
+
+void QGridLayoutRowData::reset(int count)
+{
+ ignore.fill(false, count);
+ boxes.fill(QGridLayoutBox(), count);
+ multiCellMap.clear();
+ stretches.fill(0, count);
+ spacings.fill(0.0, count);
+ hasIgnoreFlag = false;
+}
+
+void QGridLayoutRowData::distributeMultiCells()
+{
+ MultiCellMap::const_iterator i = multiCellMap.constBegin();
+ for (; i != multiCellMap.constEnd(); ++i) {
+ int start = i.key().first;
+ int span = i.key().second;
+ int end = start + span;
+ const QGridLayoutBox &box = i.value().q_box;
+ int stretch = i.value().q_stretch;
+
+ QGridLayoutBox totalBox = this->totalBox(start, end);
+ QVarLengthArray<QGridLayoutBox> extras(span);
+ QVarLengthArray<qreal> dummy(span);
+ QVarLengthArray<qreal> newSizes(span);
+
+ for (int j = 0; j < NSizes; ++j) {
+ qreal extra = compare(totalBox, box, j);
+ if (extra > 0.0) {
+ calculateGeometries(start, end, totalBox.q_sizes(j), dummy.data(), newSizes.data(),
+ 0, totalBox);
+
+ for (int k = 0; k < span; ++k)
+ extras[k].q_sizes(j) = newSizes[k];
+ }
+ }
+
+ for (int k = 0; k < span; ++k) {
+ boxes[start + k].combine(extras[k]);
+ stretches[start + k] = qMax(stretches[start + k], stretch);
+ }
+ }
+ multiCellMap.clear();
+}
+
+void QGridLayoutRowData::calculateGeometries(int start, int end, qreal targetSize, qreal *positions,
+ qreal *sizes, qreal *descents,
+ const QGridLayoutBox &totalBox)
+{
+ Q_ASSERT(end > start);
+
+ targetSize = qBound(totalBox.q_minimumSize, targetSize, totalBox.q_maximumSize);
+
+ int n = end - start;
+ QVarLengthArray<qreal> newSizes(n);
+ QVarLengthArray<qreal> factors(n);
+ qreal sumFactors = 0.0;
+ int sumStretches = 0;
+ qreal sumAvailable;
+
+ for (int i = 0; i < n; ++i) {
+ if (stretches[start + i] > 0)
+ sumStretches += stretches[start + i];
+ }
+
+ if (targetSize < totalBox.q_preferredSize) {
+ stealBox(start, end, MinimumSize, positions, sizes);
+
+ sumAvailable = targetSize - totalBox.q_minimumSize;
+ if (sumAvailable > 0.0) {
+ qreal sumDesired = totalBox.q_preferredSize - totalBox.q_minimumSize;
+
+ for (int i = 0; i < n; ++i) {
+ if (ignore.testBit(start + i)) {
+ factors[i] = 0.0;
+ continue;
+ }
+
+ const QGridLayoutBox &box = boxes.at(start + i);
+ qreal desired = box.q_preferredSize - box.q_minimumSize;
+ factors[i] = growthFactorBelowPreferredSize(desired, sumAvailable, sumDesired);
+ sumFactors += factors[i];
+ }
+
+ for (int i = 0; i < n; ++i) {
+ Q_ASSERT(sumFactors > 0.0);
+ qreal delta = sumAvailable * factors[i] / sumFactors;
+ newSizes[i] = sizes[i] + delta;
+ }
+ }
+ } else {
+ stealBox(start, end, PreferredSize, positions, sizes);
+
+ sumAvailable = targetSize - totalBox.q_preferredSize;
+ if (sumAvailable > 0.0) {
+ bool somethingHasAMaximumSize = false;
+
+ qreal sumPreferredSizes = 0.0;
+ for (int i = 0; i < n; ++i)
+ sumPreferredSizes += sizes[i];
+
+ for (int i = 0; i < n; ++i) {
+ if (ignore.testBit(start + i)) {
+ newSizes[i] = 0.0;
+ factors[i] = 0.0;
+ continue;
+ }
+
+ const QGridLayoutBox &box = boxes.at(start + i);
+ qreal desired = box.q_maximumSize - box.q_preferredSize;
+ if (desired == 0.0) {
+ newSizes[i] = sizes[i];
+ factors[i] = 0.0;
+ } else {
+ Q_ASSERT(desired > 0.0);
+
+ int stretch = stretches[start + i];
+ if (sumStretches == 0) {
+ if (hasIgnoreFlag) {
+ factors[i] = (stretch < 0) ? 1.0 : 0.0;
+ } else {
+ factors[i] = (stretch < 0) ? sizes[i] : 0.0;
+ }
+ } else if (stretch == sumStretches) {
+ factors[i] = 1.0;
+ } else if (stretch <= 0) {
+ factors[i] = 0.0;
+ } else {
+ qreal ultimatePreferredSize;
+ qreal ultimateSumPreferredSizes;
+ qreal x = ((stretch * sumPreferredSizes)
+ - (sumStretches * box.q_preferredSize))
+ / (sumStretches - stretch);
+ if (x >= 0.0) {
+ ultimatePreferredSize = box.q_preferredSize + x;
+ ultimateSumPreferredSizes = sumPreferredSizes + x;
+ } else {
+ ultimatePreferredSize = box.q_preferredSize;
+ ultimateSumPreferredSizes = (sumStretches * box.q_preferredSize)
+ / stretch;
+ }
+
+ /*
+ We multiply these by 1.5 to give some space for a smooth transition
+ (at the expense of the stretch factors, which are not fully respected
+ during the transition).
+ */
+ ultimatePreferredSize = ultimatePreferredSize * 3 / 2;
+ ultimateSumPreferredSizes = ultimateSumPreferredSizes * 3 / 2;
+
+ qreal ultimateFactor = (stretch * ultimateSumPreferredSizes
+ / sumStretches)
+ - (box.q_preferredSize);
+ qreal transitionalFactor = sumAvailable
+ * (ultimatePreferredSize - box.q_preferredSize)
+ / (ultimateSumPreferredSizes
+ - sumPreferredSizes);
+
+ qreal alpha = qMin(sumAvailable,
+ ultimateSumPreferredSizes - sumPreferredSizes);
+ qreal beta = ultimateSumPreferredSizes - sumPreferredSizes;
+
+ factors[i] = ((alpha * ultimateFactor)
+ + ((beta - alpha) * transitionalFactor)) / beta;
+ }
+ sumFactors += factors[i];
+ if (desired < sumAvailable)
+ somethingHasAMaximumSize = true;
+
+ newSizes[i] = -1.0;
+ }
+ }
+
+ bool keepGoing = somethingHasAMaximumSize;
+ while (keepGoing) {
+ keepGoing = false;
+
+ for (int i = 0; i < n; ++i) {
+ if (newSizes[i] >= 0.0)
+ continue;
+
+ const QGridLayoutBox &box = boxes.at(start + i);
+ qreal avail = sumAvailable * factors[i] / sumFactors;
+ if (sizes[i] + avail >= box.q_maximumSize) {
+ newSizes[i] = box.q_maximumSize;
+ sumAvailable -= box.q_maximumSize - sizes[i];
+ sumFactors -= factors[i];
+ keepGoing = (sumAvailable > 0.0);
+ if (!keepGoing)
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < n; ++i) {
+ if (newSizes[i] < 0.0) {
+ qreal delta = (sumFactors == 0.0) ? 0.0
+ : sumAvailable * factors[i] / sumFactors;
+ newSizes[i] = sizes[i] + delta;
+ }
+ }
+ }
+ }
+
+ if (sumAvailable > 0) {
+ qreal offset = 0;
+ for (int i = 0; i < n; ++i) {
+ qreal delta = newSizes[i] - sizes[i];
+ positions[i] += offset;
+ sizes[i] += delta;
+ offset += delta;
+ }
+
+#if 0 // some "pixel allocation"
+ int surplus = targetSize - (positions[n - 1] + sizes[n - 1]);
+ Q_ASSERT(surplus >= 0 && surplus <= n);
+
+ int prevSurplus = -1;
+ while (surplus > 0 && surplus != prevSurplus) {
+ prevSurplus = surplus;
+
+ int offset = 0;
+ for (int i = 0; i < n; ++i) {
+ const QGridLayoutBox &box = boxes.at(start + i);
+ int delta = (!ignore.testBit(start + i) && surplus > 0
+ && factors[i] > 0 && sizes[i] < box.q_maximumSize)
+ ? 1 : 0;
+
+ positions[i] += offset;
+ sizes[i] += delta;
+ offset += delta;
+ surplus -= delta;
+ }
+ }
+ Q_ASSERT(surplus == 0);
+#endif
+ }
+
+ if (descents) {
+ for (int i = 0; i < n; ++i) {
+ if (ignore.testBit(start + i))
+ continue;
+ const QGridLayoutBox &box = boxes.at(start + i);
+ descents[i] = fixedDescent(box.q_minimumDescent, box.q_minimumAscent, sizes[i]);
+ }
+ }
+}
+
+QGridLayoutBox QGridLayoutRowData::totalBox(int start, int end) const
+{
+ QGridLayoutBox result;
+ if (start < end) {
+ result.q_maximumSize = 0.0;
+ qreal nextSpacing = 0.0;
+ for (int i = start; i < end; ++i) {
+ result.add(boxes.at(i), stretches.at(i), nextSpacing);
+ nextSpacing = spacings.at(i);
+ }
+ }
+ return result;
+}
+
+void QGridLayoutRowData::stealBox(int start, int end, int which, qreal *positions, qreal *sizes)
+{
+ qreal offset = 0.0;
+ qreal nextSpacing = 0.0;
+
+ for (int i = start; i < end; ++i) {
+ qreal avail = 0.0;
+
+ if (!ignore.testBit(i)) {
+ const QGridLayoutBox &box = boxes.at(i);
+ avail = box.q_sizes(which);
+ offset += nextSpacing;
+ nextSpacing = spacings.at(i);
+ }
+
+ *positions++ = offset;
+ *sizes++ = avail;
+ offset += avail;
+ }
+}
+
+#ifdef QT_DEBUG
+void QGridLayoutRowData::dump(int indent) const
+{
+ qDebug("%*sData", indent, "");
+
+ for (int i = 0; i < ignore.count(); ++i) {
+ qDebug("%*s Row %d (stretch %d, spacing %g)", indent, "", i, stretches.at(i),
+ spacings.at(i));
+ if (ignore.testBit(i))
+ qDebug("%*s Ignored", indent, "");
+ boxes.at(i).dump(indent + 2);
+ }
+
+ MultiCellMap::const_iterator it = multiCellMap.constBegin();
+ while (it != multiCellMap.constEnd()) {
+ qDebug("%*s Multi-cell entry <%d, %d> (stretch %d)", indent, "", it.key().first,
+ it.key().second, it.value().q_stretch);
+ it.value().q_box.dump(indent + 2);
+ }
+}
+#endif
+
+QGridLayoutItem::QGridLayoutItem(QGridLayoutEngine *engine, QGraphicsLayoutItem *layoutItem,
+ int row, int column, int rowSpan, int columnSpan,
+ Qt::Alignment alignment)
+ : q_engine(engine), q_layoutItem(layoutItem), q_alignment(alignment)
+{
+ q_firstRows[Hor] = column;
+ q_firstRows[Ver] = row;
+ q_rowSpans[Hor] = columnSpan;
+ q_rowSpans[Ver] = rowSpan;
+ q_stretches[Hor] = -1;
+ q_stretches[Ver] = -1;
+
+ q_engine->addItem(this);
+}
+
+int QGridLayoutItem::firstRow(Qt::Orientation orientation) const
+{
+ return q_firstRows[orientation == Qt::Vertical];
+}
+
+int QGridLayoutItem::firstColumn(Qt::Orientation orientation) const
+{
+ return q_firstRows[orientation == Qt::Horizontal];
+}
+
+int QGridLayoutItem::lastRow(Qt::Orientation orientation) const
+{
+ return firstRow(orientation) + rowSpan(orientation) - 1;
+}
+
+int QGridLayoutItem::lastColumn(Qt::Orientation orientation) const
+{
+ return firstColumn(orientation) + columnSpan(orientation) - 1;
+}
+
+int QGridLayoutItem::rowSpan(Qt::Orientation orientation) const
+{
+ return q_rowSpans[orientation == Qt::Vertical];
+}
+
+int QGridLayoutItem::columnSpan(Qt::Orientation orientation) const
+{
+ return q_rowSpans[orientation == Qt::Horizontal];
+}
+
+void QGridLayoutItem::setFirstRow(int row, Qt::Orientation orientation)
+{
+ q_firstRows[orientation == Qt::Vertical] = row;
+}
+
+void QGridLayoutItem::setRowSpan(int rowSpan, Qt::Orientation orientation)
+{
+ q_rowSpans[orientation == Qt::Vertical] = rowSpan;
+}
+
+int QGridLayoutItem::stretchFactor(Qt::Orientation orientation) const
+{
+ int stretch = q_stretches[orientation == Qt::Vertical];
+ if (stretch >= 0)
+ return stretch;
+
+ QSizePolicy::Policy policy = sizePolicy(orientation);
+
+ if (policy & QSizePolicy::ExpandFlag) {
+ return 1;
+ } else if (policy & QSizePolicy::GrowFlag) {
+ return -1; // because we max it up
+ } else {
+ return 0;
+ }
+}
+
+void QGridLayoutItem::setStretchFactor(int stretch, Qt::Orientation orientation)
+{
+ Q_ASSERT(stretch >= 0); // ### deal with too big stretches
+ q_stretches[orientation == Qt::Vertical] = stretch;
+}
+
+QSizePolicy::Policy QGridLayoutItem::sizePolicy(Qt::Orientation orientation) const
+{
+ QSizePolicy sizePolicy(q_layoutItem->sizePolicy());
+ return (orientation == Qt::Horizontal) ? sizePolicy.horizontalPolicy()
+ : sizePolicy.verticalPolicy();
+}
+
+QSizePolicy::ControlTypes QGridLayoutItem::controlTypes(LayoutSide /* side */) const
+{
+ return q_layoutItem->sizePolicy().controlType();
+}
+
+QSizeF QGridLayoutItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ return q_layoutItem->effectiveSizeHint(which, constraint);
+}
+
+QGridLayoutBox QGridLayoutItem::box(Qt::Orientation orientation, qreal constraint) const
+{
+ QGridLayoutBox result;
+ QSizePolicy::Policy policy = sizePolicy(orientation);
+
+ if (orientation == Qt::Horizontal) {
+ QSizeF constraintSize(-1.0, constraint);
+
+ result.q_preferredSize = sizeHint(Qt::PreferredSize, constraintSize).width();
+
+ if (policy & QSizePolicy::ShrinkFlag) {
+ result.q_minimumSize = sizeHint(Qt::MinimumSize, constraintSize).width();
+ } else {
+ result.q_minimumSize = result.q_preferredSize;
+ }
+
+ if (policy & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag)) {
+ result.q_maximumSize = sizeHint(Qt::MaximumSize, constraintSize).width();
+ } else {
+ result.q_maximumSize = result.q_preferredSize;
+ }
+ } else {
+ QSizeF constraintSize(constraint, -1.0);
+
+ result.q_preferredSize = sizeHint(Qt::PreferredSize, constraintSize).height();
+
+ if (policy & QSizePolicy::ShrinkFlag) {
+ result.q_minimumSize = sizeHint(Qt::MinimumSize, constraintSize).height();
+ } else {
+ result.q_minimumSize = result.q_preferredSize;
+ }
+
+ if (policy & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag)) {
+ result.q_maximumSize = sizeHint(Qt::MaximumSize, constraintSize).height();
+ } else {
+ result.q_maximumSize = result.q_preferredSize;
+ }
+
+ result.q_minimumDescent = sizeHint(Qt::MinimumDescent, constraintSize).height();
+ if (result.q_minimumDescent >= 0.0)
+ result.q_minimumAscent = result.q_minimumSize - result.q_minimumDescent;
+ }
+ if (policy & QSizePolicy::IgnoreFlag)
+ result.q_preferredSize = result.q_minimumSize;
+
+ return result;
+}
+
+QRectF QGridLayoutItem::geometryWithin(qreal x, qreal y, qreal width, qreal height,
+ qreal rowDescent) const
+{
+ rowDescent = -1.0; // ### This disables the descent
+
+ QGridLayoutBox vBox = box(Qt::Vertical);
+ if (vBox.q_minimumDescent < 0.0 || rowDescent < 0.0) {
+ qreal cellWidth = width;
+ qreal cellHeight = height;
+
+ QSizeF size = effectiveMaxSize().boundedTo(QSizeF(cellWidth, cellHeight));
+ width = size.width();
+ height = size.height();
+
+ Qt::Alignment align = q_engine->effectiveAlignment(this);
+ switch (align & Qt::AlignHorizontal_Mask) {
+ case Qt::AlignHCenter:
+ x += (cellWidth - width)/2;
+ break;
+ case Qt::AlignRight:
+ x += cellWidth - width;
+ break;
+ default:
+ break;
+ }
+ switch (align & Qt::AlignVertical_Mask) {
+ case Qt::AlignVCenter:
+ y += (cellHeight - height)/2;
+ break;
+ case Qt::AlignBottom:
+ y += cellHeight - height;
+ break;
+ default:
+ break;
+ }
+ return QRectF(x, y, width, height);
+ } else {
+ qreal descent = vBox.q_minimumDescent;
+ qreal ascent = vBox.q_minimumSize - descent;
+ return QRectF(x, y + height - rowDescent - ascent, width, ascent + descent);
+ }
+}
+
+void QGridLayoutItem::setGeometry(const QRectF &rect)
+{
+ q_layoutItem->setGeometry(rect);
+}
+
+void QGridLayoutItem::transpose()
+{
+ qSwap(q_firstRows[Hor], q_firstRows[Ver]);
+ qSwap(q_rowSpans[Hor], q_rowSpans[Ver]);
+ qSwap(q_stretches[Hor], q_stretches[Ver]);
+}
+
+void QGridLayoutItem::insertOrRemoveRows(int row, int delta, Qt::Orientation orientation)
+{
+ int oldFirstRow = firstRow(orientation);
+ if (oldFirstRow >= row) {
+ setFirstRow(oldFirstRow + delta, orientation);
+ } else if (lastRow(orientation) >= row) {
+ setRowSpan(rowSpan(orientation) + delta, orientation);
+ }
+}
+/*!
+ \internal
+ returns the effective maximumSize, will take the sizepolicy into
+ consideration. (i.e. if sizepolicy does not have QSizePolicy::Grow, then
+ maxSizeHint will be the preferredSize)
+ Note that effectiveSizeHint does not take sizePolicy into consideration,
+ (since it only evaluates the hints, as the name implies)
+*/
+QSizeF QGridLayoutItem::effectiveMaxSize() const
+{
+ QSizeF size;
+ bool vGrow = (sizePolicy(Qt::Vertical) & QSizePolicy::GrowFlag) == QSizePolicy::GrowFlag;
+ bool hGrow = (sizePolicy(Qt::Horizontal) & QSizePolicy::GrowFlag) == QSizePolicy::GrowFlag;
+ if (!vGrow || !hGrow) {
+ QSizeF pref = layoutItem()->effectiveSizeHint(Qt::PreferredSize);
+ if (!vGrow)
+ size.setHeight(pref.height());
+ if (!hGrow)
+ size.setWidth(pref.width());
+ }
+
+ if (!size.isValid()) {
+ QSizeF maxSize = layoutItem()->effectiveSizeHint(Qt::MaximumSize);
+ if (size.width() == -1)
+ size.setWidth(maxSize.width());
+ if (size.height() == -1)
+ size.setHeight(maxSize.height());
+ }
+ return size;
+}
+
+#ifdef QT_DEBUG
+void QGridLayoutItem::dump(int indent) const
+{
+ qDebug("%*s%p (%d, %d) %d x %d", indent, "", q_layoutItem, firstRow(), firstColumn(),
+ rowSpan(), columnSpan());
+
+ if (q_stretches[Hor] >= 0)
+ qDebug("%*s Horizontal stretch: %d", indent, "", q_stretches[Hor]);
+ if (q_stretches[Ver] >= 0)
+ qDebug("%*s Vertical stretch: %d", indent, "", q_stretches[Ver]);
+ if (q_alignment != 0)
+ qDebug("%*s Alignment: %x", indent, "", uint(q_alignment));
+ qDebug("%*s Horizontal size policy: %x Vertical size policy: %x",
+ indent, "", sizePolicy(Qt::Horizontal), sizePolicy(Qt::Vertical));
+}
+#endif
+
+void QGridLayoutRowInfo::insertOrRemoveRows(int row, int delta)
+{
+ count += delta;
+
+ insertOrRemoveItems(stretches, row, delta);
+ insertOrRemoveItems(spacings, row, delta);
+ insertOrRemoveItems(alignments, row, delta);
+ insertOrRemoveItems(boxes, row, delta);
+}
+
+#ifdef QT_DEBUG
+void QGridLayoutRowInfo::dump(int indent) const
+{
+ qDebug("%*sInfo (count: %d)", indent, "", count);
+ for (int i = 0; i < count; ++i) {
+ QString message;
+
+ if (stretches.value(i).value() >= 0)
+ message += QString::fromAscii(" stretch %1").arg(stretches.value(i).value());
+ if (spacings.value(i).value() >= 0.0)
+ message += QString::fromAscii(" spacing %1").arg(spacings.value(i).value());
+ if (alignments.value(i) != 0)
+ message += QString::fromAscii(" alignment %1").arg(int(alignments.value(i)), 16);
+
+ if (!message.isEmpty() || boxes.value(i) != QGridLayoutBox()) {
+ qDebug("%*s Row %d:%s", indent, "", i, qPrintable(message));
+ if (boxes.value(i) != QGridLayoutBox())
+ boxes.value(i).dump(indent + 1);
+ }
+ }
+}
+#endif
+
+QGridLayoutEngine::QGridLayoutEngine()
+{
+ m_visualDirection = Qt::LeftToRight;
+ invalidate();
+}
+
+int QGridLayoutEngine::rowCount(Qt::Orientation orientation) const
+{
+ return q_infos[orientation == Qt::Vertical].count;
+}
+
+int QGridLayoutEngine::columnCount(Qt::Orientation orientation) const
+{
+ return q_infos[orientation == Qt::Horizontal].count;
+}
+
+int QGridLayoutEngine::itemCount() const
+{
+ return q_items.count();
+}
+
+QGridLayoutItem *QGridLayoutEngine::itemAt(int index) const
+{
+ Q_ASSERT(index >= 0 && index < itemCount());
+ return q_items.at(index);
+}
+
+int QGridLayoutEngine::effectiveFirstRow(Qt::Orientation orientation) const
+{
+ ensureEffectiveFirstAndLastRows();
+ return q_cachedEffectiveFirstRows[orientation == Qt::Vertical];
+}
+
+int QGridLayoutEngine::effectiveLastRow(Qt::Orientation orientation) const
+{
+ ensureEffectiveFirstAndLastRows();
+ return q_cachedEffectiveLastRows[orientation == Qt::Vertical];
+}
+
+void QGridLayoutEngine::setSpacing(qreal spacing, Qt::Orientations orientations)
+{
+ Q_ASSERT(spacing >= 0.0);
+ if (orientations & Qt::Horizontal)
+ q_defaultSpacings[Hor].setUserValue(spacing);
+ if (orientations & Qt::Vertical)
+ q_defaultSpacings[Ver].setUserValue(spacing);
+
+ invalidate();
+}
+
+qreal QGridLayoutEngine::spacing(const QLayoutStyleInfo &styleInfo, Qt::Orientation orientation) const
+{
+ if (q_defaultSpacings[orientation == Qt::Vertical].isDefault()) {
+ QStyle *style = styleInfo.style();
+ QStyleOption option;
+ option.initFrom(styleInfo.widget());
+ qreal defaultSpacing = (qreal)style->pixelMetric(orientation == Qt::Vertical ? QStyle::PM_LayoutVerticalSpacing
+ : QStyle::PM_LayoutHorizontalSpacing, &option, styleInfo.widget());
+ q_defaultSpacings[orientation == Qt::Vertical].setCachedValue(defaultSpacing);
+ }
+ return q_defaultSpacings[orientation == Qt::Vertical].value();
+}
+
+void QGridLayoutEngine::setRowSpacing(int row, qreal spacing, Qt::Orientation orientation)
+{
+ Q_ASSERT(row >= 0);
+
+ QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical];
+ if (row >= rowInfo.spacings.count())
+ rowInfo.spacings.resize(row + 1);
+ if (spacing >= 0)
+ rowInfo.spacings[row].setUserValue(spacing);
+ else
+ rowInfo.spacings[row] = QLayoutParameter<qreal>();
+ invalidate();
+}
+
+qreal QGridLayoutEngine::rowSpacing(int row, Qt::Orientation orientation) const
+{
+ QLayoutParameter<qreal> spacing = q_infos[orientation == Qt::Vertical].spacings.value(row);
+ if (!spacing.isDefault())
+ return spacing.value();
+ return q_defaultSpacings[orientation == Qt::Vertical].value();
+}
+
+void QGridLayoutEngine::setRowStretchFactor(int row, int stretch, Qt::Orientation orientation)
+{
+ Q_ASSERT(row >= 0);
+ Q_ASSERT(stretch >= 0);
+
+ maybeExpandGrid(row, -1, orientation);
+
+ QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical];
+ if (row >= rowInfo.stretches.count())
+ rowInfo.stretches.resize(row + 1);
+ rowInfo.stretches[row].setUserValue(stretch);
+}
+
+int QGridLayoutEngine::rowStretchFactor(int row, Qt::Orientation orientation) const
+{
+ QStretchParameter stretch = q_infos[orientation == Qt::Vertical].stretches.value(row);
+ if (!stretch.isDefault())
+ return stretch.value();
+ return 0;
+}
+
+void QGridLayoutEngine::setStretchFactor(QGraphicsLayoutItem *layoutItem, int stretch,
+ Qt::Orientation orientation)
+{
+ Q_ASSERT(stretch >= 0);
+
+ if (QGridLayoutItem *item = findLayoutItem(layoutItem))
+ item->setStretchFactor(stretch, orientation);
+}
+
+int QGridLayoutEngine::stretchFactor(QGraphicsLayoutItem *layoutItem, Qt::Orientation orientation) const
+{
+ if (QGridLayoutItem *item = findLayoutItem(layoutItem))
+ return item->stretchFactor(orientation);
+ return 0;
+}
+
+void QGridLayoutEngine::setRowSizeHint(Qt::SizeHint which, int row, qreal size,
+ Qt::Orientation orientation)
+{
+ Q_ASSERT(row >= 0);
+ Q_ASSERT(size >= 0.0);
+
+ maybeExpandGrid(row, -1, orientation);
+
+ QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical];
+ if (row >= rowInfo.boxes.count())
+ rowInfo.boxes.resize(row + 1);
+ rowInfo.boxes[row].q_sizes(which) = size;
+}
+
+qreal QGridLayoutEngine::rowSizeHint(Qt::SizeHint which, int row, Qt::Orientation orientation) const
+{
+ return q_infos[orientation == Qt::Vertical].boxes.value(row).q_sizes(which);
+}
+
+void QGridLayoutEngine::setRowAlignment(int row, Qt::Alignment alignment,
+ Qt::Orientation orientation)
+{
+ Q_ASSERT(row >= 0);
+
+ maybeExpandGrid(row, -1, orientation);
+
+ QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical];
+ if (row >= rowInfo.alignments.count())
+ rowInfo.alignments.resize(row + 1);
+ rowInfo.alignments[row] = alignment;
+}
+
+Qt::Alignment QGridLayoutEngine::rowAlignment(int row, Qt::Orientation orientation) const
+{
+ Q_ASSERT(row >= 0);
+ return q_infos[orientation == Qt::Vertical].alignments.value(row);
+}
+
+void QGridLayoutEngine::setAlignment(QGraphicsLayoutItem *layoutItem, Qt::Alignment alignment)
+{
+ if (QGridLayoutItem *item = findLayoutItem(layoutItem))
+ item->setAlignment(alignment);
+ invalidate();
+}
+
+Qt::Alignment QGridLayoutEngine::alignment(QGraphicsLayoutItem *layoutItem) const
+{
+ if (QGridLayoutItem *item = findLayoutItem(layoutItem))
+ return item->alignment();
+ return 0;
+}
+
+Qt::Alignment QGridLayoutEngine::effectiveAlignment(const QGridLayoutItem *layoutItem) const
+{
+ Qt::Alignment align = layoutItem->alignment();
+ if (!(align & Qt::AlignVertical_Mask)) {
+ // no vertical alignment, respect the row alignment
+ int y = layoutItem->firstRow();
+ align |= (rowAlignment(y, Qt::Vertical) & Qt::AlignVertical_Mask);
+ }
+ if (!(align & Qt::AlignHorizontal_Mask)) {
+ // no horizontal alignment, respect the column alignment
+ int x = layoutItem->firstColumn();
+ align |= (rowAlignment(x, Qt::Horizontal) & Qt::AlignHorizontal_Mask);
+ }
+ return align;
+}
+
+void QGridLayoutEngine::addItem(QGridLayoutItem *item)
+{
+ maybeExpandGrid(item->lastRow(), item->lastColumn());
+
+ q_items.append(item);
+
+ for (int i = item->firstRow(); i <= item->lastRow(); ++i) {
+ for (int j = item->firstColumn(); j <= item->lastColumn(); ++j) {
+ if (itemAt(i, j))
+ qWarning("QGridLayoutEngine::addItem: Cell (%d, %d) already taken", i, j);
+ setItemAt(i, j, item);
+ }
+ }
+}
+
+void QGridLayoutEngine::removeItem(QGridLayoutItem *item)
+{
+ Q_ASSERT(q_items.contains(item));
+
+ invalidate();
+
+ for (int i = item->firstRow(); i <= item->lastRow(); ++i) {
+ for (int j = item->firstColumn(); j <= item->lastColumn(); ++j) {
+ if (itemAt(i, j) == item)
+ setItemAt(i, j, 0);
+ }
+ }
+
+ q_items.removeAll(item);
+}
+
+QGridLayoutItem *QGridLayoutEngine::findLayoutItem(QGraphicsLayoutItem *layoutItem) const
+{
+ for (int i = q_items.count() - 1; i >= 0; --i) {
+ QGridLayoutItem *item = q_items.at(i);
+ if (item->layoutItem() == layoutItem)
+ return item;
+ }
+ return 0;
+}
+
+QGridLayoutItem *QGridLayoutEngine::itemAt(int row, int column, Qt::Orientation orientation) const
+{
+ if (orientation == Qt::Horizontal)
+ qSwap(row, column);
+ if (uint(row) >= uint(rowCount()) || uint(column) >= uint(columnCount()))
+ return 0;
+ return q_grid.at((row * internalGridColumnCount()) + column);
+}
+
+void QGridLayoutEngine::invalidate()
+{
+ q_cachedEffectiveFirstRows[Hor] = -1;
+ q_cachedEffectiveFirstRows[Ver] = -1;
+ q_cachedEffectiveLastRows[Hor] = -1;
+ q_cachedEffectiveLastRows[Ver] = -1;
+ q_cachedDataForStyleInfo.invalidate();
+ q_cachedSize = QSizeF();
+}
+
+static void visualRect(QRectF *geom, Qt::LayoutDirection dir, const QRectF &contentsRect)
+{
+ if (dir == Qt::RightToLeft)
+ geom->moveRight(contentsRect.right() - (geom->left() - contentsRect.left()));
+}
+
+void QGridLayoutEngine::setGeometries(const QLayoutStyleInfo &styleInfo,
+ const QRectF &contentsGeometry)
+{
+ if (rowCount() < 1 || columnCount() < 1)
+ return;
+
+ ensureGeometries(styleInfo, contentsGeometry.size());
+
+ for (int i = q_items.count() - 1; i >= 0; --i) {
+ QGridLayoutItem *item = q_items.at(i);
+
+ qreal x = q_xx[item->firstColumn()];
+ qreal y = q_yy[item->firstRow()];
+ qreal width = q_widths[item->lastColumn()];
+ qreal height = q_heights[item->lastRow()];
+
+ if (item->columnSpan() != 1)
+ width += q_xx[item->lastColumn()] - x;
+ if (item->rowSpan() != 1)
+ height += q_yy[item->lastRow()] - y;
+
+ QRectF geom = item->geometryWithin(contentsGeometry.x() + x, contentsGeometry.y() + y,
+ width, height, q_descents[item->lastRow()]);
+ visualRect(&geom, visualDirection(), contentsGeometry);
+ item->setGeometry(geom);
+ }
+}
+
+// ### candidate for deletion
+QRectF QGridLayoutEngine::cellRect(const QLayoutStyleInfo &styleInfo,
+ const QRectF &contentsGeometry, int row, int column, int rowSpan,
+ int columnSpan) const
+{
+ if (uint(row) >= uint(rowCount()) || uint(column) >= uint(columnCount())
+ || rowSpan < 1 || columnSpan < 1)
+ return QRectF();
+
+ ensureGeometries(styleInfo, contentsGeometry.size());
+
+ int lastColumn = qMax(column + columnSpan, columnCount()) - 1;
+ int lastRow = qMax(row + rowSpan, rowCount()) - 1;
+
+ qreal x = q_xx[column];
+ qreal y = q_yy[row];
+ qreal width = q_widths[lastColumn];
+ qreal height = q_heights[lastRow];
+
+ if (columnSpan != 1)
+ width += q_xx[lastColumn] - x;
+ if (rowSpan != 1)
+ height += q_yy[lastRow] - y;
+
+ return QRectF(contentsGeometry.x() + x, contentsGeometry.y() + y, width, height);
+}
+
+QSizeF QGridLayoutEngine::sizeHint(const QLayoutStyleInfo &styleInfo, Qt::SizeHint which,
+ const QSizeF & /* constraint */) const
+{
+ ensureColumnAndRowData(styleInfo);
+
+ switch (which) {
+ case Qt::MinimumSize:
+ return QSizeF(q_totalBoxes[Hor].q_minimumSize, q_totalBoxes[Ver].q_minimumSize);
+ case Qt::PreferredSize:
+ return QSizeF(q_totalBoxes[Hor].q_preferredSize, q_totalBoxes[Ver].q_preferredSize);
+ case Qt::MaximumSize:
+ return QSizeF(q_totalBoxes[Hor].q_maximumSize, q_totalBoxes[Ver].q_maximumSize);
+ case Qt::MinimumDescent:
+ return QSizeF(-1.0, q_totalBoxes[Hor].q_minimumDescent); // ### doesn't work
+ default:
+ break;
+ }
+ return QSizeF();
+}
+
+QSizePolicy::ControlTypes QGridLayoutEngine::controlTypes(LayoutSide side) const
+{
+ Qt::Orientation orientation = (side == Top || side == Bottom) ? Qt::Vertical : Qt::Horizontal;
+ int row = (side == Top || side == Left) ? effectiveFirstRow(orientation)
+ : effectiveLastRow(orientation);
+ QSizePolicy::ControlTypes result = 0;
+
+ for (int column = columnCount(orientation) - 1; column >= 0; --column) {
+ if (QGridLayoutItem *item = itemAt(row, column, orientation))
+ result |= item->controlTypes(side);
+ }
+ return result;
+}
+
+void QGridLayoutEngine::transpose()
+{
+ invalidate();
+
+ for (int i = q_items.count() - 1; i >= 0; --i)
+ q_items.at(i)->transpose();
+
+ qSwap(q_defaultSpacings[Hor], q_defaultSpacings[Ver]);
+ qSwap(q_infos[Hor], q_infos[Ver]);
+
+ regenerateGrid();
+}
+
+void QGridLayoutEngine::setVisualDirection(Qt::LayoutDirection direction)
+{
+ m_visualDirection = direction;
+}
+
+Qt::LayoutDirection QGridLayoutEngine::visualDirection() const
+{
+ return m_visualDirection;
+}
+
+#ifdef QT_DEBUG
+void QGridLayoutEngine::dump(int indent) const
+{
+ qDebug("%*sEngine", indent, "");
+
+ qDebug("%*s Items (%d)", indent, "", q_items.count());
+ int i;
+ for (i = 0; i < q_items.count(); ++i)
+ q_items.at(i)->dump(indent + 2);
+
+ qDebug("%*s Grid (%d x %d)", indent, "", internalGridRowCount(),
+ internalGridColumnCount());
+ for (int row = 0; row < internalGridRowCount(); ++row) {
+ QString message = QLatin1String("[ ");
+ for (int column = 0; column < internalGridColumnCount(); ++column) {
+ message += QString::number(q_items.indexOf(itemAt(row, column))).rightJustified(3);
+ message += QLatin1String(" ");
+ }
+ message += QLatin1String("]");
+ qDebug("%*s %s", indent, "", qPrintable(message));
+ }
+
+ if (q_defaultSpacings[Hor].value() >= 0.0 || q_defaultSpacings[Ver].value() >= 0.0)
+ qDebug("%*s Default spacings: %g %g", indent, "", q_defaultSpacings[Hor].value(),
+ q_defaultSpacings[Ver].value());
+
+ qDebug("%*s Column and row info", indent, "");
+ q_infos[Hor].dump(indent + 2);
+ q_infos[Ver].dump(indent + 2);
+
+ qDebug("%*s Column and row data", indent, "");
+ q_columnData.dump(indent + 2);
+ q_rowData.dump(indent + 2);
+
+ qDebug("%*s Geometries output", indent, "");
+ for (int pass = 0; pass < 2; ++pass) {
+ QVector<qreal> &cellPos = q_yy;
+ QString message;
+ for (i = 0; i < cellPos.count(); ++i) {
+ message += QLatin1String((message.isEmpty() ? "[" : ", "));
+ message += QString::number(cellPos.at(i));
+ }
+ message += QLatin1String("]");
+ qDebug("%*s %s %s", indent, "", (pass == 0 ? "rows:" : "columns:"), qPrintable(message));
+ cellPos = q_xx;
+ }
+}
+#endif
+
+void QGridLayoutEngine::maybeExpandGrid(int row, int column, Qt::Orientation orientation)
+{
+ invalidate(); // ### move out of here?
+
+ if (orientation == Qt::Horizontal)
+ qSwap(row, column);
+
+ if (row < rowCount() && column < columnCount())
+ return;
+
+ int oldGridRowCount = internalGridRowCount();
+ int oldGridColumnCount = internalGridColumnCount();
+
+ q_infos[Ver].count = qMax(row + 1, rowCount());
+ q_infos[Hor].count = qMax(column + 1, columnCount());
+
+ int newGridRowCount = internalGridRowCount();
+ int newGridColumnCount = internalGridColumnCount();
+
+ int newGridSize = newGridRowCount * newGridColumnCount;
+ if (newGridSize != q_grid.count()) {
+ q_grid.resize(newGridSize);
+
+ if (newGridColumnCount != oldGridColumnCount) {
+ for (int i = oldGridRowCount - 1; i >= 1; --i) {
+ for (int j = oldGridColumnCount - 1; j >= 0; --j) {
+ int oldIndex = (i * oldGridColumnCount) + j;
+ int newIndex = (i * newGridColumnCount) + j;
+
+ Q_ASSERT(newIndex > oldIndex);
+ q_grid[newIndex] = q_grid[oldIndex];
+ q_grid[oldIndex] = 0;
+ }
+ }
+ }
+ }
+}
+
+void QGridLayoutEngine::regenerateGrid()
+{
+ q_grid.fill(0);
+
+ for (int i = q_items.count() - 1; i >= 0; --i) {
+ QGridLayoutItem *item = q_items.at(i);
+
+ for (int j = item->firstRow(); j <= item->lastRow(); ++j) {
+ for (int k = item->firstColumn(); k <= item->lastColumn(); ++k) {
+ setItemAt(j, k, item);
+ }
+ }
+ }
+}
+
+void QGridLayoutEngine::setItemAt(int row, int column, QGridLayoutItem *item)
+{
+ Q_ASSERT(row >= 0 && row < rowCount());
+ Q_ASSERT(column >= 0 && column < columnCount());
+ q_grid[(row * internalGridColumnCount()) + column] = item;
+}
+
+void QGridLayoutEngine::insertOrRemoveRows(int row, int delta, Qt::Orientation orientation)
+{
+ int oldRowCount = rowCount(orientation);
+ Q_ASSERT(uint(row) <= uint(oldRowCount));
+
+ invalidate();
+
+ // appending rows (or columns) is easy
+ if (row == oldRowCount && delta > 0) {
+ maybeExpandGrid(oldRowCount + delta - 1, -1, orientation);
+ return;
+ }
+
+ q_infos[orientation == Qt::Vertical].insertOrRemoveRows(row, delta);
+
+ for (int i = q_items.count() - 1; i >= 0; --i)
+ q_items.at(i)->insertOrRemoveRows(row, delta, orientation);
+
+ q_grid.resize(internalGridRowCount() * internalGridColumnCount());
+ regenerateGrid();
+}
+
+void QGridLayoutEngine::fillRowData(QGridLayoutRowData *rowData, const QLayoutStyleInfo &styleInfo,
+ Qt::Orientation orientation) const
+{
+ const int ButtonMask = QSizePolicy::ButtonBox | QSizePolicy::PushButton;
+ const QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical];
+ const QGridLayoutRowInfo &columnInfo = q_infos[orientation == Qt::Horizontal];
+ LayoutSide top = (orientation == Qt::Vertical) ? Top : Left;
+ LayoutSide bottom = (orientation == Qt::Vertical) ? Bottom : Right;
+
+ QStyle *style = styleInfo.style();
+ QStyleOption option;
+ option.initFrom(styleInfo.widget());
+
+ const QLayoutParameter<qreal> &defaultSpacing = q_defaultSpacings[orientation == Qt::Vertical];
+ qreal innerSpacing = 0.0;
+ if (style)
+ innerSpacing = (qreal)style->pixelMetric(orientation == Qt::Vertical ? QStyle::PM_LayoutVerticalSpacing
+ : QStyle::PM_LayoutHorizontalSpacing,
+ &option, styleInfo.widget());
+ if (innerSpacing >= 0.0)
+ defaultSpacing.setCachedValue(innerSpacing);
+
+ for (int row = 0; row < rowInfo.count; ++row) {
+ bool rowIsEmpty = true;
+ bool rowIsIdenticalToPrevious = (row > 0);
+
+ for (int column = 0; column < columnInfo.count; ++column) {
+ QGridLayoutItem *item = itemAt(row, column, orientation);
+
+ if (rowIsIdenticalToPrevious && item != itemAt(row - 1, column, orientation))
+ rowIsIdenticalToPrevious = false;
+
+ if (item)
+ rowIsEmpty = false;
+ }
+
+ if ((rowIsEmpty || rowIsIdenticalToPrevious)
+ && rowInfo.spacings.value(row).isDefault()
+ && rowInfo.stretches.value(row).isDefault()
+ && rowInfo.boxes.value(row) == QGridLayoutBox())
+ rowData->ignore.setBit(row, true);
+
+ if (rowInfo.spacings.value(row).isUser()) {
+ rowData->spacings[row] = rowInfo.spacings.at(row).value();
+ } else if (!defaultSpacing.isDefault()) {
+ rowData->spacings[row] = defaultSpacing.value();
+ }
+
+ rowData->stretches[row] = rowInfo.stretches.value(row).value();
+ }
+
+ struct RowAdHocData {
+ int q_row;
+ unsigned int q_hasButtons : 8;
+ unsigned int q_hasNonButtons : 8;
+
+ inline RowAdHocData() : q_row(-1), q_hasButtons(false), q_hasNonButtons(false) {}
+ inline void init(int row) {
+ this->q_row = row;
+ q_hasButtons = false;
+ q_hasNonButtons = false;
+ }
+ inline bool hasOnlyButtons() const { return q_hasButtons && !q_hasNonButtons; }
+ inline bool hasOnlyNonButtons() const { return q_hasNonButtons && !q_hasButtons; }
+ };
+ RowAdHocData lastRowAdHocData;
+ RowAdHocData nextToLastRowAdHocData;
+ RowAdHocData nextToNextToLastRowAdHocData;
+
+ rowData->hasIgnoreFlag = false;
+ for (int row = 0; row < rowInfo.count; ++row) {
+ if (rowData->ignore.testBit(row))
+ continue;
+
+ QGridLayoutBox &rowBox = rowData->boxes[row];
+ if (option.state & QStyle::State_Window) {
+ nextToNextToLastRowAdHocData = nextToLastRowAdHocData;
+ nextToLastRowAdHocData = lastRowAdHocData;
+ lastRowAdHocData.init(row);
+ }
+
+ bool userRowStretch = rowInfo.stretches.value(row).isUser();
+ int &rowStretch = rowData->stretches[row];
+
+ bool hasIgnoreFlag = true;
+ for (int column = 0; column < columnInfo.count; ++column) {
+ QGridLayoutItem *item = itemAt(row, column, orientation);
+ if (item) {
+ int itemRow = item->firstRow(orientation);
+ int itemColumn = item->firstColumn(orientation);
+
+ if (itemRow == row && itemColumn == column) {
+ int itemStretch = item->stretchFactor(orientation);
+ if (!(item->sizePolicy(orientation) & QSizePolicy::IgnoreFlag))
+ hasIgnoreFlag = false;
+ int itemRowSpan = item->rowSpan(orientation);
+
+ int effectiveRowSpan = 1;
+ for (int i = 1; i < itemRowSpan; ++i) {
+ if (!rowData->ignore.testBit(i))
+ ++effectiveRowSpan;
+ }
+
+ QGridLayoutBox *box;
+ if (effectiveRowSpan == 1) {
+ box = &rowBox;
+ if (!userRowStretch)
+ rowStretch = qMax(rowStretch, itemStretch);
+ } else {
+ QGridLayoutMultiCellData &multiCell =
+ rowData->multiCellMap[qMakePair(row, effectiveRowSpan)];
+ box = &multiCell.q_box;
+ multiCell.q_stretch = itemStretch;
+ }
+ box->combine(item->box(orientation));
+
+ if (effectiveRowSpan == 1) {
+ QSizePolicy::ControlTypes controls = item->controlTypes(top);
+ if (controls & ButtonMask)
+ lastRowAdHocData.q_hasButtons = true;
+ if (controls & ~ButtonMask)
+ lastRowAdHocData.q_hasNonButtons = true;
+ }
+ }
+ }
+ }
+ if (row < rowInfo.boxes.count()) {
+ QGridLayoutBox rowBoxInfo = rowInfo.boxes.at(row);
+ rowBoxInfo.normalize();
+ rowBox.q_minimumSize = qMax(rowBox.q_minimumSize, rowBoxInfo.q_minimumSize);
+ rowBox.q_maximumSize = qMax(rowBox.q_minimumSize,
+ (rowBoxInfo.q_maximumSize != FLT_MAX ?
+ rowBoxInfo.q_maximumSize : rowBox.q_maximumSize));
+ rowBox.q_preferredSize = qBound(rowBox.q_minimumSize,
+ qMax(rowBox.q_preferredSize, rowBoxInfo.q_preferredSize),
+ rowBox.q_maximumSize);
+ }
+ if (hasIgnoreFlag)
+ rowData->hasIgnoreFlag = true;
+ }
+
+ /*
+ Heuristic: Detect button boxes that don't use QSizePolicy::ButtonBox.
+ This is somewhat ad hoc but it usually does the trick.
+ */
+ bool lastRowIsButtonBox = (lastRowAdHocData.hasOnlyButtons()
+ && nextToLastRowAdHocData.hasOnlyNonButtons());
+ bool lastTwoRowsIsButtonBox = (lastRowAdHocData.hasOnlyButtons()
+ && nextToLastRowAdHocData.hasOnlyButtons()
+ && nextToNextToLastRowAdHocData.hasOnlyNonButtons()
+ && orientation == Qt::Vertical);
+
+ if (defaultSpacing.isDefault()) {
+ int prevRow = -1;
+ for (int row = 0; row < rowInfo.count; ++row) {
+ if (rowData->ignore.testBit(row))
+ continue;
+
+ if (prevRow != -1 && !rowInfo.spacings.value(prevRow).isUser()) {
+ qreal &rowSpacing = rowData->spacings[prevRow];
+ for (int column = 0; column < columnInfo.count; ++column) {
+ QGridLayoutItem *item1 = itemAt(prevRow, column, orientation);
+ QGridLayoutItem *item2 = itemAt(row, column, orientation);
+
+ if (item1 && item2 && item1 != item2) {
+ QSizePolicy::ControlTypes controls1 = item1->controlTypes(bottom);
+ QSizePolicy::ControlTypes controls2 = item2->controlTypes(top);
+
+ if (controls2 & QSizePolicy::PushButton) {
+ if ((row == nextToLastRowAdHocData.q_row && lastTwoRowsIsButtonBox)
+ || (row == lastRowAdHocData.q_row && lastRowIsButtonBox)) {
+ controls2 &= ~QSizePolicy::PushButton;
+ controls2 |= QSizePolicy::ButtonBox;
+ }
+ }
+
+ qreal spacing = style->combinedLayoutSpacing(controls1, controls2,
+ orientation, &option,
+ styleInfo.widget());
+ if (orientation == Qt::Horizontal) {
+ qreal width1 = rowData->boxes.at(prevRow).q_minimumSize;
+ qreal width2 = rowData->boxes.at(row).q_minimumSize;
+ QRectF rect1 = item1->geometryWithin(0.0, 0.0, width1, FLT_MAX, -1.0);
+ QRectF rect2 = item2->geometryWithin(0.0, 0.0, width2, FLT_MAX, -1.0);
+ spacing -= (width1 - (rect1.x() + rect1.width())) + rect2.x();
+ } else {
+ const QGridLayoutBox &box1 = rowData->boxes.at(prevRow);
+ const QGridLayoutBox &box2 = rowData->boxes.at(row);
+ qreal height1 = box1.q_minimumSize;
+ qreal height2 = box2.q_minimumSize;
+ qreal rowDescent1 = fixedDescent(box1.q_minimumDescent,
+ box1.q_minimumAscent, height1);
+ qreal rowDescent2 = fixedDescent(box2.q_minimumDescent,
+ box2.q_minimumAscent, height2);
+ QRectF rect1 = item1->geometryWithin(0.0, 0.0, FLT_MAX, height1,
+ rowDescent1);
+ QRectF rect2 = item2->geometryWithin(0.0, 0.0, FLT_MAX, height2,
+ rowDescent2);
+ spacing -= (height1 - (rect1.y() + rect1.height())) + rect2.y();
+ }
+ rowSpacing = qMax(spacing, rowSpacing);
+ }
+ }
+ }
+ prevRow = row;
+ }
+ } else if (lastRowIsButtonBox || lastTwoRowsIsButtonBox) {
+ /*
+ Even for styles that define a uniform spacing, we cheat a
+ bit and use the window margin as the spacing. This
+ significantly improves the look of dialogs.
+ */
+ int prevRow = lastRowIsButtonBox ? nextToLastRowAdHocData.q_row
+ : nextToNextToLastRowAdHocData.q_row;
+ if (!defaultSpacing.isUser() && !rowInfo.spacings.value(prevRow).isUser()) {
+ qreal windowMargin = style->pixelMetric(orientation == Qt::Vertical
+ ? QStyle::PM_LayoutBottomMargin
+ : QStyle::PM_LayoutRightMargin,
+ &option, styleInfo.widget());
+
+ qreal &rowSpacing = rowData->spacings[prevRow];
+ rowSpacing = qMax(windowMargin, rowSpacing);
+ }
+ }
+}
+
+void QGridLayoutEngine::ensureEffectiveFirstAndLastRows() const
+{
+ if (q_cachedEffectiveFirstRows[Hor] == -1 && !q_items.isEmpty()) {
+ int rowCount = this->rowCount();
+ int columnCount = this->columnCount();
+
+ q_cachedEffectiveFirstRows[Ver] = rowCount;
+ q_cachedEffectiveFirstRows[Hor] = columnCount;
+ q_cachedEffectiveLastRows[Ver] = -1;
+ q_cachedEffectiveLastRows[Hor] = -1;
+
+ for (int i = q_items.count() - 1; i >= 0; --i) {
+ const QGridLayoutItem *item = q_items.at(i);
+
+ for (int j = 0; j < NOrientations; ++j) {
+ Qt::Orientation orientation = (j == Hor) ? Qt::Horizontal : Qt::Vertical;
+ if (item->firstRow(orientation) < q_cachedEffectiveFirstRows[j])
+ q_cachedEffectiveFirstRows[j] = item->firstRow(orientation);
+ if (item->lastRow(orientation) > q_cachedEffectiveLastRows[j])
+ q_cachedEffectiveLastRows[j] = item->lastRow(orientation);
+ }
+ }
+ }
+}
+
+void QGridLayoutEngine::ensureColumnAndRowData(const QLayoutStyleInfo &styleInfo) const
+{
+ if (q_cachedDataForStyleInfo == styleInfo)
+ return;
+
+ q_columnData.reset(columnCount());
+ q_rowData.reset(rowCount());
+
+ fillRowData(&q_columnData, styleInfo, Qt::Horizontal);
+ fillRowData(&q_rowData, styleInfo, Qt::Vertical);
+
+ q_columnData.distributeMultiCells();
+ q_rowData.distributeMultiCells();
+
+ q_totalBoxes[Hor] = q_columnData.totalBox(0, columnCount());
+ q_totalBoxes[Ver] = q_rowData.totalBox(0, rowCount());
+
+ q_cachedDataForStyleInfo = styleInfo;
+}
+
+void QGridLayoutEngine::ensureGeometries(const QLayoutStyleInfo &styleInfo,
+ const QSizeF &size) const
+{
+ ensureColumnAndRowData(styleInfo);
+ if (q_cachedSize == size)
+ return;
+
+ q_xx.resize(columnCount());
+ q_yy.resize(rowCount());
+ q_widths.resize(columnCount());
+ q_heights.resize(rowCount());
+ q_descents.resize(rowCount());
+ q_columnData.calculateGeometries(0, columnCount(), size.width(), q_xx.data(), q_widths.data(),
+ 0, q_totalBoxes[Hor]);
+ q_rowData.calculateGeometries(0, rowCount(), size.height(), q_yy.data(), q_heights.data(),
+ q_descents.data(), q_totalBoxes[Ver]);
+
+ q_cachedSize = size;
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgridlayoutengine_p.h b/src/gui/graphicsview/qgridlayoutengine_p.h
new file mode 100644
index 0000000..acc96de
--- /dev/null
+++ b/src/gui/graphicsview/qgridlayoutengine_p.h
@@ -0,0 +1,449 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRIDLAYOUTENGINE_P_H
+#define QGRIDLAYOUTENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the graphics view layout classes. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qalgorithms.h"
+#include "qbitarray.h"
+#include "qlist.h"
+#include "qmap.h"
+#include "qpair.h"
+#include "qvector.h"
+
+#include <float.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsLayoutItem;
+class QStyle;
+class QWidget;
+
+// ### deal with Descent in a similar way
+enum {
+ MinimumSize = Qt::MinimumSize,
+ PreferredSize = Qt::PreferredSize,
+ MaximumSize = Qt::MaximumSize,
+ NSizes
+};
+
+// do not reorder
+enum {
+ Hor,
+ Ver,
+ NOrientations
+};
+
+// do not reorder
+enum LayoutSide {
+ Left,
+ Top,
+ Right,
+ Bottom
+};
+
+template <typename T>
+class QLayoutParameter
+{
+public:
+ enum State { Default, User, Cached };
+
+ inline QLayoutParameter() : q_value(T()), q_state(Default) {}
+ inline QLayoutParameter(T value, State state = Default) : q_value(value), q_state(state) {}
+
+ inline void setUserValue(T value) {
+ q_value = value;
+ q_state = User;
+ }
+ inline void setCachedValue(T value) const {
+ if (q_state != User) {
+ q_value = value;
+ q_state = Cached;
+ }
+ }
+ inline T value() const { return q_value; }
+ inline T value(T defaultValue) const { return isUser() ? q_value : defaultValue; }
+ inline bool isDefault() const { return q_state == Default; }
+ inline bool isUser() const { return q_state == User; }
+ inline bool isCached() const { return q_state == Cached; }
+
+private:
+ mutable T q_value;
+ mutable State q_state;
+};
+
+class QStretchParameter : public QLayoutParameter<int>
+{
+public:
+ QStretchParameter() : QLayoutParameter<int>(-1) {}
+
+};
+
+class QLayoutStyleInfo
+{
+public:
+ inline QLayoutStyleInfo() { invalidate(); }
+ inline QLayoutStyleInfo(QStyle *style, QWidget *widget)
+ : q_valid(true), q_style(style), q_widget(widget) {}
+
+ inline void invalidate() { q_valid = false; q_style = 0; q_widget = 0; }
+
+ inline QStyle *style() const { return q_style; }
+ inline QWidget *widget() const { return q_widget; }
+
+ inline bool operator==(const QLayoutStyleInfo &other)
+ { return q_style == other.q_style && q_widget == other.q_widget; }
+ inline bool operator!=(const QLayoutStyleInfo &other)
+ { return !(*this == other); }
+
+private:
+ bool q_valid;
+ QStyle *q_style;
+ QWidget *q_widget;
+};
+
+class QGridLayoutBox
+{
+public:
+ inline QGridLayoutBox()
+ : q_minimumSize(0), q_preferredSize(0), q_maximumSize(FLT_MAX),
+ q_minimumDescent(-1), q_minimumAscent(-1) {}
+
+ void add(const QGridLayoutBox &other, int stretch, qreal spacing);
+ void combine(const QGridLayoutBox &other);
+ void normalize();
+
+#ifdef QT_DEBUG
+ void dump(int indent = 0) const;
+#endif
+ // This code could use the union-struct-array trick, but a compiler
+ // bug prevents this from working.
+ qreal q_minimumSize;
+ qreal q_preferredSize;
+ qreal q_maximumSize;
+ qreal q_minimumDescent;
+ qreal q_minimumAscent;
+ inline qreal &q_sizes(int which)
+ {
+ qreal *t;
+ switch (which) {
+ case Qt::MinimumSize:
+ t = &q_minimumSize;
+ break;
+ case Qt::PreferredSize:
+ t = &q_preferredSize;
+ break;
+ case Qt::MaximumSize:
+ t = &q_maximumSize;
+ break;
+ case Qt::MinimumDescent:
+ t = &q_minimumDescent;
+ break;
+ case (Qt::MinimumDescent + 1):
+ t = &q_minimumAscent;
+ break;
+ default:
+ t = 0;
+ break;
+ }
+ return *t;
+ }
+ inline const qreal &q_sizes(int which) const
+ {
+ const qreal *t;
+ switch (which) {
+ case Qt::MinimumSize:
+ t = &q_minimumSize;
+ break;
+ case Qt::PreferredSize:
+ t = &q_preferredSize;
+ break;
+ case Qt::MaximumSize:
+ t = &q_maximumSize;
+ break;
+ case Qt::MinimumDescent:
+ t = &q_minimumDescent;
+ break;
+ case (Qt::MinimumDescent + 1):
+ t = &q_minimumAscent;
+ break;
+ default:
+ t = 0;
+ break;
+ }
+ return *t;
+ }
+};
+
+bool operator==(const QGridLayoutBox &box1, const QGridLayoutBox &box2);
+inline bool operator!=(const QGridLayoutBox &box1, const QGridLayoutBox &box2)
+ { return !operator==(box1, box2); }
+
+class QGridLayoutMultiCellData
+{
+public:
+ inline QGridLayoutMultiCellData() : q_stretch(-1) {}
+
+ QGridLayoutBox q_box;
+ int q_stretch;
+};
+
+typedef QMap<QPair<int, int>, QGridLayoutMultiCellData> MultiCellMap;
+
+class QGridLayoutRowData
+{
+public:
+ void reset(int count);
+ void distributeMultiCells();
+ void calculateGeometries(int start, int end, qreal targetSize, qreal *positions, qreal *sizes,
+ qreal *descents, const QGridLayoutBox &totalBox);
+ QGridLayoutBox totalBox(int start, int end) const;
+ void stealBox(int start, int end, int which, qreal *positions, qreal *sizes);
+
+#ifdef QT_DEBUG
+ void dump(int indent = 0) const;
+#endif
+
+ QBitArray ignore; // ### rename q_
+ QVector<QGridLayoutBox> boxes;
+ MultiCellMap multiCellMap;
+ QVector<int> stretches;
+ QVector<qreal> spacings;
+ bool hasIgnoreFlag;
+};
+
+class QGridLayoutEngine;
+
+class QGridLayoutItem
+{
+public:
+ QGridLayoutItem(QGridLayoutEngine *engine, QGraphicsLayoutItem *layoutItem, int row, int column,
+ int rowSpan = 1, int columnSpan = 1, Qt::Alignment alignment = 0);
+
+ inline int firstRow() const { return q_firstRows[Ver]; }
+ inline int firstColumn() const { return q_firstRows[Hor]; }
+ inline int rowSpan() const { return q_rowSpans[Ver]; }
+ inline int columnSpan() const { return q_rowSpans[Hor]; }
+ inline int lastRow() const { return firstRow() + rowSpan() - 1; }
+ inline int lastColumn() const { return firstColumn() + columnSpan() - 1; }
+
+ int firstRow(Qt::Orientation orientation) const;
+ int firstColumn(Qt::Orientation orientation) const;
+ int lastRow(Qt::Orientation orientation) const;
+ int lastColumn(Qt::Orientation orientation) const;
+ int rowSpan(Qt::Orientation orientation) const;
+ int columnSpan(Qt::Orientation orientation) const;
+ void setFirstRow(int row, Qt::Orientation orientation = Qt::Vertical);
+ void setRowSpan(int rowSpan, Qt::Orientation orientation = Qt::Vertical);
+
+ int stretchFactor(Qt::Orientation orientation) const;
+ void setStretchFactor(int stretch, Qt::Orientation orientation);
+
+ inline Qt::Alignment alignment() const { return q_alignment; }
+ inline void setAlignment(Qt::Alignment alignment) { q_alignment = alignment; }
+
+ QSizePolicy::Policy sizePolicy(Qt::Orientation orientation) const;
+ QSizePolicy::ControlTypes controlTypes(LayoutSide side) const;
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+ QGridLayoutBox box(Qt::Orientation orientation, qreal constraint = -1.0) const;
+ QRectF geometryWithin(qreal x, qreal y, qreal width, qreal height, qreal rowDescent) const;
+
+ QGraphicsLayoutItem *layoutItem() const { return q_layoutItem; }
+
+ void setGeometry(const QRectF &rect);
+ void transpose();
+ void insertOrRemoveRows(int row, int delta, Qt::Orientation orientation = Qt::Vertical);
+ QSizeF effectiveMaxSize() const;
+
+#ifdef QT_DEBUG
+ void dump(int indent = 0) const;
+#endif
+
+private:
+ QGridLayoutEngine *q_engine; // ### needed?
+ QGraphicsLayoutItem *q_layoutItem;
+ int q_firstRows[NOrientations];
+ int q_rowSpans[NOrientations];
+ int q_stretches[NOrientations];
+ Qt::Alignment q_alignment;
+};
+
+class QGridLayoutRowInfo
+{
+public:
+ inline QGridLayoutRowInfo() : count(0) {}
+
+ void insertOrRemoveRows(int row, int delta);
+
+#ifdef QT_DEBUG
+ void dump(int indent = 0) const;
+#endif
+
+ int count;
+ QVector<QStretchParameter> stretches;
+ QVector<QLayoutParameter<qreal> > spacings;
+ QVector<Qt::Alignment> alignments;
+ QVector<QGridLayoutBox> boxes;
+};
+
+class QGridLayoutEngine
+{
+public:
+ QGridLayoutEngine();
+ inline ~QGridLayoutEngine() { qDeleteAll(q_items); }
+
+ int rowCount(Qt::Orientation orientation) const;
+ int columnCount(Qt::Orientation orientation) const;
+ inline int rowCount() const { return q_infos[Ver].count; }
+ inline int columnCount() const { return q_infos[Hor].count; }
+ // returns the number of items inserted, which may be less than (rowCount * columnCount)
+ int itemCount() const;
+ QGridLayoutItem *itemAt(int index) const;
+
+ int effectiveFirstRow(Qt::Orientation orientation = Qt::Vertical) const;
+ int effectiveLastRow(Qt::Orientation orientation = Qt::Vertical) const;
+
+ void setSpacing(qreal spacing, Qt::Orientations orientations);
+ qreal spacing(const QLayoutStyleInfo &styleInfo, Qt::Orientation orientation) const;
+ // ### setSpacingAfterRow(), spacingAfterRow()
+ void setRowSpacing(int row, qreal spacing, Qt::Orientation orientation = Qt::Vertical);
+ qreal rowSpacing(int row, Qt::Orientation orientation = Qt::Vertical) const;
+
+ void setRowStretchFactor(int row, int stretch, Qt::Orientation orientation = Qt::Vertical);
+ int rowStretchFactor(int row, Qt::Orientation orientation = Qt::Vertical) const;
+
+ void setStretchFactor(QGraphicsLayoutItem *layoutItem, int stretch,
+ Qt::Orientation orientation);
+ int stretchFactor(QGraphicsLayoutItem *layoutItem, Qt::Orientation orientation) const;
+
+ void setRowSizeHint(Qt::SizeHint which, int row, qreal size,
+ Qt::Orientation orientation = Qt::Vertical);
+ qreal rowSizeHint(Qt::SizeHint which, int row,
+ Qt::Orientation orientation = Qt::Vertical) const;
+
+ void setRowAlignment(int row, Qt::Alignment alignment, Qt::Orientation orientation);
+ Qt::Alignment rowAlignment(int row, Qt::Orientation orientation) const;
+
+ void setAlignment(QGraphicsLayoutItem *layoutItem, Qt::Alignment alignment);
+ Qt::Alignment alignment(QGraphicsLayoutItem *layoutItem) const;
+ Qt::Alignment effectiveAlignment(const QGridLayoutItem *layoutItem) const;
+
+
+ void addItem(QGridLayoutItem *item);
+ void removeItem(QGridLayoutItem *item);
+ QGridLayoutItem *findLayoutItem(QGraphicsLayoutItem *layoutItem) const;
+ QGridLayoutItem *itemAt(int row, int column, Qt::Orientation orientation = Qt::Vertical) const;
+ inline void insertRow(int row, Qt::Orientation orientation = Qt::Vertical)
+ { insertOrRemoveRows(row, +1, orientation); }
+ inline void removeRow(int row, Qt::Orientation orientation = Qt::Vertical)
+ { insertOrRemoveRows(row, -1, orientation); }
+
+ void invalidate();
+ void setGeometries(const QLayoutStyleInfo &styleInfo, const QRectF &contentsGeometry);
+ QRectF cellRect(const QLayoutStyleInfo &styleInfo, const QRectF &contentsGeometry, int row,
+ int column, int rowSpan, int columnSpan) const;
+ QSizeF sizeHint(const QLayoutStyleInfo &styleInfo, Qt::SizeHint which,
+ const QSizeF &constraint) const;
+ QSizePolicy::ControlTypes controlTypes(LayoutSide side) const;
+ void transpose();
+ void setVisualDirection(Qt::LayoutDirection direction);
+ Qt::LayoutDirection visualDirection() const;
+#ifdef QT_DEBUG
+ void dump(int indent = 0) const;
+#endif
+
+private:
+ static int grossRoundUp(int n) { return ((n + 2) | 0x3) - 2; }
+
+ void maybeExpandGrid(int row, int column, Qt::Orientation orientation = Qt::Vertical);
+ void regenerateGrid();
+ inline int internalGridRowCount() const { return grossRoundUp(rowCount()); }
+ inline int internalGridColumnCount() const { return grossRoundUp(columnCount()); }
+ void setItemAt(int row, int column, QGridLayoutItem *item);
+ void insertOrRemoveRows(int row, int delta, Qt::Orientation orientation = Qt::Vertical);
+ void fillRowData(QGridLayoutRowData *rowData, const QLayoutStyleInfo &styleInfo,
+ Qt::Orientation orientation = Qt::Vertical) const;
+ void ensureEffectiveFirstAndLastRows() const;
+ void ensureColumnAndRowData(const QLayoutStyleInfo &styleInfo) const;
+ void ensureGeometries(const QLayoutStyleInfo &styleInfo, const QSizeF &size) const;
+
+ // User input
+ QVector<QGridLayoutItem *> q_grid;
+ QList<QGridLayoutItem *> q_items;
+ QLayoutParameter<qreal> q_defaultSpacings[NOrientations];
+ QGridLayoutRowInfo q_infos[NOrientations];
+ Qt::LayoutDirection m_visualDirection;
+
+ // Lazily computed from the above user input
+ mutable int q_cachedEffectiveFirstRows[NOrientations];
+ mutable int q_cachedEffectiveLastRows[NOrientations];
+
+ // Layout item input
+ mutable QLayoutStyleInfo q_cachedDataForStyleInfo;
+ mutable QGridLayoutRowData q_columnData;
+ mutable QGridLayoutRowData q_rowData;
+ mutable QGridLayoutBox q_totalBoxes[NOrientations];
+
+ // Output
+ mutable QSizeF q_cachedSize;
+ mutable QVector<qreal> q_xx;
+ mutable QVector<qreal> q_yy;
+ mutable QVector<qreal> q_widths;
+ mutable QVector<qreal> q_heights;
+ mutable QVector<qreal> q_descents;
+
+ friend class QGridLayoutItem;
+};
+
+QT_END_NAMESPACE
+
+#endif