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
39QT_REQUIRE_CONFIG(graphicsview);
40
41QT_BEGIN_NAMESPACE
42
43class QGraphicsSceneIndex;
44class QGraphicsView;
45class QGraphicsWidget;
46
47class Q_AUTOTEST_EXPORT QGraphicsScenePrivate : public QObjectPrivate
48{
49 Q_DECLARE_PUBLIC(QGraphicsScene)
50public:
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 *> popupWidgets;
145 void addPopup(QGraphicsWidget *widget);
146 void removePopup(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.
312static 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
321static 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
329static 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
337QT_END_NAMESPACE
338
339#endif
340

source code of qtbase/src/widgets/graphicsview/qgraphicsscene_p.h