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 
75 QT_REQUIRE_CONFIG(graphicsview);
76 
77 QT_BEGIN_NAMESPACE
78 
79 class QGraphicsSceneIndex;
80 class QGraphicsView;
81 class QGraphicsWidget;
82 
83 class Q_AUTOTEST_EXPORT QGraphicsScenePrivate : public QObjectPrivate
84 {
85     Q_DECLARE_PUBLIC(QGraphicsScene)
86 public:
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     {
operatorUpdatedRectsCmp131         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     QVector<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 
ensureSortedTopLevelItems()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, QTouchEvent::TouchPoint> 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.
_q_adjustRect(QRectF * rect)348 static 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 
adjustedItemBoundingRect(const QGraphicsItem * item)357 static 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 
adjustedItemEffectiveBoundingRect(const QGraphicsItem * item)365 static 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 
373 QT_END_NAMESPACE
374 
375 #endif
376