summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview/qgraphicsitem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/graphicsview/qgraphicsitem.cpp')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp320
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