1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
44 \brief The QGraphicsScene class provides a surface for managing a large
45 number of 2D graphical items.
47 \ingroup graphicsview-api
50 The class serves as a container for QGraphicsItems. It is used together
51 with QGraphicsView for visualizing graphical items, such as lines,
52 rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is
53 part of the \l{Graphics View Framework}.
55 QGraphicsScene also provides functionality that lets you efficiently
56 determine both the location of items, and for determining what items are
57 visible within an arbitrary area on the scene. With the QGraphicsView
58 widget, you can either visualize the whole scene, or zoom in and view only
63 \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 0
65 Note that QGraphicsScene has no visual appearance of its own; it only
66 manages the items. You need to create a QGraphicsView widget to visualize
69 To add items to a scene, you start off by constructing a QGraphicsScene
70 object. Then, you have two options: either add your existing QGraphicsItem
71 objects by calling addItem(), or you can call one of the convenience
72 functions addEllipse(), addLine(), addPath(), addPixmap(), addPolygon(),
73 addRect(), or addText(), which all return a pointer to the newly added item.
74 The dimensions of the items added with these functions are relative to the
75 item's coordinate system, and the items position is initialized to (0,
78 You can then visualize the scene using QGraphicsView. When the scene
79 changes, (e.g., when an item moves or is transformed) QGraphicsScene
80 emits the changed() signal. To remove an item, call removeItem().
82 QGraphicsScene uses an indexing algorithm to manage the location of items
83 efficiently. By default, a BSP (Binary Space Partitioning) tree is used; an
84 algorithm suitable for large scenes where most items remain static (i.e.,
85 do not move around). You can choose to disable this index by calling
86 setItemIndexMethod(). For more information about the available indexing
87 algorithms, see the itemIndexMethod property.
89 The scene's bounding rect is set by calling setSceneRect(). Items can be
90 placed at any position on the scene, and the size of the scene is by
91 default unlimited. The scene rect is used only for internal bookkeeping,
92 maintaining the scene's item index. If the scene rect is unset,
93 QGraphicsScene will use the bounding area of all items, as returned by
94 itemsBoundingRect(), as the scene rect. However, itemsBoundingRect() is a
95 relatively time consuming function, as it operates by collecting
96 positional information for every item on the scene. Because of this, you
97 should always set the scene rect when operating on large scenes.
99 One of QGraphicsScene's greatest strengths is its ability to efficiently
100 determine the location of items. Even with millions of items on the scene,
101 the items() functions can determine the location of an item within few
102 milliseconds. There are several overloads to items(): one that finds items
103 at a certain position, one that finds items inside or intersecting with a
104 polygon or a rectangle, and more. The list of returned items is sorted by
105 stacking order, with the topmost item being the first item in the list.
106 For convenience, there is also an itemAt() function that returns the
107 topmost item at a given position.
109 QGraphicsScene maintains selection information for the scene. To select
110 items, call setSelectionArea(), and to clear the current selection, call
111 clearSelection(). Call selectedItems() to get the list of all selected
114 \section1 Event Handling and Propagation
116 Another responsibility that QGraphicsScene has, is to propagate events
117 from QGraphicsView. To send an event to a scene, you construct an event
118 that inherits QEvent, and then send it using, for example,
119 QApplication::sendEvent(). event() is responsible for dispatching
120 the event to the individual items. Some common events are handled by
121 convenience event handlers. For example, key press events are handled by
122 keyPressEvent(), and mouse press events are handled by mousePressEvent().
124 Key events are delivered to the \e {focus item}. To set the focus item,
125 you can either call setFocusItem(), passing an item that accepts focus, or
126 the item itself can call QGraphicsItem::setFocus(). Call focusItem() to
127 get the current focus item. For compatibility with widgets, the scene also
128 maintains its own focus information. By default, the scene does not have
129 focus, and all key events are discarded. If setFocus() is called, or if an
130 item on the scene gains focus, the scene automatically gains focus. If the
131 scene has focus, hasFocus() will return true, and key events will be
132 forwarded to the focus item, if any. If the scene loses focus, (i.e.,
133 someone calls clearFocus()) while an item has focus, the scene will
134 maintain its item focus information, and once the scene regains focus, it
135 will make sure the last focus item regains focus.
137 For mouse-over effects, QGraphicsScene dispatches \e {hover
138 events}. If an item accepts hover events (see
139 QGraphicsItem::acceptHoverEvents()), it will receive a \l
140 {QEvent::}{GraphicsSceneHoverEnter} event when the mouse enters
141 its area. As the mouse continues moving inside the item's area,
142 QGraphicsScene will send it \l {QEvent::}{GraphicsSceneHoverMove}
143 events. When the mouse leaves the item's area, the item will
144 receive a \l {QEvent::}{GraphicsSceneHoverLeave} event.
146 All mouse events are delivered to the current \e {mouse grabber}
147 item. An item becomes the scene's mouse grabber if it accepts
148 mouse events (see QGraphicsItem::acceptedMouseButtons()) and it
149 receives a mouse press. It stays the mouse grabber until it
150 receives a mouse release when no other mouse buttons are
151 pressed. You can call mouseGrabberItem() to determine what item is
152 currently grabbing the mouse.
154 \sa QGraphicsItem, QGraphicsView
158 \enum QGraphicsScene::SceneLayer
161 This enum describes the rendering layers in a QGraphicsScene. When
162 QGraphicsScene draws the scene contents, it renders each of these layers
163 separately, in order.
165 Each layer represents a flag that can be OR'ed together when calling
166 functions such as invalidate() or QGraphicsView::invalidateScene().
168 \value ItemLayer The item layer. QGraphicsScene renders all items are in
169 this layer by calling the virtual function drawItems(). The item layer is
170 drawn after the background layer, but before the foreground layer.
172 \value BackgroundLayer The background layer. QGraphicsScene renders the
173 scene's background in this layer by calling the virtual function
174 drawBackground(). The background layer is drawn first of all layers.
176 \value ForegroundLayer The foreground layer. QGraphicsScene renders the
177 scene's foreground in this layer by calling the virtual function
178 drawForeground(). The foreground layer is drawn last of all layers.
180 \value AllLayers All layers; this value represents a combination of all
183 \sa invalidate(), QGraphicsView::invalidateScene()
187 \enum QGraphicsScene::ItemIndexMethod
189 This enum describes the indexing algorithms QGraphicsScene provides for
190 managing positional information about items on the scene.
192 \value BspTreeIndex A Binary Space Partitioning tree is applied. All
193 QGraphicsScene's item location algorithms are of an order close to
194 logarithmic complexity, by making use of binary search. Adding, moving and
195 removing items is logarithmic. This approach is best for static scenes
196 (i.e., scenes where most items do not move).
198 \value NoIndex No index is applied. Item location is of linear complexity,
199 as all items on the scene are searched. Adding, moving and removing items,
200 however, is done in constant time. This approach is ideal for dynamic
201 scenes, where many items are added, moved or removed continuously.
203 \sa setItemIndexMethod(), bspTreeDepth
206 #include "qgraphicsscene.h"
208 #ifndef QT_NO_GRAPHICSVIEW
210 #include "qgraphicsitem.h"
211 #include "qgraphicsitem_p.h"
212 #include "qgraphicslayout.h"
213 #include "qgraphicsscene_p.h"
214 #include "qgraphicssceneevent.h"
215 #include "qgraphicsview.h"
216 #include "qgraphicsview_p.h"
217 #include "qgraphicswidget.h"
218 #include "qgraphicswidget_p.h"
219 #include "qgraphicssceneindex_p.h"
220 #include "qgraphicsscenebsptreeindex_p.h"
221 #include "qgraphicsscenelinearindex_p.h"
223 #include <QtCore/qdebug.h>
224 #include <QtCore/qlist.h>
225 #include <QtCore/qmath.h>
226 #include <QtCore/qrect.h>
227 #include <QtCore/qset.h>
228 #include <QtCore/qstack.h>
229 #include <QtCore/qtimer.h>
230 #include <QtCore/qvarlengtharray.h>
231 #include <QtCore/QMetaMethod>
232 #include <QtWidgets/qapplication.h>
233 #include <QtWidgets/qdesktopwidget.h>
234 #include <QtGui/qevent.h>
235 #include <QtWidgets/qgraphicslayout.h>
236 #include <QtWidgets/qgraphicsproxywidget.h>
237 #include <QtWidgets/qgraphicswidget.h>
238 #include <QtGui/qmatrix.h>
239 #include <QtGui/qpaintengine.h>
240 #include <QtGui/qpainter.h>
241 #include <QtGui/qpixmapcache.h>
242 #include <QtGui/qpolygon.h>
243 #include <QtWidgets/qstyleoption.h>
244 #include <QtWidgets/qtooltip.h>
245 #include <QtGui/qtransform.h>
246 #include <QtGui/qinputmethod.h>
247 #include <QtWidgets/qgraphicseffect.h>
248 #ifndef QT_NO_ACCESSIBILITY
249 # include <QtGui/qaccessible.h>
251 #include <private/qapplication_p.h>
252 #include <private/qobject_p.h>
254 #include <private/qt_x11_p.h>
256 #include <private/qgraphicseffect_p.h>
257 #include <private/qgesturemanager_p.h>
258 #include <private/qpathclipper_p.h>
260 // #define GESTURE_DEBUG
261 #ifndef GESTURE_DEBUG
262 # define DEBUG if (0) qDebug
264 # define DEBUG qDebug
269 bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
271 static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent)
273 hover->setWidget(mouseEvent->widget());
274 hover->setPos(mouseEvent->pos());
275 hover->setScenePos(mouseEvent->scenePos());
276 hover->setScreenPos(mouseEvent->screenPos());
277 hover->setLastPos(mouseEvent->lastPos());
278 hover->setLastScenePos(mouseEvent->lastScenePos());
279 hover->setLastScreenPos(mouseEvent->lastScreenPos());
280 hover->setModifiers(mouseEvent->modifiers());
281 hover->setAccepted(mouseEvent->isAccepted());
287 QGraphicsScenePrivate::QGraphicsScenePrivate()
288 : indexMethod(QGraphicsScene::BspTreeIndex),
292 dirtyGrowingItemsBoundingRect(true),
294 calledEmitUpdated(false),
295 processDirtyItemsEmitted(false),
296 needSortTopLevelItems(true),
297 holesInTopLevelSiblingIndex(false),
298 topLevelSequentialOrdering(true),
299 scenePosDescendantsUpdatePending(false),
302 lastMouseGrabberItemHasImplicitMouseGrab(false),
303 allItemsIgnoreHoverEvents(true),
304 allItemsUseDefaultCursor(true),
305 painterStateProtection(true),
306 sortCacheEnabled(false),
307 allItemsIgnoreTouchEvents(true),
308 selectionChanging(0),
316 activationRefCount(0),
317 childExplicitActivation(0),
318 lastMouseGrabberItem(0),
321 lastDropAction(Qt::IgnoreAction),
329 void QGraphicsScenePrivate::init()
333 index = new QGraphicsSceneBspTreeIndex(q);
335 // Keep this index so we can check for connected slots later on.
336 changedSignalIndex = signalIndex("changed(QList<QRectF>)");
337 processDirtyItemsIndex = q->metaObject()->indexOfSlot("_q_processDirtyItems()");
338 polishItemsIndex = q->metaObject()->indexOfSlot("_q_polishItems()");
340 qApp->d_func()->scene_list.append(q);
347 QGraphicsScenePrivate *QGraphicsScenePrivate::get(QGraphicsScene *q)
352 void QGraphicsScenePrivate::_q_emitUpdated()
355 calledEmitUpdated = false;
357 if (dirtyGrowingItemsBoundingRect) {
359 const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
360 growingItemsBoundingRect |= q->itemsBoundingRect();
361 if (oldGrowingItemsBoundingRect != growingItemsBoundingRect)
362 emit q->sceneRectChanged(growingItemsBoundingRect);
364 dirtyGrowingItemsBoundingRect = false;
367 // Ensure all views are connected if anything is connected. This disables
368 // the optimization that items send updates directly to the views, but it
369 // needs to happen in order to keep compatibility with the behavior from
370 // Qt 4.4 and backward.
371 if (isSignalConnected(changedSignalIndex)) {
372 for (int i = 0; i < views.size(); ++i) {
373 QGraphicsView *view = views.at(i);
374 if (!view->d_func()->connectedToScene) {
375 view->d_func()->connectedToScene = true;
376 q->connect(q, SIGNAL(changed(QList<QRectF>)),
377 views.at(i), SLOT(updateScene(QList<QRectF>)));
381 if (views.isEmpty()) {
385 for (int i = 0; i < views.size(); ++i)
386 views.at(i)->d_func()->processPendingUpdates();
387 // It's important that we update all views before we dispatch, hence two for-loops.
388 for (int i = 0; i < views.size(); ++i)
389 views.at(i)->d_func()->dispatchPendingUpdateRequests();
393 // Notify the changes to anybody interested.
394 QList<QRectF> oldUpdatedRects;
395 oldUpdatedRects = updateAll ? (QList<QRectF>() << q->sceneRect()) : updatedRects;
397 updatedRects.clear();
398 emit q->changed(oldUpdatedRects);
404 ### This function is almost identical to QGraphicsItemPrivate::addChild().
406 void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item)
408 item->d_ptr->ensureSequentialSiblingIndex();
409 needSortTopLevelItems = true; // ### maybe false
410 item->d_ptr->siblingIndex = topLevelItems.size();
411 topLevelItems.append(item);
417 ### This function is almost identical to QGraphicsItemPrivate::removeChild().
419 void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item)
421 if (!holesInTopLevelSiblingIndex)
422 holesInTopLevelSiblingIndex = item->d_ptr->siblingIndex != topLevelItems.size() - 1;
423 if (topLevelSequentialOrdering && !holesInTopLevelSiblingIndex)
424 topLevelItems.removeAt(item->d_ptr->siblingIndex);
426 topLevelItems.removeOne(item);
427 // NB! Do not use topLevelItems.removeAt(item->d_ptr->siblingIndex) because
428 // the item is not guaranteed to be at the index after the list is sorted
429 // (see ensureSortedTopLevelItems()).
430 item->d_ptr->siblingIndex = -1;
431 if (topLevelSequentialOrdering)
432 topLevelSequentialOrdering = !holesInTopLevelSiblingIndex;
438 void QGraphicsScenePrivate::_q_polishItems()
440 if (unpolishedItems.isEmpty())
443 const QVariant booleanTrueVariant(true);
444 QGraphicsItem *item = 0;
445 QGraphicsItemPrivate *itemd = 0;
446 const int oldUnpolishedCount = unpolishedItems.count();
448 for (int i = 0; i < oldUnpolishedCount; ++i) {
449 item = unpolishedItems.at(i);
452 itemd = item->d_ptr.data();
453 itemd->pendingPolish = false;
454 if (!itemd->explicitlyHidden) {
455 item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant);
456 item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant);
458 if (itemd->isWidget) {
459 QEvent event(QEvent::Polish);
460 QApplication::sendEvent((QGraphicsWidget *)item, &event);
464 if (unpolishedItems.count() == oldUnpolishedCount) {
465 // No new items were added to the vector.
466 unpolishedItems.clear();
468 // New items were appended; keep them and remove the old ones.
469 unpolishedItems.remove(0, oldUnpolishedCount);
470 unpolishedItems.squeeze();
471 QMetaObject::invokeMethod(q_ptr, "_q_polishItems", Qt::QueuedConnection);
475 void QGraphicsScenePrivate::_q_processDirtyItems()
477 processDirtyItemsEmitted = false;
480 Q_ASSERT(calledEmitUpdated);
481 // No need for further processing (except resetting the dirty states).
482 // The growingItemsBoundingRect is updated in _q_emitUpdated.
483 for (int i = 0; i < topLevelItems.size(); ++i)
484 resetDirtyItem(topLevelItems.at(i), /*recursive=*/true);
488 const bool wasPendingSceneUpdate = calledEmitUpdated;
489 const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
491 // Process items recursively.
492 for (int i = 0; i < topLevelItems.size(); ++i)
493 processDirtyItemsRecursive(topLevelItems.at(i));
495 dirtyGrowingItemsBoundingRect = false;
496 if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect)
497 emit q_func()->sceneRectChanged(growingItemsBoundingRect);
499 if (wasPendingSceneUpdate)
502 for (int i = 0; i < views.size(); ++i)
503 views.at(i)->d_func()->processPendingUpdates();
505 if (calledEmitUpdated) {
506 // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive
507 // and we cannot wait for the control to reach the eventloop before the
508 // changed signal is emitted, so we emit it now.
512 // Immediately dispatch all pending update requests on the views.
513 for (int i = 0; i < views.size(); ++i)
514 views.at(i)->d_func()->dispatchPendingUpdateRequests();
520 void QGraphicsScenePrivate::setScenePosItemEnabled(QGraphicsItem *item, bool enabled)
522 QGraphicsItem *p = item->d_ptr->parent;
524 p->d_ptr->scenePosDescendants = enabled;
525 p = p->d_ptr->parent;
527 if (!enabled && !scenePosDescendantsUpdatePending) {
528 scenePosDescendantsUpdatePending = true;
529 QMetaObject::invokeMethod(q_func(), "_q_updateScenePosDescendants", Qt::QueuedConnection);
536 void QGraphicsScenePrivate::registerScenePosItem(QGraphicsItem *item)
538 scenePosItems.insert(item);
539 setScenePosItemEnabled(item, true);
545 void QGraphicsScenePrivate::unregisterScenePosItem(QGraphicsItem *item)
547 scenePosItems.remove(item);
548 setScenePosItemEnabled(item, false);
554 void QGraphicsScenePrivate::_q_updateScenePosDescendants()
556 foreach (QGraphicsItem *item, scenePosItems) {
557 QGraphicsItem *p = item->d_ptr->parent;
559 p->d_ptr->scenePosDescendants = 1;
560 p = p->d_ptr->parent;
563 scenePosDescendantsUpdatePending = false;
569 Schedules an item for removal. This function leaves some stale indexes
570 around in the BSP tree if called from the item's destructor; these will
571 be cleaned up the next time someone triggers purgeRemovedItems().
573 Note: This function might get called from QGraphicsItem's destructor. \a item is
574 being destroyed, so we cannot call any pure virtual functions on it (such
575 as boundingRect()). Also, it is unnecessary to update the item's own state
578 void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
582 // Clear focus on the item to remove any reference in the focusWidget chain.
585 markDirty(item, QRectF(), /*invalidateChildren=*/false, /*force=*/false,
586 /*ignoreOpacity=*/false, /*removingItemFromScene=*/true);
588 if (item->d_ptr->inDestructor) {
589 // The item is actually in its destructor, we call the special method in the index.
590 index->deleteItem(item);
592 // Can potentially call item->boundingRect() (virtual function), that's why
593 // we only can call this function if the item is not in its destructor.
594 index->removeItem(item);
597 item->d_ptr->clearSubFocus();
599 if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges)
600 unregisterScenePosItem(item);
602 QGraphicsScene *oldScene = item->d_func()->scene;
603 item->d_func()->scene = 0;
605 //We need to remove all children first because they might use their parent
606 //attributes (e.g. sceneTransform).
607 if (!item->d_ptr->inDestructor) {
608 // Remove all children recursively
609 for (int i = 0; i < item->d_ptr->children.size(); ++i)
610 q->removeItem(item->d_ptr->children.at(i));
613 if (!item->d_ptr->inDestructor && item == tabFocusFirst) {
614 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
615 widget->d_func()->fixFocusChainBeforeReparenting(0, oldScene, 0);
618 // Unregister focus proxy.
619 item->d_ptr->resetFocusProxy();
621 // Remove from parent, or unregister from toplevels.
622 if (QGraphicsItem *parentItem = item->parentItem()) {
623 if (parentItem->scene()) {
624 Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem",
625 "Parent item's scene is different from this item's scene");
626 item->setParentItem(0);
629 unregisterTopLevelItem(item);
632 // Reset the mouse grabber and focus item data.
633 if (item == focusItem)
635 if (item == lastFocusItem)
637 if (item == passiveFocusItem)
638 passiveFocusItem = 0;
639 if (item == activePanel) {
643 if (item == lastActivePanel)
646 // Cancel active touches
648 QMap<int, QGraphicsItem *>::iterator it = itemForTouchPointId.begin();
649 while (it != itemForTouchPointId.end()) {
650 if (it.value() == item) {
651 sceneCurrentTouchPoints.remove(it.key());
652 it = itemForTouchPointId.erase(it);
659 // Disable selectionChanged() for individual items
661 int oldSelectedItemsSize = selectedItems.size();
663 // Update selected & hovered item bookkeeping
664 selectedItems.remove(item);
665 hoverItems.removeAll(item);
666 cachedItemsUnderMouse.removeAll(item);
667 if (item->d_ptr->pendingPolish) {
668 const int unpolishedIndex = unpolishedItems.indexOf(item);
669 if (unpolishedIndex != -1)
670 unpolishedItems[unpolishedIndex] = 0;
671 item->d_ptr->pendingPolish = false;
673 resetDirtyItem(item);
675 //We remove all references of item from the sceneEventFilter arrays
676 QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin();
677 while (iterator != sceneEventFilters.end()) {
678 if (iterator.value() == item || iterator.key() == item)
679 iterator = sceneEventFilters.erase(iterator);
684 if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
687 // Reset the mouse grabber and focus item data.
688 if (mouseGrabberItems.contains(item))
689 ungrabMouse(item, /* item is dying */ item->d_ptr->inDestructor);
691 // Reset the keyboard grabber
692 if (keyboardGrabberItems.contains(item))
693 ungrabKeyboard(item, /* item is dying */ item->d_ptr->inDestructor);
695 // Reset the last mouse grabber item
696 if (item == lastMouseGrabberItem)
697 lastMouseGrabberItem = 0;
699 // Reset the current drop item
700 if (item == dragDropItem)
703 // Reenable selectionChanged() for individual items
705 if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize)
706 emit q->selectionChanged();
708 #ifndef QT_NO_GESTURES
709 QHash<QGesture *, QGraphicsObject *>::iterator it;
710 for (it = gestureTargets.begin(); it != gestureTargets.end();) {
711 if (it.value() == item)
712 it = gestureTargets.erase(it);
717 QGraphicsObject *dummy = static_cast<QGraphicsObject *>(item);
718 cachedTargetItems.removeOne(dummy);
719 cachedItemGestures.remove(dummy);
720 cachedAlreadyDeliveredGestures.remove(dummy);
722 foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys())
723 ungrabGesture(item, gesture);
724 #endif // QT_NO_GESTURES
730 void QGraphicsScenePrivate::setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent)
733 if (item && item->scene() != q) {
734 qWarning("QGraphicsScene::setActivePanel: item %p must be part of this scene",
739 // Ensure the scene has focus when we change panel activation.
740 q->setFocus(Qt::ActiveWindowFocusReason);
742 // Find the item's panel.
743 QGraphicsItem *panel = item ? item->panel() : 0;
744 lastActivePanel = panel ? activePanel : 0;
745 if (panel == activePanel || (!q->isActive() && !duringActivationEvent))
748 // Deactivate the last active panel.
750 if (QGraphicsItem *fi = activePanel->focusItem()) {
751 // Remove focus from the current focus item.
752 if (fi == q->focusItem())
753 q->setFocusItem(0, Qt::ActiveWindowFocusReason);
756 QEvent event(QEvent::WindowDeactivate);
757 q->sendEvent(activePanel, &event);
758 } else if (panel && !duringActivationEvent) {
759 // Deactivate the scene if changing activation to a panel.
760 QEvent event(QEvent::WindowDeactivate);
761 foreach (QGraphicsItem *item, q->items()) {
762 if (item->isVisible() && !item->isPanel() && !item->parentItem())
763 q->sendEvent(item, &event);
767 // Update activate state.
769 QEvent event(QEvent::ActivationChange);
770 QApplication::sendEvent(q, &event);
774 QEvent event(QEvent::WindowActivate);
775 q->sendEvent(panel, &event);
777 // Set focus on the panel's focus item.
778 if (QGraphicsItem *focusItem = panel->focusItem())
779 focusItem->setFocus(Qt::ActiveWindowFocusReason);
780 } else if (q->isActive()) {
781 // Activate the scene
782 QEvent event(QEvent::WindowActivate);
783 foreach (QGraphicsItem *item, q->items()) {
784 if (item->isVisible() && !item->isPanel() && !item->parentItem())
785 q->sendEvent(item, &event);
793 void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item,
794 Qt::FocusReason focusReason)
797 if (item == focusItem)
800 // Clear focus if asked to set focus on something that can't
801 // accept input focus.
802 if (item && (!(item->flags() & QGraphicsItem::ItemIsFocusable)
803 || !item->isVisible() || !item->isEnabled())) {
807 // Set focus on the scene if an item requests focus.
809 q->setFocus(focusReason);
810 if (item == focusItem)
815 lastFocusItem = focusItem;
818 if (lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod) {
819 // Close any external input method panel. This happens
820 // automatically by removing WA_InputMethodEnabled on
821 // the views, but if we are changing focus, we have to
824 qApp->inputMethod()->commit();
829 QFocusEvent event(QEvent::FocusOut, focusReason);
830 sendEvent(lastFocusItem, &event);
833 // This handles the case that the item has been removed from the
834 // scene in response to the FocusOut event.
835 if (item && item->scene() != q)
840 updateInputMethodSensitivityInViews();
842 #ifndef QT_NO_ACCESSIBILITY
844 if (QGraphicsObject *focusObj = focusItem->toGraphicsObject()) {
845 QAccessibleEvent event(focusObj, QAccessible::Focus);
846 QAccessible::updateAccessibility(&event);
851 QFocusEvent event(QEvent::FocusIn, focusReason);
852 sendEvent(item, &event);
859 void QGraphicsScenePrivate::addPopup(QGraphicsWidget *widget)
862 Q_ASSERT(!popupWidgets.contains(widget));
863 popupWidgets << widget;
864 if (QGraphicsWidget *focusWidget = widget->focusWidget()) {
865 focusWidget->setFocus(Qt::PopupFocusReason);
867 grabKeyboard((QGraphicsItem *)widget);
868 if (focusItem && popupWidgets.size() == 1) {
869 QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
870 sendEvent(focusItem, &event);
873 grabMouse((QGraphicsItem *)widget);
879 Remove \a widget from the popup list. Important notes:
881 \a widget is guaranteed to be in the list of popups, but it might not be
882 the last entry; you can hide any item in the pop list before the others,
883 and this must cause all later mouse grabbers to lose the grab.
885 void QGraphicsScenePrivate::removePopup(QGraphicsWidget *widget, bool itemIsDying)
888 int index = popupWidgets.indexOf(widget);
889 Q_ASSERT(index != -1);
891 for (int i = popupWidgets.size() - 1; i >= index; --i) {
892 QGraphicsWidget *widget = popupWidgets.takeLast();
893 ungrabMouse(widget, itemIsDying);
894 if (focusItem && popupWidgets.isEmpty()) {
895 QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
896 sendEvent(focusItem, &event);
897 } else if (keyboardGrabberItems.contains(static_cast<QGraphicsItem *>(widget))) {
898 ungrabKeyboard(static_cast<QGraphicsItem *>(widget), itemIsDying);
900 if (!itemIsDying && widget->isVisible()) {
901 widget->QGraphicsItem::d_ptr->setVisibleHelper(false, /* explicit = */ false);
909 void QGraphicsScenePrivate::grabMouse(QGraphicsItem *item, bool implicit)
911 // Append to list of mouse grabber items, and send a mouse grab event.
912 if (mouseGrabberItems.contains(item)) {
913 if (mouseGrabberItems.last() == item) {
915 if (!lastMouseGrabberItemHasImplicitMouseGrab) {
916 qWarning("QGraphicsItem::grabMouse: already a mouse grabber");
918 // Upgrade to an explicit mouse grab
919 lastMouseGrabberItemHasImplicitMouseGrab = false;
922 qWarning("QGraphicsItem::grabMouse: already blocked by mouse grabber: %p",
923 mouseGrabberItems.last());
928 // Send ungrab event to the last grabber.
929 if (!mouseGrabberItems.isEmpty()) {
930 QGraphicsItem *last = mouseGrabberItems.last();
931 if (lastMouseGrabberItemHasImplicitMouseGrab) {
932 // Implicit mouse grab is immediately lost.
935 // Just send ungrab event to current grabber.
936 QEvent ungrabEvent(QEvent::UngrabMouse);
937 sendEvent(last, &ungrabEvent);
941 mouseGrabberItems << item;
942 lastMouseGrabberItemHasImplicitMouseGrab = implicit;
944 // Send grab event to current grabber.
945 QEvent grabEvent(QEvent::GrabMouse);
946 sendEvent(item, &grabEvent);
952 void QGraphicsScenePrivate::ungrabMouse(QGraphicsItem *item, bool itemIsDying)
954 int index = mouseGrabberItems.indexOf(item);
956 qWarning("QGraphicsItem::ungrabMouse: not a mouse grabber");
960 if (item != mouseGrabberItems.last()) {
961 // Recursively ungrab the next mouse grabber until we reach this item
962 // to ensure state consistency.
963 ungrabMouse(mouseGrabberItems.at(index + 1), itemIsDying);
965 if (!popupWidgets.isEmpty() && item == popupWidgets.last()) {
966 // If the item is a popup, go via removePopup to ensure state
967 // consistency and that it gets hidden correctly - beware that
968 // removePopup() reenters this function to continue removing the grab.
969 removePopup((QGraphicsWidget *)item, itemIsDying);
973 // Send notification about mouse ungrab.
975 QEvent event(QEvent::UngrabMouse);
976 sendEvent(item, &event);
979 // Remove the item from the list of grabbers. Whenever this happens, we
980 // reset the implicitGrab (there can be only ever be one implicit grabber
981 // in a scene, and it is always the latest grabber; if the implicit grab
982 // is lost, it is not automatically regained.
983 mouseGrabberItems.takeLast();
984 lastMouseGrabberItemHasImplicitMouseGrab = false;
986 // Send notification about mouse regrab. ### It's unfortunate that all the
987 // items get a GrabMouse event, but this is a rare case with a simple
988 // implementation and it does ensure a consistent state.
989 if (!itemIsDying && !mouseGrabberItems.isEmpty()) {
990 QGraphicsItem *last = mouseGrabberItems.last();
991 QEvent event(QEvent::GrabMouse);
992 sendEvent(last, &event);
999 void QGraphicsScenePrivate::clearMouseGrabber()
1001 if (!mouseGrabberItems.isEmpty())
1002 mouseGrabberItems.first()->ungrabMouse();
1003 lastMouseGrabberItem = 0;
1009 void QGraphicsScenePrivate::grabKeyboard(QGraphicsItem *item)
1011 if (keyboardGrabberItems.contains(item)) {
1012 if (keyboardGrabberItems.last() == item)
1013 qWarning("QGraphicsItem::grabKeyboard: already a keyboard grabber");
1015 qWarning("QGraphicsItem::grabKeyboard: already blocked by keyboard grabber: %p",
1016 keyboardGrabberItems.last());
1020 // Send ungrab event to the last grabber.
1021 if (!keyboardGrabberItems.isEmpty()) {
1022 // Just send ungrab event to current grabber.
1023 QEvent ungrabEvent(QEvent::UngrabKeyboard);
1024 sendEvent(keyboardGrabberItems.last(), &ungrabEvent);
1027 keyboardGrabberItems << item;
1029 // Send grab event to current grabber.
1030 QEvent grabEvent(QEvent::GrabKeyboard);
1031 sendEvent(item, &grabEvent);
1037 void QGraphicsScenePrivate::ungrabKeyboard(QGraphicsItem *item, bool itemIsDying)
1039 int index = keyboardGrabberItems.lastIndexOf(item);
1041 qWarning("QGraphicsItem::ungrabKeyboard: not a keyboard grabber");
1044 if (item != keyboardGrabberItems.last()) {
1045 // Recursively ungrab the topmost keyboard grabber until we reach this
1046 // item to ensure state consistency.
1047 ungrabKeyboard(keyboardGrabberItems.at(index + 1), itemIsDying);
1050 // Send notification about keyboard ungrab.
1052 QEvent event(QEvent::UngrabKeyboard);
1053 sendEvent(item, &event);
1056 // Remove the item from the list of grabbers.
1057 keyboardGrabberItems.takeLast();
1059 // Send notification about mouse regrab.
1060 if (!itemIsDying && !keyboardGrabberItems.isEmpty()) {
1061 QGraphicsItem *last = keyboardGrabberItems.last();
1062 QEvent event(QEvent::GrabKeyboard);
1063 sendEvent(last, &event);
1070 void QGraphicsScenePrivate::clearKeyboardGrabber()
1072 if (!keyboardGrabberItems.isEmpty())
1073 ungrabKeyboard(keyboardGrabberItems.first());
1076 void QGraphicsScenePrivate::enableMouseTrackingOnViews()
1078 foreach (QGraphicsView *view, views)
1079 view->viewport()->setMouseTracking(true);
1083 Returns all items for the screen position in \a event.
1085 QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &screenPos,
1086 const QPointF &scenePos,
1087 QWidget *widget) const
1089 Q_Q(const QGraphicsScene);
1090 QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
1092 return q->items(scenePos, Qt::IntersectsItemShape, Qt::DescendingOrder, QTransform());
1094 const QRectF pointRect(QPointF(widget->mapFromGlobal(screenPos)), QSizeF(1, 1));
1095 if (!view->isTransformed())
1096 return q->items(pointRect, Qt::IntersectsItemShape, Qt::DescendingOrder);
1098 const QTransform viewTransform = view->viewportTransform();
1099 if (viewTransform.type() <= QTransform::TxScale) {
1100 return q->items(viewTransform.inverted().mapRect(pointRect), Qt::IntersectsItemShape,
1101 Qt::DescendingOrder, viewTransform);
1103 return q->items(viewTransform.inverted().map(pointRect), Qt::IntersectsItemShape,
1104 Qt::DescendingOrder, viewTransform);
1110 void QGraphicsScenePrivate::storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event)
1112 for (int i = 0x1; i <= 0x10; i <<= 1) {
1113 if (event->buttons() & i) {
1114 mouseGrabberButtonDownPos.insert(Qt::MouseButton(i),
1115 mouseGrabberItems.last()->d_ptr->genericMapFromScene(event->scenePos(),
1117 mouseGrabberButtonDownScenePos.insert(Qt::MouseButton(i), event->scenePos());
1118 mouseGrabberButtonDownScreenPos.insert(Qt::MouseButton(i), event->screenPos());
1126 void QGraphicsScenePrivate::installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
1128 sceneEventFilters.insert(watched, filter);
1134 void QGraphicsScenePrivate::removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
1136 if (!sceneEventFilters.contains(watched))
1139 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(watched);
1140 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(watched);
1142 if (it.value() == filter)
1143 it = sceneEventFilters.erase(it);
1146 } while (it != end);
1152 bool QGraphicsScenePrivate::filterDescendantEvent(QGraphicsItem *item, QEvent *event)
1154 if (item && (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents)) {
1155 QGraphicsItem *parent = item->parentItem();
1157 if (parent->d_ptr->filtersDescendantEvents && parent->sceneEventFilter(item, event))
1159 if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents))
1161 parent = parent->parentItem();
1170 bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event)
1172 if (item && !sceneEventFilters.contains(item))
1175 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(item);
1176 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(item);
1178 // ### The filterer and filteree might both be deleted.
1179 if (it.value()->sceneEventFilter(it.key(), event))
1189 This is the final dispatch point for any events from the scene to the
1190 item. It filters the event first - if the filter returns true, the event
1191 is considered to have been eaten by the filter, and is therefore stopped
1192 (the default filter returns false). Then/otherwise, if the item is
1193 enabled, the event is sent; otherwise it is stopped.
1195 bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
1197 if (QGraphicsObject *object = item->toGraphicsObject()) {
1198 #ifndef QT_NO_GESTURES
1199 QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
1200 if (gestureManager) {
1201 if (gestureManager->filterEvent(object, event))
1204 #endif // QT_NO_GESTURES
1207 if (filterEvent(item, event))
1209 if (filterDescendantEvent(item, event))
1211 if (!item || !item->isEnabled())
1213 if (QGraphicsObject *o = item->toGraphicsObject()) {
1214 bool spont = event->spontaneous();
1215 if (spont ? qt_sendSpontaneousEvent(o, event) : QApplication::sendEvent(o, event))
1217 event->spont = spont;
1219 return item->sceneEvent(event);
1225 void QGraphicsScenePrivate::cloneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
1226 QGraphicsSceneDragDropEvent *source)
1228 dest->setWidget(source->widget());
1229 dest->setPos(source->pos());
1230 dest->setScenePos(source->scenePos());
1231 dest->setScreenPos(source->screenPos());
1232 dest->setButtons(source->buttons());
1233 dest->setModifiers(source->modifiers());
1234 dest->setPossibleActions(source->possibleActions());
1235 dest->setProposedAction(source->proposedAction());
1236 dest->setDropAction(source->dropAction());
1237 dest->setSource(source->source());
1238 dest->setMimeData(source->mimeData());
1244 void QGraphicsScenePrivate::sendDragDropEvent(QGraphicsItem *item,
1245 QGraphicsSceneDragDropEvent *dragDropEvent)
1247 dragDropEvent->setPos(item->d_ptr->genericMapFromScene(dragDropEvent->scenePos(), dragDropEvent->widget()));
1248 sendEvent(item, dragDropEvent);
1254 void QGraphicsScenePrivate::sendHoverEvent(QEvent::Type type, QGraphicsItem *item,
1255 QGraphicsSceneHoverEvent *hoverEvent)
1257 QGraphicsSceneHoverEvent event(type);
1258 event.setWidget(hoverEvent->widget());
1259 event.setPos(item->d_ptr->genericMapFromScene(hoverEvent->scenePos(), hoverEvent->widget()));
1260 event.setScenePos(hoverEvent->scenePos());
1261 event.setScreenPos(hoverEvent->screenPos());
1262 event.setLastPos(item->d_ptr->genericMapFromScene(hoverEvent->lastScenePos(), hoverEvent->widget()));
1263 event.setLastScenePos(hoverEvent->lastScenePos());
1264 event.setLastScreenPos(hoverEvent->lastScreenPos());
1265 event.setModifiers(hoverEvent->modifiers());
1266 sendEvent(item, &event);
1272 void QGraphicsScenePrivate::sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent)
1274 if (mouseEvent->button() == 0 && mouseEvent->buttons() == 0 && lastMouseGrabberItemHasImplicitMouseGrab) {
1275 // ### This is a temporary fix for until we get proper mouse
1277 clearMouseGrabber();
1281 QGraphicsItem *item = mouseGrabberItems.last();
1282 if (item->isBlockedByModalPanel())
1285 for (int i = 0x1; i <= 0x10; i <<= 1) {
1286 Qt::MouseButton button = Qt::MouseButton(i);
1287 mouseEvent->setButtonDownPos(button, mouseGrabberButtonDownPos.value(button, item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget())));
1288 mouseEvent->setButtonDownScenePos(button, mouseGrabberButtonDownScenePos.value(button, mouseEvent->scenePos()));
1289 mouseEvent->setButtonDownScreenPos(button, mouseGrabberButtonDownScreenPos.value(button, mouseEvent->screenPos()));
1291 mouseEvent->setPos(item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget()));
1292 mouseEvent->setLastPos(item->d_ptr->genericMapFromScene(mouseEvent->lastScenePos(), mouseEvent->widget()));
1293 sendEvent(item, mouseEvent);
1299 void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent)
1301 Q_Q(QGraphicsScene);
1303 // Ignore by default, unless we find a mouse grabber that accepts it.
1304 mouseEvent->ignore();
1306 // Deliver to any existing mouse grabber.
1307 if (!mouseGrabberItems.isEmpty()) {
1308 if (mouseGrabberItems.last()->isBlockedByModalPanel())
1310 // The event is ignored by default, but we disregard the event's
1311 // accepted state after delivery; the mouse is grabbed, after all.
1312 sendMouseEvent(mouseEvent);
1316 // Start by determining the number of items at the current position.
1317 // Reuse value from earlier calculations if possible.
1318 if (cachedItemsUnderMouse.isEmpty()) {
1319 cachedItemsUnderMouse = itemsAtPosition(mouseEvent->screenPos(),
1320 mouseEvent->scenePos(),
1321 mouseEvent->widget());
1324 // Update window activation.
1325 QGraphicsItem *topItem = cachedItemsUnderMouse.value(0);
1326 QGraphicsWidget *newActiveWindow = topItem ? topItem->window() : 0;
1327 if (newActiveWindow && newActiveWindow->isBlockedByModalPanel(&topItem)) {
1328 // pass activation to the blocking modal window
1329 newActiveWindow = topItem ? topItem->window() : 0;
1332 if (newActiveWindow != q->activeWindow())
1333 q->setActiveWindow(newActiveWindow);
1335 // Set focus on the topmost enabled item that can take focus.
1336 bool setFocus = false;
1338 foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
1339 if (item->isBlockedByModalPanel()
1340 || (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling)) {
1341 // Make sure we don't clear focus.
1345 if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable))) {
1346 if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
1348 if (item != q->focusItem() && item->d_ptr->mouseSetsFocus)
1349 q->setFocusItem(item, Qt::MouseFocusReason);
1353 if (item->isPanel())
1355 if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
1359 // Check for scene modality.
1360 bool sceneModality = false;
1361 for (int i = 0; i < modalPanels.size(); ++i) {
1362 if (modalPanels.at(i)->panelModality() == QGraphicsItem::SceneModal) {
1363 sceneModality = true;
1368 // If nobody could take focus, clear it.
1369 if (!stickyFocus && !setFocus && !sceneModality)
1370 q->setFocusItem(0, Qt::MouseFocusReason);
1372 // Any item will do.
1373 if (sceneModality && cachedItemsUnderMouse.isEmpty())
1374 cachedItemsUnderMouse << modalPanels.first();
1376 // Find a mouse grabber by sending mouse press events to all mouse grabber
1377 // candidates one at a time, until the event is accepted. It's accepted by
1378 // default, so the receiver has to explicitly ignore it for it to pass
1380 foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
1381 if (!(item->acceptedMouseButtons() & mouseEvent->button())) {
1382 // Skip items that don't accept the event's mouse button.
1386 // Check if this item is blocked by a modal panel and deliver the mouse event to the
1387 // blocking panel instead of this item if blocked.
1388 (void) item->isBlockedByModalPanel(&item);
1390 grabMouse(item, /* implicit = */ true);
1391 mouseEvent->accept();
1393 // check if the item we are sending to are disabled (before we send the event)
1394 bool disabled = !item->isEnabled();
1395 bool isPanel = item->isPanel();
1396 if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick
1397 && item != lastMouseGrabberItem && lastMouseGrabberItem) {
1398 // If this item is different from the item that received the last
1399 // mouse event, and mouseEvent is a doubleclick event, then the
1400 // event is converted to a press. Known limitation:
1401 // Triple-clicking will not generate a doubleclick, though.
1402 QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
1403 mousePress.spont = mouseEvent->spont;
1404 mousePress.accept();
1405 mousePress.setButton(mouseEvent->button());
1406 mousePress.setButtons(mouseEvent->buttons());
1407 mousePress.setScreenPos(mouseEvent->screenPos());
1408 mousePress.setScenePos(mouseEvent->scenePos());
1409 mousePress.setModifiers(mouseEvent->modifiers());
1410 mousePress.setWidget(mouseEvent->widget());
1411 mousePress.setButtonDownPos(mouseEvent->button(),
1412 mouseEvent->buttonDownPos(mouseEvent->button()));
1413 mousePress.setButtonDownScenePos(mouseEvent->button(),
1414 mouseEvent->buttonDownScenePos(mouseEvent->button()));
1415 mousePress.setButtonDownScreenPos(mouseEvent->button(),
1416 mouseEvent->buttonDownScreenPos(mouseEvent->button()));
1417 sendMouseEvent(&mousePress);
1418 mouseEvent->setAccepted(mousePress.isAccepted());
1420 sendMouseEvent(mouseEvent);
1423 bool dontSendUngrabEvents = mouseGrabberItems.isEmpty() || mouseGrabberItems.last() != item;
1425 ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
1428 if (mouseEvent->isAccepted()) {
1429 if (!mouseGrabberItems.isEmpty())
1430 storeMouseButtonsForMouseGrabber(mouseEvent);
1431 lastMouseGrabberItem = item;
1434 ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
1436 // Don't propagate through panels.
1441 // Is the event still ignored? Then the mouse press goes to the scene.
1442 // Reset the mouse grabber, clear the selection, clear focus, and leave
1443 // the event ignored so that it can propagate through the originating
1445 if (!mouseEvent->isAccepted()) {
1446 clearMouseGrabber();
1448 QGraphicsView *view = mouseEvent->widget() ? qobject_cast<QGraphicsView *>(mouseEvent->widget()->parentWidget()) : 0;
1449 bool dontClearSelection = view && view->dragMode() == QGraphicsView::ScrollHandDrag;
1450 if (!dontClearSelection) {
1451 // Clear the selection if the originating view isn't in scroll
1452 // hand drag mode. The view will clear the selection if no drag
1454 q->clearSelection();
1462 Ensures that the list of toplevels is sorted by insertion order, and that
1463 the siblingIndexes are packed (no gaps), and start at 0.
1465 ### This function is almost identical to
1466 QGraphicsItemPrivate::ensureSequentialSiblingIndex().
1468 void QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes()
1470 if (!topLevelSequentialOrdering) {
1471 qSort(topLevelItems.begin(), topLevelItems.end(), QGraphicsItemPrivate::insertionOrder);
1472 topLevelSequentialOrdering = true;
1473 needSortTopLevelItems = 1;
1475 if (holesInTopLevelSiblingIndex) {
1476 holesInTopLevelSiblingIndex = 0;
1477 for (int i = 0; i < topLevelItems.size(); ++i)
1478 topLevelItems[i]->d_ptr->siblingIndex = i;
1485 Set the font and propagate the changes if the font is different from the
1488 void QGraphicsScenePrivate::setFont_helper(const QFont &font)
1490 if (this->font == font && this->font.resolve() == font.resolve())
1498 Resolve the scene's font against the application font, and propagate the
1499 changes too all items in the scene.
1501 void QGraphicsScenePrivate::resolveFont()
1503 QFont naturalFont = QApplication::font();
1504 naturalFont.resolve(0);
1505 QFont resolvedFont = font.resolve(naturalFont);
1506 updateFont(resolvedFont);
1512 Update the font, and whether or not it has changed, reresolve all fonts in
1515 void QGraphicsScenePrivate::updateFont(const QFont &font)
1517 Q_Q(QGraphicsScene);
1519 // Update local font setting.
1522 // Resolve the fonts of all top-level widget items, or widget items
1523 // whose parent is not a widget.
1524 foreach (QGraphicsItem *item, q->items()) {
1525 if (!item->parentItem()) {
1526 // Resolvefont for an item is a noop operation, but
1527 // every item can be a widget, or can have a widget
1529 item->d_ptr->resolveFont(font.resolve());
1533 // Send the scene a FontChange event.
1534 QEvent event(QEvent::FontChange);
1535 QApplication::sendEvent(q, &event);
1541 Set the palette and propagate the changes if the palette is different from
1542 the current palette.
1544 void QGraphicsScenePrivate::setPalette_helper(const QPalette &palette)
1546 if (this->palette == palette && this->palette.resolve() == palette.resolve())
1548 updatePalette(palette);
1554 Resolve the scene's palette against the application palette, and propagate
1555 the changes too all items in the scene.
1557 void QGraphicsScenePrivate::resolvePalette()
1559 QPalette naturalPalette = QApplication::palette();
1560 naturalPalette.resolve(0);
1561 QPalette resolvedPalette = palette.resolve(naturalPalette);
1562 updatePalette(resolvedPalette);
1568 Update the palette, and whether or not it has changed, reresolve all
1569 palettes in the scene.
1571 void QGraphicsScenePrivate::updatePalette(const QPalette &palette)
1573 Q_Q(QGraphicsScene);
1575 // Update local palette setting.
1576 this->palette = palette;
1578 // Resolve the palettes of all top-level widget items, or widget items
1579 // whose parent is not a widget.
1580 foreach (QGraphicsItem *item, q->items()) {
1581 if (!item->parentItem()) {
1582 // Resolvefont for an item is a noop operation, but
1583 // every item can be a widget, or can have a widget
1585 item->d_ptr->resolvePalette(palette.resolve());
1589 // Send the scene a PaletteChange event.
1590 QEvent event(QEvent::PaletteChange);
1591 QApplication::sendEvent(q, &event);
1595 Constructs a QGraphicsScene object. The \a parent parameter is
1596 passed to QObject's constructor.
1598 QGraphicsScene::QGraphicsScene(QObject *parent)
1599 : QObject(*new QGraphicsScenePrivate, parent)
1605 Constructs a QGraphicsScene object, using \a sceneRect for its
1606 scene rectangle. The \a parent parameter is passed to QObject's
1611 QGraphicsScene::QGraphicsScene(const QRectF &sceneRect, QObject *parent)
1612 : QObject(*new QGraphicsScenePrivate, parent)
1615 setSceneRect(sceneRect);
1619 Constructs a QGraphicsScene object, using the rectangle specified
1620 by (\a x, \a y), and the given \a width and \a height for its
1621 scene rectangle. The \a parent parameter is passed to QObject's
1626 QGraphicsScene::QGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObject *parent)
1627 : QObject(*new QGraphicsScenePrivate, parent)
1630 setSceneRect(x, y, width, height);
1634 Removes and deletes all items from the scene object
1635 before destroying the scene object. The scene object
1636 is removed from the application's global scene list,
1637 and it is removed from all associated views.
1639 QGraphicsScene::~QGraphicsScene()
1641 Q_D(QGraphicsScene);
1643 // Remove this scene from qApp's global scene list.
1644 if (!QApplicationPrivate::is_app_closing)
1645 qApp->d_func()->scene_list.removeAll(this);
1649 // Remove this scene from all associated views.
1650 for (int j = 0; j < d->views.size(); ++j)
1651 d->views.at(j)->setScene(0);
1655 \property QGraphicsScene::sceneRect
1656 \brief the scene rectangle; the bounding rectangle of the scene
1658 The scene rectangle defines the extent of the scene. It is
1659 primarily used by QGraphicsView to determine the view's default
1660 scrollable area, and by QGraphicsScene to manage item indexing.
1662 If unset, or if set to a null QRectF, sceneRect() will return the largest
1663 bounding rect of all items on the scene since the scene was created (i.e.,
1664 a rectangle that grows when items are added to or moved in the scene, but
1667 \sa width(), height(), QGraphicsView::sceneRect
1669 QRectF QGraphicsScene::sceneRect() const
1671 Q_D(const QGraphicsScene);
1672 if (d->hasSceneRect)
1673 return d->sceneRect;
1675 if (d->dirtyGrowingItemsBoundingRect) {
1676 // Lazily update the growing items bounding rect
1677 QGraphicsScenePrivate *thatd = const_cast<QGraphicsScenePrivate *>(d);
1678 QRectF oldGrowingBoundingRect = thatd->growingItemsBoundingRect;
1679 thatd->growingItemsBoundingRect |= itemsBoundingRect();
1680 thatd->dirtyGrowingItemsBoundingRect = false;
1681 if (oldGrowingBoundingRect != thatd->growingItemsBoundingRect)
1682 emit const_cast<QGraphicsScene *>(this)->sceneRectChanged(thatd->growingItemsBoundingRect);
1684 return d->growingItemsBoundingRect;
1686 void QGraphicsScene::setSceneRect(const QRectF &rect)
1688 Q_D(QGraphicsScene);
1689 if (rect != d->sceneRect) {
1690 d->hasSceneRect = !rect.isNull();
1691 d->sceneRect = rect;
1692 emit sceneRectChanged(d->hasSceneRect ? rect : d->growingItemsBoundingRect);
1697 \fn qreal QGraphicsScene::width() const
1699 This convenience function is equivalent to calling sceneRect().width().
1705 \fn qreal QGraphicsScene::height() const
1707 This convenience function is equivalent to calling \c sceneRect().height().
1713 Renders the \a source rect from scene into \a target, using \a painter. This
1714 function is useful for capturing the contents of the scene onto a paint
1715 device, such as a QImage (e.g., to take a screenshot), or for printing
1716 with QPrinter. For example:
1718 \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 1
1720 If \a source is a null rect, this function will use sceneRect() to
1721 determine what to render. If \a target is a null rect, the dimensions of \a
1722 painter's paint device will be used.
1724 The source rect contents will be transformed according to \a
1725 aspectRatioMode to fit into the target rect. By default, the aspect ratio
1726 is kept, and \a source is scaled to fit in \a target.
1728 \sa QGraphicsView::render()
1730 void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRectF &source,
1731 Qt::AspectRatioMode aspectRatioMode)
1733 // ### Switch to using the recursive rendering algorithm instead.
1735 // Default source rect = scene rect
1736 QRectF sourceRect = source;
1737 if (sourceRect.isNull())
1738 sourceRect = sceneRect();
1740 // Default target rect = device rect
1741 QRectF targetRect = target;
1742 if (targetRect.isNull()) {
1743 if (painter->device()->devType() == QInternal::Picture)
1744 targetRect = sourceRect;
1746 targetRect.setRect(0, 0, painter->device()->width(), painter->device()->height());
1749 // Find the ideal x / y scaling ratio to fit \a source into \a target.
1750 qreal xratio = targetRect.width() / sourceRect.width();
1751 qreal yratio = targetRect.height() / sourceRect.height();
1753 // Scale according to the aspect ratio mode.
1754 switch (aspectRatioMode) {
1755 case Qt::KeepAspectRatio:
1756 xratio = yratio = qMin(xratio, yratio);
1758 case Qt::KeepAspectRatioByExpanding:
1759 xratio = yratio = qMax(xratio, yratio);
1761 case Qt::IgnoreAspectRatio:
1765 // Find all items to draw, and reverse the list (we want to draw
1766 // in reverse order).
1767 QList<QGraphicsItem *> itemList = items(sourceRect, Qt::IntersectsItemBoundingRect);
1768 QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
1769 int numItems = itemList.size();
1770 for (int i = 0; i < numItems; ++i)
1771 itemArray[numItems - i - 1] = itemList.at(i);
1776 // Transform the painter.
1777 painter->setClipRect(targetRect, Qt::IntersectClip);
1778 QTransform painterTransform;
1779 painterTransform *= QTransform()
1780 .translate(targetRect.left(), targetRect.top())
1781 .scale(xratio, yratio)
1782 .translate(-sourceRect.left(), -sourceRect.top());
1783 painter->setWorldTransform(painterTransform, true);
1785 // Two unit vectors.
1786 QLineF v1(0, 0, 1, 0);
1787 QLineF v2(0, 0, 0, 1);
1789 // Generate the style options
1790 QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems];
1791 for (int i = 0; i < numItems; ++i)
1792 itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect());
1794 // Render the scene.
1795 drawBackground(painter, sourceRect);
1796 drawItems(painter, numItems, itemArray, styleOptionArray);
1797 drawForeground(painter, sourceRect);
1799 delete [] itemArray;
1800 delete [] styleOptionArray;
1806 \property QGraphicsScene::itemIndexMethod
1807 \brief the item indexing method.
1809 QGraphicsScene applies an indexing algorithm to the scene, to speed up
1810 item discovery functions like items() and itemAt(). Indexing is most
1811 efficient for static scenes (i.e., where items don't move around). For
1812 dynamic scenes, or scenes with many animated items, the index bookkeeping
1813 can outweight the fast lookup speeds.
1815 For the common case, the default index method BspTreeIndex works fine. If
1816 your scene uses many animations and you are experiencing slowness, you can
1817 disable indexing by calling \c setItemIndexMethod(NoIndex).
1821 QGraphicsScene::ItemIndexMethod QGraphicsScene::itemIndexMethod() const
1823 Q_D(const QGraphicsScene);
1824 return d->indexMethod;
1826 void QGraphicsScene::setItemIndexMethod(ItemIndexMethod method)
1828 Q_D(QGraphicsScene);
1829 if (d->indexMethod == method)
1832 d->indexMethod = method;
1834 QList<QGraphicsItem *> oldItems = d->index->items(Qt::DescendingOrder);
1836 if (method == BspTreeIndex)
1837 d->index = new QGraphicsSceneBspTreeIndex(this);
1839 d->index = new QGraphicsSceneLinearIndex(this);
1840 for (int i = oldItems.size() - 1; i >= 0; --i)
1841 d->index->addItem(oldItems.at(i));
1845 \property QGraphicsScene::bspTreeDepth
1846 \brief the depth of QGraphicsScene's BSP index tree
1849 This property has no effect when NoIndex is used.
1851 This value determines the depth of QGraphicsScene's BSP tree. The depth
1852 directly affects QGraphicsScene's performance and memory usage; the latter
1853 growing exponentially with the depth of the tree. With an optimal tree
1854 depth, QGraphicsScene can instantly determine the locality of items, even
1855 for scenes with thousands or millions of items. This also greatly improves
1856 rendering performance.
1858 By default, the value is 0, in which case Qt will guess a reasonable
1859 default depth based on the size, location and number of items in the
1860 scene. If these parameters change frequently, however, you may experience
1861 slowdowns as QGraphicsScene retunes the depth internally. You can avoid
1862 potential slowdowns by fixating the tree depth through setting this
1865 The depth of the tree and the size of the scene rectangle decide the
1866 granularity of the scene's partitioning. The size of each scene segment is
1867 determined by the following algorithm:
1869 \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 2
1871 The BSP tree has an optimal size when each segment contains between 0 and
1876 int QGraphicsScene::bspTreeDepth() const
1878 Q_D(const QGraphicsScene);
1879 QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
1880 return bspTree ? bspTree->bspTreeDepth() : 0;
1882 void QGraphicsScene::setBspTreeDepth(int depth)
1884 Q_D(QGraphicsScene);
1886 qWarning("QGraphicsScene::setBspTreeDepth: invalid depth %d ignored; must be >= 0", depth);
1890 QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
1892 qWarning("QGraphicsScene::setBspTreeDepth: can not apply if indexing method is not BSP");
1895 bspTree->setBspTreeDepth(depth);
1899 \property QGraphicsScene::sortCacheEnabled
1900 \brief whether sort caching is enabled
1904 Since Qt 4.6, this property has no effect.
1906 bool QGraphicsScene::isSortCacheEnabled() const
1908 Q_D(const QGraphicsScene);
1909 return d->sortCacheEnabled;
1911 void QGraphicsScene::setSortCacheEnabled(bool enabled)
1913 Q_D(QGraphicsScene);
1914 if (d->sortCacheEnabled == enabled)
1916 d->sortCacheEnabled = enabled;
1920 Calculates and returns the bounding rect of all items on the scene. This
1921 function works by iterating over all items, and because if this, it can
1922 be slow for large scenes.
1926 QRectF QGraphicsScene::itemsBoundingRect() const
1928 // Does not take untransformable items into account.
1929 QRectF boundingRect;
1930 foreach (QGraphicsItem *item, items())
1931 boundingRect |= item->sceneBoundingRect();
1932 return boundingRect;
1936 Returns an ordered list of all items on the scene. \a order decides the
1939 \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting}
1941 QList<QGraphicsItem *> QGraphicsScene::items(Qt::SortOrder order) const
1943 Q_D(const QGraphicsScene);
1944 return d->index->items(order);
1948 \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const
1952 This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode).
1954 This function is deprecated and returns incorrect results if the scene
1955 contains items that ignore transformations. Use the overload that takes
1956 a QTransform instead.
1960 \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
1964 \brief Returns all visible items that, depending on \a mode, are
1965 either inside or intersect with the rectangle defined by \a x, \a y,
1966 \a w and \a h, in a list sorted using \a order.
1968 \a deviceTransform is the transformation that applies to the view, and needs to
1969 be provided if the scene contains items that ignore transformations.
1973 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
1976 \brief Returns all visible items that, depending on \a mode, are at
1977 the specified \a pos in a list sorted using \a order.
1979 The default value for \a mode is Qt::IntersectsItemShape; all items whose
1980 exact shape intersects with \a pos are returned.
1982 \a deviceTransform is the transformation that applies to the view, and needs to
1983 be provided if the scene contains items that ignore transformations.
1985 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
1987 QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode,
1988 Qt::SortOrder order, const QTransform &deviceTransform) const
1990 Q_D(const QGraphicsScene);
1991 return d->index->items(pos, mode, order, deviceTransform);
1995 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
1999 \brief Returns all visible items that, depending on \a mode, are
2000 either inside or intersect with the specified \a rect and return a
2001 list sorted using \a order.
2003 The default value for \a mode is Qt::IntersectsItemShape; all items whose
2004 exact shape intersects with or is contained by \a rect are returned.
2006 \a deviceTransform is the transformation that applies to the view, and needs to
2007 be provided if the scene contains items that ignore transformations.
2009 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2011 QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode,
2012 Qt::SortOrder order, const QTransform &deviceTransform) const
2014 Q_D(const QGraphicsScene);
2015 return d->index->items(rect, mode, order, deviceTransform);
2019 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
2023 \brief Returns all visible items that, depending on \a mode, are
2024 either inside or intersect with the specified \a polygon and return
2025 a list sorted using \a order.
2027 The default value for \a mode is Qt::IntersectsItemShape; all items whose
2028 exact shape intersects with or is contained by \a polygon are returned.
2030 \a deviceTransform is the transformation that applies to the view, and needs to
2031 be provided if the scene contains items that ignore transformations.
2033 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2035 QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode,
2036 Qt::SortOrder order, const QTransform &deviceTransform) const
2038 Q_D(const QGraphicsScene);
2039 return d->index->items(polygon, mode, order, deviceTransform);
2043 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
2047 \brief Returns all visible items that, depending on \a mode, are
2048 either inside or intersect with the specified \a path and return a
2049 list sorted using \a order.
2051 The default value for \a mode is Qt::IntersectsItemShape; all items whose
2052 exact shape intersects with or is contained by \a path are returned.
2054 \a deviceTransform is the transformation that applies to the view, and needs to
2055 be provided if the scene contains items that ignore transformations.
2057 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2059 QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode,
2060 Qt::SortOrder order, const QTransform &deviceTransform) const
2062 Q_D(const QGraphicsScene);
2063 return d->index->items(path, mode, order, deviceTransform);
2067 Returns a list of all items that collide with \a item. Collisions are
2068 determined by calling QGraphicsItem::collidesWithItem(); the collision
2069 detection is determined by \a mode. By default, all items whose shape
2070 intersects \a item or is contained inside \a item's shape are returned.
2072 The items are returned in descending stacking order (i.e., the first item
2073 in the list is the uppermost item, and the last item is the lowermost
2076 \sa items(), itemAt(), QGraphicsItem::collidesWithItem(), {QGraphicsItem#Sorting}{Sorting}
2078 QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item,
2079 Qt::ItemSelectionMode mode) const
2081 Q_D(const QGraphicsScene);
2083 qWarning("QGraphicsScene::collidingItems: cannot find collisions for null item");
2084 return QList<QGraphicsItem *>();
2087 // Does not support ItemIgnoresTransformations.
2088 QList<QGraphicsItem *> tmp;
2089 foreach (QGraphicsItem *itemInVicinity, d->index->estimateItems(item->sceneBoundingRect(), Qt::DescendingOrder)) {
2090 if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode))
2091 tmp << itemInVicinity;
2097 \fn QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const
2101 Returns the topmost visible item at the specified \a position, or 0 if
2102 there are no items at this position.
2104 This function is deprecated and returns incorrect results if the scene
2105 contains items that ignore transformations. Use the overload that takes
2106 a QTransform instead.
2108 \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
2114 Returns the topmost visible item at the specified \a position, or 0
2115 if there are no items at this position.
2117 \a deviceTransform is the transformation that applies to the view, and needs to
2118 be provided if the scene contains items that ignore transformations.
2120 \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
2122 QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position, const QTransform &deviceTransform) const
2124 QList<QGraphicsItem *> itemsAtPoint = items(position, Qt::IntersectsItemShape,
2125 Qt::DescendingOrder, deviceTransform);
2126 return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
2130 \fn QGraphicsScene::itemAt(qreal x, qreal y, const QTransform &deviceTransform) const
2134 Returns the topmost item at the position specified by (\a x, \a
2135 y), or 0 if there are no items at this position.
2137 \a deviceTransform is the transformation that applies to the view, and needs to
2138 be provided if the scene contains items that ignore transformations.
2140 This convenience function is equivalent to calling \c
2141 {itemAt(QPointF(x, y), deviceTransform)}.
2145 \fn QGraphicsScene::itemAt(qreal x, qreal y) const
2149 Returns the topmost item at the position specified by (\a x, \a
2150 y), or 0 if there are no items at this position.
2152 This convenience function is equivalent to calling \c
2153 {itemAt(QPointF(x, y))}.
2155 This function is deprecated and returns incorrect results if the scene
2156 contains items that ignore transformations. Use the overload that takes
2157 a QTransform instead.
2161 Returns a list of all currently selected items. The items are
2162 returned in no particular order.
2164 \sa setSelectionArea()
2166 QList<QGraphicsItem *> QGraphicsScene::selectedItems() const
2168 Q_D(const QGraphicsScene);
2170 // Optimization: Lazily removes items that are not selected.
2171 QGraphicsScene *that = const_cast<QGraphicsScene *>(this);
2172 QSet<QGraphicsItem *> actuallySelectedSet;
2173 foreach (QGraphicsItem *item, that->d_func()->selectedItems) {
2174 if (item->isSelected())
2175 actuallySelectedSet << item;
2178 that->d_func()->selectedItems = actuallySelectedSet;
2180 return d->selectedItems.values();
2184 Returns the selection area that was previously set with
2185 setSelectionArea(), or an empty QPainterPath if no selection area has been
2188 \sa setSelectionArea()
2190 QPainterPath QGraphicsScene::selectionArea() const
2192 Q_D(const QGraphicsScene);
2193 return d->selectionArea;
2199 Sets the selection area to \a path. All items within this area are
2200 immediately selected, and all items outside are unselected. You can get
2201 the list of all selected items by calling selectedItems().
2203 \a deviceTransform is the transformation that applies to the view, and needs to
2204 be provided if the scene contains items that ignore transformations.
2206 For an item to be selected, it must be marked as \e selectable
2207 (QGraphicsItem::ItemIsSelectable).
2209 \sa clearSelection(), selectionArea()
2211 void QGraphicsScene::setSelectionArea(const QPainterPath &path, const QTransform &deviceTransform)
2213 setSelectionArea(path, Qt::IntersectsItemShape, deviceTransform);
2220 Sets the selection area to \a path using \a mode to determine if items are
2221 included in the selection area.
2223 \a deviceTransform is the transformation that applies to the view, and needs to
2224 be provided if the scene contains items that ignore transformations.
2226 \sa clearSelection(), selectionArea()
2228 void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode,
2229 const QTransform &deviceTransform)
2231 Q_D(QGraphicsScene);
2233 // Note: with boolean path operations, we can improve performance here
2234 // quite a lot by "growing" the old path instead of replacing it. That
2235 // allows us to only check the intersect area for changes, instead of
2236 // reevaluating the whole path over again.
2237 d->selectionArea = path;
2239 QSet<QGraphicsItem *> unselectItems = d->selectedItems;
2241 // Disable emitting selectionChanged() for individual items.
2242 ++d->selectionChanging;
2243 bool changed = false;
2245 // Set all items in path to selected.
2246 foreach (QGraphicsItem *item, items(path, mode, Qt::DescendingOrder, deviceTransform)) {
2247 if (item->flags() & QGraphicsItem::ItemIsSelectable) {
2248 if (!item->isSelected())
2250 unselectItems.remove(item);
2251 item->setSelected(true);
2255 // Unselect all items outside path.
2256 foreach (QGraphicsItem *item, unselectItems) {
2257 item->setSelected(false);
2261 // Reenable emitting selectionChanged() for individual items.
2262 --d->selectionChanging;
2264 if (!d->selectionChanging && changed)
2265 emit selectionChanged();
2269 Clears the current selection.
2271 \sa setSelectionArea(), selectedItems()
2273 void QGraphicsScene::clearSelection()
2275 Q_D(QGraphicsScene);
2277 // Disable emitting selectionChanged
2278 ++d->selectionChanging;
2279 bool changed = !d->selectedItems.isEmpty();
2281 foreach (QGraphicsItem *item, d->selectedItems)
2282 item->setSelected(false);
2283 d->selectedItems.clear();
2285 // Reenable emitting selectionChanged() for individual items.
2286 --d->selectionChanging;
2288 if (!d->selectionChanging && changed)
2289 emit selectionChanged();
2295 Removes and deletes all items from the scene, but otherwise leaves the
2296 state of the scene unchanged.
2300 void QGraphicsScene::clear()
2302 Q_D(QGraphicsScene);
2303 // NB! We have to clear the index before deleting items; otherwise the
2304 // index might try to access dangling item pointers.
2306 // NB! QGraphicsScenePrivate::unregisterTopLevelItem() removes items
2307 while (!d->topLevelItems.isEmpty())
2308 delete d->topLevelItems.first();
2309 Q_ASSERT(d->topLevelItems.isEmpty());
2310 d->lastItemCount = 0;
2311 d->allItemsIgnoreHoverEvents = true;
2312 d->allItemsUseDefaultCursor = true;
2313 d->allItemsIgnoreTouchEvents = true;
2317 Groups all items in \a items into a new QGraphicsItemGroup, and returns a
2318 pointer to the group. The group is created with the common ancestor of \a
2319 items as its parent, and with position (0, 0). The items are all
2320 reparented to the group, and their positions and transformations are
2321 mapped to the group. If \a items is empty, this function will return an
2322 empty top-level QGraphicsItemGroup.
2324 QGraphicsScene has ownership of the group item; you do not need to delete
2325 it. To dismantle (ungroup) a group, call destroyItemGroup().
2327 \sa destroyItemGroup(), QGraphicsItemGroup::addToGroup()
2329 QGraphicsItemGroup *QGraphicsScene::createItemGroup(const QList<QGraphicsItem *> &items)
2331 // Build a list of the first item's ancestors
2332 QList<QGraphicsItem *> ancestors;
2334 if (!items.isEmpty()) {
2335 QGraphicsItem *parent = items.at(n++);
2336 while ((parent = parent->parentItem()))
2337 ancestors.append(parent);
2340 // Find the common ancestor for all items
2341 QGraphicsItem *commonAncestor = 0;
2342 if (!ancestors.isEmpty()) {
2343 while (n < items.size()) {
2344 int commonIndex = -1;
2345 QGraphicsItem *parent = items.at(n++);
2347 int index = ancestors.indexOf(parent, qMax(0, commonIndex));
2349 commonIndex = index;
2352 } while ((parent = parent->parentItem()));
2354 if (commonIndex == -1) {
2359 commonAncestor = ancestors.at(commonIndex);
2363 // Create a new group at that level
2364 QGraphicsItemGroup *group = new QGraphicsItemGroup(commonAncestor);
2365 if (!commonAncestor)
2367 foreach (QGraphicsItem *item, items)
2368 group->addToGroup(item);
2373 Reparents all items in \a group to \a group's parent item, then removes \a
2374 group from the scene, and finally deletes it. The items' positions and
2375 transformations are mapped from the group to the group's parent.
2377 \sa createItemGroup(), QGraphicsItemGroup::removeFromGroup()
2379 void QGraphicsScene::destroyItemGroup(QGraphicsItemGroup *group)
2381 foreach (QGraphicsItem *item, group->children())
2382 group->removeFromGroup(item);
2388 Adds or moves the \a item and all its childen to this scene.
2389 This scene takes ownership of the \a item.
2391 If the item is visible (i.e., QGraphicsItem::isVisible() returns
2392 true), QGraphicsScene will emit changed() once control goes back
2395 If the item is already in a different scene, it will first be
2396 removed from its old scene, and then added to this scene as a
2399 QGraphicsScene will send ItemSceneChange notifications to \a item
2400 while it is added to the scene. If item does not currently belong
2401 to a scene, only one notification is sent. If it does belong to
2402 scene already (i.e., it is moved to this scene), QGraphicsScene
2403 will send an addition notification as the item is removed from its
2406 If the item is a panel, the scene is active, and there is no
2407 active panel in the scene, then the item will be activated.
2409 \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(),
2410 addRect(), addText(), addWidget(), {QGraphicsItem#Sorting}{Sorting}
2412 void QGraphicsScene::addItem(QGraphicsItem *item)
2414 Q_D(QGraphicsScene);
2416 qWarning("QGraphicsScene::addItem: cannot add null item");
2419 if (item->d_ptr->scene == this) {
2420 qWarning("QGraphicsScene::addItem: item has already been added to this scene");
2423 // Remove this item from its existing scene
2424 if (QGraphicsScene *oldScene = item->d_ptr->scene)
2425 oldScene->removeItem(item);
2427 // Notify the item that its scene is changing, and allow the item to
2429 const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
2430 QVariant::fromValue<QGraphicsScene *>(this)));
2431 QGraphicsScene *targetScene = qvariant_cast<QGraphicsScene *>(newSceneVariant);
2432 if (targetScene != this) {
2433 if (targetScene && item->d_ptr->scene != targetScene)
2434 targetScene->addItem(item);
2438 // QDeclarativeItems do not rely on initial itemChanged message, as the componentComplete
2439 // function allows far more opportunity for delayed-construction optimization.
2440 if (!item->d_ptr->isDeclarativeItem) {
2441 if (d->unpolishedItems.isEmpty()) {
2442 QMetaMethod method = metaObject()->method(d->polishItemsIndex);
2443 method.invoke(this, Qt::QueuedConnection);
2445 d->unpolishedItems.append(item);
2446 item->d_ptr->pendingPolish = true;
2449 // Detach this item from its parent if the parent's scene is different
2451 if (QGraphicsItem *itemParent = item->d_ptr->parent) {
2452 if (itemParent->d_ptr->scene != this)
2453 item->setParentItem(0);
2456 // Add the item to this scene
2457 item->d_func()->scene = targetScene;
2459 // Add the item in the index
2460 d->index->addItem(item);
2462 // Add to list of toplevels if this item is a toplevel.
2463 if (!item->d_ptr->parent)
2464 d->registerTopLevelItem(item);
2466 // Add to list of items that require an update. We cannot assume that the
2467 // item is fully constructed, so calling item->update() can lead to a pure
2468 // virtual function call to boundingRect().
2470 d->dirtyGrowingItemsBoundingRect = true;
2472 // Disable selectionChanged() for individual items
2473 ++d->selectionChanging;
2474 int oldSelectedItemSize = d->selectedItems.size();
2476 // Enable mouse tracking if the item accepts hover events or has a cursor set.
2477 if (d->allItemsIgnoreHoverEvents && d->itemAcceptsHoverEvents_helper(item)) {
2478 d->allItemsIgnoreHoverEvents = false;
2479 d->enableMouseTrackingOnViews();
2481 #ifndef QT_NO_CURSOR
2482 if (d->allItemsUseDefaultCursor && item->d_ptr->hasCursor) {
2483 d->allItemsUseDefaultCursor = false;
2484 if (d->allItemsIgnoreHoverEvents) // already enabled otherwise
2485 d->enableMouseTrackingOnViews();
2487 #endif //QT_NO_CURSOR
2489 // Enable touch events if the item accepts touch events.
2490 if (d->allItemsIgnoreTouchEvents && item->d_ptr->acceptTouchEvents) {
2491 d->allItemsIgnoreTouchEvents = false;
2492 d->enableTouchEventsOnViews();
2495 #ifndef QT_NO_GESTURES
2496 foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys())
2497 d->grabGesture(item, gesture);
2500 // Update selection lists
2501 if (item->isSelected())
2502 d->selectedItems << item;
2503 if (item->isWidget() && item->isVisible() && static_cast<QGraphicsWidget *>(item)->windowType() == Qt::Popup)
2504 d->addPopup(static_cast<QGraphicsWidget *>(item));
2505 if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
2506 d->enterModal(item);
2508 // Update creation order focus chain. Make sure to leave the widget's
2509 // internal tab order intact.
2510 if (item->isWidget()) {
2511 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
2512 if (!d->tabFocusFirst) {
2513 // No first tab focus widget - make this the first tab focus
2515 d->tabFocusFirst = widget;
2516 } else if (!widget->parentWidget()) {
2517 // Adding a widget that is not part of a tab focus chain.
2518 QGraphicsWidget *last = d->tabFocusFirst->d_func()->focusPrev;
2519 QGraphicsWidget *lastNew = widget->d_func()->focusPrev;
2520 last->d_func()->focusNext = widget;
2521 widget->d_func()->focusPrev = last;
2522 d->tabFocusFirst->d_func()->focusPrev = lastNew;
2523 lastNew->d_func()->focusNext = d->tabFocusFirst;
2527 // Add all children recursively
2528 item->d_ptr->ensureSortedChildren();
2529 for (int i = 0; i < item->d_ptr->children.size(); ++i)
2530 addItem(item->d_ptr->children.at(i));
2532 // Resolve font and palette.
2533 item->d_ptr->resolveFont(d->font.resolve());
2534 item->d_ptr->resolvePalette(d->palette.resolve());
2537 // Reenable selectionChanged() for individual items
2538 --d->selectionChanging;
2539 if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemSize)
2540 emit selectionChanged();
2542 // Deliver post-change notification
2543 item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
2545 // Update explicit activation
2546 bool autoActivate = true;
2547 if (!d->childExplicitActivation && item->d_ptr->explicitActivate)
2548 d->childExplicitActivation = item->d_ptr->wantsActive ? 1 : 2;
2549 if (d->childExplicitActivation && item->isPanel()) {
2550 if (d->childExplicitActivation == 1)
2551 setActivePanel(item);
2553 autoActivate = false;
2554 d->childExplicitActivation = 0;
2555 } else if (!item->d_ptr->parent) {
2556 d->childExplicitActivation = 0;
2559 // Auto-activate this item's panel if nothing else has been activated
2561 if (!d->lastActivePanel && !d->activePanel && item->isPanel()) {
2563 setActivePanel(item);
2565 d->lastActivePanel = item;
2569 if (item->d_ptr->flags & QGraphicsItem::ItemSendsScenePositionChanges)
2570 d->registerScenePosItem(item);
2572 // Ensure that newly added items that have subfocus set, gain
2573 // focus automatically if there isn't a focus item already.
2574 if (!d->focusItem && item != d->lastFocusItem && item->focusItem() == item)
2575 item->focusItem()->setFocus();
2577 d->updateInputMethodSensitivityInViews();
2581 Creates and adds an ellipse item to the scene, and returns the item
2582 pointer. The geometry of the ellipse is defined by \a rect, and its pen
2583 and brush are initialized to \a pen and \a brush.
2585 Note that the item's geometry is provided in item coordinates, and its
2586 position is initialized to (0, 0).
2588 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2589 QGraphicsScene will emit changed() once control goes back to the event
2592 \sa addLine(), addPath(), addPixmap(), addRect(), addText(), addItem(),
2595 QGraphicsEllipseItem *QGraphicsScene::addEllipse(const QRectF &rect, const QPen &pen, const QBrush &brush)
2597 QGraphicsEllipseItem *item = new QGraphicsEllipseItem(rect);
2599 item->setBrush(brush);
2605 \fn QGraphicsEllipseItem *QGraphicsScene::addEllipse(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
2608 This convenience function is equivalent to calling addEllipse(QRectF(\a x,
2609 \a y, \a w, \a h), \a pen, \a brush).
2613 Creates and adds a line item to the scene, and returns the item
2614 pointer. The geometry of the line is defined by \a line, and its pen
2615 is initialized to \a pen.
2617 Note that the item's geometry is provided in item coordinates, and its
2618 position is initialized to (0, 0).
2620 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2621 QGraphicsScene will emit changed() once control goes back to the event
2624 \sa addEllipse(), addPath(), addPixmap(), addRect(), addText(), addItem(),
2627 QGraphicsLineItem *QGraphicsScene::addLine(const QLineF &line, const QPen &pen)
2629 QGraphicsLineItem *item = new QGraphicsLineItem(line);
2636 \fn QGraphicsLineItem *QGraphicsScene::addLine(qreal x1, qreal y1, qreal x2, qreal y2, const QPen &pen)
2639 This convenience function is equivalent to calling addLine(QLineF(\a x1,
2640 \a y1, \a x2, \a y2), \a pen).
2644 Creates and adds a path item to the scene, and returns the item
2645 pointer. The geometry of the path is defined by \a path, and its pen and
2646 brush are initialized to \a pen and \a brush.
2648 Note that the item's geometry is provided in item coordinates, and its
2649 position is initialized to (0, 0).
2651 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2652 QGraphicsScene will emit changed() once control goes back to the event
2655 \sa addEllipse(), addLine(), addPixmap(), addRect(), addText(), addItem(),
2658 QGraphicsPathItem *QGraphicsScene::addPath(const QPainterPath &path, const QPen &pen, const QBrush &brush)
2660 QGraphicsPathItem *item = new QGraphicsPathItem(path);
2662 item->setBrush(brush);
2668 Creates and adds a pixmap item to the scene, and returns the item
2669 pointer. The pixmap is defined by \a pixmap.
2671 Note that the item's geometry is provided in item coordinates, and its
2672 position is initialized to (0, 0).
2674 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2675 QGraphicsScene will emit changed() once control goes back to the event
2678 \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
2681 QGraphicsPixmapItem *QGraphicsScene::addPixmap(const QPixmap &pixmap)
2683 QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
2689 Creates and adds a polygon item to the scene, and returns the item
2690 pointer. The polygon is defined by \a polygon, and its pen and
2691 brush are initialized to \a pen and \a brush.
2693 Note that the item's geometry is provided in item coordinates, and its
2694 position is initialized to (0, 0).
2696 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2697 QGraphicsScene will emit changed() once control goes back to the event
2700 \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
2703 QGraphicsPolygonItem *QGraphicsScene::addPolygon(const QPolygonF &polygon,
2704 const QPen &pen, const QBrush &brush)
2706 QGraphicsPolygonItem *item = new QGraphicsPolygonItem(polygon);
2708 item->setBrush(brush);
2714 Creates and adds a rectangle item to the scene, and returns the item
2715 pointer. The geometry of the rectangle is defined by \a rect, and its pen
2716 and brush are initialized to \a pen and \a brush.
2718 Note that the item's geometry is provided in item coordinates, and its
2719 position is initialized to (0, 0). For example, if a QRect(50, 50, 100,
2720 100) is added, its top-left corner will be at (50, 50) relative to the
2721 origin in the items coordinate system.
2723 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2724 QGraphicsScene will emit changed() once control goes back to the event
2727 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addText(),
2728 addItem(), addWidget()
2730 QGraphicsRectItem *QGraphicsScene::addRect(const QRectF &rect, const QPen &pen, const QBrush &brush)
2732 QGraphicsRectItem *item = new QGraphicsRectItem(rect);
2734 item->setBrush(brush);
2740 \fn QGraphicsRectItem *QGraphicsScene::addRect(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
2743 This convenience function is equivalent to calling addRect(QRectF(\a x,
2744 \a y, \a w, \a h), \a pen, \a brush).
2748 Creates and adds a text item to the scene, and returns the item
2749 pointer. The text string is initialized to \a text, and its font
2750 is initialized to \a font.
2752 The item's position is initialized to (0, 0).
2754 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2755 QGraphicsScene will emit changed() once control goes back to the event
2758 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
2759 addItem(), addWidget()
2761 QGraphicsTextItem *QGraphicsScene::addText(const QString &text, const QFont &font)
2763 QGraphicsTextItem *item = new QGraphicsTextItem(text);
2764 item->setFont(font);
2770 Creates and adds a QGraphicsSimpleTextItem to the scene, and returns the
2771 item pointer. The text string is initialized to \a text, and its font is
2772 initialized to \a font.
2774 The item's position is initialized to (0, 0).
2776 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2777 QGraphicsScene will emit changed() once control goes back to the event
2780 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
2781 addItem(), addWidget()
2783 QGraphicsSimpleTextItem *QGraphicsScene::addSimpleText(const QString &text, const QFont &font)
2785 QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem(text);
2786 item->setFont(font);
2792 Creates a new QGraphicsProxyWidget for \a widget, adds it to the scene,
2793 and returns a pointer to the proxy. \a wFlags set the default window flags
2794 for the embedding proxy widget.
2796 The item's position is initialized to (0, 0).
2798 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2799 QGraphicsScene will emit changed() once control goes back to the event
2802 Note that widgets with the Qt::WA_PaintOnScreen widget attribute
2803 set and widgets that wrap an external application or controller
2804 are not supported. Examples are QGLWidget and QAxWidget.
2806 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
2807 addText(), addSimpleText(), addItem()
2809 QGraphicsProxyWidget *QGraphicsScene::addWidget(QWidget *widget, Qt::WindowFlags wFlags)
2811 QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(0, wFlags);
2812 proxy->setWidget(widget);
2818 Removes the item \a item and all its children from the scene. The
2819 ownership of \a item is passed on to the caller (i.e.,
2820 QGraphicsScene will no longer delete \a item when destroyed).
2824 void QGraphicsScene::removeItem(QGraphicsItem *item)
2826 // ### Refactoring: This function shares much functionality with _q_removeItemLater()
2827 Q_D(QGraphicsScene);
2829 qWarning("QGraphicsScene::removeItem: cannot remove 0-item");
2832 if (item->scene() != this) {
2833 qWarning("QGraphicsScene::removeItem: item %p's scene (%p)"
2834 " is different from this scene (%p)",
2835 item, item->scene(), this);
2839 // Notify the item that it's scene is changing to 0, allowing the item to
2841 const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
2842 QVariant::fromValue<QGraphicsScene *>(0)));
2843 QGraphicsScene *targetScene = qvariant_cast<QGraphicsScene *>(newSceneVariant);
2844 if (targetScene != 0 && targetScene != this) {
2845 targetScene->addItem(item);
2849 d->removeItemHelper(item);
2851 // Deliver post-change notification
2852 item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
2854 d->updateInputMethodSensitivityInViews();
2858 When the scene is active, this functions returns the scene's current focus
2859 item, or 0 if no item currently has focus. When the scene is inactive, this
2860 functions returns the item that will gain input focus when the scene becomes
2863 The focus item receives keyboard input when the scene receives a
2866 \sa setFocusItem(), QGraphicsItem::hasFocus(), isActive()
2868 QGraphicsItem *QGraphicsScene::focusItem() const
2870 Q_D(const QGraphicsScene);
2871 return isActive() ? d->focusItem : d->passiveFocusItem;
2875 Sets the scene's focus item to \a item, with the focus reason \a
2876 focusReason, after removing focus from any previous item that may have had
2879 If \a item is 0, or if it either does not accept focus (i.e., it does not
2880 have the QGraphicsItem::ItemIsFocusable flag enabled), or is not visible
2881 or not enabled, this function only removes focus from any previous
2884 If item is not 0, and the scene does not currently have focus (i.e.,
2885 hasFocus() returns false), this function will call setFocus()
2888 \sa focusItem(), hasFocus(), setFocus()
2890 void QGraphicsScene::setFocusItem(QGraphicsItem *item, Qt::FocusReason focusReason)
2892 Q_D(QGraphicsScene);
2894 item->setFocus(focusReason);
2896 d->setFocusItemHelper(item, focusReason);
2900 Returns true if the scene has focus; otherwise returns false. If the scene
2901 has focus, it will will forward key events from QKeyEvent to any item that
2904 \sa setFocus(), setFocusItem()
2906 bool QGraphicsScene::hasFocus() const
2908 Q_D(const QGraphicsScene);
2913 Sets focus on the scene by sending a QFocusEvent to the scene, passing \a
2914 focusReason as the reason. If the scene regains focus after having
2915 previously lost it while an item had focus, the last focus item will
2916 receive focus with \a focusReason as the reason.
2918 If the scene already has focus, this function does nothing.
2920 \sa hasFocus(), clearFocus(), setFocusItem()
2922 void QGraphicsScene::setFocus(Qt::FocusReason focusReason)
2924 Q_D(QGraphicsScene);
2925 if (d->hasFocus || !isActive())
2927 QFocusEvent event(QEvent::FocusIn, focusReason);
2928 QCoreApplication::sendEvent(this, &event);
2932 Clears focus from the scene. If any item has focus when this function is
2933 called, it will lose focus, and regain focus again once the scene regains
2936 A scene that does not have focus ignores key events.
2938 \sa hasFocus(), setFocus(), setFocusItem()
2940 void QGraphicsScene::clearFocus()
2942 Q_D(QGraphicsScene);
2944 d->hasFocus = false;
2945 d->passiveFocusItem = d->focusItem;
2946 setFocusItem(0, Qt::OtherFocusReason);
2951 \property QGraphicsScene::stickyFocus
2952 \brief whether clicking into the scene background will clear focus
2956 In a QGraphicsScene with stickyFocus set to true, focus will remain
2957 unchanged when the user clicks into the scene background or on an item
2958 that does not accept focus. Otherwise, focus will be cleared.
2960 By default, this property is false.
2962 Focus changes in response to a mouse press. You can reimplement
2963 mousePressEvent() in a subclass of QGraphicsScene to toggle this property
2964 based on where the user has clicked.
2966 \sa clearFocus(), setFocusItem()
2968 void QGraphicsScene::setStickyFocus(bool enabled)
2970 Q_D(QGraphicsScene);
2971 d->stickyFocus = enabled;
2973 bool QGraphicsScene::stickyFocus() const
2975 Q_D(const QGraphicsScene);
2976 return d->stickyFocus;
2980 Returns the current mouse grabber item, or 0 if no item is currently
2981 grabbing the mouse. The mouse grabber item is the item that receives all
2982 mouse events sent to the scene.
2984 An item becomes a mouse grabber when it receives and accepts a
2985 mouse press event, and it stays the mouse grabber until either of
2986 the following events occur:
2989 \li If the item receives a mouse release event when there are no other
2990 buttons pressed, it loses the mouse grab.
2991 \li If the item becomes invisible (i.e., someone calls \c {item->setVisible(false)}),
2992 or if it becomes disabled (i.e., someone calls \c {item->setEnabled(false)}),
2993 it loses the mouse grab.
2994 \li If the item is removed from the scene, it loses the mouse grab.
2997 If the item loses its mouse grab, the scene will ignore all mouse events
2998 until a new item grabs the mouse (i.e., until a new item receives a mouse
3001 QGraphicsItem *QGraphicsScene::mouseGrabberItem() const
3003 Q_D(const QGraphicsScene);
3004 return !d->mouseGrabberItems.isEmpty() ? d->mouseGrabberItems.last() : 0;
3008 \property QGraphicsScene::backgroundBrush
3009 \brief the background brush of the scene.
3011 Set this property to changes the scene's background to a different color,
3012 gradient or texture. The default background brush is Qt::NoBrush. The
3013 background is drawn before (behind) the items.
3017 \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 3
3019 QGraphicsScene::render() calls drawBackground() to draw the scene
3020 background. For more detailed control over how the background is drawn,
3021 you can reimplement drawBackground() in a subclass of QGraphicsScene.
3023 QBrush QGraphicsScene::backgroundBrush() const
3025 Q_D(const QGraphicsScene);
3026 return d->backgroundBrush;
3028 void QGraphicsScene::setBackgroundBrush(const QBrush &brush)
3030 Q_D(QGraphicsScene);
3031 d->backgroundBrush = brush;
3032 foreach (QGraphicsView *view, d->views) {
3033 view->resetCachedContent();
3034 view->viewport()->update();
3040 \property QGraphicsScene::foregroundBrush
3041 \brief the foreground brush of the scene.
3043 Change this property to set the scene's foreground to a different
3044 color, gradient or texture.
3046 The foreground is drawn after (on top of) the items. The default
3047 foreground brush is Qt::NoBrush ( i.e. the foreground is not
3052 \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 4
3054 QGraphicsScene::render() calls drawForeground() to draw the scene
3055 foreground. For more detailed control over how the foreground is
3056 drawn, you can reimplement the drawForeground() function in a
3057 QGraphicsScene subclass.
3059 QBrush QGraphicsScene::foregroundBrush() const
3061 Q_D(const QGraphicsScene);
3062 return d->foregroundBrush;
3064 void QGraphicsScene::setForegroundBrush(const QBrush &brush)
3066 Q_D(QGraphicsScene);
3067 d->foregroundBrush = brush;
3068 foreach (QGraphicsView *view, views())
3069 view->viewport()->update();
3074 This method is used by input methods to query a set of properties of
3075 the scene to be able to support complex input method operations as support
3076 for surrounding text and reconversions.
3078 The \a query parameter specifies which property is queried.
3080 \sa QWidget::inputMethodQuery()
3082 QVariant QGraphicsScene::inputMethodQuery(Qt::InputMethodQuery query) const
3084 Q_D(const QGraphicsScene);
3085 if (!d->focusItem || !(d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
3087 const QTransform matrix = d->focusItem->sceneTransform();
3088 QVariant value = d->focusItem->inputMethodQuery(query);
3089 if (value.type() == QVariant::RectF)
3090 value = matrix.mapRect(value.toRectF());
3091 else if (value.type() == QVariant::PointF)
3092 value = matrix.map(value.toPointF());
3093 else if (value.type() == QVariant::Rect)
3094 value = matrix.mapRect(value.toRect());
3095 else if (value.type() == QVariant::Point)
3096 value = matrix.map(value.toPoint());
3101 \fn void QGraphicsScene::update(const QRectF &rect)
3102 Schedules a redraw of the area \a rect on the scene.
3104 \sa sceneRect(), changed()
3106 void QGraphicsScene::update(const QRectF &rect)
3108 Q_D(QGraphicsScene);
3109 if (d->updateAll || (rect.isEmpty() && !rect.isNull()))
3112 // Check if anyone's connected; if not, we can send updates directly to
3113 // the views. Otherwise or if there are no views, use old behavior.
3114 bool directUpdates = !(d->isSignalConnected(d->changedSignalIndex)) && !d->views.isEmpty();
3115 if (rect.isNull()) {
3116 d->updateAll = true;
3117 d->updatedRects.clear();
3118 if (directUpdates) {
3119 // Update all views.
3120 for (int i = 0; i < d->views.size(); ++i)
3121 d->views.at(i)->d_func()->fullUpdatePending = true;
3124 if (directUpdates) {
3125 // Update all views.
3126 for (int i = 0; i < d->views.size(); ++i) {
3127 QGraphicsView *view = d->views.at(i);
3128 if (view->isTransformed())
3129 view->d_func()->updateRectF(view->viewportTransform().mapRect(rect));
3131 view->d_func()->updateRectF(rect);
3134 d->updatedRects << rect;
3138 if (!d->calledEmitUpdated) {
3139 d->calledEmitUpdated = true;
3140 QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection);
3145 \fn void QGraphicsScene::update(qreal x, qreal y, qreal w, qreal h)
3149 This function is equivalent to calling update(QRectF(\a x, \a y, \a w,
3154 Invalidates and schedules a redraw of the \a layers in \a rect on the
3155 scene. Any cached content in \a layers is unconditionally invalidated and
3158 You can use this function overload to notify QGraphicsScene of changes to
3159 the background or the foreground of the scene. This function is commonly
3160 used for scenes with tile-based backgrounds to notify changes when
3161 QGraphicsView has enabled
3162 \l{QGraphicsView::CacheBackground}{CacheBackground}.
3166 \snippet code/src_gui_graphicsview_qgraphicsscene.cpp 5
3168 Note that QGraphicsView currently supports background caching only (see
3169 QGraphicsView::CacheBackground). This function is equivalent to calling
3170 update() if any layer but BackgroundLayer is passed.
3172 \sa QGraphicsView::resetCachedContent()
3174 void QGraphicsScene::invalidate(const QRectF &rect, SceneLayers layers)
3176 foreach (QGraphicsView *view, views())
3177 view->invalidateScene(rect, layers);
3182 \fn void QGraphicsScene::invalidate(qreal x, qreal y, qreal w, qreal h, SceneLayers layers)
3186 This convenience function is equivalent to calling invalidate(QRectF(\a x, \a
3187 y, \a w, \a h), \a layers);
3191 Returns a list of all the views that display this scene.
3193 \sa QGraphicsView::scene()
3195 QList <QGraphicsView *> QGraphicsScene::views() const
3197 Q_D(const QGraphicsScene);
3202 This slot \e advances the scene by one step, by calling
3203 QGraphicsItem::advance() for all items on the scene. This is done in two
3204 phases: in the first phase, all items are notified that the scene is about
3205 to change, and in the second phase all items are notified that they can
3206 move. In the first phase, QGraphicsItem::advance() is called passing a
3207 value of 0 as an argument, and 1 is passed in the second phase.
3209 \sa QGraphicsItem::advance(), QGraphicsItemAnimation, QTimeLine
3211 void QGraphicsScene::advance()
3213 for (int i = 0; i < 2; ++i) {
3214 foreach (QGraphicsItem *item, items())
3220 Processes the event \a event, and dispatches it to the respective
3223 In addition to calling the convenience event handlers, this
3224 function is responsible for converting mouse move events to hover
3225 events for when there is no mouse grabber item. Hover events are
3226 delivered directly to items; there is no convenience function for
3229 Unlike QWidget, QGraphicsScene does not have the convenience functions
3230 \l{QWidget::}{enterEvent()} and \l{QWidget::}{leaveEvent()}. Use this
3231 function to obtain those events instead.
3233 \sa contextMenuEvent(), keyPressEvent(), keyReleaseEvent(),
3234 mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(),
3235 mouseDoubleClickEvent(), focusInEvent(), focusOutEvent()
3237 bool QGraphicsScene::event(QEvent *event)
3239 Q_D(QGraphicsScene);
3241 switch (event->type()) {
3242 case QEvent::GraphicsSceneMousePress:
3243 case QEvent::GraphicsSceneMouseMove:
3244 case QEvent::GraphicsSceneMouseRelease:
3245 case QEvent::GraphicsSceneMouseDoubleClick:
3246 case QEvent::GraphicsSceneHoverEnter:
3247 case QEvent::GraphicsSceneHoverLeave:
3248 case QEvent::GraphicsSceneHoverMove:
3249 case QEvent::TouchBegin:
3250 case QEvent::TouchUpdate:
3251 case QEvent::TouchEnd:
3252 // Reset the under-mouse list to ensure that this event gets fresh
3253 // item-under-mouse data. Be careful about this list; if people delete
3254 // items from inside event handlers, this list can quickly end up
3255 // having stale pointers in it. We need to clear it before dispatching
3256 // events that use it.
3257 // ### this should only be cleared if we received a new mouse move event,
3258 // which relies on us fixing the replay mechanism in QGraphicsView.
3259 d->cachedItemsUnderMouse.clear();
3264 switch (event->type()) {
3265 case QEvent::GraphicsSceneDragEnter:
3266 dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3268 case QEvent::GraphicsSceneDragMove:
3269 dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3271 case QEvent::GraphicsSceneDragLeave:
3272 dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3274 case QEvent::GraphicsSceneDrop:
3275 dropEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3277 case QEvent::GraphicsSceneContextMenu:
3278 contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent *>(event));
3280 case QEvent::KeyPress:
3281 if (!d->focusItem) {
3282 QKeyEvent *k = static_cast<QKeyEvent *>(event);
3283 if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
3284 if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
3286 if (k->key() == Qt::Key_Backtab
3287 || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) {
3288 res = focusNextPrevChild(false);
3289 } else if (k->key() == Qt::Key_Tab) {
3290 res = focusNextPrevChild(true);
3298 keyPressEvent(static_cast<QKeyEvent *>(event));
3300 case QEvent::KeyRelease:
3301 keyReleaseEvent(static_cast<QKeyEvent *>(event));
3303 case QEvent::ShortcutOverride: {
3304 QGraphicsItem *parent = focusItem();
3306 d->sendEvent(parent, event);
3307 if (event->isAccepted())
3309 parent = parent->parentItem();
3313 case QEvent::GraphicsSceneMouseMove:
3315 QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent *>(event);
3316 d->lastSceneMousePos = mouseEvent->scenePos();
3317 mouseMoveEvent(mouseEvent);
3320 case QEvent::GraphicsSceneMousePress:
3321 mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3323 case QEvent::GraphicsSceneMouseRelease:
3324 mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3326 case QEvent::GraphicsSceneMouseDoubleClick:
3327 mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3329 case QEvent::GraphicsSceneWheel:
3330 wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event));
3332 case QEvent::FocusIn:
3333 focusInEvent(static_cast<QFocusEvent *>(event));
3335 case QEvent::FocusOut:
3336 focusOutEvent(static_cast<QFocusEvent *>(event));
3338 case QEvent::GraphicsSceneHoverEnter:
3339 case QEvent::GraphicsSceneHoverLeave:
3340 case QEvent::GraphicsSceneHoverMove:
3342 QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event);
3343 d->lastSceneMousePos = hoverEvent->scenePos();
3344 d->dispatchHoverEvent(hoverEvent);
3348 // hackieshly unpacking the viewport pointer from the leave event.
3349 d->leaveScene(reinterpret_cast<QWidget *>(event->d));
3351 case QEvent::GraphicsSceneHelp:
3352 helpEvent(static_cast<QGraphicsSceneHelpEvent *>(event));
3354 case QEvent::InputMethod:
3355 inputMethodEvent(static_cast<QInputMethodEvent *>(event));
3357 case QEvent::WindowActivate:
3358 if (!d->activationRefCount++) {
3359 if (d->lastActivePanel) {
3360 // Activate the last panel.
3361 d->setActivePanelHelper(d->lastActivePanel, true);
3362 } else if (d->tabFocusFirst && d->tabFocusFirst->isPanel()) {
3363 // Activate the panel of the first item in the tab focus
3365 d->setActivePanelHelper(d->tabFocusFirst, true);
3367 // Activate all toplevel items.
3368 QEvent event(QEvent::WindowActivate);
3369 foreach (QGraphicsItem *item, items()) {
3370 if (item->isVisible() && !item->isPanel() && !item->parentItem())
3371 sendEvent(item, &event);
3376 case QEvent::WindowDeactivate:
3377 if (!--d->activationRefCount) {
3378 if (d->activePanel) {
3379 // Deactivate the active panel (but keep it so we can
3380 // reactivate it later).
3381 QGraphicsItem *lastActivePanel = d->activePanel;
3382 d->setActivePanelHelper(0, true);
3383 d->lastActivePanel = lastActivePanel;
3385 // Activate all toplevel items.
3386 QEvent event(QEvent::WindowDeactivate);
3387 foreach (QGraphicsItem *item, items()) {
3388 if (item->isVisible() && !item->isPanel() && !item->parentItem())
3389 sendEvent(item, &event);
3394 case QEvent::ApplicationFontChange: {
3395 // Resolve the existing scene font.
3399 case QEvent::FontChange:
3400 // Update the entire scene when the font changes.
3403 case QEvent::ApplicationPaletteChange: {
3404 // Resolve the existing scene palette.
3405 d->resolvePalette();
3408 case QEvent::PaletteChange:
3409 // Update the entire scene when the palette changes.
3412 case QEvent::StyleChange:
3413 // Reresolve all widgets' styles. Update all top-level widgets'
3414 // geometries that do not have an explicit style set.
3417 case QEvent::TouchBegin:
3418 case QEvent::TouchUpdate:
3419 case QEvent::TouchEnd:
3420 d->touchEventHandler(static_cast<QTouchEvent *>(event));
3422 #ifndef QT_NO_GESTURES
3423 case QEvent::Gesture:
3424 case QEvent::GestureOverride:
3425 d->gestureEventHandler(static_cast<QGestureEvent *>(event));
3427 #endif // QT_NO_GESTURES
3429 return QObject::event(event);
3437 QGraphicsScene filters QApplication's events to detect palette and font
3440 bool QGraphicsScene::eventFilter(QObject *watched, QEvent *event)
3442 if (watched != qApp)
3445 switch (event->type()) {
3446 case QEvent::ApplicationPaletteChange:
3447 QApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
3449 case QEvent::ApplicationFontChange:
3450 QApplication::postEvent(this, new QEvent(QEvent::ApplicationFontChange));
3459 This event handler, for event \a contextMenuEvent, can be reimplemented in
3460 a subclass to receive context menu events. The default implementation
3461 forwards the event to the topmost item that accepts context menu events at
3462 the position of the event. If no items accept context menu events at this
3463 position, the event is ignored.
3465 \sa QGraphicsItem::contextMenuEvent()
3467 void QGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *contextMenuEvent)
3469 Q_D(QGraphicsScene);
3470 // Ignore by default.
3471 contextMenuEvent->ignore();
3473 // Send the event to all items at this position until one item accepts the
3475 foreach (QGraphicsItem *item, d->itemsAtPosition(contextMenuEvent->screenPos(),
3476 contextMenuEvent->scenePos(),
3477 contextMenuEvent->widget())) {
3478 contextMenuEvent->setPos(item->d_ptr->genericMapFromScene(contextMenuEvent->scenePos(),
3479 contextMenuEvent->widget()));
3480 contextMenuEvent->accept();
3481 if (!d->sendEvent(item, contextMenuEvent))
3484 if (contextMenuEvent->isAccepted())
3490 This event handler, for event \a event, can be reimplemented in a subclass
3491 to receive drag enter events for the scene.
3493 The default implementation accepts the event and prepares the scene to
3494 accept drag move events.
3496 \sa QGraphicsItem::dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(),
3499 void QGraphicsScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
3501 Q_D(QGraphicsScene);
3502 d->dragDropItem = 0;
3503 d->lastDropAction = Qt::IgnoreAction;
3508 This event handler, for event \a event, can be reimplemented in a subclass
3509 to receive drag move events for the scene.
3511 \sa QGraphicsItem::dragMoveEvent(), dragEnterEvent(), dragLeaveEvent(),
3514 void QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
3516 Q_D(QGraphicsScene);
3519 if (!d->mouseGrabberItems.isEmpty()) {
3520 // Mouse grabbers that start drag events lose the mouse grab.
3521 d->clearMouseGrabber();
3522 d->mouseGrabberButtonDownPos.clear();
3523 d->mouseGrabberButtonDownScenePos.clear();
3524 d->mouseGrabberButtonDownScreenPos.clear();
3527 bool eventDelivered = false;
3529 // Find the topmost enabled items under the cursor. They are all
3530 // candidates for accepting drag & drop events.
3531 foreach (QGraphicsItem *item, d->itemsAtPosition(event->screenPos(),
3534 if (!item->isEnabled() || !item->acceptDrops())
3537 if (item != d->dragDropItem) {
3538 // Enter the new drag drop item. If it accepts the event, we send
3539 // the leave to the parent item.
3540 QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);
3541 d->cloneDragDropEvent(&dragEnter, event);
3542 dragEnter.setDropAction(event->proposedAction());
3543 d->sendDragDropEvent(item, &dragEnter);
3544 event->setAccepted(dragEnter.isAccepted());
3545 event->setDropAction(dragEnter.dropAction());
3546 if (!event->isAccepted()) {
3547 // Propagate to the item under
3551 d->lastDropAction = event->dropAction();
3553 if (d->dragDropItem) {
3554 // Leave the last drag drop item. A perfect implementation
3555 // would set the position of this event to the point where
3556 // this event and the last event intersect with the item's
3557 // shape, but that's not easy to do. :-)
3558 QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
3559 d->cloneDragDropEvent(&dragLeave, event);
3560 d->sendDragDropEvent(d->dragDropItem, &dragLeave);
3563 // We've got a new drag & drop item
3564 d->dragDropItem = item;
3567 // Send the move event.
3568 event->setDropAction(d->lastDropAction);
3570 d->sendDragDropEvent(item, event);
3571 if (event->isAccepted())
3572 d->lastDropAction = event->dropAction();
3573 eventDelivered = true;
3577 if (!eventDelivered) {
3578 if (d->dragDropItem) {
3579 // Leave the last drag drop item
3580 QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
3581 d->cloneDragDropEvent(&dragLeave, event);
3582 d->sendDragDropEvent(d->dragDropItem, &dragLeave);
3583 d->dragDropItem = 0;
3586 event->setDropAction(Qt::IgnoreAction);
3591 This event handler, for event \a event, can be reimplemented in a subclass
3592 to receive drag leave events for the scene.
3594 \sa QGraphicsItem::dragLeaveEvent(), dragEnterEvent(), dragMoveEvent(),
3597 void QGraphicsScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
3599 Q_D(QGraphicsScene);
3600 if (d->dragDropItem) {
3601 // Leave the last drag drop item
3602 d->sendDragDropEvent(d->dragDropItem, event);
3603 d->dragDropItem = 0;
3608 This event handler, for event \a event, can be reimplemented in a subclass
3609 to receive drop events for the scene.
3611 \sa QGraphicsItem::dropEvent(), dragEnterEvent(), dragMoveEvent(),
3614 void QGraphicsScene::dropEvent(QGraphicsSceneDragDropEvent *event)
3617 Q_D(QGraphicsScene);
3618 if (d->dragDropItem) {
3619 // Drop on the last drag drop item
3620 d->sendDragDropEvent(d->dragDropItem, event);
3621 d->dragDropItem = 0;
3626 This event handler, for event \a focusEvent, can be reimplemented in a
3627 subclass to receive focus in events.
3629 The default implementation sets focus on the scene, and then on the last
3632 \sa QGraphicsItem::focusOutEvent()
3634 void QGraphicsScene::focusInEvent(QFocusEvent *focusEvent)
3636 Q_D(QGraphicsScene);
3639 switch (focusEvent->reason()) {
3640 case Qt::TabFocusReason:
3641 if (!focusNextPrevChild(true))
3642 focusEvent->ignore();
3644 case Qt::BacktabFocusReason:
3645 if (!focusNextPrevChild(false))
3646 focusEvent->ignore();
3649 if (d->passiveFocusItem) {
3650 // Set focus on the last focus item
3651 setFocusItem(d->passiveFocusItem, focusEvent->reason());
3658 This event handler, for event \a focusEvent, can be reimplemented in a
3659 subclass to receive focus out events.
3661 The default implementation removes focus from any focus item, then removes
3662 focus from the scene.
3664 \sa QGraphicsItem::focusInEvent()
3666 void QGraphicsScene::focusOutEvent(QFocusEvent *focusEvent)
3668 Q_D(QGraphicsScene);
3669 d->hasFocus = false;
3670 d->passiveFocusItem = d->focusItem;
3671 setFocusItem(0, focusEvent->reason());
3673 // Remove all popups when the scene loses focus.
3674 if (!d->popupWidgets.isEmpty())
3675 d->removePopup(d->popupWidgets.first());
3679 This event handler, for event \a helpEvent, can be
3680 reimplemented in a subclass to receive help events. The events
3681 are of type QEvent::ToolTip, which are created when a tooltip is
3684 The default implementation shows the tooltip of the topmost
3685 item, i.e., the item with the highest z-value, at the mouse
3686 cursor position. If no item has a tooltip set, this function
3689 \sa QGraphicsItem::toolTip(), QGraphicsSceneHelpEvent
3691 void QGraphicsScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent)
3693 #ifdef QT_NO_TOOLTIP
3694 Q_UNUSED(helpEvent);
3696 // Find the first item that does tooltips
3697 Q_D(QGraphicsScene);
3698 QList<QGraphicsItem *> itemsAtPos = d->itemsAtPosition(helpEvent->screenPos(),
3699 helpEvent->scenePos(),
3700 helpEvent->widget());
3701 QGraphicsItem *toolTipItem = 0;
3702 for (int i = 0; i < itemsAtPos.size(); ++i) {
3703 QGraphicsItem *tmp = itemsAtPos.at(i);
3704 if (tmp->d_func()->isProxyWidget()) {
3705 // if the item is a proxy widget, the event is forwarded to it
3706 sendEvent(tmp, helpEvent);
3707 if (helpEvent->isAccepted())
3710 if (!tmp->toolTip().isEmpty()) {
3716 // Show or hide the tooltip
3719 if (toolTipItem && !toolTipItem->toolTip().isEmpty()) {
3720 text = toolTipItem->toolTip();
3721 point = helpEvent->screenPos();
3723 QToolTip::showText(point, text, helpEvent->widget());
3724 helpEvent->setAccepted(!text.isEmpty());
3728 bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const
3730 return (item->d_ptr->acceptsHover
3731 || (item->d_ptr->isWidget
3732 && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration()))
3733 && !item->isBlockedByModalPanel();
3737 This event handler, for event \a hoverEvent, can be reimplemented in a
3738 subclass to receive hover enter events. The default implementation
3739 forwards the event to the topmost item that accepts hover events at the
3740 scene position from the event.
3742 \sa QGraphicsItem::hoverEvent(), QGraphicsItem::setAcceptHoverEvents()
3744 bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent)
3746 if (allItemsIgnoreHoverEvents)
3749 // Find the first item that accepts hover events, reusing earlier
3750 // calculated data is possible.
3751 if (cachedItemsUnderMouse.isEmpty()) {
3752 cachedItemsUnderMouse = itemsAtPosition(hoverEvent->screenPos(),
3753 hoverEvent->scenePos(),
3754 hoverEvent->widget());
3757 QGraphicsItem *item = 0;
3758 for (int i = 0; i < cachedItemsUnderMouse.size(); ++i) {
3759 QGraphicsItem *tmp = cachedItemsUnderMouse.at(i);
3760 if (itemAcceptsHoverEvents_helper(tmp)) {
3766 // Find the common ancestor item for the new topmost hoverItem and the
3767 // last item in the hoverItem list.
3768 QGraphicsItem *commonAncestorItem = (item && !hoverItems.isEmpty()) ? item->commonAncestorItem(hoverItems.last()) : 0;
3769 while (commonAncestorItem && !itemAcceptsHoverEvents_helper(commonAncestorItem))
3770 commonAncestorItem = commonAncestorItem->parentItem();
3771 if (commonAncestorItem && commonAncestorItem->panel() != item->panel()) {
3772 // The common ancestor isn't in the same panel as the two hovered
3774 commonAncestorItem = 0;
3777 // Check if the common ancestor item is known.
3778 int index = commonAncestorItem ? hoverItems.indexOf(commonAncestorItem) : -1;
3779 // Send hover leaves to any existing hovered children of the common
3781 for (int i = hoverItems.size() - 1; i > index; --i) {
3782 QGraphicsItem *lastItem = hoverItems.takeLast();
3783 if (itemAcceptsHoverEvents_helper(lastItem))
3784 sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, hoverEvent);
3787 // Item is a child of a known item. Generate enter events for the
3789 QList<QGraphicsItem *> parents;
3790 QGraphicsItem *parent = item;
3791 while (parent && parent != commonAncestorItem) {
3792 parents.prepend(parent);
3793 if (parent->isPanel()) {
3794 // Stop at the panel - we don't deliver beyond this point.
3797 parent = parent->parentItem();
3799 for (int i = 0; i < parents.size(); ++i) {
3800 parent = parents.at(i);
3801 hoverItems << parent;
3802 if (itemAcceptsHoverEvents_helper(parent))
3803 sendHoverEvent(QEvent::GraphicsSceneHoverEnter, parent, hoverEvent);
3806 // Generate a move event for the item itself
3808 && !hoverItems.isEmpty()
3809 && item == hoverItems.last()) {
3810 sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, hoverEvent);
3819 Handles all actions necessary to clean up the scene when the mouse leaves
3822 void QGraphicsScenePrivate::leaveScene(QWidget *viewport)
3824 #ifndef QT_NO_TOOLTIP
3825 QToolTip::hideText();
3827 QGraphicsView *view = qobject_cast<QGraphicsView *>(viewport->parent());
3828 // Send HoverLeave events to all existing hover items, topmost first.
3829 QGraphicsSceneHoverEvent hoverEvent;
3830 hoverEvent.setWidget(viewport);
3833 QPoint cursorPos = QCursor::pos();
3834 hoverEvent.setScenePos(view->mapToScene(viewport->mapFromGlobal(cursorPos)));
3835 hoverEvent.setLastScenePos(hoverEvent.scenePos());
3836 hoverEvent.setScreenPos(cursorPos);
3837 hoverEvent.setLastScreenPos(hoverEvent.screenPos());
3840 while (!hoverItems.isEmpty()) {
3841 QGraphicsItem *lastItem = hoverItems.takeLast();
3842 if (itemAcceptsHoverEvents_helper(lastItem))
3843 sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, &hoverEvent);
3848 This event handler, for event \a keyEvent, can be reimplemented in a
3849 subclass to receive keypress events. The default implementation forwards
3850 the event to current focus item.
3852 \sa QGraphicsItem::keyPressEvent(), focusItem()
3854 void QGraphicsScene::keyPressEvent(QKeyEvent *keyEvent)
3856 // ### Merge this function with keyReleaseEvent; they are identical
3857 // ### (except this comment).
3858 Q_D(QGraphicsScene);
3859 QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
3863 QGraphicsItem *p = item;
3865 // Accept the event by default
3867 // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
3868 // is filtered out, stop propagating it.
3869 if (p->isBlockedByModalPanel())
3871 if (!d->sendEvent(p, keyEvent))
3873 } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
3880 This event handler, for event \a keyEvent, can be reimplemented in a
3881 subclass to receive key release events. The default implementation
3882 forwards the event to current focus item.
3884 \sa QGraphicsItem::keyReleaseEvent(), focusItem()
3886 void QGraphicsScene::keyReleaseEvent(QKeyEvent *keyEvent)
3888 // ### Merge this function with keyPressEvent; they are identical (except
3889 // ### this comment).
3890 Q_D(QGraphicsScene);
3891 QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
3895 QGraphicsItem *p = item;
3897 // Accept the event by default
3899 // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
3900 // is filtered out, stop propagating it.
3901 if (p->isBlockedByModalPanel())
3903 if (!d->sendEvent(p, keyEvent))
3905 } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
3912 This event handler, for event \a mouseEvent, can be reimplemented
3913 in a subclass to receive mouse press events for the scene.
3915 The default implementation depends on the state of the scene. If
3916 there is a mouse grabber item, then the event is sent to the mouse
3917 grabber. Otherwise, it is forwarded to the topmost item that
3918 accepts mouse events at the scene position from the event, and
3919 that item promptly becomes the mouse grabber item.
3921 If there is no item at the given position on the scene, the
3922 selection area is reset, any focus item loses its input focus, and
3923 the event is then ignored.
3925 \sa QGraphicsItem::mousePressEvent(),
3926 QGraphicsItem::setAcceptedMouseButtons()
3928 void QGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
3930 Q_D(QGraphicsScene);
3931 if (d->mouseGrabberItems.isEmpty()) {
3932 // Dispatch hover events
3933 QGraphicsSceneHoverEvent hover;
3934 _q_hoverFromMouseEvent(&hover, mouseEvent);
3935 d->dispatchHoverEvent(&hover);
3938 d->mousePressEventHandler(mouseEvent);
3942 This event handler, for event \a mouseEvent, can be reimplemented
3943 in a subclass to receive mouse move events for the scene.
3945 The default implementation depends on the mouse grabber state. If there is
3946 a mouse grabber item, the event is sent to the mouse grabber. If there
3947 are any items that accept hover events at the current position, the event
3948 is translated into a hover event and accepted; otherwise it's ignored.
3950 \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseReleaseEvent(),
3951 QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
3953 void QGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
3955 Q_D(QGraphicsScene);
3956 if (d->mouseGrabberItems.isEmpty()) {
3957 if (mouseEvent->buttons())
3959 QGraphicsSceneHoverEvent hover;
3960 _q_hoverFromMouseEvent(&hover, mouseEvent);
3961 mouseEvent->setAccepted(d->dispatchHoverEvent(&hover));
3965 // Forward the event to the mouse grabber
3966 d->sendMouseEvent(mouseEvent);
3967 mouseEvent->accept();
3971 This event handler, for event \a mouseEvent, can be reimplemented
3972 in a subclass to receive mouse release events for the scene.
3974 The default implementation depends on the mouse grabber state. If
3975 there is no mouse grabber, the event is ignored. Otherwise, if
3976 there is a mouse grabber item, the event is sent to the mouse
3977 grabber. If this mouse release represents the last pressed button
3978 on the mouse, the mouse grabber item then loses the mouse grab.
3980 \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
3981 QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
3983 void QGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
3985 Q_D(QGraphicsScene);
3986 if (d->mouseGrabberItems.isEmpty()) {
3987 mouseEvent->ignore();
3991 // Forward the event to the mouse grabber
3992 d->sendMouseEvent(mouseEvent);
3993 mouseEvent->accept();
3995 // Reset the mouse grabber when the last mouse button has been released.
3996 if (!mouseEvent->buttons()) {
3997 if (!d->mouseGrabberItems.isEmpty()) {
3998 d->lastMouseGrabberItem = d->mouseGrabberItems.last();
3999 if (d->lastMouseGrabberItemHasImplicitMouseGrab)
4000 d->mouseGrabberItems.last()->ungrabMouse();
4002 d->lastMouseGrabberItem = 0;
4005 // Generate a hoverevent
4006 QGraphicsSceneHoverEvent hoverEvent;
4007 _q_hoverFromMouseEvent(&hoverEvent, mouseEvent);
4008 d->dispatchHoverEvent(&hoverEvent);
4013 This event handler, for event \a mouseEvent, can be reimplemented
4014 in a subclass to receive mouse doubleclick events for the scene.
4016 If someone doubleclicks on the scene, the scene will first receive
4017 a mouse press event, followed by a release event (i.e., a click),
4018 then a doubleclick event, and finally a release event. If the
4019 doubleclick event is delivered to a different item than the one
4020 that received the first press and release, it will be delivered as
4021 a press event. However, tripleclick events are not delivered as
4022 doubleclick events in this case.
4024 The default implementation is similar to mousePressEvent().
4026 \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
4027 QGraphicsItem::mouseReleaseEvent(), QGraphicsItem::setAcceptedMouseButtons()
4029 void QGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
4031 Q_D(QGraphicsScene);
4032 d->mousePressEventHandler(mouseEvent);
4036 This event handler, for event \a wheelEvent, can be reimplemented in a
4037 subclass to receive mouse wheel events for the scene.
4039 By default, the event is delivered to the topmost visible item under the
4040 cursor. If ignored, the event propagates to the item beneath, and again
4041 until the event is accepted, or it reaches the scene. If no items accept
4042 the event, it is ignored.
4044 \sa QGraphicsItem::wheelEvent()
4046 void QGraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *wheelEvent)
4048 Q_D(QGraphicsScene);
4049 QList<QGraphicsItem *> wheelCandidates = d->itemsAtPosition(wheelEvent->screenPos(),
4050 wheelEvent->scenePos(),
4051 wheelEvent->widget());
4054 // On Mac, ignore the event if the first item under the mouse is not the last opened
4055 // popup (or one of its descendant)
4056 if (!d->popupWidgets.isEmpty() && !wheelCandidates.isEmpty() && wheelCandidates.first() != d->popupWidgets.back() && !d->popupWidgets.back()->isAncestorOf(wheelCandidates.first())) {
4057 wheelEvent->accept();
4061 // Find the first popup under the mouse (including the popup's descendants) starting from the last.
4062 // Remove all popups after the one found, or all or them if no popup is under the mouse.
4063 // Then continue with the event.
4064 QList<QGraphicsWidget *>::const_iterator iter = d->popupWidgets.constEnd();
4065 while (--iter >= d->popupWidgets.constBegin() && !wheelCandidates.isEmpty()) {
4066 if (wheelCandidates.first() == *iter || (*iter)->isAncestorOf(wheelCandidates.first()))
4068 d->removePopup(*iter);
4072 bool hasSetFocus = false;
4073 foreach (QGraphicsItem *item, wheelCandidates) {
4074 if (!hasSetFocus && item->isEnabled()
4075 && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
4076 if (item->isWidget() && static_cast<QGraphicsWidget *>(item)->focusPolicy() == Qt::WheelFocus) {
4078 if (item != focusItem())
4079 setFocusItem(item, Qt::MouseFocusReason);
4083 wheelEvent->setPos(item->d_ptr->genericMapFromScene(wheelEvent->scenePos(),
4084 wheelEvent->widget()));
4085 wheelEvent->accept();
4086 bool isPanel = item->isPanel();
4087 d->sendEvent(item, wheelEvent);
4088 if (isPanel || wheelEvent->isAccepted())
4094 This event handler, for event \a event, can be reimplemented in a
4095 subclass to receive input method events for the scene.
4097 The default implementation forwards the event to the focusItem().
4098 If no item currently has focus or the current focus item does not
4099 accept input methods, this function does nothing.
4101 \sa QGraphicsItem::inputMethodEvent()
4103 void QGraphicsScene::inputMethodEvent(QInputMethodEvent *event)
4105 Q_D(QGraphicsScene);
4106 if (d->focusItem && (d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
4107 d->sendEvent(d->focusItem, event);
4111 Draws the background of the scene using \a painter, before any items and
4112 the foreground are drawn. Reimplement this function to provide a custom
4113 background for the scene.
4115 All painting is done in \e scene coordinates. The \a rect
4116 parameter is the exposed rectangle.
4118 If all you want is to define a color, texture, or gradient for the
4119 background, you can call setBackgroundBrush() instead.
4121 \sa drawForeground(), drawItems()
4123 void QGraphicsScene::drawBackground(QPainter *painter, const QRectF &rect)
4125 Q_D(QGraphicsScene);
4127 if (d->backgroundBrush.style() != Qt::NoBrush) {
4128 if (d->painterStateProtection)
4130 painter->setBrushOrigin(0, 0);
4131 painter->fillRect(rect, backgroundBrush());
4132 if (d->painterStateProtection)
4138 Draws the foreground of the scene using \a painter, after the background
4139 and all items have been drawn. Reimplement this function to provide a
4140 custom foreground for the scene.
4142 All painting is done in \e scene coordinates. The \a rect
4143 parameter is the exposed rectangle.
4145 If all you want is to define a color, texture or gradient for the
4146 foreground, you can call setForegroundBrush() instead.
4148 \sa drawBackground(), drawItems()
4150 void QGraphicsScene::drawForeground(QPainter *painter, const QRectF &rect)
4152 Q_D(QGraphicsScene);
4154 if (d->foregroundBrush.style() != Qt::NoBrush) {
4155 if (d->painterStateProtection)
4157 painter->setBrushOrigin(0, 0);
4158 painter->fillRect(rect, foregroundBrush());
4159 if (d->painterStateProtection)
4164 static void _q_paintItem(QGraphicsItem *item, QPainter *painter,
4165 const QStyleOptionGraphicsItem *option, QWidget *widget,
4166 bool useWindowOpacity, bool painterStateProtection)
4168 if (!item->isWidget()) {
4169 item->paint(painter, option, widget);
4172 QGraphicsWidget *widgetItem = static_cast<QGraphicsWidget *>(item);
4173 QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(widgetItem);
4174 const qreal windowOpacity = (proxy && proxy->widget() && useWindowOpacity)
4175 ? proxy->widget()->windowOpacity() : 1.0;
4176 const qreal oldPainterOpacity = painter->opacity();
4178 if (qFuzzyIsNull(windowOpacity))
4180 // Set new painter opacity.
4181 if (windowOpacity < 1.0)
4182 painter->setOpacity(oldPainterOpacity * windowOpacity);
4184 // set layoutdirection on the painter
4185 Qt::LayoutDirection oldLayoutDirection = painter->layoutDirection();
4186 painter->setLayoutDirection(widgetItem->layoutDirection());
4188 if (widgetItem->isWindow() && widgetItem->windowType() != Qt::Popup && widgetItem->windowType() != Qt::ToolTip
4189 && !(widgetItem->windowFlags() & Qt::FramelessWindowHint)) {
4190 if (painterStateProtection)
4192 widgetItem->paintWindowFrame(painter, option, widget);
4193 if (painterStateProtection)
4195 } else if (widgetItem->autoFillBackground()) {
4196 painter->fillRect(option->exposedRect, widgetItem->palette().window());
4199 widgetItem->paint(painter, option, widget);
4201 // Restore layoutdirection on the painter.
4202 painter->setLayoutDirection(oldLayoutDirection);
4203 // Restore painter opacity.
4204 if (windowOpacity < 1.0)
4205 painter->setOpacity(oldPainterOpacity);
4208 static void _q_paintIntoCache(QPixmap *pix, QGraphicsItem *item, const QRegion &pixmapExposed,
4209 const QTransform &itemToPixmap, QPainter::RenderHints renderHints,
4210 const QStyleOptionGraphicsItem *option, bool painterStateProtection)
4213 QPainter pixmapPainter;
4214 QRect br = pixmapExposed.boundingRect();
4216 // Don't use subpixmap if we get a full update.
4217 if (pixmapExposed.isEmpty() || (pixmapExposed.rectCount() == 1 && br.contains(pix->rect()))) {
4218 pix->fill(Qt::transparent);
4219 pixmapPainter.begin(pix);
4221 subPix = QPixmap(br.size());
4222 subPix.fill(Qt::transparent);
4223 pixmapPainter.begin(&subPix);
4224 pixmapPainter.translate(-br.topLeft());
4225 if (!pixmapExposed.isEmpty()) {
4226 // Applied to subPix; paint is adjusted to the coordinate space is
4228 pixmapPainter.setClipRegion(pixmapExposed);
4232 pixmapPainter.setRenderHints(pixmapPainter.renderHints(), false);
4233 pixmapPainter.setRenderHints(renderHints, true);
4234 pixmapPainter.setWorldTransform(itemToPixmap, true);
4237 _q_paintItem(item, &pixmapPainter, option, 0, false, painterStateProtection);
4238 pixmapPainter.end();
4240 if (!subPix.isNull()) {
4241 // Blit the subpixmap into the main pixmap.
4242 pixmapPainter.begin(pix);
4243 pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
4244 pixmapPainter.setClipRegion(pixmapExposed);
4245 pixmapPainter.drawPixmap(br.topLeft(), subPix);
4246 pixmapPainter.end();
4250 // Copied from qpaintengine_vg.cpp
4251 // Returns true for 90, 180, and 270 degree rotations.
4252 static inline bool transformIsSimple(const QTransform& transform)
4254 QTransform::TransformationType type = transform.type();
4255 if (type <= QTransform::TxScale) {
4257 } else if (type == QTransform::TxRotate) {
4258 // Check for 90, and 270 degree rotations.
4259 qreal m11 = transform.m11();
4260 qreal m12 = transform.m12();
4261 qreal m21 = transform.m21();
4262 qreal m22 = transform.m22();
4263 if (m11 == 0.0f && m22 == 0.0f) {
4264 if (m12 == 1.0f && m21 == -1.0f)
4265 return true; // 90 degrees.
4266 else if (m12 == -1.0f && m21 == 1.0f)
4267 return true; // 270 degrees.
4268 else if (m12 == -1.0f && m21 == -1.0f)
4269 return true; // 90 degrees inverted y.
4270 else if (m12 == 1.0f && m21 == 1.0f)
4271 return true; // 270 degrees inverted y.
4280 Draws items directly, or using cache.
4282 void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painter,
4283 const QStyleOptionGraphicsItem *option, QWidget *widget,
4284 bool painterStateProtection)
4286 QGraphicsItemPrivate *itemd = item->d_ptr.data();
4287 QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode);
4289 // Render directly, using no cache.
4290 if (cacheMode == QGraphicsItem::NoCache
4292 || !X11->use_xrender
4295 _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget, true, painterStateProtection);
4299 const qreal oldPainterOpacity = painter->opacity();
4300 qreal newPainterOpacity = oldPainterOpacity;
4301 QGraphicsProxyWidget *proxy = item->isWidget() ? qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(item)) : 0;
4302 if (proxy && proxy->widget()) {
4303 const qreal windowOpacity = proxy->widget()->windowOpacity();
4304 if (windowOpacity < 1.0)
4305 newPainterOpacity *= windowOpacity;
4308 // Item's (local) bounding rect
4309 QRectF brect = item->boundingRect();
4310 QRectF adjustedBrect(brect);
4311 _q_adjustRect(&adjustedBrect);
4312 if (adjustedBrect.isEmpty())
4315 // Fetch the off-screen transparent buffer and exposed area info.
4316 QPixmapCache::Key pixmapKey;
4319 QGraphicsItemCache *itemCache = itemd->extraItemCache();
4320 if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
4321 pixmapKey = itemCache->key;
4323 pixmapKey = itemCache->deviceData.value(widget).key;
4326 // Find pixmap in cache.
4327 pixmapFound = QPixmapCache::find(pixmapKey, &pix);
4329 // Render using item coordinate cache mode.
4330 if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
4332 bool fixedCacheSize = false;
4333 QRect br = brect.toAlignedRect();
4334 if ((fixedCacheSize = itemCache->fixedSize.isValid())) {
4335 pixmapSize = itemCache->fixedSize;
4337 pixmapSize = br.size();
4340 // Create or recreate the pixmap.
4341 int adjust = itemCache->fixedSize.isValid() ? 0 : 2;
4342 QSize adjustSize(adjust*2, adjust*2);
4343 br.adjust(-adjust, -adjust, adjust, adjust);
4344 if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) {
4345 pix = QPixmap(pixmapSize + adjustSize);
4346 itemCache->boundingRect = br;
4347 itemCache->exposed.clear();
4348 itemCache->allExposed = true;
4349 } else if (itemCache->boundingRect != br) {
4350 itemCache->boundingRect = br;
4351 itemCache->exposed.clear();
4352 itemCache->allExposed = true;
4355 // Redraw any newly exposed areas.
4356 if (itemCache->allExposed || !itemCache->exposed.isEmpty()) {
4358 //We know that we will modify the pixmap, removing it from the cache
4359 //will detach the one we have and avoid a deep copy
4361 QPixmapCache::remove(pixmapKey);
4363 // Fit the item's bounding rect into the pixmap's coordinates.
4364 QTransform itemToPixmap;
4365 if (fixedCacheSize) {
4366 const QPointF scale(pixmapSize.width() / brect.width(), pixmapSize.height() / brect.height());
4367 itemToPixmap.scale(scale.x(), scale.y());
4369 itemToPixmap.translate(-br.x(), -br.y());
4371 // Generate the item's exposedRect and map its list of expose
4372 // rects to device coordinates.
4373 styleOptionTmp = *option;
4374 QRegion pixmapExposed;
4376 if (!itemCache->allExposed) {
4377 for (int i = 0; i < itemCache->exposed.size(); ++i) {
4378 QRectF r = itemCache->exposed.at(i);
4380 pixmapExposed += itemToPixmap.mapRect(r).toAlignedRect();
4383 exposedRect = brect;
4385 styleOptionTmp.exposedRect = exposedRect;
4388 _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
4389 &styleOptionTmp, painterStateProtection);
4391 // insert this pixmap into the cache.
4392 itemCache->key = QPixmapCache::insert(pix);
4394 // Reset expose data.
4395 itemCache->allExposed = false;
4396 itemCache->exposed.clear();
4399 // Redraw the exposed area using the transformed painter. Depending on
4400 // the hardware, this may be a server-side operation, or an expensive
4401 // qpixmap-image-transform-pixmap roundtrip.
4402 if (newPainterOpacity != oldPainterOpacity) {
4403 painter->setOpacity(newPainterOpacity);
4404 painter->drawPixmap(br.topLeft(), pix);
4405 painter->setOpacity(oldPainterOpacity);
4407 painter->drawPixmap(br.topLeft(), pix);
4412 // Render using device coordinate cache mode.
4413 if (cacheMode == QGraphicsItem::DeviceCoordinateCache) {
4414 // Find the item's bounds in device coordinates.
4415 QRectF deviceBounds = painter->worldTransform().mapRect(brect);
4416 QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
4417 if (deviceRect.isEmpty())
4419 QRect viewRect = widget ? widget->rect() : QRect();
4420 if (widget && !viewRect.intersects(deviceRect))
4423 // Resort to direct rendering if the device rect exceeds the
4424 // (optional) maximum bounds. (QGraphicsSvgItem uses this).
4425 QSize maximumCacheSize =
4426 itemd->extra(QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize).toSize();
4427 if (!maximumCacheSize.isEmpty()
4428 && (deviceRect.width() > maximumCacheSize.width()
4429 || deviceRect.height() > maximumCacheSize.height())) {
4430 _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget,
4431 oldPainterOpacity != newPainterOpacity, painterStateProtection);
4435 // Create or reuse offscreen pixmap, possibly scroll/blit from the old one.
4436 // If the world transform is rotated we always recreate the cache to avoid
4438 bool pixModified = false;
4439 QGraphicsItemCache::DeviceData *deviceData = &itemCache->deviceData[widget];
4440 bool invertable = true;
4441 QTransform diff = deviceData->lastTransform.inverted(&invertable);
4443 diff *= painter->worldTransform();
4444 deviceData->lastTransform = painter->worldTransform();
4445 bool allowPartialCacheExposure = false;
4446 bool simpleTransform = invertable && diff.type() <= QTransform::TxTranslate
4447 && transformIsSimple(painter->worldTransform());
4448 if (!simpleTransform) {
4450 itemCache->allExposed = true;
4451 itemCache->exposed.clear();
4452 deviceData->cacheIndent = QPoint();
4454 } else if (!viewRect.isNull()) {
4455 allowPartialCacheExposure = deviceData->cacheIndent != QPoint();
4458 // Allow partial cache exposure if the device rect isn't fully contained and
4459 // deviceRect is 20% taller or wider than the viewRect.
4460 if (!allowPartialCacheExposure && !viewRect.isNull() && !viewRect.contains(deviceRect)) {
4461 allowPartialCacheExposure = (viewRect.width() * 1.2 < deviceRect.width())
4462 || (viewRect.height() * 1.2 < deviceRect.height());
4465 QRegion scrollExposure;
4466 if (allowPartialCacheExposure) {
4467 // Part of pixmap is drawn. Either device contains viewrect (big
4468 // item covers whole screen) or parts of device are outside the
4469 // viewport. In either case the device rect must be the intersect
4471 int dx = deviceRect.left() < viewRect.left() ? viewRect.left() - deviceRect.left() : 0;
4472 int dy = deviceRect.top() < viewRect.top() ? viewRect.top() - deviceRect.top() : 0;
4473 QPoint newCacheIndent(dx, dy);
4474 deviceRect &= viewRect;
4477 deviceData->cacheIndent = QPoint();
4478 itemCache->allExposed = true;
4479 itemCache->exposed.clear();
4483 // Copy / "scroll" the old pixmap onto the new ole and calculate
4484 // scrolled exposure.
4485 if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size()) {
4486 QPoint diff = newCacheIndent - deviceData->cacheIndent;
4487 QPixmap newPix(deviceRect.size());
4488 // ### Investigate removing this fill (test with Plasma and
4489 // graphicssystem raster).
4490 newPix.fill(Qt::transparent);
4491 if (!pix.isNull()) {
4492 QPainter newPixPainter(&newPix);
4493 newPixPainter.drawPixmap(-diff, pix);
4494 newPixPainter.end();
4497 exposed += newPix.rect();
4499 exposed -= QRect(-diff, pix.size());
4500 scrollExposure = exposed;
4505 deviceData->cacheIndent = newCacheIndent;
4507 // Full pixmap is drawn.
4508 deviceData->cacheIndent = QPoint();
4510 // Auto-adjust the pixmap size.
4511 if (deviceRect.size() != pix.size()) {
4512 // exposed needs to cover the whole pixmap
4513 pix = QPixmap(deviceRect.size());
4515 itemCache->allExposed = true;
4516 itemCache->exposed.clear();
4520 // Check for newly invalidated areas.
4521 if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) {
4522 //We know that we will modify the pixmap, removing it from the cache
4523 //will detach the one we have and avoid a deep copy
4525 QPixmapCache::remove(pixmapKey);
4527 // Construct an item-to-pixmap transform.
4528 QPointF p = deviceRect.topLeft();
4529 QTransform itemToPixmap = painter->worldTransform();
4531 itemToPixmap *= QTransform::fromTranslate(-p.x(), -p.y());
4533 // Map the item's logical expose to pixmap coordinates.
4534 QRegion pixmapExposed = scrollExposure;
4535 if (!itemCache->allExposed) {
4536 const QVector<QRectF> &exposed = itemCache->exposed;
4537 for (int i = 0; i < exposed.size(); ++i)
4538 pixmapExposed += itemToPixmap.mapRect(exposed.at(i)).toRect().adjusted(-1, -1, 1, 1);
4541 // Calculate the style option's exposedRect.
4543 if (itemCache->allExposed) {
4544 br = item->boundingRect();
4546 const QVector<QRectF> &exposed = itemCache->exposed;
4547 for (int i = 0; i < exposed.size(); ++i)
4548 br |= exposed.at(i);
4549 QTransform pixmapToItem = itemToPixmap.inverted();
4550 foreach (QRect r, scrollExposure.rects())
4551 br |= pixmapToItem.mapRect(r);
4553 styleOptionTmp = *option;
4554 styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1);
4556 // Render the exposed areas.
4557 _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
4558 &styleOptionTmp, painterStateProtection);
4560 // Reset expose data.
4562 itemCache->allExposed = false;
4563 itemCache->exposed.clear();
4567 // Insert this pixmap into the cache.
4568 deviceData->key = QPixmapCache::insert(pix);
4571 // Redraw the exposed area using an untransformed painter. This
4572 // effectively becomes a bitblit that does not transform the cache.
4573 QTransform restoreTransform = painter->worldTransform();
4574 painter->setWorldTransform(QTransform());
4575 if (newPainterOpacity != oldPainterOpacity) {
4576 painter->setOpacity(newPainterOpacity);
4577 painter->drawPixmap(deviceRect.topLeft(), pix);
4578 painter->setOpacity(oldPainterOpacity);
4580 painter->drawPixmap(deviceRect.topLeft(), pix);
4582 painter->setWorldTransform(restoreTransform);
4587 void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const viewTransform,
4588 QRegion *exposedRegion, QWidget *widget)
4590 // Make sure we don't have unpolished items before we draw.
4591 if (!unpolishedItems.isEmpty())
4595 QRectF exposedSceneRect;
4596 if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) {
4597 exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1);
4599 exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect);
4601 const QList<QGraphicsItem *> tli = index->estimateTopLevelItems(exposedSceneRect, Qt::AscendingOrder);
4602 for (int i = 0; i < tli.size(); ++i)
4603 drawSubtreeRecursive(tli.at(i), painter, viewTransform, exposedRegion, widget);
4606 void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter,
4607 const QTransform *const viewTransform,
4608 QRegion *exposedRegion, QWidget *widget,
4609 qreal parentOpacity, const QTransform *const effectTransform)
4613 if (!item->d_ptr->visible)
4616 const bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
4617 const bool itemHasChildren = !item->d_ptr->children.isEmpty();
4618 if (!itemHasContents && !itemHasChildren)
4619 return; // Item has neither contents nor children!(?)
4621 const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
4622 const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
4623 if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity()))
4626 QTransform transform(Qt::Uninitialized);
4627 QTransform *transformPtr = 0;
4628 bool translateOnlyTransform = false;
4629 #define ENSURE_TRANSFORM_PTR \
4630 if (!transformPtr) { \
4631 Q_ASSERT(!itemIsUntransformable); \
4632 if (viewTransform) { \
4633 transform = item->d_ptr->sceneTransform; \
4634 transform *= *viewTransform; \
4635 transformPtr = &transform; \
4637 transformPtr = &item->d_ptr->sceneTransform; \
4638 translateOnlyTransform = item->d_ptr->sceneTransformTranslateOnly; \
4642 // Update the item's scene transform if the item is transformable;
4643 // otherwise calculate the full transform,
4644 bool wasDirtyParentSceneTransform = false;
4645 const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
4646 if (itemIsUntransformable) {
4647 transform = item->deviceTransform(viewTransform ? *viewTransform : QTransform());
4648 transformPtr = &transform;
4649 } else if (item->d_ptr->dirtySceneTransform) {
4650 item->d_ptr->updateSceneTransformFromParent();
4651 Q_ASSERT(!item->d_ptr->dirtySceneTransform);
4652 wasDirtyParentSceneTransform = true;
4655 const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
4656 bool drawItem = itemHasContents && !itemIsFullyTransparent;
4658 const QRectF brect = adjustedItemEffectiveBoundingRect(item);
4659 ENSURE_TRANSFORM_PTR
4660 QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toAlignedRect()
4661 : transformPtr->mapRect(brect).toAlignedRect();
4662 viewBoundingRect.adjust(-int(rectAdjust), -int(rectAdjust), rectAdjust, rectAdjust);
4664 item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
4665 drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect)
4666 : !viewBoundingRect.normalized().isEmpty();
4668 if (!itemHasChildren)
4670 if (itemClipsChildrenToShape) {
4671 if (wasDirtyParentSceneTransform)
4672 item->d_ptr->invalidateChildrenSceneTransform();
4676 } // else we know for sure this item has children we must process.
4678 if (itemHasChildren && itemClipsChildrenToShape)
4679 ENSURE_TRANSFORM_PTR;
4681 #ifndef QT_NO_GRAPHICSEFFECT
4682 if (item->d_ptr->graphicsEffect && item->d_ptr->graphicsEffect->isEnabled()) {
4683 ENSURE_TRANSFORM_PTR;
4684 QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp,
4685 painter, opacity, wasDirtyParentSceneTransform, itemHasContents && !itemIsFullyTransparent);
4686 QGraphicsEffectSource *source = item->d_ptr->graphicsEffect->d_func()->source;
4687 QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *>
4689 sourced->info = &info;
4690 const QTransform restoreTransform = painter->worldTransform();
4691 if (effectTransform)
4692 painter->setWorldTransform(*transformPtr * *effectTransform);
4694 painter->setWorldTransform(*transformPtr);
4695 painter->setOpacity(opacity);
4697 if (sourced->currentCachedSystem() != Qt::LogicalCoordinates
4698 && sourced->lastEffectTransform != painter->worldTransform())
4700 if (sourced->lastEffectTransform.type() <= QTransform::TxTranslate
4701 && painter->worldTransform().type() <= QTransform::TxTranslate)
4703 QRectF sourceRect = sourced->boundingRect(Qt::DeviceCoordinates);
4704 QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect);
4706 sourced->setCachedOffset(effectRect.topLeft());
4708 sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged);
4711 sourced->lastEffectTransform = painter->worldTransform();
4714 item->d_ptr->graphicsEffect->draw(painter);
4715 painter->setWorldTransform(restoreTransform);
4718 #endif //QT_NO_GRAPHICSEFFECT
4720 draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity,
4721 effectTransform, wasDirtyParentSceneTransform, drawItem);
4725 static inline void setClip(QPainter *painter, QGraphicsItem *item)
4729 const QPainterPath clipPath(item->shape());
4730 if (QPathClipper::pathToRect(clipPath, &clipRect))
4731 painter->setClipRect(clipRect, Qt::IntersectClip);
4733 painter->setClipPath(clipPath, Qt::IntersectClip);
4736 static inline void setWorldTransform(QPainter *painter, const QTransform *const transformPtr,
4737 const QTransform *effectTransform)
4739 Q_ASSERT(transformPtr);
4740 if (effectTransform)
4741 painter->setWorldTransform(*transformPtr * *effectTransform);
4743 painter->setWorldTransform(*transformPtr);
4746 void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform,
4747 const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget,
4748 qreal opacity, const QTransform *effectTransform,
4749 bool wasDirtyParentSceneTransform, bool drawItem)
4751 const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
4752 const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
4753 const bool itemHasChildren = !item->d_ptr->children.isEmpty();
4754 bool setChildClip = itemClipsChildrenToShape;
4755 bool itemHasChildrenStackedBehind = false;
4758 if (itemHasChildren) {
4759 if (itemClipsChildrenToShape)
4760 setWorldTransform(painter, transformPtr, effectTransform);
4762 item->d_ptr->ensureSortedChildren();
4763 // Items with the 'ItemStacksBehindParent' flag are put in front of the list
4764 // so all we have to do is to check the first item.
4765 itemHasChildrenStackedBehind = (item->d_ptr->children.at(0)->d_ptr->flags
4766 & QGraphicsItem::ItemStacksBehindParent);
4768 if (itemHasChildrenStackedBehind) {
4769 if (itemClipsChildrenToShape) {
4770 setClip(painter, item);
4771 setChildClip = false;
4774 // Draw children behind
4775 for (i = 0; i < item->d_ptr->children.size(); ++i) {
4776 QGraphicsItem *child = item->d_ptr->children.at(i);
4777 if (wasDirtyParentSceneTransform)
4778 child->d_ptr->dirtySceneTransform = 1;
4779 if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
4781 if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
4783 drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
4790 Q_ASSERT(!itemIsFullyTransparent);
4791 Q_ASSERT(!(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents));
4792 Q_ASSERT(transformPtr);
4793 item->d_ptr->initStyleOption(&styleOptionTmp, *transformPtr, exposedRegion
4794 ? *exposedRegion : QRegion(), exposedRegion == 0);
4796 const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape;
4797 bool restorePainterClip = false;
4799 if (!itemHasChildren || !itemClipsChildrenToShape) {
4800 // Item does not have children or clip children to shape.
4801 setWorldTransform(painter, transformPtr, effectTransform);
4802 if ((restorePainterClip = itemClipsToShape))
4803 setClip(painter, item);
4804 } else if (itemHasChildrenStackedBehind){
4805 // Item clips children to shape and has children stacked behind, which means
4806 // the painter is already clipped to the item's shape.
4807 if (itemClipsToShape) {
4808 // The clip is already correct. Ensure correct world transform.
4809 setWorldTransform(painter, transformPtr, effectTransform);
4811 // Remove clip (this also ensures correct world transform).
4813 setChildClip = true;
4815 } else if (itemClipsToShape) {
4816 // Item clips children and itself to shape. It does not have hildren stacked
4817 // behind, which means the clip has not yet been set. We set it now and re-use it
4818 // for the children.
4819 setClip(painter, item);
4820 setChildClip = false;
4823 if (painterStateProtection && !restorePainterClip)
4826 painter->setOpacity(opacity);
4827 if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget)
4828 item->paint(painter, &styleOptionTmp, widget);
4830 drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection);
4832 if (painterStateProtection || restorePainterClip)
4835 static int drawRect = qgetenv("QT_DRAW_SCENE_ITEM_RECTS").toInt();
4837 QPen oldPen = painter->pen();
4838 QBrush oldBrush = painter->brush();
4839 quintptr ptr = reinterpret_cast<quintptr>(item);
4840 const QColor color = QColor::fromHsv(ptr % 255, 255, 255);
4841 painter->setPen(color);
4842 painter->setBrush(Qt::NoBrush);
4843 painter->drawRect(adjustedItemBoundingRect(item));
4844 painter->setPen(oldPen);
4845 painter->setBrush(oldBrush);
4849 // Draw children in front
4850 if (itemHasChildren) {
4852 setClip(painter, item);
4854 for (; i < item->d_ptr->children.size(); ++i) {
4855 QGraphicsItem *child = item->d_ptr->children.at(i);
4856 if (wasDirtyParentSceneTransform)
4857 child->d_ptr->dirtySceneTransform = 1;
4858 if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
4860 drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
4863 // Restore child clip
4864 if (itemClipsChildrenToShape)
4869 void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren,
4870 bool force, bool ignoreOpacity, bool removingItemFromScene,
4871 bool updateBoundingRect)
4877 if (removingItemFromScene && !ignoreOpacity && !item->d_ptr->ignoreOpacity) {
4878 // If any of the item's ancestors ignore opacity, it means that the opacity
4879 // was set to 0 (and the update request has not yet been processed). That
4880 // also means that we have to ignore the opacity for the item itself; otherwise
4881 // things like: parent->setOpacity(0); scene->removeItem(child) won't work.
4882 // Note that we only do this when removing items from the scene. In all other
4883 // cases the ignoreOpacity bit propagates properly in processDirtyItems, but
4884 // since the item is removed immediately it won't be processed there.
4885 QGraphicsItem *p = item->d_ptr->parent;
4887 if (p->d_ptr->ignoreOpacity) {
4888 item->d_ptr->ignoreOpacity = true;
4891 p = p->d_ptr->parent;
4895 if (item->d_ptr->discardUpdateRequest(/*ignoreVisibleBit=*/force,
4896 /*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren,
4897 /*ignoreOpacity=*/ignoreOpacity)) {
4898 if (item->d_ptr->dirty) {
4899 // The item is already marked as dirty and will be processed later. However,
4900 // we have to make sure ignoreVisible and ignoreOpacity are set properly;
4901 // otherwise things like: item->update(); item->hide() (force is now true)
4902 // won't work as expected.
4904 item->d_ptr->ignoreVisible = 1;
4906 item->d_ptr->ignoreOpacity = 1;
4911 const bool fullItemUpdate = rect.isNull();
4912 if (!fullItemUpdate && rect.isEmpty())
4915 if (!processDirtyItemsEmitted) {
4916 QMetaMethod method = q_ptr->metaObject()->method(processDirtyItemsIndex);
4917 method.invoke(q_ptr, Qt::QueuedConnection);
4918 // QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection);
4919 processDirtyItemsEmitted = true;
4922 if (removingItemFromScene) {
4923 // Note that this function can be called from the item's destructor, so
4924 // do NOT call any virtual functions on it within this block.
4925 if (isSignalConnected(changedSignalIndex) || views.isEmpty()) {
4926 // This block of code is kept for compatibility. Since 4.5, by default
4927 // QGraphicsView does not connect the signal and we use the below
4928 // method of delivering updates.
4933 for (int i = 0; i < views.size(); ++i) {
4934 QGraphicsViewPrivate *viewPrivate = views.at(i)->d_func();
4935 QRect rect = item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport);
4936 rect.translate(viewPrivate->dirtyScrollOffset);
4937 viewPrivate->updateRect(rect);
4942 bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents;
4943 if (!hasNoContents) {
4944 item->d_ptr->dirty = 1;
4946 item->d_ptr->fullUpdatePending = 1;
4947 else if (!item->d_ptr->fullUpdatePending)
4948 item->d_ptr->needsRepaint |= rect;
4949 } else if (item->d_ptr->graphicsEffect) {
4950 invalidateChildren = true;
4953 if (invalidateChildren) {
4954 item->d_ptr->allChildrenDirty = 1;
4955 item->d_ptr->dirtyChildren = 1;
4959 item->d_ptr->ignoreVisible = 1;
4961 item->d_ptr->ignoreOpacity = 1;
4963 if (!updateBoundingRect)
4964 item->d_ptr->markParentDirty();
4967 static inline bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate *item,
4968 const QRectF &rect, bool itemIsUntransformable)
4973 QGraphicsItem *itemq = static_cast<QGraphicsItem *>(item->q_ptr);
4974 QGraphicsView *viewq = static_cast<QGraphicsView *>(view->q_ptr);
4976 if (itemIsUntransformable) {
4977 const QTransform xform = itemq->deviceTransform(viewq->viewportTransform());
4978 if (!item->hasBoundingRegionGranularity)
4979 return view->updateRectF(xform.mapRect(rect));
4980 return view->updateRegion(rect, xform);
4983 if (item->sceneTransformTranslateOnly && view->identityMatrix) {
4984 const qreal dx = item->sceneTransform.dx();
4985 const qreal dy = item->sceneTransform.dy();
4987 r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll());
4988 return view->updateRectF(r);
4991 if (!viewq->isTransformed()) {
4992 if (!item->hasBoundingRegionGranularity)
4993 return view->updateRectF(item->sceneTransform.mapRect(rect));
4994 return view->updateRegion(rect, item->sceneTransform);
4997 QTransform xform = item->sceneTransform;
4998 xform *= viewq->viewportTransform();
4999 if (!item->hasBoundingRegionGranularity)
5000 return view->updateRectF(xform.mapRect(rect));
5001 return view->updateRegion(rect, xform);
5004 void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren,
5005 qreal parentOpacity)
5007 Q_Q(QGraphicsScene);
5009 Q_ASSERT(!updateAll);
5011 if (!item->d_ptr->dirty && !item->d_ptr->dirtyChildren) {
5012 resetDirtyItem(item);
5016 const bool itemIsHidden = !item->d_ptr->ignoreVisible && !item->d_ptr->visible;
5018 resetDirtyItem(item, /*recursive=*/true);
5022 bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
5023 const bool itemHasChildren = !item->d_ptr->children.isEmpty();
5024 if (!itemHasContents) {
5025 if (!itemHasChildren) {
5026 resetDirtyItem(item);
5027 return; // Item has neither contents nor children!(?)
5029 if (item->d_ptr->graphicsEffect)
5030 itemHasContents = true;
5033 const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
5034 const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity
5035 && QGraphicsItemPrivate::isOpacityNull(opacity);
5036 if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) {
5037 resetDirtyItem(item, /*recursive=*/itemHasChildren);
5041 bool wasDirtyParentSceneTransform = item->d_ptr->dirtySceneTransform;
5042 const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
5043 if (wasDirtyParentSceneTransform && !itemIsUntransformable) {
5044 item->d_ptr->updateSceneTransformFromParent();
5045 Q_ASSERT(!item->d_ptr->dirtySceneTransform);
5048 const bool wasDirtyParentViewBoundingRects = item->d_ptr->paintedViewBoundingRectsNeedRepaint;
5049 if (itemIsFullyTransparent || !itemHasContents || dirtyAncestorContainsChildren) {
5050 // Make sure we don't process invisible items or items with no content.
5051 item->d_ptr->dirty = 0;
5052 item->d_ptr->fullUpdatePending = 0;
5053 // Might have a dirty view bounding rect otherwise.
5054 if (itemIsFullyTransparent || !itemHasContents)
5055 item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0;
5058 if (!hasSceneRect && item->d_ptr->geometryChanged && item->d_ptr->visible) {
5059 // Update growingItemsBoundingRect.
5060 if (item->d_ptr->sceneTransformTranslateOnly) {
5061 growingItemsBoundingRect |= item->boundingRect().translated(item->d_ptr->sceneTransform.dx(),
5062 item->d_ptr->sceneTransform.dy());
5064 growingItemsBoundingRect |= item->d_ptr->sceneTransform.mapRect(item->boundingRect());
5069 if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
5070 const bool useCompatUpdate = views.isEmpty() || isSignalConnected(changedSignalIndex);
5071 const QRectF itemBoundingRect = adjustedItemEffectiveBoundingRect(item);
5073 if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) {
5074 // This block of code is kept for compatibility. Since 4.5, by default
5075 // QGraphicsView does not connect the signal and we use the below
5076 // method of delivering updates.
5077 if (item->d_ptr->sceneTransformTranslateOnly) {
5078 q->update(itemBoundingRect.translated(item->d_ptr->sceneTransform.dx(),
5079 item->d_ptr->sceneTransform.dy()));
5081 QRectF rect = item->d_ptr->sceneTransform.mapRect(itemBoundingRect);
5082 if (!rect.isEmpty())
5087 bool uninitializedDirtyRect = true;
5089 for (int j = 0; j < views.size(); ++j) {
5090 QGraphicsView *view = views.at(j);
5091 QGraphicsViewPrivate *viewPrivate = view->d_func();
5092 QRect &paintedViewBoundingRect = item->d_ptr->paintedViewBoundingRects[viewPrivate->viewport];
5093 if (viewPrivate->fullUpdatePending
5094 || viewPrivate->viewportUpdateMode == QGraphicsView::NoViewportUpdate) {
5095 // Okay, if we have a full update pending or no viewport update, this item's
5096 // paintedViewBoundingRect will be updated correctly in the next paintEvent if
5097 // it is inside the viewport, but for now we can pretend that it is outside.
5098 paintedViewBoundingRect = QRect(-1, -1, -1, -1);
5102 if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
5103 paintedViewBoundingRect.translate(viewPrivate->dirtyScrollOffset);
5104 if (!viewPrivate->updateRect(paintedViewBoundingRect))
5105 paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
5108 if (!item->d_ptr->dirty)
5111 if (!item->d_ptr->paintedViewBoundingRectsNeedRepaint
5112 && paintedViewBoundingRect.x() == -1 && paintedViewBoundingRect.y() == -1
5113 && paintedViewBoundingRect.width() == -1 && paintedViewBoundingRect.height() == -1) {
5114 continue; // Outside viewport.
5117 if (uninitializedDirtyRect) {
5118 dirtyRect = itemBoundingRect;
5119 if (!item->d_ptr->fullUpdatePending) {
5120 _q_adjustRect(&item->d_ptr->needsRepaint);
5121 dirtyRect &= item->d_ptr->needsRepaint;
5123 uninitializedDirtyRect = false;
5126 if (dirtyRect.isEmpty())
5127 continue; // Discard updates outside the bounding rect.
5129 if (!updateHelper(viewPrivate, item->d_ptr.data(), dirtyRect, itemIsUntransformable)
5130 && item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
5131 paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
5137 // Process children.
5138 if (itemHasChildren && item->d_ptr->dirtyChildren) {
5139 const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape;
5140 // Items with no content are threated as 'dummy' items which means they are never drawn and
5141 // 'processed', so the painted view bounding rect is never up-to-date. This means that whenever
5142 // such an item changes geometry, its children have to take care of the update regardless
5143 // of whether the item clips children to shape or not.
5144 const bool bypassUpdateClip = !itemHasContents && wasDirtyParentViewBoundingRects;
5145 if (itemClipsChildrenToShape && !bypassUpdateClip) {
5146 // Make sure child updates are clipped to the item's bounding rect.
5147 for (int i = 0; i < views.size(); ++i)
5148 views.at(i)->d_func()->setUpdateClip(item);
5150 if (!dirtyAncestorContainsChildren) {
5151 dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending
5152 && itemClipsChildrenToShape;
5154 const bool allChildrenDirty = item->d_ptr->allChildrenDirty;
5155 const bool parentIgnoresVisible = item->d_ptr->ignoreVisible;
5156 const bool parentIgnoresOpacity = item->d_ptr->ignoreOpacity;
5157 for (int i = 0; i < item->d_ptr->children.size(); ++i) {
5158 QGraphicsItem *child = item->d_ptr->children.at(i);
5159 if (wasDirtyParentSceneTransform)
5160 child->d_ptr->dirtySceneTransform = 1;
5161 if (wasDirtyParentViewBoundingRects)
5162 child->d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
5163 if (parentIgnoresVisible)
5164 child->d_ptr->ignoreVisible = 1;
5165 if (parentIgnoresOpacity)
5166 child->d_ptr->ignoreOpacity = 1;
5167 if (allChildrenDirty) {
5168 child->d_ptr->dirty = 1;
5169 child->d_ptr->fullUpdatePending = 1;
5170 child->d_ptr->dirtyChildren = 1;
5171 child->d_ptr->allChildrenDirty = 1;
5173 processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity);
5176 if (itemClipsChildrenToShape) {
5177 // Reset updateClip.
5178 for (int i = 0; i < views.size(); ++i)
5179 views.at(i)->d_func()->setUpdateClip(0);
5181 } else if (wasDirtyParentSceneTransform) {
5182 item->d_ptr->invalidateChildrenSceneTransform();
5185 resetDirtyItem(item);
5191 Paints the given \a items using the provided \a painter, after the
5192 background has been drawn, and before the foreground has been
5193 drawn. All painting is done in \e scene coordinates. Before
5194 drawing each item, the painter must be transformed using
5195 QGraphicsItem::sceneTransform().
5197 The \a options parameter is the list of style option objects for
5198 each item in \a items. The \a numItems parameter is the number of
5199 items in \a items and options in \a options. The \a widget
5200 parameter is optional; if specified, it should point to the widget
5201 that is being painted on.
5203 The default implementation prepares the painter matrix, and calls
5204 QGraphicsItem::paint() on all items. Reimplement this function to
5205 provide custom painting of all items for the scene; gaining
5206 complete control over how each item is drawn. In some cases this
5207 can increase drawing performance significantly.
5211 \snippet graphicssceneadditemsnippet.cpp 0
5213 Since Qt 4.6, this function is not called anymore unless
5214 the QGraphicsView::IndirectPainting flag is given as an Optimization
5217 \sa drawBackground(), drawForeground()
5219 void QGraphicsScene::drawItems(QPainter *painter,
5221 QGraphicsItem *items[],
5222 const QStyleOptionGraphicsItem options[], QWidget *widget)
5224 Q_D(QGraphicsScene);
5225 // Make sure we don't have unpolished items before we draw.
5226 if (!d->unpolishedItems.isEmpty())
5227 d->_q_polishItems();
5229 const qreal opacity = painter->opacity();
5230 QTransform viewTransform = painter->worldTransform();
5233 // Determine view, expose and flags.
5234 QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
5235 QRegion *expose = 0;
5236 const quint32 oldRectAdjust = d->rectAdjust;
5238 d->updateAll = false;
5239 expose = &view->d_func()->exposedRegion;
5240 if (view->d_func()->optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
5246 // Find all toplevels, they are already sorted.
5247 QList<QGraphicsItem *> topLevelItems;
5248 for (int i = 0; i < numItems; ++i) {
5249 QGraphicsItem *item = items[i]->topLevelItem();
5250 if (!item->d_ptr->itemDiscovered) {
5251 topLevelItems << item;
5252 item->d_ptr->itemDiscovered = 1;
5253 d->drawSubtreeRecursive(item, painter, &viewTransform, expose, widget);
5257 d->rectAdjust = oldRectAdjust;
5258 // Reset discovery bits.
5259 for (int i = 0; i < topLevelItems.size(); ++i)
5260 topLevelItems.at(i)->d_ptr->itemDiscovered = 0;
5262 painter->setWorldTransform(viewTransform);
5263 painter->setOpacity(opacity);
5269 Finds a new widget to give the keyboard focus to, as appropriate for Tab
5270 and Shift+Tab, and returns true if it can find a new widget, or false if
5271 it cannot. If \a next is true, this function searches forward; if \a next
5272 is false, it searches backward.
5274 You can reimplement this function in a subclass of QGraphicsScene to
5275 provide fine-grained control over how tab focus passes inside your
5276 scene. The default implementation is based on the tab focus chain defined
5277 by QGraphicsWidget::setTabOrder().
5279 bool QGraphicsScene::focusNextPrevChild(bool next)
5281 Q_D(QGraphicsScene);
5283 QGraphicsItem *item = focusItem();
5284 if (item && !item->isWidget()) {
5285 // Tab out of the scene.
5289 if (d->lastFocusItem && !d->lastFocusItem->isWidget()) {
5290 // Restore focus to the last focusable non-widget item that had
5292 setFocusItem(d->lastFocusItem, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
5296 if (!d->tabFocusFirst) {
5301 // The item must be a widget.
5302 QGraphicsWidget *widget = 0;
5304 widget = next ? d->tabFocusFirst : d->tabFocusFirst->d_func()->focusPrev;
5306 QGraphicsWidget *test = static_cast<QGraphicsWidget *>(item);
5307 widget = next ? test->d_func()->focusNext : test->d_func()->focusPrev;
5308 if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
5311 QGraphicsWidget *widgetThatHadFocus = widget;
5313 // Run around the focus chain until we find a widget that can take tab focus.
5315 if (widget->flags() & QGraphicsItem::ItemIsFocusable
5316 && widget->isEnabled() && widget->isVisibleTo(0)
5317 && (widget->focusPolicy() & Qt::TabFocus)
5318 && (!item || !item->isPanel() || item->isAncestorOf(widget))
5320 setFocusItem(widget, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
5323 widget = next ? widget->d_func()->focusNext : widget->d_func()->focusPrev;
5324 if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
5326 } while (widget != widgetThatHadFocus);
5332 \fn QGraphicsScene::changed(const QList<QRectF> ®ion)
5334 This signal is emitted by QGraphicsScene when control reaches the
5335 event loop, if the scene content changes. The \a region parameter
5336 contains a list of scene rectangles that indicate the area that
5339 \sa QGraphicsView::updateScene()
5343 \fn QGraphicsScene::sceneRectChanged(const QRectF &rect)
5345 This signal is emitted by QGraphicsScene whenever the scene rect changes.
5346 The \a rect parameter is the new scene rectangle.
5348 \sa QGraphicsView::updateSceneRect()
5352 \fn QGraphicsScene::selectionChanged()
5355 This signal is emitted by QGraphicsScene whenever the selection
5356 changes. You can call selectedItems() to get the new list of selected
5359 The selection changes whenever an item is selected or unselected, a
5360 selection area is set, cleared or otherwise changed, if a preselected item
5361 is added to the scene, or if a selected item is removed from the scene.
5363 QGraphicsScene emits this signal only once for group selection operations.
5364 For example, if you set a selection area, select or unselect a
5365 QGraphicsItemGroup, or if you add or remove from the scene a parent item
5366 that contains several selected items, selectionChanged() is emitted only
5367 once after the operation has completed (instead of once for each item).
5369 \sa setSelectionArea(), selectedItems(), QGraphicsItem::setSelected()
5375 Returns the scene's style, or the same as QApplication::style() if the
5376 scene has not been explicitly assigned a style.
5380 QStyle *QGraphicsScene::style() const
5382 Q_D(const QGraphicsScene);
5383 // ### This function, and the use of styles in general, is non-reentrant.
5384 return d->style ? d->style : QApplication::style();
5390 Sets or replaces the style of the scene to \a style, and reparents the
5391 style to this scene. Any previously assigned style is deleted. The scene's
5392 style defaults to QApplication::style(), and serves as the default for all
5393 QGraphicsWidget items in the scene.
5395 Changing the style, either directly by calling this function, or
5396 indirectly by calling QApplication::setStyle(), will automatically update
5397 the style for all widgets in the scene that do not have a style explicitly
5400 If \a style is 0, QGraphicsScene will revert to QApplication::style().
5404 void QGraphicsScene::setStyle(QStyle *style)
5406 Q_D(QGraphicsScene);
5407 // ### This function, and the use of styles in general, is non-reentrant.
5408 if (style == d->style)
5411 // Delete the old style,
5413 if ((d->style = style))
5414 d->style->setParent(this);
5416 // Notify the scene.
5417 QEvent event(QEvent::StyleChange);
5418 QApplication::sendEvent(this, &event);
5420 // Notify all widgets that don't have a style explicitly set.
5421 foreach (QGraphicsItem *item, items()) {
5422 if (item->isWidget()) {
5423 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
5424 if (!widget->testAttribute(Qt::WA_SetStyle))
5425 QApplication::sendEvent(widget, &event);
5431 \property QGraphicsScene::font
5433 \brief the scene's default font
5435 This property provides the scene's font. The scene font defaults to,
5436 and resolves all its entries from, QApplication::font.
5438 If the scene's font changes, either directly through setFont() or
5439 indirectly when the application font changes, QGraphicsScene first
5440 sends itself a \l{QEvent::FontChange}{FontChange} event, and it then
5441 sends \l{QEvent::FontChange}{FontChange} events to all top-level
5442 widget items in the scene. These items respond by resolving their own
5443 fonts to the scene, and they then notify their children, who again
5444 notify their children, and so on, until all widget items have updated
5447 Changing the scene font, (directly or indirectly through
5448 QApplication::setFont(),) automatically schedules a redraw the entire
5451 \sa QWidget::font, QApplication::setFont(), palette, style()
5453 QFont QGraphicsScene::font() const
5455 Q_D(const QGraphicsScene);
5458 void QGraphicsScene::setFont(const QFont &font)
5460 Q_D(QGraphicsScene);
5461 QFont naturalFont = QApplication::font();
5462 naturalFont.resolve(0);
5463 QFont resolvedFont = font.resolve(naturalFont);
5464 d->setFont_helper(resolvedFont);
5468 \property QGraphicsScene::palette
5470 \brief the scene's default palette
5472 This property provides the scene's palette. The scene palette defaults to,
5473 and resolves all its entries from, QApplication::palette.
5475 If the scene's palette changes, either directly through setPalette() or
5476 indirectly when the application palette changes, QGraphicsScene first
5477 sends itself a \l{QEvent::PaletteChange}{PaletteChange} event, and it then
5478 sends \l{QEvent::PaletteChange}{PaletteChange} events to all top-level
5479 widget items in the scene. These items respond by resolving their own
5480 palettes to the scene, and they then notify their children, who again
5481 notify their children, and so on, until all widget items have updated
5484 Changing the scene palette, (directly or indirectly through
5485 QApplication::setPalette(),) automatically schedules a redraw the entire
5488 \sa QWidget::palette, QApplication::setPalette(), font, style()
5490 QPalette QGraphicsScene::palette() const
5492 Q_D(const QGraphicsScene);
5495 void QGraphicsScene::setPalette(const QPalette &palette)
5497 Q_D(QGraphicsScene);
5498 QPalette naturalPalette = QApplication::palette();
5499 naturalPalette.resolve(0);
5500 QPalette resolvedPalette = palette.resolve(naturalPalette);
5501 d->setPalette_helper(resolvedPalette);
5507 Returns true if the scene is active (e.g., it's viewed by
5508 at least one QGraphicsView that is active); otherwise returns false.
5510 \sa QGraphicsItem::isActive(), QWidget::isActiveWindow()
5512 bool QGraphicsScene::isActive() const
5514 Q_D(const QGraphicsScene);
5515 return d->activationRefCount > 0;
5520 Returns the current active panel, or 0 if no panel is currently active.
5522 \sa QGraphicsScene::setActivePanel()
5524 QGraphicsItem *QGraphicsScene::activePanel() const
5526 Q_D(const QGraphicsScene);
5527 return d->activePanel;
5532 Activates \a item, which must be an item in this scene. You
5533 can also pass 0 for \a item, in which case QGraphicsScene will
5534 deactivate any currently active panel.
5536 If the scene is currently inactive, \a item remains inactive until the
5537 scene becomes active (or, ir \a item is 0, no item will be activated).
5539 \sa activePanel(), isActive(), QGraphicsItem::isActive()
5541 void QGraphicsScene::setActivePanel(QGraphicsItem *item)
5543 Q_D(QGraphicsScene);
5544 d->setActivePanelHelper(item, false);
5550 Returns the current active window, or 0 if no window is currently
5553 \sa QGraphicsScene::setActiveWindow()
5555 QGraphicsWidget *QGraphicsScene::activeWindow() const
5557 Q_D(const QGraphicsScene);
5558 if (d->activePanel && d->activePanel->isWindow())
5559 return static_cast<QGraphicsWidget *>(d->activePanel);
5565 Activates \a widget, which must be a widget in this scene. You can also
5566 pass 0 for \a widget, in which case QGraphicsScene will deactivate any
5567 currently active window.
5569 \sa activeWindow(), QGraphicsWidget::isActiveWindow()
5571 void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
5573 if (widget && widget->scene() != this) {
5574 qWarning("QGraphicsScene::setActiveWindow: widget %p must be part of this scene",
5579 // Activate the widget's panel (all windows are panels).
5580 QGraphicsItem *panel = widget ? widget->panel() : 0;
5581 setActivePanel(panel);
5585 QList<QGraphicsItem *> siblingWindows;
5586 QGraphicsItem *parent = panel->parentItem();
5587 // Raise ### inefficient for toplevels
5588 foreach (QGraphicsItem *sibling, parent ? parent->children() : items()) {
5589 if (sibling != panel && sibling->isWindow())
5590 siblingWindows << sibling;
5593 // Find the highest z value.
5594 qreal z = panel->zValue();
5595 for (int i = 0; i < siblingWindows.size(); ++i)
5596 z = qMax(z, siblingWindows.at(i)->zValue());
5598 // This will probably never overflow.
5599 const qreal litt = qreal(0.001);
5600 panel->setZValue(z + litt);
5607 Sends event \a event to item \a item through possible event filters.
5609 The event is sent only if the item is enabled.
5611 Returns \c false if the event was filtered or if the item is disabled.
5612 Otherwise returns the value that was returned from the event handler.
5614 \sa QGraphicsItem::sceneEvent(), QGraphicsItem::sceneEventFilter()
5616 bool QGraphicsScene::sendEvent(QGraphicsItem *item, QEvent *event)
5618 Q_D(QGraphicsScene);
5620 qWarning("QGraphicsScene::sendEvent: cannot send event to a null item");
5623 if (item->scene() != this) {
5624 qWarning("QGraphicsScene::sendEvent: item %p's scene (%p)"
5625 " is different from this scene (%p)",
5626 item, item->scene(), this);
5629 return d->sendEvent(item, event);
5632 void QGraphicsScenePrivate::addView(QGraphicsView *view)
5635 #ifndef QT_NO_GESTURES
5636 foreach (Qt::GestureType gesture, grabbedGestures.keys())
5637 view->viewport()->grabGesture(gesture);
5641 void QGraphicsScenePrivate::removeView(QGraphicsView *view)
5643 views.removeAll(view);
5646 void QGraphicsScenePrivate::updateTouchPointsForItem(QGraphicsItem *item, QTouchEvent *touchEvent)
5648 QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
5649 for (int i = 0; i < touchPoints.count(); ++i) {
5650 QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
5651 touchPoint.setRect(item->mapFromScene(touchPoint.sceneRect()).boundingRect());
5652 touchPoint.setStartPos(item->d_ptr->genericMapFromScene(touchPoint.startScenePos(), static_cast<QWidget *>(touchEvent->target())));
5653 touchPoint.setLastPos(item->d_ptr->genericMapFromScene(touchPoint.lastScenePos(), static_cast<QWidget *>(touchEvent->target())));
5655 touchEvent->setTouchPoints(touchPoints);
5658 int QGraphicsScenePrivate::findClosestTouchPointId(const QPointF &scenePos)
5660 int closestTouchPointId = -1;
5661 qreal closestDistance = qreal(0.);
5662 foreach (const QTouchEvent::TouchPoint &touchPoint, sceneCurrentTouchPoints) {
5663 qreal distance = QLineF(scenePos, touchPoint.scenePos()).length();
5664 if (closestTouchPointId == -1|| distance < closestDistance) {
5665 closestTouchPointId = touchPoint.id();
5666 closestDistance = distance;
5669 return closestTouchPointId;
5672 void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent)
5674 typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
5675 QHash<QGraphicsItem *, StatesAndTouchPoints> itemsNeedingEvents;
5677 for (int i = 0; i < sceneTouchEvent->touchPoints().count(); ++i) {
5678 const QTouchEvent::TouchPoint &touchPoint = sceneTouchEvent->touchPoints().at(i);
5681 QGraphicsItem *item = 0;
5682 if (touchPoint.state() == Qt::TouchPointPressed) {
5683 if (sceneTouchEvent->device()->type() == QTouchDevice::TouchPad) {
5684 // on touch-pad devices, send all touch points to the same item
5685 item = itemForTouchPointId.isEmpty()
5687 : itemForTouchPointId.constBegin().value();
5691 // determine which item this touch point will go to
5692 cachedItemsUnderMouse = itemsAtPosition(touchPoint.screenPos().toPoint(),
5693 touchPoint.scenePos(),
5694 static_cast<QWidget *>(sceneTouchEvent->target()));
5695 item = cachedItemsUnderMouse.isEmpty() ? 0 : cachedItemsUnderMouse.first();
5698 if (sceneTouchEvent->device()->type() == QTouchDevice::TouchScreen) {
5699 // on touch-screens, combine this touch point with the closest one we find
5700 int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos());
5701 QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId);
5702 if (!item || (closestItem && cachedItemsUnderMouse.contains(closestItem)))
5708 itemForTouchPointId.insert(touchPoint.id(), item);
5709 sceneCurrentTouchPoints.insert(touchPoint.id(), touchPoint);
5710 } else if (touchPoint.state() == Qt::TouchPointReleased) {
5711 item = itemForTouchPointId.take(touchPoint.id());
5715 sceneCurrentTouchPoints.remove(touchPoint.id());
5717 item = itemForTouchPointId.value(touchPoint.id());
5720 Q_ASSERT(sceneCurrentTouchPoints.contains(touchPoint.id()));
5721 sceneCurrentTouchPoints[touchPoint.id()] = touchPoint;
5724 StatesAndTouchPoints &statesAndTouchPoints = itemsNeedingEvents[item];
5725 statesAndTouchPoints.first |= touchPoint.state();
5726 statesAndTouchPoints.second.append(touchPoint);
5729 if (itemsNeedingEvents.isEmpty()) {
5730 sceneTouchEvent->accept();
5734 bool ignoreSceneTouchEvent = true;
5735 QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator it = itemsNeedingEvents.constBegin();
5736 const QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator end = itemsNeedingEvents.constEnd();
5737 for (; it != end; ++it) {
5738 QGraphicsItem *item = it.key();
5740 (void) item->isBlockedByModalPanel(&item);
5742 // determine event type from the state mask
5743 QEvent::Type eventType;
5744 switch (it.value().first) {
5745 case Qt::TouchPointPressed:
5746 // all touch points have pressed state
5747 eventType = QEvent::TouchBegin;
5749 case Qt::TouchPointReleased:
5750 // all touch points have released state
5751 eventType = QEvent::TouchEnd;
5753 case Qt::TouchPointStationary:
5754 // don't send the event if nothing changed
5757 // all other combinations
5758 eventType = QEvent::TouchUpdate;
5762 QTouchEvent touchEvent(eventType);
5763 touchEvent.setWindow(sceneTouchEvent->window());
5764 touchEvent.setTarget(sceneTouchEvent->target());
5765 touchEvent.setDevice(sceneTouchEvent->device());
5766 touchEvent.setModifiers(sceneTouchEvent->modifiers());
5767 touchEvent.setTouchPointStates(it.value().first);
5768 touchEvent.setTouchPoints(it.value().second);
5769 touchEvent.setTimestamp(sceneTouchEvent->timestamp());
5771 switch (touchEvent.type()) {
5772 case QEvent::TouchBegin:
5774 // if the TouchBegin handler recurses, we assume that means the event
5775 // has been implicitly accepted and continue to send touch events
5776 item->d_ptr->acceptedTouchBeginEvent = true;
5777 bool res = sendTouchBeginEvent(item, &touchEvent)
5778 && touchEvent.isAccepted();
5780 // forget about these touch points, we didn't handle them
5781 for (int i = 0; i < touchEvent.touchPoints().count(); ++i) {
5782 const QTouchEvent::TouchPoint &touchPoint = touchEvent.touchPoints().at(i);
5783 itemForTouchPointId.remove(touchPoint.id());
5784 sceneCurrentTouchPoints.remove(touchPoint.id());
5786 ignoreSceneTouchEvent = false;
5791 if (item->d_ptr->acceptedTouchBeginEvent) {
5792 updateTouchPointsForItem(item, &touchEvent);
5793 (void) sendEvent(item, &touchEvent);
5794 ignoreSceneTouchEvent = false;
5799 sceneTouchEvent->setAccepted(ignoreSceneTouchEvent);
5802 bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEvent *touchEvent)
5804 Q_Q(QGraphicsScene);
5806 if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.first() != origin) {
5807 const QTouchEvent::TouchPoint &firstTouchPoint = touchEvent->touchPoints().first();
5808 cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint.screenPos().toPoint(),
5809 firstTouchPoint.scenePos(),
5810 static_cast<QWidget *>(touchEvent->target()));
5812 Q_ASSERT(cachedItemsUnderMouse.first() == origin);
5814 // Set focus on the topmost enabled item that can take focus.
5815 bool setFocus = false;
5817 foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
5818 if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
5819 if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
5821 if (item != q->focusItem())
5822 q->setFocusItem(item, Qt::MouseFocusReason);
5826 if (item->isPanel())
5828 if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
5830 if (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling) {
5831 // Make sure we don't clear focus.
5837 // If nobody could take focus, clear it.
5838 if (!stickyFocus && !setFocus)
5839 q->setFocusItem(0, Qt::MouseFocusReason);
5842 bool eventAccepted = touchEvent->isAccepted();
5843 foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
5844 // first, try to deliver the touch event
5845 updateTouchPointsForItem(item, touchEvent);
5846 bool acceptTouchEvents = item->acceptTouchEvents();
5847 touchEvent->setAccepted(acceptTouchEvents);
5848 res = acceptTouchEvents && sendEvent(item, touchEvent);
5849 eventAccepted = touchEvent->isAccepted();
5850 if (itemForTouchPointId.value(touchEvent->touchPoints().first().id()) == 0) {
5854 item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted);
5856 touchEvent->spont = false;
5857 if (res && eventAccepted) {
5858 // the first item to accept the TouchBegin gets an implicit grab.
5859 for (int i = 0; i < touchEvent->touchPoints().count(); ++i) {
5860 const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i);
5861 itemForTouchPointId[touchPoint.id()] = item; // can be zero
5865 if (item && item->isPanel())
5869 touchEvent->setAccepted(eventAccepted);
5873 void QGraphicsScenePrivate::enableTouchEventsOnViews()
5875 foreach (QGraphicsView *view, views)
5876 view->viewport()->setAttribute(Qt::WA_AcceptTouchEvents, true);
5879 void QGraphicsScenePrivate::updateInputMethodSensitivityInViews()
5881 for (int i = 0; i < views.size(); ++i)
5882 views.at(i)->d_func()->updateInputMethodSensitivity();
5885 void QGraphicsScenePrivate::enterModal(QGraphicsItem *panel, QGraphicsItem::PanelModality previousModality)
5887 Q_Q(QGraphicsScene);
5888 Q_ASSERT(panel && panel->isPanel());
5890 QGraphicsItem::PanelModality panelModality = panel->d_ptr->panelModality;
5891 if (previousModality != QGraphicsItem::NonModal) {
5892 // the panel is changing from one modality type to another... temporarily set it back so
5893 // that blockedPanels is populated correctly
5894 panel->d_ptr->panelModality = previousModality;
5897 QSet<QGraphicsItem *> blockedPanels;
5898 QList<QGraphicsItem *> items = q->items(); // ### store panels separately
5899 for (int i = 0; i < items.count(); ++i) {
5900 QGraphicsItem *item = items.at(i);
5901 if (item->isPanel() && item->isBlockedByModalPanel())
5902 blockedPanels.insert(item);
5904 // blockedPanels contains all currently blocked panels
5906 if (previousModality != QGraphicsItem::NonModal) {
5907 // reset the modality to the proper value, since we changed it above
5908 panel->d_ptr->panelModality = panelModality;
5909 // remove this panel so that it will be reinserted at the front of the stack
5910 modalPanels.removeAll(panel);
5913 modalPanels.prepend(panel);
5915 if (!hoverItems.isEmpty()) {
5916 // send GraphicsSceneHoverLeave events to newly blocked hoverItems
5917 QGraphicsSceneHoverEvent hoverEvent;
5918 hoverEvent.setScenePos(lastSceneMousePos);
5919 dispatchHoverEvent(&hoverEvent);
5922 if (!mouseGrabberItems.isEmpty() && lastMouseGrabberItemHasImplicitMouseGrab) {
5923 QGraphicsItem *item = mouseGrabberItems.last();
5924 if (item->isBlockedByModalPanel())
5925 ungrabMouse(item, /*itemIsDying =*/ false);
5928 QEvent windowBlockedEvent(QEvent::WindowBlocked);
5929 QEvent windowUnblockedEvent(QEvent::WindowUnblocked);
5930 for (int i = 0; i < items.count(); ++i) {
5931 QGraphicsItem *item = items.at(i);
5932 if (item->isPanel()) {
5933 if (!blockedPanels.contains(item) && item->isBlockedByModalPanel()) {
5934 // send QEvent::WindowBlocked to newly blocked panels
5935 sendEvent(item, &windowBlockedEvent);
5936 } else if (blockedPanels.contains(item) && !item->isBlockedByModalPanel()) {
5937 // send QEvent::WindowUnblocked to unblocked panels when downgrading
5938 // a panel from SceneModal to PanelModal
5939 sendEvent(item, &windowUnblockedEvent);
5945 void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel)
5947 Q_Q(QGraphicsScene);
5948 Q_ASSERT(panel && panel->isPanel());
5950 QSet<QGraphicsItem *> blockedPanels;
5951 QList<QGraphicsItem *> items = q->items(); // ### same as above
5952 for (int i = 0; i < items.count(); ++i) {
5953 QGraphicsItem *item = items.at(i);
5954 if (item->isPanel() && item->isBlockedByModalPanel())
5955 blockedPanels.insert(item);
5958 modalPanels.removeAll(panel);
5960 QEvent e(QEvent::WindowUnblocked);
5961 for (int i = 0; i < items.count(); ++i) {
5962 QGraphicsItem *item = items.at(i);
5963 if (item->isPanel() && blockedPanels.contains(item) && !item->isBlockedByModalPanel())
5964 sendEvent(item, &e);
5967 // send GraphicsSceneHoverEnter events to newly unblocked items
5968 QGraphicsSceneHoverEvent hoverEvent;
5969 hoverEvent.setScenePos(lastSceneMousePos);
5970 dispatchHoverEvent(&hoverEvent);
5973 #ifndef QT_NO_GESTURES
5974 void QGraphicsScenePrivate::gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures,
5975 Qt::GestureFlag flag,
5976 QHash<QGraphicsObject *, QSet<QGesture *> > *targets,
5977 QSet<QGraphicsObject *> *itemsSet,
5978 QSet<QGesture *> *normal,
5979 QSet<QGesture *> *conflicts)
5981 QSet<QGesture *> normalGestures; // that are not in conflicted state.
5982 foreach (QGesture *gesture, gestures) {
5983 if (!gesture->hasHotSpot())
5985 const Qt::GestureType gestureType = gesture->gestureType();
5986 QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), gesture->d_func()->sceneHotSpot, 0);
5987 for (int j = 0; j < items.size(); ++j) {
5988 QGraphicsItem *item = items.at(j);
5990 // Check if the item is blocked by a modal panel and use it as
5991 // a target instead of this item.
5992 (void) item->isBlockedByModalPanel(&item);
5994 if (QGraphicsObject *itemobj = item->toGraphicsObject()) {
5995 QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
5996 QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it =
5997 d->gestureContext.constFind(gestureType);
5998 if (it != d->gestureContext.constEnd() && (!flag || (it.value() & flag))) {
5999 if (normalGestures.contains(gesture)) {
6000 normalGestures.remove(gesture);
6002 conflicts->insert(gesture);
6004 normalGestures.insert(gesture);
6007 (*targets)[itemobj].insert(gesture);
6009 (*itemsSet).insert(itemobj);
6012 // Don't propagate through panels.
6013 if (item->isPanel())
6018 *normal = normalGestures;
6021 void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
6023 QWidget *viewport = event->widget();
6026 QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(viewport->parent());
6030 QList<QGesture *> allGestures = event->gestures();
6031 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6032 << "Gestures:" << allGestures;
6034 QSet<QGesture *> startedGestures;
6035 QPoint delta = viewport->mapFromGlobal(QPoint());
6036 QTransform toScene = QTransform::fromTranslate(delta.x(), delta.y())
6037 * graphicsView->viewportTransform().inverted();
6038 foreach (QGesture *gesture, allGestures) {
6039 // cache scene coordinates of the hot spot
6040 if (gesture->hasHotSpot()) {
6041 gesture->d_func()->sceneHotSpot = toScene.map(gesture->hotSpot());
6043 gesture->d_func()->sceneHotSpot = QPointF();
6046 QGraphicsObject *target = gestureTargets.value(gesture, 0);
6048 // when we are not in started mode but don't have a target
6049 // then the only one interested in gesture is the view/scene
6050 if (gesture->state() == Qt::GestureStarted)
6051 startedGestures.insert(gesture);
6055 if (!startedGestures.isEmpty()) {
6056 QSet<QGesture *> normalGestures; // that have just one target
6057 QSet<QGesture *> conflictedGestures; // that have multiple possible targets
6058 gestureTargetsAtHotSpots(startedGestures, Qt::GestureFlag(0), &cachedItemGestures, 0,
6059 &normalGestures, &conflictedGestures);
6060 cachedTargetItems = cachedItemGestures.keys();
6061 qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
6062 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6063 << "Normal gestures:" << normalGestures
6064 << "Conflicting gestures:" << conflictedGestures;
6066 // deliver conflicted gestures as override events AND remember
6067 // initial gesture targets
6068 if (!conflictedGestures.isEmpty()) {
6069 for (int i = 0; i < cachedTargetItems.size(); ++i) {
6070 QWeakPointer<QGraphicsObject> item = cachedTargetItems.at(i);
6072 // get gestures to deliver to the current item
6073 QSet<QGesture *> gestures = conflictedGestures & cachedItemGestures.value(item.data());
6074 if (gestures.isEmpty())
6077 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6078 << "delivering override to"
6079 << item.data() << gestures;
6080 // send gesture override
6081 QGestureEvent ev(gestures.toList());
6082 ev.t = QEvent::GestureOverride;
6083 ev.setWidget(event->widget());
6084 // mark event and individual gestures as ignored
6086 foreach(QGesture *g, gestures)
6087 ev.setAccepted(g, false);
6088 sendEvent(item.data(), &ev);
6089 // mark all accepted gestures to deliver them as normal gesture events
6090 foreach (QGesture *g, gestures) {
6091 if (ev.isAccepted() || ev.isAccepted(g)) {
6092 conflictedGestures.remove(g);
6093 // mark the item as a gesture target
6095 gestureTargets.insert(g, item.data());
6096 QHash<QGraphicsObject *, QSet<QGesture *> >::iterator it, e;
6097 it = cachedItemGestures.begin();
6098 e = cachedItemGestures.end();
6099 for(; it != e; ++it)
6100 it.value().remove(g);
6101 cachedItemGestures[item.data()].insert(g);
6103 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6104 << "override was accepted:"
6105 << g << item.data();
6107 // remember the first item that received the override event
6108 // as it most likely become a target if no one else accepts
6109 // the override event
6110 if (!gestureTargets.contains(g) && item)
6111 gestureTargets.insert(g, item.data());
6114 if (conflictedGestures.isEmpty())
6118 // remember the initial target item for each gesture that was not in
6119 // the conflicted state.
6120 if (!normalGestures.isEmpty()) {
6121 for (int i = 0; i < cachedTargetItems.size() && !normalGestures.isEmpty(); ++i) {
6122 QGraphicsObject *item = cachedTargetItems.at(i);
6124 // get gestures to deliver to the current item
6125 foreach (QGesture *g, cachedItemGestures.value(item)) {
6126 if (!gestureTargets.contains(g)) {
6127 gestureTargets.insert(g, item);
6128 normalGestures.remove(g);
6136 // deliver all gesture events
6137 QSet<QGesture *> undeliveredGestures;
6138 QSet<QGesture *> parentPropagatedGestures;
6139 foreach (QGesture *gesture, allGestures) {
6140 if (QGraphicsObject *target = gestureTargets.value(gesture, 0)) {
6141 cachedItemGestures[target].insert(gesture);
6142 cachedTargetItems.append(target);
6143 undeliveredGestures.insert(gesture);
6144 QGraphicsItemPrivate *d = target->QGraphicsItem::d_func();
6145 const Qt::GestureFlags flags = d->gestureContext.value(gesture->gestureType());
6146 if (flags & Qt::IgnoredGesturesPropagateToParent)
6147 parentPropagatedGestures.insert(gesture);
6149 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6150 << "no target for" << gesture << "at"
6151 << gesture->hotSpot() << gesture->d_func()->sceneHotSpot;
6154 qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
6155 for (int i = 0; i < cachedTargetItems.size(); ++i) {
6156 QWeakPointer<QGraphicsObject> receiver = cachedTargetItems.at(i);
6157 QSet<QGesture *> gestures =
6158 undeliveredGestures & cachedItemGestures.value(receiver.data());
6159 gestures -= cachedAlreadyDeliveredGestures.value(receiver.data());
6161 if (gestures.isEmpty())
6164 cachedAlreadyDeliveredGestures[receiver.data()] += gestures;
6165 const bool isPanel = receiver.data()->isPanel();
6167 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6169 << receiver.data() << gestures;
6170 QGestureEvent ev(gestures.toList());
6171 ev.setWidget(event->widget());
6172 sendEvent(receiver.data(), &ev);
6173 QSet<QGesture *> ignoredGestures;
6174 foreach (QGesture *g, gestures) {
6175 if (!ev.isAccepted() && !ev.isAccepted(g)) {
6176 // if the gesture was ignored by its target, we will update the
6177 // targetItems list with a possible target items (items that
6178 // want to receive partial gestures).
6179 // ### wont' work if the target was destroyed in the event
6180 // we will just stop delivering it.
6181 if (receiver && receiver.data() == gestureTargets.value(g, 0))
6182 ignoredGestures.insert(g);
6184 if (receiver && g->state() == Qt::GestureStarted) {
6185 // someone accepted the propagated initial GestureStarted
6186 // event, let it be the new target for all following events.
6187 gestureTargets[g] = receiver.data();
6189 undeliveredGestures.remove(g);
6192 if (undeliveredGestures.isEmpty())
6195 // ignoredGestures list is only filled when delivering to the gesture
6196 // target item, so it is safe to assume item == target.
6197 if (!ignoredGestures.isEmpty() && !isPanel) {
6198 // look for new potential targets for gestures that were ignored
6199 // and should be propagated.
6201 QSet<QGraphicsObject *> targetsSet = cachedTargetItems.toSet();
6204 // first if the gesture should be propagated to parents only
6205 for (QSet<QGesture *>::iterator it = ignoredGestures.begin();
6206 it != ignoredGestures.end();) {
6207 if (parentPropagatedGestures.contains(*it)) {
6208 QGesture *gesture = *it;
6209 const Qt::GestureType gestureType = gesture->gestureType();
6210 QGraphicsItem *item = receiver.data();
6212 if (QGraphicsObject *obj = item->toGraphicsObject()) {
6213 if (item->d_func()->gestureContext.contains(gestureType)) {
6214 targetsSet.insert(obj);
6215 cachedItemGestures[obj].insert(gesture);
6218 if (item->isPanel())
6220 item = item->parentItem();
6223 it = ignoredGestures.erase(it);
6230 gestureTargetsAtHotSpots(ignoredGestures, Qt::ReceivePartialGestures,
6231 &cachedItemGestures, &targetsSet, 0, 0);
6233 cachedTargetItems = targetsSet.toList();
6234 qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
6235 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6236 << "new targets:" << cachedTargetItems;
6237 i = -1; // start delivery again
6242 foreach (QGesture *g, startedGestures) {
6243 if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
6244 DEBUG() << "lets try to cancel some";
6245 // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
6246 cancelGesturesForChildren(g);
6250 // forget about targets for gestures that have ended
6251 foreach (QGesture *g, allGestures) {
6252 switch (g->state()) {
6253 case Qt::GestureFinished:
6254 case Qt::GestureCanceled:
6255 gestureTargets.remove(g);
6262 cachedTargetItems.clear();
6263 cachedItemGestures.clear();
6264 cachedAlreadyDeliveredGestures.clear();
6267 void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original)
6270 QGraphicsItem *originalItem = gestureTargets.value(original);
6271 if (originalItem == 0) // we only act on accepted gestures, which implies it has a target.
6274 // iterate over all active gestures and for each find the owner
6275 // if the owner is part of our sub-hierarchy, cancel it.
6277 QSet<QGesture *> canceledGestures;
6278 QHash<QGesture *, QGraphicsObject *>::Iterator iter = gestureTargets.begin();
6279 while (iter != gestureTargets.end()) {
6280 QGraphicsObject *item = iter.value();
6281 // note that we don't touch the gestures for our originalItem
6282 if (item != originalItem && originalItem->isAncestorOf(item)) {
6283 DEBUG() << " found a gesture to cancel" << iter.key();
6284 iter.key()->d_func()->state = Qt::GestureCanceled;
6285 canceledGestures << iter.key();
6290 // sort them per target item by cherry picking from almostCanceledGestures and delivering
6291 QSet<QGesture *> almostCanceledGestures = canceledGestures;
6292 QSet<QGesture *>::Iterator setIter;
6293 while (!almostCanceledGestures.isEmpty()) {
6294 QGraphicsObject *target = 0;
6295 QSet<QGesture*> gestures;
6296 setIter = almostCanceledGestures.begin();
6297 // sort per target item
6298 while (setIter != almostCanceledGestures.end()) {
6299 QGraphicsObject *item = gestureTargets.value(*setIter);
6302 if (target == item) {
6303 gestures << *setIter;
6304 setIter = almostCanceledGestures.erase(setIter);
6311 QList<QGesture *> list = gestures.toList();
6312 QGestureEvent ev(list);
6313 sendEvent(target, &ev);
6315 foreach (QGesture *g, list) {
6316 if (ev.isAccepted() || ev.isAccepted(g))
6320 foreach (QGesture *g, gestures) {
6321 if (!g->hasHotSpot())
6324 QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), g->d_func()->sceneHotSpot, 0);
6325 for (int j = 0; j < items.size(); ++j) {
6326 QGraphicsObject *item = items.at(j)->toGraphicsObject();
6329 QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
6330 if (d->gestureContext.contains(g->gestureType())) {
6331 QList<QGesture *> list;
6333 QGestureEvent ev(list);
6334 sendEvent(item, &ev);
6335 if (ev.isAccepted() || ev.isAccepted(g))
6336 break; // successfully delivered
6342 QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
6343 Q_ASSERT(gestureManager); // it would be very odd if we got called without a manager.
6344 for (setIter = canceledGestures.begin(); setIter != canceledGestures.end(); ++setIter) {
6345 gestureManager->recycle(*setIter);
6346 gestureTargets.remove(*setIter);
6350 void QGraphicsScenePrivate::grabGesture(QGraphicsItem *, Qt::GestureType gesture)
6352 (void)QGestureManager::instance(); // create a gesture manager
6353 if (!grabbedGestures[gesture]++) {
6354 foreach (QGraphicsView *view, views)
6355 view->viewport()->grabGesture(gesture);
6359 void QGraphicsScenePrivate::ungrabGesture(QGraphicsItem *item, Qt::GestureType gesture)
6361 // we know this can only be an object
6362 Q_ASSERT(item->d_ptr->isObject);
6363 QGraphicsObject *obj = static_cast<QGraphicsObject *>(item);
6364 QGestureManager::instance()->cleanupCachedGestures(obj, gesture);
6365 if (!--grabbedGestures[gesture]) {
6366 foreach (QGraphicsView *view, views)
6367 view->viewport()->ungrabGesture(gesture);
6370 #endif // QT_NO_GESTURES
6374 #include "moc_qgraphicsscene.cpp"
6376 #endif // QT_NO_GRAPHICSVIEW