84void QGraphicsSceneBspTreeIndexPrivate::_q_updateIndex()
86 if (!indexTimer.isActive())
94 for (
int i = 0; i < unindexedItems.size(); ++i) {
95 if (QGraphicsItem *item = unindexedItems.at(i)) {
96 Q_ASSERT(!item->d_ptr->itemDiscovered);
97 if (!freeItemIndexes.isEmpty()) {
98 int freeIndex = freeItemIndexes.takeFirst();
99 item->d_func()->index = freeIndex;
100 indexedItems[freeIndex] = item;
102 item->d_func()->index = indexedItems.size();
103 indexedItems << item;
109 if (bspTreeDepth == 0) {
110 int oldDepth = intmaxlog(lastItemCount);
111 bspTreeDepth = intmaxlog(indexedItems.size());
112 static const int slack = 100;
113 if (bsp.leafCount() == 0 || (oldDepth != bspTreeDepth && qAbs(lastItemCount - indexedItems.size()) > slack)) {
115 regenerateIndex =
true;
120 if (regenerateIndex) {
121 regenerateIndex =
false;
122 bsp.initialize(sceneRect, bspTreeDepth);
123 unindexedItems = indexedItems;
124 lastItemCount = indexedItems.size();
128 for (
int i = 0; i < unindexedItems.size(); ++i) {
129 if (QGraphicsItem *item = unindexedItems.at(i)) {
130 if (item->d_ptr->itemIsUntransformable()) {
131 untransformableItems << item;
134 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
135 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)
138 bsp.insertItem(item, item->d_ptr->sceneEffectiveBoundingRect());
141 unindexedItems.clear();
172void QGraphicsSceneBspTreeIndexPrivate::startIndexTimer(
int interval)
174 Q_Q(QGraphicsSceneBspTreeIndex);
175 if (indexTimer.isActive()) {
176 restartIndexTimer =
true;
178 indexTimer.start(interval * 1ms, q);
185void QGraphicsSceneBspTreeIndexPrivate::resetIndex()
188 for (
int i = 0; i < indexedItems.size(); ++i) {
189 if (QGraphicsItem *item = indexedItems.at(i)) {
190 item->d_ptr->index = -1;
191 Q_ASSERT(!item->d_ptr->itemDiscovered);
192 unindexedItems << item;
195 indexedItems.clear();
196 freeItemIndexes.clear();
197 untransformableItems.clear();
198 regenerateIndex =
true;
205void QGraphicsSceneBspTreeIndexPrivate::climbTree(QGraphicsItem *item,
int *stackingOrder)
207 if (!item->d_ptr->children.isEmpty()) {
208 QList<QGraphicsItem *> childList = item->d_ptr->children;
209 std::sort(childList.begin(), childList.end(), qt_closestLeaf);
210 for (
int i = 0; i < childList.size(); ++i) {
211 QGraphicsItem *item = childList.at(i);
212 if (!(item->flags() & QGraphicsItem::ItemStacksBehindParent))
213 climbTree(childList.at(i), stackingOrder);
215 item->d_ptr->globalStackingOrder = (*stackingOrder)++;
216 for (
int i = 0; i < childList.size(); ++i) {
217 QGraphicsItem *item = childList.at(i);
218 if (item->flags() & QGraphicsItem::ItemStacksBehindParent)
219 climbTree(childList.at(i), stackingOrder);
222 item->d_ptr->globalStackingOrder = (*stackingOrder)++;
229void QGraphicsSceneBspTreeIndexPrivate::_q_updateSortCache()
231 Q_Q(QGraphicsSceneBspTreeIndex);
234 if (!sortCacheEnabled || !updatingSortCache)
237 updatingSortCache =
false;
238 int stackingOrder = 0;
240 QList<QGraphicsItem *> topLevels;
241 const QList<QGraphicsItem *> items = q->items();
242 for (
int i = 0; i < items.size(); ++i) {
243 QGraphicsItem *item = items.at(i);
244 if (item && !item->d_ptr->parent)
248 std::sort(topLevels.begin(), topLevels.end(), qt_closestLeaf);
249 for (
int i = 0; i < topLevels.size(); ++i)
250 climbTree(topLevels.at(i), &stackingOrder);
256void QGraphicsSceneBspTreeIndexPrivate::invalidateSortCache()
258 Q_Q(QGraphicsSceneBspTreeIndex);
259 if (!sortCacheEnabled || updatingSortCache)
262 updatingSortCache =
true;
263 QMetaObject::invokeMethod(q,
"_q_updateSortCache", Qt::QueuedConnection);
266void QGraphicsSceneBspTreeIndexPrivate::addItem(QGraphicsItem *item,
bool recursive)
276 item->d_ptr->globalStackingOrder = -1;
277 invalidateSortCache();
282 if (item->d_ptr->index == -1) {
283 Q_ASSERT(!unindexedItems.contains(item));
284 unindexedItems << item;
287 Q_ASSERT(indexedItems.contains(item));
288 qWarning(
"QGraphicsSceneBspTreeIndex::addItem: item has already been added to this BSP");
292 for (
int i = 0; i < item->d_ptr->children.size(); ++i)
293 addItem(item->d_ptr->children.at(i), recursive);
297void QGraphicsSceneBspTreeIndexPrivate::removeItem(QGraphicsItem *item,
bool recursive,
298 bool moveToUnindexedItems)
303 if (item->d_ptr->index != -1) {
304 Q_ASSERT(item->d_ptr->index < indexedItems.size());
305 Q_ASSERT(indexedItems.at(item->d_ptr->index) == item);
306 Q_ASSERT(!item->d_ptr->itemDiscovered);
307 freeItemIndexes << item->d_ptr->index;
308 indexedItems[item->d_ptr->index] = 0;
309 item->d_ptr->index = -1;
311 if (item->d_ptr->itemIsUntransformable()) {
312 untransformableItems.removeOne(item);
313 }
else if (item->d_ptr->inDestructor) {
316 removedItems << item;
317 }
else if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
318 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)) {
319 bsp.removeItem(item, item->d_ptr->sceneEffectiveBoundingRect());
322 unindexedItems.removeOne(item);
324 invalidateSortCache();
326 Q_ASSERT(item->d_ptr->index == -1);
327 Q_ASSERT(!indexedItems.contains(item));
328 Q_ASSERT(!unindexedItems.contains(item));
329 Q_ASSERT(!untransformableItems.contains(item));
331 if (moveToUnindexedItems)
335 for (
int i = 0; i < item->d_ptr->children.size(); ++i)
336 removeItem(item->d_ptr->children.at(i), recursive, moveToUnindexedItems);
340QList<QGraphicsItem *> QGraphicsSceneBspTreeIndexPrivate::estimateItems(
const QRectF &rect, Qt::SortOrder order,
341 bool onlyTopLevelItems)
343 Q_Q(QGraphicsSceneBspTreeIndex);
344 if (onlyTopLevelItems && rect.isNull())
345 return q->QGraphicsSceneIndex::estimateTopLevelItems(rect, order);
348 _q_updateSortCache();
349 Q_ASSERT(unindexedItems.isEmpty());
351 QList<QGraphicsItem *> rectItems = bsp.items(rect, onlyTopLevelItems);
352 if (onlyTopLevelItems) {
353 for (
int i = 0; i < untransformableItems.size(); ++i) {
354 QGraphicsItem *item = untransformableItems.at(i);
355 if (!item->d_ptr->parent) {
358 item = item->topLevelItem();
359 if (!rectItems.contains(item))
364 rectItems += untransformableItems;
367 sortItems(&rectItems, order, sortCacheEnabled, onlyTopLevelItems);
376void QGraphicsSceneBspTreeIndexPrivate::sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order,
377 bool sortCacheEnabled,
bool onlyTopLevelItems)
379 if (order == Qt::SortOrder(-1))
382 if (onlyTopLevelItems) {
383 if (order == Qt::DescendingOrder)
384 std::sort(itemList->begin(), itemList->end(), qt_closestLeaf);
385 else if (order == Qt::AscendingOrder)
386 std::sort(itemList->begin(), itemList->end(), qt_notclosestLeaf);
390 if (sortCacheEnabled) {
391 if (order == Qt::DescendingOrder) {
392 std::sort(itemList->begin(), itemList->end(), closestItemFirst_withCache);
393 }
else if (order == Qt::AscendingOrder) {
394 std::sort(itemList->begin(), itemList->end(), closestItemLast_withCache);
397 if (order == Qt::DescendingOrder) {
398 std::sort(itemList->begin(), itemList->end(), qt_closestItemFirst);
399 }
else if (order == Qt::AscendingOrder) {
400 std::sort(itemList->begin(), itemList->end(), qt_closestItemLast);
414QGraphicsSceneBspTreeIndex::~QGraphicsSceneBspTreeIndex()
416 Q_D(QGraphicsSceneBspTreeIndex);
417 for (
int i = 0; i < d->indexedItems.size(); ++i) {
419 if (QGraphicsItem *item = d->indexedItems.at(i)) {
420 Q_ASSERT(!item->d_ptr->itemDiscovered);
421 item->d_ptr->index = -1;
430void QGraphicsSceneBspTreeIndex::clear()
432 Q_D(QGraphicsSceneBspTreeIndex);
434 d->lastItemCount = 0;
435 d->freeItemIndexes.clear();
436 for (
int i = 0; i < d->indexedItems.size(); ++i) {
438 if (QGraphicsItem *item = d->indexedItems.at(i)) {
439 Q_ASSERT(!item->d_ptr->itemDiscovered);
440 item->d_ptr->index = -1;
443 d->indexedItems.clear();
444 d->unindexedItems.clear();
445 d->untransformableItems.clear();
446 d->regenerateIndex =
true;
471void QGraphicsSceneBspTreeIndex::prepareBoundingRectChange(
const QGraphicsItem *item)
476 if (item->d_ptr->index == -1 || item->d_ptr->itemIsUntransformable()
477 || (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
478 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)) {
482 Q_D(QGraphicsSceneBspTreeIndex);
483 QGraphicsItem *thatItem =
const_cast<QGraphicsItem *>(item);
484 d->removeItem(thatItem,
false,
true);
485 for (
int i = 0; i < item->d_ptr->children.size(); ++i)
486 prepareBoundingRectChange(item->d_ptr->children.at(i));
496QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::estimateItems(
const QRectF &rect, Qt::SortOrder order)
const
498 Q_D(
const QGraphicsSceneBspTreeIndex);
499 return const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->estimateItems(rect, order);
502QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::estimateTopLevelItems(
const QRectF &rect, Qt::SortOrder order)
const
504 Q_D(
const QGraphicsSceneBspTreeIndex);
505 return const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->estimateItems(rect, order,
true);
513QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::items(Qt::SortOrder order)
const
515 Q_D(
const QGraphicsSceneBspTreeIndex);
516 const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->purgeRemovedItems();
517 QList<QGraphicsItem *> itemList;
518 itemList.reserve(d->indexedItems.size() + d->unindexedItems.size());
522 QGraphicsItem *null =
nullptr;
525 std::remove_copy(d->indexedItems.cbegin(), d->indexedItems.cend(),
526 std::back_inserter(itemList), null);
527 std::remove_copy(d->unindexedItems.cbegin(), d->unindexedItems.cend(),
528 std::back_inserter(itemList), null);
530 d->sortItems(&itemList, order, d->sortCacheEnabled);
595void QGraphicsSceneBspTreeIndex::itemChange(
const QGraphicsItem *item, QGraphicsItem::GraphicsItemChange change,
const void *
const value)
597 Q_D(QGraphicsSceneBspTreeIndex);
599 case QGraphicsItem::ItemFlagsChange: {
601 QGraphicsItem::GraphicsItemFlags newFlags = *
static_cast<
const QGraphicsItem::GraphicsItemFlags *>(value);
602 bool ignoredTransform = item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations;
603 bool willIgnoreTransform = newFlags & QGraphicsItem::ItemIgnoresTransformations;
604 bool clipsChildren = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
605 || item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape;
606 bool willClipChildren = newFlags & QGraphicsItem::ItemClipsChildrenToShape
607 || newFlags & QGraphicsItem::ItemContainsChildrenInShape;
608 if ((ignoredTransform != willIgnoreTransform) || (clipsChildren != willClipChildren)) {
609 QGraphicsItem *thatItem =
const_cast<QGraphicsItem *>(item);
614 d->removeItem(thatItem,
true,
true);
618 case QGraphicsItem::ItemZValueChange:
619 d->invalidateSortCache();
621 case QGraphicsItem::ItemParentChange: {
622 d->invalidateSortCache();
624 const QGraphicsItem *newParent =
static_cast<
const QGraphicsItem *>(value);
625 bool ignoredTransform = item->d_ptr->itemIsUntransformable();
626 bool willIgnoreTransform = (item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations)
627 || (newParent && newParent->d_ptr->itemIsUntransformable());
628 bool ancestorClippedChildren = item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
629 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren;
630 bool ancestorWillClipChildren = newParent
631 && ((newParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
632 || newParent->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape)
633 || (newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
634 || newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren));
635 if ((ignoredTransform != willIgnoreTransform) || (ancestorClippedChildren != ancestorWillClipChildren)) {
636 QGraphicsItem *thatItem =
const_cast<QGraphicsItem *>(item);
641 d->removeItem(thatItem,
true,
true);
656bool QGraphicsSceneBspTreeIndex::event(QEvent *event)
658 Q_D(QGraphicsSceneBspTreeIndex);
659 if (event->type() == QEvent::Timer) {
660 if (d->indexTimer.isActive() &&
static_cast<QTimerEvent *>(event)->id() == d->indexTimer.id()) {
661 if (d->restartIndexTimer) {
662 d->restartIndexTimer =
false;
669 return QObject::event(event);