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 | |
70 | QT_BEGIN_NAMESPACE |
71 | |
72 | class QGraphicsItemPrivate; |
73 | |
74 | #ifndef QDECLARATIVELISTPROPERTY |
75 | #define QDECLARATIVELISTPROPERTY |
76 | template<typename T> |
77 | class QDeclarativeListProperty { |
78 | public: |
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 | |
115 | private: |
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 | |
131 | class QGraphicsItemCache |
132 | { |
133 | public: |
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 | |
158 | class Q_GUI_EXPORT QGraphicsItemPrivate |
159 | { |
160 | Q_DECLARE_PUBLIC(QGraphicsItem) |
161 | public: |
162 | enum { |
163 | , |
164 | , |
165 | , |
166 | , |
167 | |
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 type) const |
327 | { |
328 | for (int i = 0; i < extras.size(); ++i) { |
329 | const ExtraStruct & = extras.at(i); |
330 | if (extra.type == type) |
331 | return extra.value; |
332 | } |
333 | return QVariant(); |
334 | } |
335 | |
336 | inline void (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 (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 { |
364 | (Extra type, QVariant value) |
365 | : type(type), value(value) |
366 | { } |
367 | |
368 | Extra ; |
369 | QVariant ; |
370 | |
371 | bool (Extra ) const |
372 | { return type < extra; } |
373 | }; |
374 | |
375 | QList<ExtraStruct> ; |
376 | |
377 | QGraphicsItemCache *() const; |
378 | QGraphicsItemCache *() const; |
379 | void (); |
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 | |
596 | struct 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 | |
639 | struct 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 |
662 | class QGraphicsItemEffectSourcePrivate : public QGraphicsEffectSourcePrivate |
663 | { |
664 | public: |
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 | */ |
729 | inline 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 | */ |
783 | inline bool qt_closestItemLast(const QGraphicsItem *item1, const QGraphicsItem *item2) |
784 | { |
785 | return qt_closestItemFirst(item2, item1); |
786 | } |
787 | |
788 | /*! |
789 | \internal |
790 | */ |
791 | inline 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 | */ |
808 | inline 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 | */ |
814 | inline QTransform QGraphicsItemPrivate::transformToParent() const |
815 | { |
816 | QTransform matrix; |
817 | combineTransformToParent(&matrix); |
818 | return matrix; |
819 | } |
820 | |
821 | /*! |
822 | \internal |
823 | */ |
824 | inline 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 | */ |
844 | inline bool QGraphicsItemPrivate::insertionOrder(QGraphicsItem *a, QGraphicsItem *b) |
845 | { |
846 | return a->d_ptr->siblingIndex < b->d_ptr->siblingIndex; |
847 | } |
848 | |
849 | /*! |
850 | \internal |
851 | */ |
852 | inline 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 | |
887 | QT_END_NAMESPACE |
888 | |
889 | #endif // QT_NO_GRAPHICSVIEW |
890 | |
891 | #endif |
892 | |