summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview
diff options
context:
space:
mode:
authoraxis <qt-info@nokia.com>2009-10-23 09:40:37 (GMT)
committeraxis <qt-info@nokia.com>2009-10-23 09:40:37 (GMT)
commit180d9189e8098d98848367f673fff723ddd1d068 (patch)
treeb052fb1b8361e962884f54aa4d6e6d8dd6f67e73 /src/gui/graphicsview
parent18acf933474577a4cec31560eeee22de04111e1e (diff)
parent0f6909e8e1be93d16798d31f18c4da2b0b5a084c (diff)
downloadQt-180d9189e8098d98848367f673fff723ddd1d068.zip
Qt-180d9189e8098d98848367f673fff723ddd1d068.tar.gz
Qt-180d9189e8098d98848367f673fff723ddd1d068.tar.bz2
Merge branch '4.6' of git@scm.dev.nokia.troll.no:qt/qt into 4.6
Diffstat (limited to 'src/gui/graphicsview')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp44
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h3
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h11
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp258
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h7
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp13
6 files changed, 326 insertions, 10 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 4b2ff52..97979e5 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -2484,12 +2484,14 @@ void QGraphicsItem::setOpacity(qreal opacity)
itemChange(ItemOpacityHasChanged, newOpacityVariant);
// Update.
- if (d_ptr->scene)
+ if (d_ptr->scene) {
+ d_ptr->invalidateGraphicsEffectsRecursively();
d_ptr->scene->d_func()->markDirty(this, QRectF(),
/*invalidateChildren=*/true,
/*maybeDirtyClipPath=*/false,
/*force=*/false,
/*ignoreOpacity=*/true);
+ }
if (d_ptr->isObject)
emit static_cast<QGraphicsObject *>(this)->opacityChanged();
@@ -4951,6 +4953,22 @@ int QGraphicsItemPrivate::depth() const
/*!
\internal
*/
+void QGraphicsItemPrivate::invalidateGraphicsEffectsRecursively()
+{
+ QGraphicsItemPrivate *itemPrivate = this;
+ do {
+ if (itemPrivate->graphicsEffect) {
+ itemPrivate->notifyInvalidated = 1;
+
+ if (!itemPrivate->updateDueToGraphicsEffect)
+ static_cast<QGraphicsItemEffectSourcePrivate *>(itemPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache();
+ }
+ } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : 0));
+}
+
+/*!
+ \internal
+*/
void QGraphicsItemPrivate::invalidateDepthRecursively()
{
if (itemDepth == -1)
@@ -5282,11 +5300,7 @@ void QGraphicsItem::update(const QRectF &rect)
return;
// Make sure we notify effects about invalidated source.
- QGraphicsItem *item = this;
- do {
- if (item->d_ptr->graphicsEffect)
- item->d_ptr->notifyInvalidated = 1;
- } while ((item = item->d_ptr->parent));
+ d_ptr->invalidateGraphicsEffectsRecursively();
if (CacheMode(d_ptr->cacheMode) != NoCache) {
// Invalidate cache.
@@ -10723,6 +10737,7 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP
}
pixmapPainter.end();
+
return pixmap;
}
@@ -10742,6 +10757,23 @@ QDebug operator<<(QDebug debug, QGraphicsItem *item)
return debug;
}
+QDebug operator<<(QDebug debug, QGraphicsObject *item)
+{
+ if (!item) {
+ debug << "QGraphicsObject(0)";
+ return debug;
+ }
+
+ debug.nospace() << item->metaObject()->className() << '(' << (void*)item;
+ if (!item->objectName().isEmpty())
+ debug << ", name = " << item->objectName();
+ debug.nospace() << ", parent = " << ((void*)item->parentItem())
+ << ", pos = " << item->pos()
+ << ", z = " << item->zValue() << ", flags = "
+ << item->flags() << ')';
+ return debug.space();
+}
+
QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemChange change)
{
const char *str = "UnknownChange";
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index 2665235..f3fe99c 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -555,7 +555,7 @@ public:
using QObject::children;
#endif
- void grabGesture(Qt::GestureType type, Qt::GestureContext context = Qt::WidgetWithChildrenGesture);
+ void grabGesture(Qt::GestureType type, Qt::GestureContext context = Qt::ItemWithChildrenGesture);
Q_SIGNALS:
void parentChanged();
@@ -1120,6 +1120,7 @@ template <class T> inline T qgraphicsitem_cast(const QGraphicsItem *item)
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem *item);
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsObject *item);
Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemChange change);
Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag);
Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlags flags);
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 5b401ba..046f5dc 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -177,6 +177,7 @@ public:
wantsActive(0),
holesInSiblingIndex(0),
sequentialOrdering(1),
+ updateDueToGraphicsEffect(0),
globalStackingOrder(-1),
q_ptr(0)
{
@@ -221,6 +222,7 @@ public:
bool discardUpdateRequest(bool ignoreClipping = false, bool ignoreVisibleBit = false,
bool ignoreDirtyBit = false, bool ignoreOpacity = false) const;
int depth() const;
+ void invalidateGraphicsEffectsRecursively();
void invalidateDepthRecursively();
void resolveDepth();
void addChild(QGraphicsItem *child);
@@ -502,6 +504,7 @@ public:
quint32 wantsActive : 1;
quint32 holesInSiblingIndex : 1;
quint32 sequentialOrdering : 1;
+ quint32 updateDueToGraphicsEffect : 1;
// Optional stacking order
int globalStackingOrder;
@@ -589,8 +592,11 @@ public:
inline const QWidget *widget() const
{ return 0; }
- inline void update()
- { item->update(); }
+ inline void update() {
+ item->d_ptr->updateDueToGraphicsEffect = true;
+ item->update();
+ item->d_ptr->updateDueToGraphicsEffect = false;
+ }
inline void effectBoundingRectChanged()
{ item->prepareGeometryChange(); }
@@ -619,6 +625,7 @@ public:
QGraphicsItem *item;
QGraphicsItemPaintInfo *info;
+ QTransform lastEffectTransform;
};
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index a624b10..c459d21 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -242,7 +242,6 @@
#include <QtGui/qstyleoption.h>
#include <QtGui/qtooltip.h>
#include <QtGui/qtransform.h>
-#include <QtGui/qgesture.h>
#include <QtGui/qinputcontext.h>
#include <QtGui/qgraphicseffect.h>
#include <private/qapplication_p.h>
@@ -251,6 +250,14 @@
#include <private/qt_x11_p.h>
#endif
#include <private/qgraphicseffect_p.h>
+#include <private/qgesturemanager_p.h>
+
+// #define GESTURE_DEBUG
+#ifndef GESTURE_DEBUG
+# define DEBUG if (0) qDebug
+#else
+# define DEBUG qDebug
+#endif
QT_BEGIN_NAMESPACE
@@ -1052,6 +1059,14 @@ bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event)
*/
bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
{
+ if (QGraphicsObject *object = item->toGraphicsObject()) {
+ QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
+ if (qAppPriv->gestureManager) {
+ if (qAppPriv->gestureManager->filterEvent(object, event))
+ return true;
+ }
+ }
+
if (filterEvent(item, event))
return false;
if (filterDescendantEvent(item, event))
@@ -3365,6 +3380,10 @@ bool QGraphicsScene::event(QEvent *event)
case QEvent::TouchEnd:
d->touchEventHandler(static_cast<QTouchEvent *>(event));
break;
+ case QEvent::Gesture:
+ case QEvent::GestureOverride:
+ d->gestureEventHandler(static_cast<QGestureEvent *>(event));
+ break;
default:
return QObject::event(event);
}
@@ -4569,6 +4588,11 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
else
painter->setWorldTransform(*transformPtr);
painter->setOpacity(opacity);
+
+ if (sourced->lastEffectTransform != painter->worldTransform()) {
+ sourced->lastEffectTransform = painter->worldTransform();
+ sourced->invalidateCache();
+ }
item->d_ptr->graphicsEffect->draw(painter, source);
painter->setWorldTransform(restoreTransform);
sourced->info = 0;
@@ -5699,6 +5723,238 @@ void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel)
dispatchHoverEvent(&hoverEvent);
}
+void QGraphicsScenePrivate::getGestureTargets(const QSet<QGesture *> &gestures,
+ QWidget *viewport,
+ QMap<Qt::GestureType, QGesture *> *conflictedGestures,
+ QList<QList<QGraphicsObject *> > *conflictedItems,
+ QHash<QGesture *, QGraphicsObject *> *normalGestures)
+{
+ foreach (QGesture *gesture, gestures) {
+ Qt::GestureType gestureType = gesture->gestureType();
+ if (gesture->hasHotSpot()) {
+ QPoint screenPos = gesture->hotSpot().toPoint();
+ QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport);
+ QList<QGraphicsObject *> result;
+ 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(gestureType)) {
+ result.append(item);
+ }
+ }
+ DEBUG() << "QGraphicsScenePrivate::getGestureTargets:"
+ << gesture << result;
+ if (result.size() == 1) {
+ normalGestures->insert(gesture, result.first());
+ } else if (!result.isEmpty()) {
+ conflictedGestures->insert(gestureType, gesture);
+ conflictedItems->append(result);
+ }
+ }
+ }
+}
+
+void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
+{
+ QWidget *viewport = event->widget();
+ if (!viewport)
+ return;
+ QList<QGesture *> allGestures = event->allGestures();
+ DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
+ << "Delivering gestures:" << allGestures;
+
+ typedef QHash<QGraphicsObject *, QList<QGesture *> > GesturesPerItem;
+ GesturesPerItem gesturesPerItem;
+
+ QSet<QGesture *> startedGestures;
+ foreach (QGesture *gesture, allGestures) {
+ 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);
+ } else {
+ gesturesPerItem[target].append(gesture);
+ }
+ }
+
+ QMap<Qt::GestureType, QGesture *> conflictedGestures;
+ QList<QList<QGraphicsObject *> > conflictedItems;
+ QHash<QGesture *, QGraphicsObject *> normalGestures;
+ getGestureTargets(startedGestures, viewport, &conflictedGestures, &conflictedItems,
+ &normalGestures);
+ DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
+ << "Conflicting gestures:" << conflictedGestures.values() << conflictedItems;
+ Q_ASSERT((conflictedGestures.isEmpty() && conflictedItems.isEmpty()) ||
+ (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()));
+
+ // gestures that were sent as override events, but no one accepted them
+ QHash<QGesture *, QGraphicsObject *> ignoredConflictedGestures;
+
+ // deliver conflicted gestures as override events first
+ while (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()) {
+ // get the topmost item to deliver the override event
+ Q_ASSERT(!conflictedItems.isEmpty());
+ Q_ASSERT(!conflictedItems.first().isEmpty());
+ QGraphicsObject *topmost = conflictedItems.first().first();
+ for (int i = 1; i < conflictedItems.size(); ++i) {
+ QGraphicsObject *item = conflictedItems.at(i).first();
+ if (qt_closestItemFirst(item, topmost)) {
+ topmost = item;
+ }
+ }
+ // get a list of gestures to send to the item
+ QList<Qt::GestureType> grabbedGestures =
+ topmost->QGraphicsItem::d_func()->gestureContext.keys();
+ QList<QGesture *> gestures;
+ for (int i = 0; i < grabbedGestures.size(); ++i) {
+ if (QGesture *g = conflictedGestures.value(grabbedGestures.at(i), 0)) {
+ gestures.append(g);
+ if (!ignoredConflictedGestures.contains(g))
+ ignoredConflictedGestures.insert(g, topmost);
+ }
+ }
+
+ // send gesture override to the topmost item
+ QGestureEvent ev(gestures);
+ 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);
+ DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
+ << "delivering override to"
+ << topmost << gestures;
+ sendEvent(topmost, &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->gestureType());
+ gestureTargets.remove(g);
+ // add the gesture to the list of normal delivered gestures
+ normalGestures.insert(g, topmost);
+ DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
+ << "override was accepted:"
+ << g << topmost;
+ ignoredConflictedGestures.remove(g);
+ }
+ }
+ // remove the item that we've already delivered from the list
+ for (int i = 0; i < conflictedItems.size(); ) {
+ QList<QGraphicsObject *> &items = conflictedItems[i];
+ if (items.first() == topmost) {
+ items.removeFirst();
+ if (items.isEmpty()) {
+ conflictedItems.removeAt(i);
+ continue;
+ }
+ }
+ ++i;
+ }
+ }
+
+ // put back those started gestures that are not in the conflicted state
+ // and remember their targets
+ QHash<QGesture *, QGraphicsObject *>::const_iterator it = normalGestures.begin(),
+ e = normalGestures.end();
+ for (; it != e; ++it) {
+ QGesture *g = it.key();
+ QGraphicsObject *receiver = it.value();
+ Q_ASSERT(!gestureTargets.contains(g));
+ gestureTargets.insert(g, receiver);
+ gesturesPerItem[receiver].append(g);
+ }
+ it = ignoredConflictedGestures.begin();
+ e = ignoredConflictedGestures.end();
+ for (; it != e; ++it) {
+ QGesture *g = it.key();
+ QGraphicsObject *receiver = it.value();
+ Q_ASSERT(!gestureTargets.contains(g));
+ gestureTargets.insert(g, receiver);
+ gesturesPerItem[receiver].append(g);
+ }
+
+ DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
+ << "Started gestures:" << normalGestures.keys()
+ << "All gestures:" << gesturesPerItem.values();
+
+ // deliver all events
+ QList<QGesture *> alreadyIgnoredGestures;
+ QHash<QGraphicsObject *, QSet<QGesture *> > itemIgnoredGestures;
+ QList<QGraphicsObject *> targetItems = gesturesPerItem.keys();
+ qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst);
+ for (int i = 0; i < targetItems.size(); ++i) {
+ QGraphicsObject *item = targetItems.at(i);
+ QList<QGesture *> gestures = gesturesPerItem.value(item);
+ // remove gestures that were already delivered once and were ignored
+ DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
+ << "already ignored gestures for item"
+ << item << ":" << itemIgnoredGestures.value(item);
+
+ if (itemIgnoredGestures.contains(item)) // don't deliver twice to the same item
+ continue;
+
+ QGraphicsItemPrivate *gid = item->QGraphicsItem::d_func();
+ foreach(QGesture *g, alreadyIgnoredGestures) {
+ if (gid->gestureContext.contains(g->gestureType()))
+ gestures += g;
+ }
+ if (gestures.isEmpty())
+ continue;
+ DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
+ << "delivering to"
+ << item << gestures;
+ QGestureEvent ev(gestures);
+ ev.setWidget(event->widget());
+ sendEvent(item, &ev);
+ QSet<QGesture *> ignoredGestures;
+ foreach (QGesture *g, gestures) {
+ if (!ev.isAccepted() && !ev.isAccepted(g))
+ ignoredGestures.insert(g);
+ }
+ if (!ignoredGestures.isEmpty()) {
+ // get a list of items under the (current) hotspot of each ignored
+ // gesture and start delivery again from the beginning
+ DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
+ << "item has ignored the event, will propagate."
+ << item << ignoredGestures;
+ itemIgnoredGestures[item] += ignoredGestures;
+ QMap<Qt::GestureType, QGesture *> conflictedGestures;
+ QList<QList<QGraphicsObject *> > itemsForConflictedGestures;
+ QHash<QGesture *, QGraphicsObject *> normalGestures;
+ getGestureTargets(ignoredGestures, viewport,
+ &conflictedGestures, &itemsForConflictedGestures,
+ &normalGestures);
+ QSet<QGraphicsObject *> itemsSet = targetItems.toSet();
+ for (int k = 0; k < itemsForConflictedGestures.size(); ++k)
+ itemsSet += itemsForConflictedGestures.at(k).toSet();
+ targetItems = itemsSet.toList();
+ qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst);
+ alreadyIgnoredGestures = conflictedGestures.values();
+ DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
+ << "new targets:" << targetItems;
+ i = -1; // start delivery again
+ continue;
+ }
+ }
+
+ // 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;
+ }
+ }
+}
+
QT_END_NAMESPACE
#include "moc_qgraphicsscene.cpp"
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index 8073695..cd20fd0 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -282,6 +282,13 @@ public:
bool allItemsIgnoreTouchEvents;
void enableTouchEventsOnViews();
+ QHash<QGesture *, QGraphicsObject *> gestureTargets;
+ void gestureEventHandler(QGestureEvent *event);
+ void getGestureTargets(const QSet<QGesture *> &gestures, QWidget *viewport,
+ QMap<Qt::GestureType, QGesture *> *conflictedGestures,
+ QList<QList<QGraphicsObject *> > *conflictedItems,
+ QHash<QGesture *, QGraphicsObject *> *normalGestures);
+
void updateInputMethodSensitivityInViews();
QList<QGraphicsItem *> modalPanels;
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index 32747cc..710c745 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -2701,6 +2701,19 @@ bool QGraphicsView::viewportEvent(QEvent *event)
return true;
}
+ case QEvent::Gesture:
+ case QEvent::GestureOverride:
+ {
+ if (!isEnabled())
+ return false;
+
+ if (d->scene && d->sceneInteractionAllowed) {
+ QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(event);
+ gestureEvent->setWidget(viewport());
+ (void) QApplication::sendEvent(d->scene, gestureEvent);
+ }
+ return true;
+ }
default:
break;
}