summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview
diff options
context:
space:
mode:
authorJason Barron <jbarron@trolltech.com>2009-06-25 13:49:53 (GMT)
committerJason Barron <jbarron@trolltech.com>2009-06-25 13:49:53 (GMT)
commitdb8f05e257019694f5e8076845626008f2adc3dd (patch)
tree05d3959403cf15ac5f702091439e028af01f343b /src/gui/graphicsview
parent8aafaa65a1d16f8b982279f5aceedf1e281ddb5a (diff)
parent796a5a2c7d8c91a46ac761dde18b7da2ec6c177b (diff)
downloadQt-db8f05e257019694f5e8076845626008f2adc3dd.zip
Qt-db8f05e257019694f5e8076845626008f2adc3dd.tar.gz
Qt-db8f05e257019694f5e8076845626008f2adc3dd.tar.bz2
Merge commit 'qt/master-stable' into 4.6-stable
Bring Qt 4.6 into the Qt-S60 repo. Conflicts: configure.exe mkspecs/features/qttest_p4.prf qmake/generators/makefile.cpp src/corelib/io/qdir.cpp src/corelib/io/qprocess.h src/corelib/kernel/qcoreevent.h src/corelib/kernel/qobject.cpp src/corelib/kernel/qsharedmemory_unix.cpp src/corelib/thread/qthread_p.h src/corelib/tools/qvector.h src/gui/dialogs/qdialog.cpp src/gui/dialogs/qfiledialog.cpp src/gui/dialogs/qfiledialog_p.h src/gui/dialogs/qmessagebox.cpp src/gui/graphicsview/qgraphicsitem.cpp src/gui/graphicsview/qgraphicsview.cpp src/gui/image/qpixmapcache.cpp src/gui/kernel/qapplication.cpp src/gui/kernel/qapplication_p.h src/gui/kernel/qwidget.cpp src/gui/kernel/qwidget_p.h src/gui/painting/qdrawhelper.cpp src/gui/painting/qpaintengine_raster.cpp src/gui/text/qfontengine_qpf.cpp src/gui/widgets/qmenubar.cpp src/network/socket/qlocalserver.cpp src/testlib/qtestcase.cpp src/testlib/testlib.pro tests/auto/qimagereader/tst_qimagereader.cpp tests/auto/qitemdelegate/tst_qitemdelegate.cpp tests/auto/qnetworkreply/tst_qnetworkreply.cpp tests/auto/qpixmap/qpixmap.pro
Diffstat (limited to 'src/gui/graphicsview')
-rw-r--r--src/gui/graphicsview/graphicsview.pri77
-rw-r--r--src/gui/graphicsview/qgraphicsgridlayout.cpp2
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp2036
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h89
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h202
-rw-r--r--src/gui/graphicsview/qgraphicslayoutitem.cpp134
-rw-r--r--src/gui/graphicsview/qgraphicslayoutitem_p.h8
-rw-r--r--src/gui/graphicsview/qgraphicslinearlayout.cpp2
-rw-r--r--src/gui/graphicsview/qgraphicsproxywidget.cpp11
-rw-r--r--src/gui/graphicsview/qgraphicsproxywidget.h2
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp1133
-rw-r--r--src/gui/graphicsview/qgraphicsscene.h5
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h49
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp579
-rw-r--r--src/gui/graphicsview/qgraphicsview.h7
-rw-r--r--src/gui/graphicsview/qgraphicsview_p.h28
-rw-r--r--src/gui/graphicsview/qgraphicswidget.cpp185
-rw-r--r--src/gui/graphicsview/qgraphicswidget.h15
-rw-r--r--src/gui/graphicsview/qgraphicswidget_p.cpp260
-rw-r--r--src/gui/graphicsview/qgraphicswidget_p.h70
-rw-r--r--src/gui/graphicsview/qgridlayoutengine.cpp24
21 files changed, 3031 insertions, 1887 deletions
diff --git a/src/gui/graphicsview/graphicsview.pri b/src/gui/graphicsview/graphicsview.pri
index 02d9bb1..4cee6d6 100644
--- a/src/gui/graphicsview/graphicsview.pri
+++ b/src/gui/graphicsview/graphicsview.pri
@@ -1,46 +1,37 @@
# 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
+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
-
+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
index 1e21b54..36281f8 100644
--- a/src/gui/graphicsview/qgraphicsgridlayout.cpp
+++ b/src/gui/graphicsview/qgraphicsgridlayout.cpp
@@ -100,7 +100,7 @@ QLayoutStyleInfo QGraphicsGridLayoutPrivate::styleInfo() const
if (!wid)
wid = new QWidget;
QGraphicsItem *item = parentItem();
- QStyle *style = (item && item->isWidget()) ? static_cast<QGraphicsWidget*>(item)->style() : qApp->style();
+ QStyle *style = (item && item->isWidget()) ? static_cast<QGraphicsWidget*>(item)->style() : QApplication::style();
return QLayoutStyleInfo(style, wid);
}
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 596326b..d9cba2a 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -91,30 +91,33 @@
\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.
+ 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 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.
+ \o Reimplement collidesWithItem() to provide your own custom item
+ and shape collision algorithm.
\endlist
@@ -130,21 +133,42 @@
\img graphicsview-parentchild.png
+ \section1 Transformation
+
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(),
+ position, pos(). To change the item's transformation, you can pass
+ a transformation matrix to setTransform()
+
+ 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().
+ 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().
+
+ Another way to apply transformation to an item is to use the , or
+ set the different transformation properties (transformOrigin,
+ x/y/zRotation, x/yScale, horizontal/verticalShear). Those
+ properties come in addition to the base transformation
+
+ The order you set the transformation properties does not affect
+ the resulting transformation The resulting transformation is
+ always computed in the following order
+
+ \code
+ [Origin] [Base] [RotateX] [RotateY] [RotateZ] [Shear] [Scale] [-Origin]
+ \endcode
+
+ Where [Base] is the stransformation set by setTransform
+
+ \section1 Painting
The paint() function is called by QGraphicsView to paint the item's
contents. The item has no background or default fill of its own; whatever
@@ -161,6 +185,8 @@
high z-values. Stacking order applies to sibling items; parents are always
drawn before their children.
+ \section1 Events
+
QGraphicsItem receives events from QGraphicsScene through the virtual
function sceneEvent(). This function distributes the most common events
to a set of convenience event handlers:
@@ -186,6 +212,8 @@
by the virtual function sceneEventFilter(). You can remove item
event filters by calling removeSceneEventFilter().
+ \section1 Custom Data
+
Sometimes it's useful to register custom data with an item, be it a custom
item, or a standard item. You can call setData() on any item to store data
in it using a key-value pair (the key being an integer, and the value is a
@@ -274,6 +302,27 @@
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.
+
+ \value ItemUsesExtendedStyleOption The item makes use of either
+ QStyleOptionGraphicsItem::exposedRect or QStyleOptionGraphicsItem::matrix.
+ By default, the exposedRect is initialized to the item's boundingRect and
+ the matrix is untransformed. Enable this flag for more fine-grained values.
+ Note that QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag
+ and is always initialized to 1.
+ Use QStyleOptionGraphicsItem::levelOfDetailFromTransform for a more
+ fine-grained value.
+
+ \value ItemHasNoContents The item does not paint anything (i.e., calling
+ paint() on the item has no effect). You should set this flag on items that
+ do not need to be painted to ensure that Graphics View avoids unnecessary
+ painting preparations. This flag was introduced in Qt 4.6.
+
+ \value ItemSendsGeometryChanges The item enables itemChange()
+ notifications for ItemPositionChange, ItemPositionHasChanged,
+ ItemMatrixChange, ItemTransformChange, and ItemTransformHasChanged. For
+ performance reasons, these notifications are disabled by default. You must
+ enable this flag to receive notifications for position and transform
+ changes. This flag was introduced in Qt 4.6.
*/
/*!
@@ -312,33 +361,37 @@
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.
+ is sent if the ItemSendsGeometryChanges flag is enabled, and when the
+ item's local position changes, relative to its parent (i.e., as a result
+ of calling setPos() or moveBy()). The value argument is the new position
+ (i.e., a QPointF). You can call pos() to get the original position. Do
+ not call setPos() or moveBy() in itemChange() as this notification is
+ delivered; instead, you can return the new, adjusted position from
+ itemChange(). After this notification, QGraphicsItem immediately sends the
+ ItemPositionHasChanged notification if the position changed.
\value ItemPositionHasChanged The item's position has changed. This
- notification is 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).
+ notification is sent if the ItemSendsGeometryChanges flag is enabled, and
+ after the item's local position, relative to its parent, has changed. The
+ value argument is the new position (the same as pos()), and QGraphicsItem
+ ignores the return value for this notification (i.e., a read-only
+ notification).
\value ItemTransformChange The item's transformation matrix changes. This
- notification is 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().
+ notification is send if the ItemSendsGeometryChanges flag is enabled, and
+ when the item's local transformation matrix changes (i.e., as a result of
+ calling setTransform(). The value argument is the new matrix (i.e., a
+ QTransform); to get the old matrix, call transform(). Do not call
+ setTransform() or set any of the transformation properties in itemChange()
+ as this notification is delivered; instead, you can return the new matrix
+ from itemChange(). This notification is not sent if you change the
+ transformation properties.
\value ItemTransformHasChanged The item's transformation matrix has
- changed. This notification is only sent after the item's local
- trasformation matrix has changed. The value argument is the new matrix
+ changed either because setTransform is called, or one of the
+ transformation properties is changed. This notification is sent if the
+ ItemSendsGeometryChanges flag is enabled, and after the item's local
+ transformation matrix has changed. The value argument is the new matrix
(same as transform()), and QGraphicsItem ignores the return value for this
notification (i.e., a read-only notification).
@@ -523,6 +576,11 @@
#include <private/qtextdocumentlayout_p.h>
#include <private/qtextengine_p.h>
+#ifdef Q_WS_X11
+#include <private/qt_x11_p.h>
+#include <private/qpixmap_x11_p.h>
+#endif
+
#include <math.h>
QT_BEGIN_NAMESPACE
@@ -560,29 +618,6 @@ 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.
*/
@@ -755,12 +790,43 @@ QPointF QGraphicsItemPrivate::genericMapFromScene(const QPointF &pos,
/*!
\internal
- Returns true if this item or any of its ancestors are untransformable.
+ Combines this item's position and transform onto \a transform.
+
+ If you need to change this function (e.g., adding more transformation
+ modes / options), make sure to change all places marked with COMBINE.
+*/
+void QGraphicsItemPrivate::combineTransformToParent(QTransform *x, const QTransform *viewTransform) const
+{
+ // COMBINE
+ if (itemIsUntransformable() && viewTransform) {
+ *x = q_ptr->deviceTransform(*viewTransform);
+ } else {
+ if (transformData)
+ *x *= transformData->computedFullTransform();
+ if (!pos.isNull())
+ *x *= QTransform::fromTranslate(pos.x(), pos.y());
+ }
+}
+
+/*!
+ \internal
+
+ Combines this item's position and transform onto \a transform.
+
+ If you need to change this function (e.g., adding more transformation
+ modes / options), make sure to change QGraphicsItem::deviceTransform() as
+ well.
*/
-bool QGraphicsItemPrivate::itemIsUntransformable() const
+void QGraphicsItemPrivate::combineTransformFromParent(QTransform *x, const QTransform *viewTransform) const
{
- return (flags & QGraphicsItem::ItemIgnoresTransformations)
- || (ancestorFlags & AncestorIgnoresTransformations);
+ // COMBINE
+ if (itemIsUntransformable() && viewTransform) {
+ *x = q_ptr->deviceTransform(*viewTransform);
+ } else {
+ x->translate(pos.x(), pos.y());
+ if (transformData)
+ *x = transformData->computedFullTransform(x);
+ }
}
/*!
@@ -782,11 +848,217 @@ QVariant QGraphicsItemPrivate::inputMethodQueryHelper(Qt::InputMethodQuery query
/*!
\internal
+ Make sure not to trigger any pure virtual function calls (e.g.,
+ prepareGeometryChange) if the item is in its destructor, i.e.
+ inDestructor is 1.
+*/
+void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent)
+{
+ Q_Q(QGraphicsItem);
+ if (newParent == q) {
+ qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this);
+ return;
+ }
+ if (newParent == parent)
+ return;
+
+ const QVariant newParentVariant(q->itemChange(QGraphicsItem::ItemParentChange,
+ qVariantFromValue<QGraphicsItem *>(newParent)));
+ newParent = qVariantValue<QGraphicsItem *>(newParentVariant);
+ if (newParent == parent)
+ return;
+
+ if (QGraphicsWidget *w = isWidget ? static_cast<QGraphicsWidget *>(q) : q->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. If the item is deleted, it will be
+ // removed from the index at a later stage, and the whole scene will be
+ // updated.
+ if (!inDestructor)
+ q_ptr->prepareGeometryChange();
+
+ const QVariant thisPointerVariant(qVariantFromValue<QGraphicsItem *>(q));
+ if (parent) {
+ // Remove from current parent
+ parent->d_ptr->removeChild(q);
+ parent->itemChange(QGraphicsItem::ItemChildRemovedChange, thisPointerVariant);
+ }
+
+ // Update toplevelitem list. If this item is being deleted, its parent
+ // will be 0 but we don't want to register/unregister it in the TLI list.
+ if (scene && !inDestructor) {
+ if (parent && !newParent) {
+ scene->d_func()->registerTopLevelItem(q);
+ } else if (!parent && newParent) {
+ scene->d_func()->unregisterTopLevelItem(q);
+ }
+ }
+
+ if ((parent = newParent)) {
+ bool implicitUpdate = false;
+ if (parent->d_func()->scene && parent->d_func()->scene != scene) {
+ // Move this item to its new parent's scene
+ parent->d_func()->scene->addItem(q);
+ implicitUpdate = true;
+ } else if (!parent->d_func()->scene && scene) {
+ // Remove this item from its former scene
+ scene->removeItem(q);
+ }
+
+ parent->d_ptr->addChild(q);
+ parent->itemChange(QGraphicsItem::ItemChildAddedChange, thisPointerVariant);
+ if (!implicitUpdate && scene) {
+ scene->d_func()->markDirty(q_ptr, QRect(),
+ /*invalidateChildren=*/false,
+ /*maybeDirtyClipPath=*/true);
+ }
+
+ // Inherit ancestor flags from the new parent.
+ updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
+ updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape);
+ updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations);
+
+ // Update item visible / enabled.
+ if (parent->isVisible() != visible) {
+ if (!parent->isVisible() || !explicitlyHidden)
+ setVisibleHelper(parent->isVisible(), /* explicit = */ false, /* update = */ !implicitUpdate);
+ }
+ if (parent->isEnabled() != enabled) {
+ if (!parent->isEnabled() || !explicitlyDisabled)
+ setEnabledHelper(parent->isEnabled(), /* explicit = */ false, /* update = */ !implicitUpdate);
+ }
+
+ } else {
+ // Inherit ancestor flags from the new parent.
+ updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
+ updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape);
+ updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations);
+
+ if (!inDestructor) {
+ // Update item visible / enabled.
+ if (!visible && !explicitlyHidden)
+ setVisibleHelper(true, /* explicit = */ false);
+ if (!enabled && !explicitlyDisabled)
+ setEnabledHelper(true, /* explicit = */ false);
+
+ // If the item is being deleted, the whole scene will be updated.
+ if (scene) {
+ scene->d_func()->markDirty(q_ptr, QRect(),
+ /*invalidateChildren=*/false,
+ /*maybeDirtyClipPath=*/true);
+ }
+ }
+ }
+
+ if (scene) {
+ // Invalidate any sort caching; arrival of a new item means we need to
+ // resort.
+ scene->d_func()->invalidateSortCache();
+ }
+
+ // Resolve depth.
+ resolveDepth(parent ? parent->d_ptr->depth : -1);
+ dirtySceneTransform = 1;
+
+ // Deliver post-change notification
+ q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant);
+
+ if (isObject)
+ emit static_cast<QGraphicsObject *>(q)->parentChanged();
+}
+
+/*!
+ \internal
+
+ Returns the bounding rect of this item's children (excluding itself).
+*/
+void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rect)
+{
+ if (!dirtyChildrenBoundingRect) {
+ *rect |= x->mapRect(childrenBoundingRect);
+ return;
+ }
+
+ for (int i = 0; i < children.size(); ++i) {
+ QGraphicsItem *child = children.at(i);
+ QGraphicsItemPrivate *childd = child->d_ptr;
+ bool hasPos = !childd->pos.isNull();
+ if (hasPos || childd->transformData) {
+ // COMBINE
+ QTransform matrix = childd->transformToParent() * *x;
+ *rect |= matrix.mapRect(child->boundingRect());
+ if (!childd->children.isEmpty())
+ childd->childrenBoundingRectHelper(&matrix, rect);
+ } else {
+ *rect |= x->mapRect(child->boundingRect());
+ if (!childd->children.isEmpty())
+ childd->childrenBoundingRectHelper(x, rect);
+ }
+ }
+
+ childrenBoundingRect = *rect;
+ dirtyChildrenBoundingRect = 0;
+}
+
+void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform,
+ const QRegion &exposedRegion, bool allItems) const
+{
+ Q_ASSERT(option);
+ Q_Q(const QGraphicsItem);
+
+ // Initialize standard QStyleOption values.
+ const QRectF brect = q->boundingRect();
+ option->state = QStyle::State_None;
+ option->rect = brect.toRect();
+ option->levelOfDetail = 1;
+ option->exposedRect = brect;
+ if (selected)
+ option->state |= QStyle::State_Selected;
+ if (enabled)
+ option->state |= QStyle::State_Enabled;
+ if (q->hasFocus())
+ option->state |= QStyle::State_HasFocus;
+ if (scene) {
+ if (scene->d_func()->hoverItems.contains(q_ptr))
+ option->state |= QStyle::State_MouseOver;
+ if (q == scene->mouseGrabberItem())
+ option->state |= QStyle::State_Sunken;
+ }
+
+ if (!(flags & QGraphicsItem::ItemUsesExtendedStyleOption))
+ return;
+
+ // Initialize QStyleOptionGraphicsItem specific values (matrix, exposedRect).
+ option->matrix = worldTransform.toAffine(); //### discards perspective
+
+ if (!allItems) {
+ // Determine the item's exposed area
+ option->exposedRect = QRectF();
+ const QTransform reverseMap = worldTransform.inverted();
+ const QVector<QRect> exposedRects(exposedRegion.rects());
+ for (int i = 0; i < exposedRects.size(); ++i) {
+ option->exposedRect |= reverseMap.mapRect(exposedRects.at(i));
+ if (option->exposedRect.contains(brect))
+ break;
+ }
+ option->exposedRect &= brect;
+ }
+}
+
+/*!
+ \internal
+
Empty all cached pixmaps from the pixmap cache.
*/
void QGraphicsItemCache::purge()
{
QPixmapCache::remove(key);
+ key = QPixmapCache::Key();
QMutableMapIterator<QPaintDevice *, DeviceData> it(deviceData);
while (it.hasNext()) {
DeviceData &data = it.next().value();
@@ -854,26 +1126,23 @@ QGraphicsItem::QGraphicsItem(QGraphicsItemPrivate &dd, QGraphicsItem *parent,
*/
QGraphicsItem::~QGraphicsItem()
{
- clearFocus();
+ d_ptr->inDestructor = 1;
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;
+ clearFocus();
+ if (!d_ptr->children.isEmpty()) {
+ QList<QGraphicsItem *> oldChildren = d_ptr->children;
+ qDeleteAll(oldChildren);
+ Q_ASSERT(d_ptr->children.isEmpty());
}
- 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);
+ d_ptr->scene->d_func()->removeItemHelper(this);
+ else
+ d_ptr->setParentItemHelper(0);
+
+ delete d_ptr->transformData;
+ delete d_ptr;
qt_dataStore()->data.remove(this);
}
@@ -955,6 +1224,20 @@ QGraphicsItem *QGraphicsItem::topLevelItem() const
/*!
\since 4.4
+ Returns a pointer to the item's parent, cast to a QGraphicsObject. returns 0 if the parent item
+ is not a QGraphicsObject.
+
+ \sa parentItem(), childItems()
+*/
+QGraphicsObject *QGraphicsItem::parentObject() const
+{
+ QGraphicsItem *p = d_ptr->parent;
+ return (p && p->d_ptr->isObject) ? static_cast<QGraphicsObject *>(p) : 0;
+}
+
+/*!
+ \since 4.4
+
Returns a pointer to the item's parent widget. The item's parent widget is
the closest parent item that is a widget.
@@ -1002,6 +1285,28 @@ QGraphicsWidget *QGraphicsItem::window() const
}
/*!
+ \since 4.6
+
+ Return the graphics item cast to a QGraphicsObject, if the class is actually a
+ graphics object, 0 otherwise.
+*/
+QGraphicsObject *QGraphicsItem::toGraphicsObject()
+{
+ return d_ptr->isObject ? static_cast<QGraphicsObject *>(this) : 0;
+}
+
+/*!
+ \since 4.6
+
+ Return the graphics item cast to a QGraphicsObject, if the class is actually a
+ graphics object, 0 otherwise.
+*/
+const QGraphicsObject *QGraphicsItem::toGraphicsObject() const
+{
+ return d_ptr->isObject ? static_cast<const QGraphicsObject *>(this) : 0;
+}
+
+/*!
Sets this item's parent item to \a 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.
@@ -1014,98 +1319,7 @@ QGraphicsWidget *QGraphicsItem::window() const
*/
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;
- const QVariant newParentVariant(itemChange(ItemParentChange, qVariantFromValue<QGraphicsItem *>(parent)));
- parent = qVariantValue<QGraphicsItem *>(newParentVariant);
- 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();
-
- const QVariant thisPointerVariant(qVariantFromValue<QGraphicsItem *>(this));
- if (d_ptr->parent) {
- // Remove from current parent
- qt_graphicsitem_removeChild(this, &d_ptr->parent->d_func()->children);
- d_ptr->parent->itemChange(ItemChildRemovedChange, thisPointerVariant);
- }
-
- 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;
- d_ptr->parent->itemChange(ItemChildAddedChange, thisPointerVariant);
- if (!implicitUpdate)
- d_ptr->updateHelper(QRectF(), false, true);
-
- // 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(QRectF(), false, true);
- }
-
- 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.
- d_ptr->updateEffectiveOpacity();
-
- // Resolve depth.
- d_ptr->resolveDepth(parent ? parent->d_ptr->depth : -1);
-
- // Invalidate transform cache.
- d_ptr->invalidateSceneTransformCache();
-
- // Deliver post-change notification
- itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant);
+ d_ptr->setParentItemHelper(parent);
}
/*!
@@ -1210,7 +1424,9 @@ static void _q_qgraphicsItemSetFlag(QGraphicsItem *item, QGraphicsItem::Graphics
item was selected, and \a flags does not enabled ItemIsSelectable, the
item is automatically unselected.
- By default, no flags are enabled.
+ By default, no flags are enabled. (QGraphicsWidget enables the
+ ItemSendsGeometryChanges flag by default in order to track position
+ changes.)
\sa flags(), setFlag()
*/
@@ -1227,7 +1443,7 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags)
const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations);
bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask);
if (fullUpdate)
- d_ptr->fullUpdateHelper(false, true);
+ d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
// Keep the old flags to compare the diff.
GraphicsItemFlags oldFlags = this->flags();
@@ -1235,11 +1451,6 @@ void QGraphicsItem::setFlags(GraphicsItemFlags 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))
- d_ptr->updateEffectiveOpacity();
-
if (!(d_ptr->flags & ItemIsFocusable) && hasFocus()) {
// Clear focus on the item if it has focus when the focusable flag
// is unset.
@@ -1267,8 +1478,19 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags)
d_ptr->updateAncestorFlag(ItemIgnoresTransformations);
}
- // ### Why updateHelper?
- d_ptr->updateHelper(QRectF(), false, true);
+ if ((flags & ItemStacksBehindParent) != (oldFlags & ItemStacksBehindParent)) {
+ // Ensure child item sorting is up to date when toggling this flag.
+ if (d_ptr->parent)
+ d_ptr->parent->d_ptr->needSortChildren = 1;
+ else if (d_ptr->scene)
+ d_ptr->scene->d_func()->needSortTopLevelItems = 1;
+ }
+
+ if (d_ptr->scene) {
+ d_ptr->scene->d_func()->markDirty(this, QRectF(),
+ /*invalidateChildren=*/true,
+ /*maybeDirtyClipPath*/true);
+ }
// Notify change.
itemChange(ItemFlagsHaveChanged, quint32(flags));
@@ -1331,12 +1553,6 @@ void QGraphicsItem::setCacheMode(CacheMode mode, const QSize &logicalCacheSize)
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;
@@ -1414,7 +1630,9 @@ void QGraphicsItem::setCursor(const QCursor &cursor)
d_ptr->setExtra(QGraphicsItemPrivate::ExtraCursor, qVariantValue<QCursor>(cursorVariant));
d_ptr->hasCursor = 1;
if (d_ptr->scene) {
+ d_ptr->scene->d_func()->allItemsUseDefaultCursor = false;
foreach (QGraphicsView *view, d_ptr->scene->views()) {
+ view->viewport()->setMouseTracking(true);
// Note: Some of this logic is duplicated in QGraphicsView's mouse events.
if (view->underMouse()) {
foreach (QGraphicsItem *itemUnderCursor, view->items(view->mapFromGlobal(QCursor::pos()))) {
@@ -1538,7 +1756,12 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo
QGraphicsItemCache *c = (QGraphicsItemCache *)qVariantValue<void *>(extra(ExtraCacheData));
if (c)
c->purge();
- updateHelper(QRectF(), /* force = */ true);
+ if (scene) {
+ scene->d_func()->markDirty(q_ptr, QRectF(),
+ /*invalidateChildren=*/false,
+ /*maybeDirtyClipPath=*/false,
+ /*force=*/true);
+ }
}
// Certain properties are dropped as an item becomes invisible.
@@ -1591,6 +1814,9 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo
// Deliver post-change notification.
q_ptr->itemChange(QGraphicsItem::ItemVisibleHasChanged, newVisibleVariant);
+
+ if (isObject)
+ emit static_cast<QGraphicsObject *>(q_ptr)->visibleChanged();
}
/*!
@@ -1701,8 +1927,8 @@ void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bo
enabled = newEnabledVariant.toBool();
// Schedule redraw.
- if (update)
- updateHelper();
+ if (update && scene)
+ scene->d_func()->markDirty(q_ptr);
foreach (QGraphicsItem *child, children) {
if (!newEnabled || !child->d_ptr->explicitlyDisabled)
@@ -1711,6 +1937,9 @@ void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bo
// Deliver post-change notification.
q_ptr->itemChange(QGraphicsItem::ItemEnabledHasChanged, newEnabledVariant);
+
+ if (isObject)
+ emit static_cast<QGraphicsObject *>(q_ptr)->enabledChanged();
}
/*!
@@ -1803,9 +2032,8 @@ void QGraphicsItem::setSelected(bool selected)
return;
d_ptr->selected = newSelected;
- d_ptr->updateHelper();
-
if (d_ptr->scene) {
+ d_ptr->scene->d_func()->markDirty(this);
QGraphicsScenePrivate *sceneD = d_ptr->scene->d_func();
if (selected) {
sceneD->selectedItems << this;
@@ -1841,12 +2069,7 @@ void QGraphicsItem::setSelected(bool selected)
*/
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);
+ return d_ptr->opacity;
}
/*!
@@ -1862,11 +2085,7 @@ qreal QGraphicsItem::opacity() const
*/
qreal QGraphicsItem::effectiveOpacity() const
{
- if (!d_ptr->hasEffectiveOpacity)
- return qreal(1.0);
-
- QVariant effectiveOpacity = d_ptr->extra(QGraphicsItemPrivate::ExtraEffectiveOpacity);
- return effectiveOpacity.isNull() ? qreal(1.0) : qreal(effectiveOpacity.toDouble());
+ return d_ptr->effectiveOpacity();
}
/*!
@@ -1901,30 +2120,24 @@ void QGraphicsItem::setOpacity(qreal opacity)
newOpacity = qBound<qreal>(0.0, newOpacity, 1.0);
// No change? Done.
- if (qFuzzyCompare(newOpacity, this->opacity()))
+ if (newOpacity == d_ptr->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);
+ d_ptr->opacity = newOpacity;
// Notify change.
- itemChange(ItemOpacityHasChanged, newOpacity);
+ itemChange(ItemOpacityHasChanged, newOpacityVariant);
// Update.
- d_ptr->fullUpdateHelper(/*childrenOnly=*/false, /*maybeDirtyClipPath=*/false, /*ignoreOpacity=*/true);
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->markDirty(this, QRectF(),
+ /*invalidateChildren=*/true,
+ /*maybeDirtyClipPath=*/false,
+ /*force=*/false,
+ /*ignoreOpacity=*/true);
+
+ if (d_ptr->isObject)
+ emit static_cast<QGraphicsObject *>(this)->opacityChanged();
}
/*!
@@ -2050,7 +2263,13 @@ bool QGraphicsItem::acceptsHoverEvents() const
*/
void QGraphicsItem::setAcceptHoverEvents(bool enabled)
{
+ if (d_ptr->acceptsHover == quint32(enabled))
+ return;
d_ptr->acceptsHover = quint32(enabled);
+ if (d_ptr->acceptsHover && d_ptr->scene && d_ptr->scene->d_func()->allItemsIgnoreHoverEvents) {
+ d_ptr->scene->d_func()->allItemsIgnoreHoverEvents = false;
+ d_ptr->scene->d_func()->enableMouseTrackingOnViews();
+ }
}
/*!
@@ -2060,7 +2279,7 @@ void QGraphicsItem::setAcceptHoverEvents(bool enabled)
*/
void QGraphicsItem::setAcceptsHoverEvents(bool enabled)
{
- d_ptr->acceptsHover = quint32(enabled);
+ setAcceptHoverEvents(enabled);
}
/*!
@@ -2328,6 +2547,17 @@ QPointF QGraphicsItem::pos() const
*/
/*!
+ Set's the \a x coordinate of the item's position. Equivalent to
+ calling setPos(x, y()).
+
+ \sa x(), setPos()
+*/
+void QGraphicsItem::setX(qreal x)
+{
+ d_ptr->setPosHelper(QPointF(x, d_ptr->pos.y()));
+}
+
+/*!
\fn QGraphicsItem::y() const
This convenience function is equivalent to calling pos().y().
@@ -2336,6 +2566,17 @@ QPointF QGraphicsItem::pos() const
*/
/*!
+ Set's the \a y coordinate of the item's position. Equivalent to
+ calling setPos(x(), y).
+
+ \sa x(), setPos()
+*/
+void QGraphicsItem::setY(qreal y)
+{
+ d_ptr->setPosHelper(QPointF(d_ptr->pos.x(), y));
+}
+
+/*!
Returns the item's position in scene coordinates. This is
equivalent to calling \c mapToScene(0, 0).
@@ -2349,35 +2590,37 @@ QPointF QGraphicsItem::scenePos() const
/*!
\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.
+ Sets the position \a pos.
*/
void QGraphicsItemPrivate::setPosHelper(const QPointF &pos)
{
Q_Q(QGraphicsItem);
- if (this->pos == pos)
- return;
-
- // Notify the item that the position is changing.
- const QVariant newPosVariant(q->itemChange(QGraphicsItem::ItemPositionChange, pos));
- QPointF newPos = newPosVariant.toPointF();
- if (newPos == this->pos)
- return;
-
- // Update and repositition.
inSetPosHelper = 1;
- updateCachedClipPathFromSetPosHelper(newPos);
- if (scene) {
- fullUpdateHelper(true);
+ updateCachedClipPathFromSetPosHelper(pos);
+ if (scene)
q->prepareGeometryChange();
+ QPointF oldPos = this->pos;
+ this->pos = pos;
+ dirtySceneTransform = 1;
+ inSetPosHelper = 0;
+ if (isObject) {
+ if (pos.x() != oldPos.x())
+ emit static_cast<QGraphicsObject *>(q_ptr)->xChanged();
+ if (pos.y() != oldPos.y())
+ emit static_cast<QGraphicsObject *>(q_ptr)->yChanged();
}
- this->pos = newPos;
- invalidateSceneTransformCache();
+}
- // Send post-notification.
- q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant);
- inSetPosHelper = 0;
+/*!
+ \internal
+
+ Sets the transform \a transform.
+*/
+void QGraphicsItemPrivate::setTransformHelper(const QTransform &transform)
+{
+ q_ptr->prepareGeometryChange();
+ transformData->transform = transform;
+ dirtySceneTransform = 1;
}
/*!
@@ -2392,7 +2635,26 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos)
*/
void QGraphicsItem::setPos(const QPointF &pos)
{
- d_ptr->setPosHelper(pos);
+ if (d_ptr->pos == pos)
+ return;
+
+ // Update and repositition.
+ if (!(d_ptr->flags & ItemSendsGeometryChanges)) {
+ d_ptr->setPosHelper(pos);
+ return;
+ }
+
+ // Notify the item that the position is changing.
+ const QVariant newPosVariant(itemChange(ItemPositionChange, qVariantFromValue<QPointF>(pos)));
+ QPointF newPos = newPosVariant.toPointF();
+ if (newPos == d_ptr->pos)
+ return;
+
+ // Update and repositition.
+ d_ptr->setPosHelper(newPos);
+
+ // Send post-notification.
+ itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant);
}
/*!
@@ -2465,19 +2727,391 @@ QMatrix QGraphicsItem::matrix() const
/*!
\since 4.3
- Returns this item's transformation matrix. If no matrix has been set, the
- identity matrix is returned.
+ Returns this item's transformation matrix.
+
+ Either the one set by setTransform, or the resulting transformation from
+ all the transfmation properties
+
+ If no matrix or transformation property has been set, the
+ identity matrix is returned.
\sa setTransform(), sceneTransform()
*/
QTransform QGraphicsItem::transform() const
{
- if (!d_ptr->hasTransform)
+ if (!d_ptr->transformData)
return QTransform();
- return qVariantValue<QTransform>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform));
+ return d_ptr->transformData->transform;
+}
+
+/*!
+ \since 4.6
+
+ Returns the rotation around the X axis.
+
+ The default is 0
+
+ \warning The value doesn't take in account any rotation set with
+ the setTransform() method.
+
+ \sa setXRotation(), {Transformations}
+*/
+qreal QGraphicsItem::xRotation() const
+{
+ if (!d_ptr->transformData)
+ return 0;
+ return d_ptr->transformData->xRotation;
+}
+
+/*!
+ \since 4.6
+
+ Sets the rotation around the X axis to \a angle degrees.
+
+ \warning The value doesn't take in account any rotation set with the setTransform() method.
+
+ \sa xRotation(), setTransformOrigin(), {Transformations}
+*/
+void QGraphicsItem::setXRotation(qreal angle)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->xRotation = angle;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+ \since 4.6
+
+ Returns the rotation around the Y axis.
+
+ The default is 0
+
+ \warning The value doesn't take in account any rotation set with the setTransform() method.
+
+ \sa setYRotation(), {Transformations}
+*/
+qreal QGraphicsItem::yRotation() const
+{
+ if (!d_ptr->transformData)
+ return 0;
+ return d_ptr->transformData->yRotation;
+}
+
+/*!
+ \since 4.6
+
+ Sets the rotation around the Y axis to \a angle degrees.
+
+ \warning The value doesn't take in account any rotation set with the setTransform() method.
+
+ \sa yRotation(), setTransformOrigin() {Transformations}
+*/
+void QGraphicsItem::setYRotation(qreal angle)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->yRotation = angle;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
}
/*!
+ \since 4.6
+
+ Returns the rotation around the Z axis.
+
+ The default is 0
+
+ \warning The value doesn't take in account any rotation set with the setTransform() method.
+
+ \sa setZRotation(), {Transformations}
+*/
+qreal QGraphicsItem::zRotation() const
+{
+ if (!d_ptr->transformData)
+ return 0;
+ return d_ptr->transformData->zRotation;
+}
+
+/*!
+ \since 4.6
+
+ Sets the rotation around the Z axis to \a angle degrees.
+
+ \warning The value doesn't take in account any rotation set with the setTransform() method.
+
+ \sa zRotation(), setTransformOrigin(), {Transformations}
+*/
+void QGraphicsItem::setZRotation(qreal angle)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->zRotation = angle;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+ \since 4.6
+
+ This convenience function set the rotation angles around the 3 axes
+ to \a x, \a y and \a z.
+
+ \sa setXRotation(), setYRotation(), setZRotation(), {Transformations}
+*/
+void QGraphicsItem::setRotation(qreal x, qreal y, qreal z)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->xRotation = x;
+ d_ptr->transformData->yRotation = y;
+ d_ptr->transformData->zRotation = z;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+ \since 4.6
+
+ Returns the scale factor on the X axis.
+
+ The default is 1
+
+ \warning The value doesn't take in account any scaling set with the setTransform() method.
+
+ \sa setXScale(), {Transformations}
+*/
+qreal QGraphicsItem::xScale() const
+{
+ if (!d_ptr->transformData)
+ return 1;
+ return d_ptr->transformData->xScale;
+}
+
+/*!
+ \since 4.6
+
+ Sets the scale factor on the X axis to \a factor.
+
+ \warning The value doesn't take in account any scaling set with the setTransform() method.
+
+ \sa xScale(), setTransformOrigin(), {Transformations}
+*/
+void QGraphicsItem::setXScale(qreal factor)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->xScale = factor;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+ \since 4.6
+
+ Returns the scale factor on the Y axis.
+
+ The default is 1
+
+ \warning The value doesn't take in account any scaling set with the setTransform() method.
+
+ \sa setYScale(), {Transformations}
+*/
+qreal QGraphicsItem::yScale() const
+{
+ if (!d_ptr->transformData)
+ return 1;
+ return d_ptr->transformData->yScale;
+}
+
+/*!
+ \since 4.6
+
+ Sets the scale factor on the Y axis to \a factor.
+
+ \warning The value doesn't take in account any scaling set with the setTransform() method.
+
+ \sa yScale(), setTransformOrigin(), {Transformations}
+*/
+void QGraphicsItem::setYScale(qreal factor)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->yScale = factor;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+ \since 4.6
+
+ This convenience function set the scaling factors on X and Y axis to \a sx and \a sy.
+
+ \warning The value doesn't take in account any scaling set with the setTransform() method.
+
+ \sa setXScale(), setYScale(), {Transformations}
+*/
+void QGraphicsItem::setScale(qreal sx, qreal sy)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->xScale = sx;
+ d_ptr->transformData->yScale = sy;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+ \since 4.6
+
+ Returns the horizontal shear.
+
+ The default is 0
+
+ \warning The value doesn't take in account any shearing set with the setTransform() method.
+
+ \sa setHorizontalShear(), {Transformations}
+*/
+qreal QGraphicsItem::horizontalShear() const
+{
+ if (!d_ptr->transformData)
+ return 0;
+ return d_ptr->transformData->horizontalShear;
+}
+
+/*!
+ \since 4.6
+
+ Sets the horizontal shear to \a shear.
+
+ \warning The value doesn't take in account any shearing set with the setTransform() method.
+
+ \sa horizontalShear(), {Transformations}
+*/
+void QGraphicsItem::setHorizontalShear(qreal shear)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->horizontalShear = shear;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+ \since 4.6
+
+ Returns the vertical shear.
+
+ The default is 0
+
+ \warning The value doesn't take in account any shearing set with the setTransform() method.
+
+ \sa setHorizontalShear(), {Transformations}
+*/
+qreal QGraphicsItem::verticalShear() const
+{
+ if (!d_ptr->transformData)
+ return 0;
+ return d_ptr->transformData->verticalShear;
+}
+
+/*!
+ \since 4.6
+
+ Sets the vertical shear to \a shear.
+
+ \warning The value doesn't take in account any shearing set with the setTransform() method.
+
+ \sa verticalShear(), {Transformations}
+*/
+void QGraphicsItem::setVerticalShear(qreal shear)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->verticalShear = shear;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+ \since 4.6
+
+ This convenience function sets the horizontal shear to \a sh and the vertical shear to \a sv.
+
+ \warning The value doesn't take in account any shearing set with the setTransform() method.
+
+ \sa setHorizontalShear(), setVerticalShear()
+*/
+void QGraphicsItem::setShear(qreal sh, qreal sv)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->horizontalShear = sh;
+ d_ptr->transformData->verticalShear = sv;
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+ \since 4.6
+
+ Returns the origin point used for transformation in item coordinate.
+
+ The default is QPointF(0,0).
+
+ \sa setTransformOrigin(), {Transformations}
+*/
+QPointF QGraphicsItem::transformOrigin() const
+{
+ if (!d_ptr->transformData)
+ return QPointF(0,0);
+ return QPointF(d_ptr->transformData->xOrigin, d_ptr->transformData->yOrigin);
+}
+
+/*!
+ \since 4.6
+
+ Sets the \a origin for transformation in item coordinate
+
+ \sa transformOrigin(), {Transformations}
+*/
+void QGraphicsItem::setTransformOrigin(const QPointF &origin)
+{
+ prepareGeometryChange();
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+ d_ptr->transformData->xOrigin = origin.x();
+ d_ptr->transformData->yOrigin = origin.y();
+ d_ptr->transformData->onlyTransform = false;
+ d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+ \fn void QGraphicsItem::setTransformOrigin(qreal x, qreal y)
+
+ \since 4.6
+ \overload
+
+ Sets the origin for the transformation to the point
+ composed of \a x and \a y.
+
+ \sa setTransformOrigin(), {Transformations}
+*/
+
+
+/*!
\obsolete
Use sceneTransform() instead.
@@ -2503,51 +3137,23 @@ QMatrix QGraphicsItem::sceneMatrix() const
\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.
+ function includes the item's (and any parents') position, and all the transfomation properties.
- \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}
+ \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}, {Transformations}
*/
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();
- if (!d_ptr->pos.isNull())
- m *= QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y());
- } else if (!d_ptr->pos.isNull()) {
- m = QTransform::fromTranslate(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;
- }
+ if (d_ptr->dirtySceneTransform) {
+ // This item and all its descendants have dirty scene transforms.
+ // We're about to validate this item's scene transform, so we have to
+ // invalidate all the children; otherwise there's no way for the descendants
+ // to detect that the ancestor has changed.
+ d_ptr->invalidateChildrenSceneTransform();
}
- return m;
+
+ QGraphicsItem *that = const_cast<QGraphicsItem *>(this);
+ d_ptr->ensureSceneTransformRecursive(&that);
+ return d_ptr->sceneTransform;
}
/*!
@@ -2597,17 +3203,17 @@ QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) c
// First translate the base untransformable item.
QPointF mappedPoint = (untransformedAncestor->sceneTransform() * viewportTransform).map(QPointF(0, 0));
+
+ // COMBINE
QTransform matrix;
matrix.translate(mappedPoint.x(), mappedPoint.y());
- matrix = untransformedAncestor->transform() * matrix;
+ if (untransformedAncestor->d_ptr->transformData)
+ matrix = untransformedAncestor->d_ptr->transformData->computedFullTransform(&matrix);
// Then transform and translate all children.
for (int i = 0; i < parents.size(); ++i) {
const QGraphicsItem *parent = parents.at(i);
- QPointF pos = parent->pos();
- QTransform moveMatrix;
- moveMatrix.translate(pos.x(), pos.y());
- matrix = (parent->transform() * moveMatrix) * matrix;
+ parent->d_ptr->combineTransformFromParent(&matrix);
}
return matrix;
@@ -2650,51 +3256,40 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co
if (parent == other) {
if (ok)
*ok = true;
- const QPointF &itemPos = d_ptr->pos;
- if (itemPos.isNull())
- return d_ptr->hasTransform ? transform() : QTransform();
- if (d_ptr->hasTransform)
- return transform() * QTransform::fromTranslate(itemPos.x(), itemPos.y());
- return QTransform::fromTranslate(itemPos.x(), itemPos.y());
+ QTransform x;
+ d_ptr->combineTransformFromParent(&x);
+ return x;
}
// This is other's parent
if (otherParent == this) {
const QPointF &otherPos = other->d_ptr->pos;
- if (other->d_ptr->hasTransform) {
- QTransform otherToParent = other->transform();
- if (!otherPos.isNull())
- otherToParent *= QTransform::fromTranslate(otherPos.x(), otherPos.y());
+ if (other->d_ptr->transformData) {
+ QTransform otherToParent;
+ other->d_ptr->combineTransformFromParent(&otherToParent);
return otherToParent.inverted(ok);
- } else {
- if (ok)
- *ok = true;
- return QTransform::fromTranslate(-otherPos.x(), -otherPos.y());
}
+ 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;
+ // COMBINE
const QPointF &itemPos = d_ptr->pos;
const QPointF &otherPos = other->d_ptr->pos;
-
- if (!hasTr && !otherHasTr) {
+ if (!d_ptr->transformData && !other->d_ptr->transformData) {
QPointF delta = itemPos - otherPos;
if (ok)
*ok = true;
return QTransform::fromTranslate(delta.x(), delta.y());
}
- QTransform itemToParent = QTransform::fromTranslate(itemPos.x(), itemPos.y());
- if (hasTr)
- itemToParent = itemPos.isNull() ? transform() : transform() * itemToParent;
-
- QTransform otherToParent = QTransform::fromTranslate(otherPos.x(), otherPos.y());
- if (otherHasTr)
- otherToParent = otherPos.isNull() ? other->transform() : other->transform() * otherToParent;
-
+ QTransform itemToParent;
+ d_ptr->combineTransformFromParent(&itemToParent);
+ QTransform otherToParent;
+ other->d_ptr->combineTransformFromParent(&otherToParent);
return itemToParent * otherToParent.inverted(ok);
}
@@ -2730,11 +3325,7 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co
QTransform x;
const QGraphicsItem *p = child;
do {
- const QGraphicsItemPrivate *pd = p->d_ptr.data();
- if (pd->hasTransform)
- x *= p->transform();
- if (!pd->pos.isNull())
- x *= QTransform::fromTranslate(pd->pos.x(), pd->pos.y());
+ p->d_ptr->.data()->combineTransformToParent(&x);
} while ((p = p->d_ptr->parent) && p != root);
if (parentOfOther)
return x.inverted(ok);
@@ -2752,37 +3343,34 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co
Use setTransform() instead.
- \sa transform(), rotate(), scale(), shear(), translate(), {The Graphics View Coordinate System}
+ \sa transform(), {The Graphics View Coordinate System}
*/
void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
{
- QTransform oldTransform = this->transform();
- QTransform newTransform;
- if (!combine)
- newTransform = QTransform(matrix);
- else
- newTransform = QTransform(matrix) * oldTransform;
- if (oldTransform == newTransform)
- return;
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
- // Notify the item that the matrix is changing.
- QVariant newTransformVariant(itemChange(ItemMatrixChange,
- qVariantFromValue<QMatrix>(newTransform.toAffine())));
- newTransform = QTransform(qVariantValue<QMatrix>(newTransformVariant));
- if (oldTransform == newTransform)
+ QTransform newTransform(combine ? QTransform(matrix) * d_ptr->transformData->transform : QTransform(matrix));
+ if (d_ptr->transformData->transform == newTransform)
return;
// Update and set the new transformation.
- d_ptr->fullUpdateHelper(true, true);
- prepareGeometryChange();
- d_ptr->hasTransform = !newTransform.isIdentity();
- d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform);
- d_ptr->invalidateSceneTransformCache();
+ if (!(d_ptr->flags & ItemSendsGeometryChanges)) {
+ d_ptr->setTransformHelper(newTransform);
+ return;
+ }
+
+ // Notify the item that the transformation matrix is changing.
+ const QVariant newMatrixVariant = qVariantFromValue<QMatrix>(newTransform.toAffine());
+ newTransform = QTransform(qVariantValue<QMatrix>(itemChange(ItemMatrixChange, newMatrixVariant)));
+ if (d_ptr->transformData->transform == newTransform)
+ return;
+ // Update and set the new transformation.
+ d_ptr->setTransformHelper(newTransform);
+
// Send post-notification.
- // NB! We have to change the value from QMatrix to QTransform.
- qVariantSetValue<QTransform>(newTransformVariant, newTransform);
- itemChange(ItemTransformHasChanged, newTransformVariant);
+ itemChange(ItemTransformHasChanged, qVariantFromValue<QTransform>(newTransform));
}
/*!
@@ -2800,32 +3388,34 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
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}
+ \warning using this function doesnt affect the value of the transformation properties
+
+ \sa transform(), setRotation(), setScale(), setShear(), setTransformOrigin(), {The Graphics View Coordinate System}, {Transformations}
*/
void QGraphicsItem::setTransform(const QTransform &matrix, bool combine)
{
- QTransform oldTransform = this->transform();
- QTransform newTransform;
- if (!combine)
- newTransform = matrix;
- else
- newTransform = matrix * oldTransform;
- if (oldTransform == newTransform)
+ if (!d_ptr->transformData)
+ d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+
+ QTransform newTransform(combine ? matrix * d_ptr->transformData->transform : matrix);
+ if (d_ptr->transformData->transform == newTransform)
return;
+ // Update and set the new transformation.
+ if (!(d_ptr->flags & ItemSendsGeometryChanges)) {
+ d_ptr->setTransformHelper(newTransform);
+ return;
+ }
+
// Notify the item that the transformation matrix is changing.
const QVariant newTransformVariant(itemChange(ItemTransformChange,
qVariantFromValue<QTransform>(newTransform)));
newTransform = qVariantValue<QTransform>(newTransformVariant);
- if (oldTransform == newTransform)
+ if (d_ptr->transformData->transform == newTransform)
return;
// Update and set the new transformation.
- d_ptr->fullUpdateHelper(true, true);
- prepareGeometryChange();
- d_ptr->hasTransform = !newTransform.isIdentity();
- d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform);
- d_ptr->invalidateSceneTransformCache();
+ d_ptr->setTransformHelper(newTransform);
// Send post-notification.
itemChange(ItemTransformHasChanged, newTransformVariant);
@@ -2844,8 +3434,9 @@ void QGraphicsItem::resetMatrix()
/*!
\since 4.3
- Resets this item's transformation matrix to the identity matrix. This is
- equivalent to calling \c setTransform(QTransform()).
+ Resets this item's transformation matrix to the identity matrix or
+ all the transformation properties to their default values.
+ This is equivalent to calling \c setTransform(QTransform()).
\sa setTransform(), transform()
*/
@@ -2855,6 +3446,9 @@ void QGraphicsItem::resetTransform()
}
/*!
+ \obsolete
+ Use setZRotation() instead
+
Rotates the current item transformation \a angle degrees clockwise around
its origin. To translate around an arbitrary point (x, y), you need to
combine translation and rotation with setTransform().
@@ -2863,6 +3457,8 @@ void QGraphicsItem::resetTransform()
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 6
+ \warning using this functionhas no effect on the zRotation value
+
\sa setTransform(), transform(), scale(), shear(), translate()
*/
void QGraphicsItem::rotate(qreal angle)
@@ -2871,6 +3467,9 @@ void QGraphicsItem::rotate(qreal angle)
}
/*!
+ \obsolete
+ Use setScale() instead
+
Scales the current item transformation by (\a sx, \a sy) around its
origin. To scale from an arbitrary point (x, y), you need to combine
translation and scaling with setTransform().
@@ -2879,7 +3478,9 @@ void QGraphicsItem::rotate(qreal angle)
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 7
- \sa setTransform(), transform(), rotate(), shear(), translate()
+ \warning using this function has no effect on the xScale or yScale value
+
+ \sa setTransform(), transform()
*/
void QGraphicsItem::scale(qreal sx, qreal sy)
{
@@ -2887,9 +3488,14 @@ void QGraphicsItem::scale(qreal sx, qreal sy)
}
/*!
+ \obsolete
+ Use setShear instead.
+
Shears the current item transformation by (\a sh, \a sv).
- \sa setTransform(), transform(), rotate(), scale(), translate()
+ \warning using this function has no effect on the horizontalShear or verticalShear value
+
+ \sa setTransform(), transform()
*/
void QGraphicsItem::shear(qreal sh, qreal sv)
{
@@ -2897,13 +3503,16 @@ void QGraphicsItem::shear(qreal sh, qreal sv)
}
/*!
+ \obsolete
+ Use setPos() or setTransformOrigin() instead.
+
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()
+ \sa setTransform(), transform()
*/
void QGraphicsItem::translate(qreal dx, qreal dy)
{
@@ -2948,11 +3557,11 @@ qreal QGraphicsItem::zValue() const
/*!
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.
+ 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 order of insertion; the
+ last inserted child is stacked above previous children.
\img graphicsview-zorder.png
@@ -2980,16 +3589,23 @@ void QGraphicsItem::setZValue(qreal z)
qreal newZ = qreal(newZVariant.toDouble());
if (newZ == d_ptr->z)
return;
- d_ptr->z = z;
- d_ptr->fullUpdateHelper();
+ d_ptr->z = newZ;
+ if (d_ptr->parent)
+ d_ptr->parent->d_ptr->needSortChildren = 1;
+ else if (d_ptr->scene)
+ d_ptr->scene->d_func()->needSortTopLevelItems = 1;
if (d_ptr->scene) {
+ d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
// Invalidate any sort caching; arrival of a new item means we need to
// resort.
d_ptr->scene->d_func()->invalidateSortCache();
}
itemChange(ItemZValueHasChanged, newZVariant);
+
+ if (d_ptr->isObject)
+ emit static_cast<QGraphicsObject *>(this)->zChanged();
}
/*!
@@ -3011,14 +3627,12 @@ void QGraphicsItem::setZValue(qreal z)
*/
QRectF QGraphicsItem::childrenBoundingRect() const
{
+ if (!d_ptr->dirtyChildrenBoundingRect)
+ return d_ptr->childrenBoundingRect;
+
QRectF childRect;
- foreach (QGraphicsItem *child, children()) {
- QPointF childPos = child->pos();
- QTransform matrix = child->transform();
- if (!childPos.isNull())
- matrix *= QTransform::fromTranslate(childPos.x(), childPos.y());
- childRect |= matrix.mapRect(child->boundingRect() | child->childrenBoundingRect());
- }
+ QTransform x;
+ d_ptr->childrenBoundingRectHelper(&x, &childRect);
return childRect;
}
@@ -3032,7 +3646,7 @@ QRectF QGraphicsItem::childrenBoundingRect() const
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.).
+ transformation.
If you want to change the item's bounding rectangle, you must first call
prepareGeometryChange(). This notifies the scene of the imminent change,
@@ -3064,12 +3678,13 @@ QRectF QGraphicsItem::childrenBoundingRect() const
QRectF QGraphicsItem::sceneBoundingRect() const
{
// Find translate-only offset
+ // COMBINE
QPointF offset;
const QGraphicsItem *parentItem = this;
const QGraphicsItemPrivate *itemd;
do {
itemd = parentItem->d_ptr.data();
- if (itemd->hasTransform)
+ if (itemd->transformData)
break;
offset += itemd->pos;
} while ((parentItem = itemd->parent));
@@ -3633,7 +4248,7 @@ void QGraphicsItem::setBoundingRegionGranularity(qreal granularity)
All painting is done in local coordinates.
- \sa setCacheMode(), QPen::width(), {Item Coordinates}
+ \sa setCacheMode(), QPen::width(), {Item Coordinates}, ItemUsesExtendedStyleOption
*/
/*!
@@ -3646,7 +4261,7 @@ bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, bool ignore
// No scene, or if the scene is updating everything, means we have nothing
// to do. The only exception is if the scene tracks the growing scene rect.
return (!visible && !ignoreVisibleBit)
- || (dirty && !ignoreDirtyBit)
+ || (!ignoreDirtyBit && fullUpdatePending)
|| !scene
|| (scene->d_func()->updateAll && scene->d_func()->hasSceneRect)
|| (!ignoreClipping && (childrenClippedToShape() && isClippedAway()))
@@ -3656,163 +4271,43 @@ bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, bool ignore
/*!
\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.
+ Resolves the stacking depth of this object and all its children.
*/
-void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force, bool maybeDirtyClipPath)
+void QGraphicsItemPrivate::resolveDepth(int parentDepth)
{
- // 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 (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/force))
- return;
-
- if (rect.isNull())
- dirty = 1;
- scene->itemUpdated(q_ptr, rect);
+ depth = parentDepth + 1;
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->resolveDepth(depth);
}
/*!
\internal
-
- Propagates updates to \a item and all its children.
*/
-void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly, bool maybeDirtyClipPath, bool ignoreOpacity)
+void QGraphicsItemPrivate::addChild(QGraphicsItem *child)
{
- if (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/false,
- /*ignoreDirtyBit=*/true, ignoreOpacity)) {
- return;
- }
-
- if (!childrenOnly && !dirty) {
- // Effectively the same as updateHelper(QRectF(), false, maybeDirtyClipPath).
- dirty = 1;
- scene->itemUpdated(q_ptr, QRectF());
- }
-
- if (dirtyChildren || childrenClippedToShape()) {
- // 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(false, maybeDirtyClipPath);
- dirtyChildren = 1;
-}
-
-static inline bool qt_allChildrenCombineOpacity(QGraphicsItem *parent)
-{
- Q_ASSERT(parent);
- if (parent->flags() & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)
- return false;
-
- const QList<QGraphicsItem *> children(parent->childItems());
- for (int i = 0; i < children.size(); ++i) {
- if (children.at(i)->flags() & QGraphicsItem::ItemIgnoresParentOpacity)
- return false;
- }
- return true;
-}
-
-void QGraphicsItemPrivate::updateEffectiveOpacity()
-{
- Q_Q(QGraphicsItem);
- if (parent) {
- resolveEffectiveOpacity(parent->effectiveOpacity());
- parent->d_ptr->allChildrenCombineOpacity = qt_allChildrenCombineOpacity(parent);
- } else {
- resolveEffectiveOpacity(1.0);
- }
- allChildrenCombineOpacity = qt_allChildrenCombineOpacity(q);
+ needSortChildren = 1;
+ children.append(child);
}
/*!
\internal
-
- Resolves and propagates this item's effective opacity to its children.
*/
-void QGraphicsItemPrivate::resolveEffectiveOpacity(qreal parentEffectiveOpacity)
+void QGraphicsItemPrivate::removeChild(QGraphicsItem *child)
{
- 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.
- if (qFuzzyCompare(myEffectiveOpacity, qreal(1.0))) {
- // Opaque, unset effective opacity.
- hasEffectiveOpacity = 0;
- unsetExtra(ExtraEffectiveOpacity);
- } else {
- hasEffectiveOpacity = 1;
- setExtra(ExtraEffectiveOpacity, myEffectiveOpacity);
- }
-
- // Resolve children always.
- for (int i = 0; i < children.size(); ++i)
- children.at(i)->d_ptr->resolveEffectiveOpacity(myEffectiveOpacity);
+ children.removeOne(child);
}
/*!
\internal
-
- Resolves the stacking depth of this object and all its children.
*/
-void QGraphicsItemPrivate::resolveDepth(int parentDepth)
+QGraphicsItemCache *QGraphicsItemPrivate::maybeExtraItemCache() const
{
- depth = parentDepth + 1;
- for (int i = 0; i < children.size(); ++i)
- children.at(i)->d_ptr->resolveDepth(depth);
+ return (QGraphicsItemCache *)qVariantValue<void *>(extra(ExtraCacheData));
}
/*!
\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));
@@ -3824,6 +4319,9 @@ QGraphicsItemCache *QGraphicsItemPrivate::extraItemCache() const
return c;
}
+/*!
+ \internal
+*/
void QGraphicsItemPrivate::removeExtraItemCache()
{
QGraphicsItemCache *c = (QGraphicsItemCache *)qVariantValue<void *>(extra(ExtraCacheData));
@@ -3885,17 +4383,13 @@ void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &n
// Find closest clip ancestor and transform.
Q_Q(QGraphicsItem);
- QTransform thisToParentTransform = hasTransform
- ? q->transform() * QTransform::fromTranslate(newPos.x(), newPos.y())
- : QTransform::fromTranslate(newPos.x(), newPos.y());
+ // COMBINE
+ QTransform thisToParentTransform = QTransform::fromTranslate(newPos.x(), newPos.y());
+ if (transformData)
+ thisToParentTransform = transformData->computedFullTransform(&thisToParentTransform);
QGraphicsItem *clipParent = parent;
while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) {
- if (clipParent->d_ptr->hasTransform)
- thisToParentTransform *= clipParent->transform();
- if (!clipParent->d_ptr->pos.isNull()) {
- thisToParentTransform *= QTransform::fromTranslate(clipParent->d_ptr->pos.x(),
- clipParent->d_ptr->pos.y());
- }
+ thisToParentTransform *= clipParent->d_ptr->transformToParent();
clipParent = clipParent->d_ptr->parent;
}
@@ -3937,6 +4431,35 @@ void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &n
}
}
+// Traverses all the ancestors up to the top-level and updates the pointer to
+// always point to the top-most item that has a dirty scene transform.
+// It then backtracks to the top-most dirty item and start calculating the
+// scene transform by combining the item's transform (+pos) with the parent's
+// cached scene transform (which we at this point know for sure is valid).
+void QGraphicsItemPrivate::ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem)
+{
+ Q_ASSERT(topMostDirtyItem);
+
+ if (dirtySceneTransform)
+ *topMostDirtyItem = q_ptr;
+
+ if (parent)
+ parent->d_ptr->ensureSceneTransformRecursive(topMostDirtyItem);
+
+ if (*topMostDirtyItem == q_ptr) {
+ if (!dirtySceneTransform)
+ return; // OK, neither my ancestors nor I have dirty scene transforms.
+ *topMostDirtyItem = 0;
+ } else if (*topMostDirtyItem) {
+ return; // Continue backtrack.
+ }
+
+ // COMBINE my transform with the parent's scene transform.
+ sceneTransform = parent ? parent->d_ptr->sceneTransform : QTransform();
+ combineTransformFromParent(&sceneTransform);
+ dirtySceneTransform = 0;
+}
+
/*!
\internal
@@ -3979,25 +4502,62 @@ void QGraphicsItem::update(const QRectF &rect)
}
// Invalidate cache.
- if (rect.isNull()) {
- cache->allExposed = true;
- cache->exposed.clear();
- } else {
- cache->exposed.append(rect);
+ if (!cache->allExposed) {
+ if (rect.isNull()) {
+ cache->allExposed = true;
+ cache->exposed.clear();
+ } else {
+ cache->exposed.append(rect);
+ }
}
// Only invalidate cache; item is already dirty.
- if (d_ptr->dirty)
+ if (d_ptr->fullUpdatePending)
return;
- } else if (d_ptr->discardUpdateRequest()) {
- return;
}
- // Effectively the same as updateHelper(rect);
- if (rect.isNull())
- d_ptr->dirty = 1;
- d_ptr->scene->itemUpdated(this, rect);
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->markDirty(this, rect);
}
+/*!
+ \internal
+
+ Scrolls \a rect in \a pix by \a dx, \a dy.
+
+ ### This can be done much more efficiently by using XCopyArea on X11 with
+ the same dst and src, and through moving pixels in the raster engine. It
+ can probably also be done much better on the other paint engines.
+*/
+void _q_scrollPixmap(QPixmap *pix, const QRect &rect, int dx, int dy)
+{
+#if 0
+ QPainter painter(pix);
+ painter.setClipRect(rect);
+ painter.drawPixmap(rect.translated(dx, dy), *pix, rect);
+ painter.end();
+#elif defined Q_WS_X11
+ GC gc = XCreateGC(X11->display, pix->handle(), 0, 0);
+
+ XRectangle xrect;
+ xrect.x = rect.x();
+ xrect.y = rect.y();
+ xrect.width = rect.width();
+ xrect.height = rect.height();
+ XSetClipRectangles(X11->display, gc, 0, 0, &xrect, 1, YXBanded);
+
+ XCopyArea(X11->display, pix->handle(), pix->handle(), gc,
+ rect.x(), rect.y(), rect.width(), rect.height(),
+ rect.x()+dx, rect.y()+dy);
+ XFreeGC(X11->display, gc);
+#else
+ QPixmap newPix = *pix;
+ QPainter painter(&newPix);
+ painter.setClipRect(rect);
+ painter.drawPixmap(rect.translated(dx, dy), *pix, rect);
+ painter.end();
+ *pix = newPix;
+#endif
+}
/*!
\since 4.4
@@ -4026,11 +4586,45 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect)
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);
+ QGraphicsItemCache *c;
+ bool scrollCache = qFuzzyIsNull(dx - int(dx)) && qFuzzyIsNull(dy - int(dy))
+ && (c = (QGraphicsItemCache *)qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraCacheData)))
+ && (d->cacheMode == ItemCoordinateCache && !c->fixedSize.isValid());
+ if (scrollCache) {
+ QPixmap pix;
+ if (QPixmapCache::find(c->key, &pix)) {
+ // Adjust with 2 pixel margin. Notice the loss of precision
+ // when converting to QRect.
+ int adjust = 2;
+ QRectF br = boundingRect().adjusted(-adjust, -adjust, adjust, adjust);
+ QRect irect = rect.toRect().translated(-br.x(), -br.y());
+
+ _q_scrollPixmap(&pix, irect, dx, dy);
+
+ QPixmapCache::replace(c->key, pix);
+
+ // Translate the existing expose.
+ foreach (QRectF exposedRect, c->exposed)
+ c->exposed += exposedRect.translated(dx, dy) & rect;
+
+ // Calculate exposure.
+ QRegion exposed;
+ QRect r = rect.toRect();
+ exposed += r;
+ exposed -= r.translated(dx, dy);
+ foreach (QRect rect, exposed.rects())
+ update(rect);
+ d->scene->d_func()->markDirty(this);
+ } else {
+ update(rect);
+ }
+ } else {
+ // ### 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;
}
@@ -4049,13 +4643,7 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect)
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();
- }
-
+ QTransform deviceTr = deviceTransform(view->viewportTransform());
QRect deviceScrollRect = deviceTr.mapRect(scrollRect).toRect();
QLineF v1 = deviceTr.map(right);
QLineF v2 = deviceTr.map(down);
@@ -4187,7 +4775,10 @@ QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPointF &point
*/
QPointF QGraphicsItem::mapToParent(const QPointF &point) const
{
- return d_ptr->pos + (d_ptr->hasTransform ? transform().map(point) : point);
+ // COMBINE
+ if (!d_ptr->transformData)
+ return point + d_ptr->pos;
+ return d_ptr->transformToParent().map(point);
}
/*!
@@ -4252,9 +4843,10 @@ QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QRectF &rect
*/
QPolygonF QGraphicsItem::mapToParent(const QRectF &rect) const
{
- QPolygonF p = !d_ptr->hasTransform ? rect : transform().map(rect);
- p.translate(d_ptr->pos);
- return p;
+ // COMBINE
+ if (!d_ptr->transformData)
+ return rect.translated(d_ptr->pos);
+ return d_ptr->transformToParent().map(rect);
}
/*!
@@ -4321,8 +4913,10 @@ QRectF QGraphicsItem::mapRectToItem(const QGraphicsItem *item, const QRectF &rec
*/
QRectF QGraphicsItem::mapRectToParent(const QRectF &rect) const
{
- QRectF r = !d_ptr->hasTransform ? rect : transform().mapRect(rect);
- return r.translated(d_ptr->pos);
+ // COMBINE
+ if (!d_ptr->transformData)
+ return rect.translated(d_ptr->pos);
+ return d_ptr->transformToParent().mapRect(rect);
}
/*!
@@ -4393,8 +4987,10 @@ QRectF QGraphicsItem::mapRectFromItem(const QGraphicsItem *item, const QRectF &r
*/
QRectF QGraphicsItem::mapRectFromParent(const QRectF &rect) const
{
- QRectF r = rect.translated(-d_ptr->pos);
- return d_ptr->hasTransform ? transform().inverted().mapRect(r) : r;
+ // COMBINE
+ if (!d_ptr->transformData)
+ return rect.translated(-d_ptr->pos);
+ return d_ptr->transformToParent().inverted().mapRect(rect);
}
/*!
@@ -4453,9 +5049,10 @@ QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPolygonF &p
*/
QPolygonF QGraphicsItem::mapToParent(const QPolygonF &polygon) const
{
- QPolygonF p = !d_ptr->hasTransform ? polygon : transform().map(polygon);
- p.translate(d_ptr->pos);
- return p;
+ // COMBINE
+ if (!d_ptr->transformData)
+ return polygon.translated(d_ptr->pos);
+ return d_ptr->transformToParent().map(polygon);
}
/*!
@@ -4497,10 +5094,10 @@ QPainterPath QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPainterP
*/
QPainterPath QGraphicsItem::mapToParent(const QPainterPath &path) const
{
- QTransform x = QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y());
- if (d_ptr->hasTransform)
- x = transform() * x;
- return x.map(path);
+ // COMBINE
+ if (!d_ptr->transformData)
+ return path.translated(d_ptr->pos);
+ return d_ptr->transformToParent().map(path);
}
/*!
@@ -4549,8 +5146,9 @@ QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPointF &poi
*/
QPointF QGraphicsItem::mapFromParent(const QPointF &point) const
{
- if (d_ptr->hasTransform)
- return transform().inverted().map(point - d_ptr->pos);
+ // COMBINE
+ if (d_ptr->transformData)
+ return d_ptr->transformToParent().inverted().map(point);
return point - d_ptr->pos;
}
@@ -4617,8 +5215,10 @@ QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QRectF &re
*/
QPolygonF QGraphicsItem::mapFromParent(const QRectF &rect) const
{
- QRectF r = rect.translated(-d_ptr->pos);
- return d_ptr->hasTransform ? transform().inverted().map(r) : r;
+ // COMBINE
+ if (!d_ptr->transformData)
+ return rect.translated(-d_ptr->pos);
+ return d_ptr->transformToParent().inverted().map(rect);
}
/*!
@@ -4673,9 +5273,10 @@ QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPolygonF
*/
QPolygonF QGraphicsItem::mapFromParent(const QPolygonF &polygon) const
{
- QPolygonF p = polygon;
- p.translate(-d_ptr->pos);
- return d_ptr->hasTransform ? transform().inverted().map(p) : p;
+ // COMBINE
+ if (!d_ptr->transformData)
+ return polygon.translated(-d_ptr->pos);
+ return d_ptr->transformToParent().inverted().map(polygon);
}
/*!
@@ -4715,9 +5316,10 @@ QPainterPath QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPainte
*/
QPainterPath QGraphicsItem::mapFromParent(const QPainterPath &path) const
{
- if (d_ptr->parent)
- return d_ptr->parent->itemTransform(this).map(path);
- return mapFromScene(path);
+ // COMBINE
+ if (!d_ptr->transformData)
+ return path.translated(-d_ptr->pos);
+ return d_ptr->transformToParent().inverted().map(path);
}
/*!
@@ -5235,7 +5837,8 @@ void QGraphicsItem::focusOutEvent(QFocusEvent *event)
void QGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
- d_ptr->updateHelper();
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->markDirty(this);
}
/*!
@@ -5263,7 +5866,8 @@ void QGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
void QGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
- d_ptr->updateHelper();
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->markDirty(this);
}
/*!
@@ -5693,7 +6297,6 @@ void QGraphicsItem::addToIndex()
}
if (d_ptr->scene)
d_ptr->scene->d_func()->addToIndex(this);
- d_ptr->updateHelper();
}
/*!
@@ -5709,7 +6312,6 @@ void QGraphicsItem::removeFromIndex()
// ### remove from child index only if applicable
return;
}
- d_ptr->updateHelper();
if (d_ptr->scene)
d_ptr->scene->d_func()->removeFromIndex(this);
}
@@ -5730,11 +6332,30 @@ void QGraphicsItem::removeFromIndex()
void QGraphicsItem::prepareGeometryChange()
{
if (d_ptr->scene) {
- d_ptr->updateHelper(QRectF(), false, /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper);
+ d_ptr->geometryChanged = 1;
+ d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
+
QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func();
+ scenePrivate->markDirty(this, QRectF(),
+ /*invalidateChildren=*/true,
+ /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper);
+
+ // For compatibility reasons, we have to update the item's old geometry
+ // if someone is connected to the changed signal or the scene has no views.
+ // Note that this has to be done *after* markDirty to ensure that
+ // _q_processDirtyItems is called before _q_emitUpdated.
+ if ((scenePrivate->connectedSignals & scenePrivate->changedSignalMask)
+ || scenePrivate->views.isEmpty()) {
+ d_ptr->scene->update(sceneTransform().mapRect(boundingRect()));
+ }
+
scenePrivate->removeFromIndex(this);
}
+ QGraphicsItem *parent = this;
+ while ((parent = parent->d_ptr->parent))
+ parent->d_ptr->dirtyChildrenBoundingRect = 1;
+
if (d_ptr->inSetPosHelper)
return;
@@ -5756,7 +6377,7 @@ 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))
+ if (qFuzzyIsNull(qMax(murect.width(), murect.height())))
return;
const QRectF mbrect = painter->transform().mapRect(item->boundingRect());
@@ -5806,6 +6427,172 @@ static void qt_graphicsItem_highlightSelected(
}
/*!
+ \class QGraphicsObject
+ \brief The QGraphicsObject class provides a base class for all graphics items that
+ require signals, slots and properties.
+ \since 4.6
+ \ingroup graphicsview-api
+
+ The class extends a QGraphicsItem with QObject's signal/slot and property mechanisms.
+ It maps many of QGraphicsItem's basic setters and getters to properties and adds notification
+ signals for many of them.
+*/
+
+/*!
+ Constructs a QGraphicsObject with \a parent.
+*/
+QGraphicsObject::QGraphicsObject(QGraphicsItem *parent)
+ : QGraphicsItem(parent)
+{
+ QGraphicsItem::d_ptr->isObject = true;
+}
+
+/*!
+ \internal
+*/
+QGraphicsObject::QGraphicsObject(QGraphicsItemPrivate &dd, QGraphicsItem *parent, QGraphicsScene *scene)
+ : QGraphicsItem(dd, parent, scene)
+{
+ QGraphicsItem::d_ptr->isObject = true;
+}
+
+/*!
+ \property QGraphicsObject::parent
+ \brief the parent of the item
+
+ \sa QGraphicsItem::setParentItem(), QGraphicsItem::parentObject()
+*/
+
+/*!
+ \property QGraphicsObject::id
+ \brief the id of of the item
+
+ \sa QGraphicsItem::opacity(), QGraphicsItem::setOpacity()
+*/
+
+/*!
+ \property QGraphicsObject::opacity
+ \brief the opacity of the item
+
+ \sa QGraphicsItem::setOpacity(), QGraphicsItem::opacity()
+*/
+
+/*!
+ \fn QGraphicsObject::opacityChanged()
+
+ This signal gets emitted whenever the opacity of the item changes
+
+ \sa QGraphicsItem::opacity()
+*/
+
+/*!
+ \fn QGraphicsObject::parentChanged()
+
+ This signal gets emitted whenever the parent of the item changes
+*/
+
+/*!
+ \property QGraphicsObject::pos
+ \brief the position of the item
+
+ Describes the items position.
+
+ \sa QGraphicsItem::setPos(), QGraphicsItem::pos()
+*/
+
+/*!
+ \property QGraphicsObject::x
+ \brief the x position of the item
+
+ Describes the items x position.
+
+ \sa QGraphicsItem::setX(), setPos(), xChanged()
+*/
+
+/*!
+ \fn QGraphicsObject::xChanged()
+
+ This signal gets emitted whenever the x position of the item changes
+
+ \sa pos()
+*/
+
+/*!
+ \property QGraphicsObject::y
+ \brief the y position of the item
+
+ Describes the items y position.
+
+ \sa QGraphicsItem::setY(), setPos(), yChanged()
+*/
+
+/*!
+ \fn QGraphicsObject::yChanged()
+
+ This signal gets emitted whenever the y position of the item changes.
+
+ \sa pos()
+*/
+
+/*!
+ \property QGraphicsObject::z
+ \brief the z value of the item
+
+ Describes the items z value.
+
+ \sa QGraphicsItem::setZValue(), zValue(), zChanged()
+*/
+
+/*!
+ \fn QGraphicsObject::zChanged()
+
+ This signal gets emitted whenever the z value of the item changes.
+
+ \sa pos()
+*/
+
+
+/*!
+ \property QGraphicsObject::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(), enabledChanged()
+*/
+
+/*!
+ \fn QGraphicsObject::enabledChanged()
+
+ This signal gets emitted whenever the item get's enabled or disabled.
+
+ \sa isEnabled()
+*/
+
+/*!
+ \property QGraphicsObject::visible
+ \brief whether the item is visible or not
+
+ This property is declared in QGraphicsItem.
+
+ By default, this property is true.
+
+ \sa QGraphicsItem::isVisible(), QGraphicsItem::setVisible(), visibleChanged()
+*/
+
+/*!
+ \fn QGraphicsObject::visibleChanged()
+
+ This signal gets emitted whenever the visibility of the item changes
+
+ \sa visible
+*/
+
+
+
+/*!
\class QAbstractGraphicsShapeItem
\brief The QAbstractGraphicsShapeItem class provides a common base for
all path items.
@@ -7395,7 +8182,6 @@ void QGraphicsPixmapItem::setTransformationMode(Qt::TransformationMode mode)
{
Q_D(QGraphicsPixmapItem);
if (mode != d->transformationMode) {
- d_ptr->updateHelper();
d->transformationMode = mode;
update();
}
@@ -7483,9 +8269,7 @@ void QGraphicsPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsIte
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));
+ painter->drawPixmap(d->offset, d->pixmap);
if (option->state & QStyle::State_Selected)
qt_graphicsItem_highlightSelected(this, painter, option);
@@ -7634,6 +8418,7 @@ public:
QGraphicsTextItem *qq;
};
+
/*!
Constructs a QGraphicsTextItem, using \a text as the default plain
text. \a parent is passed to QGraphicsItem's constructor.
@@ -7646,13 +8431,14 @@ QGraphicsTextItem::QGraphicsTextItem(const QString &text, QGraphicsItem *parent
, QGraphicsScene *scene
#endif
)
- : QGraphicsItem(parent, scene), dd(new QGraphicsTextItemPrivate)
+ : QGraphicsObject(*new QGraphicsItemPrivate, parent, scene), dd(new QGraphicsTextItemPrivate)
{
dd->qq = this;
if (!text.isEmpty())
setPlainText(text);
setAcceptDrops(true);
setAcceptHoverEvents(true);
+ setFlags(ItemUsesExtendedStyleOption);
}
/*!
@@ -7667,11 +8453,12 @@ QGraphicsTextItem::QGraphicsTextItem(QGraphicsItem *parent
, QGraphicsScene *scene
#endif
)
- : QGraphicsItem(parent, scene), dd(new QGraphicsTextItemPrivate)
+ : QGraphicsObject(*new QGraphicsItemPrivate, parent, scene), dd(new QGraphicsTextItemPrivate)
{
dd->qq = this;
setAcceptDrops(true);
setAcceptHoverEvents(true);
+ setFlag(ItemUsesExtendedStyleOption);
}
/*!
@@ -7942,19 +8729,19 @@ bool QGraphicsTextItem::sceneEvent(QEvent *event)
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;
+ && (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;
+ && 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;
+ if (!event->isAccepted())
+ dd->useDefaultImpl = false;
return;
}
@@ -7991,14 +8778,14 @@ 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.
+ 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.
+ } else if ((event->buttons() & Qt::LeftButton) == 0) {
+ // User released the left button on an interactive item.
dd->useDefaultImpl = false;
- }
+ }
return;
}
@@ -8400,9 +9187,9 @@ bool QGraphicsTextItemPrivate::_q_mouseOnEdge(QGraphicsSceneMouseEvent *event)
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.
+ The default for a QGraphicsTextItem is Qt::NoTextInteraction. This function
+ also affects the ItemIsFocusable QGraphicsItem flag by setting it if \a flags
+ is different from Qt::NoTextInteraction and clearing it otherwise.
By default, the text is read-only. To transform the item into an editor,
set the Qt::TextEditable flag.
@@ -8903,6 +9690,8 @@ void QGraphicsItemGroup::addToGroup(QGraphicsItem *item)
return;
}
+ // COMBINE
+ // ### Use itemTransform() instead.
QTransform oldSceneMatrix = item->sceneTransform();
item->setPos(mapFromItem(item, 0, 0));
item->setParentItem(this);
@@ -9141,6 +9930,15 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag)
case QGraphicsItem::ItemStacksBehindParent:
str = "ItemStacksBehindParent";
break;
+ case QGraphicsItem::ItemUsesExtendedStyleOption:
+ str = "ItemUsesExtendedStyleOption";
+ break;
+ case QGraphicsItem::ItemHasNoContents:
+ str = "ItemHasNoContents";
+ break;
+ case QGraphicsItem::ItemSendsGeometryChanges:
+ str = "ItemSendsGeometryChanges";
+ break;
}
debug << str;
return debug;
@@ -9148,17 +9946,17 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag)
QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlags flags)
{
- debug << "(";
+ debug << '(';
bool f = false;
for (int i = 0; i < 9; ++i) {
if (flags & (1 << i)) {
if (f)
- debug << "|";
+ debug << '|';
f = true;
debug << QGraphicsItem::GraphicsItemFlag(int(flags & (1 << i)));
}
}
- debug << ")";
+ debug << ')';
return debug;
}
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index 25678a6..989be43 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -64,6 +64,7 @@ class QBrush;
class QCursor;
class QFocusEvent;
class QGraphicsItemGroup;
+class QGraphicsObject;
class QGraphicsSceneContextMenuEvent;
class QGraphicsSceneDragDropEvent;
class QGraphicsSceneEvent;
@@ -95,7 +96,11 @@ public:
ItemIgnoresTransformations = 0x20,
ItemIgnoresParentOpacity = 0x40,
ItemDoesntPropagateOpacityToChildren = 0x80,
- ItemStacksBehindParent = 0x100
+ ItemStacksBehindParent = 0x100,
+ ItemUsesExtendedStyleOption = 0x200,
+ ItemHasNoContents = 0x400,
+ ItemSendsGeometryChanges = 0x800
+ // NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag.
};
Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag)
@@ -147,6 +152,7 @@ public:
QGraphicsItem *parentItem() const;
QGraphicsItem *topLevelItem() const;
+ QGraphicsObject *parentObject() const;
QGraphicsWidget *parentWidget() const;
QGraphicsWidget *topLevelWidget() const;
QGraphicsWidget *window() const;
@@ -156,6 +162,9 @@ public:
bool isWidget() const;
bool isWindow() const;
+ QGraphicsObject *toGraphicsObject();
+ const QGraphicsObject *toGraphicsObject() const;
+
QGraphicsItemGroup *group() const;
void setGroup(QGraphicsItemGroup *group);
@@ -220,7 +229,9 @@ public:
// Positioning in scene coordinates
QPointF pos() const;
inline qreal x() const { return pos().x(); }
+ void setX(qreal x);
inline qreal y() const { return pos().y(); }
+ void setY(qreal y);
QPointF scenePos() const;
void setPos(const QPointF &pos);
inline void setPos(qreal x, qreal y);
@@ -240,11 +251,41 @@ public:
QTransform itemTransform(const QGraphicsItem *other, bool *ok = 0) 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 rotate(qreal angle); // ### obsolete
+ void scale(qreal sx, qreal sy); // ### obsolete
+ void shear(qreal sh, qreal sv); // ### obsolete
+ void translate(qreal dx, qreal dy); // ### obsolete
+
+ qreal xRotation() const;
+ void setXRotation(qreal angle);
+
+ qreal yRotation() const;
+ void setYRotation(qreal angle);
+
+ qreal zRotation() const;
+ void setZRotation(qreal angle);
+ void setRotation(qreal x, qreal y, qreal z);
+
+ qreal xScale() const;
+ void setXScale(qreal factor);
+
+ qreal yScale() const;
+ void setYScale(qreal factor);
+ void setScale(qreal sx, qreal sy);
+
+ qreal horizontalShear() const;
+ void setHorizontalShear(qreal shear);
+
+ qreal verticalShear() const;
+ void setVerticalShear(qreal shear);
+ void setShear(qreal sh, qreal sv);
+
+ QPointF transformOrigin() const;
+ void setTransformOrigin(const QPointF &origin);
+ inline void setTransformOrigin(qreal x, qreal y)
+ { setTransformOrigin(QPointF(x,y)); }
+
virtual void advance(int phase);
// Stacking order
@@ -451,6 +492,39 @@ inline QRectF QGraphicsItem::mapRectFromParent(qreal ax, qreal ay, qreal w, qrea
inline QRectF QGraphicsItem::mapRectFromScene(qreal ax, qreal ay, qreal w, qreal h) const
{ return mapRectFromScene(QRectF(ax, ay, w, h)); }
+
+class Q_GUI_EXPORT QGraphicsObject : public QObject, public QGraphicsItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QGraphicsObject * parent READ parentObject WRITE setParentItem NOTIFY parentChanged DESIGNABLE false)
+ Q_PROPERTY(QString id READ objectName WRITE setObjectName)
+ Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
+ Q_PROPERTY(QPointF pos READ pos WRITE setPos)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+ Q_PROPERTY(qreal z READ zValue WRITE setZValue NOTIFY zChanged)
+public:
+ QGraphicsObject(QGraphicsItem *parent = 0);
+
+Q_SIGNALS:
+ void parentChanged();
+ void opacityChanged();
+ void visibleChanged();
+ void enabledChanged();
+ void xChanged();
+ void yChanged();
+ void zChanged();
+
+protected:
+ QGraphicsObject(QGraphicsItemPrivate &dd, QGraphicsItem *parent, QGraphicsScene *scene);
+private:
+ friend class QGraphicsItem;
+ friend class QGraphicsItemPrivate;
+};
+
+
class QAbstractGraphicsShapeItemPrivate;
class Q_GUI_EXPORT QAbstractGraphicsShapeItem : public QGraphicsItem
{
@@ -802,7 +876,7 @@ inline void QGraphicsPixmapItem::setOffset(qreal ax, qreal ay)
class QGraphicsTextItemPrivate;
class QTextDocument;
class QTextCursor;
-class Q_GUI_EXPORT QGraphicsTextItem : public QObject, public QGraphicsItem
+class Q_GUI_EXPORT QGraphicsTextItem : public QGraphicsObject
{
Q_OBJECT
QDOC_PROPERTY(bool openExternalLinks READ openExternalLinks WRITE setOpenExternalLinks)
@@ -1014,4 +1088,3 @@ 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
index 9ce1bbf..03ec040 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -54,6 +54,9 @@
//
#include "qgraphicsitem.h"
+#include "qpixmapcache.h"
+
+#include <QtCore/qpoint.h>
#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
@@ -69,13 +72,14 @@ public:
// ItemCoordinateCache only
QRect boundingRect;
QSize fixedSize;
- QString key;
+ QPixmapCache::Key key;
// DeviceCoordinateCache only
struct DeviceData {
+ DeviceData() {}
QTransform lastTransform;
QPoint cacheIndent;
- QString key;
+ QPixmapCache::Key key;
};
QMap<QPaintDevice *, DeviceData> deviceData;
@@ -92,14 +96,11 @@ class Q_AUTOTEST_EXPORT QGraphicsItemPrivate
Q_DECLARE_PUBLIC(QGraphicsItem)
public:
enum Extra {
- ExtraTransform,
ExtraToolTip,
ExtraCursor,
ExtraCacheData,
ExtraMaxDeviceCoordCacheSize,
- ExtraBoundingRegionGranularity,
- ExtraOpacity,
- ExtraEffectiveOpacity
+ ExtraBoundingRegionGranularity
};
enum AncestorFlag {
@@ -111,8 +112,10 @@ public:
inline QGraphicsItemPrivate()
: z(0),
+ opacity(1.),
scene(0),
parent(0),
+ transformData(0),
index(-1),
depth(0),
acceptedMouseButtons(0x1f),
@@ -126,14 +129,10 @@ public:
isMemberOfGroup(0),
handlesChildEvents(0),
itemDiscovered(0),
- hasTransform(0),
hasCursor(0),
ancestorFlags(0),
cacheMode(0),
hasBoundingRegionGranularity(0),
- flags(0),
- hasOpacity(0),
- hasEffectiveOpacity(0),
isWidget(0),
dirty(0),
dirtyChildren(0),
@@ -141,9 +140,17 @@ public:
dirtyClipPath(1),
emptyClipPath(0),
inSetPosHelper(0),
- allChildrenCombineOpacity(1),
+ needSortChildren(1),
+ allChildrenDirty(0),
+ fullUpdatePending(0),
+ flags(0),
+ dirtyChildrenBoundingRect(1),
+ paintedViewBoundingRectsNeedRepaint(0),
+ dirtySceneTransform(1),
+ geometryChanged(0),
+ inDestructor(0),
+ isObject(0),
globalStackingOrder(-1),
- sceneTransformIndex(-1),
q_ptr(0)
{
}
@@ -156,23 +163,32 @@ public:
void setIsMemberOfGroup(bool enabled);
void remapItemPos(QEvent *event, QGraphicsItem *item);
QPointF genericMapFromScene(const QPointF &pos, const QWidget *viewport) const;
- bool itemIsUntransformable() const;
+ inline bool itemIsUntransformable() const
+ {
+ return (flags & QGraphicsItem::ItemIgnoresTransformations)
+ || (ancestorFlags & AncestorIgnoresTransformations);
+ }
+ void combineTransformToParent(QTransform *x, const QTransform *viewTransform = 0) const;
+ void combineTransformFromParent(QTransform *x, const QTransform *viewTransform = 0) 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);
+ void setTransformHelper(const QTransform &transform);
void setVisibleHelper(bool newVisible, bool explicitly, bool update = true);
void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true);
bool discardUpdateRequest(bool ignoreClipping = false, bool ignoreVisibleBit = false,
bool ignoreDirtyBit = false, bool ignoreOpacity = false) const;
- void updateHelper(const QRectF &rect = QRectF(), bool force = false, bool maybeDirtyClipPath = false);
- void fullUpdateHelper(bool childrenOnly = false, bool maybeDirtyClipPath = false, bool ignoreOpacity = false);
- void updateEffectiveOpacity();
- void resolveEffectiveOpacity(qreal effectiveParentOpacity);
void resolveDepth(int parentDepth);
- void invalidateSceneTransformCache();
+ void addChild(QGraphicsItem *child);
+ void removeChild(QGraphicsItem *child);
+ void setParentItemHelper(QGraphicsItem *parent);
+ void childrenBoundingRectHelper(QTransform *x, QRectF *rect);
+ void initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform,
+ const QRegion &exposedRegion, bool allItems = false) const;
virtual void resolveFont(uint inheritedMask)
{
@@ -224,7 +240,7 @@ public:
}
}
}
-
+
struct ExtraStruct {
ExtraStruct(Extra type, QVariant value)
: type(type), value(value)
@@ -236,8 +252,10 @@ public:
bool operator<(Extra extra) const
{ return type < extra; }
};
+
QList<ExtraStruct> extras;
+ QGraphicsItemCache *maybeExtraItemCache() const;
QGraphicsItemCache *extraItemCache() const;
void removeExtraItemCache();
@@ -261,12 +279,67 @@ public:
void invalidateCachedClipPathRecursively(bool childrenOnly = false, const QRectF &emptyIfOutsideThisRect = QRectF());
void updateCachedClipPathFromSetPosHelper(const QPointF &newPos);
+ void ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem);
+
+ inline void invalidateChildrenSceneTransform()
+ {
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->dirtySceneTransform = 1;
+ }
+
+ inline qreal calcEffectiveOpacity() const
+ {
+ qreal o = opacity;
+ QGraphicsItem *p = parent;
+ int myFlags = flags;
+ while (p) {
+ int parentFlags = p->d_ptr->flags;
+
+ // 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 ((myFlags & QGraphicsItem::ItemIgnoresParentOpacity)
+ || (parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) {
+ break;
+ }
+
+ o *= p->d_ptr->opacity;
+ p = p->d_ptr->parent;
+ myFlags = parentFlags;
+ }
+ return o;
+ }
inline bool isFullyTransparent() const
- { return hasEffectiveOpacity && qFuzzyCompare(q_func()->effectiveOpacity() + 1, qreal(1.0)); }
+ {
+ if (opacity < 0.001)
+ return true;
+ if (!parent)
+ return false;
+
+ return calcEffectiveOpacity() < 0.001;
+ }
+
+ inline qreal effectiveOpacity() const {
+ if (!parent || !opacity)
+ return opacity;
+
+ return calcEffectiveOpacity();
+ }
inline bool childrenCombineOpacity() const
- { return allChildrenCombineOpacity || children.isEmpty(); }
+ {
+ if (!children.size())
+ return true;
+ if (flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)
+ return false;
+
+ for (int i = 0; i < children.size(); ++i) {
+ if (children.at(i)->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)
+ return false;
+ }
+ return true;
+ }
inline bool isClippedAway() const
{ return !dirtyClipPath && q_func()->isClipped() && (emptyClipPath || cachedClipPath.isEmpty()); }
@@ -281,16 +354,25 @@ public:
|| (childrenCombineOpacity() && isFullyTransparent());
}
+ inline QTransform transformToParent() const;
+
QPainterPath cachedClipPath;
+ QRectF childrenBoundingRect;
+ QRectF needsRepaint;
+ QMap<QWidget *, QRect> paintedViewBoundingRects;
QPointF pos;
qreal z;
+ qreal opacity;
QGraphicsScene *scene;
QGraphicsItem *parent;
QList<QGraphicsItem *> children;
+ struct TransformData;
+ TransformData *transformData;
+ QTransform sceneTransform;
int index;
int depth;
- // Packed 32 bytes
+ // Packed 32 bits
quint32 acceptedMouseButtons : 5;
quint32 visible : 1;
quint32 explicitlyHidden : 1;
@@ -302,16 +384,10 @@ public:
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 hasEffectiveOpacity : 1;
quint32 isWidget : 1;
quint32 dirty : 1;
quint32 dirtyChildren : 1;
@@ -319,15 +395,79 @@ public:
quint32 dirtyClipPath : 1;
quint32 emptyClipPath : 1;
quint32 inSetPosHelper : 1;
- quint32 allChildrenCombineOpacity : 1;
+ quint32 needSortChildren : 1;
+ quint32 allChildrenDirty : 1;
+ quint32 fullUpdatePending : 1;
+
+ // New 32 bits
+ quint32 flags : 12;
+ quint32 dirtyChildrenBoundingRect : 1;
+ quint32 paintedViewBoundingRectsNeedRepaint : 1;
+ quint32 dirtySceneTransform : 1;
+ quint32 geometryChanged : 1;
+ quint32 inDestructor : 1;
+ quint32 isObject : 1;
+ quint32 unused : 14; // feel free to use
// Optional stacking order
int globalStackingOrder;
- int sceneTransformIndex;
-
QGraphicsItem *q_ptr;
};
+struct QGraphicsItemPrivate::TransformData {
+ QTransform transform;
+ qreal xScale;
+ qreal yScale;
+ qreal xRotation;
+ qreal yRotation;
+ qreal zRotation;
+ qreal horizontalShear;
+ qreal verticalShear;
+ qreal xOrigin;
+ qreal yOrigin;
+ bool onlyTransform;
+
+ TransformData() :
+ xScale(1.0), yScale(1.0), xRotation(0.0), yRotation(0.0), zRotation(0.0),
+ horizontalShear(0.0), verticalShear(0.0), xOrigin(0.0), yOrigin(0.0),
+ onlyTransform(true)
+ {}
+
+ QTransform computedFullTransform(QTransform *postmultiplyTransform = 0) const
+ {
+ if (onlyTransform) {
+ if (!postmultiplyTransform)
+ return transform;
+ QTransform x(transform);
+ x *= *postmultiplyTransform;
+ return x;
+ }
+
+ QTransform x(transform);
+ if (xOrigin != 0 || yOrigin != 0)
+ x *= QTransform::fromTranslate(xOrigin, yOrigin);
+ x.rotate(xRotation, Qt::XAxis);
+ x.rotate(yRotation, Qt::YAxis);
+ x.rotate(zRotation, Qt::ZAxis);
+ x.shear(horizontalShear, verticalShear);
+ x.scale(xScale, yScale);
+ x.translate(-xOrigin, -yOrigin);
+ if (postmultiplyTransform)
+ x *= *postmultiplyTransform;
+ return x;
+ }
+};
+
+/*
+ return the full transform of the item to the parent. This include the position and all the transform data
+*/
+inline QTransform QGraphicsItemPrivate::transformToParent() const
+{
+ QTransform matrix;
+ combineTransformToParent(&matrix);
+ return matrix;
+}
+
QT_END_NAMESPACE
#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicslayoutitem.cpp b/src/gui/graphicsview/qgraphicslayoutitem.cpp
index c291763..2d4bddb 100644
--- a/src/gui/graphicsview/qgraphicslayoutitem.cpp
+++ b/src/gui/graphicsview/qgraphicslayoutitem.cpp
@@ -108,13 +108,22 @@ static void normalizeHints(qreal &minimum, qreal &preferred, qreal &maximum, qre
\internal
*/
QGraphicsLayoutItemPrivate::QGraphicsLayoutItemPrivate(QGraphicsLayoutItem *par, bool layout)
- : parent(par), isLayout(layout), ownedByLayout(false), graphicsItem(0)
+ : parent(par), userSizeHints(0), isLayout(layout), ownedByLayout(false), graphicsItem(0)
{
}
/*!
\internal
*/
+QGraphicsLayoutItemPrivate::~QGraphicsLayoutItemPrivate()
+{
+ // Remove any lazily allocated data
+ delete[] userSizeHints;
+}
+
+/*!
+ \internal
+*/
void QGraphicsLayoutItemPrivate::init()
{
sizeHintCacheDirty = true;
@@ -132,7 +141,8 @@ QSizeF *QGraphicsLayoutItemPrivate::effectiveSizeHints(const QSizeF &constraint)
for (int i = 0; i < Qt::NSizeHints; ++i) {
cachedSizeHints[i] = constraint;
- combineSize(cachedSizeHints[i], userSizeHints[i]);
+ if (userSizeHints)
+ combineSize(cachedSizeHints[i], userSizeHints[i]);
}
QSizeF &minS = cachedSizeHints[Qt::MinimumSize];
@@ -198,6 +208,58 @@ QGraphicsItem *QGraphicsLayoutItemPrivate::parentItem() const
}
/*!
+ \internal
+
+ Ensures that userSizeHints is allocated.
+ This function must be called before any dereferencing.
+*/
+void QGraphicsLayoutItemPrivate::ensureUserSizeHints()
+{
+ if (!userSizeHints)
+ userSizeHints = new QSizeF[Qt::NSizeHints];
+}
+
+/*!
+ \internal
+
+ Sets the user size hint \a which to \a size. Use an invalid size to unset the size hint.
+ */
+void QGraphicsLayoutItemPrivate::setSize(Qt::SizeHint which, const QSizeF &size)
+{
+ Q_Q(QGraphicsLayoutItem);
+
+ if (userSizeHints) {
+ if (size == userSizeHints[which])
+ return;
+ } else if (!size.isValid()) {
+ return;
+ }
+
+ ensureUserSizeHints();
+ userSizeHints[which] = size;
+ q->updateGeometry();
+}
+
+/*!
+ \internal
+
+ Sets the width of the user size hint \a which to \a width.
+ */
+void QGraphicsLayoutItemPrivate::setSizeComponent(
+ Qt::SizeHint which, SizeComponent component, qreal value)
+{
+ Q_Q(QGraphicsLayoutItem);
+ ensureUserSizeHints();
+ qreal &userValue = (component == Width)
+ ? userSizeHints[which].rwidth()
+ : userSizeHints[which].rheight();
+ if (value == userValue)
+ return;
+ userValue = value;
+ q->updateGeometry();
+}
+
+/*!
\class QGraphicsLayoutItem
\brief The QGraphicsLayoutItem class can be inherited to allow your custom
items to be managed by layouts.
@@ -380,12 +442,7 @@ QSizePolicy QGraphicsLayoutItem::sizePolicy() const
*/
void QGraphicsLayoutItem::setMinimumSize(const QSizeF &size)
{
- Q_D(QGraphicsLayoutItem);
- if (size == d->userSizeHints[Qt::MinimumSize])
- return;
-
- d->userSizeHints[Qt::MinimumSize] = size;
- updateGeometry();
+ d_ptr->setSize(Qt::MinimumSize, size);
}
/*!
@@ -415,12 +472,7 @@ QSizeF QGraphicsLayoutItem::minimumSize() const
*/
void QGraphicsLayoutItem::setMinimumWidth(qreal width)
{
- Q_D(QGraphicsLayoutItem);
- qreal &userSizeHint = d->userSizeHints[Qt::MinimumSize].rwidth();
- if (width == userSizeHint)
- return;
- userSizeHint = width;
- updateGeometry();
+ d_ptr->setSizeComponent(Qt::MinimumSize, d_ptr->Width, width);
}
/*!
@@ -430,12 +482,7 @@ void QGraphicsLayoutItem::setMinimumWidth(qreal width)
*/
void QGraphicsLayoutItem::setMinimumHeight(qreal height)
{
- Q_D(QGraphicsLayoutItem);
- qreal &userSizeHint = d->userSizeHints[Qt::MinimumSize].rheight();
- if (height == userSizeHint)
- return;
- userSizeHint = height;
- updateGeometry();
+ d_ptr->setSizeComponent(Qt::MinimumSize, d_ptr->Height, height);
}
@@ -449,12 +496,7 @@ void QGraphicsLayoutItem::setMinimumHeight(qreal height)
*/
void QGraphicsLayoutItem::setPreferredSize(const QSizeF &size)
{
- Q_D(QGraphicsLayoutItem);
- if (size == d->userSizeHints[Qt::PreferredSize])
- return;
-
- d->userSizeHints[Qt::PreferredSize] = size;
- updateGeometry();
+ d_ptr->setSize(Qt::PreferredSize, size);
}
/*!
@@ -484,12 +526,7 @@ QSizeF QGraphicsLayoutItem::preferredSize() const
*/
void QGraphicsLayoutItem::setPreferredHeight(qreal height)
{
- Q_D(QGraphicsLayoutItem);
- qreal &userSizeHint = d->userSizeHints[Qt::PreferredSize].rheight();
- if (height == userSizeHint)
- return;
- userSizeHint = height;
- updateGeometry();
+ d_ptr->setSizeComponent(Qt::PreferredSize, d_ptr->Height, height);
}
/*!
@@ -499,12 +536,7 @@ void QGraphicsLayoutItem::setPreferredHeight(qreal height)
*/
void QGraphicsLayoutItem::setPreferredWidth(qreal width)
{
- Q_D(QGraphicsLayoutItem);
- qreal &userSizeHint = d->userSizeHints[Qt::PreferredSize].rwidth();
- if (width == userSizeHint)
- return;
- userSizeHint = width;
- updateGeometry();
+ d_ptr->setSizeComponent(Qt::PreferredSize, d_ptr->Width, width);
}
/*!
@@ -518,12 +550,7 @@ void QGraphicsLayoutItem::setPreferredWidth(qreal width)
*/
void QGraphicsLayoutItem::setMaximumSize(const QSizeF &size)
{
- Q_D(QGraphicsLayoutItem);
- if (size == d->userSizeHints[Qt::MaximumSize])
- return;
-
- d->userSizeHints[Qt::MaximumSize] = size;
- updateGeometry();
+ d_ptr->setSize(Qt::MaximumSize, size);
}
/*!
@@ -553,12 +580,7 @@ QSizeF QGraphicsLayoutItem::maximumSize() const
*/
void QGraphicsLayoutItem::setMaximumWidth(qreal width)
{
- Q_D(QGraphicsLayoutItem);
- qreal &userSizeHint = d->userSizeHints[Qt::MaximumSize].rwidth();
- if (width == userSizeHint)
- return;
- userSizeHint = width;
- updateGeometry();
+ d_ptr->setSizeComponent(Qt::MaximumSize, d_ptr->Width, width);
}
/*!
@@ -568,12 +590,7 @@ void QGraphicsLayoutItem::setMaximumWidth(qreal width)
*/
void QGraphicsLayoutItem::setMaximumHeight(qreal height)
{
- Q_D(QGraphicsLayoutItem);
- qreal &userSizeHint = d->userSizeHints[Qt::MaximumSize].rheight();
- if (height == userSizeHint)
- return;
- userSizeHint = height;
- updateGeometry();
+ d_ptr->setSizeComponent(Qt::MaximumSize, d_ptr->Height, height);
}
/*!
@@ -731,6 +748,11 @@ QRectF QGraphicsLayoutItem::contentsRect() const
*/
QSizeF QGraphicsLayoutItem::effectiveSizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
+ Q_D(const QGraphicsLayoutItem);
+
+ if (!d->userSizeHints && constraint.isValid())
+ return constraint;
+
// ### should respect size policy???
return d_ptr->effectiveSizeHints(constraint)[which];
}
diff --git a/src/gui/graphicsview/qgraphicslayoutitem_p.h b/src/gui/graphicsview/qgraphicslayoutitem_p.h
index fab0f39..dc044e6 100644
--- a/src/gui/graphicsview/qgraphicslayoutitem_p.h
+++ b/src/gui/graphicsview/qgraphicslayoutitem_p.h
@@ -63,16 +63,20 @@ class Q_AUTOTEST_EXPORT QGraphicsLayoutItemPrivate
{
Q_DECLARE_PUBLIC(QGraphicsLayoutItem)
public:
- virtual ~QGraphicsLayoutItemPrivate() {}
+ virtual ~QGraphicsLayoutItemPrivate();
QGraphicsLayoutItemPrivate(QGraphicsLayoutItem *parent, bool isLayout);
void init();
QSizeF *effectiveSizeHints(const QSizeF &constraint) const;
QGraphicsItem *parentItem() const;
+ void ensureUserSizeHints();
+ void setSize(Qt::SizeHint which, const QSizeF &size);
+ enum SizeComponent { Width, Height };
+ void setSizeComponent(Qt::SizeHint which, SizeComponent component, qreal value);
QSizePolicy sizePolicy;
QGraphicsLayoutItem *parent;
- QSizeF userSizeHints[Qt::NSizeHints];
+ QSizeF *userSizeHints;
mutable QSizeF cachedSizeHints[Qt::NSizeHints];
mutable QSizeF cachedConstraint;
diff --git a/src/gui/graphicsview/qgraphicslinearlayout.cpp b/src/gui/graphicsview/qgraphicslinearlayout.cpp
index 6a2d456..2f32950 100644
--- a/src/gui/graphicsview/qgraphicslinearlayout.cpp
+++ b/src/gui/graphicsview/qgraphicslinearlayout.cpp
@@ -178,7 +178,7 @@ QLayoutStyleInfo QGraphicsLinearLayoutPrivate::styleInfo() const
if (!wid)
wid = new QWidget;
QGraphicsItem *item = parentItem();
- QStyle *style = (item && item->isWidget()) ? static_cast<QGraphicsWidget*>(item)->style() : qApp->style();
+ QStyle *style = (item && item->isWidget()) ? static_cast<QGraphicsWidget*>(item)->style() : QApplication::style();
return QLayoutStyleInfo(style, wid);
}
diff --git a/src/gui/graphicsview/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp
index e660879..a5b11ff 100644
--- a/src/gui/graphicsview/qgraphicsproxywidget.cpp
+++ b/src/gui/graphicsview/qgraphicsproxywidget.cpp
@@ -460,7 +460,7 @@ void QGraphicsProxyWidgetPrivate::embedSubWindow(QWidget *subWin)
{
QWExtra *extra;
if (!((extra = subWin->d_func()->extra) && extra->proxyWidget)) {
- QGraphicsProxyWidget *subProxy = new QGraphicsProxyWidget(q_func());
+ QGraphicsProxyWidget *subProxy = new QGraphicsProxyWidget(q_func(), subWin->windowFlags());
subProxy->d_func()->setWidget_helper(subWin, false);
}
}
@@ -544,6 +544,9 @@ QGraphicsProxyWidget::~QGraphicsProxyWidget()
hidden or disabled after embedding is complete. The class documentation
has a full overview over the shared state.
+ QGraphicsProxyWidget's window flags determine whether the widget, after
+ embedding, will be given window decorations or not.
+
After this function returns, QGraphicsProxyWidget will keep its state
synchronized with that of \a widget whenever possible.
@@ -661,10 +664,6 @@ void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool auto
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());
@@ -977,6 +976,7 @@ void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *even
}
#endif // QT_NO_CONTEXTMENU
+#ifndef QT_NO_DRAGANDDROP
/*!
\reimp
*/
@@ -1097,6 +1097,7 @@ void QGraphicsProxyWidget::dropEvent(QGraphicsSceneDragDropEvent *event)
}
#endif
}
+#endif
/*!
\reimp
diff --git a/src/gui/graphicsview/qgraphicsproxywidget.h b/src/gui/graphicsview/qgraphicsproxywidget.h
index f006319..0c874c8 100644
--- a/src/gui/graphicsview/qgraphicsproxywidget.h
+++ b/src/gui/graphicsview/qgraphicsproxywidget.h
@@ -90,10 +90,12 @@ protected:
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);
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 5114351..900fa1a 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -39,7 +39,6 @@
**
****************************************************************************/
-static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;
/*!
\class QGraphicsScene
@@ -250,6 +249,8 @@ static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;
QT_BEGIN_NAMESPACE
+static inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2);
+
static inline bool QRectF_intersects(const QRectF &s, const QRectF &r)
{
qreal xp = s.left();
@@ -333,8 +334,9 @@ QGraphicsScenePrivate::QGraphicsScenePrivate()
hasSceneRect(false),
updateAll(false),
calledEmitUpdated(false),
+ processDirtyItemsEmitted(false),
selectionChanging(0),
- dirtyItemResetPending(false),
+ needSortTopLevelItems(true),
regenerateIndex(true),
purgePending(false),
indexTimerId(0),
@@ -351,6 +353,8 @@ QGraphicsScenePrivate::QGraphicsScenePrivate()
dragDropItem(0),
enterWidget(0),
lastDropAction(Qt::IgnoreAction),
+ allItemsIgnoreHoverEvents(true),
+ allItemsUseDefaultCursor(true),
painterStateProtection(true),
sortCacheEnabled(false),
updatingSortCache(false),
@@ -410,7 +414,7 @@ QList<QGraphicsItem *> QGraphicsScenePrivate::estimateItemsInRect(const QRectF &
if (QGraphicsItem *item = unindexedItems.at(i)) {
if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
continue;
- if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0))
+ if (item->d_ptr->visible && !item->d_ptr->isFullyTransparent())
itemsInRect << item;
}
}
@@ -418,7 +422,7 @@ QList<QGraphicsItem *> QGraphicsScenePrivate::estimateItemsInRect(const QRectF &
if (QGraphicsItem *item = indexedItems.at(i)) {
if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
continue;
- if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0))
+ if (item->d_ptr->visible && !item->d_ptr->isFullyTransparent())
itemsInRect << item;
}
}
@@ -596,7 +600,7 @@ void QGraphicsScenePrivate::_q_emitUpdated()
// 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)) {
+ if (connectedSignals & changedSignalMask) {
for (int i = 0; i < views.size(); ++i) {
QGraphicsView *view = views.at(i);
if (!view->d_func()->connectedToScene) {
@@ -605,13 +609,13 @@ void QGraphicsScenePrivate::_q_emitUpdated()
views.at(i), SLOT(updateScene(QList<QRectF>)));
}
}
+ } else {
+ updateAll = false;
+ for (int i = 0; i < views.size(); ++i)
+ views.at(i)->d_func()->processPendingUpdates();
+ return;
}
- // 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;
@@ -622,6 +626,23 @@ void QGraphicsScenePrivate::_q_emitUpdated()
/*!
\internal
+*/
+void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item)
+{
+ needSortTopLevelItems = true;
+ topLevelItems.append(item);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item)
+{
+ topLevelItems.removeOne(item);
+}
+
+/*!
+ \internal
Updates all items in the pending update list. At this point, the list is
unlikely to contain partially constructed items.
@@ -652,70 +673,102 @@ void QGraphicsScenePrivate::_q_polishItems()
unpolishedItems.clear();
}
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::_q_resetDirtyItems()
+void QGraphicsScenePrivate::_q_processDirtyItems()
{
- 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;
-}
+ processDirtyItemsEmitted = false;
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::resetDirtyItemsLater()
-{
- Q_Q(QGraphicsScene);
- if (dirtyItemResetPending)
+ const bool wasPendingSceneUpdate = calledEmitUpdated;
+ const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
+ processDirtyItemsRecursive(0);
+ if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect)
+ emit q_func()->sceneRectChanged(growingItemsBoundingRect);
+
+ if (wasPendingSceneUpdate)
return;
- // dirtyItems.reserve(indexedItems.size() + unindexedItems.size());
- dirtyItemResetPending = true;
- QMetaObject::invokeMethod(q, "_q_resetDirtyItems", Qt::QueuedConnection);
+
+ for (int i = 0; i < views.size(); ++i)
+ views.at(i)->d_func()->processPendingUpdates();
+
+ if (calledEmitUpdated) {
+ // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive
+ // and we cannot wait for the control to reach the eventloop before the
+ // changed signal is emitted, so we emit it now.
+ _q_emitUpdated();
+ }
+
+ // Immediately dispatch all pending update requests on the views.
+ for (int i = 0; i < views.size(); ++i) {
+ QWidget *viewport = views.at(i)->d_func()->viewport;
+ if (qt_widget_private(viewport)->paintOnScreen())
+ QCoreApplication::sendPostedEvents(viewport, QEvent::UpdateRequest);
+ else
+ QCoreApplication::sendPostedEvents(viewport->window(), QEvent::UpdateRequest);
+ }
}
/*!
\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().
+ around in the BSP tree if called from the item's destructor; these will
+ be cleaned up the next time someone triggers purgeRemovedItems().
- Note: This function is called from QGraphicsItem's destructor. \a item is
+ Note: This function might get 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)
+void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
{
Q_Q(QGraphicsScene);
- // Clear focus on the item to remove any reference in the focusWidget
- // chain.
+ // 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) {
+ markDirty(item, QRectF(), false, false, false, false, /*removingItemFromScene=*/true);
+
+ if (!item->d_ptr->inDestructor) {
+ // Can potentially call item->boundingRect() (virtual function), that's why
+ // we only can call this function if the item is not in its destructor.
+ removeFromIndex(item);
+ } else if (item->d_ptr->index != -1) {
+ // Important: The index is useless until purgeRemovedItems() is called.
+ indexedItems[item->d_ptr->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();
+ }
+
+ if (!item->d_ptr->inDestructor && item == tabFocusFirst) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
+ widget->d_func()->fixFocusChainBeforeReparenting(0, 0);
+ }
+
+ item->d_func()->scene = 0;
+
+ // Remove from parent, or unregister from toplevels.
+ if (QGraphicsItem *parentItem = item->parentItem()) {
+ if (parentItem->scene()) {
+ Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem",
+ "Parent item's scene is different from this item's scene");
+ item->d_ptr->setParentItemHelper(0);
+ }
+ } else {
+ unregisterTopLevelItem(item);
+ }
+
+ if (!item->d_ptr->inDestructor) {
+ // Remove from our item lists.
+ int index = item->d_func()->index;
+ if (index != -1) {
+ freeItemIndexes << index;
+ indexedItems[index] = 0;
+ } else {
+ unindexedItems.removeAll(item);
+ }
}
// Reset the mouse grabber and focus item data.
@@ -735,10 +788,10 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item)
// Update selected & hovered item bookkeeping
selectedItems.remove(item);
hoverItems.removeAll(item);
- pendingUpdateItems.removeAll(item);
cachedItemsUnderMouse.removeAll(item);
unpolishedItems.removeAll(item);
- dirtyItems.removeAll(item);
+ pendingUpdateItems.removeAll(item);
+ resetDirtyItem(item);
//We remove all references of item from the sceneEventFilter arrays
QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin();
@@ -749,24 +802,19 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item)
++iterator;
}
- // Remove from scene transform cache
- int transformIndex = item->d_func()->sceneTransformIndex;
- if (transformIndex != -1) {
- validTransforms.setBit(transformIndex, 0);
- freeSceneTransformSlots.append(transformIndex);
+ if (!item->d_ptr->inDestructor) {
+ // Remove all children recursively
+ for (int i = 0; i < item->d_ptr->children.size(); ++i)
+ q->removeItem(item->d_ptr->children.at(i));
}
- // Remove all children recursively.
- foreach (QGraphicsItem *child, item->children())
- _q_removeItemLater(child);
-
- // Reset the mouse grabber
+ // Reset the mouse grabber and focus item data.
if (mouseGrabberItems.contains(item))
- ungrabMouse(item, /* item is dying */ true);
+ ungrabMouse(item, /* item is dying */ item->d_ptr->inDestructor);
// Reset the keyboard grabber
if (keyboardGrabberItems.contains(item))
- ungrabKeyboard(item, /* item is dying */ true);
+ ungrabKeyboard(item, /* item is dying */ item->d_ptr->inDestructor);
// Reset the last mouse grabber item
if (item == lastMouseGrabberItem)
@@ -785,8 +833,6 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item)
*/
void QGraphicsScenePrivate::purgeRemovedItems()
{
- Q_Q(QGraphicsScene);
-
if (!purgePending && removedItems.isEmpty())
return;
@@ -802,9 +848,6 @@ void QGraphicsScenePrivate::purgeRemovedItems()
freeItemIndexes << i;
}
purgePending = false;
-
- // No locality info for the items; update the whole scene.
- q->update();
}
/*!
@@ -812,13 +855,13 @@ void QGraphicsScenePrivate::purgeRemovedItems()
Starts or restarts the timer used for reindexing unindexed items.
*/
-void QGraphicsScenePrivate::startIndexTimer()
+void QGraphicsScenePrivate::startIndexTimer(int interval)
{
Q_Q(QGraphicsScene);
if (indexTimerId) {
restartIndexTimer = true;
} else {
- indexTimerId = q->startTimer(QGRAPHICSSCENE_INDEXTIMER_TIMEOUT);
+ indexTimerId = q->startTimer(interval);
}
}
@@ -880,11 +923,18 @@ 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
+ if (mouseGrabberItems.last() == item) {
+ Q_ASSERT(!implicit);
+ if (!lastMouseGrabberItemHasImplicitMouseGrab) {
+ qWarning("QGraphicsItem::grabMouse: already a mouse grabber");
+ } else {
+ // Upgrade to an explicit mouse grab
+ lastMouseGrabberItemHasImplicitMouseGrab = false;
+ }
+ } else {
qWarning("QGraphicsItem::grabMouse: already blocked by mouse grabber: %p",
mouseGrabberItems.last());
+ }
return;
}
@@ -1036,6 +1086,12 @@ void QGraphicsScenePrivate::clearKeyboardGrabber()
ungrabKeyboard(keyboardGrabberItems.first());
}
+void QGraphicsScenePrivate::enableMouseTrackingOnViews()
+{
+ foreach (QGraphicsView *view, views)
+ view->viewport()->setMouseTracking(true);
+}
+
/*!
Returns all items for the screen position in \a event.
*/
@@ -1294,7 +1350,8 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
// 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 (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick
+ && item != lastMouseGrabberItem && 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:
@@ -1367,6 +1424,109 @@ QGraphicsWidget *QGraphicsScenePrivate::windowForItem(const QGraphicsItem *item)
return 0;
}
+void QGraphicsScenePrivate::recursive_items_helper(QGraphicsItem *item, QRectF rect,
+ QList<QGraphicsItem *> *items,
+ const QTransform &parentTransform,
+ const QTransform &viewTransform,
+ Qt::ItemSelectionMode mode, Qt::SortOrder order,
+ qreal parentOpacity) const
+{
+ // Calculate opacity.
+ qreal opacity;
+ if (item) {
+ if (!item->d_ptr->visible)
+ return;
+ QGraphicsItem *p = item->d_ptr->parent;
+ bool itemIgnoresParentOpacity = item->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity;
+ bool parentDoesntPropagateOpacity = (p && (p->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren));
+ if (!itemIgnoresParentOpacity && !parentDoesntPropagateOpacity) {
+ opacity = parentOpacity * item->opacity();
+ } else {
+ opacity = item->d_ptr->opacity;
+ }
+ if (opacity == 0.0 && !(item->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren))
+ return;
+ } else {
+ opacity = parentOpacity;
+ }
+
+ // Calculate the full transform for this item.
+ QTransform transform = parentTransform;
+ bool keep = false;
+ if (item) {
+ item->d_ptr->combineTransformFromParent(&transform, &viewTransform);
+
+ // ### This does not take the clip into account.
+ QRectF brect = item->boundingRect();
+ _q_adjustRect(&brect);
+
+ keep = true;
+ if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect)
+ keep = rect.contains(transform.mapRect(brect)) && rect != brect;
+ else
+ keep = rect.intersects(transform.mapRect(brect));
+
+ if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
+ QPainterPath rectPath;
+ rectPath.addRect(rect);
+ keep = itemCollidesWithPath(item, transform.inverted().map(rectPath), mode);
+ }
+ }
+
+ bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape));
+ bool dontProcessItem = !item || !keep;
+ bool dontProcessChildren = item && dontProcessItem && childClip;
+
+ // Find and sort children.
+ QList<QGraphicsItem *> &children = item ? item->d_ptr->children : const_cast<QGraphicsScenePrivate *>(this)->topLevelItems;
+ if (!dontProcessChildren) {
+ if (item && item->d_ptr->needSortChildren) {
+ item->d_ptr->needSortChildren = 0;
+ qStableSort(children.begin(), children.end(), qt_notclosestLeaf);
+ } else if (!item && needSortTopLevelItems) {
+ const_cast<QGraphicsScenePrivate *>(this)->needSortTopLevelItems = false;
+ qStableSort(children.begin(), children.end(), qt_notclosestLeaf);
+ }
+ }
+
+ childClip &= !dontProcessChildren & !children.isEmpty();
+
+ // Clip.
+ if (childClip)
+ rect &= transform.map(item->shape()).controlPointRect();
+
+ // Process children behind
+ int i = 0;
+ if (!dontProcessChildren) {
+ for (i = 0; i < children.size(); ++i) {
+ QGraphicsItem *child = children.at(i);
+ if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
+ break;
+ recursive_items_helper(child, rect, items, transform, viewTransform,
+ mode, order, opacity);
+ }
+ }
+
+ // Process item
+ if (!dontProcessItem)
+ items->append(item);
+
+ // Process children in front
+ if (!dontProcessChildren) {
+ for (; i < children.size(); ++i)
+ recursive_items_helper(children.at(i), rect, items, transform, viewTransform,
+ mode, order, opacity);
+ }
+
+ if (!item && order == Qt::AscendingOrder) {
+ int n = items->size();
+ for (int i = 0; i < n / 2; ++i) {
+ QGraphicsItem *tmp = (*items)[n - i - 1];
+ (*items)[n - i - 1] = (*items)[i];
+ (*items)[i] = tmp;
+ }
+ }
+}
QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPointF &pos) const
{
@@ -1602,7 +1762,7 @@ void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
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())
+ if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible())
continue;
// Skip invisible items and all their children.
@@ -1642,7 +1802,7 @@ void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
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())
+ if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible())
continue;
// Skip invisible items and all their children.
@@ -1678,7 +1838,7 @@ void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
// Recurse into children.
- if (!item->d_ptr->hasTransform || item->transform().type() <= QTransform::TxScale) {
+ if (!item->d_ptr->transformData || item->d_ptr->transformData->computedFullTransform().type() <= QTransform::TxScale) {
// Rect
childItems_helper(items, item, item->mapRectFromParent(rect), mode);
} else {
@@ -1708,7 +1868,7 @@ void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
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())
+ if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible())
continue;
// Skip invisible items.
@@ -1767,7 +1927,7 @@ void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
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())
+ if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible())
continue;
// Skip invisible items.
@@ -1831,7 +1991,12 @@ inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item
if (f1 != f2) return f2;
qreal z1 = d1->z;
qreal z2 = d2->z;
- return z1 != z2 ? z1 > z2 : item1 > item2;
+ return z1 > z2;
+}
+
+static inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
+{
+ return qt_closestLeaf(item2, item1);
}
/*!
@@ -1996,7 +2161,7 @@ void QGraphicsScenePrivate::setFont_helper(const QFont &font)
*/
void QGraphicsScenePrivate::resolveFont()
{
- QFont naturalFont = qApp->font();
+ QFont naturalFont = QApplication::font();
naturalFont.resolve(0);
QFont resolvedFont = font.resolve(naturalFont);
updateFont(resolvedFont);
@@ -2052,7 +2217,7 @@ void QGraphicsScenePrivate::setPalette_helper(const QPalette &palette)
*/
void QGraphicsScenePrivate::resolvePalette()
{
- QPalette naturalPalette = qApp->palette();
+ QPalette naturalPalette = QApplication::palette();
naturalPalette.resolve(0);
QPalette resolvedPalette = palette.resolve(naturalPalette);
updatePalette(resolvedPalette);
@@ -2211,8 +2376,6 @@ void QGraphicsScene::setSceneRect(const QRectF &rect)
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())
@@ -2269,36 +2432,8 @@ void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRect
// 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 = item->deviceTransform(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;
- }
+ for (int i = 0; i < numItems; ++i)
+ itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect());
// Render the scene.
drawBackground(painter, sourceRect);
@@ -2474,7 +2609,6 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const
return d->items_helper(pos);
}
-
/*!
\fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const
@@ -2491,7 +2625,9 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const
QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode) const
{
Q_D(const QGraphicsScene);
- return d->items_helper(rect, mode, Qt::AscendingOrder);
+ QList<QGraphicsItem *> itemList;
+ d->recursive_items_helper(0, rect, &itemList, QTransform(), QTransform(), mode, Qt::AscendingOrder);
+ return itemList;
}
/*!
@@ -2742,12 +2878,13 @@ void QGraphicsScene::clear()
}
d->unindexedItems.clear();
qDeleteAll(unindexedParents);
-
d->indexedItems.clear();
d->freeItemIndexes.clear();
d->lastItemCount = 0;
d->bspTree.clear();
d->largestUntransformableItem = QRectF();
+ d->allItemsIgnoreHoverEvents = true;
+ d->allItemsUseDefaultCursor = true;
}
/*!
@@ -2851,7 +2988,6 @@ void QGraphicsScene::addItem(QGraphicsItem *item)
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);
@@ -2890,7 +3026,11 @@ void QGraphicsScene::addItem(QGraphicsItem *item)
// a temporary list and schedule an indexing for later.
d->unindexedItems << item;
item->d_func()->index = -1;
- d->startIndexTimer();
+ d->startIndexTimer(0);
+
+ // Add to list of toplevels if this item is a toplevel.
+ if (!item->d_ptr->parent)
+ d->registerTopLevelItem(item);
// Update the scene's sort cache settings.
item->d_ptr->globalStackingOrder = -1;
@@ -2909,6 +3049,19 @@ void QGraphicsScene::addItem(QGraphicsItem *item)
++d->selectionChanging;
int oldSelectedItemSize = d->selectedItems.size();
+ // Enable mouse tracking if the item accepts hover events or has a cursor set.
+ if (d->allItemsIgnoreHoverEvents && d->itemAcceptsHoverEvents_helper(item)) {
+ d->allItemsIgnoreHoverEvents = false;
+ d->enableMouseTrackingOnViews();
+ }
+#ifndef QT_NO_CURSOR
+ if (d->allItemsUseDefaultCursor && item->hasCursor()) {
+ d->allItemsUseDefaultCursor = false;
+ if (d->allItemsIgnoreHoverEvents) // already enabled otherwise
+ d->enableMouseTrackingOnViews();
+ }
+#endif //QT_NO_CURSOR
+
// Update selection lists
if (item->isSelected())
d->selectedItems << item;
@@ -3226,106 +3379,7 @@ void QGraphicsScene::removeItem(QGraphicsItem *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);
-
- //We remove all references of item from the sceneEventFilter arrays
- QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = d->sceneEventFilters.begin();
- while (iterator != d->sceneEventFilters.end()) {
- if (iterator.value() == item || iterator.key() == item)
- iterator = d->sceneEventFilters.erase(iterator);
- else
- ++iterator;
- }
-
-
- //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();
+ d->removeItemHelper(item);
// Deliver post-change notification
item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
@@ -3628,7 +3682,7 @@ void QGraphicsScene::update(const QRectF &rect)
}
}
- if (!directUpdates && !d->calledEmitUpdated) {
+ if (!d->calledEmitUpdated) {
d->calledEmitUpdated = true;
QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection);
}
@@ -3744,6 +3798,8 @@ bool QGraphicsScene::event(QEvent *event)
// 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.
+ // ### this should only be cleared if we received a new mouse move event,
+ // which relies on us fixing the replay mechanism in QGraphicsView.
d->cachedItemsUnderMouse.clear();
default:
break;
@@ -3919,10 +3975,10 @@ bool QGraphicsScene::eventFilter(QObject *watched, QEvent *event)
switch (event->type()) {
case QEvent::ApplicationPaletteChange:
- qApp->postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
+ QApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
break;
case QEvent::ApplicationFontChange:
- qApp->postEvent(this, new QEvent(QEvent::ApplicationFontChange));
+ QApplication::postEvent(this, new QEvent(QEvent::ApplicationFontChange));
break;
default:
break;
@@ -4209,6 +4265,9 @@ bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *i
*/
bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent)
{
+ if (allItemsIgnoreHoverEvents)
+ return false;
+
// Find the first item that accepts hover events, reusing earlier
// calculated data is possible.
if (cachedItemsUnderMouse.isEmpty()) {
@@ -4608,7 +4667,7 @@ static void _q_paintItem(QGraphicsItem *item, QPainter *painter,
? proxy->widget()->windowOpacity() : 1.0;
const qreal oldPainterOpacity = painter->opacity();
- if (qFuzzyCompare(windowOpacity + 1, qreal(1.0)))
+ if (qFuzzyIsNull(windowOpacity))
return;
// Set new painter opacity.
if (windowOpacity < 1.0)
@@ -4717,8 +4776,9 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
return;
// Fetch the off-screen transparent buffer and exposed area info.
- QString pixmapKey;
+ QPixmapCache::Key pixmapKey;
QPixmap pix;
+ bool pixmapFound;
QGraphicsItemCache *itemCache = itemd->extraItemCache();
if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
if (itemCache->boundingRect != brect.toRect()) {
@@ -4728,17 +4788,11 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
}
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);
- }
+ pixmapKey = itemCache->deviceData.value(widget).key;
}
// Find pixmap in cache.
- if (!itemCache->allExposed)
- QPixmapCache::find(pixmapKey, pix);
+ pixmapFound = QPixmapCache::find(pixmapKey, &pix);
// Render using item coordinate cache mode.
if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
@@ -4763,6 +4817,12 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
// Redraw any newly exposed areas.
if (itemCache->allExposed || !itemCache->exposed.isEmpty()) {
+
+ //We know that we will modify the pixmap, removing it from the cache
+ //will detach the one we have and avoid a deep copy
+ if (pixmapFound)
+ QPixmapCache::remove(pixmapKey);
+
// Fit the item's bounding rect into the pixmap's coordinates.
QTransform itemToPixmap;
if (fixedCacheSize) {
@@ -4773,7 +4833,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
// Generate the item's exposedRect and map its list of expose
// rects to device coordinates.
- QStyleOptionGraphicsItem cacheOption = *option;
+ styleOptionTmp = *option;
QRegion pixmapExposed;
QRectF exposedRect;
if (!itemCache->allExposed) {
@@ -4785,14 +4845,14 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
} else {
exposedRect = brect;
}
- cacheOption.exposedRect = exposedRect;
+ styleOptionTmp.exposedRect = exposedRect;
// Render.
_q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
- &cacheOption, painterStateProtection);
+ &styleOptionTmp, painterStateProtection);
- // Reinsert this pixmap into the cache.
- QPixmapCache::insert(pixmapKey, pix);
+ // insert this pixmap into the cache.
+ itemCache->key = QPixmapCache::insert(pix);
// Reset expose data.
itemCache->allExposed = false;
@@ -4858,7 +4918,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
bool allowPartialCacheExposure = !viewRect.contains(deviceRect);
#else
// Only if deviceRect is 20% taller or wider than the desktop.
- QRect desktopRect = qApp->desktop()->availableGeometry(widget);
+ QRect desktopRect = QApplication::desktop()->availableGeometry(widget);
bool allowPartialCacheExposure = (desktopRect.width() * 1.2 < deviceRect.width()
|| desktopRect.height() * 1.2 < deviceRect.height());
#endif
@@ -4919,6 +4979,11 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
// Check for newly invalidated areas.
if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) {
+ //We know that we will modify the pixmap, removing it from the cache
+ //will detach the one we have and avoid a deep copy
+ if (pixmapFound)
+ QPixmapCache::remove(pixmapKey);
+
// Construct an item-to-pixmap transform.
QPointF p = deviceRect.topLeft();
QTransform itemToPixmap = painter->worldTransform();
@@ -4945,12 +5010,12 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
foreach (QRect r, scrollExposure.rects())
br |= pixmapToItem.mapRect(r);
}
- QStyleOptionGraphicsItem cacheOption = *option;
- cacheOption.exposedRect = br.adjusted(-1, -1, 1, 1);
+ styleOptionTmp = *option;
+ styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1);
// Render the exposed areas.
_q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
- &cacheOption, painterStateProtection);
+ &styleOptionTmp, painterStateProtection);
// Reset expose data.
pixModified = true;
@@ -4959,8 +5024,8 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
}
if (pixModified) {
- // Reinsert this pixmap into the cache
- QPixmapCache::insert(pixmapKey, pix);
+ // Insert this pixmap into the cache.
+ deviceData->key = QPixmapCache::insert(pix);
}
// Redraw the exposed area using an untransformed painter. This
@@ -4979,6 +5044,397 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
}
}
+void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter,
+ const QTransform &viewTransform,
+ QRegion *exposedRegion, QWidget *widget,
+ QList<QGraphicsItem *> *topLevelItems,
+ qreal parentOpacity)
+{
+ // Calculate opacity.
+ qreal opacity;
+ bool invisibleButChildIgnoresParentOpacity = false;
+ if (item) {
+ if (!item->d_ptr->visible)
+ return;
+ QGraphicsItem *p = item->d_ptr->parent;
+ bool itemIgnoresParentOpacity = item->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity;
+ bool parentDoesntPropagateOpacity = (p && (p->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren));
+ if (!itemIgnoresParentOpacity && !parentDoesntPropagateOpacity) {
+ opacity = parentOpacity * item->opacity();
+ } else {
+ opacity = item->d_ptr->opacity;
+ }
+ if (opacity == 0.0 && !(item->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) {
+ invisibleButChildIgnoresParentOpacity = !item->d_ptr->childrenCombineOpacity();
+ if (!invisibleButChildIgnoresParentOpacity)
+ return;
+ }
+ } else {
+ opacity = parentOpacity;
+ }
+
+ // Calculate the full transform for this item.
+ bool wasDirtyParentSceneTransform = false;
+ bool dontDrawItem = true;
+ QTransform transform;
+ if (item) {
+ if (item->d_ptr->itemIsUntransformable()) {
+ transform = item->deviceTransform(viewTransform);
+ } else {
+ if (item->d_ptr->dirtySceneTransform) {
+ item->d_ptr->sceneTransform = item->d_ptr->parent ? item->d_ptr->parent->d_ptr->sceneTransform
+ : QTransform();
+ item->d_ptr->combineTransformFromParent(&item->d_ptr->sceneTransform);
+ item->d_ptr->dirtySceneTransform = 0;
+ wasDirtyParentSceneTransform = true;
+ }
+ transform = item->d_ptr->sceneTransform;
+ transform *= viewTransform;
+ }
+
+ QRectF brect = item->boundingRect();
+ // ### This does not take the clip into account.
+ _q_adjustRect(&brect);
+ QRect viewBoundingRect = transform.mapRect(brect).toRect();
+ item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
+ viewBoundingRect.adjust(-1, -1, 1, 1);
+ if (exposedRegion)
+ dontDrawItem = !exposedRegion->intersects(viewBoundingRect);
+ else
+ dontDrawItem = viewBoundingRect.isEmpty();
+ }
+
+ // Find and sort children.
+ QList<QGraphicsItem *> tmp;
+ QList<QGraphicsItem *> *children = 0;
+ if (item) {
+ children = &item->d_ptr->children;
+ } else if (topLevelItems) {
+ children = topLevelItems;
+ } else if (indexMethod == QGraphicsScene::NoIndex || !exposedRegion) {
+ children = &this->topLevelItems;
+ } else {
+ QRectF sceneRect = viewTransform.inverted().mapRect(QRectF(exposedRegion->boundingRect().adjusted(-1, -1, 1, 1)));
+ if (!largestUntransformableItem.isEmpty()) {
+ // ### Nuke this when we move the indexing code into a separate
+ // class. All the largestUntransformableItem code should then go
+ // away, and the estimate function should return untransformable
+ // items as well.
+ QRectF untr = largestUntransformableItem;
+ QRectF ltri = viewTransform.inverted().mapRect(untr);
+ ltri.adjust(-untr.width(), -untr.height(), untr.width(), untr.height());
+ sceneRect.adjust(-ltri.width(), -ltri.height(), ltri.width(), ltri.height());
+ }
+ tmp = estimateItemsInRect(sceneRect);
+
+ QList<QGraphicsItem *> tli;
+ for (int i = 0; i < tmp.size(); ++i)
+ tmp.at(i)->topLevelItem()->d_ptr->itemDiscovered = 1;
+
+ // Sort if the toplevel list is unsorted.
+ if (needSortTopLevelItems) {
+ needSortTopLevelItems = false;
+ qStableSort(this->topLevelItems.begin(),
+ this->topLevelItems.end(), qt_notclosestLeaf);
+ }
+
+ for (int i = 0; i < this->topLevelItems.size(); ++i) {
+ // ### Investigate smarter ways. Looping through all top level
+ // items is not optimal. If the BSP tree is to have maximum
+ // effect, it should be possible to sort the subset of items
+ // quickly. We must use this approach for now, as it's the only
+ // current way to keep the stable sorting order (insertion order).
+ QGraphicsItem *item = this->topLevelItems.at(i);
+ if (item->d_ptr->itemDiscovered) {
+ item->d_ptr->itemDiscovered = 0;
+ tli << item;
+ }
+ }
+
+ tmp = tli;
+ children = &tmp;
+ }
+
+ bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape));
+ bool dontDrawChildren = item && dontDrawItem && childClip;
+ childClip &= !dontDrawChildren && !children->isEmpty();
+ if (item && ((item->d_ptr->flags & QGraphicsItem::ItemHasNoContents) || invisibleButChildIgnoresParentOpacity))
+ dontDrawItem = true;
+
+ // Clip children.
+ if (childClip) {
+ painter->save();
+ painter->setWorldTransform(transform);
+ painter->setClipPath(item->shape(), Qt::IntersectClip);
+ }
+
+ if (!dontDrawChildren) {
+ if (item && item->d_ptr->needSortChildren) {
+ item->d_ptr->needSortChildren = 0;
+ qStableSort(children->begin(), children->end(), qt_notclosestLeaf);
+ } else if (!item && needSortTopLevelItems && children != &tmp) {
+ needSortTopLevelItems = false;
+ qStableSort(children->begin(), children->end(), qt_notclosestLeaf);
+ }
+ }
+
+ // Draw children behind
+ int i = 0;
+ if (!dontDrawChildren) {
+ // ### Don't visit children that don't ignore parent opacity if this
+ // item is invisible.
+ for (i = 0; i < children->size(); ++i) {
+ QGraphicsItem *child = children->at(i);
+ if (wasDirtyParentSceneTransform)
+ child->d_ptr->dirtySceneTransform = 1;
+ if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
+ break;
+ drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget,
+ 0, opacity);
+ }
+ }
+
+ // Draw item
+ if (!dontDrawItem) {
+ item->d_ptr->initStyleOption(&styleOptionTmp, transform, exposedRegion ? *exposedRegion : QRegion(), exposedRegion == 0);
+
+ bool clipsToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsToShape);
+ bool savePainter = clipsToShape || painterStateProtection;
+ if (savePainter)
+ painter->save();
+ if (!childClip)
+ painter->setWorldTransform(transform);
+ if (clipsToShape)
+ painter->setClipPath(item->shape(), Qt::IntersectClip);
+ painter->setOpacity(opacity);
+ drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection);
+
+ if (savePainter)
+ painter->restore();
+ }
+
+ // Draw children in front
+ if (!dontDrawChildren) {
+ // ### Don't visit children that don't ignore parent opacity if this
+ // item is invisible.
+ for (; i < children->size(); ++i) {
+ QGraphicsItem *child = children->at(i);
+ if (wasDirtyParentSceneTransform)
+ child->d_ptr->dirtySceneTransform = 1;
+ drawSubtreeRecursive(child, painter, viewTransform, exposedRegion,
+ widget, 0, opacity);
+ }
+ } else if (wasDirtyParentSceneTransform) {
+ item->d_ptr->invalidateChildrenSceneTransform();
+ }
+
+ // Restore child clip
+ if (childClip)
+ painter->restore();
+}
+
+void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren,
+ bool maybeDirtyClipPath, bool force, bool ignoreOpacity,
+ bool removingItemFromScene)
+{
+ Q_ASSERT(item);
+ if (updateAll)
+ return;
+
+ if (item->d_ptr->discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath,
+ /*ignoreVisibleBit=*/force,
+ /*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren,
+ /*ignoreOpacity=*/ignoreOpacity)) {
+ return;
+ }
+
+ const bool fullItemUpdate = rect.isNull();
+ if (!fullItemUpdate && rect.isEmpty())
+ return;
+
+ if (!processDirtyItemsEmitted) {
+ QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection);
+ processDirtyItemsEmitted = true;
+ }
+
+ if (removingItemFromScene) {
+ // Note that this function can be called from the item's destructor, so
+ // do NOT call any virtual functions on it within this block.
+ if ((connectedSignals & changedSignalMask) || views.isEmpty()) {
+ // 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.
+ q_func()->update();
+ return;
+ }
+
+ for (int i = 0; i < views.size(); ++i) {
+ QGraphicsViewPrivate *viewPrivate = views.at(i)->d_func();
+ QRect rect = item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport);
+ rect.translate(viewPrivate->dirtyScrollOffset);
+ viewPrivate->updateRect(rect);
+ }
+ return;
+ }
+
+ item->d_ptr->dirty = 1;
+ if (fullItemUpdate)
+ item->d_ptr->fullUpdatePending = 1;
+ else if (!item->d_ptr->fullUpdatePending)
+ item->d_ptr->needsRepaint |= rect;
+
+ if (invalidateChildren) {
+ item->d_ptr->allChildrenDirty = 1;
+ item->d_ptr->dirtyChildren = 1;
+ }
+
+ QGraphicsItem *p = item->d_ptr->parent;
+ while (p && !p->d_ptr->dirtyChildren) {
+ p->d_ptr->dirtyChildren = 1;
+ p = p->d_ptr->parent;
+ }
+}
+
+void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren)
+{
+ Q_Q(QGraphicsScene);
+
+ // Calculate the full scene transform for this item.
+ bool wasDirtyParentSceneTransform = false;
+ if (item && item->d_ptr->dirtySceneTransform && !item->d_ptr->itemIsUntransformable()) {
+ item->d_ptr->sceneTransform = item->d_ptr->parent ? item->d_ptr->parent->d_ptr->sceneTransform
+ : QTransform();
+ item->d_ptr->combineTransformFromParent(&item->d_ptr->sceneTransform);
+ item->d_ptr->dirtySceneTransform = 0;
+ wasDirtyParentSceneTransform = true;
+ }
+
+ // Process item.
+ bool wasDirtyParentViewBoundingRects = false;
+ if (item && (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint)) {
+ const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask);
+ const bool untransformableItem = item->d_ptr->itemIsUntransformable();
+ const QRectF itemBoundingRect = item->boundingRect();
+
+ if (item->d_ptr->geometryChanged) {
+ // Update growingItemsBoundingRect.
+ if (!hasSceneRect) {
+ QRectF itemSceneBoundingRect = item->d_ptr->sceneTransform.mapRect(itemBoundingRect);
+ _q_adjustRect(&itemSceneBoundingRect);
+ growingItemsBoundingRect |= itemSceneBoundingRect;
+ }
+ item->d_ptr->geometryChanged = 0;
+ }
+
+ if (useCompatUpdate && !untransformableItem && qFuzzyIsNull(item->boundingRegionGranularity())) {
+ // 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.
+ q->update(item->d_ptr->sceneTransform.mapRect(itemBoundingRect));
+ } else {
+ QRectF dirtyRect;
+ bool uninitializedDirtyRect = true;
+
+ for (int j = 0; j < views.size(); ++j) {
+ QGraphicsView *view = views.at(j);
+ QGraphicsViewPrivate *viewPrivate = view->d_func();
+ if (viewPrivate->fullUpdatePending)
+ continue;
+ switch (viewPrivate->viewportUpdateMode) {
+ case QGraphicsView::NoViewportUpdate:
+ continue;
+ case QGraphicsView::FullViewportUpdate:
+ view->viewport()->update();
+ viewPrivate->fullUpdatePending = 1;
+ continue;
+ default:
+ break;
+ }
+
+ if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
+ wasDirtyParentViewBoundingRects = true;
+ QRect rect = item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport);
+ rect.translate(viewPrivate->dirtyScrollOffset);
+ viewPrivate->updateRect(rect);
+ }
+
+ if (!item->d_ptr->dirty)
+ continue;
+
+ if (uninitializedDirtyRect) {
+ dirtyRect = itemBoundingRect;
+ _q_adjustRect(&dirtyRect);
+ if (!item->d_ptr->fullUpdatePending) {
+ _q_adjustRect(&item->d_ptr->needsRepaint);
+ dirtyRect &= item->d_ptr->needsRepaint;
+ }
+ uninitializedDirtyRect = false;
+ }
+
+ if (dirtyRect.isEmpty())
+ continue; // Discard updates outside the bounding rect.
+
+ QTransform deviceTransform = item->d_ptr->sceneTransform;
+ if (view->isTransformed()) {
+ if (!untransformableItem)
+ deviceTransform *= view->viewportTransform();
+ else
+ deviceTransform = item->deviceTransform(view->viewportTransform());
+ }
+ if (item->d_ptr->hasBoundingRegionGranularity)
+ viewPrivate->updateRegion(deviceTransform.map(QRegion(dirtyRect.toRect())));
+ else
+ viewPrivate->updateRect(deviceTransform.mapRect(dirtyRect).toRect());
+ }
+ }
+ }
+
+ // Process root items / children.
+ if (!item || item->d_ptr->dirtyChildren) {
+ QList<QGraphicsItem *> *children = item ? &item->d_ptr->children : &topLevelItems;
+ const bool allChildrenDirty = item && item->d_ptr->allChildrenDirty;
+ if (!dirtyAncestorContainsChildren) {
+ dirtyAncestorContainsChildren = item && item->d_ptr->fullUpdatePending
+ && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
+ }
+ for (int i = 0; i < children->size(); ++i) {
+ QGraphicsItem *child = children->at(i);
+ if (wasDirtyParentSceneTransform)
+ child->d_ptr->dirtySceneTransform = 1;
+ if (wasDirtyParentViewBoundingRects)
+ child->d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
+
+ if (allChildrenDirty) {
+ child->d_ptr->dirty = 1;
+ child->d_ptr->fullUpdatePending = 1;
+ child->d_ptr->dirtyChildren = 1;
+ child->d_ptr->allChildrenDirty = 1;
+ } else if (!child->d_ptr->dirty && !child->d_ptr->dirtyChildren) {
+ resetDirtyItem(child);
+ continue;
+ }
+
+ if (dirtyAncestorContainsChildren || updateAll) {
+ // No need to process this child's dirty rect, hence reset the dirty state.
+ // However, we have to continue the recursion because it might have a dirty
+ // view bounding rect that needs repaint. We also have to reset the dirty
+ // state of its descendants.
+ child->d_ptr->dirty = 0;
+ child->d_ptr->fullUpdatePending = 0;
+ if (updateAll)
+ child->d_ptr->paintedViewBoundingRectsNeedRepaint = 0;
+ }
+
+ processDirtyItemsRecursive(child, dirtyAncestorContainsChildren);
+ }
+ } else if (wasDirtyParentSceneTransform) {
+ item->d_ptr->invalidateChildrenSceneTransform();
+ }
+
+ if (item)
+ resetDirtyItem(item);
+}
+
/*!
Paints the given \a items using the provided \a painter, after the
background has been drawn, and before the foreground has been
@@ -5010,111 +5466,29 @@ void QGraphicsScene::drawItems(QPainter *painter,
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];
- painter->setWorldTransform(clipper->deviceTransform(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
- painter->setWorldTransform(item->deviceTransform(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());
+ Q_UNUSED(options);
- // Draw the item
- d->drawItemHelper(item, painter, &options[i], widget, d->painterStateProtection);
-
- if (saveState)
- painter->restore();
+ // Determine view, expose and flags.
+ QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
+ QRegion *expose = 0;
+ if (view)
+ expose = &view->d_func()->exposedRegion;
- 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);
+ // Find all toplevels, they are already sorted.
+ QList<QGraphicsItem *> topLevelItems;
+ for (int i = 0; i < numItems; ++i) {
+ QGraphicsItem *item = items[i]->topLevelItem();
+ if (!item->d_ptr->itemDiscovered) {
+ topLevelItems << item;
+ item->d_ptr->itemDiscovered = 1;
+ d->drawSubtreeRecursive(item, painter, viewTransform, expose, widget);
}
}
- for (int i = 0; i < childClippers.size(); ++i)
- painter->restore();
+ // Reset discovery bits.
+ for (int i = 0; i < topLevelItems.size(); ++i)
+ topLevelItems.at(i)->d_ptr->itemDiscovered = 0;
painter->setWorldTransform(viewTransform);
}
@@ -5226,73 +5600,6 @@ bool QGraphicsScene::focusNextPrevChild(bool next)
*/
/*!
- \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(adjustedItemBoundingRect(item));
- if (!rect.isNull()) {
- QRectF adjustedRect(rect);
- _q_adjustRect(&adjustedRect);
- boundingRect &= adjustedRect;
- }
-
- // 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();
- }
-
- if (!item->isVisible())
- return; // Hiding an item won't effect the largestUntransformableItem/sceneRect.
-
- // 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;
- QRectF adjustedItemSceneBoundingRect(item->sceneBoundingRect());
- _q_adjustRect(&adjustedItemSceneBoundingRect);
- d->growingItemsBoundingRect |= adjustedItemSceneBoundingRect;
- if (d->growingItemsBoundingRect != oldGrowingItemsBoundingRect)
- emit sceneRectChanged(d->growingItemsBoundingRect);
- }
-}
-
-/*!
\since 4.4
Returns the scene's style, or the same as QApplication::style() if the
@@ -5304,7 +5611,7 @@ 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();
+ return d->style ? d->style : QApplication::style();
}
/*!
@@ -5381,7 +5688,7 @@ QFont QGraphicsScene::font() const
void QGraphicsScene::setFont(const QFont &font)
{
Q_D(QGraphicsScene);
- QFont naturalFont = qApp->font();
+ QFont naturalFont = QApplication::font();
naturalFont.resolve(0);
QFont resolvedFont = font.resolve(naturalFont);
d->setFont_helper(resolvedFont);
@@ -5418,7 +5725,7 @@ QPalette QGraphicsScene::palette() const
void QGraphicsScene::setPalette(const QPalette &palette)
{
Q_D(QGraphicsScene);
- QPalette naturalPalette = qApp->palette();
+ QPalette naturalPalette = QApplication::palette();
naturalPalette.resolve(0);
QPalette resolvedPalette = palette.resolve(naturalPalette);
d->setPalette_helper(resolvedPalette);
diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h
index 9802f87..c4c9f9c 100644
--- a/src/gui/graphicsview/qgraphicsscene.h
+++ b/src/gui/graphicsview/qgraphicsscene.h
@@ -271,17 +271,14 @@ Q_SIGNALS:
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())
+ Q_PRIVATE_SLOT(d_func(), void _q_processDirtyItems())
friend class QGraphicsItem;
friend class QGraphicsItemPrivate;
friend class QGraphicsView;
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index befbbd8..11e9b64 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -57,6 +57,7 @@
#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+#include "qgraphicsview.h"
#include "qgraphicsscene_bsp_p.h"
#include "qgraphicsitem_p.h"
@@ -68,6 +69,9 @@
#include <QtGui/qfont.h>
#include <QtGui/qpalette.h>
#include <QtGui/qstyle.h>
+#include <QtGui/qstyleoption.h>
+
+static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;
QT_BEGIN_NAMESPACE
@@ -104,28 +108,30 @@ public:
QList<QRectF> updatedRects;
bool updateAll;
bool calledEmitUpdated;
+ bool processDirtyItemsEmitted;
QPainterPath selectionArea;
int selectionChanging;
QSet<QGraphicsItem *> selectedItems;
QList<QGraphicsItem *> unindexedItems;
QList<QGraphicsItem *> indexedItems;
- QList<QGraphicsItem *> dirtyItems;
QList<QGraphicsItem *> pendingUpdateItems;
QList<QGraphicsItem *> unpolishedItems;
+ QList<QGraphicsItem *> topLevelItems;
+ bool needSortTopLevelItems;
QMap<QGraphicsItem *, QPointF> movingItemsInitialPositions;
+ void registerTopLevelItem(QGraphicsItem *item);
+ void unregisterTopLevelItem(QGraphicsItem *item);
void _q_updateLater();
void _q_polishItems();
- void _q_resetDirtyItems();
- void resetDirtyItemsLater();
- bool dirtyItemResetPending;
+ void _q_processDirtyItems();
QList<int> freeItemIndexes;
bool regenerateIndex;
bool purgePending;
- void _q_removeItemLater(QGraphicsItem *item);
+ void removeItemHelper(QGraphicsItem *item);
QSet<QGraphicsItem *> removedItems;
void purgeRemovedItems();
@@ -134,7 +140,7 @@ public:
int indexTimerId;
bool restartIndexTimer;
- void startIndexTimer();
+ void startIndexTimer(int interval = QGRAPHICSSCENE_INDEXTIMER_TIMEOUT);
bool stickyFocus;
bool hasFocus;
@@ -165,6 +171,9 @@ public:
Qt::DropAction lastDropAction;
QList<QGraphicsItem *> cachedItemsUnderMouse;
QList<QGraphicsItem *> hoverItems;
+ bool allItemsIgnoreHoverEvents;
+ bool allItemsUseDefaultCursor;
+ void enableMouseTrackingOnViews();
QMap<Qt::MouseButton, QPointF> mouseGrabberButtonDownPos;
QMap<Qt::MouseButton, QPointF> mouseGrabberButtonDownScenePos;
QMap<Qt::MouseButton, QPoint> mouseGrabberButtonDownScreenPos;
@@ -197,6 +206,10 @@ public:
void mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent);
QGraphicsWidget *windowForItem(const QGraphicsItem *item) const;
+ void recursive_items_helper(QGraphicsItem *item, QRectF rect, QList<QGraphicsItem *> *items,
+ const QTransform &parentTransform, const QTransform &viewTransform,
+ Qt::ItemSelectionMode mode, Qt::SortOrder order, qreal parentOpacity = 1.0) const;
+
QList<QGraphicsItem *> items_helper(const QPointF &pos) const;
QList<QGraphicsItem *> items_helper(const QRectF &rect,
Qt::ItemSelectionMode mode,
@@ -247,6 +260,26 @@ public:
const QStyleOptionGraphicsItem *option, QWidget *widget,
bool painterStateProtection);
+ void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &viewTransform,
+ QRegion *exposedRegion, QWidget *widget,
+ QList<QGraphicsItem *> *topLevelItems = 0, qreal parentOpacity = qreal(1.0));
+ void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false,
+ bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false,
+ bool removingItemFromScene = false);
+ void processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren = false);
+
+ inline void resetDirtyItem(QGraphicsItem *item)
+ {
+ Q_ASSERT(item);
+ item->d_ptr->dirty = 0;
+ item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0;
+ item->d_ptr->geometryChanged = 0;
+ item->d_ptr->dirtyChildren = 0;
+ item->d_ptr->needsRepaint = QRectF();
+ item->d_ptr->allChildrenDirty = 0;
+ item->d_ptr->fullUpdatePending = 0;
+ }
+
QStyle *style;
QFont font;
void setFont_helper(const QFont &font);
@@ -257,9 +290,7 @@ public:
void resolvePalette();
void updatePalette(const QPalette &palette);
- mutable QVector<QTransform> sceneTransformCache;
- mutable QBitArray validTransforms;
- mutable QVector<int> freeSceneTransformSlots;
+ QStyleOptionGraphicsItem styleOptionTmp;
};
QT_END_NAMESPACE
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index 96e9a96..a3e2ebe 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -39,8 +39,6 @@
**
****************************************************************************/
-//#define QGRAPHICSVIEW_DEBUG
-
static const int QGRAPHICSVIEW_REGION_RECT_THRESHOLD = 50;
static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < 2^9
@@ -200,16 +198,7 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime <
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 DontClipPainter This value is obsolete and has no effect.
\value DontSavePainterState When rendering, QGraphicsView protects the
painter state (see QPainter::save()) when rendering the background or
@@ -228,6 +217,8 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime <
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.
+
+ \omitvalue IndirectPainting
*/
/*!
@@ -338,8 +329,6 @@ QGraphicsViewPrivate::QGraphicsViewPrivate()
#endif
lastDragDropEvent(0),
fullUpdatePending(true),
- dirtyRectCount(0),
- updatingLater(false),
updateSceneSlotReimplementedChecked(false)
{
styleOptions.reserve(QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS);
@@ -400,7 +389,7 @@ void QGraphicsViewPrivate::recalculateContentSize()
int left = q_round_bound(viewRect.left());
int right = q_round_bound(viewRect.right() - width);
if (left >= right) {
- q->horizontalScrollBar()->setRange(0, 0);
+ hbar->setRange(0, 0);
switch (alignment & Qt::AlignHorizontal_Mask) {
case Qt::AlignLeft:
@@ -415,9 +404,9 @@ void QGraphicsViewPrivate::recalculateContentSize()
break;
}
} else {
- q->horizontalScrollBar()->setRange(left, right);
- q->horizontalScrollBar()->setPageStep(width);
- q->horizontalScrollBar()->setSingleStep(width / 20);
+ hbar->setRange(left, right);
+ hbar->setPageStep(width);
+ hbar->setSingleStep(width / 20);
leftIndent = 0;
}
@@ -426,7 +415,7 @@ void QGraphicsViewPrivate::recalculateContentSize()
int top = q_round_bound(viewRect.top());
int bottom = q_round_bound(viewRect.bottom() - height);
if (top >= bottom) {
- q->verticalScrollBar()->setRange(0, 0);
+ vbar->setRange(0, 0);
switch (alignment & Qt::AlignVertical_Mask) {
case Qt::AlignTop:
@@ -441,9 +430,9 @@ void QGraphicsViewPrivate::recalculateContentSize()
break;
}
} else {
- q->verticalScrollBar()->setRange(top, bottom);
- q->verticalScrollBar()->setPageStep(height);
- q->verticalScrollBar()->setSingleStep(height / 20);
+ vbar->setRange(top, bottom);
+ vbar->setPageStep(height);
+ vbar->setSingleStep(height / 20);
topIndent = 0;
}
@@ -455,7 +444,7 @@ void QGraphicsViewPrivate::recalculateContentSize()
// scroll instead.
if (oldLeftIndent != leftIndent || oldTopIndent != topIndent) {
dirtyScroll = true;
- q->viewport()->update();
+ updateAll();
} 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
@@ -481,7 +470,7 @@ void QGraphicsViewPrivate::centerView(QGraphicsView::ViewportAnchor anchor)
if (q->underMouse()) {
// Last scene pos: lastMouseMoveScenePoint
// Current mouse pos:
- QPointF transformationDiff = q->mapToScene(q->viewport()->rect().center())
+ QPointF transformationDiff = q->mapToScene(viewport->rect().center())
- q->mapToScene(q->mapFromGlobal(QCursor::pos()));
q->centerOn(lastMouseMoveScenePoint + transformationDiff);;
} else {
@@ -503,7 +492,7 @@ void QGraphicsViewPrivate::centerView(QGraphicsView::ViewportAnchor anchor)
void QGraphicsViewPrivate::updateLastCenterPoint()
{
Q_Q(QGraphicsView);
- lastCenterPoint = q->mapToScene(q->viewport()->rect().center());
+ lastCenterPoint = q->mapToScene(viewport->rect().center());
}
/*!
@@ -541,15 +530,15 @@ void QGraphicsViewPrivate::updateScroll()
scrollX = qint64(-leftIndent);
if (q->isRightToLeft()) {
if (!leftIndent) {
- scrollX += q->horizontalScrollBar()->minimum();
- scrollX += q->horizontalScrollBar()->maximum();
- scrollX -= q->horizontalScrollBar()->value();
+ scrollX += hbar->minimum();
+ scrollX += hbar->maximum();
+ scrollX -= hbar->value();
}
} else {
- scrollX += q->horizontalScrollBar()->value();
+ scrollX += hbar->value();
}
- scrollY = qint64(q->verticalScrollBar()->value() - topIndent);
+ scrollY = qint64(vbar->value() - topIndent);
dirtyScroll = false;
}
@@ -589,7 +578,7 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event)
return;
QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
- mouseEvent.setWidget(q->viewport());
+ mouseEvent.setWidget(viewport);
mouseEvent.setButtonDownScenePos(mousePressButton, mousePressScenePoint);
mouseEvent.setButtonDownScreenPos(mousePressButton, mousePressScreenPoint);
mouseEvent.setScenePos(q->mapToScene(event->pos()));
@@ -614,6 +603,16 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event)
}
#ifndef QT_NO_CURSOR
+ // If all the items ignore hover events, we don't look-up any items
+ // in QGraphicsScenePrivate::dispatchHoverEvent, hence the
+ // cachedItemsUnderMouse list will be empty. We therefore do the look-up
+ // for cursor items here if not all items use the default cursor.
+ if (scene->d_func()->allItemsIgnoreHoverEvents && !scene->d_func()->allItemsUseDefaultCursor
+ && scene->d_func()->cachedItemsUnderMouse.isEmpty()) {
+ scene->d_func()->cachedItemsUnderMouse = scene->d_func()->itemsAtPosition(mouseEvent.screenPos(),
+ mouseEvent.scenePos(),
+ mouseEvent.widget());
+ }
// Find the topmost item under the mouse with a cursor.
foreach (QGraphicsItem *item, scene->d_func()->cachedItemsUnderMouse) {
if (item->hasCursor()) {
@@ -626,7 +625,7 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event)
if (hasStoredOriginalCursor) {
// Restore the original viewport cursor.
hasStoredOriginalCursor = false;
- q->viewport()->setCursor(originalCursor);
+ viewport->setCursor(originalCursor);
}
#endif
}
@@ -658,8 +657,6 @@ QRegion QGraphicsViewPrivate::rubberBandRegion(const QWidget *widget, const QRec
#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();
@@ -685,9 +682,9 @@ void QGraphicsViewPrivate::_q_unsetViewportCursor()
// Restore the original viewport cursor.
hasStoredOriginalCursor = false;
if (dragMode == QGraphicsView::ScrollHandDrag)
- q->viewport()->setCursor(Qt::OpenHandCursor);
+ viewport->setCursor(Qt::OpenHandCursor);
else
- q->viewport()->setCursor(originalCursor);
+ viewport->setCursor(originalCursor);
}
#endif
@@ -726,7 +723,7 @@ void QGraphicsViewPrivate::populateSceneDragDropEvent(QGraphicsSceneDragDropEven
dest->setProposedAction(source->proposedAction());
dest->setDropAction(source->dropAction());
dest->setMimeData(source->mimeData());
- dest->setWidget(q->viewport());
+ dest->setWidget(viewport);
dest->setSource(source->source());
#else
Q_UNUSED(dest)
@@ -749,12 +746,13 @@ QRect QGraphicsViewPrivate::mapToViewRect(const QGraphicsItem *item, const QRect
}
// Translate-only
+ // COMBINE
QPointF offset;
const QGraphicsItem *parentItem = item;
const QGraphicsItemPrivate *itemd;
do {
itemd = parentItem->d_ptr.data();
- if (itemd->hasTransform)
+ if (itemd->transformData)
break;
offset += itemd->pos;
} while ((parentItem = itemd->parent));
@@ -786,7 +784,7 @@ QRegion QGraphicsViewPrivate::mapToViewRegion(const QGraphicsItem *item, const Q
const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
// Accurate bounding region
- QTransform itv = item->sceneTransform() * q->viewportTransform();
+ QTransform itv = item->deviceTransform(q->viewportTransform());
return item->boundingRegion(itv) & itv.mapRect(rect).toAlignedRect();
}
@@ -803,219 +801,90 @@ static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item)
return boundingRect;
}
-/*!
- \internal
-*/
-void QGraphicsViewPrivate::itemUpdated(QGraphicsItem *item, const QRectF &rect)
+void QGraphicsViewPrivate::processPendingUpdates()
{
- if (fullUpdatePending || viewportUpdateMode == QGraphicsView::NoViewportUpdate)
- return;
- if (item->d_ptr->dirty)
- updateLater();
-
- QRectF updateRect = rect;
- if ((item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) || item->d_ptr->children.isEmpty()) {
- updateRect &= adjustedItemBoundingRect(item);
- if (updateRect.isEmpty())
- return;
- }
-
- QGraphicsItem *clipItem = item;
- if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) {
- // Minimize unnecessary redraw.
- QGraphicsItem *parent = item;
- while ((parent = parent->d_ptr->parent)) {
- if (parent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) {
- // Map update rect to the current parent and itersect with its bounding rect.
- updateRect = clipItem->itemTransform(parent).mapRect(updateRect)
- & adjustedItemBoundingRect(parent);
- if (updateRect.isEmpty())
- return;
- clipItem = parent;
- }
-
- if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren))
- break;
- }
- }
-
- // Map update rect from clipItem coordinates to view coordinates.
- Q_ASSERT(clipItem);
- if (!item->d_ptr->hasBoundingRegionGranularity)
- this->updateRect(mapToViewRect(clipItem, updateRect) & viewport->rect());
- else
- updateRegion(mapToViewRegion(clipItem, updateRect) & viewport->rect());
-}
-
-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);
- if (item->d_ptr->discardUpdateRequest(/*ignoreClipping=*/false,
- /*ignoreVisibleBit=*/false,
- /*ignoreDirtyBit=*/true)) {
- continue;
- }
- QTransform x = item->sceneTransform() * viewTransform;
- updateRect(x.mapRect(item->boundingRect()).toAlignedRect() & vr);
+ if (fullUpdatePending) { // We have already called viewport->update()
+ dirtyBoundingRect = QRect();
+ dirtyRegion = QRegion();
+ return;
}
- dirtyRectCount += dirtyRects.size();
-
- bool noUpdate = !fullUpdatePending && viewportUpdateMode == QGraphicsView::FullViewportUpdate;
- if ((dirtyRectCount > 0 || !dirtyBoundingRect.isEmpty()) && !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);
- }
+ if (viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate) {
+ if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
+ viewport->update(dirtyBoundingRect.adjusted(-1, -1, 1, 1));
+ else
+ viewport->update(dirtyBoundingRect.adjusted(-2, -2, 2, 2));
+ } else {
+ viewport->update(dirtyRegion); // Already adjusted in updateRect/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;
+ dirtyRegion = QRegion();
}
void QGraphicsViewPrivate::updateRegion(const QRegion &r)
{
- if (r.isEmpty())
+ if (r.isEmpty() || fullUpdatePending)
return;
- Q_Q(QGraphicsView);
-
// Rect intersects viewport - update everything?
switch (viewportUpdateMode) {
case QGraphicsView::FullViewportUpdate:
fullUpdatePending = true;
- q->viewport()->update();
+ viewport->update();
break;
case QGraphicsView::BoundingRectViewportUpdate:
dirtyBoundingRect |= r.boundingRect();
- if (dirtyBoundingRect == q->viewport()->rect()) {
+ if (dirtyBoundingRect.contains(viewport->rect())) {
fullUpdatePending = true;
- q->viewport()->update();
- } else {
- updateLater();
+ viewport->update();
}
break;
- case QGraphicsView::SmartViewportUpdate:
- dirtyBoundingRect |= r.boundingRect();
- if ((dirtyRectCount + r.numRects()) < QGRAPHICSVIEW_REGION_RECT_THRESHOLD)
- dirtyRegions << r;
- dirtyRectCount += r.numRects();
- updateLater();
- break;
+ case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE
case QGraphicsView::MinimalViewportUpdate:
- dirtyRegions << r;
- dirtyRectCount += r.numRects();
- updateLater();
+ {
+ const QVector<QRect> &rects = r.rects();
+ for (int i = 0; i < rects.size(); ++i) {
+ if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
+ dirtyRegion += rects.at(i).adjusted(-1, -1, 1, 1);
+ else
+ dirtyRegion += rects.at(i).adjusted(-2, -2, 2, 2);
+ }
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)
{
- if (r.isEmpty())
+ if (r.isEmpty() || fullUpdatePending)
return;
- Q_Q(QGraphicsView);
-
// Rect intersects viewport - update everything?
switch (viewportUpdateMode) {
case QGraphicsView::FullViewportUpdate:
fullUpdatePending = true;
- q->viewport()->update();
+ viewport->update();
break;
case QGraphicsView::BoundingRectViewportUpdate:
dirtyBoundingRect |= r;
- if (dirtyBoundingRect == q->viewport()->rect()) {
+ if (dirtyBoundingRect.contains(viewport->rect())) {
fullUpdatePending = true;
- q->viewport()->update();
- } else {
- updateLater();
+ viewport->update();
}
break;
- case QGraphicsView::SmartViewportUpdate:
- dirtyBoundingRect |= r;
- if ((dirtyRectCount + dirtyRects.size()) < QGRAPHICSVIEW_REGION_RECT_THRESHOLD)
- dirtyRects << r;
- updateLater();
- break;
+ case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE
case QGraphicsView::MinimalViewportUpdate:
- dirtyRects << r;
- updateLater();
+ if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
+ dirtyRegion += r.adjusted(-1, -1, 1, 1);
+ else
+ dirtyRegion += r.adjusted(-2, -2, 2, 2);
break;
case QGraphicsView::NoViewportUpdate:
// Unreachable
@@ -1061,7 +930,7 @@ QList<QGraphicsItem *> QGraphicsViewPrivate::findItems(const QRegion &exposedReg
// Step 1) If all items are contained within the expose region, then
// return a list of all visible items.
- const QRectF exposedRegionSceneBounds = q->mapToScene(exposedRegion.boundingRect().adjusted(-1, -1, 2, 2))
+ const QRectF exposedRegionSceneBounds = q->mapToScene(exposedRegion.boundingRect().adjusted(-1, -1, 1, 1))
.boundingRect();
if (exposedRegionSceneBounds.contains(scene->d_func()->growingItemsBoundingRect)) {
Q_ASSERT(allItems);
@@ -1117,69 +986,6 @@ QList<QGraphicsItem *> QGraphicsViewPrivate::findItems(const QRegion &exposedReg
return itemsInArea(exposedPath, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder);
}
-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
- itemToViewportTransform = item->deviceTransform(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.
*/
@@ -1289,7 +1095,7 @@ void QGraphicsView::setRenderHints(QPainter::RenderHints hints)
if (hints == d->renderHints)
return;
d->renderHints = hints;
- viewport()->update();
+ d->updateAll();
}
/*!
@@ -1307,7 +1113,7 @@ void QGraphicsView::setRenderHint(QPainter::RenderHint hint, bool enabled)
else
d->renderHints &= ~hint;
if (oldHints != d->renderHints)
- viewport()->update();
+ d->updateAll();
}
/*!
@@ -1594,7 +1400,7 @@ void QGraphicsView::resetCachedContent()
if (d->cacheMode & CacheBackground) {
// Background caching is enabled.
d->mustResizeBackgroundPixmap = true;
- viewport()->update();
+ d->updateAll();
} else if (d->mustResizeBackgroundPixmap) {
// Background caching is disabled.
// Cleanup, free some resources.
@@ -1683,7 +1489,7 @@ void QGraphicsView::setScene(QGraphicsScene *scene)
return;
// Always update the viewport when the scene changes.
- viewport()->update();
+ d->updateAll();
// Remove the previously assigned scene.
if (d->scene) {
@@ -1704,6 +1510,12 @@ void QGraphicsView::setScene(QGraphicsScene *scene)
d->recalculateContentSize();
d->lastCenterPoint = sceneRect().center();
d->keepLastCenterPoint = true;
+ // We are only interested in mouse tracking if items accept
+ // hover events or use non-default cursors.
+ if (!d->scene->d_func()->allItemsIgnoreHoverEvents
+ || !d->scene->d_func()->allItemsUseDefaultCursor) {
+ d->viewport->setMouseTracking(true);
+ }
} else {
d->recalculateContentSize();
}
@@ -2145,40 +1957,10 @@ void QGraphicsView::render(QPainter *painter, const QRectF &target, const QRect
.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 = item->deviceTransform(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);
- }
+ for (int i = 0; i < numItems; ++i)
+ itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterMatrix, targetRect.toRect());
painter->save();
@@ -2304,7 +2086,7 @@ QList<QGraphicsItem *> QGraphicsView::items(const QPoint &pos) const
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));
+ return d->scene->items(mapToScene(pos.x(), pos.y(), 1, 1));
}
QPainterPath path;
@@ -2466,10 +2248,11 @@ QPolygonF QGraphicsView::mapToScene(const QRect &rect) const
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();
+ QRect r = rect.adjusted(0, 0, 1, 1);
+ QPointF tl = scrollOffset + r.topLeft();
+ QPointF tr = scrollOffset + r.topRight();
+ QPointF br = scrollOffset + r.bottomRight();
+ QPointF bl = scrollOffset + r.bottomLeft();
QPolygonF poly;
poly.resize(4);
@@ -2662,7 +2445,7 @@ void QGraphicsView::setBackgroundBrush(const QBrush &brush)
{
Q_D(QGraphicsView);
d->backgroundBrush = brush;
- viewport()->update();
+ d->updateAll();
if (d->cacheMode & CacheBackground) {
// Invalidate the background pixmap
@@ -2692,7 +2475,7 @@ void QGraphicsView::setForegroundBrush(const QBrush &brush)
{
Q_D(QGraphicsView);
d->foregroundBrush = brush;
- viewport()->update();
+ d->updateAll();
}
/*!
@@ -2713,9 +2496,11 @@ void QGraphicsView::updateScene(const QList<QRectF> &rects)
// 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();
+ const QVector<QRect> &dirtyRects = d->dirtyRegion.rects();
+ for (int i = 0; i < dirtyRects.size(); ++i)
+ dirtyViewportRects += dirtyRects.at(i);
+ d->dirtyRegion = QRegion();
+ d->dirtyBoundingRect = QRect();
bool fullUpdate = !d->accelerateScrolling || d->viewportUpdateMode == QGraphicsView::FullViewportUpdate;
bool boundingRectUpdate = (d->viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate)
@@ -2799,9 +2584,7 @@ void QGraphicsView::setupViewport(QWidget *widget)
const bool isGLWidget = widget->inherits("QGLWidget");
- d->accelerateScrolling = !(isGLWidget
- || widget->testAttribute(Qt::WA_MSWindowsUseDirect3D)
- || qApp->testAttribute(Qt::AA_MSWindowsUseDirect3DByDefault));
+ d->accelerateScrolling = !(isGLWidget);
widget->setFocusPolicy(Qt::StrongFocus);
@@ -2810,7 +2593,12 @@ void QGraphicsView::setupViewport(QWidget *widget)
widget->setAutoFillBackground(true);
}
- widget->setMouseTracking(true);
+ // We are only interested in mouse tracking if items
+ // accept hover events or use non-default cursors.
+ if (d->scene && (!d->scene->d_func()->allItemsIgnoreHoverEvents
+ || !d->scene->d_func()->allItemsUseDefaultCursor)) {
+ widget->setMouseTracking(true);
+ }
widget->setAcceptDrops(acceptDrops());
}
@@ -2909,6 +2697,7 @@ bool QGraphicsView::viewportEvent(QEvent *event)
case QEvent::Paint:
// Reset full update
d->fullUpdatePending = false;
+ d->dirtyScrollOffset = QPoint();
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
@@ -3285,7 +3074,7 @@ void QGraphicsView::mouseMoveEvent(QMouseEvent *event)
if (d->viewportUpdateMode != FullViewportUpdate)
viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect));
else
- viewport()->update();
+ d->updateAll();
}
// Stop rubber banding if the user has let go of all buttons (even
@@ -3307,7 +3096,7 @@ void QGraphicsView::mouseMoveEvent(QMouseEvent *event)
if (d->viewportUpdateMode != FullViewportUpdate)
viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect));
else
- viewport()->update();
+ d->updateAll();
}
// Set the new selection area
QPainterPath selectionArea;
@@ -3350,7 +3139,7 @@ void QGraphicsView::mouseReleaseEvent(QMouseEvent *event)
if (d->viewportUpdateMode != FullViewportUpdate)
viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect));
else
- viewport()->update();
+ d->updateAll();
}
d->rubberBanding = false;
d->rubberBandRect = QRect();
@@ -3452,16 +3241,15 @@ void QGraphicsView::paintEvent(QPaintEvent *event)
d->scene->d_func()->painterStateProtection = !(d->optimizationFlags & DontSavePainterState);
// Determine the exposed region
- QRegion exposedRegion = event->region();
+ d->exposedRegion = event->region();
if (!d->accelerateScrolling)
- exposedRegion = viewport()->rect();
+ d->exposedRegion = viewport()->rect();
else if (d->viewportUpdateMode == BoundingRectViewportUpdate)
- exposedRegion = event->rect();
- QRectF exposedSceneRect = mapToScene(exposedRegion.boundingRect().adjusted(0, 0, 1, 1)).boundingRect();
+ d->exposedRegion = event->rect();
+ QRectF exposedSceneRect = mapToScene(d->exposedRegion.boundingRect()).boundingRect();
// Set up the painter
QPainter painter(viewport());
- QTransform original = painter.worldTransform();
#ifndef QT_NO_RUBBERBAND
if (d->rubberBanding && !d->rubberBandRect.isEmpty())
painter.save();
@@ -3472,22 +3260,9 @@ void QGraphicsView::paintEvent(QPaintEvent *event)
// 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, &allItems);
-
-#ifdef QGRAPHICSVIEW_DEBUG
- int exposedTime = stopWatch.elapsed();
-#endif
+ painter.setWorldTransform(viewTransform);
+ // Draw background
if ((d->cacheMode & CacheBackground)
#ifdef Q_WS_X11
&& X11->use_xrender
@@ -3511,15 +3286,15 @@ void QGraphicsView::paintEvent(QPaintEvent *event)
QPainter backgroundPainter(&d->backgroundPixmap);
backgroundPainter.setClipRegion(d->backgroundPixmapExposed, Qt::ReplaceClip);
backgroundPainter.setTransform(viewportTransform());
+ backgroundPainter.setCompositionMode(QPainter::CompositionMode_Source);
drawBackground(&backgroundPainter, exposedSceneRect);
d->backgroundPixmapExposed = QRegion();
}
// Blit the background from the background pixmap
- QTransform oldMatrix = painter.worldTransform();
- painter.setWorldTransform(original);
+ painter.setWorldTransform(QTransform());
painter.drawPixmap(QPoint(), d->backgroundPixmap);
- painter.setWorldTransform(oldMatrix);
+ painter.setWorldTransform(viewTransform);
} else {
if (!(d->optimizationFlags & DontSavePainterState))
painter.save();
@@ -3528,34 +3303,31 @@ void QGraphicsView::paintEvent(QPaintEvent *event)
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
+ if (!(d->optimizationFlags & IndirectPainting)) {
+ d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, &d->exposedRegion,
+ viewport(), 0);
+ } else {
+ // Find all exposed items
+ bool allItems = false;
+ QList<QGraphicsItem *> itemList = d->findItems(d->exposedRegion, &allItems);
+
+ if (!itemList.isEmpty()) {
+ // Generate the style options.
+ const int numItems = itemList.size();
+ QGraphicsItem **itemArray = &itemList[0]; // Relies on QList internals, but is perfectly valid.
+ QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems);
+ for (int i = 0; i < numItems; ++i)
+ itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], viewTransform, d->exposedRegion, allItems);
+ // Draw the items.
+ drawItems(&painter, numItems, itemArray, styleOptionArray);
+ d->freeStyleOptionsArray(styleOptionArray);
+ }
+ }
// 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.isEmpty()) {
@@ -3577,17 +3349,6 @@ void QGraphicsView::paintEvent(QPaintEvent *event)
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;
}
@@ -3634,10 +3395,6 @@ void QGraphicsView::scrollContentsBy(int dx, int dy)
if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate) {
if (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);
if (d->accelerateScrolling) {
#ifndef QT_NO_RUBBERBAND
// Update new and old rubberband regions
@@ -3647,12 +3404,15 @@ void QGraphicsView::scrollContentsBy(int dx, int dy)
viewport()->update(rubberBandRegion);
}
#endif
+ d->dirtyScrollOffset.rx() += dx;
+ d->dirtyScrollOffset.ry() += dy;
+ d->dirtyRegion.translate(dx, dy);
viewport()->scroll(dx, dy);
} else {
- viewport()->update();
+ d->updateAll();
}
} else {
- viewport()->update();
+ d->updateAll();
}
}
@@ -3663,31 +3423,14 @@ void QGraphicsView::scrollContentsBy(int dx, int dy)
&& 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);
- }
+ QRegion exposed;
+ if (!d->backgroundPixmap.isNull())
+ d->backgroundPixmap.scroll(dx, dy, d->backgroundPixmap.rect(), &exposed);
+
+ // Invalidate the background pixmap
+ d->backgroundPixmapExposed.translate(dx, dy);
+ d->backgroundPixmapExposed += exposed;
}
// Always replay on scroll.
@@ -3788,8 +3531,10 @@ void QGraphicsView::drawItems(QPainter *painter, int numItems,
const QStyleOptionGraphicsItem options[])
{
Q_D(QGraphicsView);
- if (d->scene)
- d->scene->drawItems(painter, numItems, items, options, viewport());
+ if (d->scene) {
+ QWidget *widget = painter->device() == viewport() ? viewport() : 0;
+ d->scene->drawItems(painter, numItems, items, options, widget);
+ }
}
/*!
@@ -3818,6 +3563,18 @@ QTransform QGraphicsView::viewportTransform() const
}
/*!
+ Returns true if the view is transformed (i.e., a non-identity transform
+ has been assigned, or the scrollbars are adjusted).
+
+ \sa setTransform(), horizontalScrollBar(), verticalScrollBar()
+*/
+bool QGraphicsView::isTransformed() const
+{
+ Q_D(const QGraphicsView);
+ return !d->identityMatrix || d->horizontalScroll() || d->verticalScroll();
+}
+
+/*!
Sets the view's current transformation matrix to \a matrix.
If \a combine is true, then \a matrix is combined with the current matrix;
@@ -3868,7 +3625,7 @@ void QGraphicsView::setTransform(const QTransform &matrix, bool combine )
d->transforming = false;
// Any matrix operation requires a full update.
- viewport()->update();
+ d->updateAll();
}
/*!
diff --git a/src/gui/graphicsview/qgraphicsview.h b/src/gui/graphicsview/qgraphicsview.h
index e77e45c..387fa01 100644
--- a/src/gui/graphicsview/qgraphicsview.h
+++ b/src/gui/graphicsview/qgraphicsview.h
@@ -110,9 +110,10 @@ public:
};
enum OptimizationFlag {
- DontClipPainter = 0x1,
+ DontClipPainter = 0x1, // obsolete
DontSavePainterState = 0x2,
- DontAdjustForAntialiasing = 0x4
+ DontAdjustForAntialiasing = 0x4,
+ IndirectPainting = 0x8
};
Q_DECLARE_FLAGS(OptimizationFlags, OptimizationFlag)
@@ -169,6 +170,7 @@ public:
void resetMatrix();
QTransform transform() const;
QTransform viewportTransform() const;
+ bool isTransformed() const;
void setTransform(const QTransform &matrix, bool combine = false);
void resetTransform();
void rotate(qreal angle);
@@ -273,7 +275,6 @@ private:
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;
diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h
index a76279e..a6f0d04 100644
--- a/src/gui/graphicsview/qgraphicsview_p.h
+++ b/src/gui/graphicsview/qgraphicsview_p.h
@@ -63,7 +63,7 @@
QT_BEGIN_NAMESPACE
-class Q_GUI_EXPORT QGraphicsViewPrivate : public QAbstractScrollAreaPrivate
+class QGraphicsViewPrivate : public QAbstractScrollAreaPrivate
{
Q_DECLARE_PUBLIC(QGraphicsView)
public:
@@ -94,6 +94,7 @@ public:
QPoint mousePressScreenPoint;
QPointF lastMouseMoveScenePoint;
QPoint lastMouseMoveScreenPoint;
+ QPoint dirtyScrollOffset;
Qt::MouseButton mousePressButton;
QTransform matrix;
bool identityMatrix;
@@ -159,28 +160,23 @@ public:
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;
+ QRegion dirtyRegion;
QRect dirtyBoundingRect;
- void updateLater();
- bool updatingLater;
- void _q_updateLaterSlot();
- void updateAll();
+ void processPendingUpdates();
+ inline void updateAll()
+ {
+ viewport->update();
+ fullUpdatePending = true;
+ dirtyBoundingRect = QRect();
+ dirtyRegion = QRegion();
+ }
void updateRect(const QRect &rect);
void updateRegion(const QRegion &region);
bool updateSceneSlotReimplementedChecked;
+ QRegion exposedRegion;
QList<QGraphicsItem *> findItems(const QRegion &exposedRegion, 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
diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp
index aa2b9bf..4e4944c 100644
--- a/src/gui/graphicsview/qgraphicswidget.cpp
+++ b/src/gui/graphicsview/qgraphicswidget.cpp
@@ -170,46 +170,13 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \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)
+ : QGraphicsObject(*new QGraphicsWidgetPrivate, 0, 0), QGraphicsLayoutItem(0, false)
{
Q_D(QGraphicsWidget);
d->init(parent, wFlags);
@@ -221,7 +188,7 @@ QGraphicsWidget::QGraphicsWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags)
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)
+ : QGraphicsObject(dd, 0, scene), QGraphicsLayoutItem(0, false)
{
Q_D(QGraphicsWidget);
d->init(parent, wFlags);
@@ -459,17 +426,19 @@ void QGraphicsWidget::setContentsMargins(qreal left, qreal top, qreal right, qre
{
Q_D(QGraphicsWidget);
- if (left == d->leftMargin
- && top == d->topMargin
- && right == d->rightMargin
- && bottom == d->bottomMargin) {
+ if (!d->margins && left == 0 && top == 0 && right == 0 && bottom == 0)
+ return;
+ d->ensureMargins();
+ if (left == d->margins[d->Left]
+ && top == d->margins[d->Top]
+ && right == d->margins[d->Right]
+ && bottom == d->margins[d->Bottom])
return;
- }
- d->leftMargin = left;
- d->topMargin = top;
- d->rightMargin = right;
- d->bottomMargin = bottom;
+ d->margins[d->Left] = left;
+ d->margins[d->Top] = top;
+ d->margins[d->Right] = right;
+ d->margins[d->Bottom] = bottom;
if (QGraphicsLayout *l = d->layout)
l->invalidate();
@@ -490,14 +459,16 @@ void QGraphicsWidget::setContentsMargins(qreal left, qreal top, qreal right, qre
void QGraphicsWidget::getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
{
Q_D(const QGraphicsWidget);
+ if (left || top || right || bottom)
+ d->ensureMargins();
if (left)
- *left = d->leftMargin;
+ *left = d->margins[d->Left];
if (top)
- *top = d->topMargin;
+ *top = d->margins[d->Top];
if (right)
- *right = d->rightMargin;
+ *right = d->margins[d->Right];
if (bottom)
- *bottom = d->bottomMargin;
+ *bottom = d->margins[d->Bottom];
}
/*!
@@ -513,16 +484,23 @@ void QGraphicsWidget::getContentsMargins(qreal *left, qreal *top, qreal *right,
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->windowFrameMargins && left == 0 && top == 0 && right == 0 && bottom == 0)
+ return;
+ d->ensureWindowFrameMargins();
+ bool unchanged =
+ d->windowFrameMargins[d->Left] == left
+ && d->windowFrameMargins[d->Top] == top
+ && d->windowFrameMargins[d->Right] == right
+ && d->windowFrameMargins[d->Bottom] == bottom;
if (d->setWindowFrameMargins && unchanged)
return;
if (!unchanged)
prepareGeometryChange();
- d->leftWindowFrameMargin = left;
- d->topWindowFrameMargin = top;
- d->rightWindowFrameMargin = right;
- d->bottomWindowFrameMargin = bottom;
+ d->windowFrameMargins[d->Left] = left;
+ d->windowFrameMargins[d->Top] = top;
+ d->windowFrameMargins[d->Right] = right;
+ d->windowFrameMargins[d->Bottom] = bottom;
d->setWindowFrameMargins = true;
}
@@ -536,14 +514,16 @@ void QGraphicsWidget::setWindowFrameMargins(qreal left, qreal top, qreal right,
void QGraphicsWidget::getWindowFrameMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
{
Q_D(const QGraphicsWidget);
+ if (left || top || right || bottom)
+ d->ensureWindowFrameMargins();
if (left)
- *left = d->leftWindowFrameMargin;
+ *left = d->windowFrameMargins[d->Left];
if (top)
- *top = d->topWindowFrameMargin;
+ *top = d->windowFrameMargins[d->Top];
if (right)
- *right = d->rightWindowFrameMargin;
+ *right = d->windowFrameMargins[d->Right];
if (bottom)
- *bottom = d->bottomWindowFrameMargin;
+ *bottom = d->windowFrameMargins[d->Bottom];
}
/*!
@@ -577,8 +557,10 @@ void QGraphicsWidget::unsetWindowFrameMargins()
QRectF QGraphicsWidget::windowFrameGeometry() const
{
Q_D(const QGraphicsWidget);
- return geometry().adjusted(-d->leftWindowFrameMargin, -d->topWindowFrameMargin,
- d->rightWindowFrameMargin, d->bottomWindowFrameMargin);
+ return d->windowFrameMargins
+ ? geometry().adjusted(-d->windowFrameMargins[d->Left], -d->windowFrameMargins[d->Top],
+ d->windowFrameMargins[d->Right], d->windowFrameMargins[d->Bottom])
+ : geometry();
}
/*!
@@ -589,8 +571,10 @@ QRectF QGraphicsWidget::windowFrameGeometry() const
QRectF QGraphicsWidget::windowFrameRect() const
{
Q_D(const QGraphicsWidget);
- return rect().adjusted(-d->leftWindowFrameMargin, -d->topWindowFrameMargin,
- d->rightWindowFrameMargin, d->bottomWindowFrameMargin);
+ return d->windowFrameMargins
+ ? rect().adjusted(-d->windowFrameMargins[d->Left], -d->windowFrameMargins[d->Top],
+ d->windowFrameMargins[d->Right], d->windowFrameMargins[d->Bottom])
+ : rect();
}
/*!
@@ -699,7 +683,10 @@ QSizeF QGraphicsWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) c
QSizeF sh;
if (d->layout) {
sh = d->layout->effectiveSizeHint(which, constraint);
- sh += QSizeF(d->leftMargin + d->rightMargin, d->topMargin + d->bottomMargin);
+ if (d->margins) {
+ sh += QSizeF(d->margins[d->Left] + d->margins[d->Right],
+ d->margins[d->Top] + d->margins[d->Bottom]);
+ }
} else {
switch (which) {
case Qt::MinimumSize:
@@ -989,6 +976,9 @@ void QGraphicsWidget::updateGeometry()
ItemParentChange both to deliver \l ParentChange events, and for managing
the focus chain.
+ QGraphicsWidget enables the ItemSendsGeometryChanges flag by default in
+ order to track position changes.
+
\sa propertyChange()
*/
QVariant QGraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &value)
@@ -1039,10 +1029,6 @@ QVariant QGraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &
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);
@@ -1131,7 +1117,8 @@ bool QGraphicsWidget::windowFrameEvent(QEvent *event)
d->windowFrameMousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
break;
case QEvent::GraphicsSceneMouseMove:
- if (d->grabbedSection != Qt::NoSection) {
+ d->ensureWindowData();
+ if (d->windowData->grabbedSection != Qt::NoSection) {
d->windowFrameMouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
event->accept();
}
@@ -1186,7 +1173,8 @@ Qt::WindowFrameSection QGraphicsWidget::windowFrameSectionAt(const QPointF &pos)
const qreal cornerMargin = 20;
//### Not sure of this one, it should be the same value for all edges.
- const qreal windowFrameWidth = d->leftWindowFrameMargin;
+ const qreal windowFrameWidth = d->windowFrameMargins
+ ? d->windowFrameMargins[d->Left] : 0;
Qt::WindowFrameSection s = Qt::NoSection;
if (x <= left + cornerMargin) {
@@ -1212,7 +1200,8 @@ Qt::WindowFrameSection QGraphicsWidget::windowFrameSectionAt(const QPointF &pos)
}
if (s == Qt::NoSection) {
QRectF r1 = r;
- r1.setHeight(d->topWindowFrameMargin);
+ r1.setHeight(d->windowFrameMargins
+ ? d->windowFrameMargins[d->Top] : 0);
if (r1.contains(pos))
s = Qt::TitleBarArea;
}
@@ -1320,7 +1309,8 @@ bool QGraphicsWidget::event(QEvent *event)
case QEvent::GraphicsSceneMouseMove:
case QEvent::GraphicsSceneMouseRelease:
case QEvent::GraphicsSceneMouseDoubleClick:
- if (d->hasDecoration() && d->grabbedSection != Qt::NoSection)
+ d->ensureWindowData();
+ if (d->hasDecoration() && d->windowData->grabbedSection != Qt::NoSection)
return windowFrameEvent(event);
break;
case QEvent::GraphicsSceneHoverEnter:
@@ -1623,6 +1613,7 @@ void QGraphicsWidget::setWindowFlags(Qt::WindowFlags wFlags)
return;
bool wasPopup = (d->windowFlags & Qt::WindowType_Mask) == Qt::Popup;
+ d->adjustWindowFlags(&wFlags);
d->windowFlags = wFlags;
if (!d->setWindowFrameMargins)
unsetWindowFrameMargins();
@@ -1635,6 +1626,11 @@ void QGraphicsWidget::setWindowFlags(Qt::WindowFlags wFlags)
else
d->scene->d_func()->addPopup(this);
}
+
+ if (d->scene && d->scene->d_func()->allItemsIgnoreHoverEvents && d->hasDecoration()) {
+ d->scene->d_func()->allItemsIgnoreHoverEvents = false;
+ d->scene->d_func()->enableMouseTrackingOnViews();
+ }
}
/*!
@@ -1662,17 +1658,19 @@ bool QGraphicsWidget::isActiveWindow() const
This property is only used for windows.
- By default, if no title has been set, this property contains an empty string.
+ 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;
+ d->ensureWindowData();
+ d->windowData->windowTitle = title;
}
QString QGraphicsWidget::windowTitle() const
{
Q_D(const QGraphicsWidget);
- return d->windowTitle;
+ return d->windowData ? d->windowData->windowTitle : QString();
}
/*!
@@ -1724,6 +1722,38 @@ QGraphicsWidget *QGraphicsWidget::focusWidget() const
return d->focusChild;
}
+/*! \property QGraphicsWidget::horizontalShear
+ \brief This property holds the horizontal shear value for the item.
+ */
+
+/*! \property QGraphicsWidget::transformOrigin
+ \brief This property holds the origin point used for transformations
+ in item coordinates.
+ */
+
+/*! \property QGraphicsWidget::verticalShear
+ \brief This property holds the vertical shear value for the item.
+ */
+
+/*! \property QGraphicsWidget::xRotation
+ \brief This property holds the value for rotation around the x axis.
+ */
+
+/*! \property QGraphicsWidget::xScale
+ \brief This property holds the scale factor for the x axis.
+ */
+
+/*! \property QGraphicsWidget::yRotation
+ \brief This property holds the value for rotation around the y axis.
+ */
+
+/*! \property QGraphicsWidget::yScale
+ \brief This property holds the scale factor for the y axis.
+ */
+
+/*! \property QGraphicsWidget::zRotation
+ \brief This property holds the value for rotation around the z axis.
+ */
#ifndef QT_NO_SHORTCUT
/*!
@@ -2110,11 +2140,12 @@ void QGraphicsWidget::paintWindowFrame(QPainter *painter, const QStyleOptionGrap
QStyleOptionTitleBar bar;
bar.QStyleOption::operator=(*option);
d->initStyleOptionTitleBar(&bar); // this clear flags in bar.state
- if (d->buttonMouseOver)
+ d->ensureWindowData();
+ if (d->windowData->buttonMouseOver)
bar.state |= QStyle::State_MouseOver;
else
bar.state &= ~QStyle::State_MouseOver;
- if (d->buttonSunken)
+ if (d->windowData->buttonSunken)
bar.state |= QStyle::State_Sunken;
else
bar.state &= ~QStyle::State_Sunken;
@@ -2269,7 +2300,7 @@ void QGraphicsWidget::dumpFocusChain()
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);
+ 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;
diff --git a/src/gui/graphicsview/qgraphicswidget.h b/src/gui/graphicsview/qgraphicswidget.h
index 49de542..0563dcb 100644
--- a/src/gui/graphicsview/qgraphicswidget.h
+++ b/src/gui/graphicsview/qgraphicswidget.h
@@ -66,7 +66,7 @@ class QStyleOption;
class QGraphicsWidgetPrivate;
-class Q_GUI_EXPORT QGraphicsWidget : public QObject, public QGraphicsItem, public QGraphicsLayoutItem
+class Q_GUI_EXPORT QGraphicsWidget : public QGraphicsObject, public QGraphicsLayoutItem
{
Q_OBJECT
Q_PROPERTY(QPalette palette READ palette WRITE setPalette)
@@ -74,14 +74,17 @@ class Q_GUI_EXPORT QGraphicsWidget : public QObject, public QGraphicsItem, publi
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(QPointF transformOrigin READ transformOrigin WRITE setTransformOrigin)
+ Q_PROPERTY(qreal xRotation READ xRotation WRITE setXRotation)
+ Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation)
+ Q_PROPERTY(qreal zRotation READ zRotation WRITE setZRotation)
+ Q_PROPERTY(qreal xScale READ xScale WRITE setXScale)
+ Q_PROPERTY(qreal yScale READ yScale WRITE setYScale)
+ Q_PROPERTY(qreal horizontalShear READ horizontalShear WRITE setHorizontalShear)
+ Q_PROPERTY(qreal verticalShear READ verticalShear WRITE setVerticalShear)
public:
QGraphicsWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0);
~QGraphicsWidget();
diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp
index 789f8da..557b883 100644
--- a/src/gui/graphicsview/qgraphicswidget_p.cpp
+++ b/src/gui/graphicsview/qgraphicswidget_p.cpp
@@ -66,17 +66,20 @@ void QGraphicsWidgetPrivate::init(QGraphicsItem *parentItem, Qt::WindowFlags wFl
isWidget = 1; // QGraphicsItem::isWidget() returns true.
focusNext = focusPrev = q;
focusPolicy = Qt::NoFocus;
+
+ adjustWindowFlags(&wFlags);
+ windowFlags = wFlags;
+
q->setParentItem(parentItem);
q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::DefaultType));
q->setGraphicsItem(q);
resolveLayoutDirection();
-
- if (!parentItem)
- adjustWindowFlags(&wFlags);
- windowFlags = wFlags;
q->unsetWindowFrameMargins();
+ q->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
+ q->setFlag(QGraphicsItem::ItemSendsGeometryChanges);
}
+
qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const
{
Q_Q(const QGraphicsWidget);
@@ -89,56 +92,57 @@ qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options
return (qreal)height;
}
-void QGraphicsWidgetPrivate::getLayoutItemMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
+/*!
+ \internal
+*/
+QGraphicsWidgetPrivate::~QGraphicsWidgetPrivate()
{
- if (left)
- *left = leftLayoutItemMargin;
- if (top)
- *top = topLayoutItemMargin;
- if (right)
- *right = rightLayoutItemMargin;
- if (bottom)
- *bottom = bottomLayoutItemMargin;
+ // Remove any lazily allocated data
+ delete[] margins;
+ delete[] windowFrameMargins;
+ delete windowData;
}
-void QGraphicsWidgetPrivate::setLayoutItemMargins(qreal left, qreal top, qreal right, qreal bottom)
-{
- if (leftLayoutItemMargin == left
- && topLayoutItemMargin == top
- && rightLayoutItemMargin == right
- && bottomLayoutItemMargin == bottom)
- return;
+/*!
+ \internal
- Q_Q(QGraphicsWidget);
- leftLayoutItemMargin = left;
- topLayoutItemMargin = top;
- rightLayoutItemMargin = right;
- bottomLayoutItemMargin = bottom;
- q->updateGeometry();
+ Ensures that margins is allocated.
+ This function must be called before any dereferencing.
+*/
+void QGraphicsWidgetPrivate::ensureMargins() const
+{
+ if (!margins) {
+ margins = new qreal[4];
+ for (int i = 0; i < 4; ++i)
+ margins[i] = 0;
+ }
}
-void QGraphicsWidgetPrivate::setLayoutItemMargins(QStyle::SubElement element, const QStyleOption *opt)
+/*!
+ \internal
+
+ Ensures that windowFrameMargins is allocated.
+ This function must be called before any dereferencing.
+*/
+void QGraphicsWidgetPrivate::ensureWindowFrameMargins() const
{
- Q_Q(QGraphicsWidget);
- QStyleOption myOpt;
- if (!opt) {
- q->initStyleOption(&myOpt);
- myOpt.rect.setRect(0, 0, 32768, 32768); // arbitrary
- opt = &myOpt;
+ if (!windowFrameMargins) {
+ windowFrameMargins = new qreal[4];
+ for (int i = 0; i < 4; ++i)
+ windowFrameMargins[i] = 0;
}
+}
- 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;
- }
+/*!
+ \internal
+
+ Ensures that windowData is allocated.
+ This function must be called before any dereferencing.
+*/
+void QGraphicsWidgetPrivate::ensureWindowData()
+{
+ if (!windowData)
+ windowData = new WindowData;
}
void QGraphicsWidgetPrivate::setPalette_helper(const QPalette &palette)
@@ -297,11 +301,12 @@ QFont QGraphicsWidgetPrivate::naturalWidgetFont() const
void QGraphicsWidgetPrivate::initStyleOptionTitleBar(QStyleOptionTitleBar *option)
{
Q_Q(QGraphicsWidget);
+ ensureWindowData();
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;
+ option->activeSubControls = windowData->hoveredSubControl;
bool isActive = q->isActiveWindow();
if (isActive) {
option->state |= QStyle::State_Active;
@@ -313,7 +318,8 @@ void QGraphicsWidgetPrivate::initStyleOptionTitleBar(QStyleOptionTitleBar *optio
}
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());
+ option->text = QFontMetrics(windowTitleFont).elidedText(
+ windowData->windowTitle, Qt::ElideRight, textRect.width());
}
void QGraphicsWidgetPrivate::adjustWindowFlags(Qt::WindowFlags *flags)
@@ -341,9 +347,10 @@ void QGraphicsWidgetPrivate::adjustWindowFlags(Qt::WindowFlags *flags)
void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_Q(QGraphicsWidget);
- if (grabbedSection != Qt::NoSection) {
- if (grabbedSection == Qt::TitleBarArea) {
- buttonSunken = false;
+ ensureWindowData();
+ if (windowData->grabbedSection != Qt::NoSection) {
+ if (windowData->grabbedSection == Qt::TitleBarArea) {
+ windowData->buttonSunken = false;
QStyleOptionTitleBar bar;
initStyleOptionTitleBar(&bar);
// make sure that the coordinates (rect and pos) we send to the style are positive.
@@ -351,8 +358,10 @@ void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEve
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;
+ if (windowFrameMargins) {
+ pos.rx() += windowFrameMargins[Left];
+ pos.ry() += windowFrameMargins[Top];
+ }
bar.subControls = QStyle::SC_TitleBarCloseButton;
if (q->style()->subControlRect(QStyle::CC_TitleBar, &bar,
QStyle::SC_TitleBarCloseButton,
@@ -361,7 +370,7 @@ void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEve
}
}
if (!(static_cast<QGraphicsSceneMouseEvent *>(event)->buttons()))
- grabbedSection = Qt::NoSection;
+ windowData->grabbedSection = Qt::NoSection;
event->accept();
}
}
@@ -372,35 +381,16 @@ void QGraphicsWidgetPrivate::windowFrameMousePressEvent(QGraphicsSceneMouseEvent
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;
+ ensureWindowData();
+ windowData->startGeometry = q->geometry();
+ windowData->grabbedSection = q->windowFrameSectionAt(event->pos());
+ ensureWindowData();
+ if (windowData->grabbedSection == Qt::TitleBarArea
+ && windowData->hoveredSubControl == QStyle::SC_TitleBarCloseButton) {
+ windowData->buttonSunken = true;
+ q->update();
}
- event->setAccepted(grabbedSection != Qt::NoSection);
+ event->setAccepted(windowData->grabbedSection != Qt::NoSection);
}
static void _q_boundGeometryToSizeConstraints(const QRectF &startGeometry,
@@ -455,7 +445,8 @@ static void _q_boundGeometryToSizeConstraints(const QRectF &startGeometry,
void QGraphicsWidgetPrivate::windowFrameMouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
Q_Q(QGraphicsWidget);
- if (!(event->buttons() & Qt::LeftButton) || hoveredSubControl != QStyle::SC_TitleBarLabel)
+ ensureWindowData();
+ if (!(event->buttons() & Qt::LeftButton) || windowData->hoveredSubControl != QStyle::SC_TitleBarLabel)
return;
QLineF delta(q->mapFromScene(event->buttonDownScenePos(Qt::LeftButton)), event->pos());
@@ -464,49 +455,56 @@ void QGraphicsWidgetPrivate::windowFrameMouseMoveEvent(QGraphicsSceneMouseEvent
QLineF parentYDelta(q->mapToParent(QPointF(0, delta.p1().y())), q->mapToParent(QPointF(0, delta.p2().y())));
QRectF newGeometry;
- switch (grabbedSection) {
+ switch (windowData->grabbedSection) {
case Qt::LeftSection:
- newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentXDelta.dx(), parentXDelta.dy()),
- startGeometry.size() - QSizeF(delta.dx(), delta.dy()));
+ newGeometry = QRectF(windowData->startGeometry.topLeft()
+ + QPointF(parentXDelta.dx(), parentXDelta.dy()),
+ windowData->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()));
+ newGeometry = QRectF(windowData->startGeometry.topLeft()
+ + QPointF(parentDelta.dx(), parentDelta.dy()),
+ windowData->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()));
+ newGeometry = QRectF(windowData->startGeometry.topLeft()
+ + QPointF(parentYDelta.dx(), parentYDelta.dy()),
+ windowData->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()));
+ newGeometry = QRectF(windowData->startGeometry.topLeft()
+ + QPointF(parentYDelta.dx(), parentYDelta.dy()),
+ windowData->startGeometry.size() - QSizeF(-delta.dx(), delta.dy()));
break;
case Qt::RightSection:
- newGeometry = QRectF(startGeometry.topLeft(),
- startGeometry.size() + QSizeF(delta.dx(), 0));
+ newGeometry = QRectF(windowData->startGeometry.topLeft(),
+ windowData->startGeometry.size() + QSizeF(delta.dx(), 0));
break;
case Qt::BottomRightSection:
- newGeometry = QRectF(startGeometry.topLeft(),
- startGeometry.size() + QSizeF(delta.dx(), delta.dy()));
+ newGeometry = QRectF(windowData->startGeometry.topLeft(),
+ windowData->startGeometry.size() + QSizeF(delta.dx(), delta.dy()));
break;
case Qt::BottomSection:
- newGeometry = QRectF(startGeometry.topLeft(),
- startGeometry.size() + QSizeF(0, delta.dy()));
+ newGeometry = QRectF(windowData->startGeometry.topLeft(),
+ windowData->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()));
+ newGeometry = QRectF(windowData->startGeometry.topLeft()
+ + QPointF(parentXDelta.dx(), parentXDelta.dy()),
+ windowData->startGeometry.size() - QSizeF(delta.dx(), -delta.dy()));
break;
case Qt::TitleBarArea:
- newGeometry = QRectF(startGeometry.topLeft() + QPointF(parentDelta.dx(), parentDelta.dy()),
- startGeometry.size());
+ newGeometry = QRectF(windowData->startGeometry.topLeft()
+ + QPointF(parentDelta.dx(), parentDelta.dy()),
+ windowData->startGeometry.size());
break;
case Qt::NoSection:
break;
}
- if (grabbedSection != Qt::NoSection) {
- _q_boundGeometryToSizeConstraints(startGeometry, &newGeometry, grabbedSection,
+ if (windowData->grabbedSection != Qt::NoSection) {
+ _q_boundGeometryToSizeConstraints(windowData->startGeometry, &newGeometry,
+ windowData->grabbedSection,
q->effectiveSizeHint(Qt::MinimumSize),
q->effectiveSizeHint(Qt::MaximumSize));
q->setGeometry(newGeometry);
@@ -519,21 +517,25 @@ void QGraphicsWidgetPrivate::windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent
if (!hasDecoration())
return;
+ ensureWindowData();
+
if (q->rect().contains(event->pos())) {
- if (buttonMouseOver || hoveredSubControl != QStyle::SC_None)
+ if (windowData->buttonMouseOver || windowData->hoveredSubControl != QStyle::SC_None)
windowFrameHoverLeaveEvent(event);
return;
}
- bool wasMouseOver = buttonMouseOver;
- QRect oldButtonRect = buttonRect;
- buttonRect = QRect();
- buttonMouseOver = false;
+ bool wasMouseOver = windowData->buttonMouseOver;
+ QRect oldButtonRect = windowData->buttonRect;
+ windowData->buttonRect = QRect();
+ windowData->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;
+ if (windowFrameMargins) {
+ pos.rx() += windowFrameMargins[Left];
+ pos.ry() += windowFrameMargins[Top];
+ }
initStyleOptionTitleBar(&bar);
bar.rect = q->windowFrameRect().toRect();
bar.rect.moveTo(0,0);
@@ -559,14 +561,17 @@ void QGraphicsWidgetPrivate::windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent
cursorShape = Qt::SizeVerCursor;
break;
case Qt::TitleBarArea:
- buttonRect = q->style()->subControlRect(QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarCloseButton, 0);
+ windowData->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);
+ windowData->buttonRect |= q->style()->subControlRect(
+ QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMinButton, 0);
+ windowData->buttonRect |= q->style()->subControlRect(
+ QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMaxButton, 0);
#endif
- if (buttonRect.contains(pos.toPoint()))
- buttonMouseOver = true;
+ if (windowData->buttonRect.contains(pos.toPoint()))
+ windowData->buttonMouseOver = true;
event->ignore();
break;
default:
@@ -578,15 +583,15 @@ void QGraphicsWidgetPrivate::windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent
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;
+ windowData->hoveredSubControl = q->style()->hitTestComplexControl(QStyle::CC_TitleBar, &bar, pos.toPoint(), 0);
+ if (windowData->hoveredSubControl != QStyle::SC_TitleBarCloseButton)
+ windowData->hoveredSubControl = QStyle::SC_TitleBarLabel;
- if (buttonMouseOver != wasMouseOver) {
+ if (windowData->buttonMouseOver != wasMouseOver) {
if (!oldButtonRect.isNull())
q->update(QRectF(oldButtonRect).translated(q->windowFrameRect().topLeft()));
- if (!buttonRect.isNull())
- q->update(QRectF(buttonRect).translated(q->windowFrameRect().topLeft()));
+ if (!windowData->buttonRect.isNull())
+ q->update(QRectF(windowData->buttonRect).translated(q->windowFrameRect().topLeft()));
}
}
@@ -600,16 +605,19 @@ void QGraphicsWidgetPrivate::windowFrameHoverLeaveEvent(QGraphicsSceneHoverEvent
q->unsetCursor();
#endif
+ ensureWindowData();
+
bool needsUpdate = false;
- if (hoveredSubControl == QStyle::SC_TitleBarCloseButton || buttonMouseOver)
+ if (windowData->hoveredSubControl == QStyle::SC_TitleBarCloseButton
+ || windowData->buttonMouseOver)
needsUpdate = true;
// update the hover state (of buttons etc...)
- hoveredSubControl = QStyle::SC_None;
- buttonMouseOver = false;
- buttonRect = QRect();
+ windowData->hoveredSubControl = QStyle::SC_None;
+ windowData->buttonMouseOver = false;
+ windowData->buttonRect = QRect();
if (needsUpdate)
- q->update(buttonRect);
+ q->update(windowData->buttonRect);
}
}
diff --git a/src/gui/graphicsview/qgraphicswidget_p.h b/src/gui/graphicsview/qgraphicswidget_p.h
index 53eaa31..f4cdeca 100644
--- a/src/gui/graphicsview/qgraphicswidget_p.h
+++ b/src/gui/graphicsview/qgraphicswidget_p.h
@@ -68,19 +68,12 @@ class QStyleOptionTitleBar;
#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
-class Q_GUI_EXPORT QGraphicsWidgetPrivate : public QGraphicsItemPrivate
+class 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),
+ : margins(0),
layout(0),
inheritedPaletteResolveMask(0),
inheritedFontResolveMask(0),
@@ -92,40 +85,23 @@ public:
focusPrev(0),
focusChild(0),
windowFlags(0),
- hoveredSubControl(QStyle::SC_None),
- grabbedSection(Qt::NoSection),
- buttonMouseOver(false),
- buttonSunken(false),
+ windowData(0),
setWindowFrameMargins(false),
- leftWindowFrameMargin(0),
- topWindowFrameMargin(0),
- rightWindowFrameMargin(0),
- bottomWindowFrameMargin(0)
+ windowFrameMargins(0)
{ }
+ virtual ~QGraphicsWidgetPrivate();
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);
+ enum {Left, Top, Right, Bottom};
+ mutable qreal *margins;
+ void ensureMargins() const;
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);
@@ -208,20 +184,26 @@ public:
// 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;
+ struct WindowData {
+ QString windowTitle;
+ QStyle::SubControl hoveredSubControl;
+ Qt::WindowFrameSection grabbedSection;
+ uint buttonMouseOver : 1;
+ uint buttonSunken : 1;
+ QRectF startGeometry;
+ QRect buttonRect;
+ WindowData()
+ : hoveredSubControl(QStyle::SC_None)
+ , grabbedSection(Qt::NoSection)
+ , buttonMouseOver(false)
+ , buttonSunken(false)
+ {}
+ } *windowData;
+ void ensureWindowData();
bool setWindowFrameMargins;
- qreal leftWindowFrameMargin;
- qreal topWindowFrameMargin;
- qreal rightWindowFrameMargin;
- qreal bottomWindowFrameMargin;
+ mutable qreal *windowFrameMargins;
+ void ensureWindowFrameMargins() const;
#ifndef QT_NO_ACTION
QList<QAction *> actions;
diff --git a/src/gui/graphicsview/qgridlayoutengine.cpp b/src/gui/graphicsview/qgridlayoutengine.cpp
index dc5ca21..88712c2 100644
--- a/src/gui/graphicsview/qgridlayoutengine.cpp
+++ b/src/gui/graphicsview/qgridlayoutengine.cpp
@@ -275,7 +275,7 @@ void QGridLayoutRowData::calculateGeometries(int start, int end, qreal targetSiz
if (hasIgnoreFlag) {
factors[i] = (stretch < 0) ? 1.0 : 0.0;
} else {
- factors[i] = (stretch < 0) ? sizes[i] : 0.0;
+ factors[i] = (stretch < 0) ? sizes[i] : 0.0;
}
} else if (stretch == sumStretches) {
factors[i] = 1.0;
@@ -615,7 +615,7 @@ QRectF QGridLayoutItem::geometryWithin(qreal x, qreal y, qreal width, qreal heig
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:
@@ -717,7 +717,7 @@ void QGridLayoutItem::dump(int indent) const
void QGridLayoutRowInfo::insertOrRemoveRows(int row, int delta)
{
count += delta;
-
+
insertOrRemoveItems(stretches, row, delta);
insertOrRemoveItems(spacings, row, delta);
insertOrRemoveItems(alignments, row, delta);
@@ -1076,7 +1076,7 @@ QSizeF QGridLayoutEngine::sizeHint(const QLayoutStyleInfo &styleInfo, Qt::SizeHi
break;
}
return QSizeF();
-}
+}
QSizePolicy::ControlTypes QGridLayoutEngine::controlTypes(LayoutSide side) const
{
@@ -1131,9 +1131,9 @@ void QGridLayoutEngine::dump(int indent) const
QString message = QLatin1String("[ ");
for (int column = 0; column < internalGridColumnCount(); ++column) {
message += QString::number(q_items.indexOf(itemAt(row, column))).rightJustified(3);
- message += QLatin1String(" ");
+ message += QLatin1Char(' ');
}
- message += QLatin1String("]");
+ message += QLatin1Char(']');
qDebug("%*s %s", indent, "", qPrintable(message));
}
@@ -1150,16 +1150,16 @@ void QGridLayoutEngine::dump(int indent) const
q_rowData.dump(indent + 2);
qDebug("%*s Geometries output", indent, "");
+ QVector<qreal> *cellPos = &q_yy;
for (int pass = 0; pass < 2; ++pass) {
- QVector<qreal> &cellPos = q_yy;
QString message;
- for (i = 0; i < cellPos.count(); ++i) {
+ for (i = 0; i < cellPos->count(); ++i) {
message += QLatin1String((message.isEmpty() ? "[" : ", "));
- message += QString::number(cellPos.at(i));
+ message += QString::number(cellPos->at(i));
}
- message += QLatin1String("]");
+ message += QLatin1Char(']');
qDebug("%*s %s %s", indent, "", (pass == 0 ? "rows:" : "columns:"), qPrintable(message));
- cellPos = q_xx;
+ cellPos = &q_xx;
}
}
#endif
@@ -1538,5 +1538,5 @@ void QGridLayoutEngine::ensureGeometries(const QLayoutStyleInfo &styleInfo,
}
QT_END_NAMESPACE
-
+
#endif //QT_NO_GRAPHICSVIEW