88void QGraphicsSceneBspTreeIndexPrivate::_q_updateIndex()
90 if (!indexTimer.isActive())
98 for (
int i = 0; i < unindexedItems.size(); ++i) {
99 if (QGraphicsItem *item = unindexedItems.at(i)) {
100 Q_ASSERT(!item->d_ptr->itemDiscovered);
101 if (!freeItemIndexes.isEmpty()) {
102 int freeIndex = freeItemIndexes.takeFirst();
103 item->d_func()->index = freeIndex;
104 indexedItems[freeIndex] = item;
106 item->d_func()->index = indexedItems.size();
107 indexedItems << item;
113 if (bspTreeDepth == 0) {
114 int oldDepth = intmaxlog(lastItemCount);
115 bspTreeDepth = intmaxlog(indexedItems.size());
116 static const int slack = 100;
117 if (bsp.leafCount() == 0 || (oldDepth != bspTreeDepth && qAbs(lastItemCount - indexedItems.size()) > slack)) {
119 regenerateIndex =
true;
124 if (regenerateIndex) {
125 regenerateIndex =
false;
126 bsp.initialize(sceneRect, bspTreeDepth);
127 unindexedItems = indexedItems;
128 lastItemCount = indexedItems.size();
132 for (
int i = 0; i < unindexedItems.size(); ++i) {
133 if (QGraphicsItem *item = unindexedItems.at(i)) {
134 if (item->d_ptr->itemIsUntransformable()) {
135 untransformableItems << item;
138 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
139 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)
142 bsp.insertItem(item, item->d_ptr->sceneEffectiveBoundingRect());
145 unindexedItems.clear();
176void QGraphicsSceneBspTreeIndexPrivate::startIndexTimer(
int interval)
178 Q_Q(QGraphicsSceneBspTreeIndex);
179 if (indexTimer.isActive()) {
180 restartIndexTimer =
true;
182 indexTimer.start(interval * 1ms, q);
189void QGraphicsSceneBspTreeIndexPrivate::resetIndex()
192 for (
int i = 0; i < indexedItems.size(); ++i) {
193 if (QGraphicsItem *item = indexedItems.at(i)) {
194 item->d_ptr->index = -1;
195 Q_ASSERT(!item->d_ptr->itemDiscovered);
196 unindexedItems << item;
199 indexedItems.clear();
200 freeItemIndexes.clear();
201 untransformableItems.clear();
202 regenerateIndex =
true;
209void QGraphicsSceneBspTreeIndexPrivate::climbTree(QGraphicsItem *item,
int *stackingOrder)
211 if (!item->d_ptr->children.isEmpty()) {
212 QList<QGraphicsItem *> childList = item->d_ptr->children;
213 std::sort(childList.begin(), childList.end(), qt_closestLeaf);
214 for (
int i = 0; i < childList.size(); ++i) {
215 QGraphicsItem *item = childList.at(i);
216 if (!(item->flags() & QGraphicsItem::ItemStacksBehindParent))
217 climbTree(childList.at(i), stackingOrder);
219 item->d_ptr->globalStackingOrder = (*stackingOrder)++;
220 for (
int i = 0; i < childList.size(); ++i) {
221 QGraphicsItem *item = childList.at(i);
222 if (item->flags() & QGraphicsItem::ItemStacksBehindParent)
223 climbTree(childList.at(i), stackingOrder);
226 item->d_ptr->globalStackingOrder = (*stackingOrder)++;
233void QGraphicsSceneBspTreeIndexPrivate::_q_updateSortCache()
235 Q_Q(QGraphicsSceneBspTreeIndex);
238 if (!sortCacheEnabled || !updatingSortCache)
241 updatingSortCache =
false;
242 int stackingOrder = 0;
244 QList<QGraphicsItem *> topLevels;
245 const QList<QGraphicsItem *> items = q->items();
246 for (
int i = 0; i < items.size(); ++i) {
247 QGraphicsItem *item = items.at(i);
248 if (item && !item->d_ptr->parent)
252 std::sort(topLevels.begin(), topLevels.end(), qt_closestLeaf);
253 for (
int i = 0; i < topLevels.size(); ++i)
254 climbTree(topLevels.at(i), &stackingOrder);
260void QGraphicsSceneBspTreeIndexPrivate::invalidateSortCache()
262 Q_Q(QGraphicsSceneBspTreeIndex);
263 if (!sortCacheEnabled || updatingSortCache)
266 updatingSortCache =
true;
267 QMetaObject::invokeMethod(q,
"_q_updateSortCache", Qt::QueuedConnection);
270void QGraphicsSceneBspTreeIndexPrivate::addItem(QGraphicsItem *item,
bool recursive)
280 item->d_ptr->globalStackingOrder = -1;
281 invalidateSortCache();
286 if (item->d_ptr->index == -1) {
287 Q_ASSERT(!unindexedItems.contains(item));
288 unindexedItems << item;
291 Q_ASSERT(indexedItems.contains(item));
292 qWarning(
"QGraphicsSceneBspTreeIndex::addItem: item has already been added to this BSP");
296 for (
int i = 0; i < item->d_ptr->children.size(); ++i)
297 addItem(item->d_ptr->children.at(i), recursive);
301void QGraphicsSceneBspTreeIndexPrivate::removeItem(QGraphicsItem *item,
bool recursive,
302 bool moveToUnindexedItems)
307 if (item->d_ptr->index != -1) {
308 Q_ASSERT(item->d_ptr->index < indexedItems.size());
309 Q_ASSERT(indexedItems.at(item->d_ptr->index) == item);
310 Q_ASSERT(!item->d_ptr->itemDiscovered);
311 freeItemIndexes << item->d_ptr->index;
312 indexedItems[item->d_ptr->index] = 0;
313 item->d_ptr->index = -1;
315 if (item->d_ptr->itemIsUntransformable()) {
316 untransformableItems.removeOne(item);
317 }
else if (item->d_ptr->inDestructor) {
320 removedItems << item;
321 }
else if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
322 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)) {
323 bsp.removeItem(item, item->d_ptr->sceneEffectiveBoundingRect());
326 unindexedItems.removeOne(item);
328 invalidateSortCache();
330 Q_ASSERT(item->d_ptr->index == -1);
331 Q_ASSERT(!indexedItems.contains(item));
332 Q_ASSERT(!unindexedItems.contains(item));
333 Q_ASSERT(!untransformableItems.contains(item));
335 if (moveToUnindexedItems)
339 for (
int i = 0; i < item->d_ptr->children.size(); ++i)
340 removeItem(item->d_ptr->children.at(i), recursive, moveToUnindexedItems);
344QList<QGraphicsItem *> QGraphicsSceneBspTreeIndexPrivate::estimateItems(
const QRectF &rect, Qt::SortOrder order,
345 bool onlyTopLevelItems)
347 Q_Q(QGraphicsSceneBspTreeIndex);
348 if (onlyTopLevelItems && rect.isNull())
349 return q->QGraphicsSceneIndex::estimateTopLevelItems(rect, order);
352 _q_updateSortCache();
353 Q_ASSERT(unindexedItems.isEmpty());
355 QList<QGraphicsItem *> rectItems = bsp.items(rect, onlyTopLevelItems);
356 if (onlyTopLevelItems) {
357 for (
int i = 0; i < untransformableItems.size(); ++i) {
358 QGraphicsItem *item = untransformableItems.at(i);
359 if (!item->d_ptr->parent) {
362 item = item->topLevelItem();
363 if (!rectItems.contains(item))
368 rectItems += untransformableItems;
371 sortItems(&rectItems, order, sortCacheEnabled, onlyTopLevelItems);
380void QGraphicsSceneBspTreeIndexPrivate::sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order,
381 bool sortCacheEnabled,
bool onlyTopLevelItems)
383 if (order == Qt::SortOrder(-1))
386 if (onlyTopLevelItems) {
387 if (order == Qt::DescendingOrder)
388 std::sort(itemList->begin(), itemList->end(), qt_closestLeaf);
389 else if (order == Qt::AscendingOrder)
390 std::sort(itemList->begin(), itemList->end(), qt_notclosestLeaf);
394 if (sortCacheEnabled) {
395 if (order == Qt::DescendingOrder) {
396 std::sort(itemList->begin(), itemList->end(), closestItemFirst_withCache);
397 }
else if (order == Qt::AscendingOrder) {
398 std::sort(itemList->begin(), itemList->end(), closestItemLast_withCache);
401 if (order == Qt::DescendingOrder) {
402 std::sort(itemList->begin(), itemList->end(), qt_closestItemFirst);
403 }
else if (order == Qt::AscendingOrder) {
404 std::sort(itemList->begin(), itemList->end(), qt_closestItemLast);
418QGraphicsSceneBspTreeIndex::~QGraphicsSceneBspTreeIndex()
420 Q_D(QGraphicsSceneBspTreeIndex);
421 for (
int i = 0; i < d->indexedItems.size(); ++i) {
423 if (QGraphicsItem *item = d->indexedItems.at(i)) {
424 Q_ASSERT(!item->d_ptr->itemDiscovered);
425 item->d_ptr->index = -1;
434void QGraphicsSceneBspTreeIndex::clear()
436 Q_D(QGraphicsSceneBspTreeIndex);
438 d->lastItemCount = 0;
439 d->freeItemIndexes.clear();
440 for (
int i = 0; i < d->indexedItems.size(); ++i) {
442 if (QGraphicsItem *item = d->indexedItems.at(i)) {
443 Q_ASSERT(!item->d_ptr->itemDiscovered);
444 item->d_ptr->index = -1;
447 d->indexedItems.clear();
448 d->unindexedItems.clear();
449 d->untransformableItems.clear();
450 d->regenerateIndex =
true;
475void QGraphicsSceneBspTreeIndex::prepareBoundingRectChange(
const QGraphicsItem *item)
480 if (item->d_ptr->index == -1 || item->d_ptr->itemIsUntransformable()
481 || (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
482 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)) {
486 Q_D(QGraphicsSceneBspTreeIndex);
487 QGraphicsItem *thatItem =
const_cast<QGraphicsItem *>(item);
488 d->removeItem(thatItem,
false,
true);
489 for (
int i = 0; i < item->d_ptr->children.size(); ++i)
490 prepareBoundingRectChange(item->d_ptr->children.at(i));
500QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::estimateItems(
const QRectF &rect, Qt::SortOrder order)
const
502 Q_D(
const QGraphicsSceneBspTreeIndex);
503 return const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->estimateItems(rect, order);
506QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::estimateTopLevelItems(
const QRectF &rect, Qt::SortOrder order)
const
508 Q_D(
const QGraphicsSceneBspTreeIndex);
509 return const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->estimateItems(rect, order,
true);
517QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::items(Qt::SortOrder order)
const
519 Q_D(
const QGraphicsSceneBspTreeIndex);
520 const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->purgeRemovedItems();
521 QList<QGraphicsItem *> itemList;
522 itemList.reserve(d->indexedItems.size() + d->unindexedItems.size());
526 QGraphicsItem *null =
nullptr;
529 std::remove_copy(d->indexedItems.cbegin(), d->indexedItems.cend(),
530 std::back_inserter(itemList), null);
531 std::remove_copy(d->unindexedItems.cbegin(), d->unindexedItems.cend(),
532 std::back_inserter(itemList), null);
534 d->sortItems(&itemList, order, d->sortCacheEnabled);
599void QGraphicsSceneBspTreeIndex::itemChange(
const QGraphicsItem *item, QGraphicsItem::GraphicsItemChange change,
const void *
const value)
601 Q_D(QGraphicsSceneBspTreeIndex);
603 case QGraphicsItem::ItemFlagsChange: {
605 QGraphicsItem::GraphicsItemFlags newFlags = *
static_cast<
const QGraphicsItem::GraphicsItemFlags *>(value);
606 bool ignoredTransform = item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations;
607 bool willIgnoreTransform = newFlags & QGraphicsItem::ItemIgnoresTransformations;
608 bool clipsChildren = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
609 || item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape;
610 bool willClipChildren = newFlags & QGraphicsItem::ItemClipsChildrenToShape
611 || newFlags & QGraphicsItem::ItemContainsChildrenInShape;
612 if ((ignoredTransform != willIgnoreTransform) || (clipsChildren != willClipChildren)) {
613 QGraphicsItem *thatItem =
const_cast<QGraphicsItem *>(item);
618 d->removeItem(thatItem,
true,
true);
622 case QGraphicsItem::ItemZValueChange:
623 d->invalidateSortCache();
625 case QGraphicsItem::ItemParentChange: {
626 d->invalidateSortCache();
628 const QGraphicsItem *newParent =
static_cast<
const QGraphicsItem *>(value);
629 bool ignoredTransform = item->d_ptr->itemIsUntransformable();
630 bool willIgnoreTransform = (item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations)
631 || (newParent && newParent->d_ptr->itemIsUntransformable());
632 bool ancestorClippedChildren = item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
633 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren;
634 bool ancestorWillClipChildren = newParent
635 && ((newParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
636 || newParent->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape)
637 || (newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
638 || newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren));
639 if ((ignoredTransform != willIgnoreTransform) || (ancestorClippedChildren != ancestorWillClipChildren)) {
640 QGraphicsItem *thatItem =
const_cast<QGraphicsItem *>(item);
645 d->removeItem(thatItem,
true,
true);
660bool QGraphicsSceneBspTreeIndex::event(QEvent *event)
662 Q_D(QGraphicsSceneBspTreeIndex);
663 if (event->type() == QEvent::Timer) {
664 if (d->indexTimer.isActive() &&
static_cast<QTimerEvent *>(event)->id() == d->indexTimer.id()) {
665 if (d->restartIndexTimer) {
666 d->restartIndexTimer =
false;
673 return QObject::event(event);