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