diff options
Diffstat (limited to 'src/gui/graphicsview/qgraphicsitem.cpp')
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 320 |
1 files changed, 148 insertions, 172 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 326f130abd..c9176d1252 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -50,7 +50,7 @@ It provides a light-weight foundation for writing your own custom items. This includes defining the item's geometry, collision detection, its painting implementation and item interaction through its event handlers. - QGraphicsItem is part of \l{The Graphics View Framework} + QGraphicsItem is part of the \l{Graphics View Framework} \image graphicsview-items.png @@ -264,7 +264,7 @@ functionality is completely untouched by Qt itself; it is provided for the user's convenience. - \sa QGraphicsScene, QGraphicsView, {The Graphics View Framework} + \sa QGraphicsScene, QGraphicsView, {Graphics View Framework} */ /*! @@ -1090,6 +1090,10 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, const Q if (newParent == parent) return; + if (isWidget) + static_cast<QGraphicsWidgetPrivate *>(this)->fixFocusChainBeforeReparenting((newParent && + newParent->isWidget()) ? static_cast<QGraphicsWidget *>(newParent) : 0, + scene); if (scene) { // Deliver the change to the index if (scene->d_func()->indexMethod != QGraphicsScene::NoIndex) @@ -1271,14 +1275,14 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec QTransform matrix = childd->transformToParent(); if (x) matrix *= *x; - *rect |= matrix.mapRect(child->boundingRect()); + *rect |= matrix.mapRect(child->d_ptr->effectiveBoundingRect()); if (!childd->children.isEmpty()) childd->childrenBoundingRectHelper(&matrix, rect); } else { if (x) - *rect |= x->mapRect(child->boundingRect()); + *rect |= x->mapRect(child->d_ptr->effectiveBoundingRect()); else - *rect |= child->boundingRect(); + *rect |= child->d_ptr->effectiveBoundingRect(); if (!childd->children.isEmpty()) childd->childrenBoundingRectHelper(x, rect); } @@ -1423,6 +1427,15 @@ QGraphicsItem::~QGraphicsItem() d_ptr->inDestructor = 1; d_ptr->removeExtraItemCache(); +#ifndef QT_NO_GESTURES + if (d_ptr->isObject && !d_ptr->gestureContext.isEmpty()) { + QGraphicsObject *o = static_cast<QGraphicsObject *>(this); + QGestureManager *manager = QGestureManager::instance(); + foreach (Qt::GestureType type, d_ptr->gestureContext.keys()) + manager->cleanupCachedGestures(o, type); + } +#endif + clearFocus(); // Update focus scope item ptr. @@ -1796,9 +1809,6 @@ static void _q_qgraphicsItemSetFlag(QGraphicsItem *item, QGraphicsItem::Graphics */ void QGraphicsItem::setFlags(GraphicsItemFlags flags) { - if (isWindow()) - flags |= ItemIsPanel; - // Notify change and check for adjustment. if (quint32(d_ptr->flags) == quint32(flags)) return; @@ -1812,7 +1822,7 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations | ItemIsSelectable); bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask); if (fullUpdate) - d_ptr->paintedViewBoundingRectsNeedRepaint = 1; + d_ptr->updatePaintedViewBoundingRects(/*children=*/true); // Keep the old flags to compare the diff. GraphicsItemFlags oldFlags = GraphicsItemFlags(d_ptr->flags); @@ -3267,7 +3277,8 @@ void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool clim */ void QGraphicsItem::clearFocus() { - d_ptr->clearFocusHelper(/* giveFocusToParent = */ true); + if (hasFocus()) + d_ptr->clearFocusHelper(/* giveFocusToParent = */ true); } /*! @@ -3648,6 +3659,8 @@ void QGraphicsItem::setPos(const QPointF &pos) // Update and repositition. if (!(d_ptr->flags & (ItemSendsGeometryChanges | ItemSendsScenePositionChanges))) { d_ptr->setPosHelper(pos); + if (d_ptr->isWidget) + static_cast<QGraphicsWidget *>(this)->d_func()->setGeometryFromSetPos(); return; } @@ -5432,6 +5445,24 @@ void QGraphicsItemPrivate::removeExtraItemCache() unsetExtra(ExtraCacheData); } +void QGraphicsItemPrivate::updatePaintedViewBoundingRects(bool updateChildren) +{ + if (!scene) + return; + + for (int i = 0; i < scene->d_func()->views.size(); ++i) { + QGraphicsViewPrivate *viewPrivate = scene->d_func()->views.at(i)->d_func(); + QRect rect = paintedViewBoundingRects.value(viewPrivate->viewport); + rect.translate(viewPrivate->dirtyScrollOffset); + viewPrivate->updateRect(rect); + } + + if (updateChildren) { + for (int i = 0; i < children.size(); ++i) + children.at(i)->d_ptr->updatePaintedViewBoundingRects(true); + } +} + // Traverses all the ancestors up to the top-level and updates the pointer to // always point to the top-most item that has a dirty scene transform. // It then backtracks to the top-most dirty item and start calculating the @@ -5615,6 +5646,14 @@ void QGraphicsItem::update(const QRectF &rect) viewport, which does not benefit from scroll optimizations), this function is equivalent to calling update(\a rect). + \bold{Note:} Scrolling is only supported when QGraphicsItem::ItemCoordinateCache + is enabled; in all other cases calling this function is equivalent to calling + update(\a rect). If you for sure know that the item is opaque and not overlapped + by other items, you can map the \a rect to viewport coordinates and scroll the + viewport. + + \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 19 + \sa boundingRect() */ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect) @@ -5624,152 +5663,71 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect) return; if (!d->scene) return; - if (d->cacheMode != NoCache) { - 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()); - - pix.scroll(dx, dy, irect); - - QPixmapCache::replace(c->key, pix); - - // Translate the existing expose. - foreach (QRectF exposedRect, c->exposed) - c->exposed += exposedRect.translated(dx, dy) & rect; - - // Calculate exposure. - QRegion exposed; - QRect r = rect.toRect(); - exposed += r; - exposed -= r.translated(dx, dy); - foreach (QRect rect, exposed.rects()) - update(rect); - d->scene->d_func()->markDirty(this); - } else { - update(rect); - } - } else { - // ### This is very slow, and can be done much better. If the cache is - // local and matches the below criteria for rotation and scaling, we - // can easily scroll. And if the cache is in device coordinates, we - // can scroll both the viewport and the cache. - update(rect); - } + + // Accelerated scrolling means moving pixels from one location to another + // and only redraw the newly exposed area. The following requirements must + // be fulfilled in order to do that: + // + // 1) Item is opaque. + // 2) Item is not overlapped by other items. + // + // There's (yet) no way to detect whether an item is opaque or not, which means + // we cannot do accelerated scrolling unless the cache is enabled. In case of using + // DeviceCoordinate cache we also have to take the device transform into account in + // order to determine whether we can do accelerated scrolling or not. That's left out + // for simplicity here, but it is definitely something we can consider in the future + // as a performance improvement. + if (d->cacheMode != QGraphicsItem::ItemCoordinateCache + || !qFuzzyIsNull(dx - int(dx)) || !qFuzzyIsNull(dy - int(dy))) { + update(rect); return; } - QRectF scrollRect = !rect.isNull() ? rect : boundingRect(); - int couldntScroll = d->scene->views().size(); - foreach (QGraphicsView *view, d->scene->views()) { - if (view->viewport()->inherits("QGLWidget")) { - // ### Please replace with a widget attribute; any widget that - // doesn't support partial updates / doesn't support scrolling - // should be skipped in this code. Qt::WA_NoPartialUpdates or so. - continue; - } + QGraphicsItemCache *cache = d->extraItemCache(); + if (cache->allExposed || cache->fixedSize.isValid()) { + // Cache is either invalidated or item is scaled (see QGraphicsItem::setCacheMode). + update(rect); + return; + } - static const QLineF up(0, 0, 0, -1); - static const QLineF down(0, 0, 0, 1); - static const QLineF left(0, 0, -1, 0); - static const QLineF right(0, 0, 1, 0); - - QTransform deviceTr = deviceTransform(view->viewportTransform()); - QRect deviceScrollRect = deviceTr.mapRect(scrollRect).toRect(); - QLineF v1 = deviceTr.map(right); - QLineF v2 = deviceTr.map(down); - QLineF u1 = v1.unitVector(); u1.translate(-v1.p1()); - QLineF u2 = v2.unitVector(); u2.translate(-v2.p1()); - bool noScroll = false; - - // Check if the delta resolves to ints in device space. - QPointF deviceDelta = deviceTr.map(QPointF(dx, dy)); - if ((deviceDelta.x() - int(deviceDelta.x())) - || (deviceDelta.y() - int(deviceDelta.y()))) { - noScroll = true; - } else { - // Check if the unit vectors have no fraction in device space. - qreal v1l = v1.length(); - if (v1l - int(v1l)) { - noScroll = true; - } else { - dx *= v1.length(); - } - qreal v2l = v2.length(); - if (v2l - int(v2l)) { - noScroll = true; - } else { - dy *= v2.length(); - } - } + // Find pixmap in cache. + QPixmap cachedPixmap; + if (!QPixmapCache::find(cache->key, &cachedPixmap)) { + update(rect); + return; + } - if (!noScroll) { - if (u1 == right) { - if (u2 == up) { - // flipped - dy = -dy; - } else if (u2 == down) { - // normal - } else { - noScroll = true; - } - } else if (u1 == left) { - if (u2 == up) { - // mirrored & flipped / rotated 180 degrees - dx = -dx; - dy = -dy; - } else if (u2 == down) { - // mirrored - dx = -dx; - } else { - noScroll = true; - } - } else if (u1 == up) { - if (u2 == left) { - // rotated -90 & mirrored - qreal tmp = dy; - dy = -dx; - dx = -tmp; - } else if (u2 == right) { - // rotated -90 - qreal tmp = dy; - dy = -dx; - dx = tmp; - } else { - noScroll = true; - } - } else if (u1 == down) { - if (u2 == left) { - // rotated 90 - qreal tmp = dy; - dy = dx; - dx = -tmp; - } else if (u2 == right) { - // rotated 90 & mirrored - qreal tmp = dy; - dy = dx; - dx = tmp; - } else { - noScroll = true; - } - } - } + QRect scrollRect = (rect.isNull() ? boundingRect() : rect).toAlignedRect(); + if (!scrollRect.intersects(cache->boundingRect)) + return; // Nothing to scroll. - if (!noScroll) { - view->viewport()->scroll(int(dx), int(dy), deviceScrollRect); - --couldntScroll; - } + // Remove from cache to avoid deep copy when modifying. + QPixmapCache::remove(cache->key); + + QRegion exposed; + cachedPixmap.scroll(dx, dy, scrollRect.translated(-cache->boundingRect.topLeft()), &exposed); + + // Reinsert into cache. + cache->key = QPixmapCache::insert(cachedPixmap); + + // Translate the existing expose. + for (int i = 0; i < cache->exposed.size(); ++i) { + QRectF &e = cache->exposed[i]; + if (!rect.isNull() && !e.intersects(rect)) + continue; + e.translate(dx, dy); } - if (couldntScroll) - update(rect); + + // Append newly exposed areas. Note that the exposed region is currently + // in pixmap coordinates, so we have to translate it to item coordinates. + exposed.translate(cache->boundingRect.topLeft()); + const QVector<QRect> exposedRects = exposed.rects(); + for (int i = 0; i < exposedRects.size(); ++i) + cache->exposed += exposedRects.at(i); + + // Trigger update. This will redraw the newly exposed area and make sure + // the pixmap is re-blitted in case there are overlapping items. + d->scene->d_func()->markDirty(this, rect); } /*! @@ -7131,7 +7089,11 @@ void QGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) // calculate their diff by mapping viewport coordinates // directly to parent coordinates. // COMBINE - QTransform viewToParentTransform = (item->d_func()->transformData->computedFullTransform().translate(item->d_ptr->pos.x(), item->d_ptr->pos.y())) + QTransform itemTransform; + if (item->d_ptr->transformData) + itemTransform = item->d_ptr->transformData->computedFullTransform(); + itemTransform.translate(item->d_ptr->pos.x(), item->d_ptr->pos.y()); + QTransform viewToParentTransform = itemTransform * (item->sceneTransform() * view->viewportTransform()).inverted(); currentParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->screenPos()))); buttonDownParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->buttonDownScreenPos(Qt::LeftButton)))); @@ -7612,6 +7574,7 @@ QGraphicsObject::QGraphicsObject(QGraphicsItemPrivate &dd, QGraphicsItem *parent QGraphicsItem::d_ptr->isObject = true; } +#ifndef QT_NO_GESTURES /*! Subscribes the graphics object to the given \a gesture with specific \a flags. @@ -7619,9 +7582,10 @@ QGraphicsObject::QGraphicsObject(QGraphicsItemPrivate &dd, QGraphicsItem *parent */ void QGraphicsObject::grabGesture(Qt::GestureType gesture, Qt::GestureFlags flags) { - QGraphicsItemPrivate * const d = QGraphicsItem::d_func(); - d->gestureContext.insert(gesture, flags); - (void)QGestureManager::instance(); // create a gesture manager + bool contains = QGraphicsItem::d_ptr->gestureContext.contains(gesture); + QGraphicsItem::d_ptr->gestureContext.insert(gesture, flags); + if (!contains && QGraphicsItem::d_ptr->scene) + QGraphicsItem::d_ptr->scene->d_func()->grabGesture(this, gesture); } /*! @@ -7631,13 +7595,18 @@ void QGraphicsObject::grabGesture(Qt::GestureType gesture, Qt::GestureFlags flag */ void QGraphicsObject::ungrabGesture(Qt::GestureType gesture) { - QGraphicsItemPrivate * const d = QGraphicsItem::d_func(); - if (d->gestureContext.remove(gesture)) { - QGestureManager *manager = QGestureManager::instance(); - manager->cleanupCachedGestures(this, gesture); - } + if (QGraphicsItem::d_ptr->gestureContext.remove(gesture) && QGraphicsItem::d_ptr->scene) + QGraphicsItem::d_ptr->scene->d_func()->ungrabGesture(this, gesture); } +#endif // QT_NO_GESTURES + +/*! + Updates the item's micro focus. This is slot for convenience. + \since 4.7 + + \sa QInputContext +*/ void QGraphicsObject::updateMicroFocus() { QGraphicsItem::updateMicroFocus(); @@ -7946,6 +7915,13 @@ void QGraphicsItemPrivate::resetHeight() */ /*! + \property QGraphicsObject::effect + \brief the effect attached to this item + + \sa QGraphicsItem::setGraphicsEffect(), QGraphicsItem::graphicsEffect() +*/ + +/*! \class QAbstractGraphicsShapeItem \brief The QAbstractGraphicsShapeItem class provides a common base for all path items. @@ -7961,7 +7937,7 @@ void QGraphicsItemPrivate::resetHeight() \sa QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsPathItem, QGraphicsPolygonItem, QGraphicsTextItem, QGraphicsLineItem, - QGraphicsPixmapItem, {The Graphics View Framework} + QGraphicsPixmapItem, {Graphics View Framework} */ class QAbstractGraphicsShapeItemPrivate : public QGraphicsItemPrivate @@ -8100,7 +8076,7 @@ QPainterPath QAbstractGraphicsShapeItem::opaqueArea() const setBrush() functions. \sa QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsPolygonItem, - QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {The Graphics + QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics View Framework} */ @@ -8309,7 +8285,7 @@ QVariant QGraphicsPathItem::extension(const QVariant &variant) const those instead. \sa QGraphicsPathItem, QGraphicsEllipseItem, QGraphicsPolygonItem, - QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {The Graphics + QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics View Framework} */ @@ -8553,7 +8529,7 @@ QVariant QGraphicsRectItem::extension(const QVariant &variant) const brush, which you can set by calling setPen() and setBrush(). \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsPolygonItem, - QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {The Graphics + QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics View Framework} */ @@ -8862,7 +8838,7 @@ QVariant QGraphicsEllipseItem::extension(const QVariant &variant) const setPen() and setBrush() functions. \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem, - QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {The Graphics + QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics View Framework} */ @@ -9094,8 +9070,8 @@ QVariant QGraphicsPolygonItem::extension(const QVariant &variant) const function draws the line using the item's associated pen. \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem, - QGraphicsTextItem, QGraphicsPolygonItem, QGraphicsPixmapItem, {The - Graphics View Framework} + QGraphicsTextItem, QGraphicsPolygonItem, QGraphicsPixmapItem, + {Graphics View Framework} */ class QGraphicsLineItemPrivate : public QGraphicsItemPrivate @@ -9364,8 +9340,8 @@ QVariant QGraphicsLineItem::extension(const QVariant &variant) const transformation mode for the item. \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem, - QGraphicsTextItem, QGraphicsPolygonItem, QGraphicsLineItem, {The - Graphics View Framework} + QGraphicsTextItem, QGraphicsPolygonItem, QGraphicsLineItem, + {Graphics View Framework} */ /*! @@ -9735,7 +9711,7 @@ QVariant QGraphicsPixmapItem::extension(const QVariant &variant) const \sa QGraphicsSimpleTextItem, QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsPixmapItem, QGraphicsPolygonItem, - QGraphicsLineItem, {The Graphics View Framework} + QGraphicsLineItem, {Graphics View Framework} */ class QGraphicsTextItemPrivate @@ -10651,9 +10627,9 @@ void QGraphicsSimpleTextItemPrivate::updateBoundingRect() \img graphicsview-simpletextitem.png - \sa QGraphicsTextItem, QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem, - QGraphicsPixmapItem, QGraphicsPolygonItem, QGraphicsLineItem, {The - Graphics View Framework} + \sa QGraphicsTextItem, QGraphicsPathItem, QGraphicsRectItem, + QGraphicsEllipseItem, QGraphicsPixmapItem, QGraphicsPolygonItem, + QGraphicsLineItem, {Graphics View Framework} */ /*! @@ -10914,7 +10890,7 @@ QVariant QGraphicsSimpleTextItem::extension(const QVariant &variant) const item group. As with addToGroup(), the item's scene-relative position and transformation remain intact. - \sa QGraphicsItem, {The Graphics View Framework} + \sa QGraphicsItem, {Graphics View Framework} */ class QGraphicsItemGroupPrivate : public QGraphicsItemPrivate |