diff options
Diffstat (limited to 'src/widgets/graphicsview')
-rw-r--r-- | src/widgets/graphicsview/qgraphicsitem.cpp | 43 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsitem.h | 13 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsitem_p.h | 17 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsscene.cpp | 92 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsscene.h | 4 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsscene_p.h | 2 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsscenebsptreeindex.cpp | 24 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicssceneevent.cpp | 58 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicssceneevent.h | 6 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicssceneindex.cpp | 3 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsscenelinearindex_p.h | 25 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsview.cpp | 10 |
12 files changed, 253 insertions, 44 deletions
diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index e327a8737a..551f229611 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -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; diff --git a/src/widgets/graphicsview/qgraphicsitem.h b/src/widgets/graphicsview/qgraphicsitem.h index 4283deb5b8..d0c6cc12af 100644 --- a/src/widgets/graphicsview/qgraphicsitem.h +++ b/src/widgets/graphicsview/qgraphicsitem.h @@ -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) @@ -1029,14 +1030,16 @@ private: template <class T> inline T qgraphicsitem_cast(QGraphicsItem *item) { - return int(static_cast<T>(0)->Type) == int(QGraphicsItem::Type) - || (item && int(static_cast<T>(0)->Type) == item->type()) ? static_cast<T>(item) : 0; + typedef typename QtPrivate::remove_cv<typename QtPrivate::remove_pointer<T>::type>::type Item; + return int(Item::Type) == int(QGraphicsItem::Type) + || (item && int(Item::Type) == item->type()) ? static_cast<T>(item) : 0; } template <class T> inline T qgraphicsitem_cast(const QGraphicsItem *item) { - return int(static_cast<T>(0)->Type) == int(QGraphicsItem::Type) - || (item && int(static_cast<T>(0)->Type) == item->type()) ? static_cast<T>(item) : 0; + typedef typename QtPrivate::remove_cv<typename QtPrivate::remove_pointer<T>::type>::type Item; + return int(Item::Type) == int(QGraphicsItem::Type) + || (item && int(Item::Type) == item->type()) ? static_cast<T>(item) : 0; } #ifndef QT_NO_DEBUG_STREAM diff --git a/src/widgets/graphicsview/qgraphicsitem_p.h b/src/widgets/graphicsview/qgraphicsitem_p.h index 3968d89a13..7e3a01ef8b 100644 --- a/src/widgets/graphicsview/qgraphicsitem_p.h +++ b/src/widgets/graphicsview/qgraphicsitem_p.h @@ -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) { @@ -317,7 +318,7 @@ public: virtual void resolvePalette(uint inheritedMask) { for (int i = 0; i < children.size(); ++i) - children.at(i)->d_ptr->resolveFont(inheritedMask); + children.at(i)->d_ptr->resolvePalette(inheritedMask); } virtual bool isProxyWidget() const; @@ -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; diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp index bccdb1fbaa..df74352e2b 100644 --- a/src/widgets/graphicsview/qgraphicsscene.cpp +++ b/src/widgets/graphicsview/qgraphicsscene.cpp @@ -299,6 +299,7 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() painterStateProtection(true), sortCacheEnabled(false), allItemsIgnoreTouchEvents(true), + minimumRenderSize(0.0), selectionChanging(0), rectAdjust(2), focusItem(0), @@ -1607,9 +1608,9 @@ void QGraphicsScenePrivate::updatePalette(const QPalette &palette) // whose parent is not a widget. foreach (QGraphicsItem *item, q->items()) { if (!item->parentItem()) { - // Resolvefont for an item is a noop operation, but + // ResolvePalette for an item is a noop operation, but // every item can be a widget, or can have a widget - // childre. + // children. item->d_ptr->resolvePalette(palette.resolve()); } } @@ -4716,19 +4717,40 @@ 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) { + if (drawItem || minimumRenderSize > 0.0) { const QRectF brect = adjustedItemEffectiveBoundingRect(item); ENSURE_TRANSFORM_PTR - QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toAlignedRect() - : transformPtr->mapRect(brect).toAlignedRect(); - viewBoundingRect.adjust(-int(rectAdjust), -int(rectAdjust), rectAdjust, rectAdjust); - if (widget) - item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); - drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) - : !viewBoundingRect.normalized().isEmpty(); - if (!drawItem) { + QRectF preciseViewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()) + : transformPtr->mapRect(brect); + + bool itemIsTooSmallToRender = false; + if (minimumRenderSize > 0.0 + && (preciseViewBoundingRect.width() < minimumRenderSize + || preciseViewBoundingRect.height() < minimumRenderSize)) { + itemIsTooSmallToRender = true; + drawItem = false; + } + + bool itemIsOutsideVisibleRect = false; + if (drawItem) { + QRect viewBoundingRect = preciseViewBoundingRect.toAlignedRect(); + viewBoundingRect.adjust(-int(rectAdjust), -int(rectAdjust), rectAdjust, rectAdjust); + if (widget) + item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); + drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) + : !viewBoundingRect.normalized().isEmpty(); + itemIsOutsideVisibleRect = !drawItem; + } + + if (itemIsTooSmallToRender || itemIsOutsideVisibleRect) { + // We cannot simply use !drawItem here. If we did it is possible + // to enter the outter if statement with drawItem == false and minimumRenderSize > 0 + // and finally end up inside this inner if, even though none of the above two + // conditions are met. In that case we should not return from this function + // but call draw() instead. if (!itemHasChildren) return; if (itemClipsChildrenToShape) { @@ -5200,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 @@ -5729,6 +5752,49 @@ bool QGraphicsScene::sendEvent(QGraphicsItem *item, QEvent *event) return d->sendEvent(item, event); } +/*! + \property QGraphicsScene::minimumRenderSize + \since 5.4 + \brief the minimal view-transformed size an item must have to be drawn + + When the scene is rendered, any item whose width or height, transformed + to the target view, is smaller that minimumRenderSize(), will not be + rendered. If an item is not rendered and it clips its children items + they will also not be rendered. Set this value to speed up rendering + of scenes with many objects rendered on a zoomed out view. + + The default value is 0. If unset, or if set to 0 or a negative value, + all items will always be rendered. + + For example, setting this property can be especially useful if a scene + is rendered by multiple views, one of which serves as an overview which + always displays all items. In scenes with many items, such a view will + use a high scaling factor so that all items can be shown. Due to the + scaling, smaller items will only make an insignificant contribution to + the final rendered scene. To avoid drawing these items and reduce the + time necessary to render the scene, you can call setMinimumRenderSize() + with a non-negative value. + + \note Items that are not drawn as a result of being too small, are still + returned by methods such as items() and itemAt(), and participate in + collision detection and interactions. It is recommended that you set + minimumRenderSize() to a value less than or equal to 1 in order to + avoid large unrendered items that are interactive. + + \sa QStyleOptionGraphicsItem::levelOfDetailFromTransform() +*/ +qreal QGraphicsScene::minimumRenderSize() const +{ + Q_D(const QGraphicsScene); + return d->minimumRenderSize; +} +void QGraphicsScene::setMinimumRenderSize(qreal minSize) +{ + Q_D(QGraphicsScene); + d->minimumRenderSize = minSize; + update(); +} + void QGraphicsScenePrivate::addView(QGraphicsView *view) { views << view; diff --git a/src/widgets/graphicsview/qgraphicsscene.h b/src/widgets/graphicsview/qgraphicsscene.h index cde0eda125..ba47d45d63 100644 --- a/src/widgets/graphicsview/qgraphicsscene.h +++ b/src/widgets/graphicsview/qgraphicsscene.h @@ -107,6 +107,7 @@ class Q_WIDGETS_EXPORT QGraphicsScene : public QObject Q_PROPERTY(QFont font READ font WRITE setFont) Q_PROPERTY(bool sortCacheEnabled READ isSortCacheEnabled WRITE setSortCacheEnabled) Q_PROPERTY(bool stickyFocus READ stickyFocus WRITE setStickyFocus) + Q_PROPERTY(qreal minimumRenderSize READ minimumRenderSize WRITE setMinimumRenderSize) public: enum ItemIndexMethod { @@ -249,6 +250,9 @@ public: bool sendEvent(QGraphicsItem *item, QEvent *event); + qreal minimumRenderSize() const; + void setMinimumRenderSize(qreal minSize); + public Q_SLOTS: void update(const QRectF &rect = QRectF()); void invalidate(const QRectF &rect = QRectF(), SceneLayers layers = AllLayers); diff --git a/src/widgets/graphicsview/qgraphicsscene_p.h b/src/widgets/graphicsview/qgraphicsscene_p.h index 9e5bcec488..9f50dcfea7 100644 --- a/src/widgets/graphicsview/qgraphicsscene_p.h +++ b/src/widgets/graphicsview/qgraphicsscene_p.h @@ -117,6 +117,8 @@ public: quint32 allItemsIgnoreTouchEvents : 1; quint32 padding : 15; + qreal minimumRenderSize; + QRectF growingItemsBoundingRect; void _q_emitUpdated(); diff --git a/src/widgets/graphicsview/qgraphicsscenebsptreeindex.cpp b/src/widgets/graphicsview/qgraphicsscenebsptreeindex.cpp index 7598163f2d..50f17ab73f 100644 --- a/src/widgets/graphicsview/qgraphicsscenebsptreeindex.cpp +++ b/src/widgets/graphicsview/qgraphicsscenebsptreeindex.cpp @@ -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 diff --git a/src/widgets/graphicsview/qgraphicssceneevent.cpp b/src/widgets/graphicsview/qgraphicssceneevent.cpp index 631aa7bf19..be91c63fad 100644 --- a/src/widgets/graphicsview/qgraphicssceneevent.cpp +++ b/src/widgets/graphicsview/qgraphicssceneevent.cpp @@ -348,7 +348,7 @@ class QGraphicsSceneMouseEventPrivate : public QGraphicsSceneEventPrivate public: inline QGraphicsSceneMouseEventPrivate() : button(Qt::NoButton), - buttons(0), modifiers(0) + buttons(0), modifiers(0), source(Qt::MouseEventNotSynthesized), flags(0) { } QPointF pos; @@ -363,6 +363,8 @@ public: Qt::MouseButton button; Qt::MouseButtons buttons; Qt::KeyboardModifiers modifiers; + Qt::MouseEventSource source; + Qt::MouseEventFlags flags; }; /*! @@ -626,6 +628,60 @@ Qt::KeyboardModifiers QGraphicsSceneMouseEvent::modifiers() const } /*! + \since 5.4 + + Returns information about the mouse event source. + + The mouse event source can be used to distinguish between genuine + and artificial mouse events. The latter are events that are + synthesized from touch events by the operating system or Qt itself. + + \sa Qt::MouseEventSource + \sa QMouseEvent::source() + */ +Qt::MouseEventSource QGraphicsSceneMouseEvent::source() const +{ + Q_D(const QGraphicsSceneMouseEvent); + return d->source; +} + +/*! + \since 5.4 + \internal + */ +void QGraphicsSceneMouseEvent::setSource(Qt::MouseEventSource source) +{ + Q_D(QGraphicsSceneMouseEvent); + d->source = source; +} + +/*! + \since 5.4 + + Returns the mouse event flags. + + The mouse event flags provide additional information about a mouse event. + + \sa Qt::MouseEventFlag + \sa QMouseEvent::flags() + */ +Qt::MouseEventFlags QGraphicsSceneMouseEvent::flags() const +{ + Q_D(const QGraphicsSceneMouseEvent); + return d->flags; +} + +/*! + \since 5.4 + \internal + */ +void QGraphicsSceneMouseEvent::setFlags(Qt::MouseEventFlags flags) +{ + Q_D(QGraphicsSceneMouseEvent); + d->flags = flags; +} + +/*! \internal */ void QGraphicsSceneMouseEvent::setModifiers(Qt::KeyboardModifiers modifiers) diff --git a/src/widgets/graphicsview/qgraphicssceneevent.h b/src/widgets/graphicsview/qgraphicssceneevent.h index e744d08edf..2c9c1f3f50 100644 --- a/src/widgets/graphicsview/qgraphicssceneevent.h +++ b/src/widgets/graphicsview/qgraphicssceneevent.h @@ -121,6 +121,12 @@ public: Qt::KeyboardModifiers modifiers() const; void setModifiers(Qt::KeyboardModifiers modifiers); + Qt::MouseEventSource source() const; + void setSource(Qt::MouseEventSource source); + + Qt::MouseEventFlags flags() const; + void setFlags(Qt::MouseEventFlags); + private: Q_DECLARE_PRIVATE(QGraphicsSceneMouseEvent) Q_DISABLE_COPY(QGraphicsSceneMouseEvent) diff --git a/src/widgets/graphicsview/qgraphicssceneindex.cpp b/src/widgets/graphicsview/qgraphicssceneindex.cpp index 40f63937f4..d06c5523ca 100644 --- a/src/widgets/graphicsview/qgraphicssceneindex.cpp +++ b/src/widgets/graphicsview/qgraphicssceneindex.cpp @@ -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); diff --git a/src/widgets/graphicsview/qgraphicsscenelinearindex_p.h b/src/widgets/graphicsview/qgraphicsscenelinearindex_p.h index 7debcfb501..5788818394 100644 --- a/src/widgets/graphicsview/qgraphicsscenelinearindex_p.h +++ b/src/widgets/graphicsview/qgraphicsscenelinearindex_p.h @@ -70,7 +70,7 @@ class Q_AUTOTEST_EXPORT QGraphicsSceneLinearIndex : public QGraphicsSceneIndex Q_OBJECT public: - QGraphicsSceneLinearIndex(QGraphicsScene *scene = 0) : QGraphicsSceneIndex(scene) + QGraphicsSceneLinearIndex(QGraphicsScene *scene = 0) : QGraphicsSceneIndex(scene), m_numSortedElements(0) { } QList<QGraphicsItem *> items(Qt::SortOrder order = Qt::DescendingOrder) const @@ -85,16 +85,35 @@ public: protected : virtual void clear() - { m_items.clear(); } + { + m_items.clear(); + m_numSortedElements = 0; + } virtual void addItem(QGraphicsItem *item) { m_items << item; } virtual void removeItem(QGraphicsItem *item) - { m_items.removeOne(item); } + { + // Sort m_items if needed + if (m_numSortedElements < m_items.size()) + { + std::sort(m_items.begin() + m_numSortedElements, m_items.end() ); + std::inplace_merge(m_items.begin(), m_items.begin() + m_numSortedElements, m_items.end()); + m_numSortedElements = m_items.size(); + } + + QList<QGraphicsItem*>::iterator element = std::lower_bound(m_items.begin(), m_items.end(), item); + if (element != m_items.end() && *element == item) + { + m_items.erase(element); + --m_numSortedElements; + } + } private: QList<QGraphicsItem*> m_items; + int m_numSortedElements; }; #endif // QT_NO_GRAPHICSVIEW diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp index 5bcf52b6a3..7bdfae5fec 100644 --- a/src/widgets/graphicsview/qgraphicsview.cpp +++ b/src/widgets/graphicsview/qgraphicsview.cpp @@ -655,6 +655,8 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event) mouseEvent.setButtons(event->buttons()); mouseEvent.setButton(event->button()); mouseEvent.setModifiers(event->modifiers()); + mouseEvent.setSource(event->source()); + mouseEvent.setFlags(event->flags()); lastMouseMoveScenePoint = mouseEvent.scenePos(); lastMouseMoveScreenPoint = mouseEvent.screenPos(); mouseEvent.setAccepted(false); @@ -2760,7 +2762,7 @@ void QGraphicsView::setupViewport(QWidget *widget) return; } - const bool isGLWidget = widget->inherits("QGLWidget"); + const bool isGLWidget = widget->inherits("QGLWidget") || widget->inherits("QOpenGLWidget"); d->accelerateScrolling = !(isGLWidget); @@ -3217,6 +3219,8 @@ void QGraphicsView::mouseDoubleClickEvent(QMouseEvent *event) mouseEvent.setAccepted(false); mouseEvent.setButton(event->button()); mouseEvent.setModifiers(event->modifiers()); + mouseEvent.setSource(event->source()); + mouseEvent.setFlags(event->flags()); if (event->spontaneous()) qt_sendSpontaneousEvent(d->scene, &mouseEvent); else @@ -3265,6 +3269,8 @@ void QGraphicsView::mousePressEvent(QMouseEvent *event) mouseEvent.setButtons(event->buttons()); mouseEvent.setButton(event->button()); mouseEvent.setModifiers(event->modifiers()); + mouseEvent.setSource(event->source()); + mouseEvent.setFlags(event->flags()); mouseEvent.setAccepted(false); if (event->spontaneous()) qt_sendSpontaneousEvent(d->scene, &mouseEvent); @@ -3392,6 +3398,8 @@ void QGraphicsView::mouseReleaseEvent(QMouseEvent *event) mouseEvent.setButtons(event->buttons()); mouseEvent.setButton(event->button()); mouseEvent.setModifiers(event->modifiers()); + mouseEvent.setSource(event->source()); + mouseEvent.setFlags(event->flags()); mouseEvent.setAccepted(false); if (event->spontaneous()) qt_sendSpontaneousEvent(d->scene, &mouseEvent); |