Add a new optimization flag to QGraphicsItem.
The new flag ItemContainsChildrenInShape is similar to the existing flag ItemClipsChildrenToShape. Setting the new flag makes QGraphicsScene assume that children are drawn within the shape of the current item but this is not enforced by clipping. When an application manually ensures this clipping boundary, setting the new flag removes the overhead of enforcing the clip with ItemClipsChildrenToShape, while still allowing other routines to behave more optimially by assuming children are within the shape of the current item. [ChangeLog][QtWidgets][QGraphicsItem] Added the ItemContainsChildrenInShape flag that enables using optimizations of ItemClipsChildrenToShape without the overhead of enforcing the clip. Change-Id: I5496fe1ca331b77fd51e0df8a3ace2b8e939eaf2 Reviewed-by: Andreas Aardal Hanssen <andreas@hanssen.name>
This commit is contained in:
parent
d13d03f012
commit
3270b4490b
@ -332,6 +332,8 @@
|
||||
this flag is disabled; children can draw anywhere. This behavior is
|
||||
enforced by QGraphicsView::drawItems() or
|
||||
QGraphicsScene::drawItems(). This flag was introduced in Qt 4.3.
|
||||
\note This flag is similar to ItemContainsChildrenInShape but in addition
|
||||
enforces the containment by clipping the children.
|
||||
|
||||
\value ItemIgnoresTransformations The item ignores inherited
|
||||
transformations (i.e., its position is still anchored to its parent, but
|
||||
@ -423,6 +425,19 @@
|
||||
ItemStopsClickFocusPropagation, but also suppresses focus-out. This flag
|
||||
allows you to completely take over focus handling.
|
||||
This flag was introduced in Qt 4.7. \endomit
|
||||
|
||||
\value ItemContainsChildrenInShape This flag indicates that all of the
|
||||
item's direct or indirect children only draw within the item's shape.
|
||||
Unlike ItemClipsChildrenToShape, this restriction is not enforced. Set
|
||||
ItemContainsChildrenInShape when you manually assure that drawing
|
||||
is bound to the item's shape and want to avoid the cost associated with
|
||||
enforcing the clip. Setting this flag enables more efficient drawing and
|
||||
collision detection. The flag is disabled by default.
|
||||
\note If both this flag and ItemClipsChildrenToShape are set, the clip
|
||||
will be enforced. This is equivalent to just setting
|
||||
ItemClipsChildrenToShape.
|
||||
.
|
||||
This flag was introduced in Qt 5.4.
|
||||
*/
|
||||
|
||||
/*!
|
||||
@ -836,6 +851,10 @@ void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag ch
|
||||
flag = AncestorIgnoresTransformations;
|
||||
enabled = flags & QGraphicsItem::ItemIgnoresTransformations;
|
||||
break;
|
||||
case QGraphicsItem::ItemContainsChildrenInShape:
|
||||
flag = AncestorContainsChildren;
|
||||
enabled = flags & QGraphicsItem::ItemContainsChildrenInShape;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@ -895,6 +914,8 @@ void QGraphicsItemPrivate::updateAncestorFlags()
|
||||
flags |= AncestorClipsChildren;
|
||||
if (pd->flags & QGraphicsItem::ItemIgnoresTransformations)
|
||||
flags |= AncestorIgnoresTransformations;
|
||||
if (pd->flags & QGraphicsItem::ItemContainsChildrenInShape)
|
||||
flags |= AncestorContainsChildren;
|
||||
}
|
||||
|
||||
if (ancestorFlags == flags)
|
||||
@ -1831,6 +1852,11 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags)
|
||||
d_ptr->markParentDirty(true);
|
||||
}
|
||||
|
||||
if ((flags & ItemContainsChildrenInShape) != (oldFlags & ItemContainsChildrenInShape)) {
|
||||
// Item children containtment changes. Propagate the ancestor flag to all children.
|
||||
d_ptr->updateAncestorFlag(ItemContainsChildrenInShape);
|
||||
}
|
||||
|
||||
if ((flags & ItemIgnoresTransformations) != (oldFlags & ItemIgnoresTransformations)) {
|
||||
// Item children clipping changes. Propagate the ancestor flag to
|
||||
// all children.
|
||||
@ -2322,7 +2348,8 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly,
|
||||
}
|
||||
|
||||
// Update children with explicitly = false.
|
||||
const bool updateChildren = update && !((flags & QGraphicsItem::ItemClipsChildrenToShape)
|
||||
const bool updateChildren = update && !((flags & QGraphicsItem::ItemClipsChildrenToShape
|
||||
|| flags & QGraphicsItem::ItemContainsChildrenInShape)
|
||||
&& !(flags & QGraphicsItem::ItemHasNoContents));
|
||||
foreach (QGraphicsItem *child, children) {
|
||||
if (!newVisible || !child->d_ptr->explicitlyHidden)
|
||||
@ -2835,7 +2862,9 @@ QRectF QGraphicsItemPrivate::effectiveBoundingRect(QGraphicsItem *topMostEffectI
|
||||
#ifndef QT_NO_GRAPHICSEFFECT
|
||||
Q_Q(const QGraphicsItem);
|
||||
QRectF brect = effectiveBoundingRect(q_ptr->boundingRect());
|
||||
if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren || topMostEffectItem == q)
|
||||
if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
|
||||
|| ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren
|
||||
|| topMostEffectItem == q)
|
||||
return brect;
|
||||
|
||||
const QGraphicsItem *effectParent = parent;
|
||||
@ -2847,6 +2876,7 @@ QRectF QGraphicsItemPrivate::effectiveBoundingRect(QGraphicsItem *topMostEffectI
|
||||
brect = effectParent->mapRectToItem(q, effectRectInParentSpace);
|
||||
}
|
||||
if (effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
|
||||
|| effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren
|
||||
|| topMostEffectItem == effectParent) {
|
||||
return brect;
|
||||
}
|
||||
@ -7442,7 +7472,8 @@ QVariant QGraphicsItem::extension(const QVariant &variant) const
|
||||
*/
|
||||
void QGraphicsItem::addToIndex()
|
||||
{
|
||||
if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) {
|
||||
if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
|
||||
|| d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren) {
|
||||
// ### add to child index only if applicable
|
||||
return;
|
||||
}
|
||||
@ -7459,7 +7490,8 @@ void QGraphicsItem::addToIndex()
|
||||
*/
|
||||
void QGraphicsItem::removeFromIndex()
|
||||
{
|
||||
if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) {
|
||||
if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
|
||||
|| d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren) {
|
||||
// ### remove from child index only if applicable
|
||||
return;
|
||||
}
|
||||
@ -11451,6 +11483,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag)
|
||||
case QGraphicsItem::ItemStopsFocusHandling:
|
||||
str = "ItemStopsFocusHandling";
|
||||
break;
|
||||
case QGraphicsItem::ItemContainsChildrenInShape:
|
||||
str = "ItemContainsChildrenInShape";
|
||||
break;
|
||||
}
|
||||
debug << str;
|
||||
return debug;
|
||||
|
@ -105,7 +105,8 @@ public:
|
||||
ItemIsFocusScope = 0x8000, // internal
|
||||
ItemSendsScenePositionChanges = 0x10000,
|
||||
ItemStopsClickFocusPropagation = 0x20000,
|
||||
ItemStopsFocusHandling = 0x40000
|
||||
ItemStopsFocusHandling = 0x40000,
|
||||
ItemContainsChildrenInShape = 0x80000
|
||||
// NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag.
|
||||
};
|
||||
Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag)
|
||||
|
@ -172,7 +172,8 @@ public:
|
||||
AncestorHandlesChildEvents = 0x1,
|
||||
AncestorClipsChildren = 0x2,
|
||||
AncestorIgnoresTransformations = 0x4,
|
||||
AncestorFiltersChildEvents = 0x8
|
||||
AncestorFiltersChildEvents = 0x8,
|
||||
AncestorContainsChildren = 0x10
|
||||
};
|
||||
|
||||
inline QGraphicsItemPrivate()
|
||||
@ -213,7 +214,6 @@ public:
|
||||
needSortChildren(0),
|
||||
allChildrenDirty(0),
|
||||
fullUpdatePending(0),
|
||||
dirtyChildrenBoundingRect(1),
|
||||
flags(0),
|
||||
paintedViewBoundingRectsNeedRepaint(0),
|
||||
dirtySceneTransform(1),
|
||||
@ -239,6 +239,7 @@ public:
|
||||
mayHaveChildWithGraphicsEffect(0),
|
||||
isDeclarativeItem(0),
|
||||
sendParentChangeNotification(0),
|
||||
dirtyChildrenBoundingRect(1),
|
||||
globalStackingOrder(-1),
|
||||
q_ptr(0)
|
||||
{
|
||||
@ -544,7 +545,7 @@ public:
|
||||
quint32 handlesChildEvents : 1;
|
||||
quint32 itemDiscovered : 1;
|
||||
quint32 hasCursor : 1;
|
||||
quint32 ancestorFlags : 4;
|
||||
quint32 ancestorFlags : 5;
|
||||
quint32 cacheMode : 2;
|
||||
quint32 hasBoundingRegionGranularity : 1;
|
||||
quint32 isWidget : 1;
|
||||
@ -555,10 +556,9 @@ public:
|
||||
quint32 needSortChildren : 1;
|
||||
quint32 allChildrenDirty : 1;
|
||||
quint32 fullUpdatePending : 1;
|
||||
quint32 dirtyChildrenBoundingRect : 1;
|
||||
|
||||
// Packed 32 bits
|
||||
quint32 flags : 19;
|
||||
quint32 flags : 20;
|
||||
quint32 paintedViewBoundingRectsNeedRepaint : 1;
|
||||
quint32 dirtySceneTransform : 1;
|
||||
quint32 geometryChanged : 1;
|
||||
@ -571,9 +571,9 @@ public:
|
||||
quint32 filtersDescendantEvents : 1;
|
||||
quint32 sceneTransformTranslateOnly : 1;
|
||||
quint32 notifyBoundingRectChanged : 1;
|
||||
quint32 notifyInvalidated : 1;
|
||||
|
||||
// New 32 bits
|
||||
quint32 notifyInvalidated : 1;
|
||||
quint32 mouseSetsFocus : 1;
|
||||
quint32 explicitActivate : 1;
|
||||
quint32 wantsActive : 1;
|
||||
@ -585,7 +585,8 @@ public:
|
||||
quint32 mayHaveChildWithGraphicsEffect : 1;
|
||||
quint32 isDeclarativeItem : 1;
|
||||
quint32 sendParentChangeNotification : 1;
|
||||
quint32 padding : 21;
|
||||
quint32 dirtyChildrenBoundingRect : 1;
|
||||
quint32 padding : 19;
|
||||
|
||||
// Optional stacking order
|
||||
int globalStackingOrder;
|
||||
|
@ -4717,7 +4717,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
|
||||
wasDirtyParentSceneTransform = true;
|
||||
}
|
||||
|
||||
const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
|
||||
const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
|
||||
|| item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape);
|
||||
bool drawItem = itemHasContents && !itemIsFullyTransparent;
|
||||
if (drawItem || minimumRenderSize > 0.0) {
|
||||
const QRectF brect = adjustedItemEffectiveBoundingRect(item);
|
||||
@ -5221,7 +5222,8 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool
|
||||
|
||||
// Process children.
|
||||
if (itemHasChildren && item->d_ptr->dirtyChildren) {
|
||||
const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape;
|
||||
const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
|
||||
|| item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape;
|
||||
// Items with no content are threated as 'dummy' items which means they are never drawn and
|
||||
// 'processed', so the painted view bounding rect is never up-to-date. This means that whenever
|
||||
// such an item changes geometry, its children have to take care of the update regardless
|
||||
|
@ -169,7 +169,8 @@ void QGraphicsSceneBspTreeIndexPrivate::_q_updateIndex()
|
||||
untransformableItems << item;
|
||||
continue;
|
||||
}
|
||||
if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
|
||||
if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
|
||||
|| item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)
|
||||
continue;
|
||||
|
||||
bsp.insertItem(item, item->d_ptr->sceneEffectiveBoundingRect());
|
||||
@ -351,7 +352,8 @@ void QGraphicsSceneBspTreeIndexPrivate::removeItem(QGraphicsItem *item, bool rec
|
||||
// Avoid virtual function calls from the destructor.
|
||||
purgePending = true;
|
||||
removedItems << item;
|
||||
} else if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
|
||||
} else if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
|
||||
|| item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)) {
|
||||
bsp.removeItem(item, item->d_ptr->sceneEffectiveBoundingRect());
|
||||
}
|
||||
} else {
|
||||
@ -510,7 +512,8 @@ void QGraphicsSceneBspTreeIndex::prepareBoundingRectChange(const QGraphicsItem *
|
||||
return;
|
||||
|
||||
if (item->d_ptr->index == -1 || item->d_ptr->itemIsUntransformable()
|
||||
|| (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
|
||||
|| (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
|
||||
|| item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)) {
|
||||
return; // Item is not in BSP tree; nothing to do.
|
||||
}
|
||||
|
||||
@ -641,8 +644,10 @@ void QGraphicsSceneBspTreeIndex::itemChange(const QGraphicsItem *item, QGraphics
|
||||
QGraphicsItem::GraphicsItemFlags newFlags = *static_cast<const QGraphicsItem::GraphicsItemFlags *>(value);
|
||||
bool ignoredTransform = item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations;
|
||||
bool willIgnoreTransform = newFlags & QGraphicsItem::ItemIgnoresTransformations;
|
||||
bool clipsChildren = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape;
|
||||
bool willClipChildren = newFlags & QGraphicsItem::ItemClipsChildrenToShape;
|
||||
bool clipsChildren = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
|
||||
|| item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape;
|
||||
bool willClipChildren = newFlags & QGraphicsItem::ItemClipsChildrenToShape
|
||||
|| newFlags & QGraphicsItem::ItemContainsChildrenInShape;
|
||||
if ((ignoredTransform != willIgnoreTransform) || (clipsChildren != willClipChildren)) {
|
||||
QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item);
|
||||
// Remove item and its descendants from the index and append
|
||||
@ -663,10 +668,13 @@ void QGraphicsSceneBspTreeIndex::itemChange(const QGraphicsItem *item, QGraphics
|
||||
bool ignoredTransform = item->d_ptr->itemIsUntransformable();
|
||||
bool willIgnoreTransform = (item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations)
|
||||
|| (newParent && newParent->d_ptr->itemIsUntransformable());
|
||||
bool ancestorClippedChildren = item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren;
|
||||
bool ancestorClippedChildren = item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
|
||||
|| item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren;
|
||||
bool ancestorWillClipChildren = newParent
|
||||
&& ((newParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)
|
||||
|| (newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren));
|
||||
&& ((newParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
|
||||
|| newParent->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape)
|
||||
|| (newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
|
||||
|| newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren));
|
||||
if ((ignoredTransform != willIgnoreTransform) || (ancestorClippedChildren != ancestorWillClipChildren)) {
|
||||
QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item);
|
||||
// Remove item and its descendants from the index and append
|
||||
|
@ -278,7 +278,8 @@ void QGraphicsSceneIndexPrivate::recursive_items_helper(QGraphicsItem *item, QRe
|
||||
Q_ASSERT(!item->d_ptr->dirtySceneTransform);
|
||||
}
|
||||
|
||||
const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
|
||||
const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
|
||||
|| item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape);
|
||||
bool processItem = !itemIsFullyTransparent;
|
||||
if (processItem) {
|
||||
processItem = intersect(item, exposeRect, mode, viewTransform, intersectData);
|
||||
|
@ -377,6 +377,8 @@ private slots:
|
||||
void itemClipsChildrenToShape5();
|
||||
void itemClipsTextChildToShape();
|
||||
void itemClippingDiscovery();
|
||||
void itemContainsChildrenInShape();
|
||||
void itemContainsChildrenInShape2();
|
||||
void ancestorFlags();
|
||||
void untransformable();
|
||||
void contextMenuEventPropagation();
|
||||
@ -5845,6 +5847,102 @@ void tst_QGraphicsItem::itemClippingDiscovery()
|
||||
QCOMPARE(scene.itemAt(90, 90), (QGraphicsItem *)0);
|
||||
}
|
||||
|
||||
class ItemCountsBoundingRectCalls : public QGraphicsRectItem
|
||||
{
|
||||
public:
|
||||
ItemCountsBoundingRectCalls(const QRectF & rect, QGraphicsItem *parent = 0)
|
||||
: QGraphicsRectItem(rect, parent), boundingRectCalls(0) {}
|
||||
QRectF boundingRect () const {
|
||||
++boundingRectCalls;
|
||||
return QGraphicsRectItem::boundingRect();
|
||||
}
|
||||
mutable int boundingRectCalls;
|
||||
};
|
||||
|
||||
void tst_QGraphicsItem::itemContainsChildrenInShape()
|
||||
{
|
||||
ItemCountsBoundingRectCalls *parent = new ItemCountsBoundingRectCalls(QRectF(0,0, 10, 10));
|
||||
ItemCountsBoundingRectCalls *childOutsideShape = new ItemCountsBoundingRectCalls(QRectF(0,0, 10, 10), parent);
|
||||
childOutsideShape->setPos(20,0);
|
||||
|
||||
QGraphicsScene scene;
|
||||
scene.setItemIndexMethod(QGraphicsScene::NoIndex);
|
||||
scene.addItem(parent);
|
||||
|
||||
QVERIFY(parent->boundingRectCalls == childOutsideShape->boundingRectCalls);
|
||||
|
||||
int oldParentBoundingRectCalls = parent->boundingRectCalls;
|
||||
int oldChildBoundingRectCalls = childOutsideShape->boundingRectCalls;
|
||||
|
||||
// First test that both items are searched if no optimization flags are set
|
||||
QGraphicsItem* item = scene.itemAt(25,5);
|
||||
|
||||
QVERIFY(item == childOutsideShape);
|
||||
QVERIFY(parent->boundingRectCalls > oldParentBoundingRectCalls);
|
||||
QVERIFY(childOutsideShape->boundingRectCalls > oldChildBoundingRectCalls);
|
||||
QVERIFY(parent->boundingRectCalls == childOutsideShape->boundingRectCalls);
|
||||
|
||||
oldParentBoundingRectCalls = parent->boundingRectCalls;
|
||||
oldChildBoundingRectCalls = childOutsideShape->boundingRectCalls;
|
||||
|
||||
// Repeat the test to make sure that no caching/indexing is in effect
|
||||
item = scene.itemAt(25,5);
|
||||
|
||||
QVERIFY(item == childOutsideShape);
|
||||
QVERIFY(parent->boundingRectCalls > oldParentBoundingRectCalls);
|
||||
QVERIFY(childOutsideShape->boundingRectCalls > oldChildBoundingRectCalls);
|
||||
QVERIFY(parent->boundingRectCalls == childOutsideShape->boundingRectCalls);
|
||||
|
||||
oldParentBoundingRectCalls = parent->boundingRectCalls;
|
||||
oldChildBoundingRectCalls = childOutsideShape->boundingRectCalls;
|
||||
|
||||
// Set the optimization flag and make sure that the child is not returned
|
||||
// and that the child's boundingRect() method is never called.
|
||||
parent->setFlag(QGraphicsItem::ItemContainsChildrenInShape);
|
||||
item = scene.itemAt(25,5);
|
||||
|
||||
QVERIFY(!(item));
|
||||
QVERIFY(parent->boundingRectCalls > oldParentBoundingRectCalls);
|
||||
QVERIFY(childOutsideShape->boundingRectCalls == oldChildBoundingRectCalls);
|
||||
QVERIFY(parent->boundingRectCalls > childOutsideShape->boundingRectCalls);
|
||||
}
|
||||
|
||||
void tst_QGraphicsItem::itemContainsChildrenInShape2()
|
||||
{
|
||||
//The tested flag behaves almost identically to ItemClipsChildrenToShape
|
||||
//in terms of optimizations but does not enforce the clip.
|
||||
//This test makes sure there is no clip.
|
||||
QGraphicsScene scene;
|
||||
QGraphicsItem *rect = scene.addRect(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::yellow));
|
||||
|
||||
QGraphicsItem *ellipse = scene.addEllipse(0, 0, 100, 100, QPen(Qt::NoPen), QBrush(Qt::green));
|
||||
ellipse->setParentItem(rect);
|
||||
|
||||
QGraphicsItem *clippedEllipse = scene.addEllipse(0, 0, 50, 50, QPen(Qt::NoPen), QBrush(Qt::blue));
|
||||
clippedEllipse->setParentItem(ellipse);
|
||||
|
||||
QGraphicsItem *clippedEllipse2 = scene.addEllipse(0, 0, 25, 25, QPen(Qt::NoPen), QBrush(Qt::red));
|
||||
clippedEllipse2->setParentItem(clippedEllipse);
|
||||
|
||||
QVERIFY(!(ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape));
|
||||
QVERIFY(!(ellipse->flags() & QGraphicsItem::ItemContainsChildrenInShape));
|
||||
ellipse->setFlags(QGraphicsItem::ItemContainsChildrenInShape);
|
||||
QVERIFY(!(ellipse->flags() & QGraphicsItem::ItemClipsChildrenToShape));
|
||||
QVERIFY((ellipse->flags() & QGraphicsItem::ItemContainsChildrenInShape));
|
||||
|
||||
QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
|
||||
image.fill(0);
|
||||
QPainter painter(&image);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
scene.render(&painter);
|
||||
painter.end();
|
||||
|
||||
QCOMPARE(image.pixel(2, 2), QColor(Qt::yellow).rgba());
|
||||
QCOMPARE(image.pixel(12, 12), QColor(Qt::red).rgba());
|
||||
QCOMPARE(image.pixel(2, 25), QColor(Qt::blue).rgba());
|
||||
QCOMPARE(image.pixel(2, 50), QColor(Qt::green).rgba());
|
||||
}
|
||||
|
||||
void tst_QGraphicsItem::ancestorFlags()
|
||||
{
|
||||
QGraphicsItem *level1 = new QGraphicsRectItem;
|
||||
@ -5965,11 +6063,27 @@ void tst_QGraphicsItem::ancestorFlags()
|
||||
// Nobody handles child events
|
||||
level21->setHandlesChildEvents(false);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
QGraphicsItem::GraphicsItemFlag flag = !i ? QGraphicsItem::ItemClipsChildrenToShape
|
||||
: QGraphicsItem::ItemIgnoresTransformations;
|
||||
int ancestorFlag = !i ? QGraphicsItemPrivate::AncestorClipsChildren
|
||||
: QGraphicsItemPrivate::AncestorIgnoresTransformations;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
QGraphicsItem::GraphicsItemFlag flag;
|
||||
int ancestorFlag;
|
||||
|
||||
switch (i) {
|
||||
case(0):
|
||||
flag = QGraphicsItem::ItemClipsChildrenToShape;
|
||||
ancestorFlag = QGraphicsItemPrivate::AncestorClipsChildren;
|
||||
break;
|
||||
case(1):
|
||||
flag = QGraphicsItem::ItemIgnoresTransformations;
|
||||
ancestorFlag = QGraphicsItemPrivate::AncestorIgnoresTransformations;
|
||||
break;
|
||||
case(2):
|
||||
flag = QGraphicsItem::ItemContainsChildrenInShape;
|
||||
ancestorFlag = QGraphicsItemPrivate::AncestorContainsChildren;
|
||||
break;
|
||||
default:
|
||||
qFatal("Unknown ancestor flag, please fix!");
|
||||
break;
|
||||
}
|
||||
|
||||
QCOMPARE(int(level1->d_ptr->ancestorFlags), 0);
|
||||
QCOMPARE(int(level21->d_ptr->ancestorFlags), 0);
|
||||
|
Loading…
Reference in New Issue
Block a user