Changeset 846 for trunk/src/gui/graphicsview/qgraphicsscene.cpp
- Timestamp:
- May 5, 2011, 5:36:53 AM (14 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:mergeinfo changed
/branches/vendor/nokia/qt/4.7.2 (added) merged: 845 /branches/vendor/nokia/qt/current merged: 844 /branches/vendor/nokia/qt/4.6.3 removed
- Property svn:mergeinfo changed
-
trunk/src/gui/graphicsview/qgraphicsscene.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 51 51 with QGraphicsView for visualizing graphical items, such as lines, 52 52 rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is 53 part of \l{TheGraphics View Framework}.53 part of the \l{Graphics View Framework}. 54 54 55 55 QGraphicsScene also provides functionality that lets you efficiently … … 229 229 #include <QtCore/qtimer.h> 230 230 #include <QtCore/qvarlengtharray.h> 231 #include <QtCore/QMetaMethod> 231 232 #include <QtGui/qapplication.h> 232 233 #include <QtGui/qdesktopwidget.h> … … 278 279 } 279 280 280 int QGraphicsScenePrivate::changedSignalIndex;281 282 281 /*! 283 282 \internal … … 292 291 calledEmitUpdated(false), 293 292 processDirtyItemsEmitted(false), 294 selectionChanging(0),295 293 needSortTopLevelItems(true), 296 294 holesInTopLevelSiblingIndex(false), … … 299 297 stickyFocus(false), 300 298 hasFocus(false), 299 lastMouseGrabberItemHasImplicitMouseGrab(false), 300 allItemsIgnoreHoverEvents(true), 301 allItemsUseDefaultCursor(true), 302 painterStateProtection(true), 303 sortCacheEnabled(false), 304 allItemsIgnoreTouchEvents(true), 305 selectionChanging(0), 306 rectAdjust(2), 301 307 focusItem(0), 302 308 lastFocusItem(0), … … 307 313 childExplicitActivation(0), 308 314 lastMouseGrabberItem(0), 309 lastMouseGrabberItemHasImplicitMouseGrab(false),310 315 dragDropItem(0), 311 316 enterWidget(0), 312 317 lastDropAction(Qt::IgnoreAction), 313 allItemsIgnoreHoverEvents(true), 314 allItemsUseDefaultCursor(true), 315 painterStateProtection(true), 316 sortCacheEnabled(false), 317 style(0), 318 allItemsIgnoreTouchEvents(true) 318 style(0) 319 319 { 320 320 } … … 330 330 331 331 // Keep this index so we can check for connected slots later on. 332 if (!changedSignalIndex) { 333 changedSignalIndex = signalIndex("changed(QList<QRectF>)"); 334 } 332 changedSignalIndex = signalIndex("changed(QList<QRectF>)"); 333 processDirtyItemsIndex = q->metaObject()->indexOfSlot("_q_processDirtyItems()"); 334 polishItemsIndex = q->metaObject()->indexOfSlot("_q_polishItems()"); 335 335 336 qApp->d_func()->scene_list.append(q); 336 337 q->update(); … … 690 691 lastMouseGrabberItem = 0; 691 692 693 // Reset the current drop item 694 if (item == dragDropItem) 695 dragDropItem = 0; 696 692 697 // Reenable selectionChanged() for individual items 693 698 --selectionChanging; … … 695 700 emit q->selectionChanged(); 696 701 702 #ifndef QT_NO_GESTURES 697 703 QHash<QGesture *, QGraphicsObject *>::iterator it; 698 704 for (it = gestureTargets.begin(); it != gestureTargets.end();) { … … 702 708 ++it; 703 709 } 710 711 QGraphicsObject *dummy = static_cast<QGraphicsObject *>(item); 712 cachedTargetItems.removeOne(dummy); 713 cachedItemGestures.remove(dummy); 714 cachedAlreadyDeliveredGestures.remove(dummy); 715 716 foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys()) 717 ungrabGesture(item, gesture); 718 #endif // QT_NO_GESTURES 704 719 } 705 720 … … 816 831 #endif //QT_NO_IM 817 832 } 833 834 // This handles the case that the item has been removed from the 835 // scene in response to the FocusOut event. 836 if (item && item->scene() != q) 837 item = 0; 818 838 819 839 if (item) … … 871 891 } 872 892 if (!itemIsDying && widget->isVisible()) { 873 widget->hide(); 874 widget->QGraphicsItem::d_ptr->explicitlyHidden = 0; 893 widget->QGraphicsItem::d_ptr->setVisibleHelper(false, /* explicit = */ false); 875 894 } 876 895 } … … 1056 1075 Returns all items for the screen position in \a event. 1057 1076 */ 1058 QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint & screenPos,1077 QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &/*screenPos*/, 1059 1078 const QPointF &scenePos, 1060 1079 QWidget *widget) const … … 1065 1084 return q->items(scenePos, Qt::IntersectsItemShape, Qt::DescendingOrder, QTransform()); 1066 1085 1067 const QRectF pointRect( QPointF(widget->mapFromGlobal(screenPos)), QSizeF(1, 1));1086 const QRectF pointRect(scenePos, QSizeF(1, 1)); 1068 1087 if (!view->isTransformed()) 1069 1088 return q->items(pointRect, Qt::IntersectsItemShape, Qt::DescendingOrder); 1070 1089 1071 1090 const QTransform viewTransform = view->viewportTransform(); 1072 if (viewTransform.type() <= QTransform::TxScale) { 1073 return q->items(viewTransform.inverted().mapRect(pointRect), Qt::IntersectsItemShape, 1074 Qt::DescendingOrder, viewTransform); 1075 } 1076 return q->items(viewTransform.inverted().map(pointRect), Qt::IntersectsItemShape, 1091 return q->items(pointRect, Qt::IntersectsItemShape, 1077 1092 Qt::DescendingOrder, viewTransform); 1078 1093 } … … 1169 1184 { 1170 1185 if (QGraphicsObject *object = item->toGraphicsObject()) { 1186 #ifndef QT_NO_GESTURES 1171 1187 QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager; 1172 1188 if (gestureManager) { … … 1174 1190 return true; 1175 1191 } 1192 #endif // QT_NO_GESTURES 1176 1193 } 1177 1194 … … 1312 1329 break; 1313 1330 } 1314 if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {1331 if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable))) { 1315 1332 if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) { 1316 1333 setFocus = true; 1317 if (item != q->focusItem() )1334 if (item != q->focusItem() && item->d_ptr->mouseSetsFocus) 1318 1335 q->setFocusItem(item, Qt::MouseFocusReason); 1319 1336 break; 1320 1337 } 1321 1338 } 1339 if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation) 1340 break; 1322 1341 if (item->isPanel()) 1323 1342 break; … … 1741 1760 1742 1761 // Transform the painter. 1743 painter->setClipRect(targetRect );1762 painter->setClipRect(targetRect, Qt::IntersectClip); 1744 1763 QTransform painterTransform; 1745 1764 painterTransform *= QTransform() … … 2534 2553 } 2535 2554 2536 if (d->unpolishedItems.isEmpty()) 2537 QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection); 2538 d->unpolishedItems.append(item); 2539 item->d_ptr->pendingPolish = true; 2555 // QDeclarativeItems do not rely on initial itemChanged message, as the componentComplete 2556 // function allows far more opportunity for delayed-construction optimization. 2557 if (!item->d_ptr->isDeclarativeItem) { 2558 if (d->unpolishedItems.isEmpty()) { 2559 QMetaMethod method = metaObject()->method(d->polishItemsIndex); 2560 method.invoke(this, Qt::QueuedConnection); 2561 } 2562 d->unpolishedItems.append(item); 2563 item->d_ptr->pendingPolish = true; 2564 } 2540 2565 2541 2566 // Detach this item from its parent if the parent's scene is different … … 2584 2609 d->enableTouchEventsOnViews(); 2585 2610 } 2611 2612 #ifndef QT_NO_GESTURES 2613 foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys()) 2614 d->grabGesture(item, gesture); 2615 #endif 2586 2616 2587 2617 // Update selection lists … … 3212 3242 for (int i = 0; i < d->views.size(); ++i) { 3213 3243 QGraphicsView *view = d->views.at(i); 3214 view->d_func()->updateRegion(QRegion(view->mapFromScene(rect).boundingRect())); 3244 if (view->isTransformed()) 3245 view->d_func()->updateRectF(view->viewportTransform().mapRect(rect)); 3246 else 3247 view->d_func()->updateRectF(rect); 3215 3248 } 3216 3249 } else { … … 3502 3535 d->touchEventHandler(static_cast<QTouchEvent *>(event)); 3503 3536 break; 3537 #ifndef QT_NO_GESTURES 3504 3538 case QEvent::Gesture: 3505 3539 case QEvent::GestureOverride: 3506 3540 d->gestureEventHandler(static_cast<QGestureEvent *>(event)); 3507 3541 break; 3542 #endif // QT_NO_GESTURES 3508 3543 default: 3509 3544 return QObject::event(event); … … 4131 4166 wheelEvent->widget()); 4132 4167 4168 #ifdef Q_WS_MAC 4169 // On Mac, ignore the event if the first item under the mouse is not the last opened 4170 // popup (or one of its descendant) 4171 if (!d->popupWidgets.isEmpty() && !wheelCandidates.isEmpty() && wheelCandidates.first() != d->popupWidgets.back() && !d->popupWidgets.back()->isAncestorOf(wheelCandidates.first())) { 4172 wheelEvent->accept(); 4173 return; 4174 } 4175 #else 4176 // Find the first popup under the mouse (including the popup's descendants) starting from the last. 4177 // Remove all popups after the one found, or all or them if no popup is under the mouse. 4178 // Then continue with the event. 4179 QList<QGraphicsWidget *>::const_iterator iter = d->popupWidgets.end(); 4180 while (--iter >= d->popupWidgets.begin() && !wheelCandidates.isEmpty()) { 4181 if (wheelCandidates.first() == *iter || (*iter)->isAncestorOf(wheelCandidates.first())) 4182 break; 4183 d->removePopup(*iter); 4184 } 4185 #endif 4186 4133 4187 bool hasSetFocus = false; 4134 4188 foreach (QGraphicsItem *item, wheelCandidates) { … … 4254 4308 if (painterStateProtection) 4255 4309 painter->restore(); 4310 } else if (widgetItem->autoFillBackground()) { 4311 painter->fillRect(option->exposedRect, widgetItem->palette().window()); 4256 4312 } 4257 4313 … … 4307 4363 } 4308 4364 4365 // Copied from qpaintengine_vg.cpp 4366 // Returns true for 90, 180, and 270 degree rotations. 4367 static inline bool transformIsSimple(const QTransform& transform) 4368 { 4369 QTransform::TransformationType type = transform.type(); 4370 if (type == QTransform::TxNone || type == QTransform::TxTranslate) { 4371 return true; 4372 } else if (type == QTransform::TxScale) { 4373 // Check for 0 and 180 degree rotations. 4374 // (0 might happen after 4 rotations of 90 degrees). 4375 qreal m11 = transform.m11(); 4376 qreal m12 = transform.m12(); 4377 qreal m21 = transform.m21(); 4378 qreal m22 = transform.m22(); 4379 if (m12 == 0.0f && m21 == 0.0f) { 4380 if (m11 == 1.0f && m22 == 1.0f) 4381 return true; // 0 degrees 4382 else if (m11 == -1.0f && m22 == -1.0f) 4383 return true; // 180 degrees. 4384 if(m11 == 1.0f && m22 == -1.0f) 4385 return true; // 0 degrees inverted y. 4386 else if(m11 == -1.0f && m22 == 1.0f) 4387 return true; // 180 degrees inverted y. 4388 } 4389 } else if (type == QTransform::TxRotate) { 4390 // Check for 90, and 270 degree rotations. 4391 qreal m11 = transform.m11(); 4392 qreal m12 = transform.m12(); 4393 qreal m21 = transform.m21(); 4394 qreal m22 = transform.m22(); 4395 if (m11 == 0.0f && m22 == 0.0f) { 4396 if (m12 == 1.0f && m21 == -1.0f) 4397 return true; // 90 degrees. 4398 else if (m12 == -1.0f && m21 == 1.0f) 4399 return true; // 270 degrees. 4400 else if (m12 == -1.0f && m21 == -1.0f) 4401 return true; // 90 degrees inverted y. 4402 else if (m12 == 1.0f && m21 == 1.0f) 4403 return true; // 270 degrees inverted y. 4404 } 4405 } 4406 return false; 4407 } 4408 4309 4409 /*! 4310 4410 \internal … … 4351 4451 QGraphicsItemCache *itemCache = itemd->extraItemCache(); 4352 4452 if (cacheMode == QGraphicsItem::ItemCoordinateCache) { 4353 if (itemCache->boundingRect != brect.toRect()) {4354 itemCache->boundingRect = brect.toRect();4355 itemCache->allExposed = true;4356 itemCache->exposed.clear();4357 }4358 4453 pixmapKey = itemCache->key; 4359 4454 } else { … … 4368 4463 QSize pixmapSize; 4369 4464 bool fixedCacheSize = false; 4370 QRect F brectAligned= brect.toAlignedRect();4465 QRect br = brect.toAlignedRect(); 4371 4466 if ((fixedCacheSize = itemCache->fixedSize.isValid())) { 4372 4467 pixmapSize = itemCache->fixedSize; 4373 4468 } else { 4374 pixmapSize = br ectAligned.size().toSize();4469 pixmapSize = br.size(); 4375 4470 } 4376 4471 … … 4378 4473 int adjust = itemCache->fixedSize.isValid() ? 0 : 2; 4379 4474 QSize adjustSize(adjust*2, adjust*2); 4380 QRectF br = brectAligned.adjusted(-adjust, -adjust, adjust, adjust);4475 br.adjust(-adjust, -adjust, adjust, adjust); 4381 4476 if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) { 4382 4477 pix = QPixmap(pixmapSize + adjustSize); 4478 itemCache->boundingRect = br; 4479 itemCache->exposed.clear(); 4480 itemCache->allExposed = true; 4481 } else if (itemCache->boundingRect != br) { 4482 itemCache->boundingRect = br; 4383 4483 itemCache->exposed.clear(); 4384 4484 itemCache->allExposed = true; … … 4434 4534 if (newPainterOpacity != oldPainterOpacity) { 4435 4535 painter->setOpacity(newPainterOpacity); 4436 painter->drawPixmap(br , pix, QRectF(QPointF(), pix.size()));4536 painter->drawPixmap(br.topLeft(), pix); 4437 4537 painter->setOpacity(oldPainterOpacity); 4438 4538 } else { 4439 painter->drawPixmap(br , pix, QRectF(QPointF(), pix.size()));4539 painter->drawPixmap(br.topLeft(), pix); 4440 4540 } 4441 4541 return; … … 4475 4575 diff *= painter->worldTransform(); 4476 4576 deviceData->lastTransform = painter->worldTransform(); 4477 if (!invertable 4478 || diff.type() > QTransform::TxTranslate 4479 || painter->worldTransform().type() > QTransform::TxScale) { 4577 bool allowPartialCacheExposure = false; 4578 bool simpleTransform = invertable && diff.type() <= QTransform::TxTranslate 4579 && transformIsSimple(painter->worldTransform()); 4580 if (!simpleTransform) { 4480 4581 pixModified = true; 4481 4582 itemCache->allExposed = true; 4482 4583 itemCache->exposed.clear(); 4584 deviceData->cacheIndent = QPoint(); 4483 4585 pix = QPixmap(); 4484 } 4485 4486 // ### This is a pretty bad way to determine when to start partial 4487 // exposure for DeviceCoordinateCache but it's the least intrusive 4488 // approach for now. 4489 #if 0 4490 // Only if the device rect isn't fully contained. 4491 bool allowPartialCacheExposure = !viewRect.contains(deviceRect); 4492 #else 4493 // Only if deviceRect is 20% taller or wider than the desktop. 4494 bool allowPartialCacheExposure = false; 4495 if (widget) { 4496 QRect desktopRect = QApplication::desktop()->availableGeometry(widget); 4497 allowPartialCacheExposure = (desktopRect.width() * 1.2 < deviceRect.width() 4498 || desktopRect.height() * 1.2 < deviceRect.height()); 4499 } 4500 #endif 4586 } else if (!viewRect.isNull()) { 4587 allowPartialCacheExposure = deviceData->cacheIndent != QPoint(); 4588 } 4589 4590 // Allow partial cache exposure if the device rect isn't fully contained and 4591 // deviceRect is 20% taller or wider than the viewRect. 4592 if (!allowPartialCacheExposure && !viewRect.isNull() && !viewRect.contains(deviceRect)) { 4593 allowPartialCacheExposure = (viewRect.width() * 1.2 < deviceRect.width()) 4594 || (viewRect.height() * 1.2 < deviceRect.height()); 4595 } 4596 4501 4597 QRegion scrollExposure; 4502 if ( deviceData->cacheIndent != QPoint() ||allowPartialCacheExposure) {4598 if (allowPartialCacheExposure) { 4503 4599 // Part of pixmap is drawn. Either device contains viewrect (big 4504 4600 // item covers whole screen) or parts of device are outside the … … 4694 4790 const QRectF brect = adjustedItemEffectiveBoundingRect(item); 4695 4791 ENSURE_TRANSFORM_PTR 4696 QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect() 4697 : transformPtr->mapRect(brect).toRect(); 4792 QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toAlignedRect() 4793 : transformPtr->mapRect(brect).toAlignedRect(); 4794 viewBoundingRect.adjust(-int(rectAdjust), -int(rectAdjust), rectAdjust, rectAdjust); 4698 4795 if (widget) 4699 4796 item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); 4700 viewBoundingRect.adjust(-1, -1, 1, 1);4701 4797 drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) 4702 4798 : !viewBoundingRect.normalized().isEmpty(); … … 4719 4815 ENSURE_TRANSFORM_PTR; 4720 4816 QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp, 4721 painter, opacity, wasDirtyParentSceneTransform, drawItem);4817 painter, opacity, wasDirtyParentSceneTransform, itemHasContents && !itemIsFullyTransparent); 4722 4818 QGraphicsEffectSource *source = item->d_ptr->graphicsEffect->d_func()->source; 4723 4819 QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *> … … 4759 4855 } 4760 4856 4857 static inline void setClip(QPainter *painter, QGraphicsItem *item) 4858 { 4859 painter->save(); 4860 QRectF clipRect; 4861 const QPainterPath clipPath(item->shape()); 4862 if (QPathClipper::pathToRect(clipPath, &clipRect)) 4863 painter->setClipRect(clipRect, Qt::IntersectClip); 4864 else 4865 painter->setClipPath(clipPath, Qt::IntersectClip); 4866 } 4867 4868 static inline void setWorldTransform(QPainter *painter, const QTransform *const transformPtr, 4869 const QTransform *effectTransform) 4870 { 4871 Q_ASSERT(transformPtr); 4872 if (effectTransform) 4873 painter->setWorldTransform(*transformPtr * *effectTransform); 4874 else 4875 painter->setWorldTransform(*transformPtr); 4876 } 4877 4761 4878 void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform, 4762 4879 const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget, … … 4767 4884 const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); 4768 4885 const bool itemHasChildren = !item->d_ptr->children.isEmpty(); 4886 bool setChildClip = itemClipsChildrenToShape; 4887 bool itemHasChildrenStackedBehind = false; 4769 4888 4770 4889 int i = 0; 4771 4890 if (itemHasChildren) { 4891 if (itemClipsChildrenToShape) 4892 setWorldTransform(painter, transformPtr, effectTransform); 4893 4772 4894 item->d_ptr->ensureSortedChildren(); 4773 4774 if (itemClipsChildrenToShape) { 4775 painter->save(); 4776 Q_ASSERT(transformPtr); 4777 if (effectTransform) 4778 painter->setWorldTransform(*transformPtr * *effectTransform); 4779 else 4780 painter->setWorldTransform(*transformPtr); 4781 QRectF clipRect; 4782 const QPainterPath clipPath(item->shape()); 4783 if (QPathClipper::pathToRect(clipPath, &clipRect)) 4784 painter->setClipRect(clipRect, Qt::IntersectClip); 4785 else 4786 painter->setClipPath(clipPath, Qt::IntersectClip); 4787 } 4788 4789 // Draw children behind 4790 for (i = 0; i < item->d_ptr->children.size(); ++i) { 4791 QGraphicsItem *child = item->d_ptr->children.at(i); 4792 if (wasDirtyParentSceneTransform) 4793 child->d_ptr->dirtySceneTransform = 1; 4794 if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) 4795 break; 4796 if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)) 4797 continue; 4798 drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform); 4895 // Items with the 'ItemStacksBehindParent' flag are put in front of the list 4896 // so all we have to do is to check the first item. 4897 itemHasChildrenStackedBehind = (item->d_ptr->children.at(0)->d_ptr->flags 4898 & QGraphicsItem::ItemStacksBehindParent); 4899 4900 if (itemHasChildrenStackedBehind) { 4901 if (itemClipsChildrenToShape) { 4902 setClip(painter, item); 4903 setChildClip = false; 4904 } 4905 4906 // Draw children behind 4907 for (i = 0; i < item->d_ptr->children.size(); ++i) { 4908 QGraphicsItem *child = item->d_ptr->children.at(i); 4909 if (wasDirtyParentSceneTransform) 4910 child->d_ptr->dirtySceneTransform = 1; 4911 if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) 4912 break; 4913 if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)) 4914 continue; 4915 drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform); 4916 } 4799 4917 } 4800 4918 } … … 4809 4927 4810 4928 const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape; 4811 const bool savePainter = itemClipsToShape || painterStateProtection; 4812 if (savePainter) 4929 bool restorePainterClip = false; 4930 4931 if (!itemHasChildren || !itemClipsChildrenToShape) { 4932 // Item does not have children or clip children to shape. 4933 setWorldTransform(painter, transformPtr, effectTransform); 4934 if ((restorePainterClip = itemClipsToShape)) 4935 setClip(painter, item); 4936 } else if (itemHasChildrenStackedBehind){ 4937 // Item clips children to shape and has children stacked behind, which means 4938 // the painter is already clipped to the item's shape. 4939 if (itemClipsToShape) { 4940 // The clip is already correct. Ensure correct world transform. 4941 setWorldTransform(painter, transformPtr, effectTransform); 4942 } else { 4943 // Remove clip (this also ensures correct world transform). 4944 painter->restore(); 4945 setChildClip = true; 4946 } 4947 } else if (itemClipsToShape) { 4948 // Item clips children and itself to shape. It does not have hildren stacked 4949 // behind, which means the clip has not yet been set. We set it now and re-use it 4950 // for the children. 4951 setClip(painter, item); 4952 setChildClip = false; 4953 } 4954 4955 if (painterStateProtection && !restorePainterClip) 4813 4956 painter->save(); 4814 4957 4815 if (!itemHasChildren || !itemClipsChildrenToShape) {4816 if (effectTransform)4817 painter->setWorldTransform(*transformPtr * *effectTransform);4818 else4819 painter->setWorldTransform(*transformPtr);4820 }4821 4822 if (itemClipsToShape) {4823 QRectF clipRect;4824 const QPainterPath clipPath(item->shape());4825 if (QPathClipper::pathToRect(clipPath, &clipRect))4826 painter->setClipRect(clipRect, Qt::IntersectClip);4827 else4828 painter->setClipPath(clipPath, Qt::IntersectClip);4829 }4830 4958 painter->setOpacity(opacity); 4831 4832 4959 if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget) 4833 4960 item->paint(painter, &styleOptionTmp, widget); … … 4835 4962 drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection); 4836 4963 4837 if ( savePainter)4964 if (painterStateProtection || restorePainterClip) 4838 4965 painter->restore(); 4839 4966 } … … 4841 4968 // Draw children in front 4842 4969 if (itemHasChildren) { 4970 if (setChildClip) 4971 setClip(painter, item); 4972 4843 4973 for (; i < item->d_ptr->children.size(); ++i) { 4844 4974 QGraphicsItem *child = item->d_ptr->children.at(i); … … 4849 4979 drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform); 4850 4980 } 4851 } 4852 4853 // Restore child clip4854 if (itemHasChildren && itemClipsChildrenToShape)4855 painter->restore();4981 4982 // Restore child clip 4983 if (itemClipsChildrenToShape) 4984 painter->restore(); 4985 } 4856 4986 } 4857 4987 … … 4863 4993 if (updateAll) 4864 4994 return; 4995 4996 if (removingItemFromScene && !ignoreOpacity && !item->d_ptr->ignoreOpacity) { 4997 // If any of the item's ancestors ignore opacity, it means that the opacity 4998 // was set to 0 (and the update request has not yet been processed). That 4999 // also means that we have to ignore the opacity for the item itself; otherwise 5000 // things like: parent->setOpacity(0); scene->removeItem(child) won't work. 5001 // Note that we only do this when removing items from the scene. In all other 5002 // cases the ignoreOpacity bit propagates properly in processDirtyItems, but 5003 // since the item is removed immediately it won't be processed there. 5004 QGraphicsItem *p = item->d_ptr->parent; 5005 while (p) { 5006 if (p->d_ptr->ignoreOpacity) { 5007 item->d_ptr->ignoreOpacity = true; 5008 break; 5009 } 5010 p = p->d_ptr->parent; 5011 } 5012 } 4865 5013 4866 5014 if (item->d_ptr->discardUpdateRequest(/*ignoreVisibleBit=*/force, … … 4885 5033 4886 5034 if (!processDirtyItemsEmitted) { 4887 QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection); 5035 QMetaMethod method = q_ptr->metaObject()->method(processDirtyItemsIndex); 5036 method.invoke(q_ptr, Qt::QueuedConnection); 5037 // QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection); 4888 5038 processDirtyItemsEmitted = true; 4889 5039 } … … 4909 5059 } 4910 5060 4911 bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents 4912 && !item->d_ptr->graphicsEffect; 5061 bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents; 4913 5062 if (!hasNoContents) { 4914 5063 item->d_ptr->dirty = 1; … … 4917 5066 else if (!item->d_ptr->fullUpdatePending) 4918 5067 item->d_ptr->needsRepaint |= rect; 5068 } else if (item->d_ptr->graphicsEffect) { 5069 invalidateChildren = true; 4919 5070 } 4920 5071 … … 4945 5096 const QTransform xform = itemq->deviceTransform(viewq->viewportTransform()); 4946 5097 if (!item->hasBoundingRegionGranularity) 4947 return view->updateRect (xform.mapRect(rect).toRect());4948 return view->updateRegion( xform.map(QRegion(rect.toRect())));5098 return view->updateRectF(xform.mapRect(rect)); 5099 return view->updateRegion(rect, xform); 4949 5100 } 4950 5101 … … 4952 5103 const qreal dx = item->sceneTransform.dx(); 4953 5104 const qreal dy = item->sceneTransform.dy(); 4954 if (!item->hasBoundingRegionGranularity) { 4955 QRectF r(rect); 4956 r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll()); 4957 return view->updateRect(r.toRect()); 4958 } 4959 QRegion r(rect.toRect()); 4960 r.translate(qRound(dx) - view->horizontalScroll(), qRound(dy) - view->verticalScroll()); 4961 return view->updateRegion(r); 5105 QRectF r(rect); 5106 r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll()); 5107 return view->updateRectF(r); 4962 5108 } 4963 5109 4964 5110 if (!viewq->isTransformed()) { 4965 5111 if (!item->hasBoundingRegionGranularity) 4966 return view->updateRect (item->sceneTransform.mapRect(rect).toRect());4967 return view->updateRegion( item->sceneTransform.map(QRegion(rect.toRect())));5112 return view->updateRectF(item->sceneTransform.mapRect(rect)); 5113 return view->updateRegion(rect, item->sceneTransform); 4968 5114 } 4969 5115 … … 4971 5117 xform *= viewq->viewportTransform(); 4972 5118 if (!item->hasBoundingRegionGranularity) 4973 return view->updateRect (xform.mapRect(rect).toRect());4974 return view->updateRegion( xform.map(QRegion(rect.toRect())));5119 return view->updateRectF(xform.mapRect(rect)); 5120 return view->updateRegion(rect, xform); 4975 5121 } 4976 5122 … … 5052 5198 item->d_ptr->sceneTransform.dy())); 5053 5199 } else { 5054 q->update(item->d_ptr->sceneTransform.mapRect(itemBoundingRect)); 5200 QRectF rect = item->d_ptr->sceneTransform.mapRect(itemBoundingRect); 5201 if (!rect.isEmpty()) 5202 q->update(rect); 5055 5203 } 5056 5204 } else { … … 5108 5256 // Process children. 5109 5257 if (itemHasChildren && item->d_ptr->dirtyChildren) { 5258 const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape; 5259 // Items with no content are threated as 'dummy' items which means they are never drawn and 5260 // 'processed', so the painted view bounding rect is never up-to-date. This means that whenever 5261 // such an item changes geometry, its children have to take care of the update regardless 5262 // of whether the item clips children to shape or not. 5263 const bool bypassUpdateClip = !itemHasContents && wasDirtyParentViewBoundingRects; 5264 if (itemClipsChildrenToShape && !bypassUpdateClip) { 5265 // Make sure child updates are clipped to the item's bounding rect. 5266 for (int i = 0; i < views.size(); ++i) 5267 views.at(i)->d_func()->setUpdateClip(item); 5268 } 5110 5269 if (!dirtyAncestorContainsChildren) { 5111 5270 dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending 5112 && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);5271 && itemClipsChildrenToShape; 5113 5272 } 5114 5273 const bool allChildrenDirty = item->d_ptr->allChildrenDirty; … … 5133 5292 processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity); 5134 5293 } 5294 5295 if (itemClipsChildrenToShape) { 5296 // Reset updateClip. 5297 for (int i = 0; i < views.size(); ++i) 5298 views.at(i)->d_func()->setUpdateClip(0); 5299 } 5135 5300 } else if (wasDirtyParentSceneTransform) { 5136 5301 item->d_ptr->invalidateChildrenSceneTransform(); … … 5181 5346 d->_q_polishItems(); 5182 5347 5183 d->updateAll = false;5348 const qreal opacity = painter->opacity(); 5184 5349 QTransform viewTransform = painter->worldTransform(); 5185 5350 Q_UNUSED(options); … … 5188 5353 QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0; 5189 5354 QRegion *expose = 0; 5190 if (view) 5355 const quint32 oldRectAdjust = d->rectAdjust; 5356 if (view) { 5357 d->updateAll = false; 5191 5358 expose = &view->d_func()->exposedRegion; 5359 if (view->d_func()->optimizationFlags & QGraphicsView::DontAdjustForAntialiasing) 5360 d->rectAdjust = 1; 5361 else 5362 d->rectAdjust = 2; 5363 } 5192 5364 5193 5365 // Find all toplevels, they are already sorted. … … 5202 5374 } 5203 5375 5376 d->rectAdjust = oldRectAdjust; 5204 5377 // Reset discovery bits. 5205 5378 for (int i = 0; i < topLevelItems.size(); ++i) … … 5207 5380 5208 5381 painter->setWorldTransform(viewTransform); 5382 painter->setOpacity(opacity); 5209 5383 } 5210 5384 … … 5578 5752 { 5579 5753 views << view; 5754 #ifndef QT_NO_GESTURES 5755 foreach (Qt::GestureType gesture, grabbedGestures.keys()) 5756 view->viewport()->grabGesture(gesture); 5757 #endif 5580 5758 } 5581 5759 … … 5638 5816 5639 5817 if (sceneTouchEvent->deviceType() == QTouchEvent::TouchScreen) { 5640 // on touch-screens, combine this touch point with the closest one we find if it 5641 // is a a direct descendent or ancestor ( 5818 // on touch-screens, combine this touch point with the closest one we find 5642 5819 int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos()); 5643 5820 QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId); 5644 if (!item 5645 || (closestItem 5646 && (item->isAncestorOf(closestItem) 5647 || closestItem->isAncestorOf(item)))) { 5821 if (!item || (closestItem && cachedItemsUnderMouse.contains(closestItem))) 5648 5822 item = closestItem; 5649 }5650 5823 } 5651 5824 if (!item) … … 5907 6080 } 5908 6081 5909 void QGraphicsScenePrivate::getGestureTargets(const QSet<QGesture *> &gestures, 5910 QWidget *viewport, 5911 QMap<Qt::GestureType, QGesture *> *conflictedGestures, 5912 QList<QList<QGraphicsObject *> > *conflictedItems, 5913 QHash<QGesture *, QGraphicsObject *> *normalGestures) 5914 { 6082 #ifndef QT_NO_GESTURES 6083 void QGraphicsScenePrivate::gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures, 6084 Qt::GestureFlag flag, 6085 QHash<QGraphicsObject *, QSet<QGesture *> > *targets, 6086 QSet<QGraphicsObject *> *itemsSet, 6087 QSet<QGesture *> *normal, 6088 QSet<QGesture *> *conflicts) 6089 { 6090 QSet<QGesture *> normalGestures; // that are not in conflicted state. 5915 6091 foreach (QGesture *gesture, gestures) { 5916 Qt::GestureType gestureType = gesture->gestureType(); 5917 if (gesture->hasHotSpot()) { 5918 QPoint screenPos = gesture->hotSpot().toPoint(); 5919 QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport); 5920 QList<QGraphicsObject *> result; 5921 for (int j = 0; j < items.size(); ++j) { 5922 QGraphicsItem *item = items.at(j); 5923 5924 // Check if the item is blocked by a modal panel and use it as 5925 // a target instead of this item. 5926 (void) item->isBlockedByModalPanel(&item); 5927 5928 if (QGraphicsObject *itemobj = item->toGraphicsObject()) { 5929 QGraphicsItemPrivate *d = item->d_func(); 5930 if (d->gestureContext.contains(gestureType)) { 5931 result.append(itemobj); 6092 if (!gesture->hasHotSpot()) 6093 continue; 6094 const Qt::GestureType gestureType = gesture->gestureType(); 6095 QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), gesture->d_func()->sceneHotSpot, 0); 6096 for (int j = 0; j < items.size(); ++j) { 6097 QGraphicsItem *item = items.at(j); 6098 6099 // Check if the item is blocked by a modal panel and use it as 6100 // a target instead of this item. 6101 (void) item->isBlockedByModalPanel(&item); 6102 6103 if (QGraphicsObject *itemobj = item->toGraphicsObject()) { 6104 QGraphicsItemPrivate *d = item->QGraphicsItem::d_func(); 6105 QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it = 6106 d->gestureContext.find(gestureType); 6107 if (it != d->gestureContext.end() && (!flag || (it.value() & flag))) { 6108 if (normalGestures.contains(gesture)) { 6109 normalGestures.remove(gesture); 6110 if (conflicts) 6111 conflicts->insert(gesture); 6112 } else { 6113 normalGestures.insert(gesture); 5932 6114 } 6115 if (targets) 6116 (*targets)[itemobj].insert(gesture); 6117 if (itemsSet) 6118 (*itemsSet).insert(itemobj); 5933 6119 } 5934 // Don't propagate through panels.5935 if (item->isPanel())5936 break;5937 6120 } 5938 DEBUG() << "QGraphicsScenePrivate::getGestureTargets:" 5939 << gesture << result; 5940 if (result.size() == 1) { 5941 normalGestures->insert(gesture, result.first()); 5942 } else if (!result.isEmpty()) { 5943 conflictedGestures->insert(gestureType, gesture); 5944 conflictedItems->append(result); 5945 } 5946 } 5947 } 6121 // Don't propagate through panels. 6122 if (item->isPanel()) 6123 break; 6124 } 6125 } 6126 if (normal) 6127 *normal = normalGestures; 5948 6128 } 5949 6129 … … 5953 6133 if (!viewport) 5954 6134 return; 6135 QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(viewport->parent()); 6136 if (!graphicsView) 6137 return; 6138 5955 6139 QList<QGesture *> allGestures = event->gestures(); 5956 6140 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 5957 << "Delivering gestures:" << allGestures; 5958 5959 typedef QHash<QGraphicsObject *, QList<QGesture *> > GesturesPerItem; 5960 GesturesPerItem gesturesPerItem; 6141 << "Gestures:" << allGestures; 5961 6142 5962 6143 QSet<QGesture *> startedGestures; 6144 QPoint delta = viewport->mapFromGlobal(QPoint()); 6145 QTransform toScene = QTransform::fromTranslate(delta.x(), delta.y()) 6146 * graphicsView->viewportTransform().inverted(); 5963 6147 foreach (QGesture *gesture, allGestures) { 6148 // cache scene coordinates of the hot spot 6149 if (gesture->hasHotSpot()) { 6150 gesture->d_func()->sceneHotSpot = toScene.map(gesture->hotSpot()); 6151 } else { 6152 gesture->d_func()->sceneHotSpot = QPointF(); 6153 } 6154 5964 6155 QGraphicsObject *target = gestureTargets.value(gesture, 0); 5965 6156 if (!target) { … … 5968 6159 if (gesture->state() == Qt::GestureStarted) 5969 6160 startedGestures.insert(gesture); 5970 } else { 5971 gesturesPerItem[target].append(gesture); 5972 } 5973 } 5974 5975 QMap<Qt::GestureType, QGesture *> conflictedGestures; 5976 QList<QList<QGraphicsObject *> > conflictedItems; 5977 QHash<QGesture *, QGraphicsObject *> normalGestures; 5978 getGestureTargets(startedGestures, viewport, &conflictedGestures, &conflictedItems, 5979 &normalGestures); 5980 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 5981 << "Conflicting gestures:" << conflictedGestures.values() << conflictedItems; 5982 Q_ASSERT((conflictedGestures.isEmpty() && conflictedItems.isEmpty()) || 5983 (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty())); 5984 5985 // gestures that were sent as override events, but no one accepted them 5986 QHash<QGesture *, QGraphicsObject *> ignoredConflictedGestures; 5987 5988 // deliver conflicted gestures as override events first 5989 while (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()) { 5990 // get the topmost item to deliver the override event 5991 Q_ASSERT(!conflictedItems.isEmpty()); 5992 Q_ASSERT(!conflictedItems.first().isEmpty()); 5993 QGraphicsObject *topmost = conflictedItems.first().first(); 5994 for (int i = 1; i < conflictedItems.size(); ++i) { 5995 QGraphicsObject *item = conflictedItems.at(i).first(); 5996 if (qt_closestItemFirst(item, topmost)) { 5997 topmost = item; 6161 } 6162 } 6163 6164 if (!startedGestures.isEmpty()) { 6165 QSet<QGesture *> normalGestures; // that have just one target 6166 QSet<QGesture *> conflictedGestures; // that have multiple possible targets 6167 gestureTargetsAtHotSpots(startedGestures, Qt::GestureFlag(0), &cachedItemGestures, 0, 6168 &normalGestures, &conflictedGestures); 6169 cachedTargetItems = cachedItemGestures.keys(); 6170 qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst); 6171 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6172 << "Normal gestures:" << normalGestures 6173 << "Conflicting gestures:" << conflictedGestures; 6174 6175 // deliver conflicted gestures as override events AND remember 6176 // initial gesture targets 6177 if (!conflictedGestures.isEmpty()) { 6178 for (int i = 0; i < cachedTargetItems.size(); ++i) { 6179 QWeakPointer<QGraphicsObject> item = cachedTargetItems.at(i); 6180 6181 // get gestures to deliver to the current item 6182 QSet<QGesture *> gestures = conflictedGestures & cachedItemGestures.value(item.data()); 6183 if (gestures.isEmpty()) 6184 continue; 6185 6186 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6187 << "delivering override to" 6188 << item.data() << gestures; 6189 // send gesture override 6190 QGestureEvent ev(gestures.toList()); 6191 ev.t = QEvent::GestureOverride; 6192 ev.setWidget(event->widget()); 6193 // mark event and individual gestures as ignored 6194 ev.ignore(); 6195 foreach(QGesture *g, gestures) 6196 ev.setAccepted(g, false); 6197 sendEvent(item.data(), &ev); 6198 // mark all accepted gestures to deliver them as normal gesture events 6199 foreach (QGesture *g, gestures) { 6200 if (ev.isAccepted() || ev.isAccepted(g)) { 6201 conflictedGestures.remove(g); 6202 // mark the item as a gesture target 6203 if (item) { 6204 gestureTargets.insert(g, item.data()); 6205 QHash<QGraphicsObject *, QSet<QGesture *> >::iterator it, e; 6206 it = cachedItemGestures.begin(); 6207 e = cachedItemGestures.end(); 6208 for(; it != e; ++it) 6209 it.value().remove(g); 6210 cachedItemGestures[item.data()].insert(g); 6211 } 6212 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6213 << "override was accepted:" 6214 << g << item.data(); 6215 } 6216 // remember the first item that received the override event 6217 // as it most likely become a target if no one else accepts 6218 // the override event 6219 if (!gestureTargets.contains(g) && item) 6220 gestureTargets.insert(g, item.data()); 6221 6222 } 6223 if (conflictedGestures.isEmpty()) 6224 break; 5998 6225 } 5999 6226 } 6000 // get a list of gestures to send to the item 6001 QList<Qt::GestureType> grabbedGestures = 6002 topmost->QGraphicsItem::d_func()->gestureContext.keys(); 6003 QList<QGesture *> gestures; 6004 for (int i = 0; i < grabbedGestures.size(); ++i) { 6005 if (QGesture *g = conflictedGestures.value(grabbedGestures.at(i), 0)) { 6006 gestures.append(g); 6007 if (!ignoredConflictedGestures.contains(g)) 6008 ignoredConflictedGestures.insert(g, topmost); 6009 } 6010 } 6011 6012 // send gesture override to the topmost item 6013 QGestureEvent ev(gestures); 6014 ev.t = QEvent::GestureOverride; 6015 ev.setWidget(event->widget()); 6016 // mark event and individual gestures as ignored 6017 ev.ignore(); 6018 foreach(QGesture *g, gestures) 6019 ev.setAccepted(g, false); 6020 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6021 << "delivering override to" 6022 << topmost << gestures; 6023 sendEvent(topmost, &ev); 6024 // mark all accepted gestures to deliver them as normal gesture events 6025 foreach (QGesture *g, gestures) { 6026 if (ev.isAccepted() || ev.isAccepted(g)) { 6027 conflictedGestures.remove(g->gestureType()); 6028 gestureTargets.remove(g); 6029 // add the gesture to the list of normal delivered gestures 6030 normalGestures.insert(g, topmost); 6031 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6032 << "override was accepted:" 6033 << g << topmost; 6034 ignoredConflictedGestures.remove(g); 6035 } 6036 } 6037 // remove the item that we've already delivered from the list 6038 for (int i = 0; i < conflictedItems.size(); ) { 6039 QList<QGraphicsObject *> &items = conflictedItems[i]; 6040 if (items.first() == topmost) { 6041 items.removeFirst(); 6042 if (items.isEmpty()) { 6043 conflictedItems.removeAt(i); 6044 continue; 6227 // remember the initial target item for each gesture that was not in 6228 // the conflicted state. 6229 if (!normalGestures.isEmpty()) { 6230 for (int i = 0; i < cachedTargetItems.size() && !normalGestures.isEmpty(); ++i) { 6231 QGraphicsObject *item = cachedTargetItems.at(i); 6232 6233 // get gestures to deliver to the current item 6234 foreach (QGesture *g, cachedItemGestures.value(item)) { 6235 if (!gestureTargets.contains(g)) { 6236 gestureTargets.insert(g, item); 6237 normalGestures.remove(g); 6238 } 6045 6239 } 6046 6240 } 6047 ++i; 6048 } 6049 } 6050 6051 // put back those started gestures that are not in the conflicted state 6052 // and remember their targets 6053 QHash<QGesture *, QGraphicsObject *>::const_iterator it = normalGestures.begin(), 6054 e = normalGestures.end(); 6055 for (; it != e; ++it) { 6056 QGesture *g = it.key(); 6057 QGraphicsObject *receiver = it.value(); 6058 Q_ASSERT(!gestureTargets.contains(g)); 6059 gestureTargets.insert(g, receiver); 6060 gesturesPerItem[receiver].append(g); 6061 } 6062 it = ignoredConflictedGestures.begin(); 6063 e = ignoredConflictedGestures.end(); 6064 for (; it != e; ++it) { 6065 QGesture *g = it.key(); 6066 QGraphicsObject *receiver = it.value(); 6067 Q_ASSERT(!gestureTargets.contains(g)); 6068 gestureTargets.insert(g, receiver); 6069 gesturesPerItem[receiver].append(g); 6070 } 6071 6072 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6073 << "Started gestures:" << normalGestures.keys() 6074 << "All gestures:" << gesturesPerItem.values(); 6075 6076 // deliver all events 6077 QList<QGesture *> alreadyIgnoredGestures; 6078 QHash<QGraphicsObject *, QSet<QGesture *> > itemIgnoredGestures; 6079 QList<QGraphicsObject *> targetItems = gesturesPerItem.keys(); 6080 qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst); 6081 for (int i = 0; i < targetItems.size(); ++i) { 6082 QGraphicsObject *item = targetItems.at(i); 6083 QList<QGesture *> gestures = gesturesPerItem.value(item); 6084 // remove gestures that were already delivered once and were ignored 6085 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6086 << "already ignored gestures for item" 6087 << item << ":" << itemIgnoredGestures.value(item); 6088 6089 if (itemIgnoredGestures.contains(item)) // don't deliver twice to the same item 6090 continue; 6091 6092 QGraphicsItemPrivate *gid = item->QGraphicsItem::d_func(); 6093 foreach(QGesture *g, alreadyIgnoredGestures) { 6094 QMap<Qt::GestureType, Qt::GestureFlags>::iterator contextit = 6095 gid->gestureContext.find(g->gestureType()); 6096 bool deliver = contextit != gid->gestureContext.end() && 6097 (g->state() == Qt::GestureStarted || 6098 (contextit.value() & Qt::ReceivePartialGestures)); 6099 if (deliver) 6100 gestures += g; 6101 } 6241 } 6242 } 6243 6244 6245 // deliver all gesture events 6246 QSet<QGesture *> undeliveredGestures; 6247 QSet<QGesture *> parentPropagatedGestures; 6248 foreach (QGesture *gesture, allGestures) { 6249 if (QGraphicsObject *target = gestureTargets.value(gesture, 0)) { 6250 cachedItemGestures[target].insert(gesture); 6251 cachedTargetItems.append(target); 6252 undeliveredGestures.insert(gesture); 6253 QGraphicsItemPrivate *d = target->QGraphicsItem::d_func(); 6254 const Qt::GestureFlags flags = d->gestureContext.value(gesture->gestureType()); 6255 if (flags & Qt::IgnoredGesturesPropagateToParent) 6256 parentPropagatedGestures.insert(gesture); 6257 } else { 6258 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6259 << "no target for" << gesture << "at" 6260 << gesture->hotSpot() << gesture->d_func()->sceneHotSpot; 6261 } 6262 } 6263 qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst); 6264 for (int i = 0; i < cachedTargetItems.size(); ++i) { 6265 QWeakPointer<QGraphicsObject> receiver = cachedTargetItems.at(i); 6266 QSet<QGesture *> gestures = 6267 undeliveredGestures & cachedItemGestures.value(receiver.data()); 6268 gestures -= cachedAlreadyDeliveredGestures.value(receiver.data()); 6269 6102 6270 if (gestures.isEmpty()) 6103 6271 continue; 6272 6273 cachedAlreadyDeliveredGestures[receiver.data()] += gestures; 6274 const bool isPanel = receiver.data()->isPanel(); 6275 6104 6276 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6105 6277 << "delivering to" 6106 << item<< gestures;6107 QGestureEvent ev(gestures );6278 << receiver.data() << gestures; 6279 QGestureEvent ev(gestures.toList()); 6108 6280 ev.setWidget(event->widget()); 6109 sendEvent( item, &ev);6281 sendEvent(receiver.data(), &ev); 6110 6282 QSet<QGesture *> ignoredGestures; 6111 6283 foreach (QGesture *g, gestures) { 6112 6284 if (!ev.isAccepted() && !ev.isAccepted(g)) { 6113 ignoredGestures.insert(g); 6285 // if the gesture was ignored by its target, we will update the 6286 // targetItems list with a possible target items (items that 6287 // want to receive partial gestures). 6288 // ### wont' work if the target was destroyed in the event 6289 // we will just stop delivering it. 6290 if (receiver && receiver.data() == gestureTargets.value(g, 0)) 6291 ignoredGestures.insert(g); 6114 6292 } else { 6115 if (g->state() == Qt::GestureStarted) 6116 gestureTargets[g] = item; 6293 if (receiver && g->state() == Qt::GestureStarted) { 6294 // someone accepted the propagated initial GestureStarted 6295 // event, let it be the new target for all following events. 6296 gestureTargets[g] = receiver.data(); 6297 } 6298 undeliveredGestures.remove(g); 6117 6299 } 6118 6300 } 6119 if (!ignoredGestures.isEmpty()) { 6120 // get a list of items under the (current) hotspot of each ignored 6121 // gesture and start delivery again from the beginning 6301 if (undeliveredGestures.isEmpty()) 6302 break; 6303 6304 // ignoredGestures list is only filled when delivering to the gesture 6305 // target item, so it is safe to assume item == target. 6306 if (!ignoredGestures.isEmpty() && !isPanel) { 6307 // look for new potential targets for gestures that were ignored 6308 // and should be propagated. 6309 6310 QSet<QGraphicsObject *> targetsSet = cachedTargetItems.toSet(); 6311 6312 if (receiver) { 6313 // first if the gesture should be propagated to parents only 6314 for (QSet<QGesture *>::iterator it = ignoredGestures.begin(); 6315 it != ignoredGestures.end();) { 6316 if (parentPropagatedGestures.contains(*it)) { 6317 QGesture *gesture = *it; 6318 const Qt::GestureType gestureType = gesture->gestureType(); 6319 QGraphicsItem *item = receiver.data(); 6320 while (item) { 6321 if (QGraphicsObject *obj = item->toGraphicsObject()) { 6322 if (item->d_func()->gestureContext.contains(gestureType)) { 6323 targetsSet.insert(obj); 6324 cachedItemGestures[obj].insert(gesture); 6325 } 6326 } 6327 if (item->isPanel()) 6328 break; 6329 item = item->parentItem(); 6330 } 6331 6332 it = ignoredGestures.erase(it); 6333 continue; 6334 } 6335 ++it; 6336 } 6337 } 6338 6339 gestureTargetsAtHotSpots(ignoredGestures, Qt::ReceivePartialGestures, 6340 &cachedItemGestures, &targetsSet, 0, 0); 6341 6342 cachedTargetItems = targetsSet.toList(); 6343 qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst); 6122 6344 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6123 << "item has ignored the event, will propagate." 6124 << item << ignoredGestures; 6125 itemIgnoredGestures[item] += ignoredGestures; 6126 QMap<Qt::GestureType, QGesture *> conflictedGestures; 6127 QList<QList<QGraphicsObject *> > itemsForConflictedGestures; 6128 QHash<QGesture *, QGraphicsObject *> normalGestures; 6129 getGestureTargets(ignoredGestures, viewport, 6130 &conflictedGestures, &itemsForConflictedGestures, 6131 &normalGestures); 6132 QSet<QGraphicsObject *> itemsSet = targetItems.toSet(); 6133 for (int k = 0; k < itemsForConflictedGestures.size(); ++k) 6134 itemsSet += itemsForConflictedGestures.at(k).toSet(); 6135 targetItems = itemsSet.toList(); 6136 qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst); 6137 alreadyIgnoredGestures = conflictedGestures.values(); 6138 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6139 << "new targets:" << targetItems; 6345 << "new targets:" << cachedTargetItems; 6140 6346 i = -1; // start delivery again 6141 6347 continue; 6142 6348 } 6143 6349 } 6350 6144 6351 foreach (QGesture *g, startedGestures) { 6145 6352 if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) { 6146 6353 DEBUG() << "lets try to cancel some"; 6147 6354 // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them 6148 cancelGesturesForChildren(g , event->widget());6355 cancelGesturesForChildren(g); 6149 6356 } 6150 6357 } … … 6161 6368 } 6162 6369 } 6163 } 6164 6165 void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original, QWidget *viewport) 6370 6371 cachedTargetItems.clear(); 6372 cachedItemGestures.clear(); 6373 cachedAlreadyDeliveredGestures.clear(); 6374 } 6375 6376 void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original) 6166 6377 { 6167 6378 Q_ASSERT(original); 6168 6379 QGraphicsItem *originalItem = gestureTargets.value(original); 6169 Q_ASSERT(originalItem); 6380 if (originalItem == 0) // we only act on accepted gestures, which implies it has a target. 6381 return; 6170 6382 6171 6383 // iterate over all active gestures and for each find the owner … … 6219 6431 continue; 6220 6432 6221 QPoint screenPos = g->hotSpot().toPoint(); 6222 QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport); 6433 QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), g->d_func()->sceneHotSpot, 0); 6223 6434 for (int j = 0; j < items.size(); ++j) { 6224 6435 QGraphicsObject *item = items.at(j)->toGraphicsObject(); … … 6246 6457 } 6247 6458 6459 void QGraphicsScenePrivate::grabGesture(QGraphicsItem *, Qt::GestureType gesture) 6460 { 6461 (void)QGestureManager::instance(); // create a gesture manager 6462 if (!grabbedGestures[gesture]++) { 6463 foreach (QGraphicsView *view, views) 6464 view->viewport()->grabGesture(gesture); 6465 } 6466 } 6467 6468 void QGraphicsScenePrivate::ungrabGesture(QGraphicsItem *item, Qt::GestureType gesture) 6469 { 6470 // we know this can only be an object 6471 Q_ASSERT(item->d_ptr->isObject); 6472 QGraphicsObject *obj = static_cast<QGraphicsObject *>(item); 6473 QGestureManager::instance()->cleanupCachedGestures(obj, gesture); 6474 if (!--grabbedGestures[gesture]) { 6475 foreach (QGraphicsView *view, views) 6476 view->viewport()->ungrabGesture(gesture); 6477 } 6478 } 6479 #endif // QT_NO_GESTURES 6480 6248 6481 QT_END_NAMESPACE 6249 6482
Note:
See TracChangeset
for help on using the changeset viewer.