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 QGRAPHICSSCENE_P_H |
5 | #define QGRAPHICSSCENE_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 "qgraphicsscene.h" |
20 | |
21 | #include "qgraphicssceneevent.h" |
22 | #include "qgraphicsview.h" |
23 | #include "qgraphicsview_p.h" |
24 | #include "qgraphicsitem_p.h" |
25 | |
26 | #include <private/qobject_p.h> |
27 | #include <QtCore/qbitarray.h> |
28 | #include <QtCore/qlist.h> |
29 | #include <QtCore/qmap.h> |
30 | #include <QtCore/qset.h> |
31 | #include <QtGui/qfont.h> |
32 | #include <QtGui/qpalette.h> |
33 | #include <QtWidgets/qstyle.h> |
34 | #include <QtWidgets/qstyleoption.h> |
35 | |
36 | #include <set> |
37 | #include <tuple> |
38 | |
39 | QT_REQUIRE_CONFIG(graphicsview); |
40 | |
41 | QT_BEGIN_NAMESPACE |
42 | |
43 | class QGraphicsSceneIndex; |
44 | class QGraphicsView; |
45 | class QGraphicsWidget; |
46 | |
47 | class Q_AUTOTEST_EXPORT QGraphicsScenePrivate : public QObjectPrivate |
48 | { |
49 | Q_DECLARE_PUBLIC(QGraphicsScene) |
50 | public: |
51 | QGraphicsScenePrivate(); |
52 | void init(); |
53 | |
54 | static QGraphicsScenePrivate *get(QGraphicsScene *q); |
55 | |
56 | int changedSignalIndex; |
57 | int processDirtyItemsIndex; |
58 | int polishItemsIndex; |
59 | |
60 | QGraphicsScene::ItemIndexMethod indexMethod; |
61 | QGraphicsSceneIndex *index; |
62 | |
63 | int lastItemCount; |
64 | |
65 | QRectF sceneRect; |
66 | |
67 | quint32 hasSceneRect : 1; |
68 | quint32 dirtyGrowingItemsBoundingRect : 1; |
69 | quint32 updateAll : 1; |
70 | quint32 calledEmitUpdated : 1; |
71 | quint32 processDirtyItemsEmitted : 1; |
72 | quint32 needSortTopLevelItems : 1; |
73 | quint32 holesInTopLevelSiblingIndex : 1; |
74 | quint32 topLevelSequentialOrdering : 1; |
75 | quint32 scenePosDescendantsUpdatePending : 1; |
76 | quint32 stickyFocus : 1; |
77 | quint32 hasFocus : 1; |
78 | quint32 lastMouseGrabberItemHasImplicitMouseGrab : 1; |
79 | quint32 allItemsIgnoreHoverEvents : 1; |
80 | quint32 allItemsUseDefaultCursor : 1; |
81 | quint32 painterStateProtection : 1; |
82 | quint32 sortCacheEnabled : 1; // for compatibility |
83 | quint32 allItemsIgnoreTouchEvents : 1; |
84 | quint32 focusOnTouch : 1; |
85 | quint32 padding : 14; |
86 | |
87 | qreal minimumRenderSize; |
88 | |
89 | QRectF growingItemsBoundingRect; |
90 | |
91 | void _q_emitUpdated(); |
92 | |
93 | struct UpdatedRectsCmp |
94 | { |
95 | bool operator() (const QRectF &a, const QRectF &b) const noexcept |
96 | { |
97 | return std::make_tuple(args: a.y(), args: a.x(), args: a.height(), args: a.width()) |
98 | < std::make_tuple(args: b.y(), args: b.x(), args: b.height(), args: b.width()); |
99 | } |
100 | }; |
101 | |
102 | // std::set was used here instead of std::unordered_set due to requiring only a comparator and |
103 | // showing equivalent performance in empirical measurements within the ranges of interest... |
104 | std::set<QRectF, UpdatedRectsCmp> updatedRects; |
105 | |
106 | QPainterPath selectionArea; |
107 | int selectionChanging; |
108 | QSet<QGraphicsItem *> selectedItems; |
109 | QList<QGraphicsItem *> unpolishedItems; |
110 | QList<QGraphicsItem *> topLevelItems; |
111 | |
112 | QHash<QGraphicsItem *, QPointF> movingItemsInitialPositions; |
113 | void registerTopLevelItem(QGraphicsItem *item); |
114 | void unregisterTopLevelItem(QGraphicsItem *item); |
115 | void _q_updateLater(); |
116 | void _q_polishItems(); |
117 | |
118 | void _q_processDirtyItems(); |
119 | |
120 | QSet<QGraphicsItem *> scenePosItems; |
121 | void setScenePosItemEnabled(QGraphicsItem *item, bool enabled); |
122 | void registerScenePosItem(QGraphicsItem *item); |
123 | void unregisterScenePosItem(QGraphicsItem *item); |
124 | void _q_updateScenePosDescendants(); |
125 | |
126 | void removeItemHelper(QGraphicsItem *item); |
127 | |
128 | QBrush backgroundBrush; |
129 | QBrush foregroundBrush; |
130 | |
131 | quint32 rectAdjust; |
132 | QGraphicsItem *focusItem; |
133 | QGraphicsItem *lastFocusItem; |
134 | QGraphicsItem *passiveFocusItem; |
135 | QGraphicsWidget *tabFocusFirst; |
136 | QGraphicsItem *activePanel; |
137 | QGraphicsItem *lastActivePanel; |
138 | int activationRefCount; |
139 | int childExplicitActivation; |
140 | void setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent); |
141 | void setFocusItemHelper(QGraphicsItem *item, Qt::FocusReason focusReason, |
142 | bool emitFocusChanged = true); |
143 | |
144 | QList<QGraphicsWidget *> ; |
145 | void (QGraphicsWidget *widget); |
146 | void (QGraphicsWidget *widget, bool itemIsDying = false); |
147 | |
148 | QGraphicsItem *lastMouseGrabberItem; |
149 | QList<QGraphicsItem *> mouseGrabberItems; |
150 | void grabMouse(QGraphicsItem *item, bool implicit = false); |
151 | void ungrabMouse(QGraphicsItem *item, bool itemIsDying = false); |
152 | void clearMouseGrabber(); |
153 | |
154 | QList<QGraphicsItem *> keyboardGrabberItems; |
155 | void grabKeyboard(QGraphicsItem *item); |
156 | void ungrabKeyboard(QGraphicsItem *item, bool itemIsDying = false); |
157 | void clearKeyboardGrabber(); |
158 | |
159 | QGraphicsItem *dragDropItem; |
160 | QGraphicsWidget *enterWidget; |
161 | Qt::DropAction lastDropAction; |
162 | QList<QGraphicsItem *> cachedItemsUnderMouse; |
163 | QList<QGraphicsItem *> hoverItems; |
164 | QPointF lastSceneMousePos; |
165 | void enableMouseTrackingOnViews(); |
166 | QMap<Qt::MouseButton, QPointF> mouseGrabberButtonDownPos; |
167 | QMap<Qt::MouseButton, QPointF> mouseGrabberButtonDownScenePos; |
168 | QMap<Qt::MouseButton, QPoint> mouseGrabberButtonDownScreenPos; |
169 | QList<QGraphicsItem *> itemsAtPosition(const QPoint &screenPos, |
170 | const QPointF &scenePos, |
171 | QWidget *widget) const; |
172 | void storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event); |
173 | |
174 | QList<QGraphicsView *> views; |
175 | void addView(QGraphicsView *view); |
176 | void removeView(QGraphicsView *view); |
177 | |
178 | QMultiMap<QGraphicsItem *, QGraphicsItem *> sceneEventFilters; |
179 | void installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter); |
180 | void removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter); |
181 | bool filterDescendantEvent(QGraphicsItem *item, QEvent *event); |
182 | bool filterEvent(QGraphicsItem *item, QEvent *event); |
183 | bool sendEvent(QGraphicsItem *item, QEvent *event); |
184 | |
185 | bool dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent); |
186 | bool itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const; |
187 | void leaveScene(QWidget *viewport); |
188 | |
189 | void cloneDragDropEvent(QGraphicsSceneDragDropEvent *dest, |
190 | QGraphicsSceneDragDropEvent *source); |
191 | void sendDragDropEvent(QGraphicsItem *item, |
192 | QGraphicsSceneDragDropEvent *dragDropEvent); |
193 | void sendHoverEvent(QEvent::Type type, QGraphicsItem *item, |
194 | QGraphicsSceneHoverEvent *hoverEvent); |
195 | void sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent); |
196 | void mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent); |
197 | QGraphicsWidget *windowForItem(const QGraphicsItem *item) const; |
198 | |
199 | void drawItemHelper(QGraphicsItem *item, QPainter *painter, |
200 | const QStyleOptionGraphicsItem *option, QWidget *widget, |
201 | bool painterStateProtection); |
202 | |
203 | void drawItems(QPainter *painter, const QTransform *const viewTransform, |
204 | QRegion *exposedRegion, QWidget *widget); |
205 | |
206 | void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform *const, |
207 | QRegion *exposedRegion, QWidget *widget, qreal parentOpacity = qreal(1.0), |
208 | const QTransform *const effectTransform = nullptr); |
209 | void draw(QGraphicsItem *, QPainter *, const QTransform *const, const QTransform *const, |
210 | QRegion *, QWidget *, qreal, const QTransform *const, bool, bool); |
211 | |
212 | void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false, |
213 | bool force = false, bool ignoreOpacity = false, bool removingItemFromScene = false, |
214 | bool updateBoundingRect = false); |
215 | void processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren = false, |
216 | qreal parentOpacity = qreal(1.0)); |
217 | |
218 | inline void resetDirtyItem(QGraphicsItem *item, bool recursive = false) |
219 | { |
220 | Q_ASSERT(item); |
221 | item->d_ptr->dirty = 0; |
222 | item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0; |
223 | item->d_ptr->geometryChanged = 0; |
224 | if (!item->d_ptr->dirtyChildren) |
225 | recursive = false; |
226 | item->d_ptr->dirtyChildren = 0; |
227 | item->d_ptr->needsRepaint = QRectF(); |
228 | item->d_ptr->allChildrenDirty = 0; |
229 | item->d_ptr->fullUpdatePending = 0; |
230 | item->d_ptr->ignoreVisible = 0; |
231 | item->d_ptr->ignoreOpacity = 0; |
232 | #if QT_CONFIG(graphicseffect) |
233 | QGraphicsEffect::ChangeFlags flags; |
234 | if (item->d_ptr->notifyBoundingRectChanged) { |
235 | flags |= QGraphicsEffect::SourceBoundingRectChanged; |
236 | item->d_ptr->notifyBoundingRectChanged = 0; |
237 | } |
238 | if (item->d_ptr->notifyInvalidated) { |
239 | flags |= QGraphicsEffect::SourceInvalidated; |
240 | item->d_ptr->notifyInvalidated = 0; |
241 | } |
242 | #endif // QT_CONFIG(graphicseffect) |
243 | if (recursive) { |
244 | for (int i = 0; i < item->d_ptr->children.size(); ++i) |
245 | resetDirtyItem(item: item->d_ptr->children.at(i), recursive); |
246 | } |
247 | #if QT_CONFIG(graphicseffect) |
248 | if (flags && item->d_ptr->graphicsEffect) |
249 | item->d_ptr->graphicsEffect->sourceChanged(flags); |
250 | #endif // QT_CONFIG(graphicseffect) |
251 | } |
252 | |
253 | inline void ensureSortedTopLevelItems() |
254 | { |
255 | if (needSortTopLevelItems) { |
256 | std::sort(first: topLevelItems.begin(), last: topLevelItems.end(), comp: qt_notclosestLeaf); |
257 | topLevelSequentialOrdering = false; |
258 | needSortTopLevelItems = false; |
259 | } |
260 | } |
261 | |
262 | void ensureSequentialTopLevelSiblingIndexes(); |
263 | |
264 | QStyle *style; |
265 | QFont font; |
266 | void setFont_helper(const QFont &font); |
267 | void resolveFont(); |
268 | void updateFont(const QFont &font); |
269 | QPalette palette; |
270 | void setPalette_helper(const QPalette &palette); |
271 | void resolvePalette(); |
272 | void updatePalette(const QPalette &palette); |
273 | |
274 | QStyleOptionGraphicsItem styleOptionTmp; |
275 | |
276 | QMap<int, QEventPoint> sceneCurrentTouchPoints; |
277 | QMap<int, QGraphicsItem *> itemForTouchPointId; |
278 | static void updateTouchPointsForItem(QGraphicsItem *item, QTouchEvent *touchEvent); |
279 | int findClosestTouchPointId(const QPointF &scenePos); |
280 | void touchEventHandler(QTouchEvent *touchEvent); |
281 | bool sendTouchBeginEvent(QGraphicsItem *item, QTouchEvent *touchEvent); |
282 | void enableTouchEventsOnViews(); |
283 | |
284 | QList<QGraphicsObject *> cachedTargetItems; |
285 | #ifndef QT_NO_GESTURES |
286 | QHash<QGraphicsObject *, QSet<QGesture *> > cachedItemGestures; |
287 | QHash<QGraphicsObject *, QSet<QGesture *> > cachedAlreadyDeliveredGestures; |
288 | QHash<QGesture *, QGraphicsObject *> gestureTargets; |
289 | QHash<Qt::GestureType, int> grabbedGestures; |
290 | void gestureEventHandler(QGestureEvent *event); |
291 | void gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures, |
292 | Qt::GestureFlag flag, |
293 | QHash<QGraphicsObject *, QSet<QGesture *> > *targets, |
294 | QSet<QGraphicsObject *> *itemsSet = nullptr, |
295 | QSet<QGesture *> *normal = nullptr, |
296 | QSet<QGesture *> *conflicts = nullptr); |
297 | void cancelGesturesForChildren(QGesture *original); |
298 | void grabGesture(QGraphicsItem *, Qt::GestureType gesture); |
299 | void ungrabGesture(QGraphicsItem *, Qt::GestureType gesture); |
300 | #endif // QT_NO_GESTURES |
301 | |
302 | void updateInputMethodSensitivityInViews(); |
303 | |
304 | QList<QGraphicsItem *> modalPanels; |
305 | void enterModal(QGraphicsItem *item, |
306 | QGraphicsItem::PanelModality panelModality = QGraphicsItem::NonModal); |
307 | void leaveModal(QGraphicsItem *item); |
308 | }; |
309 | |
310 | // QRectF::intersects() returns false always if either the source or target |
311 | // rectangle's width or height are 0. This works around that problem. |
312 | static inline void _q_adjustRect(QRectF *rect) |
313 | { |
314 | Q_ASSERT(rect); |
315 | if (!rect->width()) |
316 | rect->adjust(xp1: qreal(-0.00001), yp1: 0, xp2: qreal(0.00001), yp2: 0); |
317 | if (!rect->height()) |
318 | rect->adjust(xp1: 0, yp1: qreal(-0.00001), xp2: 0, yp2: qreal(0.00001)); |
319 | } |
320 | |
321 | static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item) |
322 | { |
323 | Q_ASSERT(item); |
324 | QRectF boundingRect(item->boundingRect()); |
325 | _q_adjustRect(rect: &boundingRect); |
326 | return boundingRect; |
327 | } |
328 | |
329 | static inline QRectF adjustedItemEffectiveBoundingRect(const QGraphicsItem *item) |
330 | { |
331 | Q_ASSERT(item); |
332 | QRectF boundingRect(QGraphicsItemPrivate::get(item)->effectiveBoundingRect()); |
333 | _q_adjustRect(rect: &boundingRect); |
334 | return boundingRect; |
335 | } |
336 | |
337 | QT_END_NAMESPACE |
338 | |
339 | #endif |
340 | |