diff options
Diffstat (limited to 'src/gui/graphicsview')
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 505 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 9 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicslayoutitem.cpp | 134 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicslayoutitem_p.h | 8 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsproxywidget.cpp | 9 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 81 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene_p.h | 6 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview.cpp | 74 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicswidget.cpp | 108 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicswidget_p.cpp | 257 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicswidget_p.h | 68 |
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; |