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