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