summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview/qgraphicsscene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/graphicsview/qgraphicsscene.cpp')
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp6503
1 files changed, 0 insertions, 6503 deletions
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
deleted file mode 100644
index 655725b8e9..0000000000
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ /dev/null
@@ -1,6503 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
- \class QGraphicsScene
- \brief The QGraphicsScene class provides a surface for managing a large
- number of 2D graphical items.
- \since 4.2
- \ingroup graphicsview-api
-
-
- The class serves as a container for QGraphicsItems. It is used together
- with QGraphicsView for visualizing graphical items, such as lines,
- rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is
- part of the \l{Graphics View Framework}.
-
- QGraphicsScene also provides functionality that lets you efficiently
- determine both the location of items, and for determining what items are
- visible within an arbitrary area on the scene. With the QGraphicsView
- widget, you can either visualize the whole scene, or zoom in and view only
- parts of the scene.
-
- Example:
-
- \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 0
-
- Note that QGraphicsScene has no visual appearance of its own; it only
- manages the items. You need to create a QGraphicsView widget to visualize
- the scene.
-
- To add items to a scene, you start off by constructing a QGraphicsScene
- object. Then, you have two options: either add your existing QGraphicsItem
- objects by calling addItem(), or you can call one of the convenience
- functions addEllipse(), addLine(), addPath(), addPixmap(), addPolygon(),
- addRect(), or addText(), which all return a pointer to the newly added item.
- The dimensions of the items added with these functions are relative to the
- item's coordinate system, and the items position is initialized to (0,
- 0) in the scene.
-
- You can then visualize the scene using QGraphicsView. When the scene
- changes, (e.g., when an item moves or is transformed) QGraphicsScene
- emits the changed() signal. To remove an item, call removeItem().
-
- QGraphicsScene uses an indexing algorithm to manage the location of items
- efficiently. By default, a BSP (Binary Space Partitioning) tree is used; an
- algorithm suitable for large scenes where most items remain static (i.e.,
- do not move around). You can choose to disable this index by calling
- setItemIndexMethod(). For more information about the available indexing
- algorithms, see the itemIndexMethod property.
-
- The scene's bounding rect is set by calling setSceneRect(). Items can be
- placed at any position on the scene, and the size of the scene is by
- default unlimited. The scene rect is used only for internal bookkeeping,
- maintaining the scene's item index. If the scene rect is unset,
- QGraphicsScene will use the bounding area of all items, as returned by
- itemsBoundingRect(), as the scene rect. However, itemsBoundingRect() is a
- relatively time consuming function, as it operates by collecting
- positional information for every item on the scene. Because of this, you
- should always set the scene rect when operating on large scenes.
-
- One of QGraphicsScene's greatest strengths is its ability to efficiently
- determine the location of items. Even with millions of items on the scene,
- the items() functions can determine the location of an item within few
- milliseconds. There are several overloads to items(): one that finds items
- at a certain position, one that finds items inside or intersecting with a
- polygon or a rectangle, and more. The list of returned items is sorted by
- stacking order, with the topmost item being the first item in the list.
- For convenience, there is also an itemAt() function that returns the
- topmost item at a given position.
-
- QGraphicsScene maintains selection information for the scene. To select
- items, call setSelectionArea(), and to clear the current selection, call
- clearSelection(). Call selectedItems() to get the list of all selected
- items.
-
- \section1 Event Handling and Propagation
-
- Another responsibility that QGraphicsScene has, is to propagate events
- from QGraphicsView. To send an event to a scene, you construct an event
- that inherits QEvent, and then send it using, for example,
- QApplication::sendEvent(). event() is responsible for dispatching
- the event to the individual items. Some common events are handled by
- convenience event handlers. For example, key press events are handled by
- keyPressEvent(), and mouse press events are handled by mousePressEvent().
-
- Key events are delivered to the \e {focus item}. To set the focus item,
- you can either call setFocusItem(), passing an item that accepts focus, or
- the item itself can call QGraphicsItem::setFocus(). Call focusItem() to
- get the current focus item. For compatibility with widgets, the scene also
- maintains its own focus information. By default, the scene does not have
- focus, and all key events are discarded. If setFocus() is called, or if an
- item on the scene gains focus, the scene automatically gains focus. If the
- scene has focus, hasFocus() will return true, and key events will be
- forwarded to the focus item, if any. If the scene loses focus, (i.e.,
- someone calls clearFocus()) while an item has focus, the scene will
- maintain its item focus information, and once the scene regains focus, it
- will make sure the last focus item regains focus.
-
- For mouse-over effects, QGraphicsScene dispatches \e {hover
- events}. If an item accepts hover events (see
- QGraphicsItem::acceptHoverEvents()), it will receive a \l
- {QEvent::}{GraphicsSceneHoverEnter} event when the mouse enters
- its area. As the mouse continues moving inside the item's area,
- QGraphicsScene will send it \l {QEvent::}{GraphicsSceneHoverMove}
- events. When the mouse leaves the item's area, the item will
- receive a \l {QEvent::}{GraphicsSceneHoverLeave} event.
-
- All mouse events are delivered to the current \e {mouse grabber}
- item. An item becomes the scene's mouse grabber if it accepts
- mouse events (see QGraphicsItem::acceptedMouseButtons()) and it
- receives a mouse press. It stays the mouse grabber until it
- receives a mouse release when no other mouse buttons are
- pressed. You can call mouseGrabberItem() to determine what item is
- currently grabbing the mouse.
-
- \sa QGraphicsItem, QGraphicsView
-*/
-
-/*!
- \enum QGraphicsScene::SceneLayer
- \since 4.3
-
- This enum describes the rendering layers in a QGraphicsScene. When
- QGraphicsScene draws the scene contents, it renders each of these layers
- separately, in order.
-
- Each layer represents a flag that can be OR'ed together when calling
- functions such as invalidate() or QGraphicsView::invalidateScene().
-
- \value ItemLayer The item layer. QGraphicsScene renders all items are in
- this layer by calling the virtual function drawItems(). The item layer is
- drawn after the background layer, but before the foreground layer.
-
- \value BackgroundLayer The background layer. QGraphicsScene renders the
- scene's background in this layer by calling the virtual function
- drawBackground(). The background layer is drawn first of all layers.
-
- \value ForegroundLayer The foreground layer. QGraphicsScene renders the
- scene's foreground in this layer by calling the virtual function
- drawForeground(). The foreground layer is drawn last of all layers.
-
- \value AllLayers All layers; this value represents a combination of all
- three layers.
-
- \sa invalidate(), QGraphicsView::invalidateScene()
-*/
-
-/*!
- \enum QGraphicsScene::ItemIndexMethod
-
- This enum describes the indexing algorithms QGraphicsScene provides for
- managing positional information about items on the scene.
-
- \value BspTreeIndex A Binary Space Partitioning tree is applied. All
- QGraphicsScene's item location algorithms are of an order close to
- logarithmic complexity, by making use of binary search. Adding, moving and
- removing items is logarithmic. This approach is best for static scenes
- (i.e., scenes where most items do not move).
-
- \value NoIndex No index is applied. Item location is of linear complexity,
- as all items on the scene are searched. Adding, moving and removing items,
- however, is done in constant time. This approach is ideal for dynamic
- scenes, where many items are added, moved or removed continuously.
-
- \sa setItemIndexMethod(), bspTreeDepth
-*/
-
-#include "qgraphicsscene.h"
-
-#ifndef QT_NO_GRAPHICSVIEW
-
-#include "qgraphicsitem.h"
-#include "qgraphicsitem_p.h"
-#include "qgraphicslayout.h"
-#include "qgraphicsscene_p.h"
-#include "qgraphicssceneevent.h"
-#include "qgraphicsview.h"
-#include "qgraphicsview_p.h"
-#include "qgraphicswidget.h"
-#include "qgraphicswidget_p.h"
-#include "qgraphicssceneindex_p.h"
-#include "qgraphicsscenebsptreeindex_p.h"
-#include "qgraphicsscenelinearindex_p.h"
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qmath.h>
-#include <QtCore/qrect.h>
-#include <QtCore/qset.h>
-#include <QtCore/qstack.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/QMetaMethod>
-#include <QtGui/qapplication.h>
-#include <QtGui/qdesktopwidget.h>
-#include <QtGui/qevent.h>
-#include <QtGui/qgraphicslayout.h>
-#include <QtGui/qgraphicsproxywidget.h>
-#include <QtGui/qgraphicswidget.h>
-#include <QtGui/qmatrix.h>
-#include <QtGui/qpaintengine.h>
-#include <QtGui/qpainter.h>
-#include <QtGui/qpixmapcache.h>
-#include <QtGui/qpolygon.h>
-#include <QtGui/qstyleoption.h>
-#include <QtGui/qtooltip.h>
-#include <QtGui/qtransform.h>
-#include <QtGui/qinputcontext.h>
-#include <QtGui/qgraphicseffect.h>
-#ifndef QT_NO_ACCESSIBILITY
-# include <QtGui/qaccessible.h>
-#endif
-
-#include <private/qapplication_p.h>
-#include <private/qobject_p.h>
-#ifdef Q_WS_X11
-#include <private/qt_x11_p.h>
-#endif
-#include <private/qgraphicseffect_p.h>
-#include <private/qgesturemanager_p.h>
-#include <private/qpathclipper_p.h>
-
-// #define GESTURE_DEBUG
-#ifndef GESTURE_DEBUG
-# define DEBUG if (0) qDebug
-#else
-# define DEBUG qDebug
-#endif
-
-QT_BEGIN_NAMESPACE
-
-bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
-
-static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent)
-{
- hover->setWidget(mouseEvent->widget());
- hover->setPos(mouseEvent->pos());
- hover->setScenePos(mouseEvent->scenePos());
- hover->setScreenPos(mouseEvent->screenPos());
- hover->setLastPos(mouseEvent->lastPos());
- hover->setLastScenePos(mouseEvent->lastScenePos());
- hover->setLastScreenPos(mouseEvent->lastScreenPos());
- hover->setModifiers(mouseEvent->modifiers());
- hover->setAccepted(mouseEvent->isAccepted());
-}
-
-/*!
- \internal
-*/
-QGraphicsScenePrivate::QGraphicsScenePrivate()
- : indexMethod(QGraphicsScene::BspTreeIndex),
- index(0),
- lastItemCount(0),
- hasSceneRect(false),
- dirtyGrowingItemsBoundingRect(true),
- updateAll(false),
- calledEmitUpdated(false),
- processDirtyItemsEmitted(false),
- needSortTopLevelItems(true),
- holesInTopLevelSiblingIndex(false),
- topLevelSequentialOrdering(true),
- scenePosDescendantsUpdatePending(false),
- stickyFocus(false),
- hasFocus(false),
- lastMouseGrabberItemHasImplicitMouseGrab(false),
- allItemsIgnoreHoverEvents(true),
- allItemsUseDefaultCursor(true),
- painterStateProtection(true),
- sortCacheEnabled(false),
- allItemsIgnoreTouchEvents(true),
- selectionChanging(0),
- rectAdjust(2),
- focusItem(0),
- lastFocusItem(0),
- passiveFocusItem(0),
- tabFocusFirst(0),
- activePanel(0),
- lastActivePanel(0),
- activationRefCount(0),
- childExplicitActivation(0),
- lastMouseGrabberItem(0),
- dragDropItem(0),
- enterWidget(0),
- lastDropAction(Qt::IgnoreAction),
- style(0)
-{
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::init()
-{
- Q_Q(QGraphicsScene);
-
- index = new QGraphicsSceneBspTreeIndex(q);
-
- // Keep this index so we can check for connected slots later on.
- changedSignalIndex = signalIndex("changed(QList<QRectF>)");
- processDirtyItemsIndex = q->metaObject()->indexOfSlot("_q_processDirtyItems()");
- polishItemsIndex = q->metaObject()->indexOfSlot("_q_polishItems()");
-
- qApp->d_func()->scene_list.append(q);
- q->update();
-}
-
-/*!
- \internal
-*/
-QGraphicsScenePrivate *QGraphicsScenePrivate::get(QGraphicsScene *q)
-{
- return q->d_func();
-}
-
-void QGraphicsScenePrivate::_q_emitUpdated()
-{
- Q_Q(QGraphicsScene);
- calledEmitUpdated = false;
-
- if (dirtyGrowingItemsBoundingRect) {
- if (!hasSceneRect) {
- const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
- growingItemsBoundingRect |= q->itemsBoundingRect();
- if (oldGrowingItemsBoundingRect != growingItemsBoundingRect)
- emit q->sceneRectChanged(growingItemsBoundingRect);
- }
- dirtyGrowingItemsBoundingRect = false;
- }
-
- // Ensure all views are connected if anything is connected. This disables
- // the optimization that items send updates directly to the views, but it
- // needs to happen in order to keep compatibility with the behavior from
- // Qt 4.4 and backward.
- if (isSignalConnected(changedSignalIndex)) {
- for (int i = 0; i < views.size(); ++i) {
- QGraphicsView *view = views.at(i);
- if (!view->d_func()->connectedToScene) {
- view->d_func()->connectedToScene = true;
- q->connect(q, SIGNAL(changed(QList<QRectF>)),
- views.at(i), SLOT(updateScene(QList<QRectF>)));
- }
- }
- } else {
- if (views.isEmpty()) {
- updateAll = false;
- return;
- }
- for (int i = 0; i < views.size(); ++i)
- views.at(i)->d_func()->processPendingUpdates();
- // It's important that we update all views before we dispatch, hence two for-loops.
- for (int i = 0; i < views.size(); ++i)
- views.at(i)->d_func()->dispatchPendingUpdateRequests();
- return;
- }
-
- // Notify the changes to anybody interested.
- QList<QRectF> oldUpdatedRects;
- oldUpdatedRects = updateAll ? (QList<QRectF>() << q->sceneRect()) : updatedRects;
- updateAll = false;
- updatedRects.clear();
- emit q->changed(oldUpdatedRects);
-}
-
-/*!
- \internal
-
- ### This function is almost identical to QGraphicsItemPrivate::addChild().
-*/
-void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item)
-{
- item->d_ptr->ensureSequentialSiblingIndex();
- needSortTopLevelItems = true; // ### maybe false
- item->d_ptr->siblingIndex = topLevelItems.size();
- topLevelItems.append(item);
-}
-
-/*!
- \internal
-
- ### This function is almost identical to QGraphicsItemPrivate::removeChild().
-*/
-void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item)
-{
- if (!holesInTopLevelSiblingIndex)
- holesInTopLevelSiblingIndex = item->d_ptr->siblingIndex != topLevelItems.size() - 1;
- if (topLevelSequentialOrdering && !holesInTopLevelSiblingIndex)
- topLevelItems.removeAt(item->d_ptr->siblingIndex);
- else
- topLevelItems.removeOne(item);
- // NB! Do not use topLevelItems.removeAt(item->d_ptr->siblingIndex) because
- // the item is not guaranteed to be at the index after the list is sorted
- // (see ensureSortedTopLevelItems()).
- item->d_ptr->siblingIndex = -1;
- if (topLevelSequentialOrdering)
- topLevelSequentialOrdering = !holesInTopLevelSiblingIndex;
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::_q_polishItems()
-{
- if (unpolishedItems.isEmpty())
- return;
-
- const QVariant booleanTrueVariant(true);
- QGraphicsItem *item = 0;
- QGraphicsItemPrivate *itemd = 0;
- const int oldUnpolishedCount = unpolishedItems.count();
-
- for (int i = 0; i < oldUnpolishedCount; ++i) {
- item = unpolishedItems.at(i);
- if (!item)
- continue;
- itemd = item->d_ptr.data();
- itemd->pendingPolish = false;
- if (!itemd->explicitlyHidden) {
- item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant);
- item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant);
- }
- if (itemd->isWidget) {
- QEvent event(QEvent::Polish);
- QApplication::sendEvent((QGraphicsWidget *)item, &event);
- }
- }
-
- if (unpolishedItems.count() == oldUnpolishedCount) {
- // No new items were added to the vector.
- unpolishedItems.clear();
- } else {
- // New items were appended; keep them and remove the old ones.
- unpolishedItems.remove(0, oldUnpolishedCount);
- unpolishedItems.squeeze();
- QMetaObject::invokeMethod(q_ptr, "_q_polishItems", Qt::QueuedConnection);
- }
-}
-
-void QGraphicsScenePrivate::_q_processDirtyItems()
-{
- processDirtyItemsEmitted = false;
-
- if (updateAll) {
- Q_ASSERT(calledEmitUpdated);
- // No need for further processing (except resetting the dirty states).
- // The growingItemsBoundingRect is updated in _q_emitUpdated.
- for (int i = 0; i < topLevelItems.size(); ++i)
- resetDirtyItem(topLevelItems.at(i), /*recursive=*/true);
- return;
- }
-
- const bool wasPendingSceneUpdate = calledEmitUpdated;
- const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
-
- // Process items recursively.
- for (int i = 0; i < topLevelItems.size(); ++i)
- processDirtyItemsRecursive(topLevelItems.at(i));
-
- dirtyGrowingItemsBoundingRect = false;
- if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect)
- emit q_func()->sceneRectChanged(growingItemsBoundingRect);
-
- if (wasPendingSceneUpdate)
- return;
-
- for (int i = 0; i < views.size(); ++i)
- views.at(i)->d_func()->processPendingUpdates();
-
- if (calledEmitUpdated) {
- // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive
- // and we cannot wait for the control to reach the eventloop before the
- // changed signal is emitted, so we emit it now.
- _q_emitUpdated();
- }
-
- // Immediately dispatch all pending update requests on the views.
- for (int i = 0; i < views.size(); ++i)
- views.at(i)->d_func()->dispatchPendingUpdateRequests();
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::setScenePosItemEnabled(QGraphicsItem *item, bool enabled)
-{
- QGraphicsItem *p = item->d_ptr->parent;
- while (p) {
- p->d_ptr->scenePosDescendants = enabled;
- p = p->d_ptr->parent;
- }
- if (!enabled && !scenePosDescendantsUpdatePending) {
- scenePosDescendantsUpdatePending = true;
- QMetaObject::invokeMethod(q_func(), "_q_updateScenePosDescendants", Qt::QueuedConnection);
- }
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::registerScenePosItem(QGraphicsItem *item)
-{
- scenePosItems.insert(item);
- setScenePosItemEnabled(item, true);
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::unregisterScenePosItem(QGraphicsItem *item)
-{
- scenePosItems.remove(item);
- setScenePosItemEnabled(item, false);
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::_q_updateScenePosDescendants()
-{
- foreach (QGraphicsItem *item, scenePosItems) {
- QGraphicsItem *p = item->d_ptr->parent;
- while (p) {
- p->d_ptr->scenePosDescendants = 1;
- p = p->d_ptr->parent;
- }
- }
- scenePosDescendantsUpdatePending = false;
-}
-
-/*!
- \internal
-
- Schedules an item for removal. This function leaves some stale indexes
- around in the BSP tree if called from the item's destructor; these will
- be cleaned up the next time someone triggers purgeRemovedItems().
-
- Note: This function might get called from QGraphicsItem's destructor. \a item is
- being destroyed, so we cannot call any pure virtual functions on it (such
- as boundingRect()). Also, it is unnecessary to update the item's own state
- in any way.
-*/
-void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
-{
- Q_Q(QGraphicsScene);
-
- // Clear focus on the item to remove any reference in the focusWidget chain.
- item->clearFocus();
-
- markDirty(item, QRectF(), /*invalidateChildren=*/false, /*force=*/false,
- /*ignoreOpacity=*/false, /*removingItemFromScene=*/true);
-
- if (item->d_ptr->inDestructor) {
- // The item is actually in its destructor, we call the special method in the index.
- index->deleteItem(item);
- } else {
- // Can potentially call item->boundingRect() (virtual function), that's why
- // we only can call this function if the item is not in its destructor.
- index->removeItem(item);
- }
-
- item->d_ptr->clearSubFocus();
-
- if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges)
- unregisterScenePosItem(item);
-
- QGraphicsScene *oldScene = item->d_func()->scene;
- item->d_func()->scene = 0;
-
- //We need to remove all children first because they might use their parent
- //attributes (e.g. sceneTransform).
- if (!item->d_ptr->inDestructor) {
- // Remove all children recursively
- for (int i = 0; i < item->d_ptr->children.size(); ++i)
- q->removeItem(item->d_ptr->children.at(i));
- }
-
- if (!item->d_ptr->inDestructor && item == tabFocusFirst) {
- QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
- widget->d_func()->fixFocusChainBeforeReparenting(0, oldScene, 0);
- }
-
- // Unregister focus proxy.
- item->d_ptr->resetFocusProxy();
-
- // Remove from parent, or unregister from toplevels.
- if (QGraphicsItem *parentItem = item->parentItem()) {
- if (parentItem->scene()) {
- Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem",
- "Parent item's scene is different from this item's scene");
- item->setParentItem(0);
- }
- } else {
- unregisterTopLevelItem(item);
- }
-
- // Reset the mouse grabber and focus item data.
- if (item == focusItem)
- focusItem = 0;
- if (item == lastFocusItem)
- lastFocusItem = 0;
- if (item == passiveFocusItem)
- passiveFocusItem = 0;
- if (item == activePanel) {
- // ### deactivate...
- activePanel = 0;
- }
- if (item == lastActivePanel)
- lastActivePanel = 0;
-
- // Cancel active touches
- {
- QMap<int, QGraphicsItem *>::iterator it = itemForTouchPointId.begin();
- while (it != itemForTouchPointId.end()) {
- if (it.value() == item) {
- sceneCurrentTouchPoints.remove(it.key());
- it = itemForTouchPointId.erase(it);
- } else {
- ++it;
- }
- }
- }
-
- // Disable selectionChanged() for individual items
- ++selectionChanging;
- int oldSelectedItemsSize = selectedItems.size();
-
- // Update selected & hovered item bookkeeping
- selectedItems.remove(item);
- hoverItems.removeAll(item);
- cachedItemsUnderMouse.removeAll(item);
- if (item->d_ptr->pendingPolish) {
- const int unpolishedIndex = unpolishedItems.indexOf(item);
- if (unpolishedIndex != -1)
- unpolishedItems[unpolishedIndex] = 0;
- item->d_ptr->pendingPolish = false;
- }
- resetDirtyItem(item);
-
- //We remove all references of item from the sceneEventFilter arrays
- QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin();
- while (iterator != sceneEventFilters.end()) {
- if (iterator.value() == item || iterator.key() == item)
- iterator = sceneEventFilters.erase(iterator);
- else
- ++iterator;
- }
-
- if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
- leaveModal(item);
-
- // Reset the mouse grabber and focus item data.
- if (mouseGrabberItems.contains(item))
- ungrabMouse(item, /* item is dying */ item->d_ptr->inDestructor);
-
- // Reset the keyboard grabber
- if (keyboardGrabberItems.contains(item))
- ungrabKeyboard(item, /* item is dying */ item->d_ptr->inDestructor);
-
- // Reset the last mouse grabber item
- if (item == lastMouseGrabberItem)
- lastMouseGrabberItem = 0;
-
- // Reset the current drop item
- if (item == dragDropItem)
- dragDropItem = 0;
-
- // Reenable selectionChanged() for individual items
- --selectionChanging;
- if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize)
- emit q->selectionChanged();
-
-#ifndef QT_NO_GESTURES
- QHash<QGesture *, QGraphicsObject *>::iterator it;
- for (it = gestureTargets.begin(); it != gestureTargets.end();) {
- if (it.value() == item)
- it = gestureTargets.erase(it);
- else
- ++it;
- }
-
- QGraphicsObject *dummy = static_cast<QGraphicsObject *>(item);
- cachedTargetItems.removeOne(dummy);
- cachedItemGestures.remove(dummy);
- cachedAlreadyDeliveredGestures.remove(dummy);
-
- foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys())
- ungrabGesture(item, gesture);
-#endif // QT_NO_GESTURES
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent)
-{
- Q_Q(QGraphicsScene);
- if (item && item->scene() != q) {
- qWarning("QGraphicsScene::setActivePanel: item %p must be part of this scene",
- item);
- return;
- }
-
- // Ensure the scene has focus when we change panel activation.
- q->setFocus(Qt::ActiveWindowFocusReason);
-
- // Find the item's panel.
- QGraphicsItem *panel = item ? item->panel() : 0;
- lastActivePanel = panel ? activePanel : 0;
- if (panel == activePanel || (!q->isActive() && !duringActivationEvent))
- return;
-
- // Deactivate the last active panel.
- if (activePanel) {
- if (QGraphicsItem *fi = activePanel->focusItem()) {
- // Remove focus from the current focus item.
- if (fi == q->focusItem())
- q->setFocusItem(0, Qt::ActiveWindowFocusReason);
- }
-
- QEvent event(QEvent::WindowDeactivate);
- q->sendEvent(activePanel, &event);
- } else if (panel && !duringActivationEvent) {
- // Deactivate the scene if changing activation to a panel.
- QEvent event(QEvent::WindowDeactivate);
- foreach (QGraphicsItem *item, q->items()) {
- if (item->isVisible() && !item->isPanel() && !item->parentItem())
- q->sendEvent(item, &event);
- }
- }
-
- // Update activate state.
- activePanel = panel;
- QEvent event(QEvent::ActivationChange);
- QApplication::sendEvent(q, &event);
-
- // Activate
- if (panel) {
- QEvent event(QEvent::WindowActivate);
- q->sendEvent(panel, &event);
-
- // Set focus on the panel's focus item.
- if (QGraphicsItem *focusItem = panel->focusItem())
- focusItem->setFocus(Qt::ActiveWindowFocusReason);
- } else if (q->isActive()) {
- // Activate the scene
- QEvent event(QEvent::WindowActivate);
- foreach (QGraphicsItem *item, q->items()) {
- if (item->isVisible() && !item->isPanel() && !item->parentItem())
- q->sendEvent(item, &event);
- }
- }
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item,
- Qt::FocusReason focusReason)
-{
- Q_Q(QGraphicsScene);
- if (item == focusItem)
- return;
-
- // Clear focus if asked to set focus on something that can't
- // accept input focus.
- if (item && (!(item->flags() & QGraphicsItem::ItemIsFocusable)
- || !item->isVisible() || !item->isEnabled())) {
- item = 0;
- }
-
- // Set focus on the scene if an item requests focus.
- if (item) {
- q->setFocus(focusReason);
- if (item == focusItem)
- return;
- }
-
- if (focusItem) {
- lastFocusItem = focusItem;
-
-#ifndef QT_NO_IM
- if (lastFocusItem
- && (lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod)) {
- // Close any external input method panel. This happens
- // automatically by removing WA_InputMethodEnabled on
- // the views, but if we are changing focus, we have to
- // do it ourselves.
- for (int i = 0; i < views.size(); ++i)
- if (views.at(i)->inputContext())
- views.at(i)->inputContext()->reset();
- }
-
- focusItem = 0;
- QFocusEvent event(QEvent::FocusOut, focusReason);
- sendEvent(lastFocusItem, &event);
-#endif //QT_NO_IM
- }
-
- // This handles the case that the item has been removed from the
- // scene in response to the FocusOut event.
- if (item && item->scene() != q)
- item = 0;
-
- if (item)
- focusItem = item;
- updateInputMethodSensitivityInViews();
-
-#ifndef QT_NO_ACCESSIBILITY
- if (focusItem) {
- if (QGraphicsObject *focusObj = focusItem->toGraphicsObject()) {
- QAccessible::updateAccessibility(focusObj, 0, QAccessible::Focus);
- }
- }
-#endif
- if (item) {
- QFocusEvent event(QEvent::FocusIn, focusReason);
- sendEvent(item, &event);
- }
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::addPopup(QGraphicsWidget *widget)
-{
- Q_ASSERT(widget);
- Q_ASSERT(!popupWidgets.contains(widget));
- popupWidgets << widget;
- if (QGraphicsWidget *focusWidget = widget->focusWidget()) {
- focusWidget->setFocus(Qt::PopupFocusReason);
- } else {
- grabKeyboard((QGraphicsItem *)widget);
- if (focusItem && popupWidgets.size() == 1) {
- QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
- sendEvent(focusItem, &event);
- }
- }
- grabMouse((QGraphicsItem *)widget);
-}
-
-/*!
- \internal
-
- Remove \a widget from the popup list. Important notes:
-
- \a widget is guaranteed to be in the list of popups, but it might not be
- the last entry; you can hide any item in the pop list before the others,
- and this must cause all later mouse grabbers to lose the grab.
-*/
-void QGraphicsScenePrivate::removePopup(QGraphicsWidget *widget, bool itemIsDying)
-{
- Q_ASSERT(widget);
- int index = popupWidgets.indexOf(widget);
- Q_ASSERT(index != -1);
-
- for (int i = popupWidgets.size() - 1; i >= index; --i) {
- QGraphicsWidget *widget = popupWidgets.takeLast();
- ungrabMouse(widget, itemIsDying);
- if (focusItem && popupWidgets.isEmpty()) {
- QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
- sendEvent(focusItem, &event);
- } else if (keyboardGrabberItems.contains(static_cast<QGraphicsItem *>(widget))) {
- ungrabKeyboard(static_cast<QGraphicsItem *>(widget), itemIsDying);
- }
- if (!itemIsDying && widget->isVisible()) {
- widget->QGraphicsItem::d_ptr->setVisibleHelper(false, /* explicit = */ false);
- }
- }
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::grabMouse(QGraphicsItem *item, bool implicit)
-{
- // Append to list of mouse grabber items, and send a mouse grab event.
- if (mouseGrabberItems.contains(item)) {
- if (mouseGrabberItems.last() == item) {
- Q_ASSERT(!implicit);
- if (!lastMouseGrabberItemHasImplicitMouseGrab) {
- qWarning("QGraphicsItem::grabMouse: already a mouse grabber");
- } else {
- // Upgrade to an explicit mouse grab
- lastMouseGrabberItemHasImplicitMouseGrab = false;
- }
- } else {
- qWarning("QGraphicsItem::grabMouse: already blocked by mouse grabber: %p",
- mouseGrabberItems.last());
- }
- return;
- }
-
- // Send ungrab event to the last grabber.
- if (!mouseGrabberItems.isEmpty()) {
- QGraphicsItem *last = mouseGrabberItems.last();
- if (lastMouseGrabberItemHasImplicitMouseGrab) {
- // Implicit mouse grab is immediately lost.
- last->ungrabMouse();
- } else {
- // Just send ungrab event to current grabber.
- QEvent ungrabEvent(QEvent::UngrabMouse);
- sendEvent(last, &ungrabEvent);
- }
- }
-
- mouseGrabberItems << item;
- lastMouseGrabberItemHasImplicitMouseGrab = implicit;
-
- // Send grab event to current grabber.
- QEvent grabEvent(QEvent::GrabMouse);
- sendEvent(item, &grabEvent);
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::ungrabMouse(QGraphicsItem *item, bool itemIsDying)
-{
- int index = mouseGrabberItems.indexOf(item);
- if (index == -1) {
- qWarning("QGraphicsItem::ungrabMouse: not a mouse grabber");
- return;
- }
-
- if (item != mouseGrabberItems.last()) {
- // Recursively ungrab the next mouse grabber until we reach this item
- // to ensure state consistency.
- ungrabMouse(mouseGrabberItems.at(index + 1), itemIsDying);
- }
- if (!popupWidgets.isEmpty() && item == popupWidgets.last()) {
- // If the item is a popup, go via removePopup to ensure state
- // consistency and that it gets hidden correctly - beware that
- // removePopup() reenters this function to continue removing the grab.
- removePopup((QGraphicsWidget *)item, itemIsDying);
- return;
- }
-
- // Send notification about mouse ungrab.
- if (!itemIsDying) {
- QEvent event(QEvent::UngrabMouse);
- sendEvent(item, &event);
- }
-
- // Remove the item from the list of grabbers. Whenever this happens, we
- // reset the implicitGrab (there can be only ever be one implicit grabber
- // in a scene, and it is always the latest grabber; if the implicit grab
- // is lost, it is not automatically regained.
- mouseGrabberItems.takeLast();
- lastMouseGrabberItemHasImplicitMouseGrab = false;
-
- // Send notification about mouse regrab. ### It's unfortunate that all the
- // items get a GrabMouse event, but this is a rare case with a simple
- // implementation and it does ensure a consistent state.
- if (!itemIsDying && !mouseGrabberItems.isEmpty()) {
- QGraphicsItem *last = mouseGrabberItems.last();
- QEvent event(QEvent::GrabMouse);
- sendEvent(last, &event);
- }
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::clearMouseGrabber()
-{
- if (!mouseGrabberItems.isEmpty())
- mouseGrabberItems.first()->ungrabMouse();
- lastMouseGrabberItem = 0;
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::grabKeyboard(QGraphicsItem *item)
-{
- if (keyboardGrabberItems.contains(item)) {
- if (keyboardGrabberItems.last() == item)
- qWarning("QGraphicsItem::grabKeyboard: already a keyboard grabber");
- else
- qWarning("QGraphicsItem::grabKeyboard: already blocked by keyboard grabber: %p",
- keyboardGrabberItems.last());
- return;
- }
-
- // Send ungrab event to the last grabber.
- if (!keyboardGrabberItems.isEmpty()) {
- // Just send ungrab event to current grabber.
- QEvent ungrabEvent(QEvent::UngrabKeyboard);
- sendEvent(keyboardGrabberItems.last(), &ungrabEvent);
- }
-
- keyboardGrabberItems << item;
-
- // Send grab event to current grabber.
- QEvent grabEvent(QEvent::GrabKeyboard);
- sendEvent(item, &grabEvent);
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::ungrabKeyboard(QGraphicsItem *item, bool itemIsDying)
-{
- int index = keyboardGrabberItems.lastIndexOf(item);
- if (index == -1) {
- qWarning("QGraphicsItem::ungrabKeyboard: not a keyboard grabber");
- return;
- }
- if (item != keyboardGrabberItems.last()) {
- // Recursively ungrab the topmost keyboard grabber until we reach this
- // item to ensure state consistency.
- ungrabKeyboard(keyboardGrabberItems.at(index + 1), itemIsDying);
- }
-
- // Send notification about keyboard ungrab.
- if (!itemIsDying) {
- QEvent event(QEvent::UngrabKeyboard);
- sendEvent(item, &event);
- }
-
- // Remove the item from the list of grabbers.
- keyboardGrabberItems.takeLast();
-
- // Send notification about mouse regrab.
- if (!itemIsDying && !keyboardGrabberItems.isEmpty()) {
- QGraphicsItem *last = keyboardGrabberItems.last();
- QEvent event(QEvent::GrabKeyboard);
- sendEvent(last, &event);
- }
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::clearKeyboardGrabber()
-{
- if (!keyboardGrabberItems.isEmpty())
- ungrabKeyboard(keyboardGrabberItems.first());
-}
-
-void QGraphicsScenePrivate::enableMouseTrackingOnViews()
-{
- foreach (QGraphicsView *view, views)
- view->viewport()->setMouseTracking(true);
-}
-
-/*!
- Returns all items for the screen position in \a event.
-*/
-QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &/*screenPos*/,
- const QPointF &scenePos,
- QWidget *widget) const
-{
- Q_Q(const QGraphicsScene);
- QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
- if (!view)
- return q->items(scenePos, Qt::IntersectsItemShape, Qt::DescendingOrder, QTransform());
-
- const QRectF pointRect(scenePos, QSizeF(1, 1));
- if (!view->isTransformed())
- return q->items(pointRect, Qt::IntersectsItemShape, Qt::DescendingOrder);
-
- const QTransform viewTransform = view->viewportTransform();
- return q->items(pointRect, Qt::IntersectsItemShape,
- Qt::DescendingOrder, viewTransform);
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event)
-{
- for (int i = 0x1; i <= 0x10; i <<= 1) {
- if (event->buttons() & i) {
- mouseGrabberButtonDownPos.insert(Qt::MouseButton(i),
- mouseGrabberItems.last()->d_ptr->genericMapFromScene(event->scenePos(),
- event->widget()));
- mouseGrabberButtonDownScenePos.insert(Qt::MouseButton(i), event->scenePos());
- mouseGrabberButtonDownScreenPos.insert(Qt::MouseButton(i), event->screenPos());
- }
- }
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
-{
- sceneEventFilters.insert(watched, filter);
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
-{
- if (!sceneEventFilters.contains(watched))
- return;
-
- QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(watched);
- QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(watched);
- do {
- if (it.value() == filter)
- it = sceneEventFilters.erase(it);
- else
- ++it;
- } while (it != end);
-}
-
-/*!
- \internal
-*/
-bool QGraphicsScenePrivate::filterDescendantEvent(QGraphicsItem *item, QEvent *event)
-{
- if (item && (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents)) {
- QGraphicsItem *parent = item->parentItem();
- while (parent) {
- if (parent->d_ptr->filtersDescendantEvents && parent->sceneEventFilter(item, event))
- return true;
- if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents))
- return false;
- parent = parent->parentItem();
- }
- }
- return false;
-}
-
-/*!
- \internal
-*/
-bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event)
-{
- if (item && !sceneEventFilters.contains(item))
- return false;
-
- QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(item);
- QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(item);
- while (it != end) {
- // ### The filterer and filteree might both be deleted.
- if (it.value()->sceneEventFilter(it.key(), event))
- return true;
- ++it;
- }
- return false;
-}
-
-/*!
- \internal
-
- This is the final dispatch point for any events from the scene to the
- item. It filters the event first - if the filter returns true, the event
- is considered to have been eaten by the filter, and is therefore stopped
- (the default filter returns false). Then/otherwise, if the item is
- enabled, the event is sent; otherwise it is stopped.
-*/
-bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
-{
- if (QGraphicsObject *object = item->toGraphicsObject()) {
-#ifndef QT_NO_GESTURES
- QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
- if (gestureManager) {
- if (gestureManager->filterEvent(object, event))
- return true;
- }
-#endif // QT_NO_GESTURES
- }
-
- if (filterEvent(item, event))
- return false;
- if (filterDescendantEvent(item, event))
- return false;
- if (!item || !item->isEnabled())
- return false;
- if (QGraphicsObject *o = item->toGraphicsObject()) {
- bool spont = event->spontaneous();
- if (spont ? qt_sendSpontaneousEvent(o, event) : QApplication::sendEvent(o, event))
- return true;
- event->spont = spont;
- }
- return item->sceneEvent(event);
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::cloneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
- QGraphicsSceneDragDropEvent *source)
-{
- dest->setWidget(source->widget());
- dest->setPos(source->pos());
- dest->setScenePos(source->scenePos());
- dest->setScreenPos(source->screenPos());
- dest->setButtons(source->buttons());
- dest->setModifiers(source->modifiers());
- dest->setPossibleActions(source->possibleActions());
- dest->setProposedAction(source->proposedAction());
- dest->setDropAction(source->dropAction());
- dest->setSource(source->source());
- dest->setMimeData(source->mimeData());
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::sendDragDropEvent(QGraphicsItem *item,
- QGraphicsSceneDragDropEvent *dragDropEvent)
-{
- dragDropEvent->setPos(item->d_ptr->genericMapFromScene(dragDropEvent->scenePos(), dragDropEvent->widget()));
- sendEvent(item, dragDropEvent);
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::sendHoverEvent(QEvent::Type type, QGraphicsItem *item,
- QGraphicsSceneHoverEvent *hoverEvent)
-{
- QGraphicsSceneHoverEvent event(type);
- event.setWidget(hoverEvent->widget());
- event.setPos(item->d_ptr->genericMapFromScene(hoverEvent->scenePos(), hoverEvent->widget()));
- event.setScenePos(hoverEvent->scenePos());
- event.setScreenPos(hoverEvent->screenPos());
- event.setLastPos(item->d_ptr->genericMapFromScene(hoverEvent->lastScenePos(), hoverEvent->widget()));
- event.setLastScenePos(hoverEvent->lastScenePos());
- event.setLastScreenPos(hoverEvent->lastScreenPos());
- event.setModifiers(hoverEvent->modifiers());
- sendEvent(item, &event);
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent)
-{
- if (mouseEvent->button() == 0 && mouseEvent->buttons() == 0 && lastMouseGrabberItemHasImplicitMouseGrab) {
- // ### This is a temporary fix for until we get proper mouse
- // grab events.
- clearMouseGrabber();
- return;
- }
-
- QGraphicsItem *item = mouseGrabberItems.last();
- if (item->isBlockedByModalPanel())
- return;
-
- for (int i = 0x1; i <= 0x10; i <<= 1) {
- Qt::MouseButton button = Qt::MouseButton(i);
- mouseEvent->setButtonDownPos(button, mouseGrabberButtonDownPos.value(button, item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget())));
- mouseEvent->setButtonDownScenePos(button, mouseGrabberButtonDownScenePos.value(button, mouseEvent->scenePos()));
- mouseEvent->setButtonDownScreenPos(button, mouseGrabberButtonDownScreenPos.value(button, mouseEvent->screenPos()));
- }
- mouseEvent->setPos(item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget()));
- mouseEvent->setLastPos(item->d_ptr->genericMapFromScene(mouseEvent->lastScenePos(), mouseEvent->widget()));
- sendEvent(item, mouseEvent);
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent)
-{
- Q_Q(QGraphicsScene);
-
- // Ignore by default, unless we find a mouse grabber that accepts it.
- mouseEvent->ignore();
-
- // Deliver to any existing mouse grabber.
- if (!mouseGrabberItems.isEmpty()) {
- if (mouseGrabberItems.last()->isBlockedByModalPanel())
- return;
- // The event is ignored by default, but we disregard the event's
- // accepted state after delivery; the mouse is grabbed, after all.
- sendMouseEvent(mouseEvent);
- return;
- }
-
- // Start by determining the number of items at the current position.
- // Reuse value from earlier calculations if possible.
- if (cachedItemsUnderMouse.isEmpty()) {
- cachedItemsUnderMouse = itemsAtPosition(mouseEvent->screenPos(),
- mouseEvent->scenePos(),
- mouseEvent->widget());
- }
-
- // Update window activation.
- QGraphicsItem *topItem = cachedItemsUnderMouse.value(0);
- QGraphicsWidget *newActiveWindow = topItem ? topItem->window() : 0;
- if (newActiveWindow && newActiveWindow->isBlockedByModalPanel(&topItem)) {
- // pass activation to the blocking modal window
- newActiveWindow = topItem ? topItem->window() : 0;
- }
-
- if (newActiveWindow != q->activeWindow())
- q->setActiveWindow(newActiveWindow);
-
- // Set focus on the topmost enabled item that can take focus.
- bool setFocus = false;
-
- foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
- if (item->isBlockedByModalPanel()
- || (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling)) {
- // Make sure we don't clear focus.
- setFocus = true;
- break;
- }
- if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable))) {
- if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
- setFocus = true;
- if (item != q->focusItem() && item->d_ptr->mouseSetsFocus)
- q->setFocusItem(item, Qt::MouseFocusReason);
- break;
- }
- }
- if (item->isPanel())
- break;
- if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
- break;
- }
-
- // Check for scene modality.
- bool sceneModality = false;
- for (int i = 0; i < modalPanels.size(); ++i) {
- if (modalPanels.at(i)->panelModality() == QGraphicsItem::SceneModal) {
- sceneModality = true;
- break;
- }
- }
-
- // If nobody could take focus, clear it.
- if (!stickyFocus && !setFocus && !sceneModality)
- q->setFocusItem(0, Qt::MouseFocusReason);
-
- // Any item will do.
- if (sceneModality && cachedItemsUnderMouse.isEmpty())
- cachedItemsUnderMouse << modalPanels.first();
-
- // Find a mouse grabber by sending mouse press events to all mouse grabber
- // candidates one at a time, until the event is accepted. It's accepted by
- // default, so the receiver has to explicitly ignore it for it to pass
- // through.
- foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
- if (!(item->acceptedMouseButtons() & mouseEvent->button())) {
- // Skip items that don't accept the event's mouse button.
- continue;
- }
-
- // Check if this item is blocked by a modal panel and deliver the mouse event to the
- // blocking panel instead of this item if blocked.
- (void) item->isBlockedByModalPanel(&item);
-
- grabMouse(item, /* implicit = */ true);
- mouseEvent->accept();
-
- // check if the item we are sending to are disabled (before we send the event)
- bool disabled = !item->isEnabled();
- bool isPanel = item->isPanel();
- if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick
- && item != lastMouseGrabberItem && lastMouseGrabberItem) {
- // If this item is different from the item that received the last
- // mouse event, and mouseEvent is a doubleclick event, then the
- // event is converted to a press. Known limitation:
- // Triple-clicking will not generate a doubleclick, though.
- QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
- mousePress.spont = mouseEvent->spont;
- mousePress.accept();
- mousePress.setButton(mouseEvent->button());
- mousePress.setButtons(mouseEvent->buttons());
- mousePress.setScreenPos(mouseEvent->screenPos());
- mousePress.setScenePos(mouseEvent->scenePos());
- mousePress.setModifiers(mouseEvent->modifiers());
- mousePress.setWidget(mouseEvent->widget());
- mousePress.setButtonDownPos(mouseEvent->button(),
- mouseEvent->buttonDownPos(mouseEvent->button()));
- mousePress.setButtonDownScenePos(mouseEvent->button(),
- mouseEvent->buttonDownScenePos(mouseEvent->button()));
- mousePress.setButtonDownScreenPos(mouseEvent->button(),
- mouseEvent->buttonDownScreenPos(mouseEvent->button()));
- sendMouseEvent(&mousePress);
- mouseEvent->setAccepted(mousePress.isAccepted());
- } else {
- sendMouseEvent(mouseEvent);
- }
-
- bool dontSendUngrabEvents = mouseGrabberItems.isEmpty() || mouseGrabberItems.last() != item;
- if (disabled) {
- ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
- break;
- }
- if (mouseEvent->isAccepted()) {
- if (!mouseGrabberItems.isEmpty())
- storeMouseButtonsForMouseGrabber(mouseEvent);
- lastMouseGrabberItem = item;
- return;
- }
- ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
-
- // Don't propagate through panels.
- if (isPanel)
- break;
- }
-
- // Is the event still ignored? Then the mouse press goes to the scene.
- // Reset the mouse grabber, clear the selection, clear focus, and leave
- // the event ignored so that it can propagate through the originating
- // view.
- if (!mouseEvent->isAccepted()) {
- clearMouseGrabber();
-
- QGraphicsView *view = mouseEvent->widget() ? qobject_cast<QGraphicsView *>(mouseEvent->widget()->parentWidget()) : 0;
- bool dontClearSelection = view && view->dragMode() == QGraphicsView::ScrollHandDrag;
- if (!dontClearSelection) {
- // Clear the selection if the originating view isn't in scroll
- // hand drag mode. The view will clear the selection if no drag
- // happened.
- q->clearSelection();
- }
- }
-}
-
-/*!
- \internal
-
- Ensures that the list of toplevels is sorted by insertion order, and that
- the siblingIndexes are packed (no gaps), and start at 0.
-
- ### This function is almost identical to
- QGraphicsItemPrivate::ensureSequentialSiblingIndex().
-*/
-void QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes()
-{
- if (!topLevelSequentialOrdering) {
- qSort(topLevelItems.begin(), topLevelItems.end(), QGraphicsItemPrivate::insertionOrder);
- topLevelSequentialOrdering = true;
- needSortTopLevelItems = 1;
- }
- if (holesInTopLevelSiblingIndex) {
- holesInTopLevelSiblingIndex = 0;
- for (int i = 0; i < topLevelItems.size(); ++i)
- topLevelItems[i]->d_ptr->siblingIndex = i;
- }
-}
-
-/*!
- \internal
-
- Set the font and propagate the changes if the font is different from the
- current font.
-*/
-void QGraphicsScenePrivate::setFont_helper(const QFont &font)
-{
- if (this->font == font && this->font.resolve() == font.resolve())
- return;
- updateFont(font);
-}
-
-/*!
- \internal
-
- Resolve the scene's font against the application font, and propagate the
- changes too all items in the scene.
-*/
-void QGraphicsScenePrivate::resolveFont()
-{
- QFont naturalFont = QApplication::font();
- naturalFont.resolve(0);
- QFont resolvedFont = font.resolve(naturalFont);
- updateFont(resolvedFont);
-}
-
-/*!
- \internal
-
- Update the font, and whether or not it has changed, reresolve all fonts in
- the scene.
-*/
-void QGraphicsScenePrivate::updateFont(const QFont &font)
-{
- Q_Q(QGraphicsScene);
-
- // Update local font setting.
- this->font = font;
-
- // Resolve the fonts of all top-level widget items, or widget items
- // whose parent is not a widget.
- foreach (QGraphicsItem *item, q->items()) {
- if (!item->parentItem()) {
- // Resolvefont for an item is a noop operation, but
- // every item can be a widget, or can have a widget
- // childre.
- item->d_ptr->resolveFont(font.resolve());
- }
- }
-
- // Send the scene a FontChange event.
- QEvent event(QEvent::FontChange);
- QApplication::sendEvent(q, &event);
-}
-
-/*!
- \internal
-
- Set the palette and propagate the changes if the palette is different from
- the current palette.
-*/
-void QGraphicsScenePrivate::setPalette_helper(const QPalette &palette)
-{
- if (this->palette == palette && this->palette.resolve() == palette.resolve())
- return;
- updatePalette(palette);
-}
-
-/*!
- \internal
-
- Resolve the scene's palette against the application palette, and propagate
- the changes too all items in the scene.
-*/
-void QGraphicsScenePrivate::resolvePalette()
-{
- QPalette naturalPalette = QApplication::palette();
- naturalPalette.resolve(0);
- QPalette resolvedPalette = palette.resolve(naturalPalette);
- updatePalette(resolvedPalette);
-}
-
-/*!
- \internal
-
- Update the palette, and whether or not it has changed, reresolve all
- palettes in the scene.
-*/
-void QGraphicsScenePrivate::updatePalette(const QPalette &palette)
-{
- Q_Q(QGraphicsScene);
-
- // Update local palette setting.
- this->palette = palette;
-
- // Resolve the palettes of all top-level widget items, or widget items
- // whose parent is not a widget.
- foreach (QGraphicsItem *item, q->items()) {
- if (!item->parentItem()) {
- // Resolvefont for an item is a noop operation, but
- // every item can be a widget, or can have a widget
- // childre.
- item->d_ptr->resolvePalette(palette.resolve());
- }
- }
-
- // Send the scene a PaletteChange event.
- QEvent event(QEvent::PaletteChange);
- QApplication::sendEvent(q, &event);
-}
-
-/*!
- Constructs a QGraphicsScene object. The \a parent parameter is
- passed to QObject's constructor.
-*/
-QGraphicsScene::QGraphicsScene(QObject *parent)
- : QObject(*new QGraphicsScenePrivate, parent)
-{
- d_func()->init();
-}
-
-/*!
- Constructs a QGraphicsScene object, using \a sceneRect for its
- scene rectangle. The \a parent parameter is passed to QObject's
- constructor.
-
- \sa sceneRect
-*/
-QGraphicsScene::QGraphicsScene(const QRectF &sceneRect, QObject *parent)
- : QObject(*new QGraphicsScenePrivate, parent)
-{
- d_func()->init();
- setSceneRect(sceneRect);
-}
-
-/*!
- Constructs a QGraphicsScene object, using the rectangle specified
- by (\a x, \a y), and the given \a width and \a height for its
- scene rectangle. The \a parent parameter is passed to QObject's
- constructor.
-
- \sa sceneRect
-*/
-QGraphicsScene::QGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObject *parent)
- : QObject(*new QGraphicsScenePrivate, parent)
-{
- d_func()->init();
- setSceneRect(x, y, width, height);
-}
-
-/*!
- Removes and deletes all items from the scene object
- before destroying the scene object. The scene object
- is removed from the application's global scene list,
- and it is removed from all associated views.
-*/
-QGraphicsScene::~QGraphicsScene()
-{
- Q_D(QGraphicsScene);
-
- // Remove this scene from qApp's global scene list.
- qApp->d_func()->scene_list.removeAll(this);
-
- clear();
-
- // Remove this scene from all associated views.
- for (int j = 0; j < d->views.size(); ++j)
- d->views.at(j)->setScene(0);
-}
-
-/*!
- \property QGraphicsScene::sceneRect
- \brief the scene rectangle; the bounding rectangle of the scene
-
- The scene rectangle defines the extent of the scene. It is
- primarily used by QGraphicsView to determine the view's default
- scrollable area, and by QGraphicsScene to manage item indexing.
-
- If unset, or if set to a null QRectF, sceneRect() will return the largest
- bounding rect of all items on the scene since the scene was created (i.e.,
- a rectangle that grows when items are added to or moved in the scene, but
- never shrinks).
-
- \sa width(), height(), QGraphicsView::sceneRect
-*/
-QRectF QGraphicsScene::sceneRect() const
-{
- Q_D(const QGraphicsScene);
- if (d->hasSceneRect)
- return d->sceneRect;
-
- if (d->dirtyGrowingItemsBoundingRect) {
- // Lazily update the growing items bounding rect
- QGraphicsScenePrivate *thatd = const_cast<QGraphicsScenePrivate *>(d);
- QRectF oldGrowingBoundingRect = thatd->growingItemsBoundingRect;
- thatd->growingItemsBoundingRect |= itemsBoundingRect();
- thatd->dirtyGrowingItemsBoundingRect = false;
- if (oldGrowingBoundingRect != thatd->growingItemsBoundingRect)
- emit const_cast<QGraphicsScene *>(this)->sceneRectChanged(thatd->growingItemsBoundingRect);
- }
- return d->growingItemsBoundingRect;
-}
-void QGraphicsScene::setSceneRect(const QRectF &rect)
-{
- Q_D(QGraphicsScene);
- if (rect != d->sceneRect) {
- d->hasSceneRect = !rect.isNull();
- d->sceneRect = rect;
- emit sceneRectChanged(d->hasSceneRect ? rect : d->growingItemsBoundingRect);
- }
-}
-
-/*!
- \fn qreal QGraphicsScene::width() const
-
- This convenience function is equivalent to calling sceneRect().width().
-
- \sa height()
-*/
-
-/*!
- \fn qreal QGraphicsScene::height() const
-
- This convenience function is equivalent to calling \c sceneRect().height().
-
- \sa width()
-*/
-
-/*!
- Renders the \a source rect from scene into \a target, using \a painter. This
- function is useful for capturing the contents of the scene onto a paint
- device, such as a QImage (e.g., to take a screenshot), or for printing
- with QPrinter. For example:
-
- \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 1
-
- If \a source is a null rect, this function will use sceneRect() to
- determine what to render. If \a target is a null rect, the dimensions of \a
- painter's paint device will be used.
-
- The source rect contents will be transformed according to \a
- aspectRatioMode to fit into the target rect. By default, the aspect ratio
- is kept, and \a source is scaled to fit in \a target.
-
- \sa QGraphicsView::render()
-*/
-void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRectF &source,
- Qt::AspectRatioMode aspectRatioMode)
-{
- // ### Switch to using the recursive rendering algorithm instead.
-
- // Default source rect = scene rect
- QRectF sourceRect = source;
- if (sourceRect.isNull())
- sourceRect = sceneRect();
-
- // Default target rect = device rect
- QRectF targetRect = target;
- if (targetRect.isNull()) {
- if (painter->device()->devType() == QInternal::Picture)
- targetRect = sourceRect;
- else
- targetRect.setRect(0, 0, painter->device()->width(), painter->device()->height());
- }
-
- // Find the ideal x / y scaling ratio to fit \a source into \a target.
- qreal xratio = targetRect.width() / sourceRect.width();
- qreal yratio = targetRect.height() / sourceRect.height();
-
- // Scale according to the aspect ratio mode.
- switch (aspectRatioMode) {
- case Qt::KeepAspectRatio:
- xratio = yratio = qMin(xratio, yratio);
- break;
- case Qt::KeepAspectRatioByExpanding:
- xratio = yratio = qMax(xratio, yratio);
- break;
- case Qt::IgnoreAspectRatio:
- break;
- }
-
- // Find all items to draw, and reverse the list (we want to draw
- // in reverse order).
- QList<QGraphicsItem *> itemList = items(sourceRect, Qt::IntersectsItemBoundingRect);
- QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
- int numItems = itemList.size();
- for (int i = 0; i < numItems; ++i)
- itemArray[numItems - i - 1] = itemList.at(i);
- itemList.clear();
-
- painter->save();
-
- // Transform the painter.
- painter->setClipRect(targetRect, Qt::IntersectClip);
- QTransform painterTransform;
- painterTransform *= QTransform()
- .translate(targetRect.left(), targetRect.top())
- .scale(xratio, yratio)
- .translate(-sourceRect.left(), -sourceRect.top());
- painter->setWorldTransform(painterTransform, true);
-
- // Two unit vectors.
- QLineF v1(0, 0, 1, 0);
- QLineF v2(0, 0, 0, 1);
-
- // Generate the style options
- QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems];
- for (int i = 0; i < numItems; ++i)
- itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect());
-
- // Render the scene.
- drawBackground(painter, sourceRect);
- drawItems(painter, numItems, itemArray, styleOptionArray);
- drawForeground(painter, sourceRect);
-
- delete [] itemArray;
- delete [] styleOptionArray;
-
- painter->restore();
-}
-
-/*!
- \property QGraphicsScene::itemIndexMethod
- \brief the item indexing method.
-
- QGraphicsScene applies an indexing algorithm to the scene, to speed up
- item discovery functions like items() and itemAt(). Indexing is most
- efficient for static scenes (i.e., where items don't move around). For
- dynamic scenes, or scenes with many animated items, the index bookkeeping
- can outweight the fast lookup speeds.
-
- For the common case, the default index method BspTreeIndex works fine. If
- your scene uses many animations and you are experiencing slowness, you can
- disable indexing by calling \c setItemIndexMethod(NoIndex).
-
- \sa bspTreeDepth
-*/
-QGraphicsScene::ItemIndexMethod QGraphicsScene::itemIndexMethod() const
-{
- Q_D(const QGraphicsScene);
- return d->indexMethod;
-}
-void QGraphicsScene::setItemIndexMethod(ItemIndexMethod method)
-{
- Q_D(QGraphicsScene);
- if (d->indexMethod == method)
- return;
-
- d->indexMethod = method;
-
- QList<QGraphicsItem *> oldItems = d->index->items(Qt::DescendingOrder);
- delete d->index;
- if (method == BspTreeIndex)
- d->index = new QGraphicsSceneBspTreeIndex(this);
- else
- d->index = new QGraphicsSceneLinearIndex(this);
- for (int i = oldItems.size() - 1; i >= 0; --i)
- d->index->addItem(oldItems.at(i));
-}
-
-/*!
- \property QGraphicsScene::bspTreeDepth
- \brief the depth of QGraphicsScene's BSP index tree
- \since 4.3
-
- This property has no effect when NoIndex is used.
-
- This value determines the depth of QGraphicsScene's BSP tree. The depth
- directly affects QGraphicsScene's performance and memory usage; the latter
- growing exponentially with the depth of the tree. With an optimal tree
- depth, QGraphicsScene can instantly determine the locality of items, even
- for scenes with thousands or millions of items. This also greatly improves
- rendering performance.
-
- By default, the value is 0, in which case Qt will guess a reasonable
- default depth based on the size, location and number of items in the
- scene. If these parameters change frequently, however, you may experience
- slowdowns as QGraphicsScene retunes the depth internally. You can avoid
- potential slowdowns by fixating the tree depth through setting this
- property.
-
- The depth of the tree and the size of the scene rectangle decide the
- granularity of the scene's partitioning. The size of each scene segment is
- determined by the following algorithm:
-
- \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 2
-
- The BSP tree has an optimal size when each segment contains between 0 and
- 10 items.
-
- \sa itemIndexMethod
-*/
-int QGraphicsScene::bspTreeDepth() const
-{
- Q_D(const QGraphicsScene);
- QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
- return bspTree ? bspTree->bspTreeDepth() : 0;
-}
-void QGraphicsScene::setBspTreeDepth(int depth)
-{
- Q_D(QGraphicsScene);
- if (depth < 0) {
- qWarning("QGraphicsScene::setBspTreeDepth: invalid depth %d ignored; must be >= 0", depth);
- return;
- }
-
- QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
- if (!bspTree) {
- qWarning("QGraphicsScene::setBspTreeDepth: can not apply if indexing method is not BSP");
- return;
- }
- bspTree->setBspTreeDepth(depth);
-}
-
-/*!
- \property QGraphicsScene::sortCacheEnabled
- \brief whether sort caching is enabled
- \since 4.5
- \obsolete
-
- Since Qt 4.6, this property has no effect.
-*/
-bool QGraphicsScene::isSortCacheEnabled() const
-{
- Q_D(const QGraphicsScene);
- return d->sortCacheEnabled;
-}
-void QGraphicsScene::setSortCacheEnabled(bool enabled)
-{
- Q_D(QGraphicsScene);
- if (d->sortCacheEnabled == enabled)
- return;
- d->sortCacheEnabled = enabled;
-}
-
-/*!
- Calculates and returns the bounding rect of all items on the scene. This
- function works by iterating over all items, and because if this, it can
- be slow for large scenes.
-
- \sa sceneRect()
-*/
-QRectF QGraphicsScene::itemsBoundingRect() const
-{
- // Does not take untransformable items into account.
- QRectF boundingRect;
- foreach (QGraphicsItem *item, items())
- boundingRect |= item->sceneBoundingRect();
- return boundingRect;
-}
-
-/*!
- Returns a list of all items in the scene in descending stacking order.
-
- \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QList<QGraphicsItem *> QGraphicsScene::items() const
-{
- Q_D(const QGraphicsScene);
- return d->index->items(Qt::DescendingOrder);
-}
-
-/*!
- Returns an ordered list of all items on the scene. \a order decides the
- stacking order.
-
- \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QList<QGraphicsItem *> QGraphicsScene::items(Qt::SortOrder order) const
-{
- Q_D(const QGraphicsScene);
- return d->index->items(order);
-}
-
-/*!
- \obsolete
-
- Returns all visible items at position \a pos in the scene. The items are
- listed in descending stacking order (i.e., the first item in the list is the
- top-most item, and the last item is the bottom-most item).
-
- This function is deprecated and returns incorrect results if the scene
- contains items that ignore transformations. Use the overload that takes
- a QTransform instead.
-
- \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const
-{
- Q_D(const QGraphicsScene);
- return d->index->items(pos, Qt::IntersectsItemShape, Qt::DescendingOrder);
-}
-
-/*!
- \overload
- \obsolete
-
- Returns all visible items that, depending on \a mode, are either inside or
- intersect with the specified \a rectangle.
-
- The default value for \a mode is Qt::IntersectsItemShape; all items whose
- exact shape intersects with or is contained by \a rectangle are returned.
-
- This function is deprecated and returns incorrect results if the scene
- contains items that ignore transformations. Use the overload that takes
- a QTransform instead.
-
- \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const
-{
- Q_D(const QGraphicsScene);
- return d->index->items(rectangle, mode, Qt::DescendingOrder);
-}
-
-/*!
- \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const
- \obsolete
- \since 4.3
-
- This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode).
-
- This function is deprecated and returns incorrect results if the scene
- contains items that ignore transformations. Use the overload that takes
- a QTransform instead.
-*/
-
-/*!
- \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
- \overload
- \since 4.6
-
- \brief Returns all visible items that, depending on \a mode, are
- either inside or intersect with the rectangle defined by \a x, \a y,
- \a w and \a h, in a list sorted using \a order.
-
- \a deviceTransform is the transformation that applies to the view, and needs to
- be provided if the scene contains items that ignore transformations.
-*/
-
-/*!
- \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const
- \overload
- \obsolete
-
- Returns all visible items that, depending on \a mode, are either inside or
- intersect with the polygon \a polygon.
-
- The default value for \a mode is Qt::IntersectsItemShape; all items whose
- exact shape intersects with or is contained by \a polygon are returned.
-
- This function is deprecated and returns incorrect results if the scene
- contains items that ignore transformations. Use the overload that takes
- a QTransform instead.
-
- \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const
-{
- Q_D(const QGraphicsScene);
- return d->index->items(polygon, mode, Qt::DescendingOrder);
-}
-
-/*!
- \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
- \overload
- \obsolete
-
- Returns all visible items that, depending on \a path, are either inside or
- intersect with the path \a path.
-
- The default value for \a mode is Qt::IntersectsItemShape; all items whose
- exact shape intersects with or is contained by \a path are returned.
-
- This function is deprecated and returns incorrect results if the scene
- contains items that ignore transformations. Use the overload that takes
- a QTransform instead.
-
- \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
-{
- Q_D(const QGraphicsScene);
- return d->index->items(path, mode, Qt::DescendingOrder);
-}
-
-/*!
- \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
- \since 4.6
-
- \brief Returns all visible items that, depending on \a mode, are at
- the specified \a pos in a list sorted using \a order.
-
- The default value for \a mode is Qt::IntersectsItemShape; all items whose
- exact shape intersects with \a pos are returned.
-
- \a deviceTransform is the transformation that applies to the view, and needs to
- be provided if the scene contains items that ignore transformations.
-
- \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode,
- Qt::SortOrder order, const QTransform &deviceTransform) const
-{
- Q_D(const QGraphicsScene);
- return d->index->items(pos, mode, order, deviceTransform);
-}
-
-/*!
- \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
- \overload
- \since 4.6
-
- \brief Returns all visible items that, depending on \a mode, are
- either inside or intersect with the specified \a rect and return a
- list sorted using \a order.
-
- The default value for \a mode is Qt::IntersectsItemShape; all items whose
- exact shape intersects with or is contained by \a rect are returned.
-
- \a deviceTransform is the transformation that applies to the view, and needs to
- be provided if the scene contains items that ignore transformations.
-
- \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode,
- Qt::SortOrder order, const QTransform &deviceTransform) const
-{
- Q_D(const QGraphicsScene);
- return d->index->items(rect, mode, order, deviceTransform);
-}
-
-/*!
- \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
- \overload
- \since 4.6
-
- \brief Returns all visible items that, depending on \a mode, are
- either inside or intersect with the specified \a polygon and return
- a list sorted using \a order.
-
- The default value for \a mode is Qt::IntersectsItemShape; all items whose
- exact shape intersects with or is contained by \a polygon are returned.
-
- \a deviceTransform is the transformation that applies to the view, and needs to
- be provided if the scene contains items that ignore transformations.
-
- \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode,
- Qt::SortOrder order, const QTransform &deviceTransform) const
-{
- Q_D(const QGraphicsScene);
- return d->index->items(polygon, mode, order, deviceTransform);
-}
-
-/*!
- \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
- \overload
- \since 4.6
-
- \brief Returns all visible items that, depending on \a mode, are
- either inside or intersect with the specified \a path and return a
- list sorted using \a order.
-
- The default value for \a mode is Qt::IntersectsItemShape; all items whose
- exact shape intersects with or is contained by \a path are returned.
-
- \a deviceTransform is the transformation that applies to the view, and needs to
- be provided if the scene contains items that ignore transformations.
-
- \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode,
- Qt::SortOrder order, const QTransform &deviceTransform) const
-{
- Q_D(const QGraphicsScene);
- return d->index->items(path, mode, order, deviceTransform);
-}
-
-/*!
- Returns a list of all items that collide with \a item. Collisions are
- determined by calling QGraphicsItem::collidesWithItem(); the collision
- detection is determined by \a mode. By default, all items whose shape
- intersects \a item or is contained inside \a item's shape are returned.
-
- The items are returned in descending stacking order (i.e., the first item
- in the list is the uppermost item, and the last item is the lowermost
- item).
-
- \sa items(), itemAt(), QGraphicsItem::collidesWithItem(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item,
- Qt::ItemSelectionMode mode) const
-{
- Q_D(const QGraphicsScene);
- if (!item) {
- qWarning("QGraphicsScene::collidingItems: cannot find collisions for null item");
- return QList<QGraphicsItem *>();
- }
-
- // Does not support ItemIgnoresTransformations.
- QList<QGraphicsItem *> tmp;
- foreach (QGraphicsItem *itemInVicinity, d->index->estimateItems(item->sceneBoundingRect(), Qt::DescendingOrder)) {
- if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode))
- tmp << itemInVicinity;
- }
- return tmp;
-}
-
-/*!
- \overload
- \obsolete
-
- Returns the topmost visible item at the specified \a position, or 0 if
- there are no items at this position.
-
- This function is deprecated and returns incorrect results if the scene
- contains items that ignore transformations. Use the overload that takes
- a QTransform instead.
-
- \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const
-{
- QList<QGraphicsItem *> itemsAtPoint = items(position);
- return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
-}
-
-/*!
- \since 4.6
-
- Returns the topmost visible item at the specified \a position, or 0
- if there are no items at this position.
-
- \a deviceTransform is the transformation that applies to the view, and needs to
- be provided if the scene contains items that ignore transformations.
-
- \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
-*/
-QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position, const QTransform &deviceTransform) const
-{
- QList<QGraphicsItem *> itemsAtPoint = items(position, Qt::IntersectsItemShape,
- Qt::DescendingOrder, deviceTransform);
- return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
-}
-
-/*!
- \fn QGraphicsScene::itemAt(qreal x, qreal y, const QTransform &deviceTransform) const
- \overload
- \since 4.6
-
- Returns the topmost item at the position specified by (\a x, \a
- y), or 0 if there are no items at this position.
-
- \a deviceTransform is the transformation that applies to the view, and needs to
- be provided if the scene contains items that ignore transformations.
-
- This convenience function is equivalent to calling \c
- {itemAt(QPointF(x, y), deviceTransform)}.
-*/
-
-/*!
- \fn QGraphicsScene::itemAt(qreal x, qreal y) const
- \overload
- \obsolete
-
- Returns the topmost item at the position specified by (\a x, \a
- y), or 0 if there are no items at this position.
-
- This convenience function is equivalent to calling \c
- {itemAt(QPointF(x, y))}.
-
- This function is deprecated and returns incorrect results if the scene
- contains items that ignore transformations. Use the overload that takes
- a QTransform instead.
-*/
-
-/*!
- Returns a list of all currently selected items. The items are
- returned in no particular order.
-
- \sa setSelectionArea()
-*/
-QList<QGraphicsItem *> QGraphicsScene::selectedItems() const
-{
- Q_D(const QGraphicsScene);
-
- // Optimization: Lazily removes items that are not selected.
- QGraphicsScene *that = const_cast<QGraphicsScene *>(this);
- QSet<QGraphicsItem *> actuallySelectedSet;
- foreach (QGraphicsItem *item, that->d_func()->selectedItems) {
- if (item->isSelected())
- actuallySelectedSet << item;
- }
-
- that->d_func()->selectedItems = actuallySelectedSet;
-
- return d->selectedItems.values();
-}
-
-/*!
- Returns the selection area that was previously set with
- setSelectionArea(), or an empty QPainterPath if no selection area has been
- set.
-
- \sa setSelectionArea()
-*/
-QPainterPath QGraphicsScene::selectionArea() const
-{
- Q_D(const QGraphicsScene);
- return d->selectionArea;
-}
-
-/*!
- \since 4.6
-
- Sets the selection area to \a path. All items within this area are
- immediately selected, and all items outside are unselected. You can get
- the list of all selected items by calling selectedItems().
-
- \a deviceTransform is the transformation that applies to the view, and needs to
- be provided if the scene contains items that ignore transformations.
-
- For an item to be selected, it must be marked as \e selectable
- (QGraphicsItem::ItemIsSelectable).
-
- \sa clearSelection(), selectionArea()
-*/
-void QGraphicsScene::setSelectionArea(const QPainterPath &path, const QTransform &deviceTransform)
-{
- setSelectionArea(path, Qt::IntersectsItemShape, deviceTransform);
-}
-
-/*!
- \obsolete
- \overload
-
- Sets the selection area to \a path.
-
- This function is deprecated and leads to incorrect results if the scene
- contains items that ignore transformations. Use the overload that takes
- a QTransform instead.
-*/
-void QGraphicsScene::setSelectionArea(const QPainterPath &path)
-{
- setSelectionArea(path, Qt::IntersectsItemShape, QTransform());
-}
-
-/*!
- \obsolete
- \overload
- \since 4.3
-
- Sets the selection area to \a path using \a mode to determine if items are
- included in the selection area.
-
- \sa clearSelection(), selectionArea()
-*/
-void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode)
-{
- setSelectionArea(path, mode, QTransform());
-}
-
-/*!
- \overload
- \since 4.6
-
- Sets the selection area to \a path using \a mode to determine if items are
- included in the selection area.
-
- \a deviceTransform is the transformation that applies to the view, and needs to
- be provided if the scene contains items that ignore transformations.
-
- \sa clearSelection(), selectionArea()
-*/
-void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode,
- const QTransform &deviceTransform)
-{
- Q_D(QGraphicsScene);
-
- // Note: with boolean path operations, we can improve performance here
- // quite a lot by "growing" the old path instead of replacing it. That
- // allows us to only check the intersect area for changes, instead of
- // reevaluating the whole path over again.
- d->selectionArea = path;
-
- QSet<QGraphicsItem *> unselectItems = d->selectedItems;
-
- // Disable emitting selectionChanged() for individual items.
- ++d->selectionChanging;
- bool changed = false;
-
- // Set all items in path to selected.
- foreach (QGraphicsItem *item, items(path, mode, Qt::DescendingOrder, deviceTransform)) {
- if (item->flags() & QGraphicsItem::ItemIsSelectable) {
- if (!item->isSelected())
- changed = true;
- unselectItems.remove(item);
- item->setSelected(true);
- }
- }
-
- // Unselect all items outside path.
- foreach (QGraphicsItem *item, unselectItems) {
- item->setSelected(false);
- changed = true;
- }
-
- // Reenable emitting selectionChanged() for individual items.
- --d->selectionChanging;
-
- if (!d->selectionChanging && changed)
- emit selectionChanged();
-}
-
-/*!
- Clears the current selection.
-
- \sa setSelectionArea(), selectedItems()
-*/
-void QGraphicsScene::clearSelection()
-{
- Q_D(QGraphicsScene);
-
- // Disable emitting selectionChanged
- ++d->selectionChanging;
- bool changed = !d->selectedItems.isEmpty();
-
- foreach (QGraphicsItem *item, d->selectedItems)
- item->setSelected(false);
- d->selectedItems.clear();
-
- // Reenable emitting selectionChanged() for individual items.
- --d->selectionChanging;
-
- if (!d->selectionChanging && changed)
- emit selectionChanged();
-}
-
-/*!
- \since 4.4
-
- Removes and deletes all items from the scene, but otherwise leaves the
- state of the scene unchanged.
-
- \sa addItem()
-*/
-void QGraphicsScene::clear()
-{
- Q_D(QGraphicsScene);
- // NB! We have to clear the index before deleting items; otherwise the
- // index might try to access dangling item pointers.
- d->index->clear();
- // NB! QGraphicsScenePrivate::unregisterTopLevelItem() removes items
- while (!d->topLevelItems.isEmpty())
- delete d->topLevelItems.first();
- Q_ASSERT(d->topLevelItems.isEmpty());
- d->lastItemCount = 0;
- d->allItemsIgnoreHoverEvents = true;
- d->allItemsUseDefaultCursor = true;
- d->allItemsIgnoreTouchEvents = true;
-}
-
-/*!
- Groups all items in \a items into a new QGraphicsItemGroup, and returns a
- pointer to the group. The group is created with the common ancestor of \a
- items as its parent, and with position (0, 0). The items are all
- reparented to the group, and their positions and transformations are
- mapped to the group. If \a items is empty, this function will return an
- empty top-level QGraphicsItemGroup.
-
- QGraphicsScene has ownership of the group item; you do not need to delete
- it. To dismantle (ungroup) a group, call destroyItemGroup().
-
- \sa destroyItemGroup(), QGraphicsItemGroup::addToGroup()
-*/
-QGraphicsItemGroup *QGraphicsScene::createItemGroup(const QList<QGraphicsItem *> &items)
-{
- // Build a list of the first item's ancestors
- QList<QGraphicsItem *> ancestors;
- int n = 0;
- if (!items.isEmpty()) {
- QGraphicsItem *parent = items.at(n++);
- while ((parent = parent->parentItem()))
- ancestors.append(parent);
- }
-
- // Find the common ancestor for all items
- QGraphicsItem *commonAncestor = 0;
- if (!ancestors.isEmpty()) {
- while (n < items.size()) {
- int commonIndex = -1;
- QGraphicsItem *parent = items.at(n++);
- do {
- int index = ancestors.indexOf(parent, qMax(0, commonIndex));
- if (index != -1) {
- commonIndex = index;
- break;
- }
- } while ((parent = parent->parentItem()));
-
- if (commonIndex == -1) {
- commonAncestor = 0;
- break;
- }
-
- commonAncestor = ancestors.at(commonIndex);
- }
- }
-
- // Create a new group at that level
- QGraphicsItemGroup *group = new QGraphicsItemGroup(commonAncestor);
- if (!commonAncestor)
- addItem(group);
- foreach (QGraphicsItem *item, items)
- group->addToGroup(item);
- return group;
-}
-
-/*!
- Reparents all items in \a group to \a group's parent item, then removes \a
- group from the scene, and finally deletes it. The items' positions and
- transformations are mapped from the group to the group's parent.
-
- \sa createItemGroup(), QGraphicsItemGroup::removeFromGroup()
-*/
-void QGraphicsScene::destroyItemGroup(QGraphicsItemGroup *group)
-{
- foreach (QGraphicsItem *item, group->children())
- group->removeFromGroup(item);
- removeItem(group);
- delete group;
-}
-
-/*!
- Adds or moves the \a item and all its childen to this scene.
- This scene takes ownership of the \a item.
-
- If the item is visible (i.e., QGraphicsItem::isVisible() returns
- true), QGraphicsScene will emit changed() once control goes back
- to the event loop.
-
- If the item is already in a different scene, it will first be
- removed from its old scene, and then added to this scene as a
- top-level.
-
- QGraphicsScene will send ItemSceneChange notifications to \a item
- while it is added to the scene. If item does not currently belong
- to a scene, only one notification is sent. If it does belong to
- scene already (i.e., it is moved to this scene), QGraphicsScene
- will send an addition notification as the item is removed from its
- previous scene.
-
- If the item is a panel, the scene is active, and there is no
- active panel in the scene, then the item will be activated.
-
- \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(),
- addRect(), addText(), addWidget(), {QGraphicsItem#Sorting}{Sorting}
-*/
-void QGraphicsScene::addItem(QGraphicsItem *item)
-{
- Q_D(QGraphicsScene);
- if (!item) {
- qWarning("QGraphicsScene::addItem: cannot add null item");
- return;
- }
- if (item->d_ptr->scene == this) {
- qWarning("QGraphicsScene::addItem: item has already been added to this scene");
- return;
- }
- // Remove this item from its existing scene
- if (QGraphicsScene *oldScene = item->d_ptr->scene)
- oldScene->removeItem(item);
-
- // Notify the item that its scene is changing, and allow the item to
- // react.
- const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
- QVariant::fromValue<QGraphicsScene *>(this)));
- QGraphicsScene *targetScene = qvariant_cast<QGraphicsScene *>(newSceneVariant);
- if (targetScene != this) {
- if (targetScene && item->d_ptr->scene != targetScene)
- targetScene->addItem(item);
- return;
- }
-
- // QDeclarativeItems do not rely on initial itemChanged message, as the componentComplete
- // function allows far more opportunity for delayed-construction optimization.
- if (!item->d_ptr->isDeclarativeItem) {
- if (d->unpolishedItems.isEmpty()) {
- QMetaMethod method = metaObject()->method(d->polishItemsIndex);
- method.invoke(this, Qt::QueuedConnection);
- }
- d->unpolishedItems.append(item);
- item->d_ptr->pendingPolish = true;
- }
-
- // Detach this item from its parent if the parent's scene is different
- // from this scene.
- if (QGraphicsItem *itemParent = item->d_ptr->parent) {
- if (itemParent->d_ptr->scene != this)
- item->setParentItem(0);
- }
-
- // Add the item to this scene
- item->d_func()->scene = targetScene;
-
- // Add the item in the index
- d->index->addItem(item);
-
- // Add to list of toplevels if this item is a toplevel.
- if (!item->d_ptr->parent)
- d->registerTopLevelItem(item);
-
- // Add to list of items that require an update. We cannot assume that the
- // item is fully constructed, so calling item->update() can lead to a pure
- // virtual function call to boundingRect().
- d->markDirty(item);
- d->dirtyGrowingItemsBoundingRect = true;
-
- // Disable selectionChanged() for individual items
- ++d->selectionChanging;
- int oldSelectedItemSize = d->selectedItems.size();
-
- // Enable mouse tracking if the item accepts hover events or has a cursor set.
- if (d->allItemsIgnoreHoverEvents && d->itemAcceptsHoverEvents_helper(item)) {
- d->allItemsIgnoreHoverEvents = false;
- d->enableMouseTrackingOnViews();
- }
-#ifndef QT_NO_CURSOR
- if (d->allItemsUseDefaultCursor && item->d_ptr->hasCursor) {
- d->allItemsUseDefaultCursor = false;
- if (d->allItemsIgnoreHoverEvents) // already enabled otherwise
- d->enableMouseTrackingOnViews();
- }
-#endif //QT_NO_CURSOR
-
- // Enable touch events if the item accepts touch events.
- if (d->allItemsIgnoreTouchEvents && item->d_ptr->acceptTouchEvents) {
- d->allItemsIgnoreTouchEvents = false;
- d->enableTouchEventsOnViews();
- }
-
-#ifndef QT_NO_GESTURES
- foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys())
- d->grabGesture(item, gesture);
-#endif
-
- // Update selection lists
- if (item->isSelected())
- d->selectedItems << item;
- if (item->isWidget() && item->isVisible() && static_cast<QGraphicsWidget *>(item)->windowType() == Qt::Popup)
- d->addPopup(static_cast<QGraphicsWidget *>(item));
- if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
- d->enterModal(item);
-
- // Update creation order focus chain. Make sure to leave the widget's
- // internal tab order intact.
- if (item->isWidget()) {
- QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
- if (!d->tabFocusFirst) {
- // No first tab focus widget - make this the first tab focus
- // widget.
- d->tabFocusFirst = widget;
- } else if (!widget->parentWidget()) {
- // Adding a widget that is not part of a tab focus chain.
- QGraphicsWidget *last = d->tabFocusFirst->d_func()->focusPrev;
- QGraphicsWidget *lastNew = widget->d_func()->focusPrev;
- last->d_func()->focusNext = widget;
- widget->d_func()->focusPrev = last;
- d->tabFocusFirst->d_func()->focusPrev = lastNew;
- lastNew->d_func()->focusNext = d->tabFocusFirst;
- }
- }
-
- // Add all children recursively
- item->d_ptr->ensureSortedChildren();
- for (int i = 0; i < item->d_ptr->children.size(); ++i)
- addItem(item->d_ptr->children.at(i));
-
- // Resolve font and palette.
- item->d_ptr->resolveFont(d->font.resolve());
- item->d_ptr->resolvePalette(d->palette.resolve());
-
-
- // Reenable selectionChanged() for individual items
- --d->selectionChanging;
- if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemSize)
- emit selectionChanged();
-
- // Deliver post-change notification
- item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
-
- // Update explicit activation
- bool autoActivate = true;
- if (!d->childExplicitActivation && item->d_ptr->explicitActivate)
- d->childExplicitActivation = item->d_ptr->wantsActive ? 1 : 2;
- if (d->childExplicitActivation && item->isPanel()) {
- if (d->childExplicitActivation == 1)
- setActivePanel(item);
- else
- autoActivate = false;
- d->childExplicitActivation = 0;
- } else if (!item->d_ptr->parent) {
- d->childExplicitActivation = 0;
- }
-
- // Auto-activate this item's panel if nothing else has been activated
- if (autoActivate) {
- if (!d->lastActivePanel && !d->activePanel && item->isPanel()) {
- if (isActive())
- setActivePanel(item);
- else
- d->lastActivePanel = item;
- }
- }
-
- if (item->d_ptr->flags & QGraphicsItem::ItemSendsScenePositionChanges)
- d->registerScenePosItem(item);
-
- // Ensure that newly added items that have subfocus set, gain
- // focus automatically if there isn't a focus item already.
- if (!d->focusItem && item != d->lastFocusItem && item->focusItem() == item)
- item->focusItem()->setFocus();
-
- d->updateInputMethodSensitivityInViews();
-}
-
-/*!
- Creates and adds an ellipse item to the scene, and returns the item
- pointer. The geometry of the ellipse is defined by \a rect, and its pen
- and brush are initialized to \a pen and \a brush.
-
- Note that the item's geometry is provided in item coordinates, and its
- position is initialized to (0, 0).
-
- If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
- QGraphicsScene will emit changed() once control goes back to the event
- loop.
-
- \sa addLine(), addPath(), addPixmap(), addRect(), addText(), addItem(),
- addWidget()
-*/
-QGraphicsEllipseItem *QGraphicsScene::addEllipse(const QRectF &rect, const QPen &pen, const QBrush &brush)
-{
- QGraphicsEllipseItem *item = new QGraphicsEllipseItem(rect);
- item->setPen(pen);
- item->setBrush(brush);
- addItem(item);
- return item;
-}
-
-/*!
- \fn QGraphicsEllipseItem *QGraphicsScene::addEllipse(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
- \since 4.3
-
- This convenience function is equivalent to calling addEllipse(QRectF(\a x,
- \a y, \a w, \a h), \a pen, \a brush).
-*/
-
-/*!
- Creates and adds a line item to the scene, and returns the item
- pointer. The geometry of the line is defined by \a line, and its pen
- is initialized to \a pen.
-
- Note that the item's geometry is provided in item coordinates, and its
- position is initialized to (0, 0).
-
- If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
- QGraphicsScene will emit changed() once control goes back to the event
- loop.
-
- \sa addEllipse(), addPath(), addPixmap(), addRect(), addText(), addItem(),
- addWidget()
-*/
-QGraphicsLineItem *QGraphicsScene::addLine(const QLineF &line, const QPen &pen)
-{
- QGraphicsLineItem *item = new QGraphicsLineItem(line);
- item->setPen(pen);
- addItem(item);
- return item;
-}
-
-/*!
- \fn QGraphicsLineItem *QGraphicsScene::addLine(qreal x1, qreal y1, qreal x2, qreal y2, const QPen &pen)
- \since 4.3
-
- This convenience function is equivalent to calling addLine(QLineF(\a x1,
- \a y1, \a x2, \a y2), \a pen).
-*/
-
-/*!
- Creates and adds a path item to the scene, and returns the item
- pointer. The geometry of the path is defined by \a path, and its pen and
- brush are initialized to \a pen and \a brush.
-
- Note that the item's geometry is provided in item coordinates, and its
- position is initialized to (0, 0).
-
- If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
- QGraphicsScene will emit changed() once control goes back to the event
- loop.
-
- \sa addEllipse(), addLine(), addPixmap(), addRect(), addText(), addItem(),
- addWidget()
-*/
-QGraphicsPathItem *QGraphicsScene::addPath(const QPainterPath &path, const QPen &pen, const QBrush &brush)
-{
- QGraphicsPathItem *item = new QGraphicsPathItem(path);
- item->setPen(pen);
- item->setBrush(brush);
- addItem(item);
- return item;
-}
-
-/*!
- Creates and adds a pixmap item to the scene, and returns the item
- pointer. The pixmap is defined by \a pixmap.
-
- Note that the item's geometry is provided in item coordinates, and its
- position is initialized to (0, 0).
-
- If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
- QGraphicsScene will emit changed() once control goes back to the event
- loop.
-
- \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
- addWidget()
-*/
-QGraphicsPixmapItem *QGraphicsScene::addPixmap(const QPixmap &pixmap)
-{
- QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
- addItem(item);
- return item;
-}
-
-/*!
- Creates and adds a polygon item to the scene, and returns the item
- pointer. The polygon is defined by \a polygon, and its pen and
- brush are initialized to \a pen and \a brush.
-
- Note that the item's geometry is provided in item coordinates, and its
- position is initialized to (0, 0).
-
- If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
- QGraphicsScene will emit changed() once control goes back to the event
- loop.
-
- \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
- addWidget()
-*/
-QGraphicsPolygonItem *QGraphicsScene::addPolygon(const QPolygonF &polygon,
- const QPen &pen, const QBrush &brush)
-{
- QGraphicsPolygonItem *item = new QGraphicsPolygonItem(polygon);
- item->setPen(pen);
- item->setBrush(brush);
- addItem(item);
- return item;
-}
-
-/*!
- Creates and adds a rectangle item to the scene, and returns the item
- pointer. The geometry of the rectangle is defined by \a rect, and its pen
- and brush are initialized to \a pen and \a brush.
-
- Note that the item's geometry is provided in item coordinates, and its
- position is initialized to (0, 0). For example, if a QRect(50, 50, 100,
- 100) is added, its top-left corner will be at (50, 50) relative to the
- origin in the items coordinate system.
-
- If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
- QGraphicsScene will emit changed() once control goes back to the event
- loop.
-
- \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addText(),
- addItem(), addWidget()
-*/
-QGraphicsRectItem *QGraphicsScene::addRect(const QRectF &rect, const QPen &pen, const QBrush &brush)
-{
- QGraphicsRectItem *item = new QGraphicsRectItem(rect);
- item->setPen(pen);
- item->setBrush(brush);
- addItem(item);
- return item;
-}
-
-/*!
- \fn QGraphicsRectItem *QGraphicsScene::addRect(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
- \since 4.3
-
- This convenience function is equivalent to calling addRect(QRectF(\a x,
- \a y, \a w, \a h), \a pen, \a brush).
-*/
-
-/*!
- Creates and adds a text item to the scene, and returns the item
- pointer. The text string is initialized to \a text, and its font
- is initialized to \a font.
-
- The item's position is initialized to (0, 0).
-
- If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
- QGraphicsScene will emit changed() once control goes back to the event
- loop.
-
- \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
- addItem(), addWidget()
-*/
-QGraphicsTextItem *QGraphicsScene::addText(const QString &text, const QFont &font)
-{
- QGraphicsTextItem *item = new QGraphicsTextItem(text);
- item->setFont(font);
- addItem(item);
- return item;
-}
-
-/*!
- Creates and adds a QGraphicsSimpleTextItem to the scene, and returns the
- item pointer. The text string is initialized to \a text, and its font is
- initialized to \a font.
-
- The item's position is initialized to (0, 0).
-
- If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
- QGraphicsScene will emit changed() once control goes back to the event
- loop.
-
- \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
- addItem(), addWidget()
-*/
-QGraphicsSimpleTextItem *QGraphicsScene::addSimpleText(const QString &text, const QFont &font)
-{
- QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem(text);
- item->setFont(font);
- addItem(item);
- return item;
-}
-
-/*!
- Creates a new QGraphicsProxyWidget for \a widget, adds it to the scene,
- and returns a pointer to the proxy. \a wFlags set the default window flags
- for the embedding proxy widget.
-
- The item's position is initialized to (0, 0).
-
- If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
- QGraphicsScene will emit changed() once control goes back to the event
- loop.
-
- Note that widgets with the Qt::WA_PaintOnScreen widget attribute
- set and widgets that wrap an external application or controller
- are not supported. Examples are QGLWidget and QAxWidget.
-
- \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
- addText(), addSimpleText(), addItem()
-*/
-QGraphicsProxyWidget *QGraphicsScene::addWidget(QWidget *widget, Qt::WindowFlags wFlags)
-{
- QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(0, wFlags);
- proxy->setWidget(widget);
- addItem(proxy);
- return proxy;
-}
-
-/*!
- Removes the item \a item and all its children from the scene. The
- ownership of \a item is passed on to the caller (i.e.,
- QGraphicsScene will no longer delete \a item when destroyed).
-
- \sa addItem()
-*/
-void QGraphicsScene::removeItem(QGraphicsItem *item)
-{
- // ### Refactoring: This function shares much functionality with _q_removeItemLater()
- Q_D(QGraphicsScene);
- if (!item) {
- qWarning("QGraphicsScene::removeItem: cannot remove 0-item");
- return;
- }
- if (item->scene() != this) {
- qWarning("QGraphicsScene::removeItem: item %p's scene (%p)"
- " is different from this scene (%p)",
- item, item->scene(), this);
- return;
- }
-
- // Notify the item that it's scene is changing to 0, allowing the item to
- // react.
- const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
- QVariant::fromValue<QGraphicsScene *>(0)));
- QGraphicsScene *targetScene = qvariant_cast<QGraphicsScene *>(newSceneVariant);
- if (targetScene != 0 && targetScene != this) {
- targetScene->addItem(item);
- return;
- }
-
- d->removeItemHelper(item);
-
- // Deliver post-change notification
- item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
-
- d->updateInputMethodSensitivityInViews();
-}
-
-/*!
- When the scene is active, this functions returns the scene's current focus
- item, or 0 if no item currently has focus. When the scene is inactive, this
- functions returns the item that will gain input focus when the scene becomes
- active.
-
- The focus item receives keyboard input when the scene receives a
- key event.
-
- \sa setFocusItem(), QGraphicsItem::hasFocus(), isActive()
-*/
-QGraphicsItem *QGraphicsScene::focusItem() const
-{
- Q_D(const QGraphicsScene);
- return isActive() ? d->focusItem : d->passiveFocusItem;
-}
-
-/*!
- Sets the scene's focus item to \a item, with the focus reason \a
- focusReason, after removing focus from any previous item that may have had
- focus.
-
- If \a item is 0, or if it either does not accept focus (i.e., it does not
- have the QGraphicsItem::ItemIsFocusable flag enabled), or is not visible
- or not enabled, this function only removes focus from any previous
- focusitem.
-
- If item is not 0, and the scene does not currently have focus (i.e.,
- hasFocus() returns false), this function will call setFocus()
- automatically.
-
- \sa focusItem(), hasFocus(), setFocus()
-*/
-void QGraphicsScene::setFocusItem(QGraphicsItem *item, Qt::FocusReason focusReason)
-{
- Q_D(QGraphicsScene);
- if (item)
- item->setFocus(focusReason);
- else
- d->setFocusItemHelper(item, focusReason);
-}
-
-/*!
- Returns true if the scene has focus; otherwise returns false. If the scene
- has focus, it will will forward key events from QKeyEvent to any item that
- has focus.
-
- \sa setFocus(), setFocusItem()
-*/
-bool QGraphicsScene::hasFocus() const
-{
- Q_D(const QGraphicsScene);
- return d->hasFocus;
-}
-
-/*!
- Sets focus on the scene by sending a QFocusEvent to the scene, passing \a
- focusReason as the reason. If the scene regains focus after having
- previously lost it while an item had focus, the last focus item will
- receive focus with \a focusReason as the reason.
-
- If the scene already has focus, this function does nothing.
-
- \sa hasFocus(), clearFocus(), setFocusItem()
-*/
-void QGraphicsScene::setFocus(Qt::FocusReason focusReason)
-{
- Q_D(QGraphicsScene);
- if (d->hasFocus || !isActive())
- return;
- QFocusEvent event(QEvent::FocusIn, focusReason);
- QCoreApplication::sendEvent(this, &event);
-}
-
-/*!
- Clears focus from the scene. If any item has focus when this function is
- called, it will lose focus, and regain focus again once the scene regains
- focus.
-
- A scene that does not have focus ignores key events.
-
- \sa hasFocus(), setFocus(), setFocusItem()
-*/
-void QGraphicsScene::clearFocus()
-{
- Q_D(QGraphicsScene);
- if (d->hasFocus) {
- d->hasFocus = false;
- d->passiveFocusItem = d->focusItem;
- setFocusItem(0, Qt::OtherFocusReason);
- }
-}
-
-/*!
- \property QGraphicsScene::stickyFocus
- \brief whether clicking into the scene background will clear focus
-
- \since 4.6
-
- In a QGraphicsScene with stickyFocus set to true, focus will remain
- unchanged when the user clicks into the scene background or on an item
- that does not accept focus. Otherwise, focus will be cleared.
-
- By default, this property is false.
-
- Focus changes in response to a mouse press. You can reimplement
- mousePressEvent() in a subclass of QGraphicsScene to toggle this property
- based on where the user has clicked.
-
- \sa clearFocus(), setFocusItem()
-*/
-void QGraphicsScene::setStickyFocus(bool enabled)
-{
- Q_D(QGraphicsScene);
- d->stickyFocus = enabled;
-}
-bool QGraphicsScene::stickyFocus() const
-{
- Q_D(const QGraphicsScene);
- return d->stickyFocus;
-}
-
-/*!
- Returns the current mouse grabber item, or 0 if no item is currently
- grabbing the mouse. The mouse grabber item is the item that receives all
- mouse events sent to the scene.
-
- An item becomes a mouse grabber when it receives and accepts a
- mouse press event, and it stays the mouse grabber until either of
- the following events occur:
-
- \list
- \o If the item receives a mouse release event when there are no other
- buttons pressed, it loses the mouse grab.
- \o If the item becomes invisible (i.e., someone calls \c {item->setVisible(false)}),
- or if it becomes disabled (i.e., someone calls \c {item->setEnabled(false)}),
- it loses the mouse grab.
- \o If the item is removed from the scene, it loses the mouse grab.
- \endlist
-
- If the item loses its mouse grab, the scene will ignore all mouse events
- until a new item grabs the mouse (i.e., until a new item receives a mouse
- press event).
-*/
-QGraphicsItem *QGraphicsScene::mouseGrabberItem() const
-{
- Q_D(const QGraphicsScene);
- return !d->mouseGrabberItems.isEmpty() ? d->mouseGrabberItems.last() : 0;
-}
-
-/*!
- \property QGraphicsScene::backgroundBrush
- \brief the background brush of the scene.
-
- Set this property to changes the scene's background to a different color,
- gradient or texture. The default background brush is Qt::NoBrush. The
- background is drawn before (behind) the items.
-
- Example:
-
- \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 3
-
- QGraphicsScene::render() calls drawBackground() to draw the scene
- background. For more detailed control over how the background is drawn,
- you can reimplement drawBackground() in a subclass of QGraphicsScene.
-*/
-QBrush QGraphicsScene::backgroundBrush() const
-{
- Q_D(const QGraphicsScene);
- return d->backgroundBrush;
-}
-void QGraphicsScene::setBackgroundBrush(const QBrush &brush)
-{
- Q_D(QGraphicsScene);
- d->backgroundBrush = brush;
- foreach (QGraphicsView *view, d->views) {
- view->resetCachedContent();
- view->viewport()->update();
- }
- update();
-}
-
-/*!
- \property QGraphicsScene::foregroundBrush
- \brief the foreground brush of the scene.
-
- Change this property to set the scene's foreground to a different
- color, gradient or texture.
-
- The foreground is drawn after (on top of) the items. The default
- foreground brush is Qt::NoBrush ( i.e. the foreground is not
- drawn).
-
- Example:
-
- \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 4
-
- QGraphicsScene::render() calls drawForeground() to draw the scene
- foreground. For more detailed control over how the foreground is
- drawn, you can reimplement the drawForeground() function in a
- QGraphicsScene subclass.
-*/
-QBrush QGraphicsScene::foregroundBrush() const
-{
- Q_D(const QGraphicsScene);
- return d->foregroundBrush;
-}
-void QGraphicsScene::setForegroundBrush(const QBrush &brush)
-{
- Q_D(QGraphicsScene);
- d->foregroundBrush = brush;
- foreach (QGraphicsView *view, views())
- view->viewport()->update();
- update();
-}
-
-/*!
- This method is used by input methods to query a set of properties of
- the scene to be able to support complex input method operations as support
- for surrounding text and reconversions.
-
- The \a query parameter specifies which property is queried.
-
- \sa QWidget::inputMethodQuery()
-*/
-QVariant QGraphicsScene::inputMethodQuery(Qt::InputMethodQuery query) const
-{
- Q_D(const QGraphicsScene);
- if (!d->focusItem || !(d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
- return QVariant();
- const QTransform matrix = d->focusItem->sceneTransform();
- QVariant value = d->focusItem->inputMethodQuery(query);
- if (value.type() == QVariant::RectF)
- value = matrix.mapRect(value.toRectF());
- else if (value.type() == QVariant::PointF)
- value = matrix.map(value.toPointF());
- else if (value.type() == QVariant::Rect)
- value = matrix.mapRect(value.toRect());
- else if (value.type() == QVariant::Point)
- value = matrix.map(value.toPoint());
- return value;
-}
-
-/*!
- \fn void QGraphicsScene::update(const QRectF &rect)
- Schedules a redraw of the area \a rect on the scene.
-
- \sa sceneRect(), changed()
-*/
-void QGraphicsScene::update(const QRectF &rect)
-{
- Q_D(QGraphicsScene);
- if (d->updateAll || (rect.isEmpty() && !rect.isNull()))
- return;
-
- // Check if anyone's connected; if not, we can send updates directly to
- // the views. Otherwise or if there are no views, use old behavior.
- bool directUpdates = !(d->isSignalConnected(d->changedSignalIndex)) && !d->views.isEmpty();
- if (rect.isNull()) {
- d->updateAll = true;
- d->updatedRects.clear();
- if (directUpdates) {
- // Update all views.
- for (int i = 0; i < d->views.size(); ++i)
- d->views.at(i)->d_func()->fullUpdatePending = true;
- }
- } else {
- if (directUpdates) {
- // Update all views.
- for (int i = 0; i < d->views.size(); ++i) {
- QGraphicsView *view = d->views.at(i);
- if (view->isTransformed())
- view->d_func()->updateRectF(view->viewportTransform().mapRect(rect));
- else
- view->d_func()->updateRectF(rect);
- }
- } else {
- d->updatedRects << rect;
- }
- }
-
- if (!d->calledEmitUpdated) {
- d->calledEmitUpdated = true;
- QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection);
- }
-}
-
-/*!
- \fn void QGraphicsScene::update(qreal x, qreal y, qreal w, qreal h)
- \overload
- \since 4.3
-
- This function is equivalent to calling update(QRectF(\a x, \a y, \a w,
- \a h));
-*/
-
-/*!
- Invalidates and schedules a redraw of the \a layers in \a rect on the
- scene. Any cached content in \a layers is unconditionally invalidated and
- redrawn.
-
- You can use this function overload to notify QGraphicsScene of changes to
- the background or the foreground of the scene. This function is commonly
- used for scenes with tile-based backgrounds to notify changes when
- QGraphicsView has enabled
- \l{QGraphicsView::CacheBackground}{CacheBackground}.
-
- Example:
-
- \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 5
-
- Note that QGraphicsView currently supports background caching only (see
- QGraphicsView::CacheBackground). This function is equivalent to calling
- update() if any layer but BackgroundLayer is passed.
-
- \sa QGraphicsView::resetCachedContent()
-*/
-void QGraphicsScene::invalidate(const QRectF &rect, SceneLayers layers)
-{
- foreach (QGraphicsView *view, views())
- view->invalidateScene(rect, layers);
- update(rect);
-}
-
-/*!
- \fn void QGraphicsScene::invalidate(qreal x, qreal y, qreal w, qreal h, SceneLayers layers)
- \overload
- \since 4.3
-
- This convenience function is equivalent to calling invalidate(QRectF(\a x, \a
- y, \a w, \a h), \a layers);
-*/
-
-/*!
- Returns a list of all the views that display this scene.
-
- \sa QGraphicsView::scene()
-*/
-QList <QGraphicsView *> QGraphicsScene::views() const
-{
- Q_D(const QGraphicsScene);
- return d->views;
-}
-
-/*!
- This slot \e advances the scene by one step, by calling
- QGraphicsItem::advance() for all items on the scene. This is done in two
- phases: in the first phase, all items are notified that the scene is about
- to change, and in the second phase all items are notified that they can
- move. In the first phase, QGraphicsItem::advance() is called passing a
- value of 0 as an argument, and 1 is passed in the second phase.
-
- \sa QGraphicsItem::advance(), QGraphicsItemAnimation, QTimeLine
-*/
-void QGraphicsScene::advance()
-{
- for (int i = 0; i < 2; ++i) {
- foreach (QGraphicsItem *item, items())
- item->advance(i);
- }
-}
-
-/*!
- Processes the event \a event, and dispatches it to the respective
- event handlers.
-
- In addition to calling the convenience event handlers, this
- function is responsible for converting mouse move events to hover
- events for when there is no mouse grabber item. Hover events are
- delivered directly to items; there is no convenience function for
- them.
-
- Unlike QWidget, QGraphicsScene does not have the convenience functions
- \l{QWidget::}{enterEvent()} and \l{QWidget::}{leaveEvent()}. Use this
- function to obtain those events instead.
-
- \sa contextMenuEvent(), keyPressEvent(), keyReleaseEvent(),
- mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(),
- mouseDoubleClickEvent(), focusInEvent(), focusOutEvent()
-*/
-bool QGraphicsScene::event(QEvent *event)
-{
- Q_D(QGraphicsScene);
-
- switch (event->type()) {
- case QEvent::GraphicsSceneMousePress:
- case QEvent::GraphicsSceneMouseMove:
- case QEvent::GraphicsSceneMouseRelease:
- case QEvent::GraphicsSceneMouseDoubleClick:
- case QEvent::GraphicsSceneHoverEnter:
- case QEvent::GraphicsSceneHoverLeave:
- case QEvent::GraphicsSceneHoverMove:
- case QEvent::TouchBegin:
- case QEvent::TouchUpdate:
- case QEvent::TouchEnd:
- // Reset the under-mouse list to ensure that this event gets fresh
- // item-under-mouse data. Be careful about this list; if people delete
- // items from inside event handlers, this list can quickly end up
- // having stale pointers in it. We need to clear it before dispatching
- // events that use it.
- // ### this should only be cleared if we received a new mouse move event,
- // which relies on us fixing the replay mechanism in QGraphicsView.
- d->cachedItemsUnderMouse.clear();
- default:
- break;
- }
-
- switch (event->type()) {
- case QEvent::GraphicsSceneDragEnter:
- dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
- break;
- case QEvent::GraphicsSceneDragMove:
- dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
- break;
- case QEvent::GraphicsSceneDragLeave:
- dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
- break;
- case QEvent::GraphicsSceneDrop:
- dropEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
- break;
- case QEvent::GraphicsSceneContextMenu:
- contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent *>(event));
- break;
- case QEvent::KeyPress:
- if (!d->focusItem) {
- QKeyEvent *k = static_cast<QKeyEvent *>(event);
- if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
- if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
- bool res = false;
- if (k->key() == Qt::Key_Backtab
- || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) {
- res = focusNextPrevChild(false);
- } else if (k->key() == Qt::Key_Tab) {
- res = focusNextPrevChild(true);
- }
- if (!res)
- event->ignore();
- return true;
- }
- }
- }
- keyPressEvent(static_cast<QKeyEvent *>(event));
- break;
- case QEvent::KeyRelease:
- keyReleaseEvent(static_cast<QKeyEvent *>(event));
- break;
- case QEvent::ShortcutOverride: {
- QGraphicsItem *parent = focusItem();
- while (parent) {
- d->sendEvent(parent, event);
- if (event->isAccepted())
- return true;
- parent = parent->parentItem();
- }
- }
- return false;
- case QEvent::GraphicsSceneMouseMove:
- {
- QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent *>(event);
- d->lastSceneMousePos = mouseEvent->scenePos();
- mouseMoveEvent(mouseEvent);
- break;
- }
- case QEvent::GraphicsSceneMousePress:
- mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
- break;
- case QEvent::GraphicsSceneMouseRelease:
- mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
- break;
- case QEvent::GraphicsSceneMouseDoubleClick:
- mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
- break;
- case QEvent::GraphicsSceneWheel:
- wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event));
- break;
- case QEvent::FocusIn:
- focusInEvent(static_cast<QFocusEvent *>(event));
- break;
- case QEvent::FocusOut:
- focusOutEvent(static_cast<QFocusEvent *>(event));
- break;
- case QEvent::GraphicsSceneHoverEnter:
- case QEvent::GraphicsSceneHoverLeave:
- case QEvent::GraphicsSceneHoverMove:
- {
- QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event);
- d->lastSceneMousePos = hoverEvent->scenePos();
- d->dispatchHoverEvent(hoverEvent);
- break;
- }
- case QEvent::Leave:
- // hackieshly unpacking the viewport pointer from the leave event.
- d->leaveScene(reinterpret_cast<QWidget *>(event->d));
- break;
- case QEvent::GraphicsSceneHelp:
- helpEvent(static_cast<QGraphicsSceneHelpEvent *>(event));
- break;
- case QEvent::InputMethod:
- inputMethodEvent(static_cast<QInputMethodEvent *>(event));
- break;
- case QEvent::WindowActivate:
- if (!d->activationRefCount++) {
- if (d->lastActivePanel) {
- // Activate the last panel.
- d->setActivePanelHelper(d->lastActivePanel, true);
- } else if (d->tabFocusFirst && d->tabFocusFirst->isPanel()) {
- // Activate the panel of the first item in the tab focus
- // chain.
- d->setActivePanelHelper(d->tabFocusFirst, true);
- } else {
- // Activate all toplevel items.
- QEvent event(QEvent::WindowActivate);
- foreach (QGraphicsItem *item, items()) {
- if (item->isVisible() && !item->isPanel() && !item->parentItem())
- sendEvent(item, &event);
- }
- }
- }
- break;
- case QEvent::WindowDeactivate:
- if (!--d->activationRefCount) {
- if (d->activePanel) {
- // Deactivate the active panel (but keep it so we can
- // reactivate it later).
- QGraphicsItem *lastActivePanel = d->activePanel;
- d->setActivePanelHelper(0, true);
- d->lastActivePanel = lastActivePanel;
- } else {
- // Activate all toplevel items.
- QEvent event(QEvent::WindowDeactivate);
- foreach (QGraphicsItem *item, items()) {
- if (item->isVisible() && !item->isPanel() && !item->parentItem())
- sendEvent(item, &event);
- }
- }
- }
- break;
- case QEvent::ApplicationFontChange: {
- // Resolve the existing scene font.
- d->resolveFont();
- break;
- }
- case QEvent::FontChange:
- // Update the entire scene when the font changes.
- update();
- break;
- case QEvent::ApplicationPaletteChange: {
- // Resolve the existing scene palette.
- d->resolvePalette();
- break;
- }
- case QEvent::PaletteChange:
- // Update the entire scene when the palette changes.
- update();
- break;
- case QEvent::StyleChange:
- // Reresolve all widgets' styles. Update all top-level widgets'
- // geometries that do not have an explicit style set.
- update();
- break;
- case QEvent::TouchBegin:
- case QEvent::TouchUpdate:
- case QEvent::TouchEnd:
- d->touchEventHandler(static_cast<QTouchEvent *>(event));
- break;
-#ifndef QT_NO_GESTURES
- case QEvent::Gesture:
- case QEvent::GestureOverride:
- d->gestureEventHandler(static_cast<QGestureEvent *>(event));
- break;
-#endif // QT_NO_GESTURES
- default:
- return QObject::event(event);
- }
- return true;
-}
-
-/*!
- \reimp
-
- QGraphicsScene filters QApplication's events to detect palette and font
- changes.
-*/
-bool QGraphicsScene::eventFilter(QObject *watched, QEvent *event)
-{
- if (watched != qApp)
- return false;
-
- switch (event->type()) {
- case QEvent::ApplicationPaletteChange:
- QApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
- break;
- case QEvent::ApplicationFontChange:
- QApplication::postEvent(this, new QEvent(QEvent::ApplicationFontChange));
- break;
- default:
- break;
- }
- return false;
-}
-
-/*!
- This event handler, for event \a contextMenuEvent, can be reimplemented in
- a subclass to receive context menu events. The default implementation
- forwards the event to the topmost item that accepts context menu events at
- the position of the event. If no items accept context menu events at this
- position, the event is ignored.
-
- \sa QGraphicsItem::contextMenuEvent()
-*/
-void QGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *contextMenuEvent)
-{
- Q_D(QGraphicsScene);
- // Ignore by default.
- contextMenuEvent->ignore();
-
- // Send the event to all items at this position until one item accepts the
- // event.
- foreach (QGraphicsItem *item, d->itemsAtPosition(contextMenuEvent->screenPos(),
- contextMenuEvent->scenePos(),
- contextMenuEvent->widget())) {
- contextMenuEvent->setPos(item->d_ptr->genericMapFromScene(contextMenuEvent->scenePos(),
- contextMenuEvent->widget()));
- contextMenuEvent->accept();
- if (!d->sendEvent(item, contextMenuEvent))
- break;
-
- if (contextMenuEvent->isAccepted())
- break;
- }
-}
-
-/*!
- This event handler, for event \a event, can be reimplemented in a subclass
- to receive drag enter events for the scene.
-
- The default implementation accepts the event and prepares the scene to
- accept drag move events.
-
- \sa QGraphicsItem::dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(),
- dropEvent()
-*/
-void QGraphicsScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
-{
- Q_D(QGraphicsScene);
- d->dragDropItem = 0;
- d->lastDropAction = Qt::IgnoreAction;
- event->accept();
-}
-
-/*!
- This event handler, for event \a event, can be reimplemented in a subclass
- to receive drag move events for the scene.
-
- \sa QGraphicsItem::dragMoveEvent(), dragEnterEvent(), dragLeaveEvent(),
- dropEvent()
-*/
-void QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
-{
- Q_D(QGraphicsScene);
- event->ignore();
-
- if (!d->mouseGrabberItems.isEmpty()) {
- // Mouse grabbers that start drag events lose the mouse grab.
- d->clearMouseGrabber();
- d->mouseGrabberButtonDownPos.clear();
- d->mouseGrabberButtonDownScenePos.clear();
- d->mouseGrabberButtonDownScreenPos.clear();
- }
-
- bool eventDelivered = false;
-
- // Find the topmost enabled items under the cursor. They are all
- // candidates for accepting drag & drop events.
- foreach (QGraphicsItem *item, d->itemsAtPosition(event->screenPos(),
- event->scenePos(),
- event->widget())) {
- if (!item->isEnabled() || !item->acceptDrops())
- continue;
-
- if (item != d->dragDropItem) {
- // Enter the new drag drop item. If it accepts the event, we send
- // the leave to the parent item.
- QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);
- d->cloneDragDropEvent(&dragEnter, event);
- dragEnter.setDropAction(event->proposedAction());
- d->sendDragDropEvent(item, &dragEnter);
- event->setAccepted(dragEnter.isAccepted());
- event->setDropAction(dragEnter.dropAction());
- if (!event->isAccepted()) {
- // Propagate to the item under
- continue;
- }
-
- d->lastDropAction = event->dropAction();
-
- if (d->dragDropItem) {
- // Leave the last drag drop item. A perfect implementation
- // would set the position of this event to the point where
- // this event and the last event intersect with the item's
- // shape, but that's not easy to do. :-)
- QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
- d->cloneDragDropEvent(&dragLeave, event);
- d->sendDragDropEvent(d->dragDropItem, &dragLeave);
- }
-
- // We've got a new drag & drop item
- d->dragDropItem = item;
- }
-
- // Send the move event.
- event->setDropAction(d->lastDropAction);
- event->accept();
- d->sendDragDropEvent(item, event);
- if (event->isAccepted())
- d->lastDropAction = event->dropAction();
- eventDelivered = true;
- break;
- }
-
- if (!eventDelivered) {
- if (d->dragDropItem) {
- // Leave the last drag drop item
- QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
- d->cloneDragDropEvent(&dragLeave, event);
- d->sendDragDropEvent(d->dragDropItem, &dragLeave);
- d->dragDropItem = 0;
- }
- // Propagate
- event->setDropAction(Qt::IgnoreAction);
- }
-}
-
-/*!
- This event handler, for event \a event, can be reimplemented in a subclass
- to receive drag leave events for the scene.
-
- \sa QGraphicsItem::dragLeaveEvent(), dragEnterEvent(), dragMoveEvent(),
- dropEvent()
-*/
-void QGraphicsScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
-{
- Q_D(QGraphicsScene);
- if (d->dragDropItem) {
- // Leave the last drag drop item
- d->sendDragDropEvent(d->dragDropItem, event);
- d->dragDropItem = 0;
- }
-}
-
-/*!
- This event handler, for event \a event, can be reimplemented in a subclass
- to receive drop events for the scene.
-
- \sa QGraphicsItem::dropEvent(), dragEnterEvent(), dragMoveEvent(),
- dragLeaveEvent()
-*/
-void QGraphicsScene::dropEvent(QGraphicsSceneDragDropEvent *event)
-{
- Q_UNUSED(event);
- Q_D(QGraphicsScene);
- if (d->dragDropItem) {
- // Drop on the last drag drop item
- d->sendDragDropEvent(d->dragDropItem, event);
- d->dragDropItem = 0;
- }
-}
-
-/*!
- This event handler, for event \a focusEvent, can be reimplemented in a
- subclass to receive focus in events.
-
- The default implementation sets focus on the scene, and then on the last
- focus item.
-
- \sa QGraphicsItem::focusOutEvent()
-*/
-void QGraphicsScene::focusInEvent(QFocusEvent *focusEvent)
-{
- Q_D(QGraphicsScene);
-
- d->hasFocus = true;
- switch (focusEvent->reason()) {
- case Qt::TabFocusReason:
- if (!focusNextPrevChild(true))
- focusEvent->ignore();
- break;
- case Qt::BacktabFocusReason:
- if (!focusNextPrevChild(false))
- focusEvent->ignore();
- break;
- default:
- if (d->passiveFocusItem) {
- // Set focus on the last focus item
- setFocusItem(d->passiveFocusItem, focusEvent->reason());
- }
- break;
- }
-}
-
-/*!
- This event handler, for event \a focusEvent, can be reimplemented in a
- subclass to receive focus out events.
-
- The default implementation removes focus from any focus item, then removes
- focus from the scene.
-
- \sa QGraphicsItem::focusInEvent()
-*/
-void QGraphicsScene::focusOutEvent(QFocusEvent *focusEvent)
-{
- Q_D(QGraphicsScene);
- d->hasFocus = false;
- d->passiveFocusItem = d->focusItem;
- setFocusItem(0, focusEvent->reason());
-
- // Remove all popups when the scene loses focus.
- if (!d->popupWidgets.isEmpty())
- d->removePopup(d->popupWidgets.first());
-}
-
-/*!
- This event handler, for event \a helpEvent, can be
- reimplemented in a subclass to receive help events. The events
- are of type QEvent::ToolTip, which are created when a tooltip is
- requested.
-
- The default implementation shows the tooltip of the topmost
- item, i.e., the item with the highest z-value, at the mouse
- cursor position. If no item has a tooltip set, this function
- does nothing.
-
- \sa QGraphicsItem::toolTip(), QGraphicsSceneHelpEvent
-*/
-void QGraphicsScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent)
-{
-#ifdef QT_NO_TOOLTIP
- Q_UNUSED(helpEvent);
-#else
- // Find the first item that does tooltips
- Q_D(QGraphicsScene);
- QList<QGraphicsItem *> itemsAtPos = d->itemsAtPosition(helpEvent->screenPos(),
- helpEvent->scenePos(),
- helpEvent->widget());
- QGraphicsItem *toolTipItem = 0;
- for (int i = 0; i < itemsAtPos.size(); ++i) {
- QGraphicsItem *tmp = itemsAtPos.at(i);
- if (tmp->d_func()->isProxyWidget()) {
- // if the item is a proxy widget, the event is forwarded to it
- sendEvent(tmp, helpEvent);
- if (helpEvent->isAccepted())
- return;
- }
- if (!tmp->toolTip().isEmpty()) {
- toolTipItem = tmp;
- break;
- }
- }
-
- // Show or hide the tooltip
- QString text;
- QPoint point;
- if (toolTipItem && !toolTipItem->toolTip().isEmpty()) {
- text = toolTipItem->toolTip();
- point = helpEvent->screenPos();
- }
- QToolTip::showText(point, text, helpEvent->widget());
- helpEvent->setAccepted(!text.isEmpty());
-#endif
-}
-
-bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const
-{
- return (item->d_ptr->acceptsHover
- || (item->d_ptr->isWidget
- && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration()))
- && !item->isBlockedByModalPanel();
-}
-
-/*!
- This event handler, for event \a hoverEvent, can be reimplemented in a
- subclass to receive hover enter events. The default implementation
- forwards the event to the topmost item that accepts hover events at the
- scene position from the event.
-
- \sa QGraphicsItem::hoverEvent(), QGraphicsItem::setAcceptHoverEvents()
-*/
-bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent)
-{
- if (allItemsIgnoreHoverEvents)
- return false;
-
- // Find the first item that accepts hover events, reusing earlier
- // calculated data is possible.
- if (cachedItemsUnderMouse.isEmpty()) {
- cachedItemsUnderMouse = itemsAtPosition(hoverEvent->screenPos(),
- hoverEvent->scenePos(),
- hoverEvent->widget());
- }
-
- QGraphicsItem *item = 0;
- for (int i = 0; i < cachedItemsUnderMouse.size(); ++i) {
- QGraphicsItem *tmp = cachedItemsUnderMouse.at(i);
- if (itemAcceptsHoverEvents_helper(tmp)) {
- item = tmp;
- break;
- }
- }
-
- // Find the common ancestor item for the new topmost hoverItem and the
- // last item in the hoverItem list.
- QGraphicsItem *commonAncestorItem = (item && !hoverItems.isEmpty()) ? item->commonAncestorItem(hoverItems.last()) : 0;
- while (commonAncestorItem && !itemAcceptsHoverEvents_helper(commonAncestorItem))
- commonAncestorItem = commonAncestorItem->parentItem();
- if (commonAncestorItem && commonAncestorItem->panel() != item->panel()) {
- // The common ancestor isn't in the same panel as the two hovered
- // items.
- commonAncestorItem = 0;
- }
-
- // Check if the common ancestor item is known.
- int index = commonAncestorItem ? hoverItems.indexOf(commonAncestorItem) : -1;
- // Send hover leaves to any existing hovered children of the common
- // ancestor item.
- for (int i = hoverItems.size() - 1; i > index; --i) {
- QGraphicsItem *lastItem = hoverItems.takeLast();
- if (itemAcceptsHoverEvents_helper(lastItem))
- sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, hoverEvent);
- }
-
- // Item is a child of a known item. Generate enter events for the
- // missing links.
- QList<QGraphicsItem *> parents;
- QGraphicsItem *parent = item;
- while (parent && parent != commonAncestorItem) {
- parents.prepend(parent);
- if (parent->isPanel()) {
- // Stop at the panel - we don't deliver beyond this point.
- break;
- }
- parent = parent->parentItem();
- }
- for (int i = 0; i < parents.size(); ++i) {
- parent = parents.at(i);
- hoverItems << parent;
- if (itemAcceptsHoverEvents_helper(parent))
- sendHoverEvent(QEvent::GraphicsSceneHoverEnter, parent, hoverEvent);
- }
-
- // Generate a move event for the item itself
- if (item
- && !hoverItems.isEmpty()
- && item == hoverItems.last()) {
- sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, hoverEvent);
- return true;
- }
- return false;
-}
-
-/*!
- \internal
-
- Handles all actions necessary to clean up the scene when the mouse leaves
- the view.
-*/
-void QGraphicsScenePrivate::leaveScene(QWidget *viewport)
-{
-#ifndef QT_NO_TOOLTIP
- QToolTip::hideText();
-#endif
- QGraphicsView *view = qobject_cast<QGraphicsView *>(viewport->parent());
- // Send HoverLeave events to all existing hover items, topmost first.
- QGraphicsSceneHoverEvent hoverEvent;
- hoverEvent.setWidget(viewport);
-
- if (view) {
- QPoint cursorPos = QCursor::pos();
- hoverEvent.setScenePos(view->mapToScene(viewport->mapFromGlobal(cursorPos)));
- hoverEvent.setLastScenePos(hoverEvent.scenePos());
- hoverEvent.setScreenPos(cursorPos);
- hoverEvent.setLastScreenPos(hoverEvent.screenPos());
- }
-
- while (!hoverItems.isEmpty()) {
- QGraphicsItem *lastItem = hoverItems.takeLast();
- if (itemAcceptsHoverEvents_helper(lastItem))
- sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, &hoverEvent);
- }
-}
-
-/*!
- This event handler, for event \a keyEvent, can be reimplemented in a
- subclass to receive keypress events. The default implementation forwards
- the event to current focus item.
-
- \sa QGraphicsItem::keyPressEvent(), focusItem()
-*/
-void QGraphicsScene::keyPressEvent(QKeyEvent *keyEvent)
-{
- // ### Merge this function with keyReleaseEvent; they are identical
- // ### (except this comment).
- Q_D(QGraphicsScene);
- QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
- if (!item)
- item = focusItem();
- if (item) {
- QGraphicsItem *p = item;
- do {
- // Accept the event by default
- keyEvent->accept();
- // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
- // is filtered out, stop propagating it.
- if (p->isBlockedByModalPanel())
- break;
- if (!d->sendEvent(p, keyEvent))
- break;
- } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
- } else {
- keyEvent->ignore();
- }
-}
-
-/*!
- This event handler, for event \a keyEvent, can be reimplemented in a
- subclass to receive key release events. The default implementation
- forwards the event to current focus item.
-
- \sa QGraphicsItem::keyReleaseEvent(), focusItem()
-*/
-void QGraphicsScene::keyReleaseEvent(QKeyEvent *keyEvent)
-{
- // ### Merge this function with keyPressEvent; they are identical (except
- // ### this comment).
- Q_D(QGraphicsScene);
- QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
- if (!item)
- item = focusItem();
- if (item) {
- QGraphicsItem *p = item;
- do {
- // Accept the event by default
- keyEvent->accept();
- // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
- // is filtered out, stop propagating it.
- if (p->isBlockedByModalPanel())
- break;
- if (!d->sendEvent(p, keyEvent))
- break;
- } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
- } else {
- keyEvent->ignore();
- }
-}
-
-/*!
- This event handler, for event \a mouseEvent, can be reimplemented
- in a subclass to receive mouse press events for the scene.
-
- The default implementation depends on the state of the scene. If
- there is a mouse grabber item, then the event is sent to the mouse
- grabber. Otherwise, it is forwarded to the topmost item that
- accepts mouse events at the scene position from the event, and
- that item promptly becomes the mouse grabber item.
-
- If there is no item at the given position on the scene, the
- selection area is reset, any focus item loses its input focus, and
- the event is then ignored.
-
- \sa QGraphicsItem::mousePressEvent(),
- QGraphicsItem::setAcceptedMouseButtons()
-*/
-void QGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
-{
- Q_D(QGraphicsScene);
- if (d->mouseGrabberItems.isEmpty()) {
- // Dispatch hover events
- QGraphicsSceneHoverEvent hover;
- _q_hoverFromMouseEvent(&hover, mouseEvent);
- d->dispatchHoverEvent(&hover);
- }
-
- d->mousePressEventHandler(mouseEvent);
-}
-
-/*!
- This event handler, for event \a mouseEvent, can be reimplemented
- in a subclass to receive mouse move events for the scene.
-
- The default implementation depends on the mouse grabber state. If there is
- a mouse grabber item, the event is sent to the mouse grabber. If there
- are any items that accept hover events at the current position, the event
- is translated into a hover event and accepted; otherwise it's ignored.
-
- \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseReleaseEvent(),
- QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
-*/
-void QGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
-{
- Q_D(QGraphicsScene);
- if (d->mouseGrabberItems.isEmpty()) {
- if (mouseEvent->buttons())
- return;
- QGraphicsSceneHoverEvent hover;
- _q_hoverFromMouseEvent(&hover, mouseEvent);
- mouseEvent->setAccepted(d->dispatchHoverEvent(&hover));
- return;
- }
-
- // Forward the event to the mouse grabber
- d->sendMouseEvent(mouseEvent);
- mouseEvent->accept();
-}
-
-/*!
- This event handler, for event \a mouseEvent, can be reimplemented
- in a subclass to receive mouse release events for the scene.
-
- The default implementation depends on the mouse grabber state. If
- there is no mouse grabber, the event is ignored. Otherwise, if
- there is a mouse grabber item, the event is sent to the mouse
- grabber. If this mouse release represents the last pressed button
- on the mouse, the mouse grabber item then loses the mouse grab.
-
- \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
- QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
-*/
-void QGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
-{
- Q_D(QGraphicsScene);
- if (d->mouseGrabberItems.isEmpty()) {
- mouseEvent->ignore();
- return;
- }
-
- // Forward the event to the mouse grabber
- d->sendMouseEvent(mouseEvent);
- mouseEvent->accept();
-
- // Reset the mouse grabber when the last mouse button has been released.
- if (!mouseEvent->buttons()) {
- if (!d->mouseGrabberItems.isEmpty()) {
- d->lastMouseGrabberItem = d->mouseGrabberItems.last();
- if (d->lastMouseGrabberItemHasImplicitMouseGrab)
- d->mouseGrabberItems.last()->ungrabMouse();
- } else {
- d->lastMouseGrabberItem = 0;
- }
-
- // Generate a hoverevent
- QGraphicsSceneHoverEvent hoverEvent;
- _q_hoverFromMouseEvent(&hoverEvent, mouseEvent);
- d->dispatchHoverEvent(&hoverEvent);
- }
-}
-
-/*!
- This event handler, for event \a mouseEvent, can be reimplemented
- in a subclass to receive mouse doubleclick events for the scene.
-
- If someone doubleclicks on the scene, the scene will first receive
- a mouse press event, followed by a release event (i.e., a click),
- then a doubleclick event, and finally a release event. If the
- doubleclick event is delivered to a different item than the one
- that received the first press and release, it will be delivered as
- a press event. However, tripleclick events are not delivered as
- doubleclick events in this case.
-
- The default implementation is similar to mousePressEvent().
-
- \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
- QGraphicsItem::mouseReleaseEvent(), QGraphicsItem::setAcceptedMouseButtons()
-*/
-void QGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
-{
- Q_D(QGraphicsScene);
- d->mousePressEventHandler(mouseEvent);
-}
-
-/*!
- This event handler, for event \a wheelEvent, can be reimplemented in a
- subclass to receive mouse wheel events for the scene.
-
- By default, the event is delivered to the topmost visible item under the
- cursor. If ignored, the event propagates to the item beneath, and again
- until the event is accepted, or it reaches the scene. If no items accept
- the event, it is ignored.
-
- \sa QGraphicsItem::wheelEvent()
-*/
-void QGraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *wheelEvent)
-{
- Q_D(QGraphicsScene);
- QList<QGraphicsItem *> wheelCandidates = d->itemsAtPosition(wheelEvent->screenPos(),
- wheelEvent->scenePos(),
- wheelEvent->widget());
-
-#ifdef Q_WS_MAC
- // On Mac, ignore the event if the first item under the mouse is not the last opened
- // popup (or one of its descendant)
- if (!d->popupWidgets.isEmpty() && !wheelCandidates.isEmpty() && wheelCandidates.first() != d->popupWidgets.back() && !d->popupWidgets.back()->isAncestorOf(wheelCandidates.first())) {
- wheelEvent->accept();
- return;
- }
-#else
- // Find the first popup under the mouse (including the popup's descendants) starting from the last.
- // Remove all popups after the one found, or all or them if no popup is under the mouse.
- // Then continue with the event.
- QList<QGraphicsWidget *>::const_iterator iter = d->popupWidgets.end();
- while (--iter >= d->popupWidgets.begin() && !wheelCandidates.isEmpty()) {
- if (wheelCandidates.first() == *iter || (*iter)->isAncestorOf(wheelCandidates.first()))
- break;
- d->removePopup(*iter);
- }
-#endif
-
- bool hasSetFocus = false;
- foreach (QGraphicsItem *item, wheelCandidates) {
- if (!hasSetFocus && item->isEnabled()
- && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
- if (item->isWidget() && static_cast<QGraphicsWidget *>(item)->focusPolicy() == Qt::WheelFocus) {
- hasSetFocus = true;
- if (item != focusItem())
- setFocusItem(item, Qt::MouseFocusReason);
- }
- }
-
- wheelEvent->setPos(item->d_ptr->genericMapFromScene(wheelEvent->scenePos(),
- wheelEvent->widget()));
- wheelEvent->accept();
- bool isPanel = item->isPanel();
- d->sendEvent(item, wheelEvent);
- if (isPanel || wheelEvent->isAccepted())
- break;
- }
-}
-
-/*!
- This event handler, for event \a event, can be reimplemented in a
- subclass to receive input method events for the scene.
-
- The default implementation forwards the event to the focusItem().
- If no item currently has focus or the current focus item does not
- accept input methods, this function does nothing.
-
- \sa QGraphicsItem::inputMethodEvent()
-*/
-void QGraphicsScene::inputMethodEvent(QInputMethodEvent *event)
-{
- Q_D(QGraphicsScene);
- if (d->focusItem && (d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
- d->sendEvent(d->focusItem, event);
-}
-
-/*!
- Draws the background of the scene using \a painter, before any items and
- the foreground are drawn. Reimplement this function to provide a custom
- background for the scene.
-
- All painting is done in \e scene coordinates. The \a rect
- parameter is the exposed rectangle.
-
- If all you want is to define a color, texture, or gradient for the
- background, you can call setBackgroundBrush() instead.
-
- \sa drawForeground(), drawItems()
-*/
-void QGraphicsScene::drawBackground(QPainter *painter, const QRectF &rect)
-{
- Q_D(QGraphicsScene);
-
- if (d->backgroundBrush.style() != Qt::NoBrush) {
- if (d->painterStateProtection)
- painter->save();
- painter->setBrushOrigin(0, 0);
- painter->fillRect(rect, backgroundBrush());
- if (d->painterStateProtection)
- painter->restore();
- }
-}
-
-/*!
- Draws the foreground of the scene using \a painter, after the background
- and all items have been drawn. Reimplement this function to provide a
- custom foreground for the scene.
-
- All painting is done in \e scene coordinates. The \a rect
- parameter is the exposed rectangle.
-
- If all you want is to define a color, texture or gradient for the
- foreground, you can call setForegroundBrush() instead.
-
- \sa drawBackground(), drawItems()
-*/
-void QGraphicsScene::drawForeground(QPainter *painter, const QRectF &rect)
-{
- Q_D(QGraphicsScene);
-
- if (d->foregroundBrush.style() != Qt::NoBrush) {
- if (d->painterStateProtection)
- painter->save();
- painter->setBrushOrigin(0, 0);
- painter->fillRect(rect, foregroundBrush());
- if (d->painterStateProtection)
- painter->restore();
- }
-}
-
-static void _q_paintItem(QGraphicsItem *item, QPainter *painter,
- const QStyleOptionGraphicsItem *option, QWidget *widget,
- bool useWindowOpacity, bool painterStateProtection)
-{
- if (!item->isWidget()) {
- item->paint(painter, option, widget);
- return;
- }
- QGraphicsWidget *widgetItem = static_cast<QGraphicsWidget *>(item);
- QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(widgetItem);
- const qreal windowOpacity = (proxy && proxy->widget() && useWindowOpacity)
- ? proxy->widget()->windowOpacity() : 1.0;
- const qreal oldPainterOpacity = painter->opacity();
-
- if (qFuzzyIsNull(windowOpacity))
- return;
- // Set new painter opacity.
- if (windowOpacity < 1.0)
- painter->setOpacity(oldPainterOpacity * windowOpacity);
-
- // set layoutdirection on the painter
- Qt::LayoutDirection oldLayoutDirection = painter->layoutDirection();
- painter->setLayoutDirection(widgetItem->layoutDirection());
-
- if (widgetItem->isWindow() && widgetItem->windowType() != Qt::Popup && widgetItem->windowType() != Qt::ToolTip
- && !(widgetItem->windowFlags() & Qt::FramelessWindowHint)) {
- if (painterStateProtection)
- painter->save();
- widgetItem->paintWindowFrame(painter, option, widget);
- if (painterStateProtection)
- painter->restore();
- } else if (widgetItem->autoFillBackground()) {
- painter->fillRect(option->exposedRect, widgetItem->palette().window());
- }
-
- widgetItem->paint(painter, option, widget);
-
- // Restore layoutdirection on the painter.
- painter->setLayoutDirection(oldLayoutDirection);
- // Restore painter opacity.
- if (windowOpacity < 1.0)
- painter->setOpacity(oldPainterOpacity);
-}
-
-static void _q_paintIntoCache(QPixmap *pix, QGraphicsItem *item, const QRegion &pixmapExposed,
- const QTransform &itemToPixmap, QPainter::RenderHints renderHints,
- const QStyleOptionGraphicsItem *option, bool painterStateProtection)
-{
- QPixmap subPix;
- QPainter pixmapPainter;
- QRect br = pixmapExposed.boundingRect();
-
- // Don't use subpixmap if we get a full update.
- if (pixmapExposed.isEmpty() || (pixmapExposed.rectCount() == 1 && br.contains(pix->rect()))) {
- pix->fill(Qt::transparent);
- pixmapPainter.begin(pix);
- } else {
- subPix = QPixmap(br.size());
- subPix.fill(Qt::transparent);
- pixmapPainter.begin(&subPix);
- pixmapPainter.translate(-br.topLeft());
- if (!pixmapExposed.isEmpty()) {
- // Applied to subPix; paint is adjusted to the coordinate space is
- // correct.
- pixmapPainter.setClipRegion(pixmapExposed);
- }
- }
-
- pixmapPainter.setRenderHints(pixmapPainter.renderHints(), false);
- pixmapPainter.setRenderHints(renderHints, true);
- pixmapPainter.setWorldTransform(itemToPixmap, true);
-
- // Render.
- _q_paintItem(item, &pixmapPainter, option, 0, false, painterStateProtection);
- pixmapPainter.end();
-
- if (!subPix.isNull()) {
- // Blit the subpixmap into the main pixmap.
- pixmapPainter.begin(pix);
- pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
- pixmapPainter.setClipRegion(pixmapExposed);
- pixmapPainter.drawPixmap(br.topLeft(), subPix);
- pixmapPainter.end();
- }
-}
-
-// Copied from qpaintengine_vg.cpp
-// Returns true for 90, 180, and 270 degree rotations.
-static inline bool transformIsSimple(const QTransform& transform)
-{
- QTransform::TransformationType type = transform.type();
- if (type <= QTransform::TxScale) {
- return true;
- } else if (type == QTransform::TxRotate) {
- // Check for 90, and 270 degree rotations.
- qreal m11 = transform.m11();
- qreal m12 = transform.m12();
- qreal m21 = transform.m21();
- qreal m22 = transform.m22();
- if (m11 == 0.0f && m22 == 0.0f) {
- if (m12 == 1.0f && m21 == -1.0f)
- return true; // 90 degrees.
- else if (m12 == -1.0f && m21 == 1.0f)
- return true; // 270 degrees.
- else if (m12 == -1.0f && m21 == -1.0f)
- return true; // 90 degrees inverted y.
- else if (m12 == 1.0f && m21 == 1.0f)
- return true; // 270 degrees inverted y.
- }
- }
- return false;
-}
-
-/*!
- \internal
-
- Draws items directly, or using cache.
-*/
-void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painter,
- const QStyleOptionGraphicsItem *option, QWidget *widget,
- bool painterStateProtection)
-{
- QGraphicsItemPrivate *itemd = item->d_ptr.data();
- QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode);
-
- // Render directly, using no cache.
- if (cacheMode == QGraphicsItem::NoCache
-#ifdef Q_WS_X11
- || !X11->use_xrender
-#endif
- ) {
- _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget, true, painterStateProtection);
- return;
- }
-
- const qreal oldPainterOpacity = painter->opacity();
- qreal newPainterOpacity = oldPainterOpacity;
- QGraphicsProxyWidget *proxy = item->isWidget() ? qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(item)) : 0;
- if (proxy && proxy->widget()) {
- const qreal windowOpacity = proxy->widget()->windowOpacity();
- if (windowOpacity < 1.0)
- newPainterOpacity *= windowOpacity;
- }
-
- // Item's (local) bounding rect
- QRectF brect = item->boundingRect();
- QRectF adjustedBrect(brect);
- _q_adjustRect(&adjustedBrect);
- if (adjustedBrect.isEmpty())
- return;
-
- // Fetch the off-screen transparent buffer and exposed area info.
- QPixmapCache::Key pixmapKey;
- QPixmap pix;
- bool pixmapFound;
- QGraphicsItemCache *itemCache = itemd->extraItemCache();
- if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
- pixmapKey = itemCache->key;
- } else {
- pixmapKey = itemCache->deviceData.value(widget).key;
- }
-
- // Find pixmap in cache.
- pixmapFound = QPixmapCache::find(pixmapKey, &pix);
-
- // Render using item coordinate cache mode.
- if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
- QSize pixmapSize;
- bool fixedCacheSize = false;
- QRect br = brect.toAlignedRect();
- if ((fixedCacheSize = itemCache->fixedSize.isValid())) {
- pixmapSize = itemCache->fixedSize;
- } else {
- pixmapSize = br.size();
- }
-
- // Create or recreate the pixmap.
- int adjust = itemCache->fixedSize.isValid() ? 0 : 2;
- QSize adjustSize(adjust*2, adjust*2);
- br.adjust(-adjust, -adjust, adjust, adjust);
- if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) {
- pix = QPixmap(pixmapSize + adjustSize);
- itemCache->boundingRect = br;
- itemCache->exposed.clear();
- itemCache->allExposed = true;
- } else if (itemCache->boundingRect != br) {
- itemCache->boundingRect = br;
- itemCache->exposed.clear();
- itemCache->allExposed = true;
- }
-
- // Redraw any newly exposed areas.
- if (itemCache->allExposed || !itemCache->exposed.isEmpty()) {
-
- //We know that we will modify the pixmap, removing it from the cache
- //will detach the one we have and avoid a deep copy
- if (pixmapFound)
- QPixmapCache::remove(pixmapKey);
-
- // Fit the item's bounding rect into the pixmap's coordinates.
- QTransform itemToPixmap;
- if (fixedCacheSize) {
- const QPointF scale(pixmapSize.width() / brect.width(), pixmapSize.height() / brect.height());
- itemToPixmap.scale(scale.x(), scale.y());
- }
- itemToPixmap.translate(-br.x(), -br.y());
-
- // Generate the item's exposedRect and map its list of expose
- // rects to device coordinates.
- styleOptionTmp = *option;
- QRegion pixmapExposed;
- QRectF exposedRect;
- if (!itemCache->allExposed) {
- for (int i = 0; i < itemCache->exposed.size(); ++i) {
- QRectF r = itemCache->exposed.at(i);
- exposedRect |= r;
- pixmapExposed += itemToPixmap.mapRect(r).toAlignedRect();
- }
- } else {
- exposedRect = brect;
- }
- styleOptionTmp.exposedRect = exposedRect;
-
- // Render.
- _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
- &styleOptionTmp, painterStateProtection);
-
- // insert this pixmap into the cache.
- itemCache->key = QPixmapCache::insert(pix);
-
- // Reset expose data.
- itemCache->allExposed = false;
- itemCache->exposed.clear();
- }
-
- // Redraw the exposed area using the transformed painter. Depending on
- // the hardware, this may be a server-side operation, or an expensive
- // qpixmap-image-transform-pixmap roundtrip.
- if (newPainterOpacity != oldPainterOpacity) {
- painter->setOpacity(newPainterOpacity);
- painter->drawPixmap(br.topLeft(), pix);
- painter->setOpacity(oldPainterOpacity);
- } else {
- painter->drawPixmap(br.topLeft(), pix);
- }
- return;
- }
-
- // Render using device coordinate cache mode.
- if (cacheMode == QGraphicsItem::DeviceCoordinateCache) {
- // Find the item's bounds in device coordinates.
- QRectF deviceBounds = painter->worldTransform().mapRect(brect);
- QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
- if (deviceRect.isEmpty())
- return;
- QRect viewRect = widget ? widget->rect() : QRect();
- if (widget && !viewRect.intersects(deviceRect))
- return;
-
- // Resort to direct rendering if the device rect exceeds the
- // (optional) maximum bounds. (QGraphicsSvgItem uses this).
- QSize maximumCacheSize =
- itemd->extra(QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize).toSize();
- if (!maximumCacheSize.isEmpty()
- && (deviceRect.width() > maximumCacheSize.width()
- || deviceRect.height() > maximumCacheSize.height())) {
- _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget,
- oldPainterOpacity != newPainterOpacity, painterStateProtection);
- return;
- }
-
- // Create or reuse offscreen pixmap, possibly scroll/blit from the old one.
- // If the world transform is rotated we always recreate the cache to avoid
- // wrong blending.
- bool pixModified = false;
- QGraphicsItemCache::DeviceData *deviceData = &itemCache->deviceData[widget];
- bool invertable = true;
- QTransform diff = deviceData->lastTransform.inverted(&invertable);
- if (invertable)
- diff *= painter->worldTransform();
- deviceData->lastTransform = painter->worldTransform();
- bool allowPartialCacheExposure = false;
- bool simpleTransform = invertable && diff.type() <= QTransform::TxTranslate
- && transformIsSimple(painter->worldTransform());
- if (!simpleTransform) {
- pixModified = true;
- itemCache->allExposed = true;
- itemCache->exposed.clear();
- deviceData->cacheIndent = QPoint();
- pix = QPixmap();
- } else if (!viewRect.isNull()) {
- allowPartialCacheExposure = deviceData->cacheIndent != QPoint();
- }
-
- // Allow partial cache exposure if the device rect isn't fully contained and
- // deviceRect is 20% taller or wider than the viewRect.
- if (!allowPartialCacheExposure && !viewRect.isNull() && !viewRect.contains(deviceRect)) {
- allowPartialCacheExposure = (viewRect.width() * 1.2 < deviceRect.width())
- || (viewRect.height() * 1.2 < deviceRect.height());
- }
-
- QRegion scrollExposure;
- if (allowPartialCacheExposure) {
- // Part of pixmap is drawn. Either device contains viewrect (big
- // item covers whole screen) or parts of device are outside the
- // viewport. In either case the device rect must be the intersect
- // between the two.
- int dx = deviceRect.left() < viewRect.left() ? viewRect.left() - deviceRect.left() : 0;
- int dy = deviceRect.top() < viewRect.top() ? viewRect.top() - deviceRect.top() : 0;
- QPoint newCacheIndent(dx, dy);
- deviceRect &= viewRect;
-
- if (pix.isNull()) {
- deviceData->cacheIndent = QPoint();
- itemCache->allExposed = true;
- itemCache->exposed.clear();
- pixModified = true;
- }
-
- // Copy / "scroll" the old pixmap onto the new ole and calculate
- // scrolled exposure.
- if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size()) {
- QPoint diff = newCacheIndent - deviceData->cacheIndent;
- QPixmap newPix(deviceRect.size());
- // ### Investigate removing this fill (test with Plasma and
- // graphicssystem raster).
- newPix.fill(Qt::transparent);
- if (!pix.isNull()) {
- QPainter newPixPainter(&newPix);
- newPixPainter.drawPixmap(-diff, pix);
- newPixPainter.end();
- }
- QRegion exposed;
- exposed += newPix.rect();
- if (!pix.isNull())
- exposed -= QRect(-diff, pix.size());
- scrollExposure = exposed;
-
- pix = newPix;
- pixModified = true;
- }
- deviceData->cacheIndent = newCacheIndent;
- } else {
- // Full pixmap is drawn.
- deviceData->cacheIndent = QPoint();
-
- // Auto-adjust the pixmap size.
- if (deviceRect.size() != pix.size()) {
- // exposed needs to cover the whole pixmap
- pix = QPixmap(deviceRect.size());
- pixModified = true;
- itemCache->allExposed = true;
- itemCache->exposed.clear();
- }
- }
-
- // Check for newly invalidated areas.
- if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) {
- //We know that we will modify the pixmap, removing it from the cache
- //will detach the one we have and avoid a deep copy
- if (pixmapFound)
- QPixmapCache::remove(pixmapKey);
-
- // Construct an item-to-pixmap transform.
- QPointF p = deviceRect.topLeft();
- QTransform itemToPixmap = painter->worldTransform();
- if (!p.isNull())
- itemToPixmap *= QTransform::fromTranslate(-p.x(), -p.y());
-
- // Map the item's logical expose to pixmap coordinates.
- QRegion pixmapExposed = scrollExposure;
- if (!itemCache->allExposed) {
- const QVector<QRectF> &exposed = itemCache->exposed;
- for (int i = 0; i < exposed.size(); ++i)
- pixmapExposed += itemToPixmap.mapRect(exposed.at(i)).toRect().adjusted(-1, -1, 1, 1);
- }
-
- // Calculate the style option's exposedRect.
- QRectF br;
- if (itemCache->allExposed) {
- br = item->boundingRect();
- } else {
- const QVector<QRectF> &exposed = itemCache->exposed;
- for (int i = 0; i < exposed.size(); ++i)
- br |= exposed.at(i);
- QTransform pixmapToItem = itemToPixmap.inverted();
- foreach (QRect r, scrollExposure.rects())
- br |= pixmapToItem.mapRect(r);
- }
- styleOptionTmp = *option;
- styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1);
-
- // Render the exposed areas.
- _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
- &styleOptionTmp, painterStateProtection);
-
- // Reset expose data.
- pixModified = true;
- itemCache->allExposed = false;
- itemCache->exposed.clear();
- }
-
- if (pixModified) {
- // Insert this pixmap into the cache.
- deviceData->key = QPixmapCache::insert(pix);
- }
-
- // Redraw the exposed area using an untransformed painter. This
- // effectively becomes a bitblit that does not transform the cache.
- QTransform restoreTransform = painter->worldTransform();
- painter->setWorldTransform(QTransform());
- if (newPainterOpacity != oldPainterOpacity) {
- painter->setOpacity(newPainterOpacity);
- painter->drawPixmap(deviceRect.topLeft(), pix);
- painter->setOpacity(oldPainterOpacity);
- } else {
- painter->drawPixmap(deviceRect.topLeft(), pix);
- }
- painter->setWorldTransform(restoreTransform);
- return;
- }
-}
-
-void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const viewTransform,
- QRegion *exposedRegion, QWidget *widget)
-{
- // Make sure we don't have unpolished items before we draw.
- if (!unpolishedItems.isEmpty())
- _q_polishItems();
-
- updateAll = false;
- QRectF exposedSceneRect;
- if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) {
- exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1);
- if (viewTransform)
- exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect);
- }
- const QList<QGraphicsItem *> tli = index->estimateTopLevelItems(exposedSceneRect, Qt::AscendingOrder);
- for (int i = 0; i < tli.size(); ++i)
- drawSubtreeRecursive(tli.at(i), painter, viewTransform, exposedRegion, widget);
-}
-
-void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter,
- const QTransform *const viewTransform,
- QRegion *exposedRegion, QWidget *widget,
- qreal parentOpacity, const QTransform *const effectTransform)
-{
- Q_ASSERT(item);
-
- if (!item->d_ptr->visible)
- return;
-
- const bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
- const bool itemHasChildren = !item->d_ptr->children.isEmpty();
- if (!itemHasContents && !itemHasChildren)
- return; // Item has neither contents nor children!(?)
-
- const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
- const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
- if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity()))
- return;
-
- QTransform transform(Qt::Uninitialized);
- QTransform *transformPtr = 0;
- bool translateOnlyTransform = false;
-#define ENSURE_TRANSFORM_PTR \
- if (!transformPtr) { \
- Q_ASSERT(!itemIsUntransformable); \
- if (viewTransform) { \
- transform = item->d_ptr->sceneTransform; \
- transform *= *viewTransform; \
- transformPtr = &transform; \
- } else { \
- transformPtr = &item->d_ptr->sceneTransform; \
- translateOnlyTransform = item->d_ptr->sceneTransformTranslateOnly; \
- } \
- }
-
- // Update the item's scene transform if the item is transformable;
- // otherwise calculate the full transform,
- bool wasDirtyParentSceneTransform = false;
- const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
- if (itemIsUntransformable) {
- transform = item->deviceTransform(viewTransform ? *viewTransform : QTransform());
- transformPtr = &transform;
- } else if (item->d_ptr->dirtySceneTransform) {
- item->d_ptr->updateSceneTransformFromParent();
- Q_ASSERT(!item->d_ptr->dirtySceneTransform);
- wasDirtyParentSceneTransform = true;
- }
-
- const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
- bool drawItem = itemHasContents && !itemIsFullyTransparent;
- if (drawItem) {
- const QRectF brect = adjustedItemEffectiveBoundingRect(item);
- ENSURE_TRANSFORM_PTR
- QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toAlignedRect()
- : transformPtr->mapRect(brect).toAlignedRect();
- viewBoundingRect.adjust(-int(rectAdjust), -int(rectAdjust), rectAdjust, rectAdjust);
- if (widget)
- item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
- drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect)
- : !viewBoundingRect.normalized().isEmpty();
- if (!drawItem) {
- if (!itemHasChildren)
- return;
- if (itemClipsChildrenToShape) {
- if (wasDirtyParentSceneTransform)
- item->d_ptr->invalidateChildrenSceneTransform();
- return;
- }
- }
- } // else we know for sure this item has children we must process.
-
- if (itemHasChildren && itemClipsChildrenToShape)
- ENSURE_TRANSFORM_PTR;
-
-#ifndef QT_NO_GRAPHICSEFFECT
- if (item->d_ptr->graphicsEffect && item->d_ptr->graphicsEffect->isEnabled()) {
- ENSURE_TRANSFORM_PTR;
- QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp,
- painter, opacity, wasDirtyParentSceneTransform, itemHasContents && !itemIsFullyTransparent);
- QGraphicsEffectSource *source = item->d_ptr->graphicsEffect->d_func()->source;
- QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *>
- (source->d_func());
- sourced->info = &info;
- const QTransform restoreTransform = painter->worldTransform();
- if (effectTransform)
- painter->setWorldTransform(*transformPtr * *effectTransform);
- else
- painter->setWorldTransform(*transformPtr);
- painter->setOpacity(opacity);
-
- if (sourced->currentCachedSystem() != Qt::LogicalCoordinates
- && sourced->lastEffectTransform != painter->worldTransform())
- {
- if (sourced->lastEffectTransform.type() <= QTransform::TxTranslate
- && painter->worldTransform().type() <= QTransform::TxTranslate)
- {
- QRectF sourceRect = sourced->boundingRect(Qt::DeviceCoordinates);
- QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect);
-
- sourced->setCachedOffset(effectRect.topLeft());
- } else {
- sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged);
- }
-
- sourced->lastEffectTransform = painter->worldTransform();
- }
-
- item->d_ptr->graphicsEffect->draw(painter);
- painter->setWorldTransform(restoreTransform);
- sourced->info = 0;
- } else
-#endif //QT_NO_GRAPHICSEFFECT
- {
- draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity,
- effectTransform, wasDirtyParentSceneTransform, drawItem);
- }
-}
-
-static inline void setClip(QPainter *painter, QGraphicsItem *item)
-{
- painter->save();
- QRectF clipRect;
- const QPainterPath clipPath(item->shape());
- if (QPathClipper::pathToRect(clipPath, &clipRect))
- painter->setClipRect(clipRect, Qt::IntersectClip);
- else
- painter->setClipPath(clipPath, Qt::IntersectClip);
-}
-
-static inline void setWorldTransform(QPainter *painter, const QTransform *const transformPtr,
- const QTransform *effectTransform)
-{
- Q_ASSERT(transformPtr);
- if (effectTransform)
- painter->setWorldTransform(*transformPtr * *effectTransform);
- else
- painter->setWorldTransform(*transformPtr);
-}
-
-void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform,
- const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget,
- qreal opacity, const QTransform *effectTransform,
- bool wasDirtyParentSceneTransform, bool drawItem)
-{
- const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
- const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
- const bool itemHasChildren = !item->d_ptr->children.isEmpty();
- bool setChildClip = itemClipsChildrenToShape;
- bool itemHasChildrenStackedBehind = false;
-
- int i = 0;
- if (itemHasChildren) {
- if (itemClipsChildrenToShape)
- setWorldTransform(painter, transformPtr, effectTransform);
-
- item->d_ptr->ensureSortedChildren();
- // Items with the 'ItemStacksBehindParent' flag are put in front of the list
- // so all we have to do is to check the first item.
- itemHasChildrenStackedBehind = (item->d_ptr->children.at(0)->d_ptr->flags
- & QGraphicsItem::ItemStacksBehindParent);
-
- if (itemHasChildrenStackedBehind) {
- if (itemClipsChildrenToShape) {
- setClip(painter, item);
- setChildClip = false;
- }
-
- // Draw children behind
- for (i = 0; i < item->d_ptr->children.size(); ++i) {
- QGraphicsItem *child = item->d_ptr->children.at(i);
- if (wasDirtyParentSceneTransform)
- child->d_ptr->dirtySceneTransform = 1;
- if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
- break;
- if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
- continue;
- drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
- }
- }
- }
-
- // Draw item
- if (drawItem) {
- Q_ASSERT(!itemIsFullyTransparent);
- Q_ASSERT(!(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents));
- Q_ASSERT(transformPtr);
- item->d_ptr->initStyleOption(&styleOptionTmp, *transformPtr, exposedRegion
- ? *exposedRegion : QRegion(), exposedRegion == 0);
-
- const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape;
- bool restorePainterClip = false;
-
- if (!itemHasChildren || !itemClipsChildrenToShape) {
- // Item does not have children or clip children to shape.
- setWorldTransform(painter, transformPtr, effectTransform);
- if ((restorePainterClip = itemClipsToShape))
- setClip(painter, item);
- } else if (itemHasChildrenStackedBehind){
- // Item clips children to shape and has children stacked behind, which means
- // the painter is already clipped to the item's shape.
- if (itemClipsToShape) {
- // The clip is already correct. Ensure correct world transform.
- setWorldTransform(painter, transformPtr, effectTransform);
- } else {
- // Remove clip (this also ensures correct world transform).
- painter->restore();
- setChildClip = true;
- }
- } else if (itemClipsToShape) {
- // Item clips children and itself to shape. It does not have hildren stacked
- // behind, which means the clip has not yet been set. We set it now and re-use it
- // for the children.
- setClip(painter, item);
- setChildClip = false;
- }
-
- if (painterStateProtection && !restorePainterClip)
- painter->save();
-
- painter->setOpacity(opacity);
- if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget)
- item->paint(painter, &styleOptionTmp, widget);
- else
- drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection);
-
- if (painterStateProtection || restorePainterClip)
- painter->restore();
-
- static int drawRect = qgetenv("QT_DRAW_SCENE_ITEM_RECTS").toInt();
- if (drawRect) {
- QPen oldPen = painter->pen();
- QBrush oldBrush = painter->brush();
- quintptr ptr = reinterpret_cast<quintptr>(item);
- const QColor color = QColor::fromHsv(ptr % 255, 255, 255);
- painter->setPen(color);
- painter->setBrush(Qt::NoBrush);
- painter->drawRect(adjustedItemBoundingRect(item));
- painter->setPen(oldPen);
- painter->setBrush(oldBrush);
- }
- }
-
- // Draw children in front
- if (itemHasChildren) {
- if (setChildClip)
- setClip(painter, item);
-
- for (; i < item->d_ptr->children.size(); ++i) {
- QGraphicsItem *child = item->d_ptr->children.at(i);
- if (wasDirtyParentSceneTransform)
- child->d_ptr->dirtySceneTransform = 1;
- if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
- continue;
- drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
- }
-
- // Restore child clip
- if (itemClipsChildrenToShape)
- painter->restore();
- }
-}
-
-void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren,
- bool force, bool ignoreOpacity, bool removingItemFromScene,
- bool updateBoundingRect)
-{
- Q_ASSERT(item);
- if (updateAll)
- return;
-
- if (removingItemFromScene && !ignoreOpacity && !item->d_ptr->ignoreOpacity) {
- // If any of the item's ancestors ignore opacity, it means that the opacity
- // was set to 0 (and the update request has not yet been processed). That
- // also means that we have to ignore the opacity for the item itself; otherwise
- // things like: parent->setOpacity(0); scene->removeItem(child) won't work.
- // Note that we only do this when removing items from the scene. In all other
- // cases the ignoreOpacity bit propagates properly in processDirtyItems, but
- // since the item is removed immediately it won't be processed there.
- QGraphicsItem *p = item->d_ptr->parent;
- while (p) {
- if (p->d_ptr->ignoreOpacity) {
- item->d_ptr->ignoreOpacity = true;
- break;
- }
- p = p->d_ptr->parent;
- }
- }
-
- if (item->d_ptr->discardUpdateRequest(/*ignoreVisibleBit=*/force,
- /*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren,
- /*ignoreOpacity=*/ignoreOpacity)) {
- if (item->d_ptr->dirty) {
- // The item is already marked as dirty and will be processed later. However,
- // we have to make sure ignoreVisible and ignoreOpacity are set properly;
- // otherwise things like: item->update(); item->hide() (force is now true)
- // won't work as expected.
- if (force)
- item->d_ptr->ignoreVisible = 1;
- if (ignoreOpacity)
- item->d_ptr->ignoreOpacity = 1;
- }
- return;
- }
-
- const bool fullItemUpdate = rect.isNull();
- if (!fullItemUpdate && rect.isEmpty())
- return;
-
- if (!processDirtyItemsEmitted) {
- QMetaMethod method = q_ptr->metaObject()->method(processDirtyItemsIndex);
- method.invoke(q_ptr, Qt::QueuedConnection);
-// QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection);
- processDirtyItemsEmitted = true;
- }
-
- if (removingItemFromScene) {
- // Note that this function can be called from the item's destructor, so
- // do NOT call any virtual functions on it within this block.
- if (isSignalConnected(changedSignalIndex) || views.isEmpty()) {
- // This block of code is kept for compatibility. Since 4.5, by default
- // QGraphicsView does not connect the signal and we use the below
- // method of delivering updates.
- q_func()->update();
- return;
- }
-
- for (int i = 0; i < views.size(); ++i) {
- QGraphicsViewPrivate *viewPrivate = views.at(i)->d_func();
- QRect rect = item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport);
- rect.translate(viewPrivate->dirtyScrollOffset);
- viewPrivate->updateRect(rect);
- }
- return;
- }
-
- bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents;
- if (!hasNoContents) {
- item->d_ptr->dirty = 1;
- if (fullItemUpdate)
- item->d_ptr->fullUpdatePending = 1;
- else if (!item->d_ptr->fullUpdatePending)
- item->d_ptr->needsRepaint |= rect;
- } else if (item->d_ptr->graphicsEffect) {
- invalidateChildren = true;
- }
-
- if (invalidateChildren) {
- item->d_ptr->allChildrenDirty = 1;
- item->d_ptr->dirtyChildren = 1;
- }
-
- if (force)
- item->d_ptr->ignoreVisible = 1;
- if (ignoreOpacity)
- item->d_ptr->ignoreOpacity = 1;
-
- if (!updateBoundingRect)
- item->d_ptr->markParentDirty();
-}
-
-static inline bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate *item,
- const QRectF &rect, bool itemIsUntransformable)
-{
- Q_ASSERT(view);
- Q_ASSERT(item);
-
- QGraphicsItem *itemq = static_cast<QGraphicsItem *>(item->q_ptr);
- QGraphicsView *viewq = static_cast<QGraphicsView *>(view->q_ptr);
-
- if (itemIsUntransformable) {
- const QTransform xform = itemq->deviceTransform(viewq->viewportTransform());
- if (!item->hasBoundingRegionGranularity)
- return view->updateRectF(xform.mapRect(rect));
- return view->updateRegion(rect, xform);
- }
-
- if (item->sceneTransformTranslateOnly && view->identityMatrix) {
- const qreal dx = item->sceneTransform.dx();
- const qreal dy = item->sceneTransform.dy();
- QRectF r(rect);
- r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll());
- return view->updateRectF(r);
- }
-
- if (!viewq->isTransformed()) {
- if (!item->hasBoundingRegionGranularity)
- return view->updateRectF(item->sceneTransform.mapRect(rect));
- return view->updateRegion(rect, item->sceneTransform);
- }
-
- QTransform xform = item->sceneTransform;
- xform *= viewq->viewportTransform();
- if (!item->hasBoundingRegionGranularity)
- return view->updateRectF(xform.mapRect(rect));
- return view->updateRegion(rect, xform);
-}
-
-void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren,
- qreal parentOpacity)
-{
- Q_Q(QGraphicsScene);
- Q_ASSERT(item);
- Q_ASSERT(!updateAll);
-
- if (!item->d_ptr->dirty && !item->d_ptr->dirtyChildren) {
- resetDirtyItem(item);
- return;
- }
-
- const bool itemIsHidden = !item->d_ptr->ignoreVisible && !item->d_ptr->visible;
- if (itemIsHidden) {
- resetDirtyItem(item, /*recursive=*/true);
- return;
- }
-
- bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
- const bool itemHasChildren = !item->d_ptr->children.isEmpty();
- if (!itemHasContents) {
- if (!itemHasChildren) {
- resetDirtyItem(item);
- return; // Item has neither contents nor children!(?)
- }
- if (item->d_ptr->graphicsEffect)
- itemHasContents = true;
- }
-
- const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
- const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity
- && QGraphicsItemPrivate::isOpacityNull(opacity);
- if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) {
- resetDirtyItem(item, /*recursive=*/itemHasChildren);
- return;
- }
-
- bool wasDirtyParentSceneTransform = item->d_ptr->dirtySceneTransform;
- const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
- if (wasDirtyParentSceneTransform && !itemIsUntransformable) {
- item->d_ptr->updateSceneTransformFromParent();
- Q_ASSERT(!item->d_ptr->dirtySceneTransform);
- }
-
- const bool wasDirtyParentViewBoundingRects = item->d_ptr->paintedViewBoundingRectsNeedRepaint;
- if (itemIsFullyTransparent || !itemHasContents || dirtyAncestorContainsChildren) {
- // Make sure we don't process invisible items or items with no content.
- item->d_ptr->dirty = 0;
- item->d_ptr->fullUpdatePending = 0;
- // Might have a dirty view bounding rect otherwise.
- if (itemIsFullyTransparent || !itemHasContents)
- item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0;
- }
-
- if (!hasSceneRect && item->d_ptr->geometryChanged && item->d_ptr->visible) {
- // Update growingItemsBoundingRect.
- if (item->d_ptr->sceneTransformTranslateOnly) {
- growingItemsBoundingRect |= item->boundingRect().translated(item->d_ptr->sceneTransform.dx(),
- item->d_ptr->sceneTransform.dy());
- } else {
- growingItemsBoundingRect |= item->d_ptr->sceneTransform.mapRect(item->boundingRect());
- }
- }
-
- // Process item.
- if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
- const bool useCompatUpdate = views.isEmpty() || isSignalConnected(changedSignalIndex);
- const QRectF itemBoundingRect = adjustedItemEffectiveBoundingRect(item);
-
- if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) {
- // This block of code is kept for compatibility. Since 4.5, by default
- // QGraphicsView does not connect the signal and we use the below
- // method of delivering updates.
- if (item->d_ptr->sceneTransformTranslateOnly) {
- q->update(itemBoundingRect.translated(item->d_ptr->sceneTransform.dx(),
- item->d_ptr->sceneTransform.dy()));
- } else {
- QRectF rect = item->d_ptr->sceneTransform.mapRect(itemBoundingRect);
- if (!rect.isEmpty())
- q->update(rect);
- }
- } else {
- QRectF dirtyRect;
- bool uninitializedDirtyRect = true;
-
- for (int j = 0; j < views.size(); ++j) {
- QGraphicsView *view = views.at(j);
- QGraphicsViewPrivate *viewPrivate = view->d_func();
- QRect &paintedViewBoundingRect = item->d_ptr->paintedViewBoundingRects[viewPrivate->viewport];
- if (viewPrivate->fullUpdatePending
- || viewPrivate->viewportUpdateMode == QGraphicsView::NoViewportUpdate) {
- // Okay, if we have a full update pending or no viewport update, this item's
- // paintedViewBoundingRect will be updated correctly in the next paintEvent if
- // it is inside the viewport, but for now we can pretend that it is outside.
- paintedViewBoundingRect = QRect(-1, -1, -1, -1);
- continue;
- }
-
- if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
- paintedViewBoundingRect.translate(viewPrivate->dirtyScrollOffset);
- if (!viewPrivate->updateRect(paintedViewBoundingRect))
- paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
- }
-
- if (!item->d_ptr->dirty)
- continue;
-
- if (!item->d_ptr->paintedViewBoundingRectsNeedRepaint
- && paintedViewBoundingRect.x() == -1 && paintedViewBoundingRect.y() == -1
- && paintedViewBoundingRect.width() == -1 && paintedViewBoundingRect.height() == -1) {
- continue; // Outside viewport.
- }
-
- if (uninitializedDirtyRect) {
- dirtyRect = itemBoundingRect;
- if (!item->d_ptr->fullUpdatePending) {
- _q_adjustRect(&item->d_ptr->needsRepaint);
- dirtyRect &= item->d_ptr->needsRepaint;
- }
- uninitializedDirtyRect = false;
- }
-
- if (dirtyRect.isEmpty())
- continue; // Discard updates outside the bounding rect.
-
- if (!updateHelper(viewPrivate, item->d_ptr.data(), dirtyRect, itemIsUntransformable)
- && item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
- paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
- }
- }
- }
- }
-
- // Process children.
- if (itemHasChildren && item->d_ptr->dirtyChildren) {
- const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape;
- // Items with no content are threated as 'dummy' items which means they are never drawn and
- // 'processed', so the painted view bounding rect is never up-to-date. This means that whenever
- // such an item changes geometry, its children have to take care of the update regardless
- // of whether the item clips children to shape or not.
- const bool bypassUpdateClip = !itemHasContents && wasDirtyParentViewBoundingRects;
- if (itemClipsChildrenToShape && !bypassUpdateClip) {
- // Make sure child updates are clipped to the item's bounding rect.
- for (int i = 0; i < views.size(); ++i)
- views.at(i)->d_func()->setUpdateClip(item);
- }
- if (!dirtyAncestorContainsChildren) {
- dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending
- && itemClipsChildrenToShape;
- }
- const bool allChildrenDirty = item->d_ptr->allChildrenDirty;
- const bool parentIgnoresVisible = item->d_ptr->ignoreVisible;
- const bool parentIgnoresOpacity = item->d_ptr->ignoreOpacity;
- for (int i = 0; i < item->d_ptr->children.size(); ++i) {
- QGraphicsItem *child = item->d_ptr->children.at(i);
- if (wasDirtyParentSceneTransform)
- child->d_ptr->dirtySceneTransform = 1;
- if (wasDirtyParentViewBoundingRects)
- child->d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
- if (parentIgnoresVisible)
- child->d_ptr->ignoreVisible = 1;
- if (parentIgnoresOpacity)
- child->d_ptr->ignoreOpacity = 1;
- if (allChildrenDirty) {
- child->d_ptr->dirty = 1;
- child->d_ptr->fullUpdatePending = 1;
- child->d_ptr->dirtyChildren = 1;
- child->d_ptr->allChildrenDirty = 1;
- }
- processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity);
- }
-
- if (itemClipsChildrenToShape) {
- // Reset updateClip.
- for (int i = 0; i < views.size(); ++i)
- views.at(i)->d_func()->setUpdateClip(0);
- }
- } else if (wasDirtyParentSceneTransform) {
- item->d_ptr->invalidateChildrenSceneTransform();
- }
-
- resetDirtyItem(item);
-}
-
-/*!
- \obsolete
-
- Paints the given \a items using the provided \a painter, after the
- background has been drawn, and before the foreground has been
- drawn. All painting is done in \e scene coordinates. Before
- drawing each item, the painter must be transformed using
- QGraphicsItem::sceneTransform().
-
- The \a options parameter is the list of style option objects for
- each item in \a items. The \a numItems parameter is the number of
- items in \a items and options in \a options. The \a widget
- parameter is optional; if specified, it should point to the widget
- that is being painted on.
-
- The default implementation prepares the painter matrix, and calls
- QGraphicsItem::paint() on all items. Reimplement this function to
- provide custom painting of all items for the scene; gaining
- complete control over how each item is drawn. In some cases this
- can increase drawing performance significantly.
-
- Example:
-
- \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0
-
- Since Qt 4.6, this function is not called anymore unless
- the QGraphicsView::IndirectPainting flag is given as an Optimization
- flag.
-
- \sa drawBackground(), drawForeground()
-*/
-void QGraphicsScene::drawItems(QPainter *painter,
- int numItems,
- QGraphicsItem *items[],
- const QStyleOptionGraphicsItem options[], QWidget *widget)
-{
- Q_D(QGraphicsScene);
- // Make sure we don't have unpolished items before we draw.
- if (!d->unpolishedItems.isEmpty())
- d->_q_polishItems();
-
- const qreal opacity = painter->opacity();
- QTransform viewTransform = painter->worldTransform();
- Q_UNUSED(options);
-
- // Determine view, expose and flags.
- QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
- QRegion *expose = 0;
- const quint32 oldRectAdjust = d->rectAdjust;
- if (view) {
- d->updateAll = false;
- expose = &view->d_func()->exposedRegion;
- if (view->d_func()->optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
- d->rectAdjust = 1;
- else
- d->rectAdjust = 2;
- }
-
- // Find all toplevels, they are already sorted.
- QList<QGraphicsItem *> topLevelItems;
- for (int i = 0; i < numItems; ++i) {
- QGraphicsItem *item = items[i]->topLevelItem();
- if (!item->d_ptr->itemDiscovered) {
- topLevelItems << item;
- item->d_ptr->itemDiscovered = 1;
- d->drawSubtreeRecursive(item, painter, &viewTransform, expose, widget);
- }
- }
-
- d->rectAdjust = oldRectAdjust;
- // Reset discovery bits.
- for (int i = 0; i < topLevelItems.size(); ++i)
- topLevelItems.at(i)->d_ptr->itemDiscovered = 0;
-
- painter->setWorldTransform(viewTransform);
- painter->setOpacity(opacity);
-}
-
-/*!
- \since 4.4
-
- Finds a new widget to give the keyboard focus to, as appropriate for Tab
- and Shift+Tab, and returns true if it can find a new widget, or false if
- it cannot. If \a next is true, this function searches forward; if \a next
- is false, it searches backward.
-
- You can reimplement this function in a subclass of QGraphicsScene to
- provide fine-grained control over how tab focus passes inside your
- scene. The default implementation is based on the tab focus chain defined
- by QGraphicsWidget::setTabOrder().
-*/
-bool QGraphicsScene::focusNextPrevChild(bool next)
-{
- Q_D(QGraphicsScene);
-
- QGraphicsItem *item = focusItem();
- if (item && !item->isWidget()) {
- // Tab out of the scene.
- return false;
- }
- if (!item) {
- if (d->lastFocusItem && !d->lastFocusItem->isWidget()) {
- // Restore focus to the last focusable non-widget item that had
- // focus.
- setFocusItem(d->lastFocusItem, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
- return true;
- }
- }
- if (!d->tabFocusFirst) {
- // No widgets...
- return false;
- }
-
- // The item must be a widget.
- QGraphicsWidget *widget = 0;
- if (!item) {
- widget = next ? d->tabFocusFirst : d->tabFocusFirst->d_func()->focusPrev;
- } else {
- QGraphicsWidget *test = static_cast<QGraphicsWidget *>(item);
- widget = next ? test->d_func()->focusNext : test->d_func()->focusPrev;
- if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
- return false;
- }
- QGraphicsWidget *widgetThatHadFocus = widget;
-
- // Run around the focus chain until we find a widget that can take tab focus.
- do {
- if (widget->flags() & QGraphicsItem::ItemIsFocusable
- && widget->isEnabled() && widget->isVisibleTo(0)
- && (widget->focusPolicy() & Qt::TabFocus)
- && (!item || !item->isPanel() || item->isAncestorOf(widget))
- ) {
- setFocusItem(widget, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
- return true;
- }
- widget = next ? widget->d_func()->focusNext : widget->d_func()->focusPrev;
- if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
- return false;
- } while (widget != widgetThatHadFocus);
-
- return false;
-}
-
-/*!
- \fn QGraphicsScene::changed(const QList<QRectF> &region)
-
- This signal is emitted by QGraphicsScene when control reaches the
- event loop, if the scene content changes. The \a region parameter
- contains a list of scene rectangles that indicate the area that
- has been changed.
-
- \sa QGraphicsView::updateScene()
-*/
-
-/*!
- \fn QGraphicsScene::sceneRectChanged(const QRectF &rect)
-
- This signal is emitted by QGraphicsScene whenever the scene rect changes.
- The \a rect parameter is the new scene rectangle.
-
- \sa QGraphicsView::updateSceneRect()
-*/
-
-/*!
- \fn QGraphicsScene::selectionChanged()
- \since 4.3
-
- This signal is emitted by QGraphicsScene whenever the selection
- changes. You can call selectedItems() to get the new list of selected
- items.
-
- The selection changes whenever an item is selected or unselected, a
- selection area is set, cleared or otherwise changed, if a preselected item
- is added to the scene, or if a selected item is removed from the scene.
-
- QGraphicsScene emits this signal only once for group selection operations.
- For example, if you set a selection area, select or unselect a
- QGraphicsItemGroup, or if you add or remove from the scene a parent item
- that contains several selected items, selectionChanged() is emitted only
- once after the operation has completed (instead of once for each item).
-
- \sa setSelectionArea(), selectedItems(), QGraphicsItem::setSelected()
-*/
-
-/*!
- \since 4.4
-
- Returns the scene's style, or the same as QApplication::style() if the
- scene has not been explicitly assigned a style.
-
- \sa setStyle()
-*/
-QStyle *QGraphicsScene::style() const
-{
- Q_D(const QGraphicsScene);
- // ### This function, and the use of styles in general, is non-reentrant.
- return d->style ? d->style : QApplication::style();
-}
-
-/*!
- \since 4.4
-
- Sets or replaces the style of the scene to \a style, and reparents the
- style to this scene. Any previously assigned style is deleted. The scene's
- style defaults to QApplication::style(), and serves as the default for all
- QGraphicsWidget items in the scene.
-
- Changing the style, either directly by calling this function, or
- indirectly by calling QApplication::setStyle(), will automatically update
- the style for all widgets in the scene that do not have a style explicitly
- assigned to them.
-
- If \a style is 0, QGraphicsScene will revert to QApplication::style().
-
- \sa style()
-*/
-void QGraphicsScene::setStyle(QStyle *style)
-{
- Q_D(QGraphicsScene);
- // ### This function, and the use of styles in general, is non-reentrant.
- if (style == d->style)
- return;
-
- // Delete the old style,
- delete d->style;
- if ((d->style = style))
- d->style->setParent(this);
-
- // Notify the scene.
- QEvent event(QEvent::StyleChange);
- QApplication::sendEvent(this, &event);
-
- // Notify all widgets that don't have a style explicitly set.
- foreach (QGraphicsItem *item, items()) {
- if (item->isWidget()) {
- QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
- if (!widget->testAttribute(Qt::WA_SetStyle))
- QApplication::sendEvent(widget, &event);
- }
- }
-}
-
-/*!
- \property QGraphicsScene::font
- \since 4.4
- \brief the scene's default font
-
- This property provides the scene's font. The scene font defaults to,
- and resolves all its entries from, QApplication::font.
-
- If the scene's font changes, either directly through setFont() or
- indirectly when the application font changes, QGraphicsScene first
- sends itself a \l{QEvent::FontChange}{FontChange} event, and it then
- sends \l{QEvent::FontChange}{FontChange} events to all top-level
- widget items in the scene. These items respond by resolving their own
- fonts to the scene, and they then notify their children, who again
- notify their children, and so on, until all widget items have updated
- their fonts.
-
- Changing the scene font, (directly or indirectly through
- QApplication::setFont(),) automatically schedules a redraw the entire
- scene.
-
- \sa QWidget::font, QApplication::setFont(), palette, style()
-*/
-QFont QGraphicsScene::font() const
-{
- Q_D(const QGraphicsScene);
- return d->font;
-}
-void QGraphicsScene::setFont(const QFont &font)
-{
- Q_D(QGraphicsScene);
- QFont naturalFont = QApplication::font();
- naturalFont.resolve(0);
- QFont resolvedFont = font.resolve(naturalFont);
- d->setFont_helper(resolvedFont);
-}
-
-/*!
- \property QGraphicsScene::palette
- \since 4.4
- \brief the scene's default palette
-
- This property provides the scene's palette. The scene palette defaults to,
- and resolves all its entries from, QApplication::palette.
-
- If the scene's palette changes, either directly through setPalette() or
- indirectly when the application palette changes, QGraphicsScene first
- sends itself a \l{QEvent::PaletteChange}{PaletteChange} event, and it then
- sends \l{QEvent::PaletteChange}{PaletteChange} events to all top-level
- widget items in the scene. These items respond by resolving their own
- palettes to the scene, and they then notify their children, who again
- notify their children, and so on, until all widget items have updated
- their palettes.
-
- Changing the scene palette, (directly or indirectly through
- QApplication::setPalette(),) automatically schedules a redraw the entire
- scene.
-
- \sa QWidget::palette, QApplication::setPalette(), font, style()
-*/
-QPalette QGraphicsScene::palette() const
-{
- Q_D(const QGraphicsScene);
- return d->palette;
-}
-void QGraphicsScene::setPalette(const QPalette &palette)
-{
- Q_D(QGraphicsScene);
- QPalette naturalPalette = QApplication::palette();
- naturalPalette.resolve(0);
- QPalette resolvedPalette = palette.resolve(naturalPalette);
- d->setPalette_helper(resolvedPalette);
-}
-
-/*!
- \since 4.6
-
- Returns true if the scene is active (e.g., it's viewed by
- at least one QGraphicsView that is active); otherwise returns false.
-
- \sa QGraphicsItem::isActive(), QWidget::isActiveWindow()
-*/
-bool QGraphicsScene::isActive() const
-{
- Q_D(const QGraphicsScene);
- return d->activationRefCount > 0;
-}
-
-/*!
- \since 4.6
- Returns the current active panel, or 0 if no panel is currently active.
-
- \sa QGraphicsScene::setActivePanel()
-*/
-QGraphicsItem *QGraphicsScene::activePanel() const
-{
- Q_D(const QGraphicsScene);
- return d->activePanel;
-}
-
-/*!
- \since 4.6
- Activates \a item, which must be an item in this scene. You
- can also pass 0 for \a item, in which case QGraphicsScene will
- deactivate any currently active panel.
-
- If the scene is currently inactive, \a item remains inactive until the
- scene becomes active (or, ir \a item is 0, no item will be activated).
-
- \sa activePanel(), isActive(), QGraphicsItem::isActive()
-*/
-void QGraphicsScene::setActivePanel(QGraphicsItem *item)
-{
- Q_D(QGraphicsScene);
- d->setActivePanelHelper(item, false);
-}
-
-/*!
- \since 4.4
-
- Returns the current active window, or 0 if no window is currently
- active.
-
- \sa QGraphicsScene::setActiveWindow()
-*/
-QGraphicsWidget *QGraphicsScene::activeWindow() const
-{
- Q_D(const QGraphicsScene);
- if (d->activePanel && d->activePanel->isWindow())
- return static_cast<QGraphicsWidget *>(d->activePanel);
- return 0;
-}
-
-/*!
- \since 4.4
- Activates \a widget, which must be a widget in this scene. You can also
- pass 0 for \a widget, in which case QGraphicsScene will deactivate any
- currently active window.
-
- \sa activeWindow(), QGraphicsWidget::isActiveWindow()
-*/
-void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
-{
- if (widget && widget->scene() != this) {
- qWarning("QGraphicsScene::setActiveWindow: widget %p must be part of this scene",
- widget);
- return;
- }
-
- // Activate the widget's panel (all windows are panels).
- QGraphicsItem *panel = widget ? widget->panel() : 0;
- setActivePanel(panel);
-
- // Raise
- if (panel) {
- QList<QGraphicsItem *> siblingWindows;
- QGraphicsItem *parent = panel->parentItem();
- // Raise ### inefficient for toplevels
- foreach (QGraphicsItem *sibling, parent ? parent->children() : items()) {
- if (sibling != panel && sibling->isWindow())
- siblingWindows << sibling;
- }
-
- // Find the highest z value.
- qreal z = panel->zValue();
- for (int i = 0; i < siblingWindows.size(); ++i)
- z = qMax(z, siblingWindows.at(i)->zValue());
-
- // This will probably never overflow.
- const qreal litt = qreal(0.001);
- panel->setZValue(z + litt);
- }
-}
-
-/*!
- \since 4.6
-
- Sends event \a event to item \a item through possible event filters.
-
- The event is sent only if the item is enabled.
-
- Returns \c false if the event was filtered or if the item is disabled.
- Otherwise returns the value that was returned from the event handler.
-
- \sa QGraphicsItem::sceneEvent(), QGraphicsItem::sceneEventFilter()
-*/
-bool QGraphicsScene::sendEvent(QGraphicsItem *item, QEvent *event)
-{
- Q_D(QGraphicsScene);
- if (!item) {
- qWarning("QGraphicsScene::sendEvent: cannot send event to a null item");
- return false;
- }
- if (item->scene() != this) {
- qWarning("QGraphicsScene::sendEvent: item %p's scene (%p)"
- " is different from this scene (%p)",
- item, item->scene(), this);
- return false;
- }
- return d->sendEvent(item, event);
-}
-
-void QGraphicsScenePrivate::addView(QGraphicsView *view)
-{
- views << view;
-#ifndef QT_NO_GESTURES
- foreach (Qt::GestureType gesture, grabbedGestures.keys())
- view->viewport()->grabGesture(gesture);
-#endif
-}
-
-void QGraphicsScenePrivate::removeView(QGraphicsView *view)
-{
- views.removeAll(view);
-}
-
-void QGraphicsScenePrivate::updateTouchPointsForItem(QGraphicsItem *item, QTouchEvent *touchEvent)
-{
- QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
- for (int i = 0; i < touchPoints.count(); ++i) {
- QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
- touchPoint.setRect(item->mapFromScene(touchPoint.sceneRect()).boundingRect());
- touchPoint.setStartPos(item->d_ptr->genericMapFromScene(touchPoint.startScenePos(), touchEvent->widget()));
- touchPoint.setLastPos(item->d_ptr->genericMapFromScene(touchPoint.lastScenePos(), touchEvent->widget()));
- }
- touchEvent->setTouchPoints(touchPoints);
-}
-
-int QGraphicsScenePrivate::findClosestTouchPointId(const QPointF &scenePos)
-{
- int closestTouchPointId = -1;
- qreal closestDistance = qreal(0.);
- foreach (const QTouchEvent::TouchPoint &touchPoint, sceneCurrentTouchPoints) {
- qreal distance = QLineF(scenePos, touchPoint.scenePos()).length();
- if (closestTouchPointId == -1|| distance < closestDistance) {
- closestTouchPointId = touchPoint.id();
- closestDistance = distance;
- }
- }
- return closestTouchPointId;
-}
-
-void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent)
-{
- typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
- QHash<QGraphicsItem *, StatesAndTouchPoints> itemsNeedingEvents;
-
- for (int i = 0; i < sceneTouchEvent->touchPoints().count(); ++i) {
- const QTouchEvent::TouchPoint &touchPoint = sceneTouchEvent->touchPoints().at(i);
-
- // update state
- QGraphicsItem *item = 0;
- if (touchPoint.state() == Qt::TouchPointPressed) {
- if (sceneTouchEvent->deviceType() == QTouchEvent::TouchPad) {
- // on touch-pad devices, send all touch points to the same item
- item = itemForTouchPointId.isEmpty()
- ? 0
- : itemForTouchPointId.constBegin().value();
- }
-
- if (!item) {
- // determine which item this touch point will go to
- cachedItemsUnderMouse = itemsAtPosition(touchPoint.screenPos().toPoint(),
- touchPoint.scenePos(),
- sceneTouchEvent->widget());
- item = cachedItemsUnderMouse.isEmpty() ? 0 : cachedItemsUnderMouse.first();
- }
-
- if (sceneTouchEvent->deviceType() == QTouchEvent::TouchScreen) {
- // on touch-screens, combine this touch point with the closest one we find
- int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos());
- QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId);
- if (!item || (closestItem && cachedItemsUnderMouse.contains(closestItem)))
- item = closestItem;
- }
- if (!item)
- continue;
-
- itemForTouchPointId.insert(touchPoint.id(), item);
- sceneCurrentTouchPoints.insert(touchPoint.id(), touchPoint);
- } else if (touchPoint.state() == Qt::TouchPointReleased) {
- item = itemForTouchPointId.take(touchPoint.id());
- if (!item)
- continue;
-
- sceneCurrentTouchPoints.remove(touchPoint.id());
- } else {
- item = itemForTouchPointId.value(touchPoint.id());
- if (!item)
- continue;
- Q_ASSERT(sceneCurrentTouchPoints.contains(touchPoint.id()));
- sceneCurrentTouchPoints[touchPoint.id()] = touchPoint;
- }
-
- StatesAndTouchPoints &statesAndTouchPoints = itemsNeedingEvents[item];
- statesAndTouchPoints.first |= touchPoint.state();
- statesAndTouchPoints.second.append(touchPoint);
- }
-
- if (itemsNeedingEvents.isEmpty()) {
- sceneTouchEvent->accept();
- return;
- }
-
- bool ignoreSceneTouchEvent = true;
- QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator it = itemsNeedingEvents.constBegin();
- const QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator end = itemsNeedingEvents.constEnd();
- for (; it != end; ++it) {
- QGraphicsItem *item = it.key();
-
- (void) item->isBlockedByModalPanel(&item);
-
- // determine event type from the state mask
- QEvent::Type eventType;
- switch (it.value().first) {
- case Qt::TouchPointPressed:
- // all touch points have pressed state
- eventType = QEvent::TouchBegin;
- break;
- case Qt::TouchPointReleased:
- // all touch points have released state
- eventType = QEvent::TouchEnd;
- break;
- case Qt::TouchPointStationary:
- // don't send the event if nothing changed
- continue;
- default:
- // all other combinations
- eventType = QEvent::TouchUpdate;
- break;
- }
-
- QTouchEvent touchEvent(eventType);
- touchEvent.setWidget(sceneTouchEvent->widget());
- touchEvent.setDeviceType(sceneTouchEvent->deviceType());
- touchEvent.setModifiers(sceneTouchEvent->modifiers());
- touchEvent.setTouchPointStates(it.value().first);
- touchEvent.setTouchPoints(it.value().second);
-
- switch (touchEvent.type()) {
- case QEvent::TouchBegin:
- {
- // if the TouchBegin handler recurses, we assume that means the event
- // has been implicitly accepted and continue to send touch events
- item->d_ptr->acceptedTouchBeginEvent = true;
- bool res = sendTouchBeginEvent(item, &touchEvent)
- && touchEvent.isAccepted();
- if (!res) {
- // forget about these touch points, we didn't handle them
- for (int i = 0; i < touchEvent.touchPoints().count(); ++i) {
- const QTouchEvent::TouchPoint &touchPoint = touchEvent.touchPoints().at(i);
- itemForTouchPointId.remove(touchPoint.id());
- sceneCurrentTouchPoints.remove(touchPoint.id());
- }
- ignoreSceneTouchEvent = false;
- }
- break;
- }
- default:
- if (item->d_ptr->acceptedTouchBeginEvent) {
- updateTouchPointsForItem(item, &touchEvent);
- (void) sendEvent(item, &touchEvent);
- ignoreSceneTouchEvent = false;
- }
- break;
- }
- }
- sceneTouchEvent->setAccepted(ignoreSceneTouchEvent);
-}
-
-bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEvent *touchEvent)
-{
- Q_Q(QGraphicsScene);
-
- if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.first() != origin) {
- const QTouchEvent::TouchPoint &firstTouchPoint = touchEvent->touchPoints().first();
- cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint.screenPos().toPoint(),
- firstTouchPoint.scenePos(),
- touchEvent->widget());
- }
- Q_ASSERT(cachedItemsUnderMouse.first() == origin);
-
- // Set focus on the topmost enabled item that can take focus.
- bool setFocus = false;
-
- foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
- if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
- if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
- setFocus = true;
- if (item != q->focusItem())
- q->setFocusItem(item, Qt::MouseFocusReason);
- break;
- }
- }
- if (item->isPanel())
- break;
- if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
- break;
- if (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling) {
- // Make sure we don't clear focus.
- setFocus = true;
- break;
- }
- }
-
- // If nobody could take focus, clear it.
- if (!stickyFocus && !setFocus)
- q->setFocusItem(0, Qt::MouseFocusReason);
-
- bool res = false;
- bool eventAccepted = touchEvent->isAccepted();
- foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
- // first, try to deliver the touch event
- updateTouchPointsForItem(item, touchEvent);
- bool acceptTouchEvents = item->acceptTouchEvents();
- touchEvent->setAccepted(acceptTouchEvents);
- res = acceptTouchEvents && sendEvent(item, touchEvent);
- eventAccepted = touchEvent->isAccepted();
- if (itemForTouchPointId.value(touchEvent->touchPoints().first().id()) == 0) {
- // item was deleted
- item = 0;
- } else {
- item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted);
- }
- touchEvent->spont = false;
- if (res && eventAccepted) {
- // the first item to accept the TouchBegin gets an implicit grab.
- for (int i = 0; i < touchEvent->touchPoints().count(); ++i) {
- const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i);
- itemForTouchPointId[touchPoint.id()] = item; // can be zero
- }
- break;
- }
- if (item && item->isPanel())
- break;
- }
-
- touchEvent->setAccepted(eventAccepted);
- return res;
-}
-
-void QGraphicsScenePrivate::enableTouchEventsOnViews()
-{
- foreach (QGraphicsView *view, views)
- view->viewport()->setAttribute(Qt::WA_AcceptTouchEvents, true);
-}
-
-void QGraphicsScenePrivate::updateInputMethodSensitivityInViews()
-{
- for (int i = 0; i < views.size(); ++i)
- views.at(i)->d_func()->updateInputMethodSensitivity();
-}
-
-void QGraphicsScenePrivate::enterModal(QGraphicsItem *panel, QGraphicsItem::PanelModality previousModality)
-{
- Q_Q(QGraphicsScene);
- Q_ASSERT(panel && panel->isPanel());
-
- QGraphicsItem::PanelModality panelModality = panel->d_ptr->panelModality;
- if (previousModality != QGraphicsItem::NonModal) {
- // the panel is changing from one modality type to another... temporarily set it back so
- // that blockedPanels is populated correctly
- panel->d_ptr->panelModality = previousModality;
- }
-
- QSet<QGraphicsItem *> blockedPanels;
- QList<QGraphicsItem *> items = q->items(); // ### store panels separately
- for (int i = 0; i < items.count(); ++i) {
- QGraphicsItem *item = items.at(i);
- if (item->isPanel() && item->isBlockedByModalPanel())
- blockedPanels.insert(item);
- }
- // blockedPanels contains all currently blocked panels
-
- if (previousModality != QGraphicsItem::NonModal) {
- // reset the modality to the proper value, since we changed it above
- panel->d_ptr->panelModality = panelModality;
- // remove this panel so that it will be reinserted at the front of the stack
- modalPanels.removeAll(panel);
- }
-
- modalPanels.prepend(panel);
-
- if (!hoverItems.isEmpty()) {
- // send GraphicsSceneHoverLeave events to newly blocked hoverItems
- QGraphicsSceneHoverEvent hoverEvent;
- hoverEvent.setScenePos(lastSceneMousePos);
- dispatchHoverEvent(&hoverEvent);
- }
-
- if (!mouseGrabberItems.isEmpty() && lastMouseGrabberItemHasImplicitMouseGrab) {
- QGraphicsItem *item = mouseGrabberItems.last();
- if (item->isBlockedByModalPanel())
- ungrabMouse(item, /*itemIsDying =*/ false);
- }
-
- QEvent windowBlockedEvent(QEvent::WindowBlocked);
- QEvent windowUnblockedEvent(QEvent::WindowUnblocked);
- for (int i = 0; i < items.count(); ++i) {
- QGraphicsItem *item = items.at(i);
- if (item->isPanel()) {
- if (!blockedPanels.contains(item) && item->isBlockedByModalPanel()) {
- // send QEvent::WindowBlocked to newly blocked panels
- sendEvent(item, &windowBlockedEvent);
- } else if (blockedPanels.contains(item) && !item->isBlockedByModalPanel()) {
- // send QEvent::WindowUnblocked to unblocked panels when downgrading
- // a panel from SceneModal to PanelModal
- sendEvent(item, &windowUnblockedEvent);
- }
- }
- }
-}
-
-void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel)
-{
- Q_Q(QGraphicsScene);
- Q_ASSERT(panel && panel->isPanel());
-
- QSet<QGraphicsItem *> blockedPanels;
- QList<QGraphicsItem *> items = q->items(); // ### same as above
- for (int i = 0; i < items.count(); ++i) {
- QGraphicsItem *item = items.at(i);
- if (item->isPanel() && item->isBlockedByModalPanel())
- blockedPanels.insert(item);
- }
-
- modalPanels.removeAll(panel);
-
- QEvent e(QEvent::WindowUnblocked);
- for (int i = 0; i < items.count(); ++i) {
- QGraphicsItem *item = items.at(i);
- if (item->isPanel() && blockedPanels.contains(item) && !item->isBlockedByModalPanel())
- sendEvent(item, &e);
- }
-
- // send GraphicsSceneHoverEnter events to newly unblocked items
- QGraphicsSceneHoverEvent hoverEvent;
- hoverEvent.setScenePos(lastSceneMousePos);
- dispatchHoverEvent(&hoverEvent);
-}
-
-#ifndef QT_NO_GESTURES
-void QGraphicsScenePrivate::gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures,
- Qt::GestureFlag flag,
- QHash<QGraphicsObject *, QSet<QGesture *> > *targets,
- QSet<QGraphicsObject *> *itemsSet,
- QSet<QGesture *> *normal,
- QSet<QGesture *> *conflicts)
-{
- QSet<QGesture *> normalGestures; // that are not in conflicted state.
- foreach (QGesture *gesture, gestures) {
- if (!gesture->hasHotSpot())
- continue;
- const Qt::GestureType gestureType = gesture->gestureType();
- QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), gesture->d_func()->sceneHotSpot, 0);
- for (int j = 0; j < items.size(); ++j) {
- QGraphicsItem *item = items.at(j);
-
- // Check if the item is blocked by a modal panel and use it as
- // a target instead of this item.
- (void) item->isBlockedByModalPanel(&item);
-
- if (QGraphicsObject *itemobj = item->toGraphicsObject()) {
- QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
- QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it =
- d->gestureContext.find(gestureType);
- if (it != d->gestureContext.end() && (!flag || (it.value() & flag))) {
- if (normalGestures.contains(gesture)) {
- normalGestures.remove(gesture);
- if (conflicts)
- conflicts->insert(gesture);
- } else {
- normalGestures.insert(gesture);
- }
- if (targets)
- (*targets)[itemobj].insert(gesture);
- if (itemsSet)
- (*itemsSet).insert(itemobj);
- }
- }
- // Don't propagate through panels.
- if (item->isPanel())
- break;
- }
- }
- if (normal)
- *normal = normalGestures;
-}
-
-void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
-{
- QWidget *viewport = event->widget();
- if (!viewport)
- return;
- QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(viewport->parent());
- if (!graphicsView)
- return;
-
- QList<QGesture *> allGestures = event->gestures();
- DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "Gestures:" << allGestures;
-
- QSet<QGesture *> startedGestures;
- QPoint delta = viewport->mapFromGlobal(QPoint());
- QTransform toScene = QTransform::fromTranslate(delta.x(), delta.y())
- * graphicsView->viewportTransform().inverted();
- foreach (QGesture *gesture, allGestures) {
- // cache scene coordinates of the hot spot
- if (gesture->hasHotSpot()) {
- gesture->d_func()->sceneHotSpot = toScene.map(gesture->hotSpot());
- } else {
- gesture->d_func()->sceneHotSpot = QPointF();
- }
-
- QGraphicsObject *target = gestureTargets.value(gesture, 0);
- if (!target) {
- // when we are not in started mode but don't have a target
- // then the only one interested in gesture is the view/scene
- if (gesture->state() == Qt::GestureStarted)
- startedGestures.insert(gesture);
- }
- }
-
- if (!startedGestures.isEmpty()) {
- QSet<QGesture *> normalGestures; // that have just one target
- QSet<QGesture *> conflictedGestures; // that have multiple possible targets
- gestureTargetsAtHotSpots(startedGestures, Qt::GestureFlag(0), &cachedItemGestures, 0,
- &normalGestures, &conflictedGestures);
- cachedTargetItems = cachedItemGestures.keys();
- qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
- DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "Normal gestures:" << normalGestures
- << "Conflicting gestures:" << conflictedGestures;
-
- // deliver conflicted gestures as override events AND remember
- // initial gesture targets
- if (!conflictedGestures.isEmpty()) {
- for (int i = 0; i < cachedTargetItems.size(); ++i) {
- QWeakPointer<QGraphicsObject> item = cachedTargetItems.at(i);
-
- // get gestures to deliver to the current item
- QSet<QGesture *> gestures = conflictedGestures & cachedItemGestures.value(item.data());
- if (gestures.isEmpty())
- continue;
-
- DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "delivering override to"
- << item.data() << gestures;
- // send gesture override
- QGestureEvent ev(gestures.toList());
- ev.t = QEvent::GestureOverride;
- ev.setWidget(event->widget());
- // mark event and individual gestures as ignored
- ev.ignore();
- foreach(QGesture *g, gestures)
- ev.setAccepted(g, false);
- sendEvent(item.data(), &ev);
- // mark all accepted gestures to deliver them as normal gesture events
- foreach (QGesture *g, gestures) {
- if (ev.isAccepted() || ev.isAccepted(g)) {
- conflictedGestures.remove(g);
- // mark the item as a gesture target
- if (item) {
- gestureTargets.insert(g, item.data());
- QHash<QGraphicsObject *, QSet<QGesture *> >::iterator it, e;
- it = cachedItemGestures.begin();
- e = cachedItemGestures.end();
- for(; it != e; ++it)
- it.value().remove(g);
- cachedItemGestures[item.data()].insert(g);
- }
- DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "override was accepted:"
- << g << item.data();
- }
- // remember the first item that received the override event
- // as it most likely become a target if no one else accepts
- // the override event
- if (!gestureTargets.contains(g) && item)
- gestureTargets.insert(g, item.data());
-
- }
- if (conflictedGestures.isEmpty())
- break;
- }
- }
- // remember the initial target item for each gesture that was not in
- // the conflicted state.
- if (!normalGestures.isEmpty()) {
- for (int i = 0; i < cachedTargetItems.size() && !normalGestures.isEmpty(); ++i) {
- QGraphicsObject *item = cachedTargetItems.at(i);
-
- // get gestures to deliver to the current item
- foreach (QGesture *g, cachedItemGestures.value(item)) {
- if (!gestureTargets.contains(g)) {
- gestureTargets.insert(g, item);
- normalGestures.remove(g);
- }
- }
- }
- }
- }
-
-
- // deliver all gesture events
- QSet<QGesture *> undeliveredGestures;
- QSet<QGesture *> parentPropagatedGestures;
- foreach (QGesture *gesture, allGestures) {
- if (QGraphicsObject *target = gestureTargets.value(gesture, 0)) {
- cachedItemGestures[target].insert(gesture);
- cachedTargetItems.append(target);
- undeliveredGestures.insert(gesture);
- QGraphicsItemPrivate *d = target->QGraphicsItem::d_func();
- const Qt::GestureFlags flags = d->gestureContext.value(gesture->gestureType());
- if (flags & Qt::IgnoredGesturesPropagateToParent)
- parentPropagatedGestures.insert(gesture);
- } else {
- DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "no target for" << gesture << "at"
- << gesture->hotSpot() << gesture->d_func()->sceneHotSpot;
- }
- }
- qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
- for (int i = 0; i < cachedTargetItems.size(); ++i) {
- QWeakPointer<QGraphicsObject> receiver = cachedTargetItems.at(i);
- QSet<QGesture *> gestures =
- undeliveredGestures & cachedItemGestures.value(receiver.data());
- gestures -= cachedAlreadyDeliveredGestures.value(receiver.data());
-
- if (gestures.isEmpty())
- continue;
-
- cachedAlreadyDeliveredGestures[receiver.data()] += gestures;
- const bool isPanel = receiver.data()->isPanel();
-
- DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "delivering to"
- << receiver.data() << gestures;
- QGestureEvent ev(gestures.toList());
- ev.setWidget(event->widget());
- sendEvent(receiver.data(), &ev);
- QSet<QGesture *> ignoredGestures;
- foreach (QGesture *g, gestures) {
- if (!ev.isAccepted() && !ev.isAccepted(g)) {
- // if the gesture was ignored by its target, we will update the
- // targetItems list with a possible target items (items that
- // want to receive partial gestures).
- // ### wont' work if the target was destroyed in the event
- // we will just stop delivering it.
- if (receiver && receiver.data() == gestureTargets.value(g, 0))
- ignoredGestures.insert(g);
- } else {
- if (receiver && g->state() == Qt::GestureStarted) {
- // someone accepted the propagated initial GestureStarted
- // event, let it be the new target for all following events.
- gestureTargets[g] = receiver.data();
- }
- undeliveredGestures.remove(g);
- }
- }
- if (undeliveredGestures.isEmpty())
- break;
-
- // ignoredGestures list is only filled when delivering to the gesture
- // target item, so it is safe to assume item == target.
- if (!ignoredGestures.isEmpty() && !isPanel) {
- // look for new potential targets for gestures that were ignored
- // and should be propagated.
-
- QSet<QGraphicsObject *> targetsSet = cachedTargetItems.toSet();
-
- if (receiver) {
- // first if the gesture should be propagated to parents only
- for (QSet<QGesture *>::iterator it = ignoredGestures.begin();
- it != ignoredGestures.end();) {
- if (parentPropagatedGestures.contains(*it)) {
- QGesture *gesture = *it;
- const Qt::GestureType gestureType = gesture->gestureType();
- QGraphicsItem *item = receiver.data();
- while (item) {
- if (QGraphicsObject *obj = item->toGraphicsObject()) {
- if (item->d_func()->gestureContext.contains(gestureType)) {
- targetsSet.insert(obj);
- cachedItemGestures[obj].insert(gesture);
- }
- }
- if (item->isPanel())
- break;
- item = item->parentItem();
- }
-
- it = ignoredGestures.erase(it);
- continue;
- }
- ++it;
- }
- }
-
- gestureTargetsAtHotSpots(ignoredGestures, Qt::ReceivePartialGestures,
- &cachedItemGestures, &targetsSet, 0, 0);
-
- cachedTargetItems = targetsSet.toList();
- qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
- DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "new targets:" << cachedTargetItems;
- i = -1; // start delivery again
- continue;
- }
- }
-
- foreach (QGesture *g, startedGestures) {
- if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
- DEBUG() << "lets try to cancel some";
- // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
- cancelGesturesForChildren(g);
- }
- }
-
- // forget about targets for gestures that have ended
- foreach (QGesture *g, allGestures) {
- switch (g->state()) {
- case Qt::GestureFinished:
- case Qt::GestureCanceled:
- gestureTargets.remove(g);
- break;
- default:
- break;
- }
- }
-
- cachedTargetItems.clear();
- cachedItemGestures.clear();
- cachedAlreadyDeliveredGestures.clear();
-}
-
-void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original)
-{
- Q_ASSERT(original);
- QGraphicsItem *originalItem = gestureTargets.value(original);
- if (originalItem == 0) // we only act on accepted gestures, which implies it has a target.
- return;
-
- // iterate over all active gestures and for each find the owner
- // if the owner is part of our sub-hierarchy, cancel it.
-
- QSet<QGesture *> canceledGestures;
- QHash<QGesture *, QGraphicsObject *>::Iterator iter = gestureTargets.begin();
- while (iter != gestureTargets.end()) {
- QGraphicsObject *item = iter.value();
- // note that we don't touch the gestures for our originalItem
- if (item != originalItem && originalItem->isAncestorOf(item)) {
- DEBUG() << " found a gesture to cancel" << iter.key();
- iter.key()->d_func()->state = Qt::GestureCanceled;
- canceledGestures << iter.key();
- }
- ++iter;
- }
-
- // sort them per target item by cherry picking from almostCanceledGestures and delivering
- QSet<QGesture *> almostCanceledGestures = canceledGestures;
- QSet<QGesture *>::Iterator setIter;
- while (!almostCanceledGestures.isEmpty()) {
- QGraphicsObject *target = 0;
- QSet<QGesture*> gestures;
- setIter = almostCanceledGestures.begin();
- // sort per target item
- while (setIter != almostCanceledGestures.end()) {
- QGraphicsObject *item = gestureTargets.value(*setIter);
- if (target == 0)
- target = item;
- if (target == item) {
- gestures << *setIter;
- setIter = almostCanceledGestures.erase(setIter);
- } else {
- ++setIter;
- }
- }
- Q_ASSERT(target);
-
- QList<QGesture *> list = gestures.toList();
- QGestureEvent ev(list);
- sendEvent(target, &ev);
-
- foreach (QGesture *g, list) {
- if (ev.isAccepted() || ev.isAccepted(g))
- gestures.remove(g);
- }
-
- foreach (QGesture *g, gestures) {
- if (!g->hasHotSpot())
- continue;
-
- QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), g->d_func()->sceneHotSpot, 0);
- for (int j = 0; j < items.size(); ++j) {
- QGraphicsObject *item = items.at(j)->toGraphicsObject();
- if (!item)
- continue;
- QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
- if (d->gestureContext.contains(g->gestureType())) {
- QList<QGesture *> list;
- list << g;
- QGestureEvent ev(list);
- sendEvent(item, &ev);
- if (ev.isAccepted() || ev.isAccepted(g))
- break; // successfully delivered
- }
- }
- }
- }
-
- QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
- Q_ASSERT(gestureManager); // it would be very odd if we got called without a manager.
- for (setIter = canceledGestures.begin(); setIter != canceledGestures.end(); ++setIter) {
- gestureManager->recycle(*setIter);
- gestureTargets.remove(*setIter);
- }
-}
-
-void QGraphicsScenePrivate::grabGesture(QGraphicsItem *, Qt::GestureType gesture)
-{
- (void)QGestureManager::instance(); // create a gesture manager
- if (!grabbedGestures[gesture]++) {
- foreach (QGraphicsView *view, views)
- view->viewport()->grabGesture(gesture);
- }
-}
-
-void QGraphicsScenePrivate::ungrabGesture(QGraphicsItem *item, Qt::GestureType gesture)
-{
- // we know this can only be an object
- Q_ASSERT(item->d_ptr->isObject);
- QGraphicsObject *obj = static_cast<QGraphicsObject *>(item);
- QGestureManager::instance()->cleanupCachedGestures(obj, gesture);
- if (!--grabbedGestures[gesture]) {
- foreach (QGraphicsView *view, views)
- view->viewport()->ungrabGesture(gesture);
- }
-}
-#endif // QT_NO_GESTURES
-
-QT_END_NAMESPACE
-
-#include "moc_qgraphicsscene.cpp"
-
-#endif // QT_NO_GRAPHICSVIEW