1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QGRAPHICSITEM_P_H |
5 | #define QGRAPHICSITEM_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists for the convenience |
12 | // of other Qt classes. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <QtWidgets/private/qtwidgetsglobal_p.h> |
19 | #include "qgraphicsitem.h" |
20 | #include "qset.h" |
21 | #include "qpixmapcache.h" |
22 | #include <private/qgraphicsview_p.h> |
23 | #include "qgraphicstransform.h" |
24 | #include <private/qgraphicstransform_p.h> |
25 | |
26 | #include <QtCore/qpoint.h> |
27 | |
28 | QT_REQUIRE_CONFIG(graphicsview); |
29 | |
30 | QT_BEGIN_NAMESPACE |
31 | |
32 | class QGraphicsItemPrivate; |
33 | |
34 | class QGraphicsItemCache |
35 | { |
36 | public: |
37 | QGraphicsItemCache() : allExposed(false) { } |
38 | |
39 | // ItemCoordinateCache only |
40 | QRect boundingRect; |
41 | QSize fixedSize; |
42 | QPixmapCache::Key key; |
43 | |
44 | // DeviceCoordinateCache only |
45 | struct DeviceData { |
46 | DeviceData() {} |
47 | QTransform lastTransform; |
48 | QPoint cacheIndent; |
49 | QPixmapCache::Key key; |
50 | }; |
51 | QHash<QPaintDevice *, DeviceData> deviceData; |
52 | |
53 | // List of logical exposed rects |
54 | QList<QRectF> exposed; |
55 | bool allExposed; |
56 | |
57 | // Empty cache |
58 | void purge(); |
59 | }; |
60 | |
61 | class Q_WIDGETS_EXPORT QGraphicsItemPrivate |
62 | { |
63 | Q_DECLARE_PUBLIC(QGraphicsItem) |
64 | public: |
65 | enum { |
66 | , |
67 | , |
68 | , |
69 | , |
70 | |
71 | }; |
72 | |
73 | enum AncestorFlag { |
74 | NoFlag = 0, |
75 | AncestorHandlesChildEvents = 0x1, |
76 | AncestorClipsChildren = 0x2, |
77 | AncestorIgnoresTransformations = 0x4, |
78 | AncestorFiltersChildEvents = 0x8, |
79 | AncestorContainsChildren = 0x10 |
80 | }; |
81 | |
82 | QGraphicsItemPrivate(); |
83 | virtual ~QGraphicsItemPrivate(); |
84 | |
85 | static const QGraphicsItemPrivate *get(const QGraphicsItem *item) |
86 | { |
87 | return item->d_ptr.data(); |
88 | } |
89 | static QGraphicsItemPrivate *get(QGraphicsItem *item) |
90 | { |
91 | return item->d_ptr.data(); |
92 | } |
93 | |
94 | void updateChildWithGraphicsEffectFlagRecursively(); |
95 | void updateAncestorFlag(QGraphicsItem::GraphicsItemFlag childFlag, |
96 | AncestorFlag flag = NoFlag, bool enabled = false, bool root = true); |
97 | void updateAncestorFlags(); |
98 | void setIsMemberOfGroup(bool enabled); |
99 | void remapItemPos(QEvent *event, QGraphicsItem *item); |
100 | QTransform genericMapFromSceneTransform(const QWidget *viewport = nullptr) const; |
101 | QPointF genericMapFromScene(const QPointF &pos, const QWidget *viewport) const; |
102 | inline bool itemIsUntransformable() const |
103 | { |
104 | return (flags & QGraphicsItem::ItemIgnoresTransformations) |
105 | || (ancestorFlags & AncestorIgnoresTransformations); |
106 | } |
107 | |
108 | void combineTransformToParent(QTransform *x, const QTransform *viewTransform = nullptr) const; |
109 | void combineTransformFromParent(QTransform *x, const QTransform *viewTransform = nullptr) const; |
110 | virtual void updateSceneTransformFromParent(); |
111 | |
112 | static bool movableAncestorIsSelected(const QGraphicsItem *item); |
113 | |
114 | virtual void setPosHelper(const QPointF &pos); |
115 | void setTransformHelper(const QTransform &transform); |
116 | void prependGraphicsTransform(QGraphicsTransform *t); |
117 | void appendGraphicsTransform(QGraphicsTransform *t); |
118 | void setVisibleHelper(bool newVisible, bool explicitly, bool update = true, |
119 | bool hiddenByPanel = false); |
120 | void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true); |
121 | bool discardUpdateRequest(bool ignoreVisibleBit = false, |
122 | bool ignoreDirtyBit = false, bool ignoreOpacity = false) const; |
123 | virtual void transformChanged() {} |
124 | int depth() const; |
125 | #if QT_CONFIG(graphicseffect) |
126 | enum InvalidateReason { |
127 | OpacityChanged |
128 | }; |
129 | void invalidateParentGraphicsEffectsRecursively(); |
130 | void invalidateChildGraphicsEffectsRecursively(InvalidateReason reason); |
131 | #endif // QT_CONFIG(graphicseffect) |
132 | void invalidateDepthRecursively(); |
133 | void resolveDepth(); |
134 | void addChild(QGraphicsItem *child); |
135 | void removeChild(QGraphicsItem *child); |
136 | void setParentItemHelper(QGraphicsItem *parent, const QVariant *newParentVariant, |
137 | const QVariant *thisPointerVariant); |
138 | void childrenBoundingRectHelper(QTransform *x, QRectF *rect, QGraphicsItem *topMostEffectItem); |
139 | void initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform, |
140 | const QRegion &exposedRegion, bool allItems = false) const; |
141 | QRectF effectiveBoundingRect(QGraphicsItem *topMostEffectItem = nullptr) const; |
142 | QRectF sceneEffectiveBoundingRect() const; |
143 | |
144 | QRectF effectiveBoundingRect(const QRectF &rect) const; |
145 | |
146 | virtual void resolveFont(uint inheritedMask) |
147 | { |
148 | for (int i = 0; i < children.size(); ++i) |
149 | children.at(i)->d_ptr->resolveFont(inheritedMask); |
150 | } |
151 | |
152 | virtual void resolvePalette(uint inheritedMask) |
153 | { |
154 | for (int i = 0; i < children.size(); ++i) |
155 | children.at(i)->d_ptr->resolvePalette(inheritedMask); |
156 | } |
157 | |
158 | virtual bool isProxyWidget() const; |
159 | |
160 | inline QVariant (Extra type) const |
161 | { |
162 | for (int i = 0; i < extras.size(); ++i) { |
163 | const ExtraStruct & = extras.at(i); |
164 | if (extra.type == type) |
165 | return extra.value; |
166 | } |
167 | return QVariant(); |
168 | } |
169 | |
170 | inline void (Extra type, const QVariant &value) |
171 | { |
172 | int index = -1; |
173 | for (int i = 0; i < extras.size(); ++i) { |
174 | if (extras.at(i).type == type) { |
175 | index = i; |
176 | break; |
177 | } |
178 | } |
179 | |
180 | if (index == -1) { |
181 | extras << ExtraStruct(type, value); |
182 | } else { |
183 | extras[index].value = value; |
184 | } |
185 | } |
186 | |
187 | inline void (Extra type) |
188 | { |
189 | for (int i = 0; i < extras.size(); ++i) { |
190 | if (extras.at(i).type == type) { |
191 | extras.removeAt(i); |
192 | return; |
193 | } |
194 | } |
195 | } |
196 | |
197 | struct { |
198 | () { } // for QList, don't use |
199 | (Extra type, const QVariant &value) |
200 | : type(type), value(value) |
201 | { } |
202 | |
203 | Extra ; |
204 | QVariant ; |
205 | |
206 | bool (Extra ) const |
207 | { return type < extra; } |
208 | }; |
209 | |
210 | QList<ExtraStruct> ; |
211 | |
212 | QGraphicsItemCache *() const; |
213 | QGraphicsItemCache *() const; |
214 | void (); |
215 | |
216 | void updatePaintedViewBoundingRects(bool updateChildren); |
217 | void ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem); |
218 | inline void ensureSceneTransform() |
219 | { |
220 | QGraphicsItem *that = q_func(); |
221 | ensureSceneTransformRecursive(topMostDirtyItem: &that); |
222 | } |
223 | |
224 | inline bool hasTranslateOnlySceneTransform() |
225 | { |
226 | ensureSceneTransform(); |
227 | return sceneTransformTranslateOnly; |
228 | } |
229 | |
230 | inline void invalidateChildrenSceneTransform() |
231 | { |
232 | for (int i = 0; i < children.size(); ++i) |
233 | children.at(i)->d_ptr->dirtySceneTransform = 1; |
234 | } |
235 | |
236 | inline qreal calcEffectiveOpacity() const |
237 | { |
238 | qreal o = opacity; |
239 | QGraphicsItem *p = parent; |
240 | int myFlags = flags; |
241 | while (p) { |
242 | int parentFlags = p->d_ptr->flags; |
243 | |
244 | // If I have a parent, and I don't ignore my parent's opacity, and my |
245 | // parent propagates to me, then combine my local opacity with my parent's |
246 | // effective opacity into my effective opacity. |
247 | if ((myFlags & QGraphicsItem::ItemIgnoresParentOpacity) |
248 | || (parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) { |
249 | break; |
250 | } |
251 | |
252 | o *= p->d_ptr->opacity; |
253 | p = p->d_ptr->parent; |
254 | myFlags = parentFlags; |
255 | } |
256 | return o; |
257 | } |
258 | |
259 | inline bool isOpacityNull() const |
260 | { return (opacity < qreal(0.001)); } |
261 | |
262 | static inline bool isOpacityNull(qreal opacity) |
263 | { return (opacity < qreal(0.001)); } |
264 | |
265 | inline bool isFullyTransparent() const |
266 | { |
267 | if (isOpacityNull()) |
268 | return true; |
269 | if (!parent) |
270 | return false; |
271 | |
272 | return isOpacityNull(opacity: calcEffectiveOpacity()); |
273 | } |
274 | |
275 | inline qreal effectiveOpacity() const { |
276 | if (!parent || !opacity) |
277 | return opacity; |
278 | |
279 | return calcEffectiveOpacity(); |
280 | } |
281 | |
282 | inline qreal combineOpacityFromParent(qreal parentOpacity) const |
283 | { |
284 | if (parent && !(flags & QGraphicsItem::ItemIgnoresParentOpacity) |
285 | && !(parent->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) { |
286 | return parentOpacity * opacity; |
287 | } |
288 | return opacity; |
289 | } |
290 | |
291 | inline bool childrenCombineOpacity() const |
292 | { |
293 | if (!children.size()) |
294 | return true; |
295 | if (flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren) |
296 | return false; |
297 | |
298 | for (int i = 0; i < children.size(); ++i) { |
299 | if (children.at(i)->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity) |
300 | return false; |
301 | } |
302 | return true; |
303 | } |
304 | |
305 | inline bool childrenClippedToShape() const |
306 | { return (flags & QGraphicsItem::ItemClipsChildrenToShape) || children.isEmpty(); } |
307 | |
308 | inline bool isInvisible() const |
309 | { |
310 | return !visible || (childrenCombineOpacity() && isFullyTransparent()); |
311 | } |
312 | |
313 | inline void markParentDirty(bool updateBoundingRect = false); |
314 | |
315 | void setFocusHelper(Qt::FocusReason focusReason, bool climb, bool focusFromHide); |
316 | void clearFocusHelper(bool giveFocusToParent, bool hiddenByParentPanel); |
317 | void setSubFocus(QGraphicsItem *rootItem = nullptr, QGraphicsItem *stopItem = nullptr); |
318 | void clearSubFocus(QGraphicsItem *rootItem = nullptr, QGraphicsItem *stopItem = nullptr); |
319 | void resetFocusProxy(); |
320 | virtual void subFocusItemChange(); |
321 | virtual void focusScopeItemChange(bool isSubFocusItem); |
322 | |
323 | inline QTransform transformToParent() const; |
324 | inline void ensureSortedChildren(); |
325 | static inline bool insertionOrder(QGraphicsItem *a, QGraphicsItem *b); |
326 | void ensureSequentialSiblingIndex(); |
327 | inline void sendScenePosChange(); |
328 | virtual void siblingOrderChange(); |
329 | |
330 | // Private Properties |
331 | virtual qreal width() const; |
332 | virtual void setWidth(qreal); |
333 | virtual void resetWidth(); |
334 | |
335 | virtual qreal height() const; |
336 | virtual void setHeight(qreal); |
337 | virtual void resetHeight(); |
338 | |
339 | QRectF childrenBoundingRect; |
340 | QRectF needsRepaint; |
341 | QHash<QWidget *, QRect> paintedViewBoundingRects; |
342 | QPointF pos; |
343 | qreal z; |
344 | qreal opacity; |
345 | QGraphicsScene *scene; |
346 | QGraphicsItem *parent; |
347 | QList<QGraphicsItem *> children; |
348 | struct TransformData; |
349 | TransformData *transformData; |
350 | QGraphicsEffect *graphicsEffect; |
351 | QTransform sceneTransform; |
352 | int index; |
353 | int siblingIndex; |
354 | int itemDepth; // Lazily calculated when calling depth(). |
355 | QGraphicsItem *focusProxy; |
356 | QList<QGraphicsItem **> focusProxyRefs; |
357 | QGraphicsItem *subFocusItem; |
358 | QGraphicsItem *focusScopeItem; |
359 | Qt::InputMethodHints imHints; |
360 | QGraphicsItem::PanelModality panelModality; |
361 | #ifndef QT_NO_GESTURES |
362 | QMap<Qt::GestureType, Qt::GestureFlags> gestureContext; |
363 | #endif |
364 | |
365 | // Packed 32 bits |
366 | quint32 acceptedMouseButtons : 5; |
367 | quint32 visible : 1; |
368 | quint32 explicitlyHidden : 1; |
369 | quint32 enabled : 1; |
370 | quint32 explicitlyDisabled : 1; |
371 | quint32 selected : 1; |
372 | quint32 acceptsHover : 1; |
373 | quint32 acceptDrops : 1; |
374 | quint32 isMemberOfGroup : 1; |
375 | quint32 handlesChildEvents : 1; |
376 | quint32 itemDiscovered : 1; |
377 | quint32 hasCursor : 1; |
378 | quint32 ancestorFlags : 5; |
379 | quint32 cacheMode : 2; |
380 | quint32 hasBoundingRegionGranularity : 1; |
381 | quint32 isWidget : 1; |
382 | quint32 dirty : 1; |
383 | quint32 dirtyChildren : 1; |
384 | quint32 localCollisionHack : 1; |
385 | quint32 inSetPosHelper : 1; |
386 | quint32 needSortChildren : 1; |
387 | quint32 allChildrenDirty : 1; |
388 | quint32 fullUpdatePending : 1; |
389 | |
390 | // Packed 32 bits |
391 | quint32 flags : 20; |
392 | quint32 paintedViewBoundingRectsNeedRepaint : 1; |
393 | quint32 dirtySceneTransform : 1; |
394 | quint32 geometryChanged : 1; |
395 | quint32 inDestructor : 1; |
396 | quint32 isObject : 1; |
397 | quint32 ignoreVisible : 1; |
398 | quint32 ignoreOpacity : 1; |
399 | quint32 acceptTouchEvents : 1; |
400 | quint32 acceptedTouchBeginEvent : 1; |
401 | quint32 filtersDescendantEvents : 1; |
402 | quint32 sceneTransformTranslateOnly : 1; |
403 | quint32 notifyBoundingRectChanged : 1; |
404 | #ifdef Q_OS_WASM |
405 | unsigned char :0; //this aligns 64bit field for wasm see QTBUG-65259 |
406 | #endif |
407 | // New 32 bits |
408 | quint32 notifyInvalidated : 1; |
409 | quint32 mouseSetsFocus : 1; |
410 | quint32 explicitActivate : 1; |
411 | quint32 wantsActive : 1; |
412 | quint32 holesInSiblingIndex : 1; |
413 | quint32 sequentialOrdering : 1; |
414 | quint32 updateDueToGraphicsEffect : 1; |
415 | quint32 scenePosDescendants : 1; |
416 | quint32 pendingPolish : 1; |
417 | quint32 mayHaveChildWithGraphicsEffect : 1; |
418 | quint32 sendParentChangeNotification : 1; |
419 | quint32 dirtyChildrenBoundingRect : 1; |
420 | quint32 padding : 20; |
421 | |
422 | // Optional stacking order |
423 | int globalStackingOrder; |
424 | QGraphicsItem *q_ptr; |
425 | }; |
426 | Q_DECLARE_TYPEINFO(QGraphicsItemPrivate::ExtraStruct, Q_RELOCATABLE_TYPE); |
427 | |
428 | struct QGraphicsItemPrivate::TransformData |
429 | { |
430 | QTransform transform; |
431 | qreal scale; |
432 | qreal rotation; |
433 | qreal xOrigin; |
434 | qreal yOrigin; |
435 | QList<QGraphicsTransform *> graphicsTransforms; |
436 | bool onlyTransform; |
437 | |
438 | TransformData() : |
439 | scale(1.0), rotation(0.0), |
440 | xOrigin(0.0), yOrigin(0.0), |
441 | onlyTransform(true) |
442 | { } |
443 | |
444 | QTransform computedFullTransform(QTransform *postmultiplyTransform = nullptr) const |
445 | { |
446 | if (onlyTransform) { |
447 | if (!postmultiplyTransform || postmultiplyTransform->isIdentity()) |
448 | return transform; |
449 | if (transform.isIdentity()) |
450 | return *postmultiplyTransform; |
451 | return transform * *postmultiplyTransform; |
452 | } |
453 | |
454 | QTransform x(transform); |
455 | if (!graphicsTransforms.isEmpty()) { |
456 | QMatrix4x4 m; |
457 | for (int i = 0; i < graphicsTransforms.size(); ++i) |
458 | graphicsTransforms.at(i)->applyTo(matrix: &m); |
459 | x *= m.toTransform(); |
460 | } |
461 | x.translate(dx: xOrigin, dy: yOrigin); |
462 | x.rotate(a: rotation); |
463 | x.scale(sx: scale, sy: scale); |
464 | x.translate(dx: -xOrigin, dy: -yOrigin); |
465 | if (postmultiplyTransform) |
466 | x *= *postmultiplyTransform; |
467 | return x; |
468 | } |
469 | }; |
470 | |
471 | struct QGraphicsItemPaintInfo |
472 | { |
473 | inline QGraphicsItemPaintInfo(const QTransform *const xform1, const QTransform *const xform2, |
474 | const QTransform *const xform3, |
475 | QRegion *r, QWidget *w, QStyleOptionGraphicsItem *opt, |
476 | QPainter *p, qreal o, bool b1, bool b2) |
477 | : viewTransform(xform1), transformPtr(xform2), effectTransform(xform3), exposedRegion(r), widget(w), |
478 | option(opt), painter(p), opacity(o), wasDirtySceneTransform(b1), drawItem(b2) |
479 | {} |
480 | |
481 | const QTransform *viewTransform; |
482 | const QTransform *transformPtr; |
483 | const QTransform *effectTransform; |
484 | QRegion *exposedRegion; |
485 | QWidget *widget; |
486 | QStyleOptionGraphicsItem *option; |
487 | QPainter *painter; |
488 | qreal opacity; |
489 | quint32 wasDirtySceneTransform : 1; |
490 | quint32 drawItem : 1; |
491 | }; |
492 | |
493 | #if QT_CONFIG(graphicseffect) |
494 | class QGraphicsItemEffectSourcePrivate : public QGraphicsEffectSourcePrivate |
495 | { |
496 | public: |
497 | QGraphicsItemEffectSourcePrivate(QGraphicsItem *i) |
498 | : QGraphicsEffectSourcePrivate(), item(i), info(nullptr) |
499 | {} |
500 | |
501 | void detach() override |
502 | { |
503 | item->d_ptr->graphicsEffect = nullptr; |
504 | item->prepareGeometryChange(); |
505 | } |
506 | |
507 | const QGraphicsItem *graphicsItem() const override |
508 | { return item; } |
509 | |
510 | const QWidget *widget() const override |
511 | { return nullptr; } |
512 | |
513 | void update() override { |
514 | item->d_ptr->updateDueToGraphicsEffect = true; |
515 | item->update(); |
516 | item->d_ptr->updateDueToGraphicsEffect = false; |
517 | } |
518 | |
519 | void effectBoundingRectChanged() override |
520 | { item->prepareGeometryChange(); } |
521 | |
522 | bool isPixmap() const override |
523 | { |
524 | return item->type() == QGraphicsPixmapItem::Type |
525 | && !(item->flags() & QGraphicsItem::ItemIsSelectable) |
526 | && item->d_ptr->children.size() == 0; |
527 | } |
528 | |
529 | const QStyleOption *styleOption() const override |
530 | { return info ? info->option : nullptr; } |
531 | |
532 | QRect deviceRect() const override |
533 | { |
534 | if (!info || !info->widget) { |
535 | qWarning(msg: "QGraphicsEffectSource::deviceRect: Not yet implemented, lacking device context" ); |
536 | return QRect(); |
537 | } |
538 | return info->widget->rect(); |
539 | } |
540 | |
541 | QRectF boundingRect(Qt::CoordinateSystem system) const override; |
542 | void draw(QPainter *) override; |
543 | QPixmap pixmap(Qt::CoordinateSystem system, |
544 | QPoint *offset, |
545 | QGraphicsEffect::PixmapPadMode mode) const override; |
546 | QRectF paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded = nullptr) const; |
547 | |
548 | QGraphicsItem *item; |
549 | QGraphicsItemPaintInfo *info; |
550 | QTransform lastEffectTransform; |
551 | }; |
552 | #endif // QT_CONFIG(graphicseffect) |
553 | |
554 | /*! |
555 | Returns \c true if \a item1 is on top of \a item2. |
556 | The items don't need to be siblings. |
557 | |
558 | \internal |
559 | */ |
560 | inline bool qt_closestItemFirst(const QGraphicsItem *item1, const QGraphicsItem *item2) |
561 | { |
562 | // Siblings? Just check their z-values. |
563 | const QGraphicsItemPrivate *d1 = item1->d_ptr.data(); |
564 | const QGraphicsItemPrivate *d2 = item2->d_ptr.data(); |
565 | if (d1->parent == d2->parent) |
566 | return qt_closestLeaf(item1, item2); |
567 | |
568 | // Find common ancestor, and each item's ancestor closest to the common |
569 | // ancestor. |
570 | int item1Depth = d1->depth(); |
571 | int item2Depth = d2->depth(); |
572 | const QGraphicsItem *p = item1; |
573 | const QGraphicsItem *t1 = item1; |
574 | while (item1Depth > item2Depth && (p = p->d_ptr->parent)) { |
575 | if (p == item2) { |
576 | // item2 is one of item1's ancestors; item1 is on top |
577 | return !(t1->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent); |
578 | } |
579 | t1 = p; |
580 | --item1Depth; |
581 | } |
582 | p = item2; |
583 | const QGraphicsItem *t2 = item2; |
584 | while (item2Depth > item1Depth && (p = p->d_ptr->parent)) { |
585 | if (p == item1) { |
586 | // item1 is one of item2's ancestors; item1 is not on top |
587 | return (t2->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent); |
588 | } |
589 | t2 = p; |
590 | --item2Depth; |
591 | } |
592 | |
593 | // item1Ancestor is now at the same level as item2Ancestor, but not the same. |
594 | const QGraphicsItem *p1 = t1; |
595 | const QGraphicsItem *p2 = t2; |
596 | while (t1 && t1 != t2) { |
597 | p1 = t1; |
598 | p2 = t2; |
599 | t1 = t1->d_ptr->parent; |
600 | t2 = t2->d_ptr->parent; |
601 | } |
602 | |
603 | // in case we have a common ancestor, we compare the immediate children in the ancestor's path. |
604 | // otherwise we compare the respective items' topLevelItems directly. |
605 | return qt_closestLeaf(p1, p2); |
606 | } |
607 | |
608 | /*! |
609 | Returns \c true if \a item2 is on top of \a item1. |
610 | The items don't need to be siblings. |
611 | |
612 | \internal |
613 | */ |
614 | inline bool qt_closestItemLast(const QGraphicsItem *item1, const QGraphicsItem *item2) |
615 | { |
616 | return qt_closestItemFirst(item1: item2, item2: item1); |
617 | } |
618 | |
619 | /*! |
620 | \internal |
621 | */ |
622 | inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2) |
623 | { |
624 | // Return true if sibling item1 is on top of item2. |
625 | const QGraphicsItemPrivate *d1 = item1->d_ptr.data(); |
626 | const QGraphicsItemPrivate *d2 = item2->d_ptr.data(); |
627 | bool f1 = d1->flags & QGraphicsItem::ItemStacksBehindParent; |
628 | bool f2 = d2->flags & QGraphicsItem::ItemStacksBehindParent; |
629 | if (f1 != f2) |
630 | return f2; |
631 | if (d1->z != d2->z) |
632 | return d1->z > d2->z; |
633 | return d1->siblingIndex > d2->siblingIndex; |
634 | } |
635 | |
636 | /*! |
637 | \internal |
638 | */ |
639 | inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2) |
640 | { return qt_closestLeaf(item1: item2, item2: item1); } |
641 | |
642 | /* |
643 | return the full transform of the item to the parent. This include the position and all the transform data |
644 | */ |
645 | inline QTransform QGraphicsItemPrivate::transformToParent() const |
646 | { |
647 | QTransform matrix; |
648 | combineTransformToParent(x: &matrix); |
649 | return matrix; |
650 | } |
651 | |
652 | /*! |
653 | \internal |
654 | */ |
655 | inline void QGraphicsItemPrivate::ensureSortedChildren() |
656 | { |
657 | if (needSortChildren) { |
658 | needSortChildren = 0; |
659 | sequentialOrdering = 1; |
660 | if (children.isEmpty()) |
661 | return; |
662 | std::sort(first: children.begin(), last: children.end(), comp: qt_notclosestLeaf); |
663 | for (int i = 0; i < children.size(); ++i) { |
664 | if (children.at(i)->d_ptr->siblingIndex != i) { |
665 | sequentialOrdering = 0; |
666 | break; |
667 | } |
668 | } |
669 | } |
670 | } |
671 | |
672 | /*! |
673 | \internal |
674 | */ |
675 | inline bool QGraphicsItemPrivate::insertionOrder(QGraphicsItem *a, QGraphicsItem *b) |
676 | { |
677 | return a->d_ptr->siblingIndex < b->d_ptr->siblingIndex; |
678 | } |
679 | |
680 | /*! |
681 | \internal |
682 | */ |
683 | inline void QGraphicsItemPrivate::markParentDirty(bool updateBoundingRect) |
684 | { |
685 | QGraphicsItemPrivate *parentp = this; |
686 | #if QT_CONFIG(graphicseffect) |
687 | if (updateBoundingRect && parentp->graphicsEffect && !parentp->inSetPosHelper) { |
688 | parentp->notifyInvalidated = 1; |
689 | static_cast<QGraphicsItemEffectSourcePrivate *>(parentp->graphicsEffect->d_func() |
690 | ->source->d_func())->invalidateCache(); |
691 | } |
692 | #endif |
693 | while (parentp->parent) { |
694 | parentp = parentp->parent->d_ptr.data(); |
695 | parentp->dirtyChildren = 1; |
696 | |
697 | if (updateBoundingRect) { |
698 | parentp->dirtyChildrenBoundingRect = 1; |
699 | // ### Only do this if the parent's effect applies to the entire subtree. |
700 | parentp->notifyBoundingRectChanged = 1; |
701 | } |
702 | #if QT_CONFIG(graphicseffect) |
703 | if (parentp->graphicsEffect) { |
704 | if (updateBoundingRect) { |
705 | static_cast<QGraphicsItemEffectSourcePrivate *>(parentp->graphicsEffect->d_func() |
706 | ->source->d_func())->invalidateCache(); |
707 | parentp->notifyInvalidated = 1; |
708 | } |
709 | if (parentp->scene && parentp->graphicsEffect->isEnabled()) { |
710 | parentp->dirty = 1; |
711 | parentp->fullUpdatePending = 1; |
712 | } |
713 | } |
714 | #endif |
715 | } |
716 | } |
717 | |
718 | QT_END_NAMESPACE |
719 | |
720 | #endif |
721 | |