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