50 It provides a light-weight foundation for writing your own custom items. |
50 It provides a light-weight foundation for writing your own custom items. |
51 This includes defining the item's geometry, collision detection, its |
51 This includes defining the item's geometry, collision detection, its |
52 painting implementation and item interaction through its event handlers. |
52 painting implementation and item interaction through its event handlers. |
53 QGraphicsItem is part of \l{The Graphics View Framework} |
53 QGraphicsItem is part of \l{The Graphics View Framework} |
54 |
54 |
55 \img graphicsview-items.png |
55 \image graphicsview-items.png |
56 |
56 |
57 For convenience, Qt provides a set of standard graphics items for the most |
57 For convenience, Qt provides a set of standard graphics items for the most |
58 common shapes. These are: |
58 common shapes. These are: |
59 |
59 |
60 \list |
60 \list |
376 |
376 |
377 \value ItemNegativeZStacksBehindParent The item automatically stacks behind |
377 \value ItemNegativeZStacksBehindParent The item automatically stacks behind |
378 it's parent if it's z-value is negative. This flag enables setZValue() to |
378 it's parent if it's z-value is negative. This flag enables setZValue() to |
379 toggle ItemStacksBehindParent. |
379 toggle ItemStacksBehindParent. |
380 |
380 |
381 \value ItemIsPanel. The item is a panel. A panel provides activation and |
381 \value ItemIsPanel The item is a panel. A panel provides activation and |
382 contained focus handling. Only one panel can be active at a time (see |
382 contained focus handling. Only one panel can be active at a time (see |
383 QGraphicsItem::isActive()). When no panel is active, QGraphicsScene |
383 QGraphicsItem::isActive()). When no panel is active, QGraphicsScene |
384 activates all non-panel items. Window items (i.e., |
384 activates all non-panel items. Window items (i.e., |
385 QGraphicsItem::isWindow() returns true) are panels. This flag was |
385 QGraphicsItem::isWindow() returns true) are panels. This flag was |
386 introduced in Qt 4.6. |
386 introduced in Qt 4.6. |
387 |
387 |
388 \omitvalue ItemIsFocusScope Internal only (for now). |
388 \omitvalue ItemIsFocusScope \omit Internal only (for now). \endomit |
|
389 |
|
390 \value ItemSendsScenePositionChanges The item enables itemChange() |
|
391 notifications for ItemScenePositionHasChanged. For performance reasons, |
|
392 these notifications are disabled by default. You must enable this flag |
|
393 to receive notifications for scene position changes. This flag was |
|
394 introduced in Qt 4.6. |
389 */ |
395 */ |
390 |
396 |
391 /*! |
397 /*! |
392 \enum QGraphicsItem::GraphicsItemChange |
398 \enum QGraphicsItem::GraphicsItemChange |
393 |
399 |
560 from itemChange(). |
566 from itemChange(). |
561 |
567 |
562 \value ItemOpacityHasChanged The item's opacity has changed. The value |
568 \value ItemOpacityHasChanged The item's opacity has changed. The value |
563 argument is the new opacity (i.e., a double). Do not call setOpacity() as |
569 argument is the new opacity (i.e., a double). Do not call setOpacity() as |
564 this notification is delivered. The return value is ignored. |
570 this notification is delivered. The return value is ignored. |
|
571 |
|
572 \value ItemScenePositionHasChanged The item's scene position has changed. |
|
573 This notification is sent if the ItemSendsScenePositionChanges flag is |
|
574 enabled, and after the item's scene position has changed (i.e., the |
|
575 position or transformation of the item itself or the position or |
|
576 transformation of any ancestor has changed). The value argument is the |
|
577 new scene position (the same as scenePos()), and QGraphicsItem ignores |
|
578 the return value for this notification (i.e., a read-only notification). |
565 */ |
579 */ |
566 |
580 |
567 /*! |
581 /*! |
568 \enum QGraphicsItem::CacheMode |
582 \enum QGraphicsItem::CacheMode |
569 \since 4.4 |
583 \since 4.4 |
739 enabled = q->handlesChildEvents(); |
753 enabled = q->handlesChildEvents(); |
740 break; |
754 break; |
741 case QGraphicsItem::ItemClipsChildrenToShape: |
755 case QGraphicsItem::ItemClipsChildrenToShape: |
742 flag = AncestorClipsChildren; |
756 flag = AncestorClipsChildren; |
743 enabled = flags & QGraphicsItem::ItemClipsChildrenToShape; |
757 enabled = flags & QGraphicsItem::ItemClipsChildrenToShape; |
744 invalidateCachedClipPathRecursively(/*childrenOnly=*/true); |
|
745 break; |
758 break; |
746 case QGraphicsItem::ItemIgnoresTransformations: |
759 case QGraphicsItem::ItemIgnoresTransformations: |
747 flag = AncestorIgnoresTransformations; |
760 flag = AncestorIgnoresTransformations; |
748 enabled = flags & QGraphicsItem::ItemIgnoresTransformations; |
761 enabled = flags & QGraphicsItem::ItemIgnoresTransformations; |
749 break; |
762 break; |
988 return; |
1001 return; |
989 |
1002 |
990 if (scene) { |
1003 if (scene) { |
991 // Deliver the change to the index |
1004 // Deliver the change to the index |
992 scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParentVariant); |
1005 scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParentVariant); |
|
1006 |
|
1007 // Disable scene pos notifications for old ancestors |
|
1008 if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges)) |
|
1009 scene->d_func()->setScenePosItemEnabled(q, false); |
993 } |
1010 } |
994 |
1011 |
995 if (subFocusItem && parent) { |
1012 if (subFocusItem && parent) { |
996 // Make sure none of the old parents point to this guy. |
1013 // Make sure none of the old parents point to this guy. |
997 subFocusItem->d_ptr->clearSubFocus(parent); |
1014 subFocusItem->d_ptr->clearSubFocus(parent); |
1037 } |
1054 } |
1038 p = p->d_ptr->parent; |
1055 p = p->d_ptr->parent; |
1039 } |
1056 } |
1040 |
1057 |
1041 // Update focus scope item ptr in new scope. |
1058 // Update focus scope item ptr in new scope. |
1042 if (newParent) { |
1059 QGraphicsItem *newFocusScopeItem = subFocusItem ? subFocusItem : parentFocusScopeItem; |
|
1060 if (newFocusScopeItem && newParent) { |
|
1061 if (subFocusItem) { |
|
1062 // Find the subFocusItem's topmost focus scope. |
|
1063 QGraphicsItem *ancestorScope = 0; |
|
1064 QGraphicsItem *p = subFocusItem->d_ptr->parent; |
|
1065 while (p) { |
|
1066 if (p->flags() & QGraphicsItem::ItemIsFocusScope) |
|
1067 ancestorScope = p; |
|
1068 if (p->isPanel()) |
|
1069 break; |
|
1070 p = p->parentItem(); |
|
1071 } |
|
1072 if (ancestorScope) |
|
1073 newFocusScopeItem = ancestorScope; |
|
1074 } |
|
1075 |
1043 QGraphicsItem *p = newParent; |
1076 QGraphicsItem *p = newParent; |
1044 while (p) { |
1077 while (p) { |
1045 if (p->flags() & QGraphicsItem::ItemIsFocusScope) { |
1078 if (p->flags() & QGraphicsItem::ItemIsFocusScope) { |
1046 p->d_ptr->focusScopeItem = subFocusItem ? subFocusItem : parentFocusScopeItem; |
1079 p->d_ptr->focusScopeItem = newFocusScopeItem; |
1047 // ### The below line might not make sense... |
1080 // Ensure the new item is no longer the subFocusItem. The |
1048 if (subFocusItem) |
1081 // only way to set focus on a child of a focus scope is |
|
1082 // by setting focus on the scope itself. |
|
1083 if (subFocusItem && !p->focusItem()) |
1049 subFocusItem->d_ptr->clearSubFocus(); |
1084 subFocusItem->d_ptr->clearSubFocus(); |
1050 break; |
1085 break; |
1051 } |
1086 } |
1052 p = p->d_ptr->parent; |
1087 p = p->d_ptr->parent; |
1053 } |
1088 } |
1064 scene->removeItem(q); |
1099 scene->removeItem(q); |
1065 } |
1100 } |
1066 |
1101 |
1067 parent->d_ptr->addChild(q); |
1102 parent->d_ptr->addChild(q); |
1068 parent->itemChange(QGraphicsItem::ItemChildAddedChange, thisPointerVariant); |
1103 parent->itemChange(QGraphicsItem::ItemChildAddedChange, thisPointerVariant); |
1069 if (!implicitUpdate && scene) { |
1104 if (scene) { |
1070 scene->d_func()->markDirty(q_ptr, QRect(), |
1105 if (!implicitUpdate) |
1071 /*invalidateChildren=*/false, |
1106 scene->d_func()->markDirty(q_ptr); |
1072 /*maybeDirtyClipPath=*/true); |
1107 |
|
1108 // Re-enable scene pos notifications for new ancestors |
|
1109 if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges)) |
|
1110 scene->d_func()->setScenePosItemEnabled(q, true); |
1073 } |
1111 } |
1074 |
1112 |
1075 // Inherit ancestor flags from the new parent. |
1113 // Inherit ancestor flags from the new parent. |
1076 updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2)); |
1114 updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2)); |
1077 updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1)); |
1115 updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1)); |
1104 setVisibleHelper(true, /* explicit = */ false); |
1142 setVisibleHelper(true, /* explicit = */ false); |
1105 if (!enabled && !explicitlyDisabled) |
1143 if (!enabled && !explicitlyDisabled) |
1106 setEnabledHelper(true, /* explicit = */ false); |
1144 setEnabledHelper(true, /* explicit = */ false); |
1107 |
1145 |
1108 // If the item is being deleted, the whole scene will be updated. |
1146 // If the item is being deleted, the whole scene will be updated. |
1109 if (scene) { |
1147 if (scene) |
1110 scene->d_func()->markDirty(q_ptr, QRect(), |
1148 scene->d_func()->markDirty(q_ptr); |
1111 /*invalidateChildren=*/false, |
|
1112 /*maybeDirtyClipPath=*/true); |
|
1113 } |
|
1114 } |
1149 } |
1115 } |
1150 } |
1116 |
1151 |
1117 // Resolve depth. |
1152 // Resolve depth. |
1118 invalidateDepthRecursively(); |
1153 invalidateDepthRecursively(); |
1197 // Determine the item's exposed area |
1232 // Determine the item's exposed area |
1198 option->exposedRect = QRectF(); |
1233 option->exposedRect = QRectF(); |
1199 const QTransform reverseMap = worldTransform.inverted(); |
1234 const QTransform reverseMap = worldTransform.inverted(); |
1200 const QVector<QRect> exposedRects(exposedRegion.rects()); |
1235 const QVector<QRect> exposedRects(exposedRegion.rects()); |
1201 for (int i = 0; i < exposedRects.size(); ++i) { |
1236 for (int i = 0; i < exposedRects.size(); ++i) { |
1202 option->exposedRect |= reverseMap.mapRect(exposedRects.at(i)); |
1237 option->exposedRect |= reverseMap.mapRect(QRectF(exposedRects.at(i))); |
1203 if (option->exposedRect.contains(brect)) |
1238 if (option->exposedRect.contains(brect)) |
1204 break; |
1239 break; |
1205 } |
1240 } |
1206 option->exposedRect &= brect; |
1241 option->exposedRect &= brect; |
1207 } |
1242 } |
1301 } |
1339 } |
1302 p = p->d_ptr->parent; |
1340 p = p->d_ptr->parent; |
1303 } |
1341 } |
1304 |
1342 |
1305 if (!d_ptr->children.isEmpty()) { |
1343 if (!d_ptr->children.isEmpty()) { |
1306 QList<QGraphicsItem *> oldChildren = d_ptr->children; |
1344 while (!d_ptr->children.isEmpty()) |
1307 qDeleteAll(oldChildren); |
1345 delete d_ptr->children.first(); |
1308 Q_ASSERT(d_ptr->children.isEmpty()); |
1346 Q_ASSERT(d_ptr->children.isEmpty()); |
1309 } |
1347 } |
1310 |
1348 |
1311 if (d_ptr->scene) { |
1349 if (d_ptr->scene) { |
1312 d_ptr->scene->d_func()->removeItemHelper(this); |
1350 d_ptr->scene->d_func()->removeItemHelper(this); |
1313 } else { |
1351 } else { |
1314 d_ptr->resetFocusProxy(); |
1352 d_ptr->resetFocusProxy(); |
1315 d_ptr->setParentItemHelper(0); |
1353 d_ptr->setParentItemHelper(0); |
1316 } |
1354 } |
1317 |
1355 |
|
1356 #ifndef QT_NO_GRAPHICSEFFECT |
1318 delete d_ptr->graphicsEffect; |
1357 delete d_ptr->graphicsEffect; |
|
1358 #endif //QT_NO_GRAPHICSEFFECT |
1319 if (d_ptr->transformData) { |
1359 if (d_ptr->transformData) { |
1320 for(int i = 0; i < d_ptr->transformData->graphicsTransforms.size(); ++i) { |
1360 for(int i = 0; i < d_ptr->transformData->graphicsTransforms.size(); ++i) { |
1321 QGraphicsTransform *t = d_ptr->transformData->graphicsTransforms.at(i); |
1361 QGraphicsTransform *t = d_ptr->transformData->graphicsTransforms.at(i); |
1322 static_cast<QGraphicsTransformPrivate *>(t->d_ptr.data())->item = 0; |
1362 static_cast<QGraphicsTransformPrivate *>(t->d_ptr.data())->item = 0; |
1323 delete t; |
1363 delete t; |
1655 return; |
1695 return; |
1656 if (d_ptr->scene) |
1696 if (d_ptr->scene) |
1657 d_ptr->scene->d_func()->index->itemChange(this, ItemFlagsChange, quint32(flags)); |
1697 d_ptr->scene->d_func()->index->itemChange(this, ItemFlagsChange, quint32(flags)); |
1658 |
1698 |
1659 // Flags that alter the geometry of the item (or its children). |
1699 // Flags that alter the geometry of the item (or its children). |
1660 const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations); |
1700 const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations | ItemIsSelectable); |
1661 bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask); |
1701 bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask); |
1662 if (fullUpdate) |
1702 if (fullUpdate) |
1663 d_ptr->paintedViewBoundingRectsNeedRepaint = 1; |
1703 d_ptr->paintedViewBoundingRectsNeedRepaint = 1; |
1664 |
1704 |
1665 // Keep the old flags to compare the diff. |
1705 // Keep the old flags to compare the diff. |
1683 if ((flags & ItemClipsChildrenToShape) != (oldFlags & ItemClipsChildrenToShape)) { |
1723 if ((flags & ItemClipsChildrenToShape) != (oldFlags & ItemClipsChildrenToShape)) { |
1684 // Item children clipping changes. Propagate the ancestor flag to |
1724 // Item children clipping changes. Propagate the ancestor flag to |
1685 // all children. |
1725 // all children. |
1686 d_ptr->updateAncestorFlag(ItemClipsChildrenToShape); |
1726 d_ptr->updateAncestorFlag(ItemClipsChildrenToShape); |
1687 } |
1727 } |
1688 |
|
1689 if ((flags & ItemClipsToShape) != (oldFlags & ItemClipsToShape)) |
|
1690 d_ptr->invalidateCachedClipPath(); |
|
1691 |
1728 |
1692 if ((flags & ItemIgnoresTransformations) != (oldFlags & ItemIgnoresTransformations)) { |
1729 if ((flags & ItemIgnoresTransformations) != (oldFlags & ItemIgnoresTransformations)) { |
1693 // Item children clipping changes. Propagate the ancestor flag to |
1730 // Item children clipping changes. Propagate the ancestor flag to |
1694 // all children. |
1731 // all children. |
1695 d_ptr->updateAncestorFlag(ItemIgnoresTransformations); |
1732 d_ptr->updateAncestorFlag(ItemIgnoresTransformations); |
2483 // Notify change. |
2520 // Notify change. |
2484 itemChange(ItemOpacityHasChanged, newOpacityVariant); |
2521 itemChange(ItemOpacityHasChanged, newOpacityVariant); |
2485 |
2522 |
2486 // Update. |
2523 // Update. |
2487 if (d_ptr->scene) { |
2524 if (d_ptr->scene) { |
|
2525 #ifndef QT_NO_GRAPHICSEFFECT |
2488 d_ptr->invalidateGraphicsEffectsRecursively(); |
2526 d_ptr->invalidateGraphicsEffectsRecursively(); |
|
2527 #endif //QT_NO_GRAPHICSEFFECT |
2489 d_ptr->scene->d_func()->markDirty(this, QRectF(), |
2528 d_ptr->scene->d_func()->markDirty(this, QRectF(), |
2490 /*invalidateChildren=*/true, |
2529 /*invalidateChildren=*/true, |
2491 /*maybeDirtyClipPath=*/false, |
|
2492 /*force=*/false, |
2530 /*force=*/false, |
2493 /*ignoreOpacity=*/true); |
2531 /*ignoreOpacity=*/true); |
2494 } |
2532 } |
2495 |
2533 |
2496 if (d_ptr->isObject) |
2534 if (d_ptr->isObject) |
2513 the new \a effect. |
2552 the new \a effect. |
2514 |
2553 |
2515 If \a effect is the installed on a different item, setGraphicsEffect() will remove |
2554 If \a effect is the installed on a different item, setGraphicsEffect() will remove |
2516 the effect from the item and install it on this item. |
2555 the effect from the item and install it on this item. |
2517 |
2556 |
|
2557 QGraphicsItem takes ownership of \a effect. |
|
2558 |
2518 \note This function will apply the effect on itself and all its children. |
2559 \note This function will apply the effect on itself and all its children. |
2519 |
2560 |
2520 \since 4.6 |
2561 \since 4.6 |
2521 */ |
2562 */ |
2522 void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect) |
2563 void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect) |
2523 { |
2564 { |
2524 if (d_ptr->graphicsEffect == effect) |
2565 if (d_ptr->graphicsEffect == effect) |
2525 return; |
2566 return; |
2526 |
2567 |
2527 if (d_ptr->graphicsEffect && effect) { |
2568 if (d_ptr->graphicsEffect) { |
2528 delete d_ptr->graphicsEffect; |
2569 delete d_ptr->graphicsEffect; |
2529 d_ptr->graphicsEffect = 0; |
2570 d_ptr->graphicsEffect = 0; |
2530 } |
2571 } |
2531 |
2572 |
2532 if (!effect) { |
2573 if (effect) { |
2533 // Unset current effect. |
|
2534 QGraphicsEffectPrivate *oldEffectPrivate = d_ptr->graphicsEffect->d_func(); |
|
2535 d_ptr->graphicsEffect = 0; |
|
2536 if (oldEffectPrivate) { |
|
2537 oldEffectPrivate->setGraphicsEffectSource(0); // deletes the current source. |
|
2538 if (d_ptr->scene) // Update the views directly. |
|
2539 d_ptr->scene->d_func()->markDirty(this, QRectF(), false, false, false, false, true); |
|
2540 } |
|
2541 } else { |
|
2542 // Set new effect. |
2574 // Set new effect. |
2543 QGraphicsEffectSourcePrivate *sourced = new QGraphicsItemEffectSourcePrivate(this); |
2575 QGraphicsEffectSourcePrivate *sourced = new QGraphicsItemEffectSourcePrivate(this); |
2544 QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced); |
2576 QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced); |
2545 d_ptr->graphicsEffect = effect; |
2577 d_ptr->graphicsEffect = effect; |
2546 effect->d_func()->setGraphicsEffectSource(source); |
2578 effect->d_func()->setGraphicsEffectSource(source); |
2547 } |
2579 prepareGeometryChange(); |
2548 |
2580 } |
2549 prepareGeometryChange(); |
2581 } |
|
2582 #endif //QT_NO_GRAPHICSEFFECT |
|
2583 |
|
2584 /*! |
|
2585 \internal |
|
2586 \since 4.6 |
|
2587 Returns the effective bounding rect of the given item space rect. |
|
2588 If the item has no effect, the rect is returned unmodified. |
|
2589 If the item has an effect, the effective rect can be extend beyond the |
|
2590 item's bounding rect, depending on the effect. |
|
2591 |
|
2592 \sa boundingRect() |
|
2593 */ |
|
2594 QRectF QGraphicsItemPrivate::effectiveBoundingRect(const QRectF &rect) const |
|
2595 { |
|
2596 #ifndef QT_NO_GRAPHICSEFFECT |
|
2597 Q_Q(const QGraphicsItem); |
|
2598 QGraphicsEffect *effect = graphicsEffect; |
|
2599 if (scene && effect && effect->isEnabled()) { |
|
2600 QRectF sceneRect = q->mapRectToScene(rect); |
|
2601 QRectF sceneEffectRect; |
|
2602 foreach (QGraphicsView *view, scene->views()) { |
|
2603 QRectF deviceRect = view->d_func()->mapRectFromScene(sceneRect); |
|
2604 QRect deviceEffectRect = effect->boundingRectFor(deviceRect).toAlignedRect(); |
|
2605 sceneEffectRect |= view->d_func()->mapRectToScene(deviceEffectRect); |
|
2606 } |
|
2607 return q->mapRectFromScene(sceneEffectRect); |
|
2608 } |
|
2609 #endif //QT_NO_GRAPHICSEFFECT |
|
2610 return rect; |
2550 } |
2611 } |
2551 |
2612 |
2552 /*! |
2613 /*! |
2553 \internal |
2614 \internal |
2554 \since 4.6 |
2615 \since 4.6 |
2559 |
2620 |
2560 \sa boundingRect() |
2621 \sa boundingRect() |
2561 */ |
2622 */ |
2562 QRectF QGraphicsItemPrivate::effectiveBoundingRect() const |
2623 QRectF QGraphicsItemPrivate::effectiveBoundingRect() const |
2563 { |
2624 { |
2564 QGraphicsEffect *effect = graphicsEffect; |
2625 #ifndef QT_NO_GRAPHICSEFFECT |
2565 QRectF brect = effect && effect->isEnabled() ? effect->boundingRect() : q_ptr->boundingRect(); |
2626 Q_Q(const QGraphicsItem); |
|
2627 QRectF brect = effectiveBoundingRect(q_ptr->boundingRect()); |
2566 if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) |
2628 if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) |
2567 return brect; |
2629 return brect; |
2568 |
2630 |
2569 const QGraphicsItem *effectParent = parent; |
2631 const QGraphicsItem *effectParent = parent; |
2570 while (effectParent) { |
2632 while (effectParent) { |
2571 effect = effectParent->d_ptr->graphicsEffect; |
2633 QGraphicsEffect *effect = effectParent->d_ptr->graphicsEffect; |
2572 if (effect && effect->isEnabled()) |
2634 if (scene && effect && effect->isEnabled()) { |
2573 brect = effect->boundingRectFor(brect); |
2635 const QRectF brectInParentSpace = q->mapRectToItem(effectParent, brect); |
|
2636 const QRectF effectRectInParentSpace = effectParent->d_ptr->effectiveBoundingRect(brectInParentSpace); |
|
2637 brect = effectParent->mapRectToItem(q, effectRectInParentSpace); |
|
2638 } |
2574 if (effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) |
2639 if (effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) |
2575 return brect; |
2640 return brect; |
2576 effectParent = effectParent->d_ptr->parent; |
2641 effectParent = effectParent->d_ptr->parent; |
2577 } |
2642 } |
2578 |
2643 |
2579 return brect; |
2644 return brect; |
|
2645 #else //QT_NO_GRAPHICSEFFECT |
|
2646 return q_ptr->boundingRect(); |
|
2647 #endif //QT_NO_GRAPHICSEFFECT |
|
2648 |
2580 } |
2649 } |
2581 |
2650 |
2582 /*! |
2651 /*! |
2583 \internal |
2652 \internal |
2584 \since 4.6 |
2653 \since 4.6 |
4220 children[i]->d_ptr->siblingIndex = i; |
4302 children[i]->d_ptr->siblingIndex = i; |
4221 } |
4303 } |
4222 } |
4304 } |
4223 |
4305 |
4224 /*! |
4306 /*! |
|
4307 \internal |
|
4308 */ |
|
4309 inline void QGraphicsItemPrivate::sendScenePosChange() |
|
4310 { |
|
4311 Q_Q(QGraphicsItem); |
|
4312 if (scene) { |
|
4313 if (flags & QGraphicsItem::ItemSendsScenePositionChanges) |
|
4314 q->itemChange(QGraphicsItem::ItemScenePositionHasChanged, q->scenePos()); |
|
4315 if (scenePosDescendants) { |
|
4316 foreach (QGraphicsItem *item, scene->d_func()->scenePosItems) { |
|
4317 if (q->isAncestorOf(item)) |
|
4318 item->itemChange(QGraphicsItem::ItemScenePositionHasChanged, item->scenePos()); |
|
4319 } |
|
4320 } |
|
4321 } |
|
4322 } |
|
4323 |
|
4324 /*! |
4225 \since 4.6 |
4325 \since 4.6 |
4226 |
4326 |
4227 Stacks this item before \a sibling, which must be a sibling item (i.e., the |
4327 Stacks this item before \a sibling, which must be a sibling item (i.e., the |
4228 two items must share the same parent item, or must both be toplevel items). |
4328 two items must share the same parent item, or must both be toplevel items). |
4229 The \a sibling must have the same Z value as this item, otherwise calling |
4329 The \a sibling must have the same Z value as this item, otherwise calling |
4261 d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes(); |
4361 d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes(); |
4262 |
4362 |
4263 // Only move items with the same Z value, and that need moving. |
4363 // Only move items with the same Z value, and that need moving. |
4264 int siblingIndex = sibling->d_ptr->siblingIndex; |
4364 int siblingIndex = sibling->d_ptr->siblingIndex; |
4265 int myIndex = d_ptr->siblingIndex; |
4365 int myIndex = d_ptr->siblingIndex; |
4266 if (myIndex >= siblingIndex && d_ptr->z == sibling->d_ptr->z) { |
4366 if (myIndex >= siblingIndex) { |
4267 siblings->move(myIndex, siblingIndex); |
4367 siblings->move(myIndex, siblingIndex); |
4268 // Fixup the insertion ordering. |
4368 // Fixup the insertion ordering. |
4269 for (int i = 0; i < siblings->size(); ++i) { |
4369 for (int i = 0; i < siblings->size(); ++i) { |
4270 int &index = siblings->at(i)->d_ptr->siblingIndex; |
4370 int &index = siblings->at(i)->d_ptr->siblingIndex; |
4271 if (i != siblingIndex && index >= siblingIndex && index <= myIndex) |
4371 if (i != siblingIndex && index >= siblingIndex && index <= myIndex) |
4272 ++index; |
4372 ++index; |
4273 } |
4373 } |
4274 d_ptr->siblingIndex = siblingIndex; |
4374 d_ptr->siblingIndex = siblingIndex; |
|
4375 for (int i = 0; i < siblings->size(); ++i) { |
|
4376 int &index = siblings->at(i)->d_ptr->siblingIndex; |
|
4377 if (i != siblingIndex && index >= siblingIndex && index <= myIndex) |
|
4378 siblings->at(i)->d_ptr->siblingOrderChange(); |
|
4379 } |
|
4380 d_ptr->siblingOrderChange(); |
4275 } |
4381 } |
4276 } |
4382 } |
4277 |
4383 |
4278 /*! |
4384 /*! |
4279 Returns the bounding rect of this item's descendants (i.e., its |
4385 Returns the bounding rect of this item's descendants (i.e., its |
4434 \sa isClipped(), shape(), setFlags() |
4540 \sa isClipped(), shape(), setFlags() |
4435 */ |
4541 */ |
4436 QPainterPath QGraphicsItem::clipPath() const |
4542 QPainterPath QGraphicsItem::clipPath() const |
4437 { |
4543 { |
4438 Q_D(const QGraphicsItem); |
4544 Q_D(const QGraphicsItem); |
4439 if (!d->dirtyClipPath) |
4545 if (!isClipped()) |
4440 return d->emptyClipPath ? QPainterPath() : d->cachedClipPath; |
4546 return QPainterPath(); |
4441 |
|
4442 if (!isClipped()) { |
|
4443 d_ptr->setCachedClipPath(QPainterPath()); |
|
4444 return d->cachedClipPath; |
|
4445 } |
|
4446 |
4547 |
4447 const QRectF thisBoundingRect(boundingRect()); |
4548 const QRectF thisBoundingRect(boundingRect()); |
4448 if (thisBoundingRect.isEmpty()) { |
4549 if (thisBoundingRect.isEmpty()) |
4449 if (d_ptr->flags & ItemClipsChildrenToShape) |
|
4450 d_ptr->setEmptyCachedClipPathRecursively(); |
|
4451 else |
|
4452 d_ptr->setEmptyCachedClipPath(); |
|
4453 return QPainterPath(); |
4550 return QPainterPath(); |
4454 } |
|
4455 |
4551 |
4456 QPainterPath clip; |
4552 QPainterPath clip; |
4457 // Start with the item's bounding rect. |
4553 // Start with the item's bounding rect. |
4458 clip.addRect(thisBoundingRect); |
4554 clip.addRect(thisBoundingRect); |
4459 |
4555 |
4460 if (d->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) { |
4556 if (d->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) { |
4461 const QGraphicsItem *parent = this; |
4557 const QGraphicsItem *parent = this; |
4462 const QGraphicsItem *lastParent = this; |
4558 const QGraphicsItem *lastParent = this; |
4463 |
4559 |
4464 // Intersect any in-between clips starting at the top and moving downwards. |
4560 // Intersect any in-between clips starting at the top and moving downwards. |
4465 bool foundValidClipPath = false; |
|
4466 while ((parent = parent->d_ptr->parent)) { |
4561 while ((parent = parent->d_ptr->parent)) { |
4467 if (parent->d_ptr->flags & ItemClipsChildrenToShape) { |
4562 if (parent->d_ptr->flags & ItemClipsChildrenToShape) { |
4468 // Map clip to the current parent and intersect with its shape/clipPath |
4563 // Map clip to the current parent and intersect with its shape/clipPath |
4469 clip = lastParent->itemTransform(parent).map(clip); |
4564 clip = lastParent->itemTransform(parent).map(clip); |
4470 if ((foundValidClipPath = !parent->d_ptr->dirtyClipPath && parent->isClipped())) { |
4565 clip = clip.intersected(parent->shape()); |
4471 if (parent->d_ptr->emptyClipPath) { |
4566 if (clip.isEmpty()) |
4472 if (d_ptr->flags & ItemClipsChildrenToShape) |
|
4473 d_ptr->setEmptyCachedClipPathRecursively(); |
|
4474 else |
|
4475 d_ptr->setEmptyCachedClipPath(); |
|
4476 return QPainterPath(); |
|
4477 } |
|
4478 clip = clip.intersected(parent->d_ptr->cachedClipPath); |
|
4479 if (!(parent->d_ptr->flags & ItemClipsToShape)) |
|
4480 clip = clip.intersected(parent->shape()); |
|
4481 } else { |
|
4482 clip = clip.intersected(parent->shape()); |
|
4483 } |
|
4484 |
|
4485 if (clip.isEmpty()) { |
|
4486 if (d_ptr->flags & ItemClipsChildrenToShape) |
|
4487 d_ptr->setEmptyCachedClipPathRecursively(); |
|
4488 else |
|
4489 d_ptr->setEmptyCachedClipPath(); |
|
4490 return clip; |
4567 return clip; |
4491 } |
|
4492 lastParent = parent; |
4568 lastParent = parent; |
4493 } |
4569 } |
4494 |
4570 |
4495 if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) |
4571 if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) |
4496 || foundValidClipPath) { |
|
4497 break; |
4572 break; |
4498 } |
|
4499 } |
4573 } |
4500 |
4574 |
4501 if (lastParent != this) { |
4575 if (lastParent != this) { |
4502 // Map clip back to the item's transform. |
4576 // Map clip back to the item's transform. |
4503 // ### what if itemtransform fails |
4577 // ### what if itemtransform fails |
4925 |
4998 |
4926 /*! |
4999 /*! |
4927 \internal |
5000 \internal |
4928 Returns true if we can discard an update request; otherwise false. |
5001 Returns true if we can discard an update request; otherwise false. |
4929 */ |
5002 */ |
4930 bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, bool ignoreVisibleBit, |
5003 bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreVisibleBit, bool ignoreDirtyBit, |
4931 bool ignoreDirtyBit, bool ignoreOpacity) const |
5004 bool ignoreOpacity) const |
4932 { |
5005 { |
4933 // No scene, or if the scene is updating everything, means we have nothing |
5006 // No scene, or if the scene is updating everything, means we have nothing |
4934 // to do. The only exception is if the scene tracks the growing scene rect. |
5007 // to do. The only exception is if the scene tracks the growing scene rect. |
4935 return !scene |
5008 return !scene |
4936 || (!visible && !ignoreVisibleBit && !this->ignoreVisible) |
5009 || (!visible && !ignoreVisibleBit && !this->ignoreVisible) |
4937 || (!ignoreDirtyBit && fullUpdatePending) |
5010 || (!ignoreDirtyBit && fullUpdatePending) |
4938 || (!ignoreClipping && (childrenClippedToShape() && isClippedAway())) |
|
4939 || (!ignoreOpacity && !this->ignoreOpacity && childrenCombineOpacity() && isFullyTransparent()); |
5011 || (!ignoreOpacity && !this->ignoreOpacity && childrenCombineOpacity() && isFullyTransparent()); |
4940 } |
5012 } |
4941 |
5013 |
4942 /*! |
5014 /*! |
4943 \internal |
5015 \internal |
5064 if (c) { |
5138 if (c) { |
5065 c->purge(); |
5139 c->purge(); |
5066 delete c; |
5140 delete c; |
5067 } |
5141 } |
5068 unsetExtra(ExtraCacheData); |
5142 unsetExtra(ExtraCacheData); |
5069 } |
|
5070 |
|
5071 void QGraphicsItemPrivate::setEmptyCachedClipPathRecursively(const QRectF &emptyIfOutsideThisRect) |
|
5072 { |
|
5073 setEmptyCachedClipPath(); |
|
5074 |
|
5075 const bool checkRect = !emptyIfOutsideThisRect.isNull() |
|
5076 && !(flags & QGraphicsItem::ItemClipsChildrenToShape); |
|
5077 for (int i = 0; i < children.size(); ++i) { |
|
5078 if (!checkRect) { |
|
5079 children.at(i)->d_ptr->setEmptyCachedClipPathRecursively(); |
|
5080 continue; |
|
5081 } |
|
5082 |
|
5083 QGraphicsItem *child = children.at(i); |
|
5084 const QRectF rect = child->mapRectFromParent(emptyIfOutsideThisRect); |
|
5085 if (rect.intersects(child->boundingRect())) |
|
5086 child->d_ptr->invalidateCachedClipPathRecursively(false, rect); |
|
5087 else |
|
5088 child->d_ptr->setEmptyCachedClipPathRecursively(rect); |
|
5089 } |
|
5090 } |
|
5091 |
|
5092 void QGraphicsItemPrivate::invalidateCachedClipPathRecursively(bool childrenOnly, const QRectF &emptyIfOutsideThisRect) |
|
5093 { |
|
5094 if (!childrenOnly) |
|
5095 invalidateCachedClipPath(); |
|
5096 |
|
5097 const bool checkRect = !emptyIfOutsideThisRect.isNull(); |
|
5098 for (int i = 0; i < children.size(); ++i) { |
|
5099 if (!checkRect) { |
|
5100 children.at(i)->d_ptr->invalidateCachedClipPathRecursively(false); |
|
5101 continue; |
|
5102 } |
|
5103 |
|
5104 QGraphicsItem *child = children.at(i); |
|
5105 const QRectF rect = child->mapRectFromParent(emptyIfOutsideThisRect); |
|
5106 if (rect.intersects(child->boundingRect())) |
|
5107 child->d_ptr->invalidateCachedClipPathRecursively(false, rect); |
|
5108 else |
|
5109 child->d_ptr->setEmptyCachedClipPathRecursively(rect); |
|
5110 } |
|
5111 } |
|
5112 |
|
5113 void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &newPos) |
|
5114 { |
|
5115 Q_ASSERT(inSetPosHelper); |
|
5116 |
|
5117 if (inDestructor || !(ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) |
|
5118 return; // Not clipped by any ancestor. |
|
5119 |
|
5120 // Find closest clip ancestor and transform. |
|
5121 Q_Q(QGraphicsItem); |
|
5122 // COMBINE |
|
5123 QTransform thisToParentTransform = QTransform::fromTranslate(newPos.x(), newPos.y()); |
|
5124 if (transformData) |
|
5125 thisToParentTransform = transformData->computedFullTransform(&thisToParentTransform); |
|
5126 QGraphicsItem *clipParent = parent; |
|
5127 while (clipParent && !clipParent->d_ptr->inDestructor && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) { |
|
5128 thisToParentTransform *= clipParent->d_ptr->transformToParent(); |
|
5129 clipParent = clipParent->d_ptr->parent; |
|
5130 } |
|
5131 |
|
5132 // Ensure no parents are currently being deleted. This can only |
|
5133 // happen if the item is moved by a dying ancestor. |
|
5134 QGraphicsItem *p = clipParent; |
|
5135 while (p) { |
|
5136 if (p->d_ptr->inDestructor) |
|
5137 return; |
|
5138 p = p->d_ptr->parent; |
|
5139 } |
|
5140 |
|
5141 // From here everything is calculated in clip parent's coordinates. |
|
5142 const QRectF parentBoundingRect(clipParent->boundingRect()); |
|
5143 const QRectF thisBoundingRect(thisToParentTransform.mapRect(q->boundingRect())); |
|
5144 |
|
5145 if (!parentBoundingRect.intersects(thisBoundingRect)) { |
|
5146 // Item is moved outside the clip parent's bounding rect, |
|
5147 // i.e. it is fully clipped and the clip path is empty. |
|
5148 if (flags & QGraphicsItem::ItemClipsChildrenToShape) |
|
5149 setEmptyCachedClipPathRecursively(); |
|
5150 else |
|
5151 setEmptyCachedClipPathRecursively(thisToParentTransform.inverted().mapRect(parentBoundingRect)); |
|
5152 return; |
|
5153 } |
|
5154 |
|
5155 const QPainterPath parentClip(clipParent->isClipped() ? clipParent->clipPath() : clipParent->shape()); |
|
5156 if (parentClip.contains(thisBoundingRect)) |
|
5157 return; // Item is inside the clip parent's shape. No update required. |
|
5158 |
|
5159 const QRectF parentClipRect(parentClip.controlPointRect()); |
|
5160 if (!parentClipRect.intersects(thisBoundingRect)) { |
|
5161 // Item is moved outside the clip parent's shape, |
|
5162 // i.e. it is fully clipped and the clip path is empty. |
|
5163 if (flags & QGraphicsItem::ItemClipsChildrenToShape) |
|
5164 setEmptyCachedClipPathRecursively(); |
|
5165 else |
|
5166 setEmptyCachedClipPathRecursively(thisToParentTransform.inverted().mapRect(parentClipRect)); |
|
5167 } else { |
|
5168 // Item is partially inside the clip parent's shape, |
|
5169 // i.e. the cached clip path must be invalidated. |
|
5170 invalidateCachedClipPathRecursively(false, thisToParentTransform.inverted().mapRect(parentClipRect)); |
|
5171 } |
|
5172 } |
5143 } |
5173 |
5144 |
5174 // Traverses all the ancestors up to the top-level and updates the pointer to |
5145 // Traverses all the ancestors up to the top-level and updates the pointer to |
5175 // always point to the top-most item that has a dirty scene transform. |
5146 // always point to the top-most item that has a dirty scene transform. |
5176 // It then backtracks to the top-most dirty item and start calculating the |
5147 // It then backtracks to the top-most dirty item and start calculating the |
5298 { |
5279 { |
5299 if (rect.isEmpty() && !rect.isNull()) |
5280 if (rect.isEmpty() && !rect.isNull()) |
5300 return; |
5281 return; |
5301 |
5282 |
5302 // Make sure we notify effects about invalidated source. |
5283 // Make sure we notify effects about invalidated source. |
|
5284 #ifndef QT_NO_GRAPHICSEFFECT |
5303 d_ptr->invalidateGraphicsEffectsRecursively(); |
5285 d_ptr->invalidateGraphicsEffectsRecursively(); |
|
5286 #endif //QT_NO_GRAPHICSEFFECT |
5304 |
5287 |
5305 if (CacheMode(d_ptr->cacheMode) != NoCache) { |
5288 if (CacheMode(d_ptr->cacheMode) != NoCache) { |
5306 // Invalidate cache. |
5289 // Invalidate cache. |
5307 QGraphicsItemCache *cache = d_ptr->extraItemCache(); |
5290 QGraphicsItemCache *cache = d_ptr->extraItemCache(); |
5308 if (!cache->allExposed) { |
5291 if (!cache->allExposed) { |
7173 d_ptr->paintedViewBoundingRectsNeedRepaint = 1; |
7156 d_ptr->paintedViewBoundingRectsNeedRepaint = 1; |
7174 d_ptr->notifyBoundingRectChanged = !d_ptr->inSetPosHelper; |
7157 d_ptr->notifyBoundingRectChanged = !d_ptr->inSetPosHelper; |
7175 |
7158 |
7176 QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); |
7159 QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); |
7177 scenePrivate->index->prepareBoundingRectChange(this); |
7160 scenePrivate->index->prepareBoundingRectChange(this); |
7178 scenePrivate->markDirty(this, QRectF(), |
7161 scenePrivate->markDirty(this, QRectF(), /*invalidateChildren=*/true); |
7179 /*invalidateChildren=*/true, |
|
7180 /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper); |
|
7181 |
7162 |
7182 // For compatibility reasons, we have to update the item's old geometry |
7163 // For compatibility reasons, we have to update the item's old geometry |
7183 // if someone is connected to the changed signal or the scene has no views. |
7164 // if someone is connected to the changed signal or the scene has no views. |
7184 // Note that this has to be done *after* markDirty to ensure that |
7165 // Note that this has to be done *after* markDirty to ensure that |
7185 // _q_processDirtyItems is called before _q_emitUpdated. |
7166 // _q_processDirtyItems is called before _q_emitUpdated. |
7194 } |
7175 } |
7195 } |
7176 } |
7196 |
7177 |
7197 QGraphicsItem *parent = this; |
7178 QGraphicsItem *parent = this; |
7198 while ((parent = parent->d_ptr->parent)) { |
7179 while ((parent = parent->d_ptr->parent)) { |
7199 parent->d_ptr->dirtyChildrenBoundingRect = 1; |
7180 QGraphicsItemPrivate *parentp = parent->d_ptr.data(); |
|
7181 parentp->dirtyChildrenBoundingRect = 1; |
7200 // ### Only do this if the parent's effect applies to the entire subtree. |
7182 // ### Only do this if the parent's effect applies to the entire subtree. |
7201 parent->d_ptr->notifyBoundingRectChanged = 1; |
7183 parentp->notifyBoundingRectChanged = 1; |
7202 } |
7184 #ifndef QT_NO_GRAPHICSEFFECT |
7203 |
7185 if (parentp->scene && parentp->graphicsEffect) { |
7204 if (d_ptr->inSetPosHelper) |
7186 parentp->notifyInvalidated = 1; |
7205 return; |
7187 static_cast<QGraphicsItemEffectSourcePrivate *>(parentp->graphicsEffect->d_func()->source->d_func())->invalidateCache(); |
7206 |
7188 } |
7207 if (d_ptr->flags & ItemClipsChildrenToShape |
7189 #endif |
7208 || d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) { |
|
7209 d_ptr->invalidateCachedClipPathRecursively(); |
|
7210 } else { |
|
7211 d_ptr->invalidateCachedClipPath(); |
|
7212 } |
7190 } |
7213 } |
7191 } |
7214 |
7192 |
7215 /*! |
7193 /*! |
7216 \internal |
7194 \internal |
7281 \ingroup graphicsview-api |
7259 \ingroup graphicsview-api |
7282 |
7260 |
7283 The class extends a QGraphicsItem with QObject's signal/slot and property mechanisms. |
7261 The class extends a QGraphicsItem with QObject's signal/slot and property mechanisms. |
7284 It maps many of QGraphicsItem's basic setters and getters to properties and adds notification |
7262 It maps many of QGraphicsItem's basic setters and getters to properties and adds notification |
7285 signals for many of them. |
7263 signals for many of them. |
|
7264 |
|
7265 \section1 Parents and Children |
|
7266 |
|
7267 Each graphics object can be constructed with a parent item. This ensures that the |
|
7268 item will be destroyed when its parent item is destroyed. Although QGraphicsObject |
|
7269 inherits from both QObject and QGraphicsItem, you should use the functions provided |
|
7270 by QGraphicsItem, \e not QObject, to manage the relationships between parent and |
|
7271 child items. |
|
7272 |
|
7273 The relationships between items can be explored using the parentItem() and childItems() |
|
7274 functions. In the hierarchy of items in a scene, the parentObject() and parentWidget() |
|
7275 functions are the equivalent of the QWidget::parent() and QWidget::parentWidget() |
|
7276 functions for QWidget subclasses. |
|
7277 |
|
7278 \sa QGraphicsWidget |
7286 */ |
7279 */ |
7287 |
7280 |
7288 /*! |
7281 /*! |
7289 Constructs a QGraphicsObject with \a parent. |
7282 Constructs a QGraphicsObject with \a parent. |
7290 */ |
7283 */ |
7302 { |
7295 { |
7303 QGraphicsItem::d_ptr->isObject = true; |
7296 QGraphicsItem::d_ptr->isObject = true; |
7304 } |
7297 } |
7305 |
7298 |
7306 /*! |
7299 /*! |
7307 Subscribes the graphics object to the given \a gesture for the specified \a context. |
7300 Subscribes the graphics object to the given \a gesture with specific \a flags. |
7308 |
7301 |
7309 \sa QGestureEvent |
7302 \sa ungrabGesture(), QGestureEvent |
7310 */ |
7303 */ |
7311 |
7304 void QGraphicsObject::grabGesture(Qt::GestureType gesture, Qt::GestureFlags flags) |
7312 void QGraphicsObject::grabGesture(Qt::GestureType gesture, Qt::GestureContext context) |
|
7313 { |
7305 { |
7314 QGraphicsItemPrivate * const d = QGraphicsItem::d_func(); |
7306 QGraphicsItemPrivate * const d = QGraphicsItem::d_func(); |
7315 d->gestureContext.insert(gesture, context); |
7307 d->gestureContext.insert(gesture, flags); |
7316 (void)QGestureManager::instance(); // create a gesture manager |
7308 (void)QGestureManager::instance(); // create a gesture manager |
7317 } |
7309 } |
7318 |
7310 |
7319 /*! |
7311 /*! |
|
7312 Unsubscribes the graphics object from the given \a gesture. |
|
7313 |
|
7314 \sa grabGesture(), QGestureEvent |
|
7315 */ |
|
7316 void QGraphicsObject::ungrabGesture(Qt::GestureType gesture) |
|
7317 { |
|
7318 QGraphicsItemPrivate * const d = QGraphicsItem::d_func(); |
|
7319 if (d->gestureContext.remove(gesture)) { |
|
7320 QGestureManager *manager = QGestureManager::instance(); |
|
7321 manager->cleanupCachedGestures(this, gesture); |
|
7322 } |
|
7323 } |
|
7324 |
|
7325 /*! |
7320 \property QGraphicsObject::parent |
7326 \property QGraphicsObject::parent |
7321 \brief the parent of the item. It is independent from \fn QObject::parent. |
7327 \brief the parent of the item |
|
7328 |
|
7329 \note The item's parent is set independently of the parent object returned |
|
7330 by QObject::parent(). |
7322 |
7331 |
7323 \sa QGraphicsItem::setParentItem(), QGraphicsItem::parentObject() |
7332 \sa QGraphicsItem::setParentItem(), QGraphicsItem::parentObject() |
7324 */ |
|
7325 |
|
7326 /*! |
|
7327 \property QGraphicsObject::id |
|
7328 \brief the id of of the item |
|
7329 |
|
7330 \sa QObject::objectName(), QObject::setObjectName() |
|
7331 */ |
7333 */ |
7332 |
7334 |
7333 /*! |
7335 /*! |
7334 \property QGraphicsObject::opacity |
7336 \property QGraphicsObject::opacity |
7335 \brief the opacity of the item |
7337 \brief the opacity of the item |
10530 |
10542 |
10531 // removing position from translation component of the new transform |
10543 // removing position from translation component of the new transform |
10532 if (!item->pos().isNull()) |
10544 if (!item->pos().isNull()) |
10533 newItemTransform *= QTransform::fromTranslate(-item->x(), -item->y()); |
10545 newItemTransform *= QTransform::fromTranslate(-item->x(), -item->y()); |
10534 |
10546 |
|
10547 // removing additional transformations properties applied with itemTransform() |
|
10548 QPointF origin = item->transformOriginPoint(); |
|
10549 QMatrix4x4 m; |
|
10550 QList<QGraphicsTransform*> transformList = item->transformations(); |
|
10551 for (int i = 0; i < transformList.size(); ++i) |
|
10552 transformList.at(i)->applyTo(&m); |
|
10553 newItemTransform *= m.toTransform().inverted(); |
|
10554 newItemTransform.translate(origin.x(), origin.y()); |
|
10555 newItemTransform.rotate(-item->rotation()); |
|
10556 newItemTransform.scale(1/item->scale(), 1/item->scale()); |
|
10557 newItemTransform.translate(-origin.x(), -origin.y()); |
|
10558 |
|
10559 // ### Expensive, we could maybe use dirtySceneTransform bit for optimization |
|
10560 |
10535 item->setTransform(newItemTransform); |
10561 item->setTransform(newItemTransform); |
10536 item->d_func()->setIsMemberOfGroup(true); |
10562 item->d_func()->setIsMemberOfGroup(true); |
10537 prepareGeometryChange(); |
10563 prepareGeometryChange(); |
10538 d->itemsBoundingRect |= itemTransform.mapRect(item->boundingRect() | item->childrenBoundingRect()); |
10564 d->itemsBoundingRect |= itemTransform.mapRect(item->boundingRect() | item->childrenBoundingRect()); |
10539 update(); |
10565 update(); |
10554 qWarning("QGraphicsItemGroup::removeFromGroup: cannot remove null item"); |
10580 qWarning("QGraphicsItemGroup::removeFromGroup: cannot remove null item"); |
10555 return; |
10581 return; |
10556 } |
10582 } |
10557 |
10583 |
10558 QGraphicsItem *newParent = d_ptr->parent; |
10584 QGraphicsItem *newParent = d_ptr->parent; |
|
10585 |
|
10586 // COMBINE |
|
10587 bool ok; |
|
10588 QTransform itemTransform; |
|
10589 if (newParent) |
|
10590 itemTransform = item->itemTransform(newParent, &ok); |
|
10591 else |
|
10592 itemTransform = item->sceneTransform(); |
|
10593 |
10559 QPointF oldPos = item->mapToItem(newParent, 0, 0); |
10594 QPointF oldPos = item->mapToItem(newParent, 0, 0); |
10560 item->setParentItem(newParent); |
10595 item->setParentItem(newParent); |
10561 // ### This function should remap the item's matrix to keep the item's |
|
10562 // transformation unchanged relative to the scene. |
|
10563 item->setPos(oldPos); |
10596 item->setPos(oldPos); |
|
10597 |
|
10598 // removing position from translation component of the new transform |
|
10599 if (!item->pos().isNull()) |
|
10600 itemTransform *= QTransform::fromTranslate(-item->x(), -item->y()); |
|
10601 |
|
10602 // removing additional transformations properties applied |
|
10603 // with itemTransform() or sceneTransform() |
|
10604 QPointF origin = item->transformOriginPoint(); |
|
10605 QMatrix4x4 m; |
|
10606 QList<QGraphicsTransform*> transformList = item->transformations(); |
|
10607 for (int i = 0; i < transformList.size(); ++i) |
|
10608 transformList.at(i)->applyTo(&m); |
|
10609 itemTransform *= m.toTransform().inverted(); |
|
10610 itemTransform.translate(origin.x(), origin.y()); |
|
10611 itemTransform.rotate(-item->rotation()); |
|
10612 itemTransform.scale(1 / item->scale(), 1 / item->scale()); |
|
10613 itemTransform.translate(-origin.x(), -origin.y()); |
|
10614 |
|
10615 // ### Expensive, we could maybe use dirtySceneTransform bit for optimization |
|
10616 |
|
10617 item->setTransform(itemTransform); |
10564 item->d_func()->setIsMemberOfGroup(item->group() != 0); |
10618 item->d_func()->setIsMemberOfGroup(item->group() != 0); |
10565 |
10619 |
10566 // ### Quite expensive. But removeFromGroup() isn't called very often. |
10620 // ### Quite expensive. But removeFromGroup() isn't called very often. |
10567 prepareGeometryChange(); |
10621 prepareGeometryChange(); |
10568 d->itemsBoundingRect = childrenBoundingRect(); |
10622 d->itemsBoundingRect = childrenBoundingRect(); |
10658 info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform, |
10713 info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform, |
10659 info->drawItem); |
10714 info->drawItem); |
10660 } |
10715 } |
10661 } |
10716 } |
10662 |
10717 |
10663 QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset) const |
10718 QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset, |
|
10719 QGraphicsEffect::PixmapPadMode mode) const |
10664 { |
10720 { |
10665 const bool deviceCoordinates = (system == Qt::DeviceCoordinates); |
10721 const bool deviceCoordinates = (system == Qt::DeviceCoordinates); |
10666 if (!info && deviceCoordinates) { |
10722 if (!info && deviceCoordinates) { |
10667 // Device coordinates without info not yet supported. |
10723 // Device coordinates without info not yet supported. |
10668 qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context"); |
10724 qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context"); |
10669 return QPixmap(); |
10725 return QPixmap(); |
10670 } |
10726 } |
10671 |
|
10672 if (!item->d_ptr->scene) |
10727 if (!item->d_ptr->scene) |
10673 return QPixmap(); |
10728 return QPixmap(); |
10674 QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func(); |
10729 QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func(); |
10675 |
10730 |
10676 const QRectF sourceRect = boundingRect(system); |
10731 const QRectF sourceRect = boundingRect(system); |
10677 QRect effectRect = item->graphicsEffect()->boundingRectFor(sourceRect).toAlignedRect(); |
10732 QRectF effectRectF; |
|
10733 |
|
10734 bool unpadded = false; |
|
10735 if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) { |
|
10736 if (info) { |
|
10737 effectRectF = item->graphicsEffect()->boundingRectFor(boundingRect(Qt::DeviceCoordinates)); |
|
10738 unpadded = (effectRectF.size() == sourceRect.size()); |
|
10739 if (info && system == Qt::LogicalCoordinates) |
|
10740 effectRectF = info->painter->worldTransform().inverted().mapRect(effectRectF); |
|
10741 } else { |
|
10742 // no choice but to send a logical coordinate bounding rect to boundingRectFor |
|
10743 effectRectF = item->graphicsEffect()->boundingRectFor(sourceRect); |
|
10744 } |
|
10745 } else if (mode == QGraphicsEffect::PadToTransparentBorder) { |
|
10746 // adjust by 1.5 to account for cosmetic pens |
|
10747 effectRectF = sourceRect.adjusted(-1.5, -1.5, 1.5, 1.5); |
|
10748 } else { |
|
10749 effectRectF = sourceRect; |
|
10750 unpadded = true; |
|
10751 } |
|
10752 |
|
10753 QRect effectRect = effectRectF.toAlignedRect(); |
|
10754 |
10678 if (offset) |
10755 if (offset) |
10679 *offset = effectRect.topLeft(); |
10756 *offset = effectRect.topLeft(); |
|
10757 |
|
10758 bool untransformed = !deviceCoordinates |
|
10759 || info->painter->worldTransform().type() <= QTransform::TxTranslate; |
|
10760 if (untransformed && unpadded && isPixmap()) { |
|
10761 if (offset) |
|
10762 *offset = boundingRect(system).topLeft().toPoint(); |
|
10763 return static_cast<QGraphicsPixmapItem *>(item)->pixmap(); |
|
10764 } |
10680 |
10765 |
10681 if (deviceCoordinates) { |
10766 if (deviceCoordinates) { |
10682 // Clip to viewport rect. |
10767 // Clip to viewport rect. |
10683 int left, top, right, bottom; |
10768 int left, top, right, bottom; |
10684 effectRect.getCoords(&left, &top, &right, &bottom); |
10769 effectRect.getCoords(&left, &top, &right, &bottom); |
10738 |
10822 |
10739 pixmapPainter.end(); |
10823 pixmapPainter.end(); |
10740 |
10824 |
10741 return pixmap; |
10825 return pixmap; |
10742 } |
10826 } |
|
10827 #endif //QT_NO_GRAPHICSEFFECT |
10743 |
10828 |
10744 #ifndef QT_NO_DEBUG_STREAM |
10829 #ifndef QT_NO_DEBUG_STREAM |
10745 QDebug operator<<(QDebug debug, QGraphicsItem *item) |
10830 QDebug operator<<(QDebug debug, QGraphicsItem *item) |
10746 { |
10831 { |
10747 if (!item) { |
10832 if (!item) { |
10748 debug << "QGraphicsItem(0)"; |
10833 debug << "QGraphicsItem(0)"; |
10749 return debug; |
10834 return debug; |
10750 } |
10835 } |
10751 |
10836 |
10752 debug << "QGraphicsItem(this =" << ((void*)item) |
10837 if (QGraphicsObject *o = item->toGraphicsObject()) |
10753 << ", parent =" << ((void*)item->parentItem()) |
10838 debug << o->metaObject()->className(); |
|
10839 else |
|
10840 debug << "QGraphicsItem"; |
|
10841 debug << "(this =" << (void*)item |
|
10842 << ", parent =" << (void*)item->parentItem() |
10754 << ", pos =" << item->pos() |
10843 << ", pos =" << item->pos() |
10755 << ", z =" << item->zValue() << ", flags = " |
10844 << ", z =" << item->zValue() << ", flags = " |
10756 << item->flags() << ")"; |
10845 << item->flags() << ")"; |
10757 return debug; |
10846 return debug; |
10758 } |
10847 } |