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 /*!
41     \class QGraphicsScene
42     \brief The QGraphicsScene class provides a surface for managing a large
43     number of 2D graphical items.
44     \since 4.2
45     \ingroup graphicsview-api
46     \inmodule QtWidgets
47 
48     The class serves as a container for QGraphicsItems. It is used together
49     with QGraphicsView for visualizing graphical items, such as lines,
50     rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is
51     part of the \l{Graphics View Framework}.
52 
53     QGraphicsScene also provides functionality that lets you efficiently
54     determine both the location of items, and for determining what items are
55     visible within an arbitrary area on the scene. With the QGraphicsView
56     widget, you can either visualize the whole scene, or zoom in and view only
57     parts of the scene.
58 
59     Example:
60 
61     \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 0
62 
63     Note that QGraphicsScene has no visual appearance of its own; it only
64     manages the items. You need to create a QGraphicsView widget to visualize
65     the scene.
66 
67     To add items to a scene, you start off by constructing a QGraphicsScene
68     object. Then, you have two options: either add your existing QGraphicsItem
69     objects by calling addItem(), or you can call one of the convenience
70     functions addEllipse(), addLine(), addPath(), addPixmap(), addPolygon(),
71     addRect(), or addText(), which all return a pointer to the newly added item.
72     The dimensions of the items added with these functions are relative to the
73     item's coordinate system, and the items position is initialized to (0,
74     0) in the scene.
75 
76     You can then visualize the scene using QGraphicsView. When the scene
77     changes, (e.g., when an item moves or is transformed) QGraphicsScene
78     emits the changed() signal. To remove an item, call removeItem().
79 
80     QGraphicsScene uses an indexing algorithm to manage the location of items
81     efficiently. By default, a BSP (Binary Space Partitioning) tree is used; an
82     algorithm suitable for large scenes where most items remain static (i.e.,
83     do not move around). You can choose to disable this index by calling
84     setItemIndexMethod(). For more information about the available indexing
85     algorithms, see the itemIndexMethod property.
86 
87     The scene's bounding rect is set by calling setSceneRect(). Items can be
88     placed at any position on the scene, and the size of the scene is by
89     default unlimited. The scene rect is used only for internal bookkeeping,
90     maintaining the scene's item index. If the scene rect is unset,
91     QGraphicsScene will use the bounding area of all items, as returned by
92     itemsBoundingRect(), as the scene rect. However, itemsBoundingRect() is a
93     relatively time consuming function, as it operates by collecting
94     positional information for every item on the scene. Because of this, you
95     should always set the scene rect when operating on large scenes.
96 
97     One of QGraphicsScene's greatest strengths is its ability to efficiently
98     determine the location of items. Even with millions of items on the scene,
99     the items() functions can determine the location of an item within a few
100     milliseconds. There are several overloads to items(): one that finds items
101     at a certain position, one that finds items inside or intersecting with a
102     polygon or a rectangle, and more. The list of returned items is sorted by
103     stacking order, with the topmost item being the first item in the list.
104     For convenience, there is also an itemAt() function that returns the
105     topmost item at a given position.
106 
107     QGraphicsScene maintains selection information for the scene. To select
108     items, call setSelectionArea(), and to clear the current selection, call
109     clearSelection(). Call selectedItems() to get the list of all selected
110     items.
111 
112     \section1 Event Handling and Propagation
113 
114     Another responsibility that QGraphicsScene has, is to propagate events
115     from QGraphicsView. To send an event to a scene, you construct an event
116     that inherits QEvent, and then send it using, for example,
117     QCoreApplication::sendEvent(). event() is responsible for dispatching
118     the event to the individual items. Some common events are handled by
119     convenience event handlers. For example, key press events are handled by
120     keyPressEvent(), and mouse press events are handled by mousePressEvent().
121 
122     Key events are delivered to the \e {focus item}. To set the focus item,
123     you can either call setFocusItem(), passing an item that accepts focus, or
124     the item itself can call QGraphicsItem::setFocus().  Call focusItem() to
125     get the current focus item. For compatibility with widgets, the scene also
126     maintains its own focus information. By default, the scene does not have
127     focus, and all key events are discarded. If setFocus() is called, or if an
128     item on the scene gains focus, the scene automatically gains focus. If the
129     scene has focus, hasFocus() will return true, and key events will be
130     forwarded to the focus item, if any. If the scene loses focus, (i.e.,
131     someone calls clearFocus()) while an item has focus, the scene will
132     maintain its item focus information, and once the scene regains focus, it
133     will make sure the last focus item regains focus.
134 
135     For mouse-over effects, QGraphicsScene dispatches \e {hover
136     events}. If an item accepts hover events (see
137     QGraphicsItem::acceptHoverEvents()), it will receive a \l
138     {QEvent::}{GraphicsSceneHoverEnter} event when the mouse enters
139     its area. As the mouse continues moving inside the item's area,
140     QGraphicsScene will send it \l {QEvent::}{GraphicsSceneHoverMove}
141     events. When the mouse leaves the item's area, the item will
142     receive a \l {QEvent::}{GraphicsSceneHoverLeave} event.
143 
144     All mouse events are delivered to the current \e {mouse grabber}
145     item. An item becomes the scene's mouse grabber if it accepts
146     mouse events (see QGraphicsItem::acceptedMouseButtons()) and it
147     receives a mouse press. It stays the mouse grabber until it
148     receives a mouse release when no other mouse buttons are
149     pressed. You can call mouseGrabberItem() to determine what item is
150     currently grabbing the mouse.
151 
152     \sa QGraphicsItem, QGraphicsView
153 */
154 
155 /*!
156     \enum QGraphicsScene::SceneLayer
157     \since 4.3
158 
159     This enum describes the rendering layers in a QGraphicsScene. When
160     QGraphicsScene draws the scene contents, it renders each of these layers
161     separately, in order.
162 
163     Each layer represents a flag that can be OR'ed together when calling
164     functions such as invalidate() or QGraphicsView::invalidateScene().
165 
166     \value ItemLayer The item layer. QGraphicsScene renders all items are in
167     this layer by calling the virtual function drawItems(). The item layer is
168     drawn after the background layer, but before the foreground layer.
169 
170     \value BackgroundLayer The background layer. QGraphicsScene renders the
171     scene's background in this layer by calling the virtual function
172     drawBackground(). The background layer is drawn first of all layers.
173 
174     \value ForegroundLayer The foreground layer. QGraphicsScene renders the
175     scene's foreground in this layer by calling the virtual function
176     drawForeground().  The foreground layer is drawn last of all layers.
177 
178     \value AllLayers All layers; this value represents a combination of all
179     three layers.
180 
181     \sa invalidate(), QGraphicsView::invalidateScene()
182 */
183 
184 /*!
185     \enum QGraphicsScene::ItemIndexMethod
186 
187     This enum describes the indexing algorithms QGraphicsScene provides for
188     managing positional information about items on the scene.
189 
190     \value BspTreeIndex A Binary Space Partitioning tree is applied. All
191     QGraphicsScene's item location algorithms are of an order close to
192     logarithmic complexity, by making use of binary search. Adding, moving and
193     removing items is logarithmic. This approach is best for static scenes
194     (i.e., scenes where most items do not move).
195 
196     \value NoIndex No index is applied. Item location is of linear complexity,
197     as all items on the scene are searched. Adding, moving and removing items,
198     however, is done in constant time. This approach is ideal for dynamic
199     scenes, where many items are added, moved or removed continuously.
200 
201     \sa setItemIndexMethod(), bspTreeDepth
202 */
203 
204 #include "qgraphicsscene.h"
205 
206 #include "qgraphicsitem.h"
207 #include "qgraphicsitem_p.h"
208 #include "qgraphicslayout.h"
209 #include "qgraphicsscene_p.h"
210 #include "qgraphicssceneevent.h"
211 #include "qgraphicsview.h"
212 #include "qgraphicsview_p.h"
213 #include "qgraphicswidget.h"
214 #include "qgraphicswidget_p.h"
215 #include "qgraphicssceneindex_p.h"
216 #include "qgraphicsscenebsptreeindex_p.h"
217 #include "qgraphicsscenelinearindex_p.h"
218 
219 #include <QtCore/qdebug.h>
220 #include <QtCore/qlist.h>
221 #include <QtCore/qmath.h>
222 #include <QtCore/qrect.h>
223 #include <QtCore/qset.h>
224 #include <QtCore/qstack.h>
225 #include <QtCore/qtimer.h>
226 #include <QtCore/qvarlengtharray.h>
227 #include <QtCore/QMetaMethod>
228 #include <QtWidgets/qapplication.h>
229 #include <QtWidgets/qdesktopwidget.h>
230 #include <QtGui/qevent.h>
231 #include <QtWidgets/qgraphicslayout.h>
232 #include <QtWidgets/qgraphicsproxywidget.h>
233 #include <QtWidgets/qgraphicswidget.h>
234 #include <QtGui/qpaintengine.h>
235 #include <QtGui/qpainter.h>
236 #include <QtGui/qpainterpath.h>
237 #include <QtGui/qpixmapcache.h>
238 #include <QtGui/qpolygon.h>
239 #include <QtGui/qtouchdevice.h>
240 #include <QtWidgets/qstyleoption.h>
241 #include <QtWidgets/qtooltip.h>
242 #include <QtGui/qtransform.h>
243 #include <QtGui/qinputmethod.h>
244 #include <private/qapplication_p.h>
245 #include <private/qobject_p.h>
246 #if QT_CONFIG(graphicseffect)
247 #include <private/qgraphicseffect_p.h>
248 #endif
249 #include <private/qgesturemanager_p.h>
250 #include <private/qpathclipper_p.h>
251 
252 // #define GESTURE_DEBUG
253 #ifndef GESTURE_DEBUG
254 # define DEBUG if (0) qDebug
255 #else
256 # define DEBUG qDebug
257 #endif
258 
259 QT_BEGIN_NAMESPACE
260 
261 bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
262 
_q_hoverFromMouseEvent(QGraphicsSceneHoverEvent * hover,const QGraphicsSceneMouseEvent * mouseEvent)263 static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent)
264 {
265     hover->setWidget(mouseEvent->widget());
266     hover->setPos(mouseEvent->pos());
267     hover->setScenePos(mouseEvent->scenePos());
268     hover->setScreenPos(mouseEvent->screenPos());
269     hover->setLastPos(mouseEvent->lastPos());
270     hover->setLastScenePos(mouseEvent->lastScenePos());
271     hover->setLastScreenPos(mouseEvent->lastScreenPos());
272     hover->setModifiers(mouseEvent->modifiers());
273     hover->setAccepted(mouseEvent->isAccepted());
274 }
275 
276 /*!
277     \internal
278 */
QGraphicsScenePrivate()279 QGraphicsScenePrivate::QGraphicsScenePrivate()
280     : indexMethod(QGraphicsScene::BspTreeIndex),
281       index(nullptr),
282       lastItemCount(0),
283       hasSceneRect(false),
284       dirtyGrowingItemsBoundingRect(true),
285       updateAll(false),
286       calledEmitUpdated(false),
287       processDirtyItemsEmitted(false),
288       needSortTopLevelItems(true),
289       holesInTopLevelSiblingIndex(false),
290       topLevelSequentialOrdering(true),
291       scenePosDescendantsUpdatePending(false),
292       stickyFocus(false),
293       hasFocus(false),
294       lastMouseGrabberItemHasImplicitMouseGrab(false),
295       allItemsIgnoreHoverEvents(true),
296       allItemsUseDefaultCursor(true),
297       painterStateProtection(true),
298       sortCacheEnabled(false),
299       allItemsIgnoreTouchEvents(true),
300       focusOnTouch(true),
301       minimumRenderSize(0.0),
302       selectionChanging(0),
303       rectAdjust(2),
304       focusItem(nullptr),
305       lastFocusItem(nullptr),
306       passiveFocusItem(nullptr),
307       tabFocusFirst(nullptr),
308       activePanel(nullptr),
309       lastActivePanel(nullptr),
310       activationRefCount(0),
311       childExplicitActivation(0),
312       lastMouseGrabberItem(nullptr),
313       dragDropItem(nullptr),
314       enterWidget(nullptr),
315       lastDropAction(Qt::IgnoreAction),
316       style(nullptr)
317 {
318 }
319 
320 /*!
321     \internal
322 */
init()323 void QGraphicsScenePrivate::init()
324 {
325     Q_Q(QGraphicsScene);
326 
327     index = new QGraphicsSceneBspTreeIndex(q);
328 
329     // Keep this index so we can check for connected slots later on.
330     changedSignalIndex = signalIndex("changed(QList<QRectF>)");
331     processDirtyItemsIndex = q->metaObject()->indexOfSlot("_q_processDirtyItems()");
332     polishItemsIndex = q->metaObject()->indexOfSlot("_q_polishItems()");
333 
334     qApp->d_func()->scene_list.append(q);
335     q->update();
336 }
337 
338 /*!
339     \internal
340 */
get(QGraphicsScene * q)341 QGraphicsScenePrivate *QGraphicsScenePrivate::get(QGraphicsScene *q)
342 {
343     return q->d_func();
344 }
345 
_q_emitUpdated()346 void QGraphicsScenePrivate::_q_emitUpdated()
347 {
348     Q_Q(QGraphicsScene);
349     calledEmitUpdated = false;
350 
351     if (dirtyGrowingItemsBoundingRect) {
352         if (!hasSceneRect) {
353             const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
354             growingItemsBoundingRect |= q->itemsBoundingRect();
355             if (oldGrowingItemsBoundingRect != growingItemsBoundingRect)
356                 emit q->sceneRectChanged(growingItemsBoundingRect);
357         }
358         dirtyGrowingItemsBoundingRect = false;
359     }
360 
361     // Ensure all views are connected if anything is connected. This disables
362     // the optimization that items send updates directly to the views, but it
363     // needs to happen in order to keep compatibility with the behavior from
364     // Qt 4.4 and backward.
365     if (isSignalConnected(changedSignalIndex)) {
366         for (int i = 0; i < views.size(); ++i) {
367             QGraphicsView *view = views.at(i);
368             if (!view->d_func()->connectedToScene) {
369                 view->d_func()->connectedToScene = true;
370                 q->connect(q, SIGNAL(changed(QList<QRectF>)),
371                            views.at(i), SLOT(updateScene(QList<QRectF>)));
372             }
373         }
374     } else {
375         if (views.isEmpty()) {
376             updateAll = false;
377             return;
378         }
379         for (int i = 0; i < views.size(); ++i)
380             views.at(i)->d_func()->processPendingUpdates();
381         // It's important that we update all views before we dispatch, hence two for-loops.
382         for (int i = 0; i < views.size(); ++i)
383             views.at(i)->d_func()->dispatchPendingUpdateRequests();
384         return;
385     }
386 
387     // Notify the changes to anybody interested.
388     QList<QRectF> oldUpdatedRects;
389     if (updateAll) {
390         oldUpdatedRects << q->sceneRect();
391     } else {
392         // Switch to a ranged constructor in Qt 6...
393         oldUpdatedRects.reserve(int(updatedRects.size()));
394         std::copy(updatedRects.cbegin(), updatedRects.cend(),
395                   std::back_inserter(oldUpdatedRects));
396     }
397 
398     updateAll = false;
399     updatedRects.clear();
400     emit q->changed(oldUpdatedRects);
401 }
402 
403 /*!
404     \internal
405 
406     ### This function is almost identical to QGraphicsItemPrivate::addChild().
407 */
registerTopLevelItem(QGraphicsItem * item)408 void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item)
409 {
410     ensureSequentialTopLevelSiblingIndexes();
411     needSortTopLevelItems = true; // ### maybe false
412     item->d_ptr->siblingIndex = topLevelItems.size();
413     topLevelItems.append(item);
414 }
415 
416 /*!
417     \internal
418 
419     ### This function is almost identical to QGraphicsItemPrivate::removeChild().
420 */
unregisterTopLevelItem(QGraphicsItem * item)421 void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item)
422 {
423     if (!holesInTopLevelSiblingIndex)
424         holesInTopLevelSiblingIndex = item->d_ptr->siblingIndex != topLevelItems.size() - 1;
425     if (topLevelSequentialOrdering && !holesInTopLevelSiblingIndex)
426         topLevelItems.removeAt(item->d_ptr->siblingIndex);
427     else
428         topLevelItems.removeOne(item);
429     // NB! Do not use topLevelItems.removeAt(item->d_ptr->siblingIndex) because
430     // the item is not guaranteed to be at the index after the list is sorted
431     // (see ensureSortedTopLevelItems()).
432     item->d_ptr->siblingIndex = -1;
433     if (topLevelSequentialOrdering)
434         topLevelSequentialOrdering = !holesInTopLevelSiblingIndex;
435 }
436 
437 /*!
438     \internal
439 */
_q_polishItems()440 void QGraphicsScenePrivate::_q_polishItems()
441 {
442     if (unpolishedItems.isEmpty())
443         return;
444 
445     const QVariant booleanTrueVariant(true);
446     QGraphicsItem *item = nullptr;
447     QGraphicsItemPrivate *itemd = nullptr;
448     const int oldUnpolishedCount = unpolishedItems.count();
449 
450     for (int i = 0; i < oldUnpolishedCount; ++i) {
451         item = unpolishedItems.at(i);
452         if (!item)
453             continue;
454         itemd = item->d_ptr.data();
455         itemd->pendingPolish = false;
456         if (!itemd->explicitlyHidden) {
457             item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant);
458             item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant);
459         }
460         if (itemd->isWidget) {
461             QEvent event(QEvent::Polish);
462             QCoreApplication::sendEvent((QGraphicsWidget *)item, &event);
463         }
464     }
465 
466     if (unpolishedItems.count() == oldUnpolishedCount) {
467         // No new items were added to the vector.
468         unpolishedItems.clear();
469     } else {
470         // New items were appended; keep them and remove the old ones.
471         unpolishedItems.remove(0, oldUnpolishedCount);
472         unpolishedItems.squeeze();
473         QMetaObject::invokeMethod(q_ptr, "_q_polishItems", Qt::QueuedConnection);
474     }
475 }
476 
_q_processDirtyItems()477 void QGraphicsScenePrivate::_q_processDirtyItems()
478 {
479     processDirtyItemsEmitted = false;
480 
481     if (updateAll) {
482         Q_ASSERT(calledEmitUpdated);
483         // No need for further processing (except resetting the dirty states).
484         // The growingItemsBoundingRect is updated in _q_emitUpdated.
485         for (int i = 0; i < topLevelItems.size(); ++i)
486             resetDirtyItem(topLevelItems.at(i), /*recursive=*/true);
487         return;
488     }
489 
490     const bool wasPendingSceneUpdate = calledEmitUpdated;
491     const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
492 
493     // Process items recursively.
494     for (int i = 0; i < topLevelItems.size(); ++i)
495         processDirtyItemsRecursive(topLevelItems.at(i));
496 
497     dirtyGrowingItemsBoundingRect = false;
498     if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect)
499         emit q_func()->sceneRectChanged(growingItemsBoundingRect);
500 
501     if (wasPendingSceneUpdate)
502         return;
503 
504     for (int i = 0; i < views.size(); ++i)
505         views.at(i)->d_func()->processPendingUpdates();
506 
507     if (calledEmitUpdated) {
508         // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive
509         // and we cannot wait for the control to reach the eventloop before the
510         // changed signal is emitted, so we emit it now.
511         _q_emitUpdated();
512     }
513 
514     // Immediately dispatch all pending update requests on the views.
515     for (int i = 0; i < views.size(); ++i)
516         views.at(i)->d_func()->dispatchPendingUpdateRequests();
517 }
518 
519 /*!
520     \internal
521 */
setScenePosItemEnabled(QGraphicsItem * item,bool enabled)522 void QGraphicsScenePrivate::setScenePosItemEnabled(QGraphicsItem *item, bool enabled)
523 {
524     QGraphicsItem *p = item->d_ptr->parent;
525     while (p) {
526         p->d_ptr->scenePosDescendants = enabled;
527         p = p->d_ptr->parent;
528     }
529     if (!enabled && !scenePosDescendantsUpdatePending) {
530         scenePosDescendantsUpdatePending = true;
531         QMetaObject::invokeMethod(q_func(), "_q_updateScenePosDescendants", Qt::QueuedConnection);
532     }
533 }
534 
535 /*!
536     \internal
537 */
registerScenePosItem(QGraphicsItem * item)538 void QGraphicsScenePrivate::registerScenePosItem(QGraphicsItem *item)
539 {
540     scenePosItems.insert(item);
541     setScenePosItemEnabled(item, true);
542 }
543 
544 /*!
545     \internal
546 */
unregisterScenePosItem(QGraphicsItem * item)547 void QGraphicsScenePrivate::unregisterScenePosItem(QGraphicsItem *item)
548 {
549     scenePosItems.remove(item);
550     setScenePosItemEnabled(item, false);
551 }
552 
553 /*!
554     \internal
555 */
_q_updateScenePosDescendants()556 void QGraphicsScenePrivate::_q_updateScenePosDescendants()
557 {
558     foreach (QGraphicsItem *item, scenePosItems) {
559         QGraphicsItem *p = item->d_ptr->parent;
560         while (p) {
561             p->d_ptr->scenePosDescendants = 1;
562             p = p->d_ptr->parent;
563         }
564     }
565     scenePosDescendantsUpdatePending = false;
566 }
567 
568 /*!
569     \internal
570 
571     Schedules an item for removal. This function leaves some stale indexes
572     around in the BSP tree if called from the item's destructor; these will
573     be cleaned up the next time someone triggers purgeRemovedItems().
574 
575     Note: This function might get called from QGraphicsItem's destructor. \a item is
576     being destroyed, so we cannot call any pure virtual functions on it (such
577     as boundingRect()). Also, it is unnecessary to update the item's own state
578     in any way.
579 */
removeItemHelper(QGraphicsItem * item)580 void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
581 {
582     Q_Q(QGraphicsScene);
583 
584     // Clear focus on the item to remove any reference in the focusWidget chain.
585     item->clearFocus();
586 
587     markDirty(item, QRectF(), /*invalidateChildren=*/false, /*force=*/false,
588               /*ignoreOpacity=*/false, /*removingItemFromScene=*/true);
589 
590     if (item->d_ptr->inDestructor) {
591         // The item is actually in its destructor, we call the special method in the index.
592         index->deleteItem(item);
593     } else {
594         // Can potentially call item->boundingRect() (virtual function), that's why
595         // we only can call this function if the item is not in its destructor.
596         index->removeItem(item);
597     }
598 
599     item->d_ptr->clearSubFocus();
600 
601     if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges)
602         unregisterScenePosItem(item);
603 
604     QGraphicsScene *oldScene = item->d_func()->scene;
605     item->d_func()->scene = nullptr;
606 
607     //We need to remove all children first because they might use their parent
608     //attributes (e.g. sceneTransform).
609     if (!item->d_ptr->inDestructor) {
610         // Remove all children recursively
611         for (int i = 0; i < item->d_ptr->children.size(); ++i)
612             q->removeItem(item->d_ptr->children.at(i));
613     }
614 
615     if (!item->d_ptr->inDestructor && !item->parentItem() && item->isWidget()) {
616         QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
617         widget->d_func()->fixFocusChainBeforeReparenting(nullptr, oldScene, nullptr);
618     }
619 
620     // Unregister focus proxy.
621     item->d_ptr->resetFocusProxy();
622 
623     // Remove from parent, or unregister from toplevels.
624     if (QGraphicsItem *parentItem = item->parentItem()) {
625         if (parentItem->scene()) {
626             Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem",
627                        "Parent item's scene is different from this item's scene");
628             item->setParentItem(nullptr);
629         }
630     } else {
631         unregisterTopLevelItem(item);
632     }
633 
634     // Reset the mouse grabber and focus item data.
635     if (item == focusItem)
636         focusItem = nullptr;
637     if (item == lastFocusItem)
638         lastFocusItem = nullptr;
639     if (item == passiveFocusItem)
640         passiveFocusItem = nullptr;
641     if (item == activePanel) {
642         // ### deactivate...
643         activePanel = nullptr;
644     }
645     if (item == lastActivePanel)
646         lastActivePanel = nullptr;
647 
648     // Change tabFocusFirst to the next widget in focus chain if removing the current one.
649     if (item == tabFocusFirst) {
650         QGraphicsWidgetPrivate *wd = tabFocusFirst->d_func();
651         if (wd->focusNext && wd->focusNext != tabFocusFirst && wd->focusNext->scene() == q)
652             tabFocusFirst = wd->focusNext;
653         else
654             tabFocusFirst = nullptr;
655     }
656 
657     // Cancel active touches
658     {
659         QMap<int, QGraphicsItem *>::iterator it = itemForTouchPointId.begin();
660         while (it != itemForTouchPointId.end()) {
661             if (it.value() == item) {
662                 sceneCurrentTouchPoints.remove(it.key());
663                 it = itemForTouchPointId.erase(it);
664             } else {
665                 ++it;
666             }
667         }
668     }
669 
670     // Disable selectionChanged() for individual items
671     ++selectionChanging;
672     int oldSelectedItemsSize = selectedItems.size();
673 
674     // Update selected & hovered item bookkeeping
675     selectedItems.remove(item);
676     hoverItems.removeAll(item);
677     cachedItemsUnderMouse.removeAll(item);
678     if (item->d_ptr->pendingPolish) {
679         const int unpolishedIndex = unpolishedItems.indexOf(item);
680         if (unpolishedIndex != -1)
681             unpolishedItems[unpolishedIndex] = 0;
682         item->d_ptr->pendingPolish = false;
683     }
684     resetDirtyItem(item);
685 
686     //We remove all references of item from the sceneEventFilter arrays
687     QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin();
688     while (iterator != sceneEventFilters.end()) {
689         if (iterator.value() == item || iterator.key() == item)
690             iterator = sceneEventFilters.erase(iterator);
691         else
692             ++iterator;
693     }
694 
695     if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
696         leaveModal(item);
697 
698     // Reset the mouse grabber and focus item data.
699     if (mouseGrabberItems.contains(item))
700         ungrabMouse(item, /* item is dying */ item->d_ptr->inDestructor);
701 
702     // Reset the keyboard grabber
703     if (keyboardGrabberItems.contains(item))
704         ungrabKeyboard(item, /* item is dying */ item->d_ptr->inDestructor);
705 
706     // Reset the last mouse grabber item
707     if (item == lastMouseGrabberItem)
708         lastMouseGrabberItem = nullptr;
709 
710     // Reset the current drop item
711     if (item == dragDropItem)
712         dragDropItem = nullptr;
713 
714     // Reenable selectionChanged() for individual items
715     --selectionChanging;
716     if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize)
717         emit q->selectionChanged();
718 
719 #ifndef QT_NO_GESTURES
720     QHash<QGesture *, QGraphicsObject *>::iterator it;
721     for (it = gestureTargets.begin(); it != gestureTargets.end();) {
722         if (it.value() == item)
723             it = gestureTargets.erase(it);
724         else
725             ++it;
726     }
727 
728     if (QGraphicsObject *dummy = item->toGraphicsObject()) {
729         cachedTargetItems.removeOne(dummy);
730         cachedItemGestures.remove(dummy);
731         cachedAlreadyDeliveredGestures.remove(dummy);
732     }
733 
734     foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys())
735         ungrabGesture(item, gesture);
736 #endif // QT_NO_GESTURES
737 }
738 
739 /*!
740     \internal
741 */
setActivePanelHelper(QGraphicsItem * item,bool duringActivationEvent)742 void QGraphicsScenePrivate::setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent)
743 {
744     Q_Q(QGraphicsScene);
745     if (item && item->scene() != q) {
746         qWarning("QGraphicsScene::setActivePanel: item %p must be part of this scene",
747                  item);
748         return;
749     }
750 
751     // Ensure the scene has focus when we change panel activation.
752     q->setFocus(Qt::ActiveWindowFocusReason);
753 
754     // Find the item's panel.
755     QGraphicsItem *panel = item ? item->panel() : nullptr;
756     lastActivePanel = panel ? activePanel : nullptr;
757     if (panel == activePanel || (!q->isActive() && !duringActivationEvent))
758         return;
759 
760     QGraphicsItem *oldFocusItem = focusItem;
761 
762     // Deactivate the last active panel.
763     if (activePanel) {
764         if (QGraphicsItem *fi = activePanel->focusItem()) {
765             // Remove focus from the current focus item.
766             if (fi == q->focusItem())
767                 setFocusItemHelper(nullptr, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
768         }
769 
770         QEvent event(QEvent::WindowDeactivate);
771         q->sendEvent(activePanel, &event);
772     } else if (panel && !duringActivationEvent) {
773         // Deactivate the scene if changing activation to a panel.
774         const auto items = q->items();
775         QEvent event(QEvent::WindowDeactivate);
776         for (QGraphicsItem *item : items) {
777             if (item->isVisible() && !item->isPanel() && !item->parentItem())
778                 q->sendEvent(item, &event);
779         }
780     }
781 
782     // Update activate state.
783     activePanel = panel;
784     QEvent event(QEvent::ActivationChange);
785     QCoreApplication::sendEvent(q, &event);
786 
787     // Activate
788     if (panel) {
789         QEvent event(QEvent::WindowActivate);
790         q->sendEvent(panel, &event);
791 
792         // Set focus on the panel's focus item, or itself if it's
793         // focusable, or on the first focusable item in the panel's
794         // focus chain as a last resort.
795         if (QGraphicsItem *focusItem = panel->focusItem()) {
796             setFocusItemHelper(focusItem, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
797         } else if (panel->flags() & QGraphicsItem::ItemIsFocusable) {
798             setFocusItemHelper(panel, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
799         } else if (panel->isWidget()) {
800             QGraphicsWidget *fw = static_cast<QGraphicsWidget *>(panel)->d_func()->focusNext;
801             do {
802                 if (fw->focusPolicy() & Qt::TabFocus) {
803                     setFocusItemHelper(fw, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
804                     break;
805                 }
806                 fw = fw->d_func()->focusNext;
807             } while (fw != panel);
808         }
809     } else if (q->isActive()) {
810         const auto items = q->items();
811         // Activate the scene
812         QEvent event(QEvent::WindowActivate);
813         for (QGraphicsItem *item : items) {
814             if (item->isVisible() && !item->isPanel() && !item->parentItem())
815                 q->sendEvent(item, &event);
816         }
817     }
818 
819     emit q->focusItemChanged(focusItem, oldFocusItem, Qt::ActiveWindowFocusReason);
820 }
821 
822 /*!
823     \internal
824 
825     \a emitFocusChanged needs to be false when focus passes from one
826     item to another through setActivePanel(); i.e. when activation
827     passes from one panel to another, to avoid getting two focusChanged()
828     emissions; one focusChanged(0, lastFocus), then one
829     focusChanged(newFocus, 0). Instead setActivePanel() emits the signal
830     once itself: focusChanged(newFocus, oldFocus).
831 */
setFocusItemHelper(QGraphicsItem * item,Qt::FocusReason focusReason,bool emitFocusChanged)832 void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item,
833                                                Qt::FocusReason focusReason,
834                                                bool emitFocusChanged)
835 {
836     Q_Q(QGraphicsScene);
837     if (item == focusItem)
838         return;
839 
840     // Clear focus if asked to set focus on something that can't
841     // accept input focus.
842     if (item && (!(item->flags() & QGraphicsItem::ItemIsFocusable)
843                  || !item->isVisible() || !item->isEnabled())) {
844         item = nullptr;
845     }
846 
847     // Set focus on the scene if an item requests focus.
848     if (item) {
849         q->setFocus(focusReason);
850         if (item == focusItem) {
851             if (emitFocusChanged)
852                 emit q->focusItemChanged(focusItem, (QGraphicsItem *)nullptr, focusReason);
853             return;
854         }
855     }
856 
857     QGraphicsItem *oldFocusItem = focusItem;
858     if (focusItem) {
859         lastFocusItem = focusItem;
860 
861 #ifndef QT_NO_IM
862         if (lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod) {
863             // Close any external input method panel. This happens
864             // automatically by removing WA_InputMethodEnabled on
865             // the views, but if we are changing focus, we have to
866             // do it ourselves.
867             if (qApp)
868                 QGuiApplication::inputMethod()->commit();
869         }
870 #endif //QT_NO_IM
871 
872         focusItem = nullptr;
873         QFocusEvent event(QEvent::FocusOut, focusReason);
874         sendEvent(lastFocusItem, &event);
875     }
876 
877     // This handles the case that the item has been removed from the
878     // scene in response to the FocusOut event.
879     if (item && item->scene() != q)
880         item = nullptr;
881 
882     if (item)
883         focusItem = item;
884     updateInputMethodSensitivityInViews();
885 
886     if (item) {
887         QFocusEvent event(QEvent::FocusIn, focusReason);
888         sendEvent(item, &event);
889     }
890 
891     if (emitFocusChanged)
892         emit q->focusItemChanged(focusItem, oldFocusItem, focusReason);
893 }
894 
895 /*!
896     \internal
897 */
addPopup(QGraphicsWidget * widget)898 void QGraphicsScenePrivate::addPopup(QGraphicsWidget *widget)
899 {
900     Q_ASSERT(widget);
901     Q_ASSERT(!popupWidgets.contains(widget));
902     popupWidgets << widget;
903     if (QGraphicsWidget *focusWidget = widget->focusWidget()) {
904         focusWidget->setFocus(Qt::PopupFocusReason);
905     } else {
906         grabKeyboard((QGraphicsItem *)widget);
907         if (focusItem && popupWidgets.size() == 1) {
908             QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
909             sendEvent(focusItem, &event);
910         }
911     }
912     grabMouse((QGraphicsItem *)widget);
913 }
914 
915 /*!
916     \internal
917 
918     Remove \a widget from the popup list. Important notes:
919 
920     \a widget is guaranteed to be in the list of popups, but it might not be
921     the last entry; you can hide any item in the pop list before the others,
922     and this must cause all later mouse grabbers to lose the grab.
923 */
removePopup(QGraphicsWidget * widget,bool itemIsDying)924 void QGraphicsScenePrivate::removePopup(QGraphicsWidget *widget, bool itemIsDying)
925 {
926     Q_ASSERT(widget);
927     int index = popupWidgets.indexOf(widget);
928     Q_ASSERT(index != -1);
929 
930     for (int i = popupWidgets.size() - 1; i >= index; --i) {
931         QGraphicsWidget *widget = popupWidgets.takeLast();
932         ungrabMouse(widget, itemIsDying);
933         if (focusItem && popupWidgets.isEmpty()) {
934             QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
935             sendEvent(focusItem, &event);
936         } else if (keyboardGrabberItems.contains(static_cast<QGraphicsItem *>(widget))) {
937             ungrabKeyboard(static_cast<QGraphicsItem *>(widget), itemIsDying);
938         }
939         if (!itemIsDying && widget->isVisible()) {
940             widget->QGraphicsItem::d_ptr->setVisibleHelper(false, /* explicit = */ false);
941         }
942     }
943 }
944 
945 /*!
946     \internal
947 */
grabMouse(QGraphicsItem * item,bool implicit)948 void QGraphicsScenePrivate::grabMouse(QGraphicsItem *item, bool implicit)
949 {
950     // Append to list of mouse grabber items, and send a mouse grab event.
951     if (mouseGrabberItems.contains(item)) {
952         if (mouseGrabberItems.constLast() == item) {
953             Q_ASSERT(!implicit);
954             if (!lastMouseGrabberItemHasImplicitMouseGrab) {
955                 qWarning("QGraphicsItem::grabMouse: already a mouse grabber");
956             } else {
957                 // Upgrade to an explicit mouse grab
958                 lastMouseGrabberItemHasImplicitMouseGrab = false;
959             }
960         } else {
961             qWarning("QGraphicsItem::grabMouse: already blocked by mouse grabber: %p",
962                      mouseGrabberItems.constLast());
963         }
964         return;
965     }
966 
967     // Send ungrab event to the last grabber.
968     if (!mouseGrabberItems.isEmpty()) {
969         QGraphicsItem *last = mouseGrabberItems.constLast();
970         if (lastMouseGrabberItemHasImplicitMouseGrab) {
971             // Implicit mouse grab is immediately lost.
972             last->ungrabMouse();
973         } else {
974             // Just send ungrab event to current grabber.
975             QEvent ungrabEvent(QEvent::UngrabMouse);
976             sendEvent(last, &ungrabEvent);
977         }
978     }
979 
980     mouseGrabberItems << item;
981     lastMouseGrabberItemHasImplicitMouseGrab = implicit;
982 
983     // Send grab event to current grabber.
984     QEvent grabEvent(QEvent::GrabMouse);
985     sendEvent(item, &grabEvent);
986 }
987 
988 /*!
989     \internal
990 */
ungrabMouse(QGraphicsItem * item,bool itemIsDying)991 void QGraphicsScenePrivate::ungrabMouse(QGraphicsItem *item, bool itemIsDying)
992 {
993     int index = mouseGrabberItems.indexOf(item);
994     if (index == -1) {
995         qWarning("QGraphicsItem::ungrabMouse: not a mouse grabber");
996         return;
997     }
998 
999     if (item != mouseGrabberItems.constLast()) {
1000         // Recursively ungrab the next mouse grabber until we reach this item
1001         // to ensure state consistency.
1002         ungrabMouse(mouseGrabberItems.at(index + 1), itemIsDying);
1003     }
1004     if (!popupWidgets.isEmpty() && item == popupWidgets.constLast()) {
1005         // If the item is a popup, go via removePopup to ensure state
1006         // consistency and that it gets hidden correctly - beware that
1007         // removePopup() reenters this function to continue removing the grab.
1008         removePopup(popupWidgets.constLast(), itemIsDying);
1009         return;
1010     }
1011 
1012     // Send notification about mouse ungrab.
1013     if (!itemIsDying) {
1014         QEvent event(QEvent::UngrabMouse);
1015         sendEvent(item, &event);
1016     }
1017 
1018     // Remove the item from the list of grabbers. Whenever this happens, we
1019     // reset the implicitGrab (there can be only ever be one implicit grabber
1020     // in a scene, and it is always the latest grabber; if the implicit grab
1021     // is lost, it is not automatically regained.
1022     mouseGrabberItems.takeLast();
1023     lastMouseGrabberItemHasImplicitMouseGrab = false;
1024 
1025     // Send notification about mouse regrab. ### It's unfortunate that all the
1026     // items get a GrabMouse event, but this is a rare case with a simple
1027     // implementation and it does ensure a consistent state.
1028     if (!itemIsDying && !mouseGrabberItems.isEmpty()) {
1029         QGraphicsItem *last = mouseGrabberItems.constLast();
1030         QEvent event(QEvent::GrabMouse);
1031         sendEvent(last, &event);
1032     }
1033 }
1034 
1035 /*!
1036     \internal
1037 */
clearMouseGrabber()1038 void QGraphicsScenePrivate::clearMouseGrabber()
1039 {
1040     if (!mouseGrabberItems.isEmpty())
1041         mouseGrabberItems.first()->ungrabMouse();
1042     lastMouseGrabberItem = nullptr;
1043 }
1044 
1045 /*!
1046     \internal
1047 */
grabKeyboard(QGraphicsItem * item)1048 void QGraphicsScenePrivate::grabKeyboard(QGraphicsItem *item)
1049 {
1050     if (keyboardGrabberItems.contains(item)) {
1051         if (keyboardGrabberItems.constLast() == item)
1052             qWarning("QGraphicsItem::grabKeyboard: already a keyboard grabber");
1053         else
1054             qWarning("QGraphicsItem::grabKeyboard: already blocked by keyboard grabber: %p",
1055                      keyboardGrabberItems.constLast());
1056         return;
1057     }
1058 
1059     // Send ungrab event to the last grabber.
1060     if (!keyboardGrabberItems.isEmpty()) {
1061         // Just send ungrab event to current grabber.
1062         QEvent ungrabEvent(QEvent::UngrabKeyboard);
1063         sendEvent(keyboardGrabberItems.constLast(), &ungrabEvent);
1064     }
1065 
1066     keyboardGrabberItems << item;
1067 
1068     // Send grab event to current grabber.
1069     QEvent grabEvent(QEvent::GrabKeyboard);
1070     sendEvent(item, &grabEvent);
1071 }
1072 
1073 /*!
1074     \internal
1075 */
ungrabKeyboard(QGraphicsItem * item,bool itemIsDying)1076 void QGraphicsScenePrivate::ungrabKeyboard(QGraphicsItem *item, bool itemIsDying)
1077 {
1078     int index = keyboardGrabberItems.lastIndexOf(item);
1079     if (index == -1) {
1080         qWarning("QGraphicsItem::ungrabKeyboard: not a keyboard grabber");
1081         return;
1082     }
1083     if (item != keyboardGrabberItems.constLast()) {
1084         // Recursively ungrab the topmost keyboard grabber until we reach this
1085         // item to ensure state consistency.
1086         ungrabKeyboard(keyboardGrabberItems.at(index + 1), itemIsDying);
1087     }
1088 
1089     // Send notification about keyboard ungrab.
1090     if (!itemIsDying) {
1091         QEvent event(QEvent::UngrabKeyboard);
1092         sendEvent(item, &event);
1093     }
1094 
1095     // Remove the item from the list of grabbers.
1096     keyboardGrabberItems.takeLast();
1097 
1098     // Send notification about mouse regrab.
1099     if (!itemIsDying && !keyboardGrabberItems.isEmpty()) {
1100         QGraphicsItem *last = keyboardGrabberItems.constLast();
1101         QEvent event(QEvent::GrabKeyboard);
1102         sendEvent(last, &event);
1103     }
1104 }
1105 
1106 /*!
1107     \internal
1108 */
clearKeyboardGrabber()1109 void QGraphicsScenePrivate::clearKeyboardGrabber()
1110 {
1111     if (!keyboardGrabberItems.isEmpty())
1112         ungrabKeyboard(keyboardGrabberItems.constFirst());
1113 }
1114 
enableMouseTrackingOnViews()1115 void QGraphicsScenePrivate::enableMouseTrackingOnViews()
1116 {
1117     foreach (QGraphicsView *view, views)
1118         view->viewport()->setMouseTracking(true);
1119 }
1120 
1121 /*!
1122     Returns all items for the screen position in \a event.
1123 */
itemsAtPosition(const QPoint & screenPos,const QPointF & scenePos,QWidget * widget) const1124 QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &screenPos,
1125                                                               const QPointF &scenePos,
1126                                                               QWidget *widget) const
1127 {
1128     Q_Q(const QGraphicsScene);
1129     QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
1130     if (!view)
1131         return q->items(scenePos, Qt::IntersectsItemShape, Qt::DescendingOrder, QTransform());
1132 
1133     const QRectF pointRect(QPointF(widget->mapFromGlobal(screenPos)), QSizeF(1, 1));
1134     if (!view->isTransformed())
1135         return q->items(pointRect, Qt::IntersectsItemShape, Qt::DescendingOrder);
1136 
1137     const QTransform viewTransform = view->viewportTransform();
1138     if (viewTransform.type() <= QTransform::TxScale) {
1139         return q->items(viewTransform.inverted().mapRect(pointRect), Qt::IntersectsItemShape,
1140                         Qt::DescendingOrder, viewTransform);
1141     }
1142     return q->items(viewTransform.inverted().map(pointRect), Qt::IntersectsItemShape,
1143                     Qt::DescendingOrder, viewTransform);
1144 }
1145 
1146 /*!
1147     \internal
1148 */
storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent * event)1149 void QGraphicsScenePrivate::storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event)
1150 {
1151     for (int i = 0x1; i <= 0x10; i <<= 1) {
1152         if (event->buttons() & i) {
1153             mouseGrabberButtonDownPos.insert(Qt::MouseButton(i),
1154                                              mouseGrabberItems.constLast()->d_ptr->genericMapFromScene(event->scenePos(),
1155                                                                                                        event->widget()));
1156             mouseGrabberButtonDownScenePos.insert(Qt::MouseButton(i), event->scenePos());
1157             mouseGrabberButtonDownScreenPos.insert(Qt::MouseButton(i), event->screenPos());
1158         }
1159     }
1160 }
1161 
1162 /*!
1163     \internal
1164 */
installSceneEventFilter(QGraphicsItem * watched,QGraphicsItem * filter)1165 void QGraphicsScenePrivate::installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
1166 {
1167     sceneEventFilters.insert(watched, filter);
1168 }
1169 
1170 /*!
1171     \internal
1172 */
removeSceneEventFilter(QGraphicsItem * watched,QGraphicsItem * filter)1173 void QGraphicsScenePrivate::removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
1174 {
1175     if (!sceneEventFilters.contains(watched))
1176         return;
1177 
1178     QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(watched);
1179     QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(watched);
1180     do {
1181         if (it.value() == filter)
1182             it = sceneEventFilters.erase(it);
1183         else
1184             ++it;
1185     } while (it != end);
1186 }
1187 
1188 /*!
1189   \internal
1190 */
filterDescendantEvent(QGraphicsItem * item,QEvent * event)1191 bool QGraphicsScenePrivate::filterDescendantEvent(QGraphicsItem *item, QEvent *event)
1192 {
1193     if (item && (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents)) {
1194         QGraphicsItem *parent = item->parentItem();
1195         while (parent) {
1196             if (parent->d_ptr->filtersDescendantEvents && parent->sceneEventFilter(item, event))
1197                 return true;
1198             if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents))
1199                 return false;
1200             parent = parent->parentItem();
1201         }
1202     }
1203     return false;
1204 }
1205 
1206 /*!
1207     \internal
1208 */
filterEvent(QGraphicsItem * item,QEvent * event)1209 bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event)
1210 {
1211     if (item && !sceneEventFilters.contains(item))
1212         return false;
1213 
1214     QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(item);
1215     QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(item);
1216     while (it != end) {
1217         // ### The filterer and filteree might both be deleted.
1218         if (it.value()->sceneEventFilter(it.key(), event))
1219             return true;
1220         ++it;
1221     }
1222     return false;
1223 }
1224 
1225 /*!
1226     \internal
1227 
1228     This is the final dispatch point for any events from the scene to the
1229     item. It filters the event first - if the filter returns \c true, the event
1230     is considered to have been eaten by the filter, and is therefore stopped
1231     (the default filter returns \c false). Then/otherwise, if the item is
1232     enabled, the event is sent; otherwise it is stopped.
1233 */
sendEvent(QGraphicsItem * item,QEvent * event)1234 bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
1235 {
1236 #if QT_CONFIG(gestures)
1237     if (QGraphicsObject *object = item->toGraphicsObject()) {
1238         QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
1239         if (gestureManager) {
1240             if (gestureManager->filterEvent(object, event))
1241                 return true;
1242         }
1243     }
1244 #endif // QT_CONFIG(gestures)
1245 
1246     if (filterEvent(item, event))
1247         return false;
1248     if (filterDescendantEvent(item, event))
1249         return false;
1250     if (!item || !item->isEnabled())
1251         return false;
1252     if (QGraphicsObject *o = item->toGraphicsObject()) {
1253         bool spont = event->spontaneous();
1254         if (spont ? qt_sendSpontaneousEvent(o, event) : QCoreApplication::sendEvent(o, event))
1255             return true;
1256         event->spont = spont;
1257     }
1258     return item->sceneEvent(event);
1259 }
1260 
1261 /*!
1262     \internal
1263 */
cloneDragDropEvent(QGraphicsSceneDragDropEvent * dest,QGraphicsSceneDragDropEvent * source)1264 void QGraphicsScenePrivate::cloneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
1265                                                QGraphicsSceneDragDropEvent *source)
1266 {
1267     dest->setWidget(source->widget());
1268     dest->setPos(source->pos());
1269     dest->setScenePos(source->scenePos());
1270     dest->setScreenPos(source->screenPos());
1271     dest->setButtons(source->buttons());
1272     dest->setModifiers(source->modifiers());
1273     dest->setPossibleActions(source->possibleActions());
1274     dest->setProposedAction(source->proposedAction());
1275     dest->setDropAction(source->dropAction());
1276     dest->setSource(source->source());
1277     dest->setMimeData(source->mimeData());
1278 }
1279 
1280 /*!
1281     \internal
1282 */
sendDragDropEvent(QGraphicsItem * item,QGraphicsSceneDragDropEvent * dragDropEvent)1283 void QGraphicsScenePrivate::sendDragDropEvent(QGraphicsItem *item,
1284                                               QGraphicsSceneDragDropEvent *dragDropEvent)
1285 {
1286     dragDropEvent->setPos(item->d_ptr->genericMapFromScene(dragDropEvent->scenePos(), dragDropEvent->widget()));
1287     sendEvent(item, dragDropEvent);
1288 }
1289 
1290 /*!
1291     \internal
1292 */
sendHoverEvent(QEvent::Type type,QGraphicsItem * item,QGraphicsSceneHoverEvent * hoverEvent)1293 void QGraphicsScenePrivate::sendHoverEvent(QEvent::Type type, QGraphicsItem *item,
1294                                            QGraphicsSceneHoverEvent *hoverEvent)
1295 {
1296     QGraphicsSceneHoverEvent event(type);
1297     event.setWidget(hoverEvent->widget());
1298     const QTransform mapFromScene = item->d_ptr->genericMapFromSceneTransform(hoverEvent->widget());
1299     event.setPos(mapFromScene.map(hoverEvent->scenePos()));
1300     event.setScenePos(hoverEvent->scenePos());
1301     event.setScreenPos(hoverEvent->screenPos());
1302     event.setLastPos(mapFromScene.map(hoverEvent->lastScenePos()));
1303     event.setLastScenePos(hoverEvent->lastScenePos());
1304     event.setLastScreenPos(hoverEvent->lastScreenPos());
1305     event.setModifiers(hoverEvent->modifiers());
1306     sendEvent(item, &event);
1307 }
1308 
1309 /*!
1310     \internal
1311 */
sendMouseEvent(QGraphicsSceneMouseEvent * mouseEvent)1312 void QGraphicsScenePrivate::sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent)
1313 {
1314     if (mouseEvent->button() == 0 && mouseEvent->buttons() == 0 && lastMouseGrabberItemHasImplicitMouseGrab) {
1315         // ### This is a temporary fix for until we get proper mouse
1316         // grab events.
1317         clearMouseGrabber();
1318         return;
1319     }
1320 
1321     QGraphicsItem *item = mouseGrabberItems.constLast();
1322     if (item->isBlockedByModalPanel())
1323         return;
1324 
1325     const QTransform mapFromScene = item->d_ptr->genericMapFromSceneTransform(mouseEvent->widget());
1326     const QPointF itemPos = mapFromScene.map(mouseEvent->scenePos());
1327     for (int i = 0x1; i <= 0x10; i <<= 1) {
1328         Qt::MouseButton button = Qt::MouseButton(i);
1329         mouseEvent->setButtonDownPos(button, mouseGrabberButtonDownPos.value(button, itemPos));
1330         mouseEvent->setButtonDownScenePos(button, mouseGrabberButtonDownScenePos.value(button, mouseEvent->scenePos()));
1331         mouseEvent->setButtonDownScreenPos(button, mouseGrabberButtonDownScreenPos.value(button, mouseEvent->screenPos()));
1332     }
1333     mouseEvent->setPos(itemPos);
1334     mouseEvent->setLastPos(mapFromScene.map(mouseEvent->lastScenePos()));
1335     sendEvent(item, mouseEvent);
1336 }
1337 
1338 /*!
1339     \internal
1340 */
mousePressEventHandler(QGraphicsSceneMouseEvent * mouseEvent)1341 void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent)
1342 {
1343     Q_Q(QGraphicsScene);
1344 
1345     // Ignore by default, unless we find a mouse grabber that accepts it.
1346     mouseEvent->ignore();
1347 
1348     // Deliver to any existing mouse grabber.
1349     if (!mouseGrabberItems.isEmpty()) {
1350         if (mouseGrabberItems.constLast()->isBlockedByModalPanel())
1351             return;
1352         // The event is ignored by default, but we disregard the event's
1353         // accepted state after delivery; the mouse is grabbed, after all.
1354         sendMouseEvent(mouseEvent);
1355         return;
1356     }
1357 
1358     // Start by determining the number of items at the current position.
1359     // Reuse value from earlier calculations if possible.
1360     if (cachedItemsUnderMouse.isEmpty()) {
1361         cachedItemsUnderMouse = itemsAtPosition(mouseEvent->screenPos(),
1362                                                 mouseEvent->scenePos(),
1363                                                 mouseEvent->widget());
1364     }
1365 
1366     // Update window activation.
1367     QGraphicsItem *topItem = cachedItemsUnderMouse.value(0);
1368     QGraphicsWidget *newActiveWindow = topItem ? topItem->window() : nullptr;
1369     if (newActiveWindow && newActiveWindow->isBlockedByModalPanel(&topItem)) {
1370         // pass activation to the blocking modal window
1371         newActiveWindow = topItem ? topItem->window() : nullptr;
1372     }
1373 
1374     if (newActiveWindow != q->activeWindow())
1375         q->setActiveWindow(newActiveWindow);
1376 
1377     // Set focus on the topmost enabled item that can take focus.
1378     bool setFocus = false;
1379 
1380     foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
1381         if (item->isBlockedByModalPanel()
1382             || (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling)) {
1383             // Make sure we don't clear focus.
1384             setFocus = true;
1385             break;
1386         }
1387         if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable))) {
1388             if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
1389                 setFocus = true;
1390                 if (item != q->focusItem() && item->d_ptr->mouseSetsFocus)
1391                     q->setFocusItem(item, Qt::MouseFocusReason);
1392                 break;
1393             }
1394         }
1395         if (item->isPanel())
1396             break;
1397         if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
1398             break;
1399     }
1400 
1401     // Check for scene modality.
1402     bool sceneModality = false;
1403     for (int i = 0; i < modalPanels.size(); ++i) {
1404         if (modalPanels.at(i)->panelModality() == QGraphicsItem::SceneModal) {
1405             sceneModality = true;
1406             break;
1407         }
1408     }
1409 
1410     // If nobody could take focus, clear it.
1411     if (!stickyFocus && !setFocus && !sceneModality)
1412         q->setFocusItem(nullptr, Qt::MouseFocusReason);
1413 
1414     // Any item will do.
1415     if (sceneModality && cachedItemsUnderMouse.isEmpty())
1416         cachedItemsUnderMouse << modalPanels.constFirst();
1417 
1418     // Find a mouse grabber by sending mouse press events to all mouse grabber
1419     // candidates one at a time, until the event is accepted. It's accepted by
1420     // default, so the receiver has to explicitly ignore it for it to pass
1421     // through.
1422     foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
1423         if (!(item->acceptedMouseButtons() & mouseEvent->button())) {
1424             // Skip items that don't accept the event's mouse button.
1425             continue;
1426         }
1427 
1428         // Check if this item is blocked by a modal panel and deliver the mouse event to the
1429         // blocking panel instead of this item if blocked.
1430         (void) item->isBlockedByModalPanel(&item);
1431 
1432         grabMouse(item, /* implicit = */ true);
1433         mouseEvent->accept();
1434 
1435         // check if the item we are sending to are disabled (before we send the event)
1436         bool disabled = !item->isEnabled();
1437         bool isPanel = item->isPanel();
1438         if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick
1439             && item != lastMouseGrabberItem && lastMouseGrabberItem) {
1440             // If this item is different from the item that received the last
1441             // mouse event, and mouseEvent is a doubleclick event, then the
1442             // event is converted to a press. Known limitation:
1443             // Triple-clicking will not generate a doubleclick, though.
1444             QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
1445             mousePress.spont = mouseEvent->spont;
1446             mousePress.accept();
1447             mousePress.setButton(mouseEvent->button());
1448             mousePress.setButtons(mouseEvent->buttons());
1449             mousePress.setScreenPos(mouseEvent->screenPos());
1450             mousePress.setScenePos(mouseEvent->scenePos());
1451             mousePress.setModifiers(mouseEvent->modifiers());
1452             mousePress.setWidget(mouseEvent->widget());
1453             mousePress.setButtonDownPos(mouseEvent->button(),
1454                                         mouseEvent->buttonDownPos(mouseEvent->button()));
1455             mousePress.setButtonDownScenePos(mouseEvent->button(),
1456                                              mouseEvent->buttonDownScenePos(mouseEvent->button()));
1457             mousePress.setButtonDownScreenPos(mouseEvent->button(),
1458                                               mouseEvent->buttonDownScreenPos(mouseEvent->button()));
1459             sendMouseEvent(&mousePress);
1460             mouseEvent->setAccepted(mousePress.isAccepted());
1461         } else {
1462             sendMouseEvent(mouseEvent);
1463         }
1464 
1465         bool dontSendUngrabEvents = mouseGrabberItems.isEmpty() || mouseGrabberItems.constLast() != item;
1466         if (disabled) {
1467             ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
1468             break;
1469         }
1470         if (mouseEvent->isAccepted()) {
1471             if (!mouseGrabberItems.isEmpty())
1472                 storeMouseButtonsForMouseGrabber(mouseEvent);
1473             lastMouseGrabberItem = item;
1474             return;
1475         }
1476         ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
1477 
1478         // Don't propagate through panels.
1479         if (isPanel)
1480             break;
1481     }
1482 
1483     // Is the event still ignored? Then the mouse press goes to the scene.
1484     // Reset the mouse grabber, clear the selection, clear focus, and leave
1485     // the event ignored so that it can propagate through the originating
1486     // view.
1487     if (!mouseEvent->isAccepted()) {
1488         clearMouseGrabber();
1489 
1490         QGraphicsView *view = mouseEvent->widget() ? qobject_cast<QGraphicsView *>(mouseEvent->widget()->parentWidget()) : 0;
1491         bool dontClearSelection = view && view->dragMode() == QGraphicsView::ScrollHandDrag;
1492         bool extendSelection = (mouseEvent->modifiers() & Qt::ControlModifier) != 0;
1493         dontClearSelection |= extendSelection;
1494         if (!dontClearSelection) {
1495             // Clear the selection if the originating view isn't in scroll
1496             // hand drag mode. The view will clear the selection if no drag
1497             // happened.
1498             q->clearSelection();
1499         }
1500     }
1501 }
1502 
1503 /*!
1504     \internal
1505 
1506     Ensures that the list of toplevels is sorted by insertion order, and that
1507     the siblingIndexes are packed (no gaps), and start at 0.
1508 
1509     ### This function is almost identical to
1510     QGraphicsItemPrivate::ensureSequentialSiblingIndex().
1511 */
ensureSequentialTopLevelSiblingIndexes()1512 void QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes()
1513 {
1514     if (!topLevelSequentialOrdering) {
1515         std::sort(topLevelItems.begin(), topLevelItems.end(), QGraphicsItemPrivate::insertionOrder);
1516         topLevelSequentialOrdering = true;
1517         needSortTopLevelItems = 1;
1518     }
1519     if (holesInTopLevelSiblingIndex) {
1520         holesInTopLevelSiblingIndex = 0;
1521         for (int i = 0; i < topLevelItems.size(); ++i)
1522             topLevelItems[i]->d_ptr->siblingIndex = i;
1523     }
1524 }
1525 
1526 /*!
1527     \internal
1528 
1529     Set the font and propagate the changes if the font is different from the
1530     current font.
1531 */
setFont_helper(const QFont & font)1532 void QGraphicsScenePrivate::setFont_helper(const QFont &font)
1533 {
1534     if (this->font == font && this->font.resolve() == font.resolve())
1535         return;
1536     updateFont(font);
1537 }
1538 
1539 /*!
1540     \internal
1541 
1542     Resolve the scene's font against the application font, and propagate the
1543     changes too all items in the scene.
1544 */
resolveFont()1545 void QGraphicsScenePrivate::resolveFont()
1546 {
1547     QFont naturalFont = QApplication::font();
1548     naturalFont.resolve(0);
1549     QFont resolvedFont = font.resolve(naturalFont);
1550     updateFont(resolvedFont);
1551 }
1552 
1553 /*!
1554     \internal
1555 
1556     Update the font, and whether or not it has changed, reresolve all fonts in
1557     the scene.
1558 */
updateFont(const QFont & font)1559 void QGraphicsScenePrivate::updateFont(const QFont &font)
1560 {
1561     Q_Q(QGraphicsScene);
1562 
1563     // Update local font setting.
1564     this->font = font;
1565 
1566     // Resolve the fonts of all top-level widget items, or widget items
1567     // whose parent is not a widget.
1568     const auto items = q->items();
1569     for (QGraphicsItem *item : items) {
1570         if (!item->parentItem()) {
1571             // Resolvefont for an item is a noop operation, but
1572             // every item can be a widget, or can have a widget
1573             // childre.
1574             item->d_ptr->resolveFont(font.resolve());
1575         }
1576     }
1577 
1578     // Send the scene a FontChange event.
1579     QEvent event(QEvent::FontChange);
1580     QCoreApplication::sendEvent(q, &event);
1581 }
1582 
1583 /*!
1584     \internal
1585 
1586     Set the palette and propagate the changes if the palette is different from
1587     the current palette.
1588 */
setPalette_helper(const QPalette & palette)1589 void QGraphicsScenePrivate::setPalette_helper(const QPalette &palette)
1590 {
1591     if (this->palette == palette && this->palette.resolve() == palette.resolve())
1592         return;
1593     updatePalette(palette);
1594 }
1595 
1596 /*!
1597     \internal
1598 
1599     Resolve the scene's palette against the application palette, and propagate
1600     the changes too all items in the scene.
1601 */
resolvePalette()1602 void QGraphicsScenePrivate::resolvePalette()
1603 {
1604     QPalette naturalPalette = QGuiApplication::palette();
1605     naturalPalette.resolve(0);
1606     QPalette resolvedPalette = palette.resolve(naturalPalette);
1607     updatePalette(resolvedPalette);
1608 }
1609 
1610 /*!
1611     \internal
1612 
1613     Update the palette, and whether or not it has changed, reresolve all
1614     palettes in the scene.
1615 */
updatePalette(const QPalette & palette)1616 void QGraphicsScenePrivate::updatePalette(const QPalette &palette)
1617 {
1618     Q_Q(QGraphicsScene);
1619 
1620     // Update local palette setting.
1621     this->palette = palette;
1622 
1623     // Resolve the palettes of all top-level widget items, or widget items
1624     // whose parent is not a widget.
1625     const auto items = q->items();
1626     for (QGraphicsItem *item : items) {
1627         if (!item->parentItem()) {
1628             // ResolvePalette for an item is a noop operation, but
1629             // every item can be a widget, or can have a widget
1630             // children.
1631             item->d_ptr->resolvePalette(palette.resolve());
1632         }
1633     }
1634 
1635     // Send the scene a PaletteChange event.
1636     QEvent event(QEvent::PaletteChange);
1637     QCoreApplication::sendEvent(q, &event);
1638 }
1639 
1640 /*!
1641     Constructs a QGraphicsScene object. The \a parent parameter is
1642     passed to QObject's constructor.
1643 */
QGraphicsScene(QObject * parent)1644 QGraphicsScene::QGraphicsScene(QObject *parent)
1645     : QObject(*new QGraphicsScenePrivate, parent)
1646 {
1647     d_func()->init();
1648 }
1649 
1650 /*!
1651     Constructs a QGraphicsScene object, using \a sceneRect for its
1652     scene rectangle. The \a parent parameter is passed to QObject's
1653     constructor.
1654 
1655     \sa sceneRect
1656 */
QGraphicsScene(const QRectF & sceneRect,QObject * parent)1657 QGraphicsScene::QGraphicsScene(const QRectF &sceneRect, QObject *parent)
1658     : QObject(*new QGraphicsScenePrivate, parent)
1659 {
1660     d_func()->init();
1661     setSceneRect(sceneRect);
1662 }
1663 
1664 /*!
1665     Constructs a QGraphicsScene object, using the rectangle specified
1666     by (\a x, \a y), and the given \a width and \a height for its
1667     scene rectangle. The \a parent parameter is passed to QObject's
1668     constructor.
1669 
1670     \sa sceneRect
1671 */
QGraphicsScene(qreal x,qreal y,qreal width,qreal height,QObject * parent)1672 QGraphicsScene::QGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObject *parent)
1673     : QObject(*new QGraphicsScenePrivate, parent)
1674 {
1675     d_func()->init();
1676     setSceneRect(x, y, width, height);
1677 }
1678 
1679 /*!
1680   Removes and deletes all items from the scene object
1681   before destroying the scene object. The scene object
1682   is removed from the application's global scene list,
1683   and it is removed from all associated views.
1684 */
~QGraphicsScene()1685 QGraphicsScene::~QGraphicsScene()
1686 {
1687     Q_D(QGraphicsScene);
1688 
1689     // Remove this scene from qApp's global scene list.
1690     if (!QApplicationPrivate::is_app_closing)
1691         qApp->d_func()->scene_list.removeAll(this);
1692 
1693     clear();
1694 
1695     // Remove this scene from all associated views.
1696     for (int j = 0; j < d->views.size(); ++j)
1697         d->views.at(j)->setScene(nullptr);
1698 }
1699 
1700 /*!
1701     \property QGraphicsScene::sceneRect
1702     \brief the scene rectangle; the bounding rectangle of the scene
1703 
1704     The scene rectangle defines the extent of the scene. It is
1705     primarily used by QGraphicsView to determine the view's default
1706     scrollable area, and by QGraphicsScene to manage item indexing.
1707 
1708     If unset, or if set to a null QRectF, sceneRect() will return the largest
1709     bounding rect of all items on the scene since the scene was created (i.e.,
1710     a rectangle that grows when items are added to or moved in the scene, but
1711     never shrinks).
1712 
1713     \sa width(), height(), QGraphicsView::sceneRect
1714 */
sceneRect() const1715 QRectF QGraphicsScene::sceneRect() const
1716 {
1717     Q_D(const QGraphicsScene);
1718     if (d->hasSceneRect)
1719         return d->sceneRect;
1720 
1721     if (d->dirtyGrowingItemsBoundingRect) {
1722         // Lazily update the growing items bounding rect
1723         QGraphicsScenePrivate *thatd = const_cast<QGraphicsScenePrivate *>(d);
1724         QRectF oldGrowingBoundingRect = thatd->growingItemsBoundingRect;
1725         thatd->growingItemsBoundingRect |= itemsBoundingRect();
1726         thatd->dirtyGrowingItemsBoundingRect = false;
1727         if (oldGrowingBoundingRect != thatd->growingItemsBoundingRect)
1728             emit const_cast<QGraphicsScene *>(this)->sceneRectChanged(thatd->growingItemsBoundingRect);
1729     }
1730     return d->growingItemsBoundingRect;
1731 }
setSceneRect(const QRectF & rect)1732 void QGraphicsScene::setSceneRect(const QRectF &rect)
1733 {
1734     Q_D(QGraphicsScene);
1735     if (rect != d->sceneRect) {
1736         d->hasSceneRect = !rect.isNull();
1737         d->sceneRect = rect;
1738         emit sceneRectChanged(d->hasSceneRect ? rect : d->growingItemsBoundingRect);
1739     }
1740 }
1741 
1742 /*!
1743      \fn qreal QGraphicsScene::width() const
1744 
1745      This convenience function is equivalent to calling sceneRect().width().
1746 
1747      \sa height()
1748 */
1749 
1750 /*!
1751      \fn qreal QGraphicsScene::height() const
1752 
1753      This convenience function is equivalent to calling \c sceneRect().height().
1754 
1755      \sa width()
1756 */
1757 
1758 /*!
1759     Renders the \a source rect from scene into \a target, using \a painter. This
1760     function is useful for capturing the contents of the scene onto a paint
1761     device, such as a QImage (e.g., to take a screenshot), or for printing
1762     with QPrinter. For example:
1763 
1764     \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 1
1765 
1766     If \a source is a null rect, this function will use sceneRect() to
1767     determine what to render. If \a target is a null rect, the dimensions of \a
1768     painter's paint device will be used.
1769 
1770     The source rect contents will be transformed according to \a
1771     aspectRatioMode to fit into the target rect. By default, the aspect ratio
1772     is kept, and \a source is scaled to fit in \a target.
1773 
1774     \sa QGraphicsView::render()
1775 */
render(QPainter * painter,const QRectF & target,const QRectF & source,Qt::AspectRatioMode aspectRatioMode)1776 void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRectF &source,
1777                             Qt::AspectRatioMode aspectRatioMode)
1778 {
1779     // ### Switch to using the recursive rendering algorithm instead.
1780 
1781     // Default source rect = scene rect
1782     QRectF sourceRect = source;
1783     if (sourceRect.isNull())
1784         sourceRect = sceneRect();
1785 
1786     // Default target rect = device rect
1787     QRectF targetRect = target;
1788     if (targetRect.isNull()) {
1789         if (painter->device()->devType() == QInternal::Picture)
1790             targetRect = sourceRect;
1791         else
1792             targetRect.setRect(0, 0, painter->device()->width(), painter->device()->height());
1793     }
1794 
1795     // Find the ideal x / y scaling ratio to fit \a source into \a target.
1796     qreal xratio = targetRect.width() / sourceRect.width();
1797     qreal yratio = targetRect.height() / sourceRect.height();
1798 
1799     // Scale according to the aspect ratio mode.
1800     switch (aspectRatioMode) {
1801     case Qt::KeepAspectRatio:
1802         xratio = yratio = qMin(xratio, yratio);
1803         break;
1804     case Qt::KeepAspectRatioByExpanding:
1805         xratio = yratio = qMax(xratio, yratio);
1806         break;
1807     case Qt::IgnoreAspectRatio:
1808         break;
1809     }
1810 
1811     // Find all items to draw, and reverse the list (we want to draw
1812     // in reverse order).
1813     QList<QGraphicsItem *> itemList = items(sourceRect, Qt::IntersectsItemBoundingRect);
1814     QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
1815     int numItems = itemList.size();
1816     for (int i = 0; i < numItems; ++i)
1817         itemArray[numItems - i - 1] = itemList.at(i);
1818     itemList.clear();
1819 
1820     painter->save();
1821 
1822     // Transform the painter.
1823     painter->setClipRect(targetRect, Qt::IntersectClip);
1824     QTransform painterTransform;
1825     painterTransform *= QTransform()
1826                         .translate(targetRect.left(), targetRect.top())
1827                         .scale(xratio, yratio)
1828                         .translate(-sourceRect.left(), -sourceRect.top());
1829     painter->setWorldTransform(painterTransform, true);
1830 
1831     // Generate the style options
1832     QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems];
1833     for (int i = 0; i < numItems; ++i)
1834         itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect());
1835 
1836     // Render the scene.
1837     drawBackground(painter, sourceRect);
1838     drawItems(painter, numItems, itemArray, styleOptionArray);
1839     drawForeground(painter, sourceRect);
1840 
1841     delete [] itemArray;
1842     delete [] styleOptionArray;
1843 
1844     painter->restore();
1845 }
1846 
1847 /*!
1848     \property QGraphicsScene::itemIndexMethod
1849     \brief the item indexing method.
1850 
1851     QGraphicsScene applies an indexing algorithm to the scene, to speed up
1852     item discovery functions like items() and itemAt(). Indexing is most
1853     efficient for static scenes (i.e., where items don't move around). For
1854     dynamic scenes, or scenes with many animated items, the index bookkeeping
1855     can outweight the fast lookup speeds.
1856 
1857     For the common case, the default index method BspTreeIndex works fine.  If
1858     your scene uses many animations and you are experiencing slowness, you can
1859     disable indexing by calling \c setItemIndexMethod(NoIndex).
1860 
1861     \sa bspTreeDepth
1862 */
itemIndexMethod() const1863 QGraphicsScene::ItemIndexMethod QGraphicsScene::itemIndexMethod() const
1864 {
1865     Q_D(const QGraphicsScene);
1866     return d->indexMethod;
1867 }
setItemIndexMethod(ItemIndexMethod method)1868 void QGraphicsScene::setItemIndexMethod(ItemIndexMethod method)
1869 {
1870     Q_D(QGraphicsScene);
1871     if (d->indexMethod == method)
1872         return;
1873 
1874     d->indexMethod = method;
1875 
1876     QList<QGraphicsItem *> oldItems = d->index->items(Qt::DescendingOrder);
1877     delete d->index;
1878     if (method == BspTreeIndex)
1879         d->index = new QGraphicsSceneBspTreeIndex(this);
1880     else
1881         d->index = new QGraphicsSceneLinearIndex(this);
1882     for (int i = oldItems.size() - 1; i >= 0; --i)
1883         d->index->addItem(oldItems.at(i));
1884 }
1885 
1886 /*!
1887     \property QGraphicsScene::bspTreeDepth
1888     \brief the depth of QGraphicsScene's BSP index tree
1889     \since 4.3
1890 
1891     This property has no effect when NoIndex is used.
1892 
1893     This value determines the depth of QGraphicsScene's BSP tree. The depth
1894     directly affects QGraphicsScene's performance and memory usage; the latter
1895     growing exponentially with the depth of the tree. With an optimal tree
1896     depth, QGraphicsScene can instantly determine the locality of items, even
1897     for scenes with thousands or millions of items. This also greatly improves
1898     rendering performance.
1899 
1900     By default, the value is 0, in which case Qt will guess a reasonable
1901     default depth based on the size, location and number of items in the
1902     scene. If these parameters change frequently, however, you may experience
1903     slowdowns as QGraphicsScene retunes the depth internally. You can avoid
1904     potential slowdowns by fixating the tree depth through setting this
1905     property.
1906 
1907     The depth of the tree and the size of the scene rectangle decide the
1908     granularity of the scene's partitioning. The size of each scene segment is
1909     determined by the following algorithm:
1910 
1911     \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 2
1912 
1913     The BSP tree has an optimal size when each segment contains between 0 and
1914     10 items.
1915 
1916     \sa itemIndexMethod
1917 */
bspTreeDepth() const1918 int QGraphicsScene::bspTreeDepth() const
1919 {
1920     Q_D(const QGraphicsScene);
1921     QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
1922     return bspTree ? bspTree->bspTreeDepth() : 0;
1923 }
setBspTreeDepth(int depth)1924 void QGraphicsScene::setBspTreeDepth(int depth)
1925 {
1926     Q_D(QGraphicsScene);
1927     if (depth < 0) {
1928         qWarning("QGraphicsScene::setBspTreeDepth: invalid depth %d ignored; must be >= 0", depth);
1929         return;
1930     }
1931 
1932     QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
1933     if (!bspTree) {
1934         qWarning("QGraphicsScene::setBspTreeDepth: cannot apply if indexing method is not BSP");
1935         return;
1936     }
1937     bspTree->setBspTreeDepth(depth);
1938 }
1939 
1940 #if QT_DEPRECATED_SINCE(5, 13)
1941 /*!
1942     \property QGraphicsScene::sortCacheEnabled
1943     \brief whether sort caching is enabled
1944     \since 4.5
1945     \obsolete
1946 
1947     Since Qt 4.6, this property has no effect.
1948 */
isSortCacheEnabled() const1949 bool QGraphicsScene::isSortCacheEnabled() const
1950 {
1951     Q_D(const QGraphicsScene);
1952     return d->sortCacheEnabled;
1953 }
setSortCacheEnabled(bool enabled)1954 void QGraphicsScene::setSortCacheEnabled(bool enabled)
1955 {
1956     Q_D(QGraphicsScene);
1957     if (d->sortCacheEnabled == enabled)
1958         return;
1959     d->sortCacheEnabled = enabled;
1960 }
1961 #endif
1962 
1963 /*!
1964     Calculates and returns the bounding rect of all items on the scene. This
1965     function works by iterating over all items, and because of this, it can
1966     be slow for large scenes.
1967 
1968     \sa sceneRect()
1969 */
itemsBoundingRect() const1970 QRectF QGraphicsScene::itemsBoundingRect() const
1971 {
1972     // Does not take untransformable items into account.
1973     QRectF boundingRect;
1974     const auto items_ = items();
1975     for (QGraphicsItem *item : items_)
1976         boundingRect |= item->sceneBoundingRect();
1977     return boundingRect;
1978 }
1979 
1980 /*!
1981     Returns an ordered list of all items on the scene. \a order decides the
1982     stacking order.
1983 
1984     \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting}
1985 */
items(Qt::SortOrder order) const1986 QList<QGraphicsItem *> QGraphicsScene::items(Qt::SortOrder order) const
1987 {
1988     Q_D(const QGraphicsScene);
1989     return d->index->items(order);
1990 }
1991 
1992 /*!
1993     \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const
1994     \obsolete
1995     \since 4.3
1996 
1997     This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode).
1998 
1999     This function is deprecated and returns incorrect results if the scene
2000     contains items that ignore transformations. Use the overload that takes
2001     a QTransform instead.
2002 */
2003 
2004 /*!
2005     \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
2006     \overload
2007     \since 4.6
2008 
2009     \brief Returns all visible items that, depending on \a mode, are
2010     either inside or intersect with the rectangle defined by \a x, \a y,
2011     \a w and \a h, in a list sorted using \a order. In this case, "visible" defines items for which:
2012     isVisible() returns \c true, effectiveOpacity() returns a value greater than 0.0
2013     (which is fully transparent) and the parent item does not clip it.
2014 
2015     \a deviceTransform is the transformation that applies to the view, and needs to
2016     be provided if the scene contains items that ignore transformations.
2017 */
2018 
2019 /*!
2020     \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
2021     \since 4.6
2022 
2023     \brief Returns all visible items that, depending on \a mode, are at
2024     the specified \a pos in a list sorted using \a order. In this case, "visible" defines items for which:
2025     isVisible() returns \c true, effectiveOpacity() returns a value greater than 0.0
2026     (which is fully transparent) and the parent item does not clip it.
2027 
2028     The default value for \a mode is Qt::IntersectsItemShape; all items whose
2029     exact shape intersects with \a pos are returned.
2030 
2031     \a deviceTransform is the transformation that applies to the view, and needs to
2032     be provided if the scene contains items that ignore transformations.
2033 
2034     \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2035 */
items(const QPointF & pos,Qt::ItemSelectionMode mode,Qt::SortOrder order,const QTransform & deviceTransform) const2036 QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode,
2037                                              Qt::SortOrder order, const QTransform &deviceTransform) const
2038 {
2039     Q_D(const QGraphicsScene);
2040     return d->index->items(pos, mode, order, deviceTransform);
2041 }
2042 
2043 /*!
2044     \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
2045     \overload
2046     \since 4.6
2047 
2048     \brief Returns all visible items that, depending on \a mode, are
2049     either inside or intersect with the specified \a rect, in a
2050     list sorted using \a order. In this case, "visible" defines items for which:
2051     isVisible() returns \c true, effectiveOpacity() returns a value greater than 0.0
2052     (which is fully transparent) and the parent item does not clip it.
2053 
2054     The default value for \a mode is Qt::IntersectsItemShape; all items whose
2055     exact shape intersects with or is contained by \a rect are returned.
2056 
2057     \a deviceTransform is the transformation that applies to the view, and needs to
2058     be provided if the scene contains items that ignore transformations.
2059 
2060     \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2061 */
items(const QRectF & rect,Qt::ItemSelectionMode mode,Qt::SortOrder order,const QTransform & deviceTransform) const2062 QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode,
2063                                              Qt::SortOrder order, const QTransform &deviceTransform) const
2064 {
2065     Q_D(const QGraphicsScene);
2066     return d->index->items(rect, mode, order, deviceTransform);
2067 }
2068 
2069 /*!
2070     \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
2071     \overload
2072     \since 4.6
2073 
2074     \brief Returns all visible items that, depending on \a mode, are
2075     either inside or intersect with the specified \a polygon, in
2076     a list sorted using \a order. In this case, "visible" defines items for which:
2077     isVisible() returns \c true, effectiveOpacity() returns a value greater than 0.0
2078     (which is fully transparent) and the parent item does not clip it.
2079 
2080     The default value for \a mode is Qt::IntersectsItemShape; all items whose
2081     exact shape intersects with or is contained by \a polygon are returned.
2082 
2083     \a deviceTransform is the transformation that applies to the view, and needs to
2084     be provided if the scene contains items that ignore transformations.
2085 
2086     \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2087 */
items(const QPolygonF & polygon,Qt::ItemSelectionMode mode,Qt::SortOrder order,const QTransform & deviceTransform) const2088 QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode,
2089                                              Qt::SortOrder order, const QTransform &deviceTransform) const
2090 {
2091     Q_D(const QGraphicsScene);
2092     return d->index->items(polygon, mode, order, deviceTransform);
2093 }
2094 
2095 /*!
2096     \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
2097     \overload
2098     \since 4.6
2099 
2100     \brief Returns all visible items that, depending on \a mode, are
2101     either inside or intersect with the specified \a path, in a
2102     list sorted using \a order. In this case, "visible" defines items for which:
2103     isVisible() returns \c true, effectiveOpacity() returns a value greater than 0.0
2104     (which is fully transparent) and the parent item does not clip it.
2105 
2106     The default value for \a mode is Qt::IntersectsItemShape; all items whose
2107     exact shape intersects with or is contained by \a path are returned.
2108 
2109     \a deviceTransform is the transformation that applies to the view, and needs to
2110     be provided if the scene contains items that ignore transformations.
2111 
2112     \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2113 */
items(const QPainterPath & path,Qt::ItemSelectionMode mode,Qt::SortOrder order,const QTransform & deviceTransform) const2114 QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode,
2115                                              Qt::SortOrder order, const QTransform &deviceTransform) const
2116 {
2117     Q_D(const QGraphicsScene);
2118     return d->index->items(path, mode, order, deviceTransform);
2119 }
2120 
2121 /*!
2122     Returns a list of all items that collide with \a item. Collisions are
2123     determined by calling QGraphicsItem::collidesWithItem(); the collision
2124     detection is determined by \a mode. By default, all items whose shape
2125     intersects \a item or is contained inside \a item's shape are returned.
2126 
2127     The items are returned in descending stacking order (i.e., the first item
2128     in the list is the uppermost item, and the last item is the lowermost
2129     item).
2130 
2131     \sa items(), itemAt(), QGraphicsItem::collidesWithItem(), {QGraphicsItem#Sorting}{Sorting}
2132 */
collidingItems(const QGraphicsItem * item,Qt::ItemSelectionMode mode) const2133 QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item,
2134                                                       Qt::ItemSelectionMode mode) const
2135 {
2136     Q_D(const QGraphicsScene);
2137     if (!item) {
2138         qWarning("QGraphicsScene::collidingItems: cannot find collisions for null item");
2139         return QList<QGraphicsItem *>();
2140     }
2141 
2142     // Does not support ItemIgnoresTransformations.
2143     QList<QGraphicsItem *> tmp;
2144     const auto itemsInVicinity = d->index->estimateItems(item->sceneBoundingRect(), Qt::DescendingOrder);
2145     for (QGraphicsItem *itemInVicinity : itemsInVicinity) {
2146         if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode))
2147             tmp << itemInVicinity;
2148     }
2149     return tmp;
2150 }
2151 
2152 /*!
2153     \fn QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const
2154     \overload
2155     \obsolete
2156 
2157     Returns the topmost visible item at the specified \a position, or
2158     \nullptr if there are no items at this position.
2159 
2160     This function is deprecated and returns incorrect results if the scene
2161     contains items that ignore transformations. Use the overload that takes
2162     a QTransform instead.
2163 
2164     Note: See items() for a definition of which items are considered visible by this function.
2165 
2166     \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
2167 */
2168 
2169 /*!
2170     \since 4.6
2171 
2172     Returns the topmost visible item at the specified \a position, or \nullptr
2173     if there are no items at this position.
2174 
2175     \a deviceTransform is the transformation that applies to the view, and needs to
2176     be provided if the scene contains items that ignore transformations.
2177 
2178     Note: See items() for a definition of which items are considered visible by this function.
2179 
2180     \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
2181 */
itemAt(const QPointF & position,const QTransform & deviceTransform) const2182 QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position, const QTransform &deviceTransform) const
2183 {
2184     const QList<QGraphicsItem *> itemsAtPoint = items(position, Qt::IntersectsItemShape,
2185                                                       Qt::DescendingOrder, deviceTransform);
2186     return itemsAtPoint.isEmpty() ? nullptr : itemsAtPoint.first();
2187 }
2188 
2189 /*!
2190     \fn QGraphicsScene::itemAt(qreal x, qreal y, const QTransform &deviceTransform) const
2191     \overload
2192     \since 4.6
2193 
2194     Returns the topmost visible item at the position specified by (\a x, \a
2195     y), or \nullptr if there are no items at this position.
2196 
2197     \a deviceTransform is the transformation that applies to the view, and needs to
2198     be provided if the scene contains items that ignore transformations.
2199 
2200     This convenience function is equivalent to calling \c
2201     {itemAt(QPointF(x, y), deviceTransform)}.
2202 
2203     Note: See items() for a definition of which items are considered visible by this function.
2204 */
2205 
2206 /*!
2207     \fn QGraphicsScene::itemAt(qreal x, qreal y) const
2208     \overload
2209     \obsolete
2210 
2211     Returns the topmost visible item at the position specified by (\a x, \a
2212     y), or \nullptr if there are no items at this position.
2213 
2214     This convenience function is equivalent to calling \c
2215     {itemAt(QPointF(x, y))}.
2216 
2217     This function is deprecated and returns incorrect results if the scene
2218     contains items that ignore transformations. Use the overload that takes
2219     a QTransform instead.
2220 
2221     Note: See items() for a definition of which items are considered visible by this function.
2222 */
2223 
2224 /*!
2225     Returns a list of all currently selected items. The items are
2226     returned in no particular order.
2227 
2228     \sa setSelectionArea()
2229 */
selectedItems() const2230 QList<QGraphicsItem *> QGraphicsScene::selectedItems() const
2231 {
2232     Q_D(const QGraphicsScene);
2233 
2234     // Optimization: Lazily removes items that are not selected.
2235     QGraphicsScene *that = const_cast<QGraphicsScene *>(this);
2236     QSet<QGraphicsItem *> actuallySelectedSet;
2237     foreach (QGraphicsItem *item, that->d_func()->selectedItems) {
2238         if (item->isSelected())
2239             actuallySelectedSet << item;
2240     }
2241 
2242     that->d_func()->selectedItems = actuallySelectedSet;
2243 
2244     return d->selectedItems.values();
2245 }
2246 
2247 /*!
2248     Returns the selection area that was previously set with
2249     setSelectionArea(), or an empty QPainterPath if no selection area has been
2250     set.
2251 
2252     \sa setSelectionArea()
2253 */
selectionArea() const2254 QPainterPath QGraphicsScene::selectionArea() const
2255 {
2256     Q_D(const QGraphicsScene);
2257     return d->selectionArea;
2258 }
2259 
2260 /*!
2261     \since 4.6
2262 
2263     Sets the selection area to \a path. All items within this area are
2264     immediately selected, and all items outside are unselected. You can get
2265     the list of all selected items by calling selectedItems().
2266 
2267     \a deviceTransform is the transformation that applies to the view, and needs to
2268     be provided if the scene contains items that ignore transformations.
2269 
2270     For an item to be selected, it must be marked as \e selectable
2271     (QGraphicsItem::ItemIsSelectable).
2272 
2273     \sa clearSelection(), selectionArea()
2274 */
setSelectionArea(const QPainterPath & path,const QTransform & deviceTransform)2275 void QGraphicsScene::setSelectionArea(const QPainterPath &path, const QTransform &deviceTransform)
2276 {
2277     setSelectionArea(path, Qt::IntersectsItemShape, deviceTransform);
2278 }
2279 
2280 /*!
2281     \overload
2282     \since 4.6
2283 
2284     Sets the selection area to \a path using \a mode to determine if items are
2285     included in the selection area.
2286 
2287     \a deviceTransform is the transformation that applies to the view, and needs to
2288     be provided if the scene contains items that ignore transformations.
2289 
2290     \sa clearSelection(), selectionArea()
2291 */
setSelectionArea(const QPainterPath & path,Qt::ItemSelectionMode mode,const QTransform & deviceTransform)2292 void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode,
2293                                       const QTransform &deviceTransform)
2294 {
2295     setSelectionArea(path, Qt::ReplaceSelection, mode, deviceTransform);
2296 }
2297 
2298 /*!
2299     \overload
2300     \since 5.5
2301 
2302     Sets the selection area to \a path using \a mode to determine if items are
2303     included in the selection area.
2304 
2305     \a deviceTransform is the transformation that applies to the view, and needs to
2306     be provided if the scene contains items that ignore transformations.
2307 
2308     \a selectionOperation determines what to do with the currently selected items.
2309 
2310     \sa clearSelection(), selectionArea()
2311 */
setSelectionArea(const QPainterPath & path,Qt::ItemSelectionOperation selectionOperation,Qt::ItemSelectionMode mode,const QTransform & deviceTransform)2312 void QGraphicsScene::setSelectionArea(const QPainterPath &path,
2313                                       Qt::ItemSelectionOperation selectionOperation,
2314                                       Qt::ItemSelectionMode mode,
2315                                       const QTransform &deviceTransform)
2316 {
2317     Q_D(QGraphicsScene);
2318 
2319     // Note: with boolean path operations, we can improve performance here
2320     // quite a lot by "growing" the old path instead of replacing it. That
2321     // allows us to only check the intersect area for changes, instead of
2322     // reevaluating the whole path over again.
2323     d->selectionArea = path;
2324 
2325     QSet<QGraphicsItem *> unselectItems = d->selectedItems;
2326 
2327     // Disable emitting selectionChanged() for individual items.
2328     ++d->selectionChanging;
2329     bool changed = false;
2330 
2331     // Set all items in path to selected.
2332     const auto items = this->items(path, mode, Qt::DescendingOrder, deviceTransform);
2333     for (QGraphicsItem *item : items) {
2334         if (item->flags() & QGraphicsItem::ItemIsSelectable) {
2335             if (!item->isSelected())
2336                 changed = true;
2337             unselectItems.remove(item);
2338             item->setSelected(true);
2339         }
2340     }
2341 
2342     switch (selectionOperation) {
2343     case Qt::ReplaceSelection:
2344         // Deselect all items outside path.
2345         foreach (QGraphicsItem *item, unselectItems) {
2346             item->setSelected(false);
2347             changed = true;
2348         }
2349         break;
2350     default:
2351         break;
2352     }
2353 
2354     // Reenable emitting selectionChanged() for individual items.
2355     --d->selectionChanging;
2356 
2357     if (!d->selectionChanging && changed)
2358         emit selectionChanged();
2359 }
2360 
2361 /*!
2362    Clears the current selection.
2363 
2364    \sa setSelectionArea(), selectedItems()
2365 */
clearSelection()2366 void QGraphicsScene::clearSelection()
2367 {
2368     Q_D(QGraphicsScene);
2369 
2370     // Disable emitting selectionChanged
2371     ++d->selectionChanging;
2372     bool changed = !d->selectedItems.isEmpty();
2373 
2374     foreach (QGraphicsItem *item, d->selectedItems)
2375         item->setSelected(false);
2376     d->selectedItems.clear();
2377 
2378     // Reenable emitting selectionChanged() for individual items.
2379     --d->selectionChanging;
2380 
2381     if (!d->selectionChanging && changed)
2382         emit selectionChanged();
2383 }
2384 
2385 /*!
2386     \since 4.4
2387 
2388     Removes and deletes all items from the scene, but otherwise leaves the
2389     state of the scene unchanged.
2390 
2391     \sa addItem()
2392 */
clear()2393 void QGraphicsScene::clear()
2394 {
2395     Q_D(QGraphicsScene);
2396     // NB! We have to clear the index before deleting items; otherwise the
2397     // index might try to access dangling item pointers.
2398     d->index->clear();
2399     // NB! QGraphicsScenePrivate::unregisterTopLevelItem() removes items
2400     while (!d->topLevelItems.isEmpty())
2401         delete d->topLevelItems.first();
2402     Q_ASSERT(d->topLevelItems.isEmpty());
2403     d->lastItemCount = 0;
2404     d->allItemsIgnoreHoverEvents = true;
2405     d->allItemsUseDefaultCursor = true;
2406     d->allItemsIgnoreTouchEvents = true;
2407     d->focusOnTouch = true;
2408 }
2409 
2410 /*!
2411     Groups all items in \a items into a new QGraphicsItemGroup, and returns a
2412     pointer to the group. The group is created with the common ancestor of \a
2413     items as its parent, and with position (0, 0). The items are all
2414     reparented to the group, and their positions and transformations are
2415     mapped to the group. If \a items is empty, this function will return an
2416     empty top-level QGraphicsItemGroup.
2417 
2418     QGraphicsScene has ownership of the group item; you do not need to delete
2419     it. To dismantle (ungroup) a group, call destroyItemGroup().
2420 
2421     \sa destroyItemGroup(), QGraphicsItemGroup::addToGroup()
2422 */
createItemGroup(const QList<QGraphicsItem * > & items)2423 QGraphicsItemGroup *QGraphicsScene::createItemGroup(const QList<QGraphicsItem *> &items)
2424 {
2425     // Build a list of the first item's ancestors
2426     QList<QGraphicsItem *> ancestors;
2427     int n = 0;
2428     if (!items.isEmpty()) {
2429         QGraphicsItem *parent = items.at(n++);
2430         while ((parent = parent->parentItem()))
2431             ancestors.append(parent);
2432     }
2433 
2434     // Find the common ancestor for all items
2435     QGraphicsItem *commonAncestor = nullptr;
2436     if (!ancestors.isEmpty()) {
2437         while (n < items.size()) {
2438             int commonIndex = -1;
2439             QGraphicsItem *parent = items.at(n++);
2440             do {
2441                 int index = ancestors.indexOf(parent, qMax(0, commonIndex));
2442                 if (index != -1) {
2443                     commonIndex = index;
2444                     break;
2445                 }
2446             } while ((parent = parent->parentItem()));
2447 
2448             if (commonIndex == -1) {
2449                 commonAncestor = nullptr;
2450                 break;
2451             }
2452 
2453             commonAncestor = ancestors.at(commonIndex);
2454         }
2455     }
2456 
2457     // Create a new group at that level
2458     QGraphicsItemGroup *group = new QGraphicsItemGroup(commonAncestor);
2459     if (!commonAncestor)
2460         addItem(group);
2461     for (QGraphicsItem *item : items)
2462         group->addToGroup(item);
2463     return group;
2464 }
2465 
2466 /*!
2467     Reparents all items in \a group to \a group's parent item, then removes \a
2468     group from the scene, and finally deletes it. The items' positions and
2469     transformations are mapped from the group to the group's parent.
2470 
2471     \sa createItemGroup(), QGraphicsItemGroup::removeFromGroup()
2472 */
destroyItemGroup(QGraphicsItemGroup * group)2473 void QGraphicsScene::destroyItemGroup(QGraphicsItemGroup *group)
2474 {
2475     const auto items = group->childItems();
2476     for (QGraphicsItem *item : items)
2477         group->removeFromGroup(item);
2478     removeItem(group);
2479     delete group;
2480 }
2481 
2482 /*!
2483     Adds or moves the \a item and all its childen to this scene.
2484     This scene takes ownership of the \a item.
2485 
2486     If the item is visible (i.e., QGraphicsItem::isVisible() returns
2487     true), QGraphicsScene will emit changed() once control goes back
2488     to the event loop.
2489 
2490     If the item is already in a different scene, it will first be
2491     removed from its old scene, and then added to this scene as a
2492     top-level.
2493 
2494     QGraphicsScene will send ItemSceneChange notifications to \a item
2495     while it is added to the scene. If item does not currently belong
2496     to a scene, only one notification is sent. If it does belong to
2497     scene already (i.e., it is moved to this scene), QGraphicsScene
2498     will send an addition notification as the item is removed from its
2499     previous scene.
2500 
2501     If the item is a panel, the scene is active, and there is no
2502     active panel in the scene, then the item will be activated.
2503 
2504     \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(),
2505     addRect(), addText(), addWidget(), {QGraphicsItem#Sorting}{Sorting}
2506 */
addItem(QGraphicsItem * item)2507 void QGraphicsScene::addItem(QGraphicsItem *item)
2508 {
2509     Q_D(QGraphicsScene);
2510     if (!item) {
2511         qWarning("QGraphicsScene::addItem: cannot add null item");
2512         return;
2513     }
2514     if (item->d_ptr->scene == this) {
2515         qWarning("QGraphicsScene::addItem: item has already been added to this scene");
2516         return;
2517     }
2518     // Remove this item from its existing scene
2519     if (QGraphicsScene *oldScene = item->d_ptr->scene)
2520         oldScene->removeItem(item);
2521 
2522     // Notify the item that its scene is changing, and allow the item to
2523     // react.
2524     const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
2525                                                     QVariant::fromValue<QGraphicsScene *>(this)));
2526     QGraphicsScene *targetScene = qvariant_cast<QGraphicsScene *>(newSceneVariant);
2527     if (targetScene != this) {
2528         if (targetScene && item->d_ptr->scene != targetScene)
2529             targetScene->addItem(item);
2530         return;
2531     }
2532 
2533     // QDeclarativeItems do not rely on initial itemChanged message, as the componentComplete
2534     // function allows far more opportunity for delayed-construction optimization.
2535     if (!item->d_ptr->isDeclarativeItem) {
2536         if (d->unpolishedItems.isEmpty()) {
2537             QMetaMethod method = metaObject()->method(d->polishItemsIndex);
2538             method.invoke(this, Qt::QueuedConnection);
2539         }
2540         d->unpolishedItems.append(item);
2541         item->d_ptr->pendingPolish = true;
2542     }
2543 
2544     // Detach this item from its parent if the parent's scene is different
2545     // from this scene.
2546     if (QGraphicsItem *itemParent = item->d_ptr->parent) {
2547         if (itemParent->d_ptr->scene != this)
2548             item->setParentItem(nullptr);
2549     }
2550 
2551     // Add the item to this scene
2552     item->d_func()->scene = targetScene;
2553 
2554     // Add the item in the index
2555     d->index->addItem(item);
2556 
2557     // Add to list of toplevels if this item is a toplevel.
2558     if (!item->d_ptr->parent)
2559         d->registerTopLevelItem(item);
2560 
2561     // Add to list of items that require an update. We cannot assume that the
2562     // item is fully constructed, so calling item->update() can lead to a pure
2563     // virtual function call to boundingRect().
2564     d->markDirty(item);
2565     d->dirtyGrowingItemsBoundingRect = true;
2566 
2567     // Disable selectionChanged() for individual items
2568     ++d->selectionChanging;
2569     int oldSelectedItemSize = d->selectedItems.size();
2570 
2571     // Enable mouse tracking if we haven't already done so, and the item needs it.
2572     // We cannot use itemAcceptsHoverEvents_helper() here, since we need to enable
2573     // mouse tracking also if this item is temporarily blocked by a modal panel.
2574 
2575     auto needsMouseTracking = [](const QGraphicsItemPrivate *item) {
2576         return item->acceptsHover
2577                 || (item->isWidget && static_cast<const QGraphicsWidgetPrivate *>(item)->hasDecoration());
2578     };
2579 
2580     if (d->allItemsIgnoreHoverEvents && needsMouseTracking(item->d_ptr.data())) {
2581         d->allItemsIgnoreHoverEvents = false;
2582         d->enableMouseTrackingOnViews();
2583     }
2584 #ifndef QT_NO_CURSOR
2585     if (d->allItemsUseDefaultCursor && item->d_ptr->hasCursor) {
2586         d->allItemsUseDefaultCursor = false;
2587         if (d->allItemsIgnoreHoverEvents) // already enabled otherwise
2588             d->enableMouseTrackingOnViews();
2589     }
2590 #endif //QT_NO_CURSOR
2591 
2592     // Enable touch events if the item accepts touch events.
2593     if (d->allItemsIgnoreTouchEvents && item->d_ptr->acceptTouchEvents) {
2594         d->allItemsIgnoreTouchEvents = false;
2595         d->enableTouchEventsOnViews();
2596     }
2597 
2598 #ifndef QT_NO_GESTURES
2599     const auto gestures = item->d_ptr->gestureContext.keys(); // FIXME: iterate over hash directly?
2600     for (Qt::GestureType gesture : gestures)
2601         d->grabGesture(item, gesture);
2602 #endif
2603 
2604     // Update selection lists
2605     if (item->isSelected())
2606         d->selectedItems << item;
2607     if (item->isWidget() && item->isVisible() && static_cast<QGraphicsWidget *>(item)->windowType() == Qt::Popup)
2608         d->addPopup(static_cast<QGraphicsWidget *>(item));
2609     if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
2610         d->enterModal(item);
2611 
2612     // Update creation order focus chain. Make sure to leave the widget's
2613     // internal tab order intact.
2614     if (item->isWidget()) {
2615         QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
2616         if (!d->tabFocusFirst) {
2617             // No first tab focus widget - make this the first tab focus
2618             // widget.
2619             d->tabFocusFirst = widget;
2620         } else if (!widget->parentWidget() && !widget->isPanel()) {
2621             // Adding a widget that is not part of a tab focus chain.
2622             QGraphicsWidget *myNewPrev = d->tabFocusFirst->d_func()->focusPrev;
2623             myNewPrev->d_func()->focusNext = widget;
2624             widget->d_func()->focusPrev->d_func()->focusNext = d->tabFocusFirst;
2625             d->tabFocusFirst->d_func()->focusPrev = widget->d_func()->focusPrev;
2626             widget->d_func()->focusPrev = myNewPrev;
2627         }
2628     }
2629 
2630     // Add all children recursively
2631     item->d_ptr->ensureSortedChildren();
2632     for (int i = 0; i < item->d_ptr->children.size(); ++i)
2633         addItem(item->d_ptr->children.at(i));
2634 
2635     // Resolve font and palette.
2636     item->d_ptr->resolveFont(d->font.resolve());
2637     item->d_ptr->resolvePalette(d->palette.resolve());
2638 
2639 
2640     // Reenable selectionChanged() for individual items
2641     --d->selectionChanging;
2642     if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemSize)
2643         emit selectionChanged();
2644 
2645     // Deliver post-change notification
2646     item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
2647 
2648     // Update explicit activation
2649     bool autoActivate = true;
2650     if (!d->childExplicitActivation && item->d_ptr->explicitActivate)
2651         d->childExplicitActivation = item->d_ptr->wantsActive ? 1 : 2;
2652     if (d->childExplicitActivation && item->isPanel()) {
2653         if (d->childExplicitActivation == 1)
2654             setActivePanel(item);
2655         else
2656             autoActivate = false;
2657         d->childExplicitActivation = 0;
2658     } else if (!item->d_ptr->parent) {
2659         d->childExplicitActivation = 0;
2660     }
2661 
2662     // Auto-activate this item's panel if nothing else has been activated
2663     if (autoActivate) {
2664         if (!d->lastActivePanel && !d->activePanel && item->isPanel()) {
2665             if (isActive())
2666                 setActivePanel(item);
2667             else
2668                 d->lastActivePanel = item;
2669         }
2670     }
2671 
2672     if (item->d_ptr->flags & QGraphicsItem::ItemSendsScenePositionChanges)
2673         d->registerScenePosItem(item);
2674 
2675     // Ensure that newly added items that have subfocus set, gain
2676     // focus automatically if there isn't a focus item already.
2677     if (!d->focusItem && item != d->lastFocusItem && item->focusItem() == item)
2678         item->focusItem()->setFocus();
2679 
2680     d->updateInputMethodSensitivityInViews();
2681 }
2682 
2683 /*!
2684     Creates and adds an ellipse item to the scene, and returns the item
2685     pointer. The geometry of the ellipse is defined by \a rect, and its pen
2686     and brush are initialized to \a pen and \a brush.
2687 
2688     Note that the item's geometry is provided in item coordinates, and its
2689     position is initialized to (0, 0).
2690 
2691     If the item is visible (i.e., QGraphicsItem::isVisible() returns \c true),
2692     QGraphicsScene will emit changed() once control goes back to the event
2693     loop.
2694 
2695     \sa addLine(), addPath(), addPixmap(), addRect(), addText(), addItem(),
2696     addWidget()
2697 */
addEllipse(const QRectF & rect,const QPen & pen,const QBrush & brush)2698 QGraphicsEllipseItem *QGraphicsScene::addEllipse(const QRectF &rect, const QPen &pen, const QBrush &brush)
2699 {
2700     QGraphicsEllipseItem *item = new QGraphicsEllipseItem(rect);
2701     item->setPen(pen);
2702     item->setBrush(brush);
2703     addItem(item);
2704     return item;
2705 }
2706 
2707 /*!
2708     \fn QGraphicsEllipseItem *QGraphicsScene::addEllipse(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
2709     \since 4.3
2710 
2711     This convenience function is equivalent to calling addEllipse(QRectF(\a x,
2712     \a y, \a w, \a h), \a pen, \a brush).
2713 */
2714 
2715 /*!
2716     Creates and adds a line item to the scene, and returns the item
2717     pointer. The geometry of the line is defined by \a line, and its pen
2718     is initialized to \a pen.
2719 
2720     Note that the item's geometry is provided in item coordinates, and its
2721     position is initialized to (0, 0).
2722 
2723     If the item is visible (i.e., QGraphicsItem::isVisible() returns \c true),
2724     QGraphicsScene will emit changed() once control goes back to the event
2725     loop.
2726 
2727     \sa addEllipse(), addPath(), addPixmap(), addRect(), addText(), addItem(),
2728     addWidget()
2729 */
addLine(const QLineF & line,const QPen & pen)2730 QGraphicsLineItem *QGraphicsScene::addLine(const QLineF &line, const QPen &pen)
2731 {
2732     QGraphicsLineItem *item = new QGraphicsLineItem(line);
2733     item->setPen(pen);
2734     addItem(item);
2735     return item;
2736 }
2737 
2738 /*!
2739     \fn QGraphicsLineItem *QGraphicsScene::addLine(qreal x1, qreal y1, qreal x2, qreal y2, const QPen &pen)
2740     \since 4.3
2741 
2742     This convenience function is equivalent to calling addLine(QLineF(\a x1,
2743     \a y1, \a x2, \a y2), \a pen).
2744 */
2745 
2746 /*!
2747     Creates and adds a path item to the scene, and returns the item
2748     pointer. The geometry of the path is defined by \a path, and its pen and
2749     brush are initialized to \a pen and \a brush.
2750 
2751     Note that the item's geometry is provided in item coordinates, and its
2752     position is initialized to (0, 0).
2753 
2754     If the item is visible (i.e., QGraphicsItem::isVisible() returns \c true),
2755     QGraphicsScene will emit changed() once control goes back to the event
2756     loop.
2757 
2758     \sa addEllipse(), addLine(), addPixmap(), addRect(), addText(), addItem(),
2759     addWidget()
2760 */
addPath(const QPainterPath & path,const QPen & pen,const QBrush & brush)2761 QGraphicsPathItem *QGraphicsScene::addPath(const QPainterPath &path, const QPen &pen, const QBrush &brush)
2762 {
2763     QGraphicsPathItem *item = new QGraphicsPathItem(path);
2764     item->setPen(pen);
2765     item->setBrush(brush);
2766     addItem(item);
2767     return item;
2768 }
2769 
2770 /*!
2771     Creates and adds a pixmap item to the scene, and returns the item
2772     pointer. The pixmap is defined by \a pixmap.
2773 
2774     Note that the item's geometry is provided in item coordinates, and its
2775     position is initialized to (0, 0).
2776 
2777     If the item is visible (i.e., QGraphicsItem::isVisible() returns \c true),
2778     QGraphicsScene will emit changed() once control goes back to the event
2779     loop.
2780 
2781     \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
2782     addWidget()
2783 */
addPixmap(const QPixmap & pixmap)2784 QGraphicsPixmapItem *QGraphicsScene::addPixmap(const QPixmap &pixmap)
2785 {
2786     QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
2787     addItem(item);
2788     return item;
2789 }
2790 
2791 /*!
2792     Creates and adds a polygon item to the scene, and returns the item
2793     pointer. The polygon is defined by \a polygon, and its pen and
2794     brush are initialized to \a pen and \a brush.
2795 
2796     Note that the item's geometry is provided in item coordinates, and its
2797     position is initialized to (0, 0).
2798 
2799     If the item is visible (i.e., QGraphicsItem::isVisible() returns \c true),
2800     QGraphicsScene will emit changed() once control goes back to the event
2801     loop.
2802 
2803     \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
2804     addWidget()
2805 */
addPolygon(const QPolygonF & polygon,const QPen & pen,const QBrush & brush)2806 QGraphicsPolygonItem *QGraphicsScene::addPolygon(const QPolygonF &polygon,
2807                                                  const QPen &pen, const QBrush &brush)
2808 {
2809     QGraphicsPolygonItem *item = new QGraphicsPolygonItem(polygon);
2810     item->setPen(pen);
2811     item->setBrush(brush);
2812     addItem(item);
2813     return item;
2814 }
2815 
2816 /*!
2817     Creates and adds a rectangle item to the scene, and returns the item
2818     pointer. The geometry of the rectangle is defined by \a rect, and its pen
2819     and brush are initialized to \a pen and \a brush.
2820 
2821     Note that the item's geometry is provided in item coordinates, and its
2822     position is initialized to (0, 0). For example, if a QRect(50, 50, 100,
2823     100) is added, its top-left corner will be at (50, 50) relative to the
2824     origin in the item's coordinate system.
2825 
2826     If the item is visible (i.e., QGraphicsItem::isVisible() returns \c true),
2827     QGraphicsScene will emit changed() once control goes back to the event
2828     loop.
2829 
2830     \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addText(),
2831     addItem(), addWidget()
2832 */
addRect(const QRectF & rect,const QPen & pen,const QBrush & brush)2833 QGraphicsRectItem *QGraphicsScene::addRect(const QRectF &rect, const QPen &pen, const QBrush &brush)
2834 {
2835     QGraphicsRectItem *item = new QGraphicsRectItem(rect);
2836     item->setPen(pen);
2837     item->setBrush(brush);
2838     addItem(item);
2839     return item;
2840 }
2841 
2842 /*!
2843     \fn QGraphicsRectItem *QGraphicsScene::addRect(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
2844     \since 4.3
2845 
2846     This convenience function is equivalent to calling addRect(QRectF(\a x,
2847     \a y, \a w, \a h), \a pen, \a brush).
2848 */
2849 
2850 /*!
2851     Creates and adds a text item to the scene, and returns the item
2852     pointer. The text string is initialized to \a text, and its font
2853     is initialized to \a font.
2854 
2855     The item's position is initialized to (0, 0).
2856 
2857     If the item is visible (i.e., QGraphicsItem::isVisible() returns \c true),
2858     QGraphicsScene will emit changed() once control goes back to the event
2859     loop.
2860 
2861     \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
2862     addItem(), addWidget()
2863 */
addText(const QString & text,const QFont & font)2864 QGraphicsTextItem *QGraphicsScene::addText(const QString &text, const QFont &font)
2865 {
2866     QGraphicsTextItem *item = new QGraphicsTextItem(text);
2867     item->setFont(font);
2868     addItem(item);
2869     return item;
2870 }
2871 
2872 /*!
2873     Creates and adds a QGraphicsSimpleTextItem to the scene, and returns the
2874     item pointer. The text string is initialized to \a text, and its font is
2875     initialized to \a font.
2876 
2877     The item's position is initialized to (0, 0).
2878 
2879     If the item is visible (i.e., QGraphicsItem::isVisible() returns \c true),
2880     QGraphicsScene will emit changed() once control goes back to the event
2881     loop.
2882 
2883     \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
2884     addItem(), addWidget()
2885 */
addSimpleText(const QString & text,const QFont & font)2886 QGraphicsSimpleTextItem *QGraphicsScene::addSimpleText(const QString &text, const QFont &font)
2887 {
2888     QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem(text);
2889     item->setFont(font);
2890     addItem(item);
2891     return item;
2892 }
2893 
2894 /*!
2895     Creates a new QGraphicsProxyWidget for \a widget, adds it to the scene,
2896     and returns a pointer to the proxy. \a wFlags set the default window flags
2897     for the embedding proxy widget.
2898 
2899     The item's position is initialized to (0, 0).
2900 
2901     If the item is visible (i.e., QGraphicsItem::isVisible() returns \c true),
2902     QGraphicsScene will emit changed() once control goes back to the event
2903     loop.
2904 
2905     Note that widgets with the Qt::WA_PaintOnScreen widget attribute
2906     set and widgets that wrap an external application or controller
2907     are not supported. Examples are QOpenGLWidget and QAxWidget.
2908 
2909     \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
2910     addText(), addSimpleText(), addItem()
2911 */
addWidget(QWidget * widget,Qt::WindowFlags wFlags)2912 QGraphicsProxyWidget *QGraphicsScene::addWidget(QWidget *widget, Qt::WindowFlags wFlags)
2913 {
2914     QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(nullptr, wFlags);
2915     proxy->setWidget(widget);
2916     addItem(proxy);
2917     return proxy;
2918 }
2919 
2920 /*!
2921     Removes the item \a item and all its children from the scene.  The
2922     ownership of \a item is passed on to the caller (i.e.,
2923     QGraphicsScene will no longer delete \a item when destroyed).
2924 
2925     \sa addItem()
2926 */
removeItem(QGraphicsItem * item)2927 void QGraphicsScene::removeItem(QGraphicsItem *item)
2928 {
2929     // ### Refactoring: This function shares much functionality with _q_removeItemLater()
2930     Q_D(QGraphicsScene);
2931     if (!item) {
2932         qWarning("QGraphicsScene::removeItem: cannot remove 0-item");
2933         return;
2934     }
2935     if (item->scene() != this) {
2936         qWarning("QGraphicsScene::removeItem: item %p's scene (%p)"
2937                  " is different from this scene (%p)",
2938                  item, item->scene(), this);
2939         return;
2940     }
2941 
2942     // Notify the item that it's scene is changing to 0, allowing the item to
2943     // react.
2944     const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
2945                                                     QVariant::fromValue<QGraphicsScene *>(0)));
2946     QGraphicsScene *targetScene = qvariant_cast<QGraphicsScene *>(newSceneVariant);
2947     if (targetScene != nullptr && targetScene != this) {
2948         targetScene->addItem(item);
2949         return;
2950     }
2951 
2952     d->removeItemHelper(item);
2953 
2954     // Deliver post-change notification
2955     item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
2956 
2957     d->updateInputMethodSensitivityInViews();
2958 }
2959 
2960 /*!
2961     When the scene is active, this functions returns the scene's current focus
2962     item, or \nullptr if no item currently has focus. When the scene is inactive,
2963     this functions returns the item that will gain input focus when the scene
2964     becomes active.
2965 
2966     The focus item receives keyboard input when the scene receives a
2967     key event.
2968 
2969     \sa setFocusItem(), QGraphicsItem::hasFocus(), isActive()
2970 */
focusItem() const2971 QGraphicsItem *QGraphicsScene::focusItem() const
2972 {
2973     Q_D(const QGraphicsScene);
2974     return isActive() ? d->focusItem : d->passiveFocusItem;
2975 }
2976 
2977 /*!
2978     Sets the scene's focus item to \a item, with the focus reason \a
2979     focusReason, after removing focus from any previous item that may have had
2980     focus.
2981 
2982     If \a item is \nullptr, or if it either does not accept focus (i.e., it does not
2983     have the QGraphicsItem::ItemIsFocusable flag enabled), or is not visible
2984     or not enabled, this function only removes focus from any previous
2985     focusitem.
2986 
2987     If item is not \nullptr, and the scene does not currently have focus (i.e.,
2988     hasFocus() returns \c false), this function will call setFocus()
2989     automatically.
2990 
2991     \sa focusItem(), hasFocus(), setFocus()
2992 */
setFocusItem(QGraphicsItem * item,Qt::FocusReason focusReason)2993 void QGraphicsScene::setFocusItem(QGraphicsItem *item, Qt::FocusReason focusReason)
2994 {
2995     Q_D(QGraphicsScene);
2996     if (item)
2997         item->setFocus(focusReason);
2998     else
2999         d->setFocusItemHelper(item, focusReason);
3000 }
3001 
3002 /*!
3003     Returns \c true if the scene has focus; otherwise returns \c false. If the scene
3004     has focus, it will will forward key events from QKeyEvent to any item that
3005     has focus.
3006 
3007     \sa setFocus(), setFocusItem()
3008 */
hasFocus() const3009 bool QGraphicsScene::hasFocus() const
3010 {
3011     Q_D(const QGraphicsScene);
3012     return d->hasFocus;
3013 }
3014 
3015 /*!
3016     Sets focus on the scene by sending a QFocusEvent to the scene, passing \a
3017     focusReason as the reason. If the scene regains focus after having
3018     previously lost it while an item had focus, the last focus item will
3019     receive focus with \a focusReason as the reason.
3020 
3021     If the scene already has focus, this function does nothing.
3022 
3023     \sa hasFocus(), clearFocus(), setFocusItem()
3024 */
setFocus(Qt::FocusReason focusReason)3025 void QGraphicsScene::setFocus(Qt::FocusReason focusReason)
3026 {
3027     Q_D(QGraphicsScene);
3028     if (d->hasFocus || !isActive())
3029         return;
3030     QFocusEvent event(QEvent::FocusIn, focusReason);
3031     QCoreApplication::sendEvent(this, &event);
3032 }
3033 
3034 /*!
3035     Clears focus from the scene. If any item has focus when this function is
3036     called, it will lose focus, and regain focus again once the scene regains
3037     focus.
3038 
3039     A scene that does not have focus ignores key events.
3040 
3041     \sa hasFocus(), setFocus(), setFocusItem()
3042 */
clearFocus()3043 void QGraphicsScene::clearFocus()
3044 {
3045     Q_D(QGraphicsScene);
3046     if (d->hasFocus) {
3047         d->hasFocus = false;
3048         d->passiveFocusItem = d->focusItem;
3049         setFocusItem(nullptr, Qt::OtherFocusReason);
3050     }
3051 }
3052 
3053 /*!
3054     \property QGraphicsScene::stickyFocus
3055     \brief whether clicking into the scene background will clear focus
3056 
3057     \since 4.6
3058 
3059     In a QGraphicsScene with stickyFocus set to true, focus will remain
3060     unchanged when the user clicks into the scene background or on an item
3061     that does not accept focus. Otherwise, focus will be cleared.
3062 
3063     By default, this property is \c false.
3064 
3065     Focus changes in response to a mouse press. You can reimplement
3066     mousePressEvent() in a subclass of QGraphicsScene to toggle this property
3067     based on where the user has clicked.
3068 
3069     \sa clearFocus(), setFocusItem()
3070 */
setStickyFocus(bool enabled)3071 void QGraphicsScene::setStickyFocus(bool enabled)
3072 {
3073     Q_D(QGraphicsScene);
3074     d->stickyFocus = enabled;
3075 }
stickyFocus() const3076 bool QGraphicsScene::stickyFocus() const
3077 {
3078     Q_D(const QGraphicsScene);
3079     return d->stickyFocus;
3080 }
3081 
3082 /*!
3083     Returns the current mouse grabber item, or \nullptr if no item is
3084     currently grabbing the mouse. The mouse grabber item is the item
3085     that receives all mouse events sent to the scene.
3086 
3087     An item becomes a mouse grabber when it receives and accepts a
3088     mouse press event, and it stays the mouse grabber until either of
3089     the following events occur:
3090 
3091     \list
3092     \li If the item receives a mouse release event when there are no other
3093     buttons pressed, it loses the mouse grab.
3094     \li If the item becomes invisible (i.e., someone calls \c {item->setVisible(false)}),
3095     or if it becomes disabled (i.e., someone calls \c {item->setEnabled(false)}),
3096     it loses the mouse grab.
3097     \li If the item is removed from the scene, it loses the mouse grab.
3098     \endlist
3099 
3100     If the item loses its mouse grab, the scene will ignore all mouse events
3101     until a new item grabs the mouse (i.e., until a new item receives a mouse
3102     press event).
3103 */
mouseGrabberItem() const3104 QGraphicsItem *QGraphicsScene::mouseGrabberItem() const
3105 {
3106     Q_D(const QGraphicsScene);
3107     return !d->mouseGrabberItems.isEmpty() ? d->mouseGrabberItems.last() : 0;
3108 }
3109 
3110 /*!
3111     \property QGraphicsScene::backgroundBrush
3112     \brief the background brush of the scene.
3113 
3114     Set this property to changes the scene's background to a different color,
3115     gradient or texture. The default background brush is Qt::NoBrush. The
3116     background is drawn before (behind) the items.
3117 
3118     Example:
3119 
3120     \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 3
3121 
3122     QGraphicsScene::render() calls drawBackground() to draw the scene
3123     background. For more detailed control over how the background is drawn,
3124     you can reimplement drawBackground() in a subclass of QGraphicsScene.
3125 */
backgroundBrush() const3126 QBrush QGraphicsScene::backgroundBrush() const
3127 {
3128     Q_D(const QGraphicsScene);
3129     return d->backgroundBrush;
3130 }
setBackgroundBrush(const QBrush & brush)3131 void QGraphicsScene::setBackgroundBrush(const QBrush &brush)
3132 {
3133     Q_D(QGraphicsScene);
3134     d->backgroundBrush = brush;
3135     foreach (QGraphicsView *view, d->views) {
3136         view->resetCachedContent();
3137         view->viewport()->update();
3138     }
3139     update();
3140 }
3141 
3142 /*!
3143     \property QGraphicsScene::foregroundBrush
3144     \brief the foreground brush of the scene.
3145 
3146     Change this property to set the scene's foreground to a different
3147     color, gradient or texture.
3148 
3149     The foreground is drawn after (on top of) the items. The default
3150     foreground brush is Qt::NoBrush ( i.e. the foreground is not
3151     drawn).
3152 
3153     Example:
3154 
3155     \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 4
3156 
3157     QGraphicsScene::render() calls drawForeground() to draw the scene
3158     foreground. For more detailed control over how the foreground is
3159     drawn, you can reimplement the drawForeground() function in a
3160     QGraphicsScene subclass.
3161 */
foregroundBrush() const3162 QBrush QGraphicsScene::foregroundBrush() const
3163 {
3164     Q_D(const QGraphicsScene);
3165     return d->foregroundBrush;
3166 }
setForegroundBrush(const QBrush & brush)3167 void QGraphicsScene::setForegroundBrush(const QBrush &brush)
3168 {
3169     Q_D(QGraphicsScene);
3170     d->foregroundBrush = brush;
3171     const auto views_ = views();
3172     for (QGraphicsView *view : views_)
3173         view->viewport()->update();
3174     update();
3175 }
3176 
3177 /*!
3178     This method is used by input methods to query a set of properties of
3179     the scene to be able to support complex input method operations as support
3180     for surrounding text and reconversions.
3181 
3182     The \a query parameter specifies which property is queried.
3183 
3184     \sa QWidget::inputMethodQuery()
3185 */
inputMethodQuery(Qt::InputMethodQuery query) const3186 QVariant QGraphicsScene::inputMethodQuery(Qt::InputMethodQuery query) const
3187 {
3188     Q_D(const QGraphicsScene);
3189     if (!d->focusItem || !(d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
3190         return QVariant();
3191     const QTransform matrix = d->focusItem->sceneTransform();
3192     QVariant value = d->focusItem->inputMethodQuery(query);
3193     if (value.userType() == QMetaType::QRectF)
3194         value = matrix.mapRect(value.toRectF());
3195     else if (value.userType() == QMetaType::QPointF)
3196         value = matrix.map(value.toPointF());
3197     else if (value.userType() == QMetaType::QRect)
3198         value = matrix.mapRect(value.toRect());
3199     else if (value.userType() == QMetaType::QPoint)
3200         value = matrix.map(value.toPoint());
3201     return value;
3202 }
3203 
3204 /*!
3205     \fn void QGraphicsScene::update(const QRectF &rect)
3206     Schedules a redraw of the area \a rect on the scene.
3207 
3208     \sa sceneRect(), changed()
3209 */
update(const QRectF & rect)3210 void QGraphicsScene::update(const QRectF &rect)
3211 {
3212     Q_D(QGraphicsScene);
3213     if (d->updateAll || (rect.isEmpty() && !rect.isNull()))
3214         return;
3215 
3216     // Check if anyone's connected; if not, we can send updates directly to
3217     // the views. Otherwise or if there are no views, use old behavior.
3218     bool directUpdates = !(d->isSignalConnected(d->changedSignalIndex)) && !d->views.isEmpty();
3219     if (rect.isNull()) {
3220         d->updateAll = true;
3221         d->updatedRects.clear();
3222         if (directUpdates) {
3223             // Update all views.
3224             for (int i = 0; i < d->views.size(); ++i)
3225                 d->views.at(i)->d_func()->fullUpdatePending = true;
3226         }
3227     } else {
3228         if (directUpdates) {
3229             // Update all views.
3230             for (int i = 0; i < d->views.size(); ++i) {
3231                 QGraphicsView *view = d->views.at(i);
3232                 if (view->isTransformed())
3233                     view->d_func()->updateRectF(view->viewportTransform().mapRect(rect));
3234                 else
3235                     view->d_func()->updateRectF(rect);
3236             }
3237         } else {
3238             d->updatedRects.insert(rect);
3239         }
3240     }
3241 
3242     if (!d->calledEmitUpdated) {
3243         d->calledEmitUpdated = true;
3244         QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection);
3245     }
3246 }
3247 
3248 /*!
3249     \fn void QGraphicsScene::update(qreal x, qreal y, qreal w, qreal h)
3250     \overload
3251     \since 4.3
3252 
3253     This function is equivalent to calling update(QRectF(\a x, \a y, \a w,
3254     \a h));
3255 */
3256 
3257 /*!
3258     Invalidates and schedules a redraw of the \a layers in \a rect on the
3259     scene. Any cached content in \a layers is unconditionally invalidated and
3260     redrawn.
3261 
3262     You can use this function overload to notify QGraphicsScene of changes to
3263     the background or the foreground of the scene. This function is commonly
3264     used for scenes with tile-based backgrounds to notify changes when
3265     QGraphicsView has enabled
3266     \l{QGraphicsView::CacheBackground}{CacheBackground}.
3267 
3268     Example:
3269 
3270     \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 5
3271 
3272     Note that QGraphicsView currently supports background caching only (see
3273     QGraphicsView::CacheBackground). This function is equivalent to calling
3274     update() if any layer but BackgroundLayer is passed.
3275 
3276     \sa QGraphicsView::resetCachedContent()
3277 */
invalidate(const QRectF & rect,SceneLayers layers)3278 void QGraphicsScene::invalidate(const QRectF &rect, SceneLayers layers)
3279 {
3280     const auto views_ = views();
3281     for (QGraphicsView *view : views_)
3282         view->invalidateScene(rect, layers);
3283     update(rect);
3284 }
3285 
3286 /*!
3287     \fn void QGraphicsScene::invalidate(qreal x, qreal y, qreal w, qreal h, SceneLayers layers)
3288     \overload
3289     \since 4.3
3290 
3291     This convenience function is equivalent to calling invalidate(QRectF(\a x, \a
3292     y, \a w, \a h), \a layers);
3293 */
3294 
3295 /*!
3296     Returns a list of all the views that display this scene.
3297 
3298     \sa QGraphicsView::scene()
3299 */
views() const3300 QList <QGraphicsView *> QGraphicsScene::views() const
3301 {
3302     Q_D(const QGraphicsScene);
3303     return d->views;
3304 }
3305 
3306 /*!
3307     This slot \e advances the scene by one step, by calling
3308     QGraphicsItem::advance() for all items on the scene. This is done in two
3309     phases: in the first phase, all items are notified that the scene is about
3310     to change, and in the second phase all items are notified that they can
3311     move. In the first phase, QGraphicsItem::advance() is called passing a
3312     value of 0 as an argument, and 1 is passed in the second phase.
3313 
3314     Note that you can also use the \l{The Animation Framework}{Animation
3315     Framework} for animations.
3316 
3317     \sa QGraphicsItem::advance(), QTimeLine
3318 */
advance()3319 void QGraphicsScene::advance()
3320 {
3321     for (int i = 0; i < 2; ++i) {
3322         const auto items_ = items();
3323         for (QGraphicsItem *item : items_)
3324             item->advance(i);
3325     }
3326 }
3327 
3328 /*!
3329     Processes the event \a event, and dispatches it to the respective
3330     event handlers.
3331 
3332     In addition to calling the convenience event handlers, this
3333     function is responsible for converting mouse move events to hover
3334     events for when there is no mouse grabber item. Hover events are
3335     delivered directly to items; there is no convenience function for
3336     them.
3337 
3338     Unlike QWidget, QGraphicsScene does not have the convenience functions
3339     \l{QWidget::}{enterEvent()} and \l{QWidget::}{leaveEvent()}. Use this
3340     function to obtain those events instead.
3341 
3342     Returns \c true if \a event has been recognized and processed; otherwise,
3343     returns \c false.
3344 
3345     \sa contextMenuEvent(), keyPressEvent(), keyReleaseEvent(),
3346     mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(),
3347     mouseDoubleClickEvent(), focusInEvent(), focusOutEvent()
3348 */
event(QEvent * event)3349 bool QGraphicsScene::event(QEvent *event)
3350 {
3351     Q_D(QGraphicsScene);
3352 
3353     switch (event->type()) {
3354     case QEvent::GraphicsSceneMousePress:
3355     case QEvent::GraphicsSceneMouseMove:
3356     case QEvent::GraphicsSceneMouseRelease:
3357     case QEvent::GraphicsSceneMouseDoubleClick:
3358     case QEvent::GraphicsSceneHoverEnter:
3359     case QEvent::GraphicsSceneHoverLeave:
3360     case QEvent::GraphicsSceneHoverMove:
3361     case QEvent::TouchBegin:
3362     case QEvent::TouchUpdate:
3363     case QEvent::TouchEnd:
3364         // Reset the under-mouse list to ensure that this event gets fresh
3365         // item-under-mouse data. Be careful about this list; if people delete
3366         // items from inside event handlers, this list can quickly end up
3367         // having stale pointers in it. We need to clear it before dispatching
3368         // events that use it.
3369         // ### this should only be cleared if we received a new mouse move event,
3370         // which relies on us fixing the replay mechanism in QGraphicsView.
3371         d->cachedItemsUnderMouse.clear();
3372     default:
3373         break;
3374     }
3375 
3376     switch (event->type()) {
3377     case QEvent::GraphicsSceneDragEnter:
3378         dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3379         break;
3380     case QEvent::GraphicsSceneDragMove:
3381         dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3382         break;
3383     case QEvent::GraphicsSceneDragLeave:
3384         dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3385         break;
3386     case QEvent::GraphicsSceneDrop:
3387         dropEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3388         break;
3389     case QEvent::GraphicsSceneContextMenu:
3390         contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent *>(event));
3391         break;
3392     case QEvent::KeyPress:
3393         if (!d->focusItem) {
3394             QKeyEvent *k = static_cast<QKeyEvent *>(event);
3395             if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
3396                 if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {  //### Add MetaModifier?
3397                     bool res = false;
3398                     if (k->key() == Qt::Key_Backtab
3399                         || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) {
3400                         res = focusNextPrevChild(false);
3401                     } else if (k->key() == Qt::Key_Tab) {
3402                         res = focusNextPrevChild(true);
3403                     }
3404                     if (!res)
3405                         event->ignore();
3406                     return true;
3407                 }
3408             }
3409         }
3410         keyPressEvent(static_cast<QKeyEvent *>(event));
3411         break;
3412     case QEvent::KeyRelease:
3413         keyReleaseEvent(static_cast<QKeyEvent *>(event));
3414         break;
3415     case QEvent::ShortcutOverride: {
3416             QGraphicsItem *parent = focusItem();
3417             while (parent) {
3418                 d->sendEvent(parent, event);
3419                 if (event->isAccepted())
3420                     return true;
3421                 parent = parent->parentItem();
3422             }
3423         }
3424         return false;
3425     case QEvent::GraphicsSceneMouseMove:
3426     {
3427         QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent *>(event);
3428         d->lastSceneMousePos = mouseEvent->scenePos();
3429         mouseMoveEvent(mouseEvent);
3430         break;
3431     }
3432     case QEvent::GraphicsSceneMousePress:
3433         mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3434         break;
3435     case QEvent::GraphicsSceneMouseRelease:
3436         mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3437         break;
3438     case QEvent::GraphicsSceneMouseDoubleClick:
3439         mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3440         break;
3441     case QEvent::GraphicsSceneWheel:
3442         wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event));
3443         break;
3444     case QEvent::FocusIn:
3445         focusInEvent(static_cast<QFocusEvent *>(event));
3446         break;
3447     case QEvent::FocusOut:
3448         focusOutEvent(static_cast<QFocusEvent *>(event));
3449         break;
3450     case QEvent::GraphicsSceneHoverEnter:
3451     case QEvent::GraphicsSceneHoverLeave:
3452     case QEvent::GraphicsSceneHoverMove:
3453     {
3454         QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event);
3455         d->lastSceneMousePos = hoverEvent->scenePos();
3456         d->dispatchHoverEvent(hoverEvent);
3457         break;
3458     }
3459     case QEvent::Leave:
3460         // hackieshly unpacking the viewport pointer from the leave event.
3461         d->leaveScene(reinterpret_cast<QWidget *>(event->d));
3462         break;
3463     case QEvent::GraphicsSceneHelp:
3464         helpEvent(static_cast<QGraphicsSceneHelpEvent *>(event));
3465         break;
3466     case QEvent::InputMethod:
3467         inputMethodEvent(static_cast<QInputMethodEvent *>(event));
3468         break;
3469     case QEvent::WindowActivate:
3470         if (!d->activationRefCount++) {
3471             if (d->lastActivePanel) {
3472                 // Activate the last panel.
3473                 d->setActivePanelHelper(d->lastActivePanel, true);
3474             } else if (d->tabFocusFirst && d->tabFocusFirst->isPanel()) {
3475                 // Activate the panel of the first item in the tab focus
3476                 // chain.
3477                 d->setActivePanelHelper(d->tabFocusFirst, true);
3478             } else {
3479                 // Activate all toplevel items.
3480                 QEvent event(QEvent::WindowActivate);
3481                 const auto items_ = items();
3482                 for (QGraphicsItem *item : items_) {
3483                     if (item->isVisible() && !item->isPanel() && !item->parentItem())
3484                         sendEvent(item, &event);
3485                 }
3486             }
3487         }
3488         break;
3489     case QEvent::WindowDeactivate:
3490         if (!--d->activationRefCount) {
3491             if (d->activePanel) {
3492                 // Deactivate the active panel (but keep it so we can
3493                 // reactivate it later).
3494                 QGraphicsItem *lastActivePanel = d->activePanel;
3495                 d->setActivePanelHelper(nullptr, true);
3496                 d->lastActivePanel = lastActivePanel;
3497             } else {
3498                 // Activate all toplevel items.
3499                 QEvent event(QEvent::WindowDeactivate);
3500                 const auto items_ = items();
3501                 for (QGraphicsItem *item : items_) {
3502                     if (item->isVisible() && !item->isPanel() && !item->parentItem())
3503                         sendEvent(item, &event);
3504                 }
3505             }
3506         }
3507         break;
3508     case QEvent::ApplicationFontChange: {
3509         // Resolve the existing scene font.
3510         d->resolveFont();
3511         break;
3512     }
3513     case QEvent::FontChange:
3514         // Update the entire scene when the font changes.
3515         update();
3516         break;
3517     case QEvent::ApplicationPaletteChange: {
3518         // Resolve the existing scene palette.
3519         d->resolvePalette();
3520         break;
3521     }
3522     case QEvent::PaletteChange:
3523         // Update the entire scene when the palette changes.
3524         update();
3525         break;
3526     case QEvent::StyleChange:
3527         // Reresolve all widgets' styles. Update all top-level widgets'
3528         // geometries that do not have an explicit style set.
3529         update();
3530         break;
3531     case QEvent::StyleAnimationUpdate:
3532         // Because QGraphicsItem is not a QObject, QStyle driven
3533         // animations are forced to update the whole scene
3534         update();
3535         break;
3536     case QEvent::TouchBegin:
3537     case QEvent::TouchUpdate:
3538     case QEvent::TouchEnd:
3539         d->touchEventHandler(static_cast<QTouchEvent *>(event));
3540         break;
3541 #ifndef QT_NO_GESTURES
3542     case QEvent::Gesture:
3543     case QEvent::GestureOverride:
3544         d->gestureEventHandler(static_cast<QGestureEvent *>(event));
3545         break;
3546 #endif // QT_NO_GESTURES
3547     default:
3548         return QObject::event(event);
3549     }
3550     return true;
3551 }
3552 
3553 /*!
3554     \reimp
3555 
3556     QGraphicsScene filters QApplication's events to detect palette and font
3557     changes.
3558 */
eventFilter(QObject * watched,QEvent * event)3559 bool QGraphicsScene::eventFilter(QObject *watched, QEvent *event)
3560 {
3561     if (watched != qApp)
3562         return false;
3563 
3564     switch (event->type()) {
3565     case QEvent::ApplicationPaletteChange:
3566         QCoreApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
3567         break;
3568     case QEvent::ApplicationFontChange:
3569         QCoreApplication::postEvent(this, new QEvent(QEvent::ApplicationFontChange));
3570         break;
3571     default:
3572         break;
3573     }
3574     return false;
3575 }
3576 
3577 /*!
3578     This event handler, for event \a contextMenuEvent, can be reimplemented in
3579     a subclass to receive context menu events. The default implementation
3580     forwards the event to the topmost visible item that accepts context menu events at
3581     the position of the event. If no items accept context menu events at this
3582     position, the event is ignored.
3583 
3584     Note: See items() for a definition of which items are considered visible by this function.
3585 
3586     \sa QGraphicsItem::contextMenuEvent()
3587 */
contextMenuEvent(QGraphicsSceneContextMenuEvent * contextMenuEvent)3588 void QGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *contextMenuEvent)
3589 {
3590     Q_D(QGraphicsScene);
3591     // Ignore by default.
3592     contextMenuEvent->ignore();
3593 
3594     // Send the event to all items at this position until one item accepts the
3595     // event.
3596     const auto items = d->itemsAtPosition(contextMenuEvent->screenPos(),
3597                                           contextMenuEvent->scenePos(),
3598                                           contextMenuEvent->widget());
3599     for (QGraphicsItem *item : items) {
3600         contextMenuEvent->setPos(item->d_ptr->genericMapFromScene(contextMenuEvent->scenePos(),
3601                                                                   contextMenuEvent->widget()));
3602         contextMenuEvent->accept();
3603         if (!d->sendEvent(item, contextMenuEvent))
3604             break;
3605 
3606         if (contextMenuEvent->isAccepted())
3607             break;
3608     }
3609 }
3610 
3611 /*!
3612     This event handler, for event \a event, can be reimplemented in a subclass
3613     to receive drag enter events for the scene.
3614 
3615     The default implementation accepts the event and prepares the scene to
3616     accept drag move events.
3617 
3618     \sa QGraphicsItem::dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(),
3619     dropEvent()
3620 */
dragEnterEvent(QGraphicsSceneDragDropEvent * event)3621 void QGraphicsScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
3622 {
3623     Q_D(QGraphicsScene);
3624     d->dragDropItem = nullptr;
3625     d->lastDropAction = Qt::IgnoreAction;
3626     event->accept();
3627 }
3628 
3629 /*!
3630     This event handler, for event \a event, can be reimplemented in a subclass
3631     to receive drag move events for the scene.
3632 
3633     Note: See items() for a definition of which items are considered visible by this function.
3634 
3635     \sa QGraphicsItem::dragMoveEvent(), dragEnterEvent(), dragLeaveEvent(),
3636     dropEvent()
3637 */
dragMoveEvent(QGraphicsSceneDragDropEvent * event)3638 void QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
3639 {
3640     Q_D(QGraphicsScene);
3641     event->ignore();
3642 
3643     if (!d->mouseGrabberItems.isEmpty()) {
3644         // Mouse grabbers that start drag events lose the mouse grab.
3645         d->clearMouseGrabber();
3646         d->mouseGrabberButtonDownPos.clear();
3647         d->mouseGrabberButtonDownScenePos.clear();
3648         d->mouseGrabberButtonDownScreenPos.clear();
3649     }
3650 
3651     bool eventDelivered = false;
3652 
3653     // Find the topmost enabled items under the cursor. They are all
3654     // candidates for accepting drag & drop events.
3655     const auto items = d->itemsAtPosition(event->screenPos(),
3656                                           event->scenePos(),
3657                                           event->widget());
3658     for (QGraphicsItem *item : items) {
3659         if (!item->isEnabled() || !item->acceptDrops())
3660             continue;
3661 
3662         if (item != d->dragDropItem) {
3663             // Enter the new drag drop item. If it accepts the event, we send
3664             // the leave to the parent item.
3665             QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);
3666             d->cloneDragDropEvent(&dragEnter, event);
3667             dragEnter.setDropAction(event->proposedAction());
3668             d->sendDragDropEvent(item, &dragEnter);
3669             event->setAccepted(dragEnter.isAccepted());
3670             event->setDropAction(dragEnter.dropAction());
3671             if (!event->isAccepted()) {
3672                 // Propagate to the item under
3673                 continue;
3674             }
3675 
3676             d->lastDropAction = event->dropAction();
3677 
3678             if (d->dragDropItem) {
3679                 // Leave the last drag drop item. A perfect implementation
3680                 // would set the position of this event to the point where
3681                 // this event and the last event intersect with the item's
3682                 // shape, but that's not easy to do. :-)
3683                 QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
3684                 d->cloneDragDropEvent(&dragLeave, event);
3685                 d->sendDragDropEvent(d->dragDropItem, &dragLeave);
3686             }
3687 
3688             // We've got a new drag & drop item
3689             d->dragDropItem = item;
3690         }
3691 
3692         // Send the move event.
3693         event->setDropAction(d->lastDropAction);
3694         event->accept();
3695         d->sendDragDropEvent(item, event);
3696         if (event->isAccepted())
3697             d->lastDropAction = event->dropAction();
3698         eventDelivered = true;
3699         break;
3700     }
3701 
3702     if (!eventDelivered) {
3703         if (d->dragDropItem) {
3704             // Leave the last drag drop item
3705             QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
3706             d->cloneDragDropEvent(&dragLeave, event);
3707             d->sendDragDropEvent(d->dragDropItem, &dragLeave);
3708             d->dragDropItem = nullptr;
3709         }
3710         // Propagate
3711         event->setDropAction(Qt::IgnoreAction);
3712     }
3713 }
3714 
3715 /*!
3716     This event handler, for event \a event, can be reimplemented in a subclass
3717     to receive drag leave events for the scene.
3718 
3719     \sa QGraphicsItem::dragLeaveEvent(), dragEnterEvent(), dragMoveEvent(),
3720     dropEvent()
3721 */
dragLeaveEvent(QGraphicsSceneDragDropEvent * event)3722 void QGraphicsScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
3723 {
3724     Q_D(QGraphicsScene);
3725     if (d->dragDropItem) {
3726         // Leave the last drag drop item
3727         d->sendDragDropEvent(d->dragDropItem, event);
3728         d->dragDropItem = nullptr;
3729     }
3730 }
3731 
3732 /*!
3733     This event handler, for event \a event, can be reimplemented in a subclass
3734     to receive drop events for the scene.
3735 
3736     \sa QGraphicsItem::dropEvent(), dragEnterEvent(), dragMoveEvent(),
3737     dragLeaveEvent()
3738 */
dropEvent(QGraphicsSceneDragDropEvent * event)3739 void QGraphicsScene::dropEvent(QGraphicsSceneDragDropEvent *event)
3740 {
3741     Q_UNUSED(event);
3742     Q_D(QGraphicsScene);
3743     if (d->dragDropItem) {
3744         // Drop on the last drag drop item
3745         d->sendDragDropEvent(d->dragDropItem, event);
3746         d->dragDropItem = nullptr;
3747     }
3748 }
3749 
3750 /*!
3751     This event handler, for event \a focusEvent, can be reimplemented in a
3752     subclass to receive focus in events.
3753 
3754     The default implementation sets focus on the scene, and then on the last
3755     focus item.
3756 
3757     \sa QGraphicsItem::focusOutEvent()
3758 */
focusInEvent(QFocusEvent * focusEvent)3759 void QGraphicsScene::focusInEvent(QFocusEvent *focusEvent)
3760 {
3761     Q_D(QGraphicsScene);
3762 
3763     d->hasFocus = true;
3764     switch (focusEvent->reason()) {
3765     case Qt::TabFocusReason:
3766         if (!focusNextPrevChild(true))
3767             focusEvent->ignore();
3768         break;
3769     case Qt::BacktabFocusReason:
3770         if (!focusNextPrevChild(false))
3771             focusEvent->ignore();
3772         break;
3773     default:
3774         if (d->passiveFocusItem) {
3775             // Set focus on the last focus item
3776             setFocusItem(d->passiveFocusItem, focusEvent->reason());
3777         }
3778         break;
3779     }
3780 }
3781 
3782 /*!
3783     This event handler, for event \a focusEvent, can be reimplemented in a
3784     subclass to receive focus out events.
3785 
3786     The default implementation removes focus from any focus item, then removes
3787     focus from the scene.
3788 
3789     \sa QGraphicsItem::focusInEvent()
3790 */
focusOutEvent(QFocusEvent * focusEvent)3791 void QGraphicsScene::focusOutEvent(QFocusEvent *focusEvent)
3792 {
3793     Q_D(QGraphicsScene);
3794     d->hasFocus = false;
3795     d->passiveFocusItem = d->focusItem;
3796     setFocusItem(nullptr, focusEvent->reason());
3797 
3798     // Remove all popups when the scene loses focus.
3799     if (!d->popupWidgets.isEmpty())
3800         d->removePopup(d->popupWidgets.constFirst());
3801 }
3802 
3803 /*!
3804     This event handler, for event \a helpEvent, can be
3805     reimplemented in a subclass to receive help events. The events
3806     are of type QEvent::ToolTip, which are created when a tooltip is
3807     requested.
3808 
3809     The default implementation shows the tooltip of the topmost
3810     visible item, i.e., the item with the highest z-value, at the mouse
3811     cursor position. If no item has a tooltip set, this function
3812     does nothing.
3813 
3814     Note: See items() for a definition of which items are considered visible by this function.
3815 
3816     \sa QGraphicsItem::toolTip(), QGraphicsSceneHelpEvent
3817 */
helpEvent(QGraphicsSceneHelpEvent * helpEvent)3818 void QGraphicsScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent)
3819 {
3820 #ifdef QT_NO_TOOLTIP
3821     Q_UNUSED(helpEvent);
3822 #else
3823     // Find the first item that does tooltips
3824     Q_D(QGraphicsScene);
3825     QList<QGraphicsItem *> itemsAtPos = d->itemsAtPosition(helpEvent->screenPos(),
3826                                                            helpEvent->scenePos(),
3827                                                            helpEvent->widget());
3828     QGraphicsItem *toolTipItem = nullptr;
3829     for (int i = 0; i < itemsAtPos.size(); ++i) {
3830         QGraphicsItem *tmp = itemsAtPos.at(i);
3831         if (tmp->d_func()->isProxyWidget()) {
3832             // if the item is a proxy widget, the event is forwarded to it
3833             sendEvent(tmp, helpEvent);
3834             if (helpEvent->isAccepted())
3835                 return;
3836         }
3837         if (!tmp->toolTip().isEmpty()) {
3838             toolTipItem = tmp;
3839             break;
3840         }
3841     }
3842 
3843     // Show or hide the tooltip
3844     QString text;
3845     QPoint point;
3846     if (toolTipItem && !toolTipItem->toolTip().isEmpty()) {
3847         text = toolTipItem->toolTip();
3848         point = helpEvent->screenPos();
3849     }
3850     QToolTip::showText(point, text, helpEvent->widget());
3851     helpEvent->setAccepted(!text.isEmpty());
3852 #endif
3853 }
3854 
itemAcceptsHoverEvents_helper(const QGraphicsItem * item) const3855 bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const
3856 {
3857     return (item->d_ptr->acceptsHover
3858             || (item->d_ptr->isWidget
3859                 && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration()))
3860            && !item->isBlockedByModalPanel();
3861 }
3862 
3863 /*!
3864     This event handler, for event \a hoverEvent, can be reimplemented in a
3865     subclass to receive hover enter events. The default implementation
3866     forwards the event to the topmost visible item that accepts hover events at the
3867     scene position from the event.
3868 
3869     Note: See items() for a definition of which items are considered visible by this function.
3870 
3871     \sa QGraphicsItem::hoverEvent(), QGraphicsItem::setAcceptHoverEvents()
3872 */
dispatchHoverEvent(QGraphicsSceneHoverEvent * hoverEvent)3873 bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent)
3874 {
3875     if (allItemsIgnoreHoverEvents)
3876         return false;
3877 
3878     // Find the first item that accepts hover events, reusing earlier
3879     // calculated data is possible.
3880     if (cachedItemsUnderMouse.isEmpty()) {
3881         cachedItemsUnderMouse = itemsAtPosition(hoverEvent->screenPos(),
3882                                                 hoverEvent->scenePos(),
3883                                                 hoverEvent->widget());
3884     }
3885 
3886     QGraphicsItem *item = nullptr;
3887     for (int i = 0; i < cachedItemsUnderMouse.size(); ++i) {
3888         QGraphicsItem *tmp = cachedItemsUnderMouse.at(i);
3889         if (itemAcceptsHoverEvents_helper(tmp)) {
3890             item = tmp;
3891             break;
3892         }
3893     }
3894 
3895     // Find the common ancestor item for the new topmost hoverItem and the
3896     // last item in the hoverItem list.
3897     QGraphicsItem *commonAncestorItem = (item && !hoverItems.isEmpty()) ? item->commonAncestorItem(hoverItems.constLast()) : nullptr;
3898     while (commonAncestorItem && !itemAcceptsHoverEvents_helper(commonAncestorItem))
3899         commonAncestorItem = commonAncestorItem->parentItem();
3900     if (commonAncestorItem && commonAncestorItem->panel() != item->panel()) {
3901         // The common ancestor isn't in the same panel as the two hovered
3902         // items.
3903         commonAncestorItem = nullptr;
3904     }
3905 
3906     // Check if the common ancestor item is known.
3907     int index = commonAncestorItem ? hoverItems.indexOf(commonAncestorItem) : -1;
3908     // Send hover leaves to any existing hovered children of the common
3909     // ancestor item.
3910     for (int i = hoverItems.size() - 1; i > index; --i) {
3911         QGraphicsItem *lastItem = hoverItems.takeLast();
3912         if (itemAcceptsHoverEvents_helper(lastItem))
3913             sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, hoverEvent);
3914     }
3915 
3916     // Item is a child of a known item. Generate enter events for the
3917     // missing links.
3918     QList<QGraphicsItem *> parents;
3919     QGraphicsItem *parent = item;
3920     while (parent && parent != commonAncestorItem) {
3921         parents.append(parent);
3922         if (parent->isPanel()) {
3923             // Stop at the panel - we don't deliver beyond this point.
3924             break;
3925         }
3926         parent = parent->parentItem();
3927     }
3928     for (auto it = parents.crbegin(), end = parents.crend(); it != end; ++it) {
3929         QGraphicsItem *parent = *it;
3930         hoverItems << parent;
3931         if (itemAcceptsHoverEvents_helper(parent))
3932             sendHoverEvent(QEvent::GraphicsSceneHoverEnter, parent, hoverEvent);
3933     }
3934 
3935     // Generate a move event for the item itself
3936     if (item
3937         && !hoverItems.isEmpty()
3938         && item == hoverItems.constLast()) {
3939         sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, hoverEvent);
3940         return true;
3941     }
3942     return false;
3943 }
3944 
3945 /*!
3946     \internal
3947 
3948     Handles all actions necessary to clean up the scene when the mouse leaves
3949     the view.
3950 */
leaveScene(QWidget * viewport)3951 void QGraphicsScenePrivate::leaveScene(QWidget *viewport)
3952 {
3953 #ifndef QT_NO_TOOLTIP
3954     QToolTip::hideText();
3955 #endif
3956     QGraphicsView *view = qobject_cast<QGraphicsView *>(viewport->parent());
3957     // Send HoverLeave events to all existing hover items, topmost first.
3958     QGraphicsSceneHoverEvent hoverEvent;
3959     hoverEvent.setWidget(viewport);
3960 
3961     if (view) {
3962         QPoint cursorPos = QCursor::pos();
3963         hoverEvent.setScenePos(view->mapToScene(viewport->mapFromGlobal(cursorPos)));
3964         hoverEvent.setLastScenePos(hoverEvent.scenePos());
3965         hoverEvent.setScreenPos(cursorPos);
3966         hoverEvent.setLastScreenPos(hoverEvent.screenPos());
3967     }
3968 
3969     while (!hoverItems.isEmpty()) {
3970         QGraphicsItem *lastItem = hoverItems.takeLast();
3971         if (itemAcceptsHoverEvents_helper(lastItem))
3972             sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, &hoverEvent);
3973     }
3974 }
3975 
3976 /*!
3977     This event handler, for event \a keyEvent, can be reimplemented in a
3978     subclass to receive keypress events. The default implementation forwards
3979     the event to current focus item.
3980 
3981     \sa QGraphicsItem::keyPressEvent(), focusItem()
3982 */
keyPressEvent(QKeyEvent * keyEvent)3983 void QGraphicsScene::keyPressEvent(QKeyEvent *keyEvent)
3984 {
3985     // ### Merge this function with keyReleaseEvent; they are identical
3986     // ### (except this comment).
3987     Q_D(QGraphicsScene);
3988     QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.constLast() : 0;
3989     if (!item)
3990         item = focusItem();
3991     if (item) {
3992         QGraphicsItem *p = item;
3993         do {
3994             // Accept the event by default
3995             keyEvent->accept();
3996             // Send it; QGraphicsItem::keyPressEvent ignores it.  If the event
3997             // is filtered out, stop propagating it.
3998             if (p->isBlockedByModalPanel())
3999                 break;
4000             if (!d->sendEvent(p, keyEvent))
4001                 break;
4002         } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
4003     } else {
4004         keyEvent->ignore();
4005     }
4006 }
4007 
4008 /*!
4009     This event handler, for event \a keyEvent, can be reimplemented in a
4010     subclass to receive key release events. The default implementation
4011     forwards the event to current focus item.
4012 
4013     \sa QGraphicsItem::keyReleaseEvent(), focusItem()
4014 */
keyReleaseEvent(QKeyEvent * keyEvent)4015 void QGraphicsScene::keyReleaseEvent(QKeyEvent *keyEvent)
4016 {
4017     // ### Merge this function with keyPressEvent; they are identical (except
4018     // ### this comment).
4019     Q_D(QGraphicsScene);
4020     QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.constLast() : 0;
4021     if (!item)
4022         item = focusItem();
4023     if (item) {
4024         QGraphicsItem *p = item;
4025         do {
4026             // Accept the event by default
4027             keyEvent->accept();
4028             // Send it; QGraphicsItem::keyPressEvent ignores it.  If the event
4029             // is filtered out, stop propagating it.
4030             if (p->isBlockedByModalPanel())
4031                 break;
4032             if (!d->sendEvent(p, keyEvent))
4033                 break;
4034         } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
4035     } else {
4036         keyEvent->ignore();
4037     }
4038 }
4039 
4040 /*!
4041     This event handler, for event \a mouseEvent, can be reimplemented
4042     in a subclass to receive mouse press events for the scene.
4043 
4044     The default implementation depends on the state of the scene. If
4045     there is a mouse grabber item, then the event is sent to the mouse
4046     grabber. Otherwise, it is forwarded to the topmost visible item that
4047     accepts mouse events at the scene position from the event, and
4048     that item promptly becomes the mouse grabber item.
4049 
4050     If there is no item at the given position on the scene, the
4051     selection area is reset, any focus item loses its input focus, and
4052     the event is then ignored.
4053 
4054     Note: See items() for a definition of which items are considered visible by this function.
4055 
4056     \sa QGraphicsItem::mousePressEvent(),
4057     QGraphicsItem::setAcceptedMouseButtons()
4058 */
mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent)4059 void QGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
4060 {
4061     Q_D(QGraphicsScene);
4062     if (d->mouseGrabberItems.isEmpty()) {
4063         // Dispatch hover events
4064         QGraphicsSceneHoverEvent hover;
4065         _q_hoverFromMouseEvent(&hover, mouseEvent);
4066         d->dispatchHoverEvent(&hover);
4067     }
4068 
4069     d->mousePressEventHandler(mouseEvent);
4070 }
4071 
4072 /*!
4073     This event handler, for event \a mouseEvent, can be reimplemented
4074     in a subclass to receive mouse move events for the scene.
4075 
4076     The default implementation depends on the mouse grabber state. If there is
4077     a mouse grabber item, the event is sent to the mouse grabber.  If there
4078     are any items that accept hover events at the current position, the event
4079     is translated into a hover event and accepted; otherwise it's ignored.
4080 
4081     \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseReleaseEvent(),
4082     QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
4083 */
mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent)4084 void QGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
4085 {
4086     Q_D(QGraphicsScene);
4087     if (d->mouseGrabberItems.isEmpty()) {
4088         if (mouseEvent->buttons())
4089             return;
4090         QGraphicsSceneHoverEvent hover;
4091         _q_hoverFromMouseEvent(&hover, mouseEvent);
4092         mouseEvent->setAccepted(d->dispatchHoverEvent(&hover));
4093         return;
4094     }
4095 
4096     // Forward the event to the mouse grabber
4097     d->sendMouseEvent(mouseEvent);
4098     mouseEvent->accept();
4099 }
4100 
4101 /*!
4102     This event handler, for event \a mouseEvent, can be reimplemented
4103     in a subclass to receive mouse release events for the scene.
4104 
4105     The default implementation depends on the mouse grabber state.  If
4106     there is no mouse grabber, the event is ignored.  Otherwise, if
4107     there is a mouse grabber item, the event is sent to the mouse
4108     grabber. If this mouse release represents the last pressed button
4109     on the mouse, the mouse grabber item then loses the mouse grab.
4110 
4111     \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
4112     QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
4113 */
mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent)4114 void QGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
4115 {
4116     Q_D(QGraphicsScene);
4117     if (d->mouseGrabberItems.isEmpty()) {
4118         mouseEvent->ignore();
4119         return;
4120     }
4121 
4122     // Forward the event to the mouse grabber
4123     d->sendMouseEvent(mouseEvent);
4124     mouseEvent->accept();
4125 
4126     // Reset the mouse grabber when the last mouse button has been released.
4127     if (!mouseEvent->buttons()) {
4128         if (!d->mouseGrabberItems.isEmpty()) {
4129             d->lastMouseGrabberItem = d->mouseGrabberItems.constLast();
4130             if (d->lastMouseGrabberItemHasImplicitMouseGrab)
4131                 d->mouseGrabberItems.constLast()->ungrabMouse();
4132         } else {
4133             d->lastMouseGrabberItem = nullptr;
4134         }
4135 
4136         // Generate a hoverevent
4137         QGraphicsSceneHoverEvent hoverEvent;
4138         _q_hoverFromMouseEvent(&hoverEvent, mouseEvent);
4139         d->dispatchHoverEvent(&hoverEvent);
4140     }
4141 }
4142 
4143 /*!
4144     This event handler, for event \a mouseEvent, can be reimplemented
4145     in a subclass to receive mouse doubleclick events for the scene.
4146 
4147     If someone doubleclicks on the scene, the scene will first receive
4148     a mouse press event, followed by a release event (i.e., a click),
4149     then a doubleclick event, and finally a release event. If the
4150     doubleclick event is delivered to a different item than the one
4151     that received the first press and release, it will be delivered as
4152     a press event. However, tripleclick events are not delivered as
4153     doubleclick events in this case.
4154 
4155     The default implementation is similar to mousePressEvent().
4156 
4157     Note: See items() for a definition of which items are considered visible by this function.
4158 
4159     \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
4160     QGraphicsItem::mouseReleaseEvent(), QGraphicsItem::setAcceptedMouseButtons()
4161 */
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * mouseEvent)4162 void QGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
4163 {
4164     Q_D(QGraphicsScene);
4165     d->mousePressEventHandler(mouseEvent);
4166 }
4167 
4168 /*!
4169     This event handler, for event \a wheelEvent, can be reimplemented in a
4170     subclass to receive mouse wheel events for the scene.
4171 
4172     By default, the event is delivered to the topmost visible item under the
4173     cursor. If ignored, the event propagates to the item beneath, and again
4174     until the event is accepted, or it reaches the scene. If no items accept
4175     the event, it is ignored.
4176 
4177     Note: See items() for a definition of which items are considered visible by this function.
4178 
4179     \sa QGraphicsItem::wheelEvent()
4180 */
wheelEvent(QGraphicsSceneWheelEvent * wheelEvent)4181 void QGraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *wheelEvent)
4182 {
4183     Q_D(QGraphicsScene);
4184     const QList<QGraphicsItem *> wheelCandidates = d->itemsAtPosition(wheelEvent->screenPos(),
4185                                                                       wheelEvent->scenePos(),
4186                                                                       wheelEvent->widget());
4187 
4188     // Find the first popup under the mouse (including the popup's descendants) starting from the last.
4189     // Remove all popups after the one found, or all or them if no popup is under the mouse.
4190     // Then continue with the event.
4191     QList<QGraphicsWidget *>::const_iterator iter = d->popupWidgets.constEnd();
4192     while (--iter >= d->popupWidgets.constBegin() && !wheelCandidates.isEmpty()) {
4193         if (wheelCandidates.first() == *iter || (*iter)->isAncestorOf(wheelCandidates.first()))
4194             break;
4195         d->removePopup(*iter);
4196     }
4197 
4198     bool hasSetFocus = false;
4199     for (QGraphicsItem *item : wheelCandidates) {
4200         if (!hasSetFocus && item->isEnabled()
4201             && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
4202             if (item->isWidget() && static_cast<QGraphicsWidget *>(item)->focusPolicy() == Qt::WheelFocus) {
4203                 hasSetFocus = true;
4204                 if (item != focusItem())
4205                     setFocusItem(item, Qt::MouseFocusReason);
4206             }
4207         }
4208 
4209         wheelEvent->setPos(item->d_ptr->genericMapFromScene(wheelEvent->scenePos(),
4210                                                             wheelEvent->widget()));
4211         wheelEvent->accept();
4212         bool isPanel = item->isPanel();
4213         bool ret = d->sendEvent(item, wheelEvent);
4214 
4215         if (ret && (isPanel || wheelEvent->isAccepted()))
4216             break;
4217     }
4218 }
4219 
4220 /*!
4221     This event handler, for event \a event, can be reimplemented in a
4222     subclass to receive input method events for the scene.
4223 
4224     The default implementation forwards the event to the focusItem().
4225     If no item currently has focus or the current focus item does not
4226     accept input methods, this function does nothing.
4227 
4228     \sa QGraphicsItem::inputMethodEvent()
4229 */
inputMethodEvent(QInputMethodEvent * event)4230 void QGraphicsScene::inputMethodEvent(QInputMethodEvent *event)
4231 {
4232     Q_D(QGraphicsScene);
4233     if (d->focusItem && (d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
4234         d->sendEvent(d->focusItem, event);
4235 }
4236 
4237 /*!
4238     Draws the background of the scene using \a painter, before any items and
4239     the foreground are drawn. Reimplement this function to provide a custom
4240     background for the scene.
4241 
4242     All painting is done in \e scene coordinates. The \a rect
4243     parameter is the exposed rectangle.
4244 
4245     If all you want is to define a color, texture, or gradient for the
4246     background, you can call setBackgroundBrush() instead.
4247 
4248     \sa drawForeground(), drawItems()
4249 */
drawBackground(QPainter * painter,const QRectF & rect)4250 void QGraphicsScene::drawBackground(QPainter *painter, const QRectF &rect)
4251 {
4252     Q_D(QGraphicsScene);
4253 
4254     if (d->backgroundBrush.style() != Qt::NoBrush) {
4255         if (d->painterStateProtection)
4256             painter->save();
4257         painter->setBrushOrigin(0, 0);
4258         painter->fillRect(rect, backgroundBrush());
4259         if (d->painterStateProtection)
4260             painter->restore();
4261     }
4262 }
4263 
4264 /*!
4265     Draws the foreground of the scene using \a painter, after the background
4266     and all items have been drawn. Reimplement this function to provide a
4267     custom foreground for the scene.
4268 
4269     All painting is done in \e scene coordinates. The \a rect
4270     parameter is the exposed rectangle.
4271 
4272     If all you want is to define a color, texture or gradient for the
4273     foreground, you can call setForegroundBrush() instead.
4274 
4275     \sa drawBackground(), drawItems()
4276 */
drawForeground(QPainter * painter,const QRectF & rect)4277 void QGraphicsScene::drawForeground(QPainter *painter, const QRectF &rect)
4278 {
4279     Q_D(QGraphicsScene);
4280 
4281     if (d->foregroundBrush.style() != Qt::NoBrush) {
4282         if (d->painterStateProtection)
4283             painter->save();
4284         painter->setBrushOrigin(0, 0);
4285         painter->fillRect(rect, foregroundBrush());
4286         if (d->painterStateProtection)
4287             painter->restore();
4288     }
4289 }
4290 
_q_paintItem(QGraphicsItem * item,QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget,bool useWindowOpacity,bool painterStateProtection)4291 static void _q_paintItem(QGraphicsItem *item, QPainter *painter,
4292                          const QStyleOptionGraphicsItem *option, QWidget *widget,
4293                          bool useWindowOpacity, bool painterStateProtection)
4294 {
4295     if (!item->isWidget()) {
4296         item->paint(painter, option, widget);
4297         return;
4298     }
4299     QGraphicsWidget *widgetItem = static_cast<QGraphicsWidget *>(item);
4300     QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(widgetItem);
4301     const qreal windowOpacity = (proxy && proxy->widget() && useWindowOpacity)
4302                                 ? proxy->widget()->windowOpacity() : 1.0;
4303     const qreal oldPainterOpacity = painter->opacity();
4304 
4305     if (qFuzzyIsNull(windowOpacity))
4306         return;
4307     // Set new painter opacity.
4308     if (windowOpacity < 1.0)
4309         painter->setOpacity(oldPainterOpacity * windowOpacity);
4310 
4311     // set layoutdirection on the painter
4312     Qt::LayoutDirection oldLayoutDirection = painter->layoutDirection();
4313     painter->setLayoutDirection(widgetItem->layoutDirection());
4314 
4315     if (widgetItem->isWindow() && widgetItem->windowType() != Qt::Popup && widgetItem->windowType() != Qt::ToolTip
4316         && !(widgetItem->windowFlags() & Qt::FramelessWindowHint)) {
4317         if (painterStateProtection)
4318             painter->save();
4319         widgetItem->paintWindowFrame(painter, option, widget);
4320         if (painterStateProtection)
4321             painter->restore();
4322     } else if (widgetItem->autoFillBackground()) {
4323         painter->fillRect(option->exposedRect, widgetItem->palette().window());
4324     }
4325 
4326     widgetItem->paint(painter, option, widget);
4327 
4328     // Restore layoutdirection on the painter.
4329     painter->setLayoutDirection(oldLayoutDirection);
4330     // Restore painter opacity.
4331     if (windowOpacity < 1.0)
4332         painter->setOpacity(oldPainterOpacity);
4333 }
4334 
_q_paintIntoCache(QPixmap * pix,QGraphicsItem * item,const QRegion & pixmapExposed,const QTransform & itemToPixmap,QPainter::RenderHints renderHints,const QStyleOptionGraphicsItem * option,bool painterStateProtection)4335 static void _q_paintIntoCache(QPixmap *pix, QGraphicsItem *item, const QRegion &pixmapExposed,
4336                               const QTransform &itemToPixmap, QPainter::RenderHints renderHints,
4337                               const QStyleOptionGraphicsItem *option, bool painterStateProtection)
4338 {
4339     QPixmap subPix;
4340     QPainter pixmapPainter;
4341     QRect br = pixmapExposed.boundingRect();
4342 
4343     // Don't use subpixmap if we get a full update.
4344     if (pixmapExposed.isEmpty() || (pixmapExposed.rectCount() == 1 && br.contains(pix->rect()))) {
4345         pix->fill(Qt::transparent);
4346         pixmapPainter.begin(pix);
4347     } else {
4348         subPix = QPixmap(br.size() * pix->devicePixelRatio());
4349         subPix.setDevicePixelRatio(pix->devicePixelRatio());
4350         subPix.fill(Qt::transparent);
4351         pixmapPainter.begin(&subPix);
4352         pixmapPainter.translate(-br.topLeft());
4353         if (!pixmapExposed.isEmpty()) {
4354             // Applied to subPix; paint is adjusted to the coordinate space is
4355             // correct.
4356             pixmapPainter.setClipRegion(pixmapExposed);
4357         }
4358     }
4359 
4360     pixmapPainter.setRenderHints(pixmapPainter.renderHints(), false);
4361     pixmapPainter.setRenderHints(renderHints, true);
4362     pixmapPainter.setWorldTransform(itemToPixmap, true);
4363 
4364     // Render.
4365     _q_paintItem(item, &pixmapPainter, option, nullptr, false, painterStateProtection);
4366     pixmapPainter.end();
4367 
4368     if (!subPix.isNull()) {
4369         // Blit the subpixmap into the main pixmap.
4370         pixmapPainter.begin(pix);
4371         pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
4372         pixmapPainter.setClipRegion(pixmapExposed);
4373         pixmapPainter.drawPixmap(br.topLeft(), subPix);
4374         pixmapPainter.end();
4375     }
4376 }
4377 
4378 // Copied from qpaintengine_vg.cpp
4379 // Returns \c true for 90, 180, and 270 degree rotations.
transformIsSimple(const QTransform & transform)4380 static inline bool transformIsSimple(const QTransform& transform)
4381 {
4382     QTransform::TransformationType type = transform.type();
4383     if (type <= QTransform::TxScale) {
4384         return true;
4385     } else if (type == QTransform::TxRotate) {
4386         // Check for 90, and 270 degree rotations.
4387         qreal m11 = transform.m11();
4388         qreal m12 = transform.m12();
4389         qreal m21 = transform.m21();
4390         qreal m22 = transform.m22();
4391         if (m11 == 0.0f && m22 == 0.0f) {
4392             if (m12 == 1.0f && m21 == -1.0f)
4393                 return true; // 90 degrees.
4394             else if (m12 == -1.0f && m21 == 1.0f)
4395                 return true; // 270 degrees.
4396             else if (m12 == -1.0f && m21 == -1.0f)
4397                 return true; // 90 degrees inverted y.
4398             else if (m12 == 1.0f && m21 == 1.0f)
4399                 return true; // 270 degrees inverted y.
4400         }
4401     }
4402     return false;
4403 }
4404 
4405 /*!
4406     \internal
4407 
4408     Draws items directly, or using cache.
4409 */
drawItemHelper(QGraphicsItem * item,QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget,bool painterStateProtection)4410 void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painter,
4411                                            const QStyleOptionGraphicsItem *option, QWidget *widget,
4412                                            bool painterStateProtection)
4413 {
4414     QGraphicsItemPrivate *itemd = item->d_ptr.data();
4415     QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode);
4416 
4417     // Render directly, using no cache.
4418     if (cacheMode == QGraphicsItem::NoCache) {
4419         _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget, true, painterStateProtection);
4420         return;
4421     }
4422 
4423     const qreal devicePixelRatio = painter->device()->devicePixelRatio();
4424     const qreal oldPainterOpacity = painter->opacity();
4425     qreal newPainterOpacity = oldPainterOpacity;
4426     QGraphicsProxyWidget *proxy = item->isWidget() ? qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(item)) : 0;
4427     if (proxy && proxy->widget()) {
4428         const qreal windowOpacity = proxy->widget()->windowOpacity();
4429         if (windowOpacity < 1.0)
4430             newPainterOpacity *= windowOpacity;
4431     }
4432 
4433     // Item's (local) bounding rect
4434     QRectF brect = item->boundingRect();
4435     QRectF adjustedBrect(brect);
4436     _q_adjustRect(&adjustedBrect);
4437     if (adjustedBrect.isEmpty())
4438         return;
4439 
4440     // Fetch the off-screen transparent buffer and exposed area info.
4441     QPixmapCache::Key pixmapKey;
4442     QPixmap pix;
4443 
4444     bool pixmapFound;
4445     QGraphicsItemCache *itemCache = itemd->extraItemCache();
4446     if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
4447         pixmapKey = itemCache->key;
4448     } else {
4449         pixmapKey = itemCache->deviceData.value(widget).key;
4450     }
4451 
4452     // Find pixmap in cache.
4453     pixmapFound = QPixmapCache::find(pixmapKey, &pix);
4454 
4455     // Render using item coordinate cache mode.
4456     if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
4457         QSize pixmapSize;
4458         bool fixedCacheSize = itemCache->fixedSize.isValid();
4459         QRect br = brect.toAlignedRect();
4460         if (fixedCacheSize) {
4461             pixmapSize = itemCache->fixedSize;
4462         } else {
4463             pixmapSize = br.size();
4464         }
4465 
4466         pixmapSize *= devicePixelRatio;
4467 
4468         // Create or recreate the pixmap.
4469         int adjust = itemCache->fixedSize.isValid() ? 0 : 2;
4470         QSize adjustSize(adjust*2, adjust*2);
4471         br.adjust(-adjust / devicePixelRatio, -adjust / devicePixelRatio, adjust / devicePixelRatio, adjust / devicePixelRatio);
4472         if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) {
4473             pix = QPixmap(pixmapSize + adjustSize);
4474             itemCache->boundingRect = br;
4475             itemCache->exposed.clear();
4476             itemCache->allExposed = true;
4477         } else if (itemCache->boundingRect != br) {
4478             itemCache->boundingRect = br;
4479             itemCache->exposed.clear();
4480             itemCache->allExposed = true;
4481         }
4482 
4483         // Redraw any newly exposed areas.
4484         if (itemCache->allExposed || !itemCache->exposed.isEmpty()) {
4485 
4486             //We know that we will modify the pixmap, removing it from the cache
4487             //will detach the one we have and avoid a deep copy
4488             if (pixmapFound)
4489                 QPixmapCache::remove(pixmapKey);
4490 
4491             // Fit the item's bounding rect into the pixmap's coordinates.
4492             QTransform itemToPixmap;
4493             if (fixedCacheSize) {
4494                 const QPointF scale((pixmapSize.width() / devicePixelRatio) / brect.width(),
4495                                     (pixmapSize.height() / devicePixelRatio) / brect.height());
4496                 itemToPixmap.scale(scale.x(), scale.y());
4497             }
4498             itemToPixmap.translate(-br.x(), -br.y());
4499 
4500             // Generate the item's exposedRect and map its list of expose
4501             // rects to device coordinates.
4502             styleOptionTmp = *option;
4503             QRegion pixmapExposed;
4504             QRectF exposedRect;
4505             if (!itemCache->allExposed) {
4506                 for (int i = 0; i < itemCache->exposed.size(); ++i) {
4507                     QRectF r = itemCache->exposed.at(i);
4508                     exposedRect |= r;
4509                     pixmapExposed += itemToPixmap.mapRect(r).toAlignedRect();
4510                 }
4511             } else {
4512                 exposedRect = brect;
4513             }
4514             styleOptionTmp.exposedRect = exposedRect;
4515 
4516             // Render.
4517             pix.setDevicePixelRatio(devicePixelRatio);
4518             _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
4519                               &styleOptionTmp, painterStateProtection);
4520 
4521             // insert this pixmap into the cache.
4522             itemCache->key = QPixmapCache::insert(pix);
4523 
4524             // Reset expose data.
4525             itemCache->allExposed = false;
4526             itemCache->exposed.clear();
4527         }
4528 
4529         // Redraw the exposed area using the transformed painter. Depending on
4530         // the hardware, this may be a server-side operation, or an expensive
4531         // qpixmap-image-transform-pixmap roundtrip.
4532         if (newPainterOpacity != oldPainterOpacity) {
4533             painter->setOpacity(newPainterOpacity);
4534             painter->drawPixmap(br.topLeft(), pix);
4535             painter->setOpacity(oldPainterOpacity);
4536         } else {
4537             painter->drawPixmap(br.topLeft(), pix);
4538         }
4539         return;
4540     }
4541 
4542     // Render using device coordinate cache mode.
4543     if (cacheMode == QGraphicsItem::DeviceCoordinateCache) {
4544         // Find the item's bounds in device coordinates.
4545         QRectF deviceBounds = painter->worldTransform().mapRect(brect);
4546         QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
4547         if (deviceRect.isEmpty())
4548             return;
4549         QRect viewRect = widget ? widget->rect() : QRect();
4550         if (widget && !viewRect.intersects(deviceRect))
4551             return;
4552 
4553         // Resort to direct rendering if the device rect exceeds the
4554         // (optional) maximum bounds. (QGraphicsSvgItem uses this).
4555         QSize maximumCacheSize =
4556             itemd->extra(QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize).toSize();
4557         if (!maximumCacheSize.isEmpty()
4558             && (deviceRect.width() > maximumCacheSize.width()
4559                 || deviceRect.height() > maximumCacheSize.height())) {
4560             _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget,
4561                          oldPainterOpacity != newPainterOpacity, painterStateProtection);
4562             return;
4563         }
4564 
4565         // Create or reuse offscreen pixmap, possibly scroll/blit from the old one.
4566         // If the world transform is rotated we always recreate the cache to avoid
4567         // wrong blending.
4568         bool pixModified = false;
4569         QGraphicsItemCache::DeviceData *deviceData = &itemCache->deviceData[widget];
4570         bool invertable = true;
4571         QTransform diff = deviceData->lastTransform.inverted(&invertable);
4572         if (invertable)
4573             diff *= painter->worldTransform();
4574         deviceData->lastTransform = painter->worldTransform();
4575         bool allowPartialCacheExposure = false;
4576         bool simpleTransform = invertable && diff.type() <= QTransform::TxTranslate
4577                                && transformIsSimple(painter->worldTransform());
4578         if (!simpleTransform) {
4579             pixModified = true;
4580             itemCache->allExposed = true;
4581             itemCache->exposed.clear();
4582             deviceData->cacheIndent = QPoint();
4583             pix = QPixmap();
4584         } else if (!viewRect.isNull()) {
4585             allowPartialCacheExposure = deviceData->cacheIndent != QPoint();
4586         }
4587 
4588         // Allow partial cache exposure if the device rect isn't fully contained and
4589         // deviceRect is 20% taller or wider than the viewRect.
4590         if (!allowPartialCacheExposure && !viewRect.isNull() && !viewRect.contains(deviceRect)) {
4591             allowPartialCacheExposure = (viewRect.width() * 1.2 < deviceRect.width())
4592                                          || (viewRect.height() * 1.2 < deviceRect.height());
4593         }
4594 
4595         QRegion scrollExposure;
4596         if (allowPartialCacheExposure) {
4597             // Part of pixmap is drawn. Either device contains viewrect (big
4598             // item covers whole screen) or parts of device are outside the
4599             // viewport. In either case the device rect must be the intersect
4600             // between the two.
4601             int dx = deviceRect.left() < viewRect.left() ? viewRect.left() - deviceRect.left() : 0;
4602             int dy = deviceRect.top() < viewRect.top() ? viewRect.top() - deviceRect.top() : 0;
4603             QPoint newCacheIndent(dx, dy);
4604             deviceRect &= viewRect;
4605 
4606             if (pix.isNull()) {
4607                 deviceData->cacheIndent = QPoint();
4608                 itemCache->allExposed = true;
4609                 itemCache->exposed.clear();
4610                 pixModified = true;
4611             }
4612 
4613             // Copy / "scroll" the old pixmap onto the new ole and calculate
4614             // scrolled exposure.
4615             if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size() / devicePixelRatio) {
4616                 QPoint diff = newCacheIndent - deviceData->cacheIndent;
4617                 QPixmap newPix(deviceRect.size() * devicePixelRatio);
4618                 // ### Investigate removing this fill (test with Plasma and
4619                 // graphicssystem raster).
4620                 newPix.fill(Qt::transparent);
4621                 if (!pix.isNull()) {
4622                     newPix.setDevicePixelRatio(devicePixelRatio);
4623                     QPainter newPixPainter(&newPix);
4624                     newPixPainter.drawPixmap(-diff, pix);
4625                     newPixPainter.end();
4626                 }
4627                 QRegion exposed;
4628                 exposed += QRect(QPoint(0,0), newPix.size() / devicePixelRatio);
4629                 if (!pix.isNull())
4630                     exposed -= QRect(-diff, pix.size() / devicePixelRatio);
4631                 scrollExposure = exposed;
4632 
4633                 pix = newPix;
4634                 pixModified = true;
4635             }
4636             deviceData->cacheIndent = newCacheIndent;
4637         } else {
4638             // Full pixmap is drawn.
4639             deviceData->cacheIndent = QPoint();
4640 
4641             // Auto-adjust the pixmap size.
4642             if (deviceRect.size() != pix.size() / devicePixelRatio) {
4643                 // exposed needs to cover the whole pixmap
4644                 pix = QPixmap(deviceRect.size() * devicePixelRatio);
4645                 pixModified = true;
4646                 itemCache->allExposed = true;
4647                 itemCache->exposed.clear();
4648             }
4649         }
4650 
4651         // Check for newly invalidated areas.
4652         if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) {
4653             //We know that we will modify the pixmap, removing it from the cache
4654             //will detach the one we have and avoid a deep copy
4655             if (pixmapFound)
4656                 QPixmapCache::remove(pixmapKey);
4657 
4658             // Construct an item-to-pixmap transform.
4659             QPointF p = deviceRect.topLeft();
4660             QTransform itemToPixmap = painter->worldTransform();
4661             if (!p.isNull())
4662                 itemToPixmap *= QTransform::fromTranslate(-p.x(), -p.y());
4663 
4664             // Map the item's logical expose to pixmap coordinates.
4665             QRegion pixmapExposed = scrollExposure;
4666             if (!itemCache->allExposed) {
4667                 const QVector<QRectF> &exposed = itemCache->exposed;
4668                 for (int i = 0; i < exposed.size(); ++i)
4669                     pixmapExposed += itemToPixmap.mapRect(exposed.at(i)).toRect().adjusted(-1, -1, 1, 1);
4670             }
4671 
4672             // Calculate the style option's exposedRect.
4673             QRectF br;
4674             if (itemCache->allExposed) {
4675                 br = item->boundingRect();
4676             } else {
4677                 const QVector<QRectF> &exposed = itemCache->exposed;
4678                 for (int i = 0; i < exposed.size(); ++i)
4679                     br |= exposed.at(i);
4680                 QTransform pixmapToItem = itemToPixmap.inverted();
4681                 for (const QRect &r : scrollExposure)
4682                     br |= pixmapToItem.mapRect(r);
4683             }
4684             styleOptionTmp = *option;
4685             styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1);
4686 
4687             // Render the exposed areas.
4688             pix.setDevicePixelRatio(devicePixelRatio);
4689             _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
4690                               &styleOptionTmp, painterStateProtection);
4691 
4692             // Reset expose data.
4693             pixModified = true;
4694             itemCache->allExposed = false;
4695             itemCache->exposed.clear();
4696         }
4697 
4698         if (pixModified) {
4699             // Insert this pixmap into the cache.
4700             deviceData->key = QPixmapCache::insert(pix);
4701         }
4702 
4703         // Redraw the exposed area using an untransformed painter. This
4704         // effectively becomes a bitblit that does not transform the cache.
4705         QTransform restoreTransform = painter->worldTransform();
4706         painter->setWorldTransform(QTransform());
4707         if (newPainterOpacity != oldPainterOpacity) {
4708             painter->setOpacity(newPainterOpacity);
4709             painter->drawPixmap(deviceRect.topLeft(), pix);
4710             painter->setOpacity(oldPainterOpacity);
4711         } else {
4712             painter->drawPixmap(deviceRect.topLeft(), pix);
4713         }
4714         painter->setWorldTransform(restoreTransform);
4715         return;
4716     }
4717 }
4718 
drawItems(QPainter * painter,const QTransform * const viewTransform,QRegion * exposedRegion,QWidget * widget)4719 void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const viewTransform,
4720                                       QRegion *exposedRegion, QWidget *widget)
4721 {
4722     // Make sure we don't have unpolished items before we draw.
4723     if (!unpolishedItems.isEmpty())
4724         _q_polishItems();
4725 
4726     updateAll = false;
4727     QRectF exposedSceneRect;
4728     if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) {
4729         exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1);
4730         if (viewTransform)
4731             exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect);
4732     }
4733     const QList<QGraphicsItem *> tli = index->estimateTopLevelItems(exposedSceneRect, Qt::AscendingOrder);
4734     for (int i = 0; i < tli.size(); ++i)
4735         drawSubtreeRecursive(tli.at(i), painter, viewTransform, exposedRegion, widget);
4736 }
4737 
drawSubtreeRecursive(QGraphicsItem * item,QPainter * painter,const QTransform * const viewTransform,QRegion * exposedRegion,QWidget * widget,qreal parentOpacity,const QTransform * const effectTransform)4738 void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter,
4739                                                  const QTransform *const viewTransform,
4740                                                  QRegion *exposedRegion, QWidget *widget,
4741                                                  qreal parentOpacity, const QTransform *const effectTransform)
4742 {
4743     Q_ASSERT(item);
4744 
4745     if (!item->d_ptr->visible)
4746         return;
4747 
4748     const bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
4749     const bool itemHasChildren = !item->d_ptr->children.isEmpty();
4750     if (!itemHasContents && !itemHasChildren)
4751         return; // Item has neither contents nor children!(?)
4752 
4753     const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
4754     const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
4755     if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity()))
4756         return;
4757 
4758     QTransform transform(Qt::Uninitialized);
4759     QTransform *transformPtr = nullptr;
4760     bool translateOnlyTransform = false;
4761 #define ENSURE_TRANSFORM_PTR \
4762     if (!transformPtr) { \
4763         Q_ASSERT(!itemIsUntransformable); \
4764         if (viewTransform) { \
4765             transform = item->d_ptr->sceneTransform; \
4766             transform *= *viewTransform; \
4767             transformPtr = &transform; \
4768         } else { \
4769             transformPtr = &item->d_ptr->sceneTransform; \
4770             translateOnlyTransform = item->d_ptr->sceneTransformTranslateOnly; \
4771         } \
4772     }
4773 
4774     // Update the item's scene transform if the item is transformable;
4775     // otherwise calculate the full transform,
4776     bool wasDirtyParentSceneTransform = false;
4777     const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
4778     if (itemIsUntransformable) {
4779         transform = item->deviceTransform(viewTransform ? *viewTransform : QTransform());
4780         transformPtr = &transform;
4781     } else if (item->d_ptr->dirtySceneTransform) {
4782         item->d_ptr->updateSceneTransformFromParent();
4783         Q_ASSERT(!item->d_ptr->dirtySceneTransform);
4784         wasDirtyParentSceneTransform = true;
4785     }
4786 
4787     const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
4788                                            || item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape);
4789     bool drawItem = itemHasContents && !itemIsFullyTransparent;
4790     if (drawItem || minimumRenderSize > 0.0) {
4791         const QRectF brect = adjustedItemEffectiveBoundingRect(item);
4792         ENSURE_TRANSFORM_PTR
4793         QRectF preciseViewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy())
4794                                                                 : transformPtr->mapRect(brect);
4795 
4796         bool itemIsTooSmallToRender = false;
4797         if (minimumRenderSize > 0.0
4798             && (preciseViewBoundingRect.width() < minimumRenderSize
4799                 || preciseViewBoundingRect.height() < minimumRenderSize)) {
4800            itemIsTooSmallToRender = true;
4801            drawItem = false;
4802         }
4803 
4804         bool itemIsOutsideVisibleRect = false;
4805         if (drawItem) {
4806             QRect viewBoundingRect = preciseViewBoundingRect.toAlignedRect();
4807             viewBoundingRect.adjust(-int(rectAdjust), -int(rectAdjust), rectAdjust, rectAdjust);
4808             if (widget)
4809                 item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
4810             drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect)
4811                                      : !viewBoundingRect.normalized().isEmpty();
4812             itemIsOutsideVisibleRect = !drawItem;
4813         }
4814 
4815         if (itemIsTooSmallToRender || itemIsOutsideVisibleRect) {
4816             // We cannot simply use !drawItem here. If we did it is possible
4817             // to enter the outter if statement with drawItem == false and minimumRenderSize > 0
4818             // and finally end up inside this inner if, even though none of the above two
4819             // conditions are met. In that case we should not return from this function
4820             // but call draw() instead.
4821             if (!itemHasChildren)
4822                 return;
4823             if (itemClipsChildrenToShape) {
4824                 if (wasDirtyParentSceneTransform)
4825                     item->d_ptr->invalidateChildrenSceneTransform();
4826                 return;
4827             }
4828         }
4829     } // else we know for sure this item has children we must process.
4830 
4831     if (itemHasChildren && itemClipsChildrenToShape)
4832         ENSURE_TRANSFORM_PTR;
4833 
4834 #if QT_CONFIG(graphicseffect)
4835     if (item->d_ptr->graphicsEffect && item->d_ptr->graphicsEffect->isEnabled()) {
4836         ENSURE_TRANSFORM_PTR;
4837         QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp,
4838                                     painter, opacity, wasDirtyParentSceneTransform, itemHasContents && !itemIsFullyTransparent);
4839         QGraphicsEffectSource *source = item->d_ptr->graphicsEffect->d_func()->source;
4840         QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *>
4841                                                     (source->d_func());
4842         sourced->info = &info;
4843         const QTransform restoreTransform = painter->worldTransform();
4844         if (effectTransform)
4845             painter->setWorldTransform(*transformPtr * *effectTransform);
4846         else
4847             painter->setWorldTransform(*transformPtr);
4848         painter->setOpacity(opacity);
4849 
4850         if (sourced->currentCachedSystem() != Qt::LogicalCoordinates
4851             && sourced->lastEffectTransform != painter->worldTransform())
4852         {
4853             if (sourced->lastEffectTransform.type() <= QTransform::TxTranslate
4854                 && painter->worldTransform().type() <= QTransform::TxTranslate)
4855             {
4856                 QRectF sourceRect = sourced->boundingRect(Qt::DeviceCoordinates);
4857                 QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect).toAlignedRect();
4858 
4859                 sourced->setCachedOffset(effectRect.topLeft());
4860             } else {
4861                 sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged);
4862             }
4863 
4864             sourced->lastEffectTransform = painter->worldTransform();
4865         }
4866 
4867         item->d_ptr->graphicsEffect->draw(painter);
4868         painter->setWorldTransform(restoreTransform);
4869         sourced->info = nullptr;
4870     } else
4871 #endif // QT_CONFIG(graphicseffect)
4872     {
4873         draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity,
4874              effectTransform, wasDirtyParentSceneTransform, drawItem);
4875     }
4876 }
4877 
setClip(QPainter * painter,QGraphicsItem * item)4878 static inline void setClip(QPainter *painter, QGraphicsItem *item)
4879 {
4880     painter->save();
4881     QRectF clipRect;
4882     const QPainterPath clipPath(item->shape());
4883     if (QPathClipper::pathToRect(clipPath, &clipRect))
4884         painter->setClipRect(clipRect, Qt::IntersectClip);
4885     else
4886         painter->setClipPath(clipPath, Qt::IntersectClip);
4887 }
4888 
setWorldTransform(QPainter * painter,const QTransform * const transformPtr,const QTransform * effectTransform)4889 static inline void setWorldTransform(QPainter *painter, const QTransform *const transformPtr,
4890                                      const QTransform *effectTransform)
4891 {
4892     Q_ASSERT(transformPtr);
4893     if (effectTransform)
4894         painter->setWorldTransform(*transformPtr * *effectTransform);
4895     else
4896         painter->setWorldTransform(*transformPtr);
4897 }
4898 
draw(QGraphicsItem * item,QPainter * painter,const QTransform * const viewTransform,const QTransform * const transformPtr,QRegion * exposedRegion,QWidget * widget,qreal opacity,const QTransform * effectTransform,bool wasDirtyParentSceneTransform,bool drawItem)4899 void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform,
4900                                  const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget,
4901                                  qreal opacity, const QTransform *effectTransform,
4902                                  bool wasDirtyParentSceneTransform, bool drawItem)
4903 {
4904     const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
4905     const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
4906     const bool itemHasChildren = !item->d_ptr->children.isEmpty();
4907     bool setChildClip = itemClipsChildrenToShape;
4908     bool itemHasChildrenStackedBehind = false;
4909 
4910     int i = 0;
4911     if (itemHasChildren) {
4912         if (itemClipsChildrenToShape)
4913             setWorldTransform(painter, transformPtr, effectTransform);
4914 
4915         item->d_ptr->ensureSortedChildren();
4916         // Items with the 'ItemStacksBehindParent' flag are put in front of the list
4917         // so all we have to do is to check the first item.
4918         itemHasChildrenStackedBehind = (item->d_ptr->children.at(0)->d_ptr->flags
4919                                         & QGraphicsItem::ItemStacksBehindParent);
4920 
4921         if (itemHasChildrenStackedBehind) {
4922             if (itemClipsChildrenToShape) {
4923                 setClip(painter, item);
4924                 setChildClip = false;
4925             }
4926 
4927             // Draw children behind
4928             for (i = 0; i < item->d_ptr->children.size(); ++i) {
4929                 QGraphicsItem *child = item->d_ptr->children.at(i);
4930                 if (wasDirtyParentSceneTransform)
4931                     child->d_ptr->dirtySceneTransform = 1;
4932                 if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
4933                     break;
4934                 if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
4935                     continue;
4936                 drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
4937             }
4938         }
4939     }
4940 
4941     // Draw item
4942     if (drawItem) {
4943         Q_ASSERT(!itemIsFullyTransparent);
4944         Q_ASSERT(!(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents));
4945         Q_ASSERT(transformPtr);
4946         item->d_ptr->initStyleOption(&styleOptionTmp, *transformPtr, exposedRegion
4947                                      ? *exposedRegion : QRegion(), exposedRegion == nullptr);
4948 
4949         const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape;
4950         bool restorePainterClip = false;
4951 
4952         if (!itemHasChildren || !itemClipsChildrenToShape) {
4953             // Item does not have children or clip children to shape.
4954             setWorldTransform(painter, transformPtr, effectTransform);
4955             if ((restorePainterClip = itemClipsToShape))
4956                 setClip(painter, item);
4957         } else if (itemHasChildrenStackedBehind){
4958             // Item clips children to shape and has children stacked behind, which means
4959             // the painter is already clipped to the item's shape.
4960             if (itemClipsToShape) {
4961                 // The clip is already correct. Ensure correct world transform.
4962                 setWorldTransform(painter, transformPtr, effectTransform);
4963             } else {
4964                 // Remove clip (this also ensures correct world transform).
4965                 painter->restore();
4966                 setChildClip = true;
4967             }
4968         } else if (itemClipsToShape) {
4969             // Item clips children and itself to shape. It does not have hildren stacked
4970             // behind, which means the clip has not yet been set. We set it now and re-use it
4971             // for the children.
4972             setClip(painter, item);
4973             setChildClip = false;
4974         }
4975 
4976         if (painterStateProtection && !restorePainterClip)
4977             painter->save();
4978 
4979         painter->setOpacity(opacity);
4980         if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget)
4981             item->paint(painter, &styleOptionTmp, widget);
4982         else
4983             drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection);
4984 
4985         if (painterStateProtection || restorePainterClip)
4986             painter->restore();
4987 
4988         static int drawRect = qEnvironmentVariableIntValue("QT_DRAW_SCENE_ITEM_RECTS");
4989         if (drawRect) {
4990             QPen oldPen = painter->pen();
4991             QBrush oldBrush = painter->brush();
4992             quintptr ptr = reinterpret_cast<quintptr>(item);
4993             const QColor color = QColor::fromHsv(ptr % 255, 255, 255);
4994             painter->setPen(color);
4995             painter->setBrush(Qt::NoBrush);
4996             painter->drawRect(adjustedItemBoundingRect(item));
4997             painter->setPen(oldPen);
4998             painter->setBrush(oldBrush);
4999         }
5000     }
5001 
5002     // Draw children in front
5003     if (itemHasChildren) {
5004         if (setChildClip)
5005             setClip(painter, item);
5006 
5007         for (; i < item->d_ptr->children.size(); ++i) {
5008             QGraphicsItem *child = item->d_ptr->children.at(i);
5009             if (wasDirtyParentSceneTransform)
5010                 child->d_ptr->dirtySceneTransform = 1;
5011             if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
5012                 continue;
5013             drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
5014         }
5015 
5016         // Restore child clip
5017         if (itemClipsChildrenToShape)
5018             painter->restore();
5019     }
5020 }
5021 
markDirty(QGraphicsItem * item,const QRectF & rect,bool invalidateChildren,bool force,bool ignoreOpacity,bool removingItemFromScene,bool updateBoundingRect)5022 void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren,
5023                                       bool force, bool ignoreOpacity, bool removingItemFromScene,
5024                                       bool updateBoundingRect)
5025 {
5026     Q_ASSERT(item);
5027     if (updateAll)
5028         return;
5029 
5030     if (removingItemFromScene && !ignoreOpacity && !item->d_ptr->ignoreOpacity) {
5031         // If any of the item's ancestors ignore opacity, it means that the opacity
5032         // was set to 0 (and the update request has not yet been processed). That
5033         // also means that we have to ignore the opacity for the item itself; otherwise
5034         // things like: parent->setOpacity(0); scene->removeItem(child) won't work.
5035         // Note that we only do this when removing items from the scene. In all other
5036         // cases the ignoreOpacity bit propagates properly in processDirtyItems, but
5037         // since the item is removed immediately it won't be processed there.
5038         QGraphicsItem *p = item->d_ptr->parent;
5039         while (p) {
5040             if (p->d_ptr->ignoreOpacity) {
5041                 item->d_ptr->ignoreOpacity = true;
5042                 break;
5043             }
5044             p = p->d_ptr->parent;
5045         }
5046     }
5047 
5048     if (item->d_ptr->discardUpdateRequest(/*ignoreVisibleBit=*/force,
5049                                           /*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren,
5050                                           /*ignoreOpacity=*/ignoreOpacity)) {
5051         if (item->d_ptr->dirty) {
5052             // The item is already marked as dirty and will be processed later. However,
5053             // we have to make sure ignoreVisible and ignoreOpacity are set properly;
5054             // otherwise things like: item->update(); item->hide() (force is now true)
5055             // won't work as expected.
5056             if (force)
5057                 item->d_ptr->ignoreVisible = 1;
5058             if (ignoreOpacity)
5059                 item->d_ptr->ignoreOpacity = 1;
5060         }
5061         return;
5062     }
5063 
5064     const bool fullItemUpdate = rect.isNull();
5065     if (!fullItemUpdate && rect.isEmpty())
5066         return;
5067 
5068     if (!processDirtyItemsEmitted) {
5069         QMetaMethod method = q_ptr->metaObject()->method(processDirtyItemsIndex);
5070         method.invoke(q_ptr, Qt::QueuedConnection);
5071 //        QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection);
5072         processDirtyItemsEmitted = true;
5073     }
5074 
5075     if (removingItemFromScene) {
5076         // Note that this function can be called from the item's destructor, so
5077         // do NOT call any virtual functions on it within this block.
5078         if (isSignalConnected(changedSignalIndex) || views.isEmpty()) {
5079             // This block of code is kept for compatibility. Since 4.5, by default
5080             // QGraphicsView does not connect the signal and we use the below
5081             // method of delivering updates.
5082             q_func()->update();
5083             return;
5084         }
5085 
5086         for (int i = 0; i < views.size(); ++i) {
5087             QGraphicsViewPrivate *viewPrivate = views.at(i)->d_func();
5088             QRect rect = item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport);
5089             rect.translate(viewPrivate->dirtyScrollOffset);
5090             viewPrivate->updateRect(rect);
5091         }
5092         return;
5093     }
5094 
5095     bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents;
5096     if (!hasNoContents) {
5097         item->d_ptr->dirty = 1;
5098         if (fullItemUpdate)
5099             item->d_ptr->fullUpdatePending = 1;
5100         else if (!item->d_ptr->fullUpdatePending)
5101             item->d_ptr->needsRepaint |= rect;
5102     } else if (item->d_ptr->graphicsEffect) {
5103         invalidateChildren = true;
5104     }
5105 
5106     if (invalidateChildren) {
5107         item->d_ptr->allChildrenDirty = 1;
5108         item->d_ptr->dirtyChildren = 1;
5109     }
5110 
5111     if (force)
5112         item->d_ptr->ignoreVisible = 1;
5113     if (ignoreOpacity)
5114         item->d_ptr->ignoreOpacity = 1;
5115 
5116     if (!updateBoundingRect)
5117         item->d_ptr->markParentDirty();
5118 }
5119 
updateHelper(QGraphicsViewPrivate * view,QGraphicsItemPrivate * item,const QRectF & rect,bool itemIsUntransformable)5120 static inline bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate *item,
5121                                 const QRectF &rect, bool itemIsUntransformable)
5122 {
5123     Q_ASSERT(view);
5124     Q_ASSERT(item);
5125 
5126     QGraphicsItem *itemq = static_cast<QGraphicsItem *>(item->q_ptr);
5127     QGraphicsView *viewq = static_cast<QGraphicsView *>(view->q_ptr);
5128 
5129     if (itemIsUntransformable) {
5130         const QTransform xform = itemq->deviceTransform(viewq->viewportTransform());
5131         if (!item->hasBoundingRegionGranularity)
5132             return view->updateRectF(xform.mapRect(rect));
5133         return view->updateRegion(rect, xform);
5134     }
5135 
5136     if (item->sceneTransformTranslateOnly && view->identityMatrix) {
5137         const qreal dx = item->sceneTransform.dx();
5138         const qreal dy = item->sceneTransform.dy();
5139         QRectF r(rect);
5140         r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll());
5141         return view->updateRectF(r);
5142     }
5143 
5144     if (!viewq->isTransformed()) {
5145         if (!item->hasBoundingRegionGranularity)
5146             return view->updateRectF(item->sceneTransform.mapRect(rect));
5147         return view->updateRegion(rect, item->sceneTransform);
5148     }
5149 
5150     QTransform xform = item->sceneTransform;
5151     xform *= viewq->viewportTransform();
5152     if (!item->hasBoundingRegionGranularity)
5153         return view->updateRectF(xform.mapRect(rect));
5154     return view->updateRegion(rect, xform);
5155 }
5156 
processDirtyItemsRecursive(QGraphicsItem * item,bool dirtyAncestorContainsChildren,qreal parentOpacity)5157 void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren,
5158                                                        qreal parentOpacity)
5159 {
5160     Q_Q(QGraphicsScene);
5161     Q_ASSERT(item);
5162     Q_ASSERT(!updateAll);
5163 
5164     if (!item->d_ptr->dirty && !item->d_ptr->dirtyChildren) {
5165         resetDirtyItem(item);
5166         return;
5167     }
5168 
5169     const bool itemIsHidden = !item->d_ptr->ignoreVisible && !item->d_ptr->visible;
5170     if (itemIsHidden) {
5171         resetDirtyItem(item, /*recursive=*/true);
5172         return;
5173     }
5174 
5175     bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
5176     const bool itemHasChildren = !item->d_ptr->children.isEmpty();
5177     if (!itemHasContents) {
5178         if (!itemHasChildren) {
5179             resetDirtyItem(item);
5180             return; // Item has neither contents nor children!(?)
5181         }
5182         if (item->d_ptr->graphicsEffect)
5183             itemHasContents = true;
5184     }
5185 
5186     const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
5187     const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity
5188                                         && QGraphicsItemPrivate::isOpacityNull(opacity);
5189     if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) {
5190         resetDirtyItem(item, /*recursive=*/itemHasChildren);
5191         return;
5192     }
5193 
5194     bool wasDirtyParentSceneTransform = item->d_ptr->dirtySceneTransform;
5195     const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
5196     if (wasDirtyParentSceneTransform && !itemIsUntransformable) {
5197         item->d_ptr->updateSceneTransformFromParent();
5198         Q_ASSERT(!item->d_ptr->dirtySceneTransform);
5199     }
5200 
5201     const bool wasDirtyParentViewBoundingRects = item->d_ptr->paintedViewBoundingRectsNeedRepaint;
5202     if (itemIsFullyTransparent || !itemHasContents || dirtyAncestorContainsChildren) {
5203         // Make sure we don't process invisible items or items with no content.
5204         item->d_ptr->dirty = 0;
5205         item->d_ptr->fullUpdatePending = 0;
5206         // Might have a dirty view bounding rect otherwise.
5207         if (itemIsFullyTransparent || !itemHasContents)
5208             item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0;
5209     }
5210 
5211     if (!hasSceneRect && item->d_ptr->geometryChanged && item->d_ptr->visible) {
5212         // Update growingItemsBoundingRect.
5213         if (item->d_ptr->sceneTransformTranslateOnly) {
5214             growingItemsBoundingRect |= item->boundingRect().translated(item->d_ptr->sceneTransform.dx(),
5215                                                                         item->d_ptr->sceneTransform.dy());
5216         } else {
5217             growingItemsBoundingRect |= item->d_ptr->sceneTransform.mapRect(item->boundingRect());
5218         }
5219     }
5220 
5221     // Process item.
5222     if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
5223         const bool useCompatUpdate = views.isEmpty() || isSignalConnected(changedSignalIndex);
5224         const QRectF itemBoundingRect = adjustedItemEffectiveBoundingRect(item);
5225 
5226         if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) {
5227             // This block of code is kept for compatibility. Since 4.5, by default
5228             // QGraphicsView does not connect the signal and we use the below
5229             // method of delivering updates.
5230             if (item->d_ptr->sceneTransformTranslateOnly) {
5231                 q->update(itemBoundingRect.translated(item->d_ptr->sceneTransform.dx(),
5232                                                       item->d_ptr->sceneTransform.dy()));
5233             } else {
5234                 QRectF rect = item->d_ptr->sceneTransform.mapRect(itemBoundingRect);
5235                 if (!rect.isEmpty())
5236                     q->update(rect);
5237             }
5238         } else {
5239             QRectF dirtyRect;
5240             bool uninitializedDirtyRect = true;
5241 
5242             for (int j = 0; j < views.size(); ++j) {
5243                 QGraphicsView *view = views.at(j);
5244                 QGraphicsViewPrivate *viewPrivate = view->d_func();
5245                 QRect &paintedViewBoundingRect = item->d_ptr->paintedViewBoundingRects[viewPrivate->viewport];
5246                 if (viewPrivate->fullUpdatePending
5247                     || viewPrivate->viewportUpdateMode == QGraphicsView::NoViewportUpdate) {
5248                     // Okay, if we have a full update pending or no viewport update, this item's
5249                     // paintedViewBoundingRect  will be updated correctly in the next paintEvent if
5250                     // it is inside the viewport, but for now we can pretend that it is outside.
5251                     paintedViewBoundingRect = QRect(-1, -1, -1, -1);
5252                     continue;
5253                 }
5254 
5255                 if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
5256                     paintedViewBoundingRect.translate(viewPrivate->dirtyScrollOffset);
5257                     if (!viewPrivate->updateRect(paintedViewBoundingRect))
5258                         paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
5259                 }
5260 
5261                 if (!item->d_ptr->dirty)
5262                     continue;
5263 
5264                 if (!item->d_ptr->paintedViewBoundingRectsNeedRepaint
5265                     && paintedViewBoundingRect.x() == -1 && paintedViewBoundingRect.y() == -1
5266                     && paintedViewBoundingRect.width() == -1 && paintedViewBoundingRect.height() == -1) {
5267                     continue; // Outside viewport.
5268                 }
5269 
5270                 if (uninitializedDirtyRect) {
5271                     dirtyRect = itemBoundingRect;
5272                     if (!item->d_ptr->fullUpdatePending) {
5273                         _q_adjustRect(&item->d_ptr->needsRepaint);
5274                         dirtyRect &= item->d_ptr->needsRepaint;
5275                     }
5276                     uninitializedDirtyRect = false;
5277                 }
5278 
5279                 if (dirtyRect.isEmpty())
5280                     continue; // Discard updates outside the bounding rect.
5281 
5282                 if (!updateHelper(viewPrivate, item->d_ptr.data(), dirtyRect, itemIsUntransformable)
5283                     && item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
5284                     paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
5285                 }
5286             }
5287         }
5288     }
5289 
5290     // Process children.
5291     if (itemHasChildren && item->d_ptr->dirtyChildren) {
5292         const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
5293                                               || item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape;
5294         // Items with no content are threated as 'dummy' items which means they are never drawn and
5295         // 'processed', so the painted view bounding rect is never up-to-date. This means that whenever
5296         // such an item changes geometry, its children have to take care of the update regardless
5297         // of whether the item clips children to shape or not.
5298         const bool bypassUpdateClip = !itemHasContents && wasDirtyParentViewBoundingRects;
5299         if (itemClipsChildrenToShape && !bypassUpdateClip) {
5300             // Make sure child updates are clipped to the item's bounding rect.
5301             for (int i = 0; i < views.size(); ++i)
5302                 views.at(i)->d_func()->setUpdateClip(item);
5303         }
5304         if (!dirtyAncestorContainsChildren) {
5305             dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending
5306                                             && itemClipsChildrenToShape;
5307         }
5308         const bool allChildrenDirty = item->d_ptr->allChildrenDirty;
5309         const bool parentIgnoresVisible = item->d_ptr->ignoreVisible;
5310         const bool parentIgnoresOpacity = item->d_ptr->ignoreOpacity;
5311         for (int i = 0; i < item->d_ptr->children.size(); ++i) {
5312             QGraphicsItem *child = item->d_ptr->children.at(i);
5313             if (wasDirtyParentSceneTransform)
5314                 child->d_ptr->dirtySceneTransform = 1;
5315             if (wasDirtyParentViewBoundingRects)
5316                 child->d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
5317             if (parentIgnoresVisible)
5318                 child->d_ptr->ignoreVisible = 1;
5319             if (parentIgnoresOpacity)
5320                 child->d_ptr->ignoreOpacity = 1;
5321             if (allChildrenDirty) {
5322                 child->d_ptr->dirty = 1;
5323                 child->d_ptr->fullUpdatePending = 1;
5324                 child->d_ptr->dirtyChildren = 1;
5325                 child->d_ptr->allChildrenDirty = 1;
5326             }
5327             processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity);
5328         }
5329 
5330         if (itemClipsChildrenToShape) {
5331             // Reset updateClip.
5332             for (int i = 0; i < views.size(); ++i)
5333                 views.at(i)->d_func()->setUpdateClip(nullptr);
5334         }
5335     } else if (wasDirtyParentSceneTransform) {
5336         item->d_ptr->invalidateChildrenSceneTransform();
5337     }
5338 
5339     resetDirtyItem(item);
5340 }
5341 
5342 /*!
5343     \obsolete
5344 
5345     Paints the given \a items using the provided \a painter, after the
5346     background has been drawn, and before the foreground has been
5347     drawn.  All painting is done in \e scene coordinates. Before
5348     drawing each item, the painter must be transformed using
5349     QGraphicsItem::sceneTransform().
5350 
5351     The \a options parameter is the list of style option objects for
5352     each item in \a items. The \a numItems parameter is the number of
5353     items in \a items and options in \a options. The \a widget
5354     parameter is optional; if specified, it should point to the widget
5355     that is being painted on.
5356 
5357     The default implementation prepares the painter matrix, and calls
5358     QGraphicsItem::paint() on all items. Reimplement this function to
5359     provide custom painting of all items for the scene; gaining
5360     complete control over how each item is drawn. In some cases this
5361     can increase drawing performance significantly.
5362 
5363     Example:
5364 
5365     \snippet graphicssceneadditem/graphicssceneadditemsnippet.cpp 0
5366 
5367     Since Qt 4.6, this function is not called anymore unless
5368     the QGraphicsView::IndirectPainting flag is given as an Optimization
5369     flag.
5370 
5371     \sa drawBackground(), drawForeground()
5372 */
drawItems(QPainter * painter,int numItems,QGraphicsItem * items[],const QStyleOptionGraphicsItem options[],QWidget * widget)5373 void QGraphicsScene::drawItems(QPainter *painter,
5374                                int numItems,
5375                                QGraphicsItem *items[],
5376                                const QStyleOptionGraphicsItem options[], QWidget *widget)
5377 {
5378     Q_D(QGraphicsScene);
5379     // Make sure we don't have unpolished items before we draw.
5380     if (!d->unpolishedItems.isEmpty())
5381         d->_q_polishItems();
5382 
5383     const qreal opacity = painter->opacity();
5384     QTransform viewTransform = painter->worldTransform();
5385     Q_UNUSED(options);
5386 
5387     // Determine view, expose and flags.
5388     QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
5389     QRegion *expose = nullptr;
5390     const quint32 oldRectAdjust = d->rectAdjust;
5391     if (view) {
5392         d->updateAll = false;
5393         expose = &view->d_func()->exposedRegion;
5394         if (view->d_func()->optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
5395             d->rectAdjust = 1;
5396         else
5397             d->rectAdjust = 2;
5398     }
5399 
5400     // Find all toplevels, they are already sorted.
5401     QList<QGraphicsItem *> topLevelItems;
5402     for (int i = 0; i < numItems; ++i) {
5403         QGraphicsItem *item = items[i]->topLevelItem();
5404         if (!item->d_ptr->itemDiscovered) {
5405             topLevelItems << item;
5406             item->d_ptr->itemDiscovered = 1;
5407             d->drawSubtreeRecursive(item, painter, &viewTransform, expose, widget);
5408         }
5409     }
5410 
5411     d->rectAdjust = oldRectAdjust;
5412     // Reset discovery bits.
5413     for (int i = 0; i < topLevelItems.size(); ++i)
5414         topLevelItems.at(i)->d_ptr->itemDiscovered = 0;
5415 
5416     painter->setWorldTransform(viewTransform);
5417     painter->setOpacity(opacity);
5418 }
5419 
5420 /*!
5421     \since 4.4
5422 
5423     Finds a new widget to give the keyboard focus to, as appropriate for Tab
5424     and Shift+Tab, and returns \c true if it can find a new widget, or false if
5425     it cannot. If \a next is true, this function searches forward; if \a next
5426     is false, it searches backward.
5427 
5428     You can reimplement this function in a subclass of QGraphicsScene to
5429     provide fine-grained control over how tab focus passes inside your
5430     scene. The default implementation is based on the tab focus chain defined
5431     by QGraphicsWidget::setTabOrder().
5432 */
focusNextPrevChild(bool next)5433 bool QGraphicsScene::focusNextPrevChild(bool next)
5434 {
5435     Q_D(QGraphicsScene);
5436 
5437     QGraphicsItem *item = focusItem();
5438     if (item && !item->isWidget()) {
5439         // Tab out of the scene.
5440         return false;
5441     }
5442     if (!item) {
5443         if (d->lastFocusItem && !d->lastFocusItem->isWidget()) {
5444             // Restore focus to the last focusable non-widget item that had
5445             // focus.
5446             setFocusItem(d->lastFocusItem, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
5447             return true;
5448         }
5449         if (d->activePanel) {
5450             if (d->activePanel->flags() & QGraphicsItem::ItemIsFocusable) {
5451                 setFocusItem(d->activePanel, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
5452                 return true;
5453             }
5454             if (d->activePanel->isWidget()) {
5455                 QGraphicsWidget *test = static_cast<QGraphicsWidget *>(d->activePanel);
5456                 QGraphicsWidget *fw = next ? test->d_func()->focusNext : test->d_func()->focusPrev;
5457                 do {
5458                     if (fw->focusPolicy() & Qt::TabFocus) {
5459                         setFocusItem(fw, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
5460                         return true;
5461                     }
5462                     fw = next ? fw->d_func()->focusNext : fw->d_func()->focusPrev;
5463                 } while (fw != d->activePanel);
5464             }
5465         }
5466     }
5467     if (!item && !d->tabFocusFirst) {
5468         // No widgets...
5469         return false;
5470     }
5471 
5472     // The item must be a widget.
5473     QGraphicsWidget *widget = nullptr;
5474     if (!item) {
5475         widget = next ? d->tabFocusFirst : d->tabFocusFirst->d_func()->focusPrev;
5476     } else {
5477         QGraphicsWidget *test = static_cast<QGraphicsWidget *>(item);
5478         widget = next ? test->d_func()->focusNext : test->d_func()->focusPrev;
5479         if (!widget->panel() && ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))) {
5480             // Tab out of the scene.
5481             return false;
5482         }
5483     }
5484     QGraphicsWidget *widgetThatHadFocus = widget;
5485 
5486     // Run around the focus chain until we find a widget that can take tab focus.
5487     do {
5488         if (widget->flags() & QGraphicsItem::ItemIsFocusable
5489             && widget->isEnabled() && widget->isVisibleTo(nullptr)
5490             && (widget->focusPolicy() & Qt::TabFocus)
5491             && (!item || !item->isPanel() || item->isAncestorOf(widget))
5492             ) {
5493             setFocusItem(widget, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
5494             return true;
5495         }
5496         widget = next ? widget->d_func()->focusNext : widget->d_func()->focusPrev;
5497         if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
5498             return false;
5499     } while (widget != widgetThatHadFocus);
5500 
5501     return false;
5502 }
5503 
5504 /*!
5505     \fn QGraphicsScene::changed(const QList<QRectF> &region)
5506 
5507     This signal is emitted by QGraphicsScene when control reaches the
5508     event loop, if the scene content changes. The \a region parameter
5509     contains a list of scene rectangles that indicate the area that
5510     has been changed.
5511 
5512     \sa QGraphicsView::updateScene()
5513 */
5514 
5515 /*!
5516     \fn QGraphicsScene::sceneRectChanged(const QRectF &rect)
5517 
5518     This signal is emitted by QGraphicsScene whenever the scene rect changes.
5519     The \a rect parameter is the new scene rectangle.
5520 
5521     \sa QGraphicsView::updateSceneRect()
5522 */
5523 
5524 /*!
5525     \fn QGraphicsScene::selectionChanged()
5526     \since 4.3
5527 
5528     This signal is emitted by QGraphicsScene whenever the selection
5529     changes. You can call selectedItems() to get the new list of selected
5530     items.
5531 
5532     The selection changes whenever an item is selected or unselected, a
5533     selection area is set, cleared or otherwise changed, if a preselected item
5534     is added to the scene, or if a selected item is removed from the scene.
5535 
5536     QGraphicsScene emits this signal only once for group selection operations.
5537     For example, if you set a selection area, select or unselect a
5538     QGraphicsItemGroup, or if you add or remove from the scene a parent item
5539     that contains several selected items, selectionChanged() is emitted only
5540     once after the operation has completed (instead of once for each item).
5541 
5542     \sa setSelectionArea(), selectedItems(), QGraphicsItem::setSelected()
5543 */
5544 
5545 /*!
5546     \fn void QGraphicsScene::focusItemChanged(QGraphicsItem *newFocusItem, QGraphicsItem *oldFocusItem, Qt::FocusReason reason)
5547 
5548     This signal is emitted by QGraphicsScene whenever focus changes in the
5549     scene (i.e., when an item gains or loses input focus, or when focus
5550     passes from one item to another). You can connect to this signal if you
5551     need to keep track of when other items gain input focus. It is
5552     particularly useful for implementing virtual keyboards, input methods,
5553     and cursor items.
5554 
5555     \a oldFocusItem is a pointer to the item that previously had focus, or
5556     0 if no item had focus before the signal was emitted. \a newFocusItem
5557     is a pointer to the item that gained input focus, or \nullptr if focus was lost.
5558     \a reason is the reason for the focus change (e.g., if the scene was
5559     deactivated while an input field had focus, \a oldFocusItem would point
5560     to the input field item, \a newFocusItem would be \nullptr, and \a reason
5561     would be Qt::ActiveWindowFocusReason.
5562 */
5563 
5564 /*!
5565     \since 4.4
5566 
5567     Returns the scene's style, or the same as QApplication::style() if the
5568     scene has not been explicitly assigned a style.
5569 
5570     \sa setStyle()
5571 */
style() const5572 QStyle *QGraphicsScene::style() const
5573 {
5574     Q_D(const QGraphicsScene);
5575     // ### This function, and the use of styles in general, is non-reentrant.
5576     return d->style ? d->style : QApplication::style();
5577 }
5578 
5579 /*!
5580     \since 4.4
5581 
5582     Sets or replaces the style of the scene to \a style, and reparents the
5583     style to this scene. Any previously assigned style is deleted. The scene's
5584     style defaults to QApplication::style(), and serves as the default for all
5585     QGraphicsWidget items in the scene.
5586 
5587     Changing the style, either directly by calling this function, or
5588     indirectly by calling QApplication::setStyle(), will automatically update
5589     the style for all widgets in the scene that do not have a style explicitly
5590     assigned to them.
5591 
5592     If \a style is \nullptr, QGraphicsScene will revert to QApplication::style().
5593 
5594     \sa style()
5595 */
setStyle(QStyle * style)5596 void QGraphicsScene::setStyle(QStyle *style)
5597 {
5598     Q_D(QGraphicsScene);
5599     // ### This function, and the use of styles in general, is non-reentrant.
5600     if (style == d->style)
5601         return;
5602 
5603     // Delete the old style,
5604     delete d->style;
5605     if ((d->style = style))
5606         d->style->setParent(this);
5607 
5608     // Notify the scene.
5609     QEvent event(QEvent::StyleChange);
5610     QCoreApplication::sendEvent(this, &event);
5611 
5612     // Notify all widgets that don't have a style explicitly set.
5613     const auto items_ = items();
5614     for (QGraphicsItem *item : items_) {
5615         if (item->isWidget()) {
5616             QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
5617             if (!widget->testAttribute(Qt::WA_SetStyle))
5618                 QCoreApplication::sendEvent(widget, &event);
5619         }
5620     }
5621 }
5622 
5623 /*!
5624     \property QGraphicsScene::font
5625     \since 4.4
5626     \brief the scene's default font
5627 
5628     This property provides the scene's font. The scene font defaults to,
5629     and resolves all its entries from, QApplication::font.
5630 
5631     If the scene's font changes, either directly through setFont() or
5632     indirectly when the application font changes, QGraphicsScene first
5633     sends itself a \l{QEvent::FontChange}{FontChange} event, and it then
5634     sends \l{QEvent::FontChange}{FontChange} events to all top-level
5635     widget items in the scene. These items respond by resolving their own
5636     fonts to the scene, and they then notify their children, who again
5637     notify their children, and so on, until all widget items have updated
5638     their fonts.
5639 
5640     Changing the scene font, (directly or indirectly through
5641     QApplication::setFont(),) automatically schedules a redraw the entire
5642     scene.
5643 
5644     \sa QWidget::font, QApplication::setFont(), palette, style()
5645 */
font() const5646 QFont QGraphicsScene::font() const
5647 {
5648     Q_D(const QGraphicsScene);
5649     return d->font;
5650 }
setFont(const QFont & font)5651 void QGraphicsScene::setFont(const QFont &font)
5652 {
5653     Q_D(QGraphicsScene);
5654     QFont naturalFont = QApplication::font();
5655     naturalFont.resolve(0);
5656     QFont resolvedFont = font.resolve(naturalFont);
5657     d->setFont_helper(resolvedFont);
5658 }
5659 
5660 /*!
5661     \property QGraphicsScene::palette
5662     \since 4.4
5663     \brief the scene's default palette
5664 
5665     This property provides the scene's palette. The scene palette defaults to,
5666     and resolves all its entries from, QApplication::palette.
5667 
5668     If the scene's palette changes, either directly through setPalette() or
5669     indirectly when the application palette changes, QGraphicsScene first
5670     sends itself a \l{QEvent::PaletteChange}{PaletteChange} event, and it then
5671     sends \l{QEvent::PaletteChange}{PaletteChange} events to all top-level
5672     widget items in the scene. These items respond by resolving their own
5673     palettes to the scene, and they then notify their children, who again
5674     notify their children, and so on, until all widget items have updated
5675     their palettes.
5676 
5677     Changing the scene palette, (directly or indirectly through
5678     QApplication::setPalette(),) automatically schedules a redraw the entire
5679     scene.
5680 
5681     \sa QWidget::palette, QApplication::setPalette(), font, style()
5682 */
palette() const5683 QPalette QGraphicsScene::palette() const
5684 {
5685     Q_D(const QGraphicsScene);
5686     return d->palette;
5687 }
setPalette(const QPalette & palette)5688 void QGraphicsScene::setPalette(const QPalette &palette)
5689 {
5690     Q_D(QGraphicsScene);
5691     QPalette naturalPalette = QGuiApplication::palette();
5692     naturalPalette.resolve(0);
5693     QPalette resolvedPalette = palette.resolve(naturalPalette);
5694     d->setPalette_helper(resolvedPalette);
5695 }
5696 
5697 /*!
5698     \since 4.6
5699 
5700     Returns \c true if the scene is active (e.g., it's viewed by
5701     at least one QGraphicsView that is active); otherwise returns \c false.
5702 
5703     \sa QGraphicsItem::isActive(), QWidget::isActiveWindow()
5704 */
isActive() const5705 bool QGraphicsScene::isActive() const
5706 {
5707     Q_D(const QGraphicsScene);
5708     return d->activationRefCount > 0;
5709 }
5710 
5711 /*!
5712     \since 4.6
5713     Returns the current active panel, or \nullptr if no panel is
5714     currently active.
5715 
5716     \sa QGraphicsScene::setActivePanel()
5717 */
activePanel() const5718 QGraphicsItem *QGraphicsScene::activePanel() const
5719 {
5720     Q_D(const QGraphicsScene);
5721     return d->activePanel;
5722 }
5723 
5724 /*!
5725     \since 4.6
5726     Activates \a item, which must be an item in this scene. You
5727     can also pass 0 for \a item, in which case QGraphicsScene will
5728     deactivate any currently active panel.
5729 
5730     If the scene is currently inactive, \a item remains inactive until the
5731     scene becomes active (or, ir \a item is \nullptr, no item will be activated).
5732 
5733     \sa activePanel(), isActive(), QGraphicsItem::isActive()
5734 */
setActivePanel(QGraphicsItem * item)5735 void QGraphicsScene::setActivePanel(QGraphicsItem *item)
5736 {
5737     Q_D(QGraphicsScene);
5738     d->setActivePanelHelper(item, false);
5739 }
5740 
5741 /*!
5742     \since 4.4
5743 
5744     Returns the current active window, or \nullptr if no window is
5745     currently  active.
5746 
5747     \sa QGraphicsScene::setActiveWindow()
5748 */
activeWindow() const5749 QGraphicsWidget *QGraphicsScene::activeWindow() const
5750 {
5751     Q_D(const QGraphicsScene);
5752     if (d->activePanel && d->activePanel->isWindow())
5753         return static_cast<QGraphicsWidget *>(d->activePanel);
5754     return nullptr;
5755 }
5756 
5757 /*!
5758     \since 4.4
5759     Activates \a widget, which must be a widget in this scene. You can also
5760     pass 0 for \a widget, in which case QGraphicsScene will deactivate any
5761     currently active window.
5762 
5763     \sa activeWindow(), QGraphicsWidget::isActiveWindow()
5764 */
setActiveWindow(QGraphicsWidget * widget)5765 void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
5766 {
5767     if (widget && widget->scene() != this) {
5768         qWarning("QGraphicsScene::setActiveWindow: widget %p must be part of this scene",
5769                  widget);
5770         return;
5771     }
5772 
5773     // Activate the widget's panel (all windows are panels).
5774     QGraphicsItem *panel = widget ? widget->panel() : nullptr;
5775     setActivePanel(panel);
5776 
5777     // Raise
5778     if (panel) {
5779         QGraphicsItem *parent = panel->parentItem();
5780         // Raise ### inefficient for toplevels
5781 
5782         // Find the highest z value.
5783         qreal z = panel->zValue();
5784         const auto siblings = parent ? parent->childItems() : items();
5785         for (QGraphicsItem *sibling : siblings) {
5786             if (sibling != panel && sibling->isWindow())
5787                 z = qMax(z, sibling->zValue());
5788         }
5789 
5790         // This will probably never overflow.
5791         const qreal litt = qreal(0.001);
5792         panel->setZValue(z + litt);
5793     }
5794 }
5795 
5796 /*!
5797     \since 4.6
5798 
5799     Sends event \a event to item \a item through possible event filters.
5800 
5801     The event is sent only if the item is enabled.
5802 
5803     Returns \c false if the event was filtered or if the item is disabled.
5804     Otherwise returns the value that was returned from the event handler.
5805 
5806     \sa QGraphicsItem::sceneEvent(), QGraphicsItem::sceneEventFilter()
5807 */
sendEvent(QGraphicsItem * item,QEvent * event)5808 bool QGraphicsScene::sendEvent(QGraphicsItem *item, QEvent *event)
5809 {
5810     Q_D(QGraphicsScene);
5811     if (!item) {
5812         qWarning("QGraphicsScene::sendEvent: cannot send event to a null item");
5813         return false;
5814     }
5815     if (item->scene() != this) {
5816         qWarning("QGraphicsScene::sendEvent: item %p's scene (%p)"
5817                  " is different from this scene (%p)",
5818                  item, item->scene(), this);
5819         return false;
5820     }
5821     return d->sendEvent(item, event);
5822 }
5823 
5824 /*!
5825     \property QGraphicsScene::minimumRenderSize
5826     \since 5.4
5827     \brief the minimal view-transformed size an item must have to be drawn
5828 
5829     When the scene is rendered, any item whose width or height, transformed
5830     to the target view, is smaller that minimumRenderSize(), will not be
5831     rendered. If an item is not rendered and it clips its children items
5832     they will also not be rendered. Set this value to speed up rendering
5833     of scenes with many objects rendered on a zoomed out view.
5834 
5835     The default value is 0. If unset, or if set to 0 or a negative value,
5836     all items will always be rendered.
5837 
5838     For example, setting this property can be especially useful if a scene
5839     is rendered by multiple views, one of which serves as an overview which
5840     always displays all items. In scenes with many items, such a view will
5841     use a high scaling factor so that all items can be shown. Due to the
5842     scaling, smaller items will only make an insignificant contribution to
5843     the final rendered scene. To avoid drawing these items and reduce the
5844     time necessary to render the scene, you can call setMinimumRenderSize()
5845     with a non-negative value.
5846 
5847     \note Items that are not drawn as a result of being too small, are still
5848     returned by methods such as items() and itemAt(), and participate in
5849     collision detection and interactions. It is recommended that you set
5850     minimumRenderSize() to a value less than or equal to 1 in order to
5851     avoid large unrendered items that are interactive.
5852 
5853     \sa QStyleOptionGraphicsItem::levelOfDetailFromTransform()
5854 */
minimumRenderSize() const5855 qreal QGraphicsScene::minimumRenderSize() const
5856 {
5857     Q_D(const QGraphicsScene);
5858     return d->minimumRenderSize;
5859 }
setMinimumRenderSize(qreal minSize)5860 void QGraphicsScene::setMinimumRenderSize(qreal minSize)
5861 {
5862     Q_D(QGraphicsScene);
5863     d->minimumRenderSize = minSize;
5864     update();
5865 }
5866 
5867 /*!
5868     \property QGraphicsScene::focusOnTouch
5869     \since 5.12
5870     \brief whether items gain focus when receiving a \e {touch begin} event.
5871 
5872     The usual behavior is to transfer focus only when an item is clicked. Often
5873     a tap on a touchpad is interpreted as equivalent to a mouse click by the
5874     operating system, generating a synthesized click event in response. However,
5875     at least on macOS you can configure this behavior.
5876 
5877     By default, QGraphicsScene also transfers focus when you touch on a trackpad
5878     or similar. If the operating system is configured to not generate a
5879     synthetic mouse click on tapping the trackpad, this is surprising. If the
5880     operating system does generate synthetic mouse clicks on tapping the
5881     trackpad, the focus transfer on starting a touch gesture is unnecessary.
5882 
5883     With focusOnTouch switched off, QGraphicsScene behaves as one would expect
5884     on macOS.
5885 
5886     The default value is \c true, ensuring that the default behavior is just as
5887     in Qt versions prior to 5.12. Set to \c false to prevent touch events from
5888     triggering focus changes.
5889 */
focusOnTouch() const5890 bool QGraphicsScene::focusOnTouch() const
5891 {
5892     Q_D(const QGraphicsScene);
5893     return d->focusOnTouch;
5894 }
5895 
setFocusOnTouch(bool enabled)5896 void QGraphicsScene::setFocusOnTouch(bool enabled)
5897 {
5898     Q_D(QGraphicsScene);
5899     d->focusOnTouch = enabled;
5900 }
5901 
addView(QGraphicsView * view)5902 void QGraphicsScenePrivate::addView(QGraphicsView *view)
5903 {
5904     views << view;
5905 #ifndef QT_NO_GESTURES
5906     const auto gestures = grabbedGestures.keys();
5907     for (Qt::GestureType gesture : gestures)
5908         view->viewport()->grabGesture(gesture);
5909 #endif
5910 }
5911 
removeView(QGraphicsView * view)5912 void QGraphicsScenePrivate::removeView(QGraphicsView *view)
5913 {
5914     views.removeAll(view);
5915 }
5916 
updateTouchPointsForItem(QGraphicsItem * item,QTouchEvent * touchEvent)5917 void QGraphicsScenePrivate::updateTouchPointsForItem(QGraphicsItem *item, QTouchEvent *touchEvent)
5918 {
5919     const QTransform mapFromScene =
5920         item->d_ptr->genericMapFromSceneTransform(static_cast<const QWidget *>(touchEvent->target()));
5921 
5922     for (auto &touchPoint : touchEvent->_touchPoints) {
5923         touchPoint.setPos(mapFromScene.map(touchPoint.scenePos()));
5924         touchPoint.setStartPos(mapFromScene.map(touchPoint.startScenePos()));
5925         touchPoint.setLastPos(mapFromScene.map(touchPoint.lastScenePos()));
5926     }
5927 }
5928 
findClosestTouchPointId(const QPointF & scenePos)5929 int QGraphicsScenePrivate::findClosestTouchPointId(const QPointF &scenePos)
5930 {
5931     int closestTouchPointId = -1;
5932     qreal closestDistance = qreal(0.);
5933     foreach (const QTouchEvent::TouchPoint &touchPoint, sceneCurrentTouchPoints) {
5934         qreal distance = QLineF(scenePos, touchPoint.scenePos()).length();
5935         if (closestTouchPointId == -1|| distance < closestDistance) {
5936             closestTouchPointId = touchPoint.id();
5937             closestDistance = distance;
5938         }
5939     }
5940     return closestTouchPointId;
5941 }
5942 
touchEventHandler(QTouchEvent * sceneTouchEvent)5943 void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent)
5944 {
5945     typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
5946     QHash<QGraphicsItem *, StatesAndTouchPoints> itemsNeedingEvents;
5947 
5948     for (int i = 0; i < sceneTouchEvent->touchPoints().count(); ++i) {
5949         const QTouchEvent::TouchPoint &touchPoint = sceneTouchEvent->touchPoints().at(i);
5950 
5951         // update state
5952         QGraphicsItem *item = nullptr;
5953         if (touchPoint.state() == Qt::TouchPointPressed) {
5954             if (sceneTouchEvent->device()->type() == QTouchDevice::TouchPad) {
5955                 // on touch-pad devices, send all touch points to the same item
5956                 item = itemForTouchPointId.isEmpty()
5957                        ? 0
5958                        : itemForTouchPointId.constBegin().value();
5959             }
5960 
5961             if (!item) {
5962                 // determine which item this touch point will go to
5963                 cachedItemsUnderMouse = itemsAtPosition(touchPoint.screenPos().toPoint(),
5964                                                         touchPoint.scenePos(),
5965                                                         static_cast<QWidget *>(sceneTouchEvent->target()));
5966                 item = cachedItemsUnderMouse.isEmpty() ? 0 : cachedItemsUnderMouse.constFirst();
5967             }
5968 
5969             if (sceneTouchEvent->device()->type() == QTouchDevice::TouchScreen) {
5970                 // on touch-screens, combine this touch point with the closest one we find
5971                 int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos());
5972                 QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId);
5973                 if (!item || (closestItem && cachedItemsUnderMouse.contains(closestItem)))
5974                     item = closestItem;
5975             }
5976             if (!item)
5977                 continue;
5978 
5979             itemForTouchPointId.insert(touchPoint.id(), item);
5980             sceneCurrentTouchPoints.insert(touchPoint.id(), touchPoint);
5981         } else if (touchPoint.state() == Qt::TouchPointReleased) {
5982             item = itemForTouchPointId.take(touchPoint.id());
5983             if (!item)
5984                 continue;
5985 
5986             sceneCurrentTouchPoints.remove(touchPoint.id());
5987         } else {
5988             item = itemForTouchPointId.value(touchPoint.id());
5989             if (!item)
5990                 continue;
5991             Q_ASSERT(sceneCurrentTouchPoints.contains(touchPoint.id()));
5992             sceneCurrentTouchPoints[touchPoint.id()] = touchPoint;
5993         }
5994 
5995         StatesAndTouchPoints &statesAndTouchPoints = itemsNeedingEvents[item];
5996         statesAndTouchPoints.first |= touchPoint.state();
5997         statesAndTouchPoints.second.append(touchPoint);
5998     }
5999 
6000     if (itemsNeedingEvents.isEmpty()) {
6001         sceneTouchEvent->ignore();
6002         return;
6003     }
6004 
6005     bool ignoreSceneTouchEvent = true;
6006     QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator it = itemsNeedingEvents.constBegin();
6007     const QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator end = itemsNeedingEvents.constEnd();
6008     for (; it != end; ++it) {
6009         QGraphicsItem *item = it.key();
6010 
6011         (void) item->isBlockedByModalPanel(&item);
6012 
6013         // determine event type from the state mask
6014         QEvent::Type eventType;
6015         switch (it.value().first) {
6016         case Qt::TouchPointPressed:
6017             // all touch points have pressed state
6018             eventType = QEvent::TouchBegin;
6019             break;
6020         case Qt::TouchPointReleased:
6021             // all touch points have released state
6022             eventType = QEvent::TouchEnd;
6023             break;
6024         case Qt::TouchPointStationary:
6025             // don't send the event if nothing changed
6026             continue;
6027         default:
6028             // all other combinations
6029             eventType = QEvent::TouchUpdate;
6030             break;
6031         }
6032 
6033         QTouchEvent touchEvent(eventType);
6034         touchEvent.setWindow(sceneTouchEvent->window());
6035         touchEvent.setTarget(sceneTouchEvent->target());
6036         touchEvent.setDevice(sceneTouchEvent->device());
6037         touchEvent.setModifiers(sceneTouchEvent->modifiers());
6038         touchEvent.setTouchPointStates(it.value().first);
6039         touchEvent.setTouchPoints(it.value().second);
6040         touchEvent.setTimestamp(sceneTouchEvent->timestamp());
6041 
6042         switch (touchEvent.type()) {
6043         case QEvent::TouchBegin:
6044         {
6045             // if the TouchBegin handler recurses, we assume that means the event
6046             // has been implicitly accepted and continue to send touch events
6047             item->d_ptr->acceptedTouchBeginEvent = true;
6048             bool res = sendTouchBeginEvent(item, &touchEvent)
6049                        && touchEvent.isAccepted();
6050             if (!res) {
6051                 // forget about these touch points, we didn't handle them
6052                 for (int i = 0; i < touchEvent.touchPoints().count(); ++i) {
6053                     const QTouchEvent::TouchPoint &touchPoint = touchEvent.touchPoints().at(i);
6054                     itemForTouchPointId.remove(touchPoint.id());
6055                     sceneCurrentTouchPoints.remove(touchPoint.id());
6056                 }
6057                 ignoreSceneTouchEvent = false;
6058             }
6059             break;
6060         }
6061         default:
6062             if (item->d_ptr->acceptedTouchBeginEvent) {
6063                 updateTouchPointsForItem(item, &touchEvent);
6064                 (void) sendEvent(item, &touchEvent);
6065                 ignoreSceneTouchEvent = false;
6066             }
6067             break;
6068         }
6069     }
6070     sceneTouchEvent->setAccepted(ignoreSceneTouchEvent);
6071 }
6072 
sendTouchBeginEvent(QGraphicsItem * origin,QTouchEvent * touchEvent)6073 bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEvent *touchEvent)
6074 {
6075     Q_Q(QGraphicsScene);
6076 
6077     if (focusOnTouch) {
6078         if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.constFirst() != origin) {
6079             const QTouchEvent::TouchPoint &firstTouchPoint = touchEvent->touchPoints().first();
6080             cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint.screenPos().toPoint(),
6081                                                     firstTouchPoint.scenePos(),
6082                                                     static_cast<QWidget *>(touchEvent->target()));
6083         }
6084 
6085         // Set focus on the topmost enabled item that can take focus.
6086         bool setFocus = false;
6087 
6088         foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
6089             if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
6090                 if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
6091                     setFocus = true;
6092                     if (item != q->focusItem())
6093                         q->setFocusItem(item, Qt::MouseFocusReason);
6094                     break;
6095                 }
6096             }
6097             if (item->isPanel())
6098                 break;
6099             if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
6100                 break;
6101             if (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling) {
6102                 // Make sure we don't clear focus.
6103                 setFocus = true;
6104                 break;
6105             }
6106         }
6107 
6108         // If nobody could take focus, clear it.
6109         if (!stickyFocus && !setFocus)
6110             q->setFocusItem(nullptr, Qt::MouseFocusReason);
6111     }
6112 
6113     bool res = false;
6114     bool eventAccepted = touchEvent->isAccepted();
6115     foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
6116         // first, try to deliver the touch event
6117         updateTouchPointsForItem(item, touchEvent);
6118         bool acceptTouchEvents = item->acceptTouchEvents();
6119         touchEvent->setAccepted(acceptTouchEvents);
6120         res = acceptTouchEvents && sendEvent(item, touchEvent);
6121         eventAccepted = touchEvent->isAccepted();
6122         if (itemForTouchPointId.value(touchEvent->touchPoints().first().id()) == 0) {
6123             // item was deleted
6124             item = nullptr;
6125         } else {
6126             item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted);
6127         }
6128         touchEvent->spont = false;
6129         if (res && eventAccepted) {
6130             // the first item to accept the TouchBegin gets an implicit grab.
6131             for (int i = 0; i < touchEvent->touchPoints().count(); ++i) {
6132                 const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i);
6133                 itemForTouchPointId[touchPoint.id()] = item; // can be zero
6134             }
6135             break;
6136         }
6137         if (item && item->isPanel())
6138             break;
6139     }
6140 
6141     touchEvent->setAccepted(eventAccepted);
6142     return res;
6143 }
6144 
enableTouchEventsOnViews()6145 void QGraphicsScenePrivate::enableTouchEventsOnViews()
6146 {
6147     foreach (QGraphicsView *view, views)
6148         view->viewport()->setAttribute(Qt::WA_AcceptTouchEvents, true);
6149 }
6150 
updateInputMethodSensitivityInViews()6151 void QGraphicsScenePrivate::updateInputMethodSensitivityInViews()
6152 {
6153     for (int i = 0; i < views.size(); ++i)
6154         views.at(i)->d_func()->updateInputMethodSensitivity();
6155 }
6156 
enterModal(QGraphicsItem * panel,QGraphicsItem::PanelModality previousModality)6157 void QGraphicsScenePrivate::enterModal(QGraphicsItem *panel, QGraphicsItem::PanelModality previousModality)
6158 {
6159     Q_Q(QGraphicsScene);
6160     Q_ASSERT(panel && panel->isPanel());
6161 
6162     QGraphicsItem::PanelModality panelModality = panel->d_ptr->panelModality;
6163     if (previousModality != QGraphicsItem::NonModal) {
6164         // the panel is changing from one modality type to another... temporarily set it back so
6165         // that blockedPanels is populated correctly
6166         panel->d_ptr->panelModality = previousModality;
6167     }
6168 
6169     QSet<QGraphicsItem *> blockedPanels;
6170     QList<QGraphicsItem *> items = q->items(); // ### store panels separately
6171     for (int i = 0; i < items.count(); ++i) {
6172         QGraphicsItem *item = items.at(i);
6173         if (item->isPanel() && item->isBlockedByModalPanel())
6174             blockedPanels.insert(item);
6175     }
6176     // blockedPanels contains all currently blocked panels
6177 
6178     if (previousModality != QGraphicsItem::NonModal) {
6179         // reset the modality to the proper value, since we changed it above
6180         panel->d_ptr->panelModality = panelModality;
6181         // remove this panel so that it will be reinserted at the front of the stack
6182         modalPanels.removeAll(panel);
6183     }
6184 
6185     modalPanels.prepend(panel);
6186 
6187     if (!hoverItems.isEmpty()) {
6188         // send GraphicsSceneHoverLeave events to newly blocked hoverItems
6189         QGraphicsSceneHoverEvent hoverEvent;
6190         hoverEvent.setScenePos(lastSceneMousePos);
6191         dispatchHoverEvent(&hoverEvent);
6192     }
6193 
6194     if (!mouseGrabberItems.isEmpty() && lastMouseGrabberItemHasImplicitMouseGrab) {
6195         QGraphicsItem *item = mouseGrabberItems.constLast();
6196         if (item->isBlockedByModalPanel())
6197             ungrabMouse(item, /*itemIsDying =*/ false);
6198     }
6199 
6200     QEvent windowBlockedEvent(QEvent::WindowBlocked);
6201     QEvent windowUnblockedEvent(QEvent::WindowUnblocked);
6202     for (int i = 0; i < items.count(); ++i) {
6203         QGraphicsItem *item = items.at(i);
6204         if (item->isPanel()) {
6205             if (!blockedPanels.contains(item) && item->isBlockedByModalPanel()) {
6206                 // send QEvent::WindowBlocked to newly blocked panels
6207                 sendEvent(item, &windowBlockedEvent);
6208             } else if (blockedPanels.contains(item) && !item->isBlockedByModalPanel()) {
6209                 // send QEvent::WindowUnblocked to unblocked panels when downgrading
6210                 // a panel from SceneModal to PanelModal
6211                 sendEvent(item, &windowUnblockedEvent);
6212             }
6213         }
6214     }
6215 }
6216 
leaveModal(QGraphicsItem * panel)6217 void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel)
6218 {
6219     Q_Q(QGraphicsScene);
6220     Q_ASSERT(panel && panel->isPanel());
6221 
6222     QSet<QGraphicsItem *> blockedPanels;
6223     QList<QGraphicsItem *> items = q->items(); // ### same as above
6224     for (int i = 0; i < items.count(); ++i) {
6225         QGraphicsItem *item = items.at(i);
6226         if (item->isPanel() && item->isBlockedByModalPanel())
6227             blockedPanels.insert(item);
6228     }
6229 
6230     modalPanels.removeAll(panel);
6231 
6232     QEvent e(QEvent::WindowUnblocked);
6233     for (int i = 0; i < items.count(); ++i) {
6234         QGraphicsItem *item = items.at(i);
6235         if (item->isPanel() && blockedPanels.contains(item) && !item->isBlockedByModalPanel())
6236             sendEvent(item, &e);
6237     }
6238 
6239     // send GraphicsSceneHoverEnter events to newly unblocked items
6240     QGraphicsSceneHoverEvent hoverEvent;
6241     hoverEvent.setScenePos(lastSceneMousePos);
6242     dispatchHoverEvent(&hoverEvent);
6243 }
6244 
6245 #ifndef QT_NO_GESTURES
gestureTargetsAtHotSpots(const QSet<QGesture * > & gestures,Qt::GestureFlag flag,QHash<QGraphicsObject *,QSet<QGesture * >> * targets,QSet<QGraphicsObject * > * itemsSet,QSet<QGesture * > * normal,QSet<QGesture * > * conflicts)6246 void QGraphicsScenePrivate::gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures,
6247                                               Qt::GestureFlag flag,
6248                                               QHash<QGraphicsObject *, QSet<QGesture *> > *targets,
6249                                               QSet<QGraphicsObject *> *itemsSet,
6250                                               QSet<QGesture *> *normal,
6251                                               QSet<QGesture *> *conflicts)
6252 {
6253     QSet<QGesture *> normalGestures; // that are not in conflicted state.
6254     for (QGesture *gesture : gestures) {
6255         if (!gesture->hasHotSpot())
6256             continue;
6257         const Qt::GestureType gestureType = gesture->gestureType();
6258         QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), gesture->d_func()->sceneHotSpot, nullptr);
6259         for (int j = 0; j < items.size(); ++j) {
6260             QGraphicsItem *item = items.at(j);
6261 
6262             // Check if the item is blocked by a modal panel and use it as
6263             // a target instead of this item.
6264             (void) item->isBlockedByModalPanel(&item);
6265 
6266             if (QGraphicsObject *itemobj = item->toGraphicsObject()) {
6267                 QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
6268                 QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it =
6269                         d->gestureContext.constFind(gestureType);
6270                 if (it != d->gestureContext.constEnd() && (!flag || (it.value() & flag))) {
6271                     if (normalGestures.contains(gesture)) {
6272                         normalGestures.remove(gesture);
6273                         if (conflicts)
6274                             conflicts->insert(gesture);
6275                     } else {
6276                         normalGestures.insert(gesture);
6277                     }
6278                     if (targets)
6279                         (*targets)[itemobj].insert(gesture);
6280                     if (itemsSet)
6281                         (*itemsSet).insert(itemobj);
6282                 }
6283             }
6284             // Don't propagate through panels.
6285             if (item->isPanel())
6286                 break;
6287         }
6288     }
6289     if (normal)
6290         *normal = normalGestures;
6291 }
6292 
gestureEventHandler(QGestureEvent * event)6293 void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
6294 {
6295     QWidget *viewport = event->widget();
6296     if (!viewport)
6297         return;
6298     QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(viewport->parent());
6299     if (!graphicsView)
6300         return;
6301 
6302     const QList<QGesture *> allGestures = event->gestures();
6303     DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6304             << "Gestures:" <<  allGestures;
6305 
6306     QSet<QGesture *> startedGestures;
6307     QPoint delta = viewport->mapFromGlobal(QPoint());
6308     QTransform toScene = QTransform::fromTranslate(delta.x(), delta.y())
6309                          * graphicsView->viewportTransform().inverted();
6310     for (QGesture *gesture : allGestures) {
6311         // cache scene coordinates of the hot spot
6312         if (gesture->hasHotSpot()) {
6313             gesture->d_func()->sceneHotSpot = toScene.map(gesture->hotSpot());
6314         } else {
6315             gesture->d_func()->sceneHotSpot = QPointF();
6316         }
6317 
6318         QGraphicsObject *target = gestureTargets.value(gesture, 0);
6319         if (!target) {
6320             // when we are not in started mode but don't have a target
6321             // then the only one interested in gesture is the view/scene
6322             if (gesture->state() == Qt::GestureStarted)
6323                 startedGestures.insert(gesture);
6324         }
6325     }
6326 
6327     if (!startedGestures.isEmpty()) {
6328         QSet<QGesture *> normalGestures; // that have just one target
6329         QSet<QGesture *> conflictedGestures; // that have multiple possible targets
6330         gestureTargetsAtHotSpots(startedGestures, Qt::GestureFlag(0), &cachedItemGestures, nullptr,
6331                                  &normalGestures, &conflictedGestures);
6332         cachedTargetItems = cachedItemGestures.keys();
6333         std::sort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
6334         DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6335                 << "Normal gestures:" << normalGestures
6336                 << "Conflicting gestures:" << conflictedGestures;
6337 
6338         // deliver conflicted gestures as override events AND remember
6339         // initial gesture targets
6340         if (!conflictedGestures.isEmpty()) {
6341             for (int i = 0; i < cachedTargetItems.size(); ++i) {
6342                 QPointer<QGraphicsObject> item = cachedTargetItems.at(i);
6343 
6344                 // get gestures to deliver to the current item
6345                 const QSet<QGesture *> gestures = conflictedGestures & cachedItemGestures.value(item.data());
6346                 if (gestures.isEmpty())
6347                     continue;
6348 
6349                 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6350                         << "delivering override to"
6351                         << item.data() << gestures;
6352                 // send gesture override
6353                 QGestureEvent ev(gestures.values());
6354                 ev.t = QEvent::GestureOverride;
6355                 ev.setWidget(event->widget());
6356                 // mark event and individual gestures as ignored
6357                 ev.ignore();
6358                 for (QGesture *g : gestures)
6359                     ev.setAccepted(g, false);
6360                 sendEvent(item.data(), &ev);
6361                 // mark all accepted gestures to deliver them as normal gesture events
6362                 for (QGesture *g : gestures) {
6363                     if (ev.isAccepted() || ev.isAccepted(g)) {
6364                         conflictedGestures.remove(g);
6365                         // mark the item as a gesture target
6366                         if (item) {
6367                             gestureTargets.insert(g, item.data());
6368                             QHash<QGraphicsObject *, QSet<QGesture *> >::iterator it, e;
6369                             it = cachedItemGestures.begin();
6370                             e = cachedItemGestures.end();
6371                             for(; it != e; ++it)
6372                                 it.value().remove(g);
6373                             cachedItemGestures[item.data()].insert(g);
6374                         }
6375                         DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6376                                 << "override was accepted:"
6377                                 << g << item.data();
6378                     }
6379                     // remember the first item that received the override event
6380                     // as it most likely become a target if no one else accepts
6381                     // the override event
6382                     if (!gestureTargets.contains(g) && item)
6383                         gestureTargets.insert(g, item.data());
6384 
6385                 }
6386                 if (conflictedGestures.isEmpty())
6387                     break;
6388             }
6389         }
6390         // remember the initial target item for each gesture that was not in
6391         // the conflicted state.
6392         if (!normalGestures.isEmpty()) {
6393             for (int i = 0; i < cachedTargetItems.size() && !normalGestures.isEmpty(); ++i) {
6394                 QGraphicsObject *item = cachedTargetItems.at(i);
6395 
6396                 // get gestures to deliver to the current item
6397                 const auto gestures = cachedItemGestures.value(item);
6398                 for (QGesture *g : gestures) {
6399                     if (!gestureTargets.contains(g)) {
6400                         gestureTargets.insert(g, item);
6401                         normalGestures.remove(g);
6402                     }
6403                 }
6404             }
6405         }
6406     }
6407 
6408 
6409     // deliver all gesture events
6410     QSet<QGesture *> undeliveredGestures;
6411     QSet<QGesture *> parentPropagatedGestures;
6412     for (QGesture *gesture : allGestures) {
6413         if (QGraphicsObject *target = gestureTargets.value(gesture, 0)) {
6414             cachedItemGestures[target].insert(gesture);
6415             cachedTargetItems.append(target);
6416             undeliveredGestures.insert(gesture);
6417             QGraphicsItemPrivate *d = target->QGraphicsItem::d_func();
6418             const Qt::GestureFlags flags = d->gestureContext.value(gesture->gestureType());
6419             if (flags & Qt::IgnoredGesturesPropagateToParent)
6420                 parentPropagatedGestures.insert(gesture);
6421         } else {
6422             DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6423                     << "no target for" << gesture << "at"
6424                     << gesture->hotSpot() << gesture->d_func()->sceneHotSpot;
6425         }
6426     }
6427     std::sort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
6428     for (int i = 0; i < cachedTargetItems.size(); ++i) {
6429         QPointer<QGraphicsObject> receiver = cachedTargetItems.at(i);
6430         QSet<QGesture *> gestures =
6431                 undeliveredGestures & cachedItemGestures.value(receiver.data());
6432         gestures -= cachedAlreadyDeliveredGestures.value(receiver.data());
6433 
6434         if (gestures.isEmpty())
6435             continue;
6436 
6437         cachedAlreadyDeliveredGestures[receiver.data()] += gestures;
6438         const bool isPanel = receiver.data()->isPanel();
6439 
6440         DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6441                 << "delivering to"
6442                 << receiver.data() << gestures;
6443         QGestureEvent ev(gestures.values());
6444         ev.setWidget(event->widget());
6445         sendEvent(receiver.data(), &ev);
6446         QSet<QGesture *> ignoredGestures;
6447         for (QGesture *g : qAsConst(gestures)) {
6448             if (!ev.isAccepted() && !ev.isAccepted(g)) {
6449                 // if the gesture was ignored by its target, we will update the
6450                 // targetItems list with a possible target items (items that
6451                 // want to receive partial gestures).
6452                 // ### won't work if the target was destroyed in the event
6453                 //     we will just stop delivering it.
6454                 if (receiver && receiver.data() == gestureTargets.value(g, 0))
6455                     ignoredGestures.insert(g);
6456             } else {
6457                 if (receiver && g->state() == Qt::GestureStarted) {
6458                     // someone accepted the propagated initial GestureStarted
6459                     // event, let it be the new target for all following events.
6460                     gestureTargets[g] = receiver.data();
6461                 }
6462                 undeliveredGestures.remove(g);
6463             }
6464         }
6465         if (undeliveredGestures.isEmpty())
6466             break;
6467 
6468         // ignoredGestures list is only filled when delivering to the gesture
6469         // target item, so it is safe to assume item == target.
6470         if (!ignoredGestures.isEmpty() && !isPanel) {
6471             // look for new potential targets for gestures that were ignored
6472             // and should be propagated.
6473 
6474             QSet<QGraphicsObject *> targetsSet(cachedTargetItems.constBegin(), cachedTargetItems.constEnd());
6475 
6476             if (receiver) {
6477                 // first if the gesture should be propagated to parents only
6478                 for (QSet<QGesture *>::iterator it = ignoredGestures.begin();
6479                      it != ignoredGestures.end();) {
6480                     if (parentPropagatedGestures.contains(*it)) {
6481                         QGesture *gesture = *it;
6482                         const Qt::GestureType gestureType = gesture->gestureType();
6483                         QGraphicsItem *item = receiver.data();
6484                         while (item) {
6485                             if (QGraphicsObject *obj = item->toGraphicsObject()) {
6486                                 if (item->d_func()->gestureContext.contains(gestureType)) {
6487                                     targetsSet.insert(obj);
6488                                     cachedItemGestures[obj].insert(gesture);
6489                                 }
6490                             }
6491                             if (item->isPanel())
6492                                 break;
6493                             item = item->parentItem();
6494                         }
6495 
6496                         it = ignoredGestures.erase(it);
6497                         continue;
6498                     }
6499                     ++it;
6500                 }
6501             }
6502 
6503             gestureTargetsAtHotSpots(ignoredGestures, Qt::ReceivePartialGestures,
6504                                      &cachedItemGestures, &targetsSet, nullptr, nullptr);
6505 
6506             cachedTargetItems = targetsSet.values();
6507             std::sort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
6508             DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6509                     << "new targets:" << cachedTargetItems;
6510             i = -1; // start delivery again
6511             continue;
6512         }
6513     }
6514 
6515     foreach (QGesture *g, startedGestures) {
6516         if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
6517             DEBUG() << "lets try to cancel some";
6518             // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
6519             cancelGesturesForChildren(g);
6520         }
6521     }
6522 
6523     // forget about targets for gestures that have ended
6524     for (QGesture *g : allGestures) {
6525         switch (g->state()) {
6526         case Qt::GestureFinished:
6527         case Qt::GestureCanceled:
6528             gestureTargets.remove(g);
6529             break;
6530         default:
6531             break;
6532         }
6533     }
6534 
6535     cachedTargetItems.clear();
6536     cachedItemGestures.clear();
6537     cachedAlreadyDeliveredGestures.clear();
6538 }
6539 
cancelGesturesForChildren(QGesture * original)6540 void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original)
6541 {
6542     Q_ASSERT(original);
6543     QGraphicsItem *originalItem = gestureTargets.value(original);
6544     if (originalItem == nullptr) // we only act on accepted gestures, which implies it has a target.
6545         return;
6546 
6547     // iterate over all active gestures and for each find the owner
6548     // if the owner is part of our sub-hierarchy, cancel it.
6549 
6550     QSet<QGesture *> canceledGestures;
6551     QHash<QGesture *, QGraphicsObject *>::Iterator iter = gestureTargets.begin();
6552     while (iter != gestureTargets.end()) {
6553         QGraphicsObject *item = iter.value();
6554         // note that we don't touch the gestures for our originalItem
6555         if (item != originalItem && originalItem->isAncestorOf(item)) {
6556             DEBUG() << "  found a gesture to cancel" << iter.key();
6557             iter.key()->d_func()->state = Qt::GestureCanceled;
6558             canceledGestures << iter.key();
6559         }
6560         ++iter;
6561     }
6562 
6563     // sort them per target item by cherry picking from almostCanceledGestures and delivering
6564     QSet<QGesture *> almostCanceledGestures = canceledGestures;
6565     QSet<QGesture *>::Iterator setIter;
6566     while (!almostCanceledGestures.isEmpty()) {
6567         QGraphicsObject *target = nullptr;
6568         QSet<QGesture*> gestures;
6569         setIter = almostCanceledGestures.begin();
6570         // sort per target item
6571         while (setIter != almostCanceledGestures.end()) {
6572             QGraphicsObject *item = gestureTargets.value(*setIter);
6573             if (target == nullptr)
6574                 target = item;
6575             if (target == item) {
6576                 gestures << *setIter;
6577                 setIter = almostCanceledGestures.erase(setIter);
6578             } else {
6579                 ++setIter;
6580             }
6581         }
6582         Q_ASSERT(target);
6583 
6584         const QList<QGesture *> list = gestures.values();
6585         QGestureEvent ev(list);
6586         sendEvent(target, &ev);
6587 
6588         if (!ev.isAccepted()) {
6589             for (QGesture *g : list) {
6590 
6591                 if (ev.isAccepted(g))
6592                     continue;
6593 
6594                 if (!g->hasHotSpot())
6595                     continue;
6596 
6597                 QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), g->d_func()->sceneHotSpot, nullptr);
6598                 for (int j = 0; j < items.size(); ++j) {
6599                     QGraphicsObject *item = items.at(j)->toGraphicsObject();
6600                     if (!item)
6601                         continue;
6602                     QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
6603                     if (d->gestureContext.contains(g->gestureType())) {
6604                         QList<QGesture *> list;
6605                         list << g;
6606                         QGestureEvent ev(list);
6607                         sendEvent(item, &ev);
6608                         if (ev.isAccepted() || ev.isAccepted(g))
6609                             break; // successfully delivered
6610                     }
6611                 }
6612             }
6613         }
6614     }
6615 
6616     QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
6617     Q_ASSERT(gestureManager); // it would be very odd if we got called without a manager.
6618     for (setIter = canceledGestures.begin(); setIter != canceledGestures.end(); ++setIter) {
6619         gestureManager->recycle(*setIter);
6620         gestureTargets.remove(*setIter);
6621     }
6622 }
6623 
grabGesture(QGraphicsItem *,Qt::GestureType gesture)6624 void QGraphicsScenePrivate::grabGesture(QGraphicsItem *, Qt::GestureType gesture)
6625 {
6626     (void)QGestureManager::instance(); // create a gesture manager
6627     if (!grabbedGestures[gesture]++) {
6628         foreach (QGraphicsView *view, views)
6629             view->viewport()->grabGesture(gesture);
6630     }
6631 }
6632 
ungrabGesture(QGraphicsItem * item,Qt::GestureType gesture)6633 void QGraphicsScenePrivate::ungrabGesture(QGraphicsItem *item, Qt::GestureType gesture)
6634 {
6635     // we know this can only be an object
6636     Q_ASSERT(item->d_ptr->isObject);
6637     QGraphicsObject *obj = static_cast<QGraphicsObject *>(item);
6638     QGestureManager::instance()->cleanupCachedGestures(obj, gesture);
6639     if (!--grabbedGestures[gesture]) {
6640         foreach (QGraphicsView *view, views)
6641             view->viewport()->ungrabGesture(gesture);
6642     }
6643 }
6644 #endif // QT_NO_GESTURES
6645 
6646 QT_END_NAMESPACE
6647 
6648 #include "moc_qgraphicsscene.cpp"
6649