summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/graphicsview')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp505
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h9
-rw-r--r--src/gui/graphicsview/qgraphicslayoutitem.cpp134
-rw-r--r--src/gui/graphicsview/qgraphicslayoutitem_p.h8
-rw-r--r--src/gui/graphicsview/qgraphicsproxywidget.cpp9
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp81
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h6
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp74
-rw-r--r--src/gui/graphicsview/qgraphicswidget.cpp108
-rw-r--r--src/gui/graphicsview/qgraphicswidget_p.cpp257
-rw-r--r--src/gui/graphicsview/qgraphicswidget_p.h68
11 files changed, 763 insertions, 496 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 30c15bc..743c16d 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -522,6 +522,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
@@ -559,29 +564,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.
*/
@@ -781,6 +763,160 @@ QVariant QGraphicsItemPrivate::inputMethodQueryHelper(Qt::InputMethodQuery query
/*!
\internal
+ If \a deleting is true, then this item is being deleted, and \a parent is
+ null. Make sure not to trigger any pure virtual function calls (e.g.,
+ prepareGeometryChange).
+*/
+void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool deleting)
+{
+ 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 (!deleting)
+ 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 && !deleting) {
+ 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)
+ updateHelper(QRectF(), false, 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 (!deleting) {
+ // 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.
+ updateHelper(QRectF(), false, true);
+ }
+ }
+
+ if (scene) {
+ // Invalidate any sort caching; arrival of a new item means we need to
+ // resort.
+ scene->d_func()->invalidateSortCache();
+ }
+
+ // Resolve opacity.
+ updateEffectiveOpacity();
+
+ // Resolve depth.
+ resolveDepth(parent ? parent->d_ptr->depth : -1);
+
+ // Invalidate transform cache.
+ invalidateSceneTransformCache();
+
+ // Deliver post-change notification
+ q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant);
+}
+
+/*!
+ \internal
+
+ Returns the bounding rect of this item's children (excluding itself).
+*/
+void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rect)
+{
+ for (int i = 0; i < children.size(); ++i) {
+ QGraphicsItem *child = children.at(i);
+ QGraphicsItemPrivate *childd = child->d_ptr;
+ bool hasX = childd->hasTransform;
+ bool hasPos = !childd->pos.isNull();
+ if (hasPos || hasX) {
+ QTransform matrix;
+ if (hasX)
+ matrix = child->transform();
+ if (hasPos) {
+ const QPointF &p = childd->pos;
+ matrix *= QTransform::fromTranslate(p.x(), p.y());
+ }
+ matrix *= *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);
+ }
+ }
+}
+
+/*!
+ \internal
+
Empty all cached pixmaps from the pixmap cache.
*/
void QGraphicsItemCache::purge()
@@ -853,24 +989,17 @@ QGraphicsItem::QGraphicsItem(QGraphicsItemPrivate &dd, QGraphicsItem *parent,
*/
QGraphicsItem::~QGraphicsItem()
{
+ if (d_ptr->scene && !d_ptr->parent)
+ d_ptr->scene->d_func()->unregisterTopLevelItem(this);
+
clearFocus();
- d_ptr->removeExtraItemCache();
- QVariant variant;
- foreach (QGraphicsItem *child, d_ptr->children) {
- if (QGraphicsItem *parent = child->parentItem()) {
- qVariantSetValue<QGraphicsItem *>(variant, child);
- parent->itemChange(ItemChildRemovedChange, variant);
- }
- delete child;
- }
- d_ptr->children.clear();
+ d_ptr->removeExtraItemCache();
+ QList<QGraphicsItem *> oldChildren = d_ptr->children;
+ qDeleteAll(oldChildren);
+ Q_ASSERT(d_ptr->children.isEmpty());
- if (QGraphicsItem *parent = parentItem()) {
- qVariantSetValue<QGraphicsItem *>(variant, this);
- parent->itemChange(ItemChildRemovedChange, variant);
- qt_graphicsitem_removeChild(this, &parent->d_func()->children);
- }
+ d_ptr->setParentItemHelper(0, /* deleting = */ true);
if (d_ptr->scene)
d_ptr->scene->d_func()->_q_removeItemLater(this);
@@ -1015,98 +1144,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, /* deleting = */ false);
}
/*!
@@ -1415,7 +1453,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()))) {
@@ -1898,11 +1938,11 @@ void QGraphicsItem::setOpacity(qreal opacity)
newOpacity = qBound<qreal>(0.0, newOpacity, 1.0);
// No change? Done.
- if (qFuzzyCompare(newOpacity, this->opacity()))
+ if (qFuzzyIsNull(newOpacity - this->opacity()))
return;
// Assign local opacity.
- if (qFuzzyCompare(newOpacity, qreal(1.0))) {
+ if (qFuzzyIsNull(newOpacity - 1)) {
// Opaque, unset opacity.
d_ptr->hasOpacity = 0;
d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraOpacity);
@@ -2047,7 +2087,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();
+ }
}
/*!
@@ -2057,7 +2103,7 @@ void QGraphicsItem::setAcceptHoverEvents(bool enabled)
*/
void QGraphicsItem::setAcceptsHoverEvents(bool enabled)
{
- d_ptr->acceptsHover = quint32(enabled);
+ setAcceptHoverEvents(enabled);
}
/*!
@@ -2941,11 +2987,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
@@ -2973,7 +3019,7 @@ void QGraphicsItem::setZValue(qreal z)
qreal newZ = qreal(newZVariant.toDouble());
if (newZ == d_ptr->z)
return;
- d_ptr->z = z;
+ d_ptr->z = newZ;
d_ptr->fullUpdateHelper();
if (d_ptr->scene) {
@@ -3005,13 +3051,8 @@ void QGraphicsItem::setZValue(qreal z)
QRectF QGraphicsItem::childrenBoundingRect() const
{
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;
}
@@ -3717,7 +3758,7 @@ void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly, bool maybeDirtyCl
dirtyChildren = 1;
}
-static inline bool qt_allChildrenCombineOpacity(QGraphicsItem *parent)
+static inline bool allChildrenCombineOpacityHelper(QGraphicsItem *parent)
{
Q_ASSERT(parent);
if (parent->flags() & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)
@@ -3736,11 +3777,11 @@ void QGraphicsItemPrivate::updateEffectiveOpacity()
Q_Q(QGraphicsItem);
if (parent) {
resolveEffectiveOpacity(parent->effectiveOpacity());
- parent->d_ptr->allChildrenCombineOpacity = qt_allChildrenCombineOpacity(parent);
+ parent->d_ptr->allChildrenCombineOpacity = allChildrenCombineOpacityHelper(parent);
} else {
resolveEffectiveOpacity(1.0);
}
- allChildrenCombineOpacity = qt_allChildrenCombineOpacity(q);
+ allChildrenCombineOpacity = allChildrenCombineOpacityHelper(q);
}
/*!
@@ -3767,7 +3808,7 @@ void QGraphicsItemPrivate::resolveEffectiveOpacity(qreal parentEffectiveOpacity)
}
// Set this item's resolved opacity.
- if (qFuzzyCompare(myEffectiveOpacity, qreal(1.0))) {
+ if (qFuzzyIsNull(myEffectiveOpacity - 1)) {
// Opaque, unset effective opacity.
hasEffectiveOpacity = 0;
unsetExtra(ExtraEffectiveOpacity);
@@ -3806,6 +3847,41 @@ void QGraphicsItemPrivate::invalidateSceneTransformCache()
children.at(i)->d_ptr->invalidateSceneTransformCache();
}
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::addChild(QGraphicsItem *child)
+{
+ child->d_ptr->siblingIndex = children.size();
+ children.append(child);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsItemPrivate::removeChild(QGraphicsItem *child)
+{
+ int idx = child->d_ptr->siblingIndex;
+ int size = children.size();
+ for (int i = idx; i < size - 1; ++i) {
+ QGraphicsItem *p = children[i + 1];
+ children[i] = p;
+ p->d_ptr->siblingIndex = i;
+ }
+ children.removeLast();
+}
+
+/*!
+ \internal
+*/
+QGraphicsItemCache *QGraphicsItemPrivate::maybeExtraItemCache() const
+{
+ return (QGraphicsItemCache *)qVariantValue<void *>(extra(ExtraCacheData));
+}
+
+/*!
+ \internal
+*/
QGraphicsItemCache *QGraphicsItemPrivate::extraItemCache() const
{
QGraphicsItemCache *c = (QGraphicsItemCache *)qVariantValue<void *>(extra(ExtraCacheData));
@@ -3817,6 +3893,9 @@ QGraphicsItemCache *QGraphicsItemPrivate::extraItemCache() const
return c;
}
+/*!
+ \internal
+*/
void QGraphicsItemPrivate::removeExtraItemCache()
{
QGraphicsItemCache *c = (QGraphicsItemCache *)qVariantValue<void *>(extra(ExtraCacheData));
@@ -3972,11 +4051,13 @@ 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)
@@ -3991,6 +4072,45 @@ void QGraphicsItem::update(const QRectF &rect)
d_ptr->scene->itemUpdated(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
@@ -4019,11 +4139,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::insert(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_ptr->updateHelper();
+ } 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;
}
@@ -4180,7 +4334,9 @@ 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);
+ if (!d_ptr->hasTransform)
+ return point + d_ptr->pos;
+ return transform().map(point) + d_ptr->pos;
}
/*!
@@ -4245,9 +4401,9 @@ 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;
+ if (!d_ptr->hasTransform)
+ return rect.translated(d_ptr->pos);
+ return transform().map(rect).translated(d_ptr->pos);
}
/*!
@@ -4446,9 +4602,9 @@ 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;
+ if (!d_ptr->hasTransform)
+ return polygon.translated(d_ptr->pos);
+ return transform().map(polygon).translated(d_ptr->pos);
}
/*!
@@ -4490,10 +4646,9 @@ 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);
+ if (!d_ptr->hasTransform)
+ return path.translated(d_ptr->pos);
+ return transform().map(path).translated(d_ptr->pos);
}
/*!
@@ -4708,9 +4863,9 @@ 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);
+ QPainterPath p(path);
+ p.translate(-d_ptr->pos);
+ return d_ptr->hasTransform ? transform().inverted().map(p) : p;
}
/*!
@@ -5749,7 +5904,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());
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 9ce1bbf..2936cf1 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -113,6 +113,7 @@ public:
: z(0),
scene(0),
parent(0),
+ siblingIndex(-1),
index(-1),
depth(0),
acceptedMouseButtons(0x1f),
@@ -173,6 +174,10 @@ public:
void resolveEffectiveOpacity(qreal effectiveParentOpacity);
void resolveDepth(int parentDepth);
void invalidateSceneTransformCache();
+ void addChild(QGraphicsItem *child);
+ void removeChild(QGraphicsItem *child);
+ void setParentItemHelper(QGraphicsItem *parent, bool deleting);
+ void childrenBoundingRectHelper(QTransform *x, QRectF *rect);
virtual void resolveFont(uint inheritedMask)
{
@@ -238,6 +243,7 @@ public:
};
QList<ExtraStruct> extras;
+ QGraphicsItemCache *maybeExtraItemCache() const;
QGraphicsItemCache *extraItemCache() const;
void removeExtraItemCache();
@@ -263,7 +269,7 @@ public:
void updateCachedClipPathFromSetPosHelper(const QPointF &newPos);
inline bool isFullyTransparent() const
- { return hasEffectiveOpacity && qFuzzyCompare(q_func()->effectiveOpacity() + 1, qreal(1.0)); }
+ { return hasEffectiveOpacity && qFuzzyIsNull(q_func()->effectiveOpacity()); }
inline bool childrenCombineOpacity() const
{ return allChildrenCombineOpacity || children.isEmpty(); }
@@ -287,6 +293,7 @@ public:
QGraphicsScene *scene;
QGraphicsItem *parent;
QList<QGraphicsItem *> children;
+ int siblingIndex;
int index;
int depth;
diff --git a/src/gui/graphicsview/qgraphicslayoutitem.cpp b/src/gui/graphicsview/qgraphicslayoutitem.cpp
index eaa97ff..e058292 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.
@@ -381,12 +443,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);
}
/*!
@@ -416,12 +473,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);
}
/*!
@@ -431,12 +483,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);
}
@@ -450,12 +497,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);
}
/*!
@@ -485,12 +527,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);
}
/*!
@@ -500,12 +537,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);
}
/*!
@@ -519,12 +551,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);
}
/*!
@@ -554,12 +581,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);
}
/*!
@@ -569,12 +591,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);
}
/*!
@@ -732,6 +749,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/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp
index e660879..01b7593 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());
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 13f70e5..69e08d1 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -351,6 +351,8 @@ QGraphicsScenePrivate::QGraphicsScenePrivate()
dragDropItem(0),
enterWidget(0),
lastDropAction(Qt::IgnoreAction),
+ allItemsIgnoreHoverEvents(true),
+ allItemsUseDefaultCursor(true),
painterStateProtection(true),
sortCacheEnabled(false),
updatingSortCache(false),
@@ -622,6 +624,30 @@ void QGraphicsScenePrivate::_q_emitUpdated()
/*!
\internal
+*/
+void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item)
+{
+ item->d_ptr->siblingIndex = topLevelItems.size();
+ topLevelItems.append(item);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item)
+{
+ int idx = item->d_ptr->siblingIndex;
+ int size = topLevelItems.size();
+ for (int i = idx; i < size - 1; ++i) {
+ QGraphicsItem *p = topLevelItems[i + 1];
+ topLevelItems[i] = p;
+ p->d_ptr->siblingIndex = i;
+ }
+ topLevelItems.removeLast();
+}
+
+/*!
+ \internal
Updates all items in the pending update list. At this point, the list is
unlikely to contain partially constructed items.
@@ -756,10 +782,6 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item)
freeSceneTransformSlots.append(transformIndex);
}
- // Remove all children recursively.
- foreach (QGraphicsItem *child, item->children())
- _q_removeItemLater(child);
-
// Reset the mouse grabber
if (mouseGrabberItems.contains(item))
ungrabMouse(item, /* item is dying */ true);
@@ -880,11 +902,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 +1065,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.
*/
@@ -1831,7 +1866,7 @@ 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 ? z1 > z2 : d1->siblingIndex > d2->siblingIndex;
}
/*!
@@ -2747,12 +2782,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;
}
/*!
@@ -2856,7 +2892,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);
@@ -2897,6 +2932,10 @@ void QGraphicsScene::addItem(QGraphicsItem *item)
item->d_func()->index = -1;
d->startIndexTimer();
+ // 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;
d->invalidateSortCache();
@@ -2914,6 +2953,17 @@ 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();
+ }
+ if (d->allItemsUseDefaultCursor && item->hasCursor()) {
+ d->allItemsUseDefaultCursor = false;
+ if (d->allItemsIgnoreHoverEvents) // already enabled otherwise
+ d->enableMouseTrackingOnViews();
+ }
+
// Update selection lists
if (item->isSelected())
d->selectedItems << item;
@@ -3249,13 +3299,15 @@ void QGraphicsScene::removeItem(QGraphicsItem *item)
// Set the item's scene ptr to 0.
item->d_func()->scene = 0;
- // Detach the item from its parent.
+ // Remove from parent, or unregister from toplevels.
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);
}
+ } else {
+ d->unregisterTopLevelItem(item);
}
// Remove from our item lists.
@@ -4214,6 +4266,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()) {
@@ -4613,7 +4668,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)
@@ -5255,7 +5310,7 @@ void QGraphicsScene::itemUpdated(QGraphicsItem *item, const QRectF &rect)
// 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)))) {
+ && 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.
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index befbbd8..9ace725 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -113,7 +113,10 @@ public:
QList<QGraphicsItem *> dirtyItems;
QList<QGraphicsItem *> pendingUpdateItems;
QList<QGraphicsItem *> unpolishedItems;
+ QList<QGraphicsItem *> topLevelItems;
QMap<QGraphicsItem *, QPointF> movingItemsInitialPositions;
+ void registerTopLevelItem(QGraphicsItem *item);
+ void unregisterTopLevelItem(QGraphicsItem *item);
void _q_updateLater();
void _q_polishItems();
@@ -165,6 +168,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;
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index 05e4907..2876016 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -614,6 +614,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()) {
@@ -1061,7 +1071,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);
@@ -1692,6 +1702,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();
}
@@ -2297,7 +2313,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;
@@ -2459,10 +2475,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);
@@ -2792,9 +2809,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);
@@ -2803,7 +2818,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());
}
@@ -3450,7 +3470,7 @@ void QGraphicsView::paintEvent(QPaintEvent *event)
exposedRegion = viewport()->rect();
else if (d->viewportUpdateMode == BoundingRectViewportUpdate)
exposedRegion = event->rect();
- QRectF exposedSceneRect = mapToScene(exposedRegion.boundingRect().adjusted(0, 0, 1, 1)).boundingRect();
+ QRectF exposedSceneRect = mapToScene(exposedRegion.boundingRect()).boundingRect();
// Set up the painter
QPainter painter(viewport());
@@ -3504,6 +3524,7 @@ 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();
}
@@ -3656,31 +3677,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.
diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp
index 7f02fb9..702e0b6 100644
--- a/src/gui/graphicsview/qgraphicswidget.cpp
+++ b/src/gui/graphicsview/qgraphicswidget.cpp
@@ -459,17 +459,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 +492,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 +517,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 +547,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 +590,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 +604,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 +716,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:
@@ -1039,10 +1059,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 +1147,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 +1203,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 +1230,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 +1339,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 +1643,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 +1656,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();
+ }
}
/*!
@@ -1667,12 +1693,13 @@ bool QGraphicsWidget::isActiveWindow() const
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();
}
/*!
@@ -2108,11 +2135,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;
diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp
index 789f8da..8ced47a 100644
--- a/src/gui/graphicsview/qgraphicswidget_p.cpp
+++ b/src/gui/graphicsview/qgraphicswidget_p.cpp
@@ -66,15 +66,15 @@ 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();
}
qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const
@@ -89,56 +89,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 +298,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 +315,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 +344,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 +355,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 +367,7 @@ void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEve
}
}
if (!(static_cast<QGraphicsSceneMouseEvent *>(event)->buttons()))
- grabbedSection = Qt::NoSection;
+ windowData->grabbedSection = Qt::NoSection;
event->accept();
}
}
@@ -372,35 +378,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 +442,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 +452,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 +514,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 +558,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 +580,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 +602,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..3509a54 100644
--- a/src/gui/graphicsview/qgraphicswidget_p.h
+++ b/src/gui/graphicsview/qgraphicswidget_p.h
@@ -73,14 +73,7 @@ class Q_GUI_EXPORT QGraphicsWidgetPrivate : public QGraphicsItemPrivate
Q_DECLARE_PUBLIC(QGraphicsWidget)
public:
QGraphicsWidgetPrivate()
- : leftMargin(0),
- topMargin(0),
- rightMargin(0),
- bottomMargin(0),
- leftLayoutItemMargin(0),
- topLayoutItemMargin(0),
- rightLayoutItemMargin(0),
- bottomLayoutItemMargin(0),
+ : 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;