src/gui/graphicsview/qgraphicsscene.cpp
branchRCL_3
changeset 7 3f74d0d4af4c
parent 5 d3bac044e0f0
child 13 c0432d11811c
equal deleted inserted replaced
6:dee5afe5301f 7:3f74d0d4af4c
   249 #ifdef Q_WS_X11
   249 #ifdef Q_WS_X11
   250 #include <private/qt_x11_p.h>
   250 #include <private/qt_x11_p.h>
   251 #endif
   251 #endif
   252 #include <private/qgraphicseffect_p.h>
   252 #include <private/qgraphicseffect_p.h>
   253 #include <private/qgesturemanager_p.h>
   253 #include <private/qgesturemanager_p.h>
       
   254 #include <private/qpathclipper_p.h>
   254 
   255 
   255 // #define GESTURE_DEBUG
   256 // #define GESTURE_DEBUG
   256 #ifndef GESTURE_DEBUG
   257 #ifndef GESTURE_DEBUG
   257 # define DEBUG if (0) qDebug
   258 # define DEBUG if (0) qDebug
   258 #else
   259 #else
   370                 q->connect(q, SIGNAL(changed(QList<QRectF>)),
   371                 q->connect(q, SIGNAL(changed(QList<QRectF>)),
   371                            views.at(i), SLOT(updateScene(QList<QRectF>)));
   372                            views.at(i), SLOT(updateScene(QList<QRectF>)));
   372             }
   373             }
   373         }
   374         }
   374     } else {
   375     } else {
   375         updateAll = false;
   376         if (views.isEmpty()) {
       
   377             updateAll = false;
       
   378             return;
       
   379         }
   376         for (int i = 0; i < views.size(); ++i)
   380         for (int i = 0; i < views.size(); ++i)
   377             views.at(i)->d_func()->processPendingUpdates();
   381             views.at(i)->d_func()->processPendingUpdates();
   378         // It's important that we update all views before we dispatch, hence two for-loops.
   382         // It's important that we update all views before we dispatch, hence two for-loops.
   379         for (int i = 0; i < views.size(); ++i)
   383         for (int i = 0; i < views.size(); ++i)
   380             views.at(i)->d_func()->dispatchPendingUpdateRequests();
   384             views.at(i)->d_func()->dispatchPendingUpdateRequests();
   795             // automatically by removing WA_InputMethodEnabled on
   799             // automatically by removing WA_InputMethodEnabled on
   796             // the views, but if we are changing focus, we have to
   800             // the views, but if we are changing focus, we have to
   797             // do it ourselves.
   801             // do it ourselves.
   798             if (item) {
   802             if (item) {
   799                 for (int i = 0; i < views.size(); ++i)
   803                 for (int i = 0; i < views.size(); ++i)
   800                     views.at(i)->inputContext()->reset();
   804                     if (views.at(i)->inputContext())
       
   805                         views.at(i)->inputContext()->reset();
   801             }
   806             }
   802         }
   807         }
   803 #endif //QT_NO_IM
   808 #endif //QT_NO_IM
   804     }
   809     }
   805 
   810 
  4278     pixmapPainter.end();
  4283     pixmapPainter.end();
  4279 
  4284 
  4280     if (!subPix.isNull()) {
  4285     if (!subPix.isNull()) {
  4281         // Blit the subpixmap into the main pixmap.
  4286         // Blit the subpixmap into the main pixmap.
  4282         pixmapPainter.begin(pix);
  4287         pixmapPainter.begin(pix);
       
  4288         pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
  4283         pixmapPainter.setClipRegion(pixmapExposed);
  4289         pixmapPainter.setClipRegion(pixmapExposed);
  4284         pixmapPainter.drawPixmap(br.topLeft(), subPix);
  4290         pixmapPainter.drawPixmap(br.topLeft(), subPix);
  4285         pixmapPainter.end();
  4291         pixmapPainter.end();
  4286     }
  4292     }
  4287 }
  4293 }
  4443                          oldPainterOpacity != newPainterOpacity, painterStateProtection);
  4449                          oldPainterOpacity != newPainterOpacity, painterStateProtection);
  4444             return;
  4450             return;
  4445         }
  4451         }
  4446 
  4452 
  4447         // Create or reuse offscreen pixmap, possibly scroll/blit from the old one.
  4453         // Create or reuse offscreen pixmap, possibly scroll/blit from the old one.
       
  4454         // If the world transform is rotated we always recreate the cache to avoid
       
  4455         // wrong blending.
  4448         bool pixModified = false;
  4456         bool pixModified = false;
  4449         QGraphicsItemCache::DeviceData *deviceData = &itemCache->deviceData[widget];
  4457         QGraphicsItemCache::DeviceData *deviceData = &itemCache->deviceData[widget];
  4450         bool invertable = true;
  4458         bool invertable = true;
  4451         QTransform diff = deviceData->lastTransform.inverted(&invertable);
  4459         QTransform diff = deviceData->lastTransform.inverted(&invertable);
  4452         if (invertable)
  4460         if (invertable)
  4453             diff *= painter->worldTransform();
  4461             diff *= painter->worldTransform();
  4454         deviceData->lastTransform = painter->worldTransform();
  4462         deviceData->lastTransform = painter->worldTransform();
  4455         if (!invertable || diff.type() > QTransform::TxTranslate) {
  4463         if (!invertable
       
  4464             || diff.type() > QTransform::TxTranslate
       
  4465             || painter->worldTransform().type() > QTransform::TxScale) {
  4456             pixModified = true;
  4466             pixModified = true;
  4457             itemCache->allExposed = true;
  4467             itemCache->allExposed = true;
  4458             itemCache->exposed.clear();
  4468             itemCache->exposed.clear();
  4459             pix = QPixmap();
  4469             pix = QPixmap();
  4460         }
  4470         }
  4601 {
  4611 {
  4602     // Make sure we don't have unpolished items before we draw.
  4612     // Make sure we don't have unpolished items before we draw.
  4603     if (!unpolishedItems.isEmpty())
  4613     if (!unpolishedItems.isEmpty())
  4604         _q_polishItems();
  4614         _q_polishItems();
  4605 
  4615 
       
  4616     updateAll = false;
  4606     QRectF exposedSceneRect;
  4617     QRectF exposedSceneRect;
  4607     if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) {
  4618     if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) {
  4608         exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1);
  4619         exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1);
  4609         if (viewTransform)
  4620         if (viewTransform)
  4610             exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect);
  4621             exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect);
  4628     const bool itemHasChildren = !item->d_ptr->children.isEmpty();
  4639     const bool itemHasChildren = !item->d_ptr->children.isEmpty();
  4629     if (!itemHasContents && !itemHasChildren)
  4640     if (!itemHasContents && !itemHasChildren)
  4630         return; // Item has neither contents nor children!(?)
  4641         return; // Item has neither contents nor children!(?)
  4631 
  4642 
  4632     const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
  4643     const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
  4633     const bool itemIsFullyTransparent = (opacity < 0.0001);
  4644     const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
  4634     if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity()))
  4645     if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity()))
  4635         return;
  4646         return;
  4636 
  4647 
  4637     QTransform transform(Qt::Uninitialized);
  4648     QTransform transform(Qt::Uninitialized);
  4638     QTransform *transformPtr = 0;
  4649     QTransform *transformPtr = 0;
  4671         QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect()
  4682         QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect()
  4672                                                         : transformPtr->mapRect(brect).toRect();
  4683                                                         : transformPtr->mapRect(brect).toRect();
  4673         if (widget)
  4684         if (widget)
  4674             item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
  4685             item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
  4675         viewBoundingRect.adjust(-1, -1, 1, 1);
  4686         viewBoundingRect.adjust(-1, -1, 1, 1);
  4676         drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.isEmpty();
  4687         drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect)
       
  4688                                  : !viewBoundingRect.normalized().isEmpty();
  4677         if (!drawItem) {
  4689         if (!drawItem) {
  4678             if (!itemHasChildren)
  4690             if (!itemHasChildren)
  4679                 return;
  4691                 return;
  4680             if (itemClipsChildrenToShape) {
  4692             if (itemClipsChildrenToShape) {
  4681                 if (wasDirtyParentSceneTransform)
  4693                 if (wasDirtyParentSceneTransform)
  4705         painter->setOpacity(opacity);
  4717         painter->setOpacity(opacity);
  4706 
  4718 
  4707         if (sourced->currentCachedSystem() != Qt::LogicalCoordinates
  4719         if (sourced->currentCachedSystem() != Qt::LogicalCoordinates
  4708             && sourced->lastEffectTransform != painter->worldTransform())
  4720             && sourced->lastEffectTransform != painter->worldTransform())
  4709         {
  4721         {
  4710             bool unclipped = false;
       
  4711             if (sourced->lastEffectTransform.type() <= QTransform::TxTranslate
  4722             if (sourced->lastEffectTransform.type() <= QTransform::TxTranslate
  4712                 && painter->worldTransform().type() <= QTransform::TxTranslate)
  4723                 && painter->worldTransform().type() <= QTransform::TxTranslate)
  4713             {
  4724             {
  4714                 QRectF itemRect = item->boundingRect();
  4725                 QRectF sourceRect = sourced->boundingRect(Qt::DeviceCoordinates);
  4715                 if (!item->d_ptr->children.isEmpty())
  4726                 QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect);
  4716                     itemRect |= item->childrenBoundingRect();
  4727 
  4717 
  4728                 sourced->setCachedOffset(effectRect.topLeft());
  4718                 QRectF oldSourceRect = sourced->lastEffectTransform.mapRect(itemRect);
  4729             } else {
  4719                 QRectF newSourceRect = painter->worldTransform().mapRect(itemRect);
  4730                 sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged);
  4720 
       
  4721                 QRect oldEffectRect = sourced->paddedEffectRect(sourced->currentCachedSystem(), sourced->currentCachedMode(), oldSourceRect);
       
  4722                 QRect newEffectRect = sourced->paddedEffectRect(sourced->currentCachedSystem(), sourced->currentCachedMode(), newSourceRect);
       
  4723 
       
  4724                 QRect deviceRect(0, 0, painter->device()->width(), painter->device()->height());
       
  4725                 if (deviceRect.contains(oldEffectRect) && deviceRect.contains(newEffectRect)) {
       
  4726                     sourced->setCachedOffset(newEffectRect.topLeft());
       
  4727                     unclipped = true;
       
  4728                 }
       
  4729             }
  4731             }
  4730 
  4732 
  4731             sourced->lastEffectTransform = painter->worldTransform();
  4733             sourced->lastEffectTransform = painter->worldTransform();
  4732 
       
  4733             if (!unclipped)
       
  4734                 sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged);
       
  4735         }
  4734         }
  4736 
  4735 
  4737         item->d_ptr->graphicsEffect->draw(painter);
  4736         item->d_ptr->graphicsEffect->draw(painter);
  4738         painter->setWorldTransform(restoreTransform);
  4737         painter->setWorldTransform(restoreTransform);
  4739         sourced->info = 0;
  4738         sourced->info = 0;
  4748 void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform,
  4747 void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform,
  4749                                  const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget,
  4748                                  const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget,
  4750                                  qreal opacity, const QTransform *effectTransform,
  4749                                  qreal opacity, const QTransform *effectTransform,
  4751                                  bool wasDirtyParentSceneTransform, bool drawItem)
  4750                                  bool wasDirtyParentSceneTransform, bool drawItem)
  4752 {
  4751 {
  4753     const bool itemIsFullyTransparent = (opacity < 0.0001);
  4752     const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
  4754     const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
  4753     const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
  4755     const bool itemHasChildren = !item->d_ptr->children.isEmpty();
  4754     const bool itemHasChildren = !item->d_ptr->children.isEmpty();
  4756 
  4755 
  4757     int i = 0;
  4756     int i = 0;
  4758     if (itemHasChildren) {
  4757     if (itemHasChildren) {
  4763             Q_ASSERT(transformPtr);
  4762             Q_ASSERT(transformPtr);
  4764             if (effectTransform)
  4763             if (effectTransform)
  4765                 painter->setWorldTransform(*transformPtr * *effectTransform);
  4764                 painter->setWorldTransform(*transformPtr * *effectTransform);
  4766             else
  4765             else
  4767                 painter->setWorldTransform(*transformPtr);
  4766                 painter->setWorldTransform(*transformPtr);
  4768             painter->setClipPath(item->shape(), Qt::IntersectClip);
  4767             QRectF clipRect;
       
  4768             const QPainterPath clipPath(item->shape());
       
  4769             if (QPathClipper::pathToRect(clipPath, &clipRect))
       
  4770                 painter->setClipRect(clipRect, Qt::IntersectClip);
       
  4771             else
       
  4772                 painter->setClipPath(clipPath, Qt::IntersectClip);
  4769         }
  4773         }
  4770 
  4774 
  4771         // Draw children behind
  4775         // Draw children behind
  4772         for (i = 0; i < item->d_ptr->children.size(); ++i) {
  4776         for (i = 0; i < item->d_ptr->children.size(); ++i) {
  4773             QGraphicsItem *child = item->d_ptr->children.at(i);
  4777             QGraphicsItem *child = item->d_ptr->children.at(i);
  4799                 painter->setWorldTransform(*transformPtr * *effectTransform);
  4803                 painter->setWorldTransform(*transformPtr * *effectTransform);
  4800             else
  4804             else
  4801                 painter->setWorldTransform(*transformPtr);
  4805                 painter->setWorldTransform(*transformPtr);
  4802         }
  4806         }
  4803 
  4807 
  4804         if (itemClipsToShape)
  4808         if (itemClipsToShape) {
  4805             painter->setClipPath(item->shape(), Qt::IntersectClip);
  4809             QRectF clipRect;
       
  4810             const QPainterPath clipPath(item->shape());
       
  4811             if (QPathClipper::pathToRect(clipPath, &clipRect))
       
  4812                 painter->setClipRect(clipRect, Qt::IntersectClip);
       
  4813             else
       
  4814                 painter->setClipPath(clipPath, Qt::IntersectClip);
       
  4815         }
  4806         painter->setOpacity(opacity);
  4816         painter->setOpacity(opacity);
  4807 
  4817 
  4808         if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget)
  4818         if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget)
  4809             item->paint(painter, &styleOptionTmp, widget);
  4819             item->paint(painter, &styleOptionTmp, widget);
  4810         else
  4820         else
  4978         if (item->d_ptr->graphicsEffect)
  4988         if (item->d_ptr->graphicsEffect)
  4979             itemHasContents = true;
  4989             itemHasContents = true;
  4980     }
  4990     }
  4981 
  4991 
  4982     const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
  4992     const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
  4983     const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity && opacity < 0.0001;
  4993     const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity
       
  4994                                         && QGraphicsItemPrivate::isOpacityNull(opacity);
  4984     if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) {
  4995     if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) {
  4985         resetDirtyItem(item, /*recursive=*/itemHasChildren);
  4996         resetDirtyItem(item, /*recursive=*/itemHasChildren);
  4986         return;
  4997         return;
  4987     }
  4998     }
  4988 
  4999 
  5113 
  5124 
  5114     resetDirtyItem(item);
  5125     resetDirtyItem(item);
  5115 }
  5126 }
  5116 
  5127 
  5117 /*!
  5128 /*!
       
  5129     \obsolete
       
  5130 
  5118     Paints the given \a items using the provided \a painter, after the
  5131     Paints the given \a items using the provided \a painter, after the
  5119     background has been drawn, and before the foreground has been
  5132     background has been drawn, and before the foreground has been
  5120     drawn.  All painting is done in \e scene coordinates. Before
  5133     drawn.  All painting is done in \e scene coordinates. Before
  5121     drawing each item, the painter must be transformed using
  5134     drawing each item, the painter must be transformed using
  5122     QGraphicsItem::sceneTransform().
  5135     QGraphicsItem::sceneTransform().
  5135 
  5148 
  5136     Example:
  5149     Example:
  5137 
  5150 
  5138     \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0
  5151     \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0
  5139 
  5152 
  5140     \obsolete Since Qt 4.6, this function is not called anymore unless
  5153     Since Qt 4.6, this function is not called anymore unless
  5141     the QGraphicsView::IndirectPainting flag is given as an Optimization
  5154     the QGraphicsView::IndirectPainting flag is given as an Optimization
  5142     flag.
  5155     flag.
  5143 
  5156 
  5144     \sa drawBackground(), drawForeground()
  5157     \sa drawBackground(), drawForeground()
  5145 */
  5158 */
  5151     Q_D(QGraphicsScene);
  5164     Q_D(QGraphicsScene);
  5152     // Make sure we don't have unpolished items before we draw.
  5165     // Make sure we don't have unpolished items before we draw.
  5153     if (!d->unpolishedItems.isEmpty())
  5166     if (!d->unpolishedItems.isEmpty())
  5154         d->_q_polishItems();
  5167         d->_q_polishItems();
  5155 
  5168 
       
  5169     d->updateAll = false;
  5156     QTransform viewTransform = painter->worldTransform();
  5170     QTransform viewTransform = painter->worldTransform();
  5157     Q_UNUSED(options);
  5171     Q_UNUSED(options);
  5158 
  5172 
  5159     // Determine view, expose and flags.
  5173     // Determine view, expose and flags.
  5160     QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
  5174     QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
  5690             // if the TouchBegin handler recurses, we assume that means the event
  5704             // if the TouchBegin handler recurses, we assume that means the event
  5691             // has been implicitly accepted and continue to send touch events
  5705             // has been implicitly accepted and continue to send touch events
  5692             item->d_ptr->acceptedTouchBeginEvent = true;
  5706             item->d_ptr->acceptedTouchBeginEvent = true;
  5693             bool res = sendTouchBeginEvent(item, &touchEvent)
  5707             bool res = sendTouchBeginEvent(item, &touchEvent)
  5694                        && touchEvent.isAccepted();
  5708                        && touchEvent.isAccepted();
  5695             if (!res)
  5709             if (!res) {
       
  5710                 // forget about these touch points, we didn't handle them
       
  5711                 for (int i = 0; i < touchEvent.touchPoints().count(); ++i) {
       
  5712                     const QTouchEvent::TouchPoint &touchPoint = touchEvent.touchPoints().at(i);
       
  5713                     itemForTouchPointId.remove(touchPoint.id());
       
  5714                     sceneCurrentTouchPoints.remove(touchPoint.id());
       
  5715                 }
  5696                 ignoreSceneTouchEvent = false;
  5716                 ignoreSceneTouchEvent = false;
       
  5717             }
  5697             break;
  5718             break;
  5698         }
  5719         }
  5699         default:
  5720         default:
  5700             if (item->d_ptr->acceptedTouchBeginEvent) {
  5721             if (item->d_ptr->acceptedTouchBeginEvent) {
  5701                 updateTouchPointsForItem(item, &touchEvent);
  5722                 updateTouchPointsForItem(item, &touchEvent);
  5882         if (gesture->hasHotSpot()) {
  5903         if (gesture->hasHotSpot()) {
  5883             QPoint screenPos = gesture->hotSpot().toPoint();
  5904             QPoint screenPos = gesture->hotSpot().toPoint();
  5884             QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport);
  5905             QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport);
  5885             QList<QGraphicsObject *> result;
  5906             QList<QGraphicsObject *> result;
  5886             for (int j = 0; j < items.size(); ++j) {
  5907             for (int j = 0; j < items.size(); ++j) {
  5887                 QGraphicsObject *item = items.at(j)->toGraphicsObject();
  5908                 QGraphicsItem *item = items.at(j);
  5888                 if (!item)
  5909 
  5889                     continue;
  5910                 // Check if the item is blocked by a modal panel and use it as
  5890                 QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
  5911                 // a target instead of this item.
  5891                 if (d->gestureContext.contains(gestureType)) {
  5912                 (void) item->isBlockedByModalPanel(&item);
  5892                     result.append(item);
  5913 
       
  5914                 if (QGraphicsObject *itemobj = item->toGraphicsObject()) {
       
  5915                     QGraphicsItemPrivate *d = item->d_func();
       
  5916                     if (d->gestureContext.contains(gestureType)) {
       
  5917                         result.append(itemobj);
       
  5918                     }
  5893                 }
  5919                 }
       
  5920                 // Don't propagate through panels.
       
  5921                 if (item->isPanel())
       
  5922                     break;
  5894             }
  5923             }
  5895             DEBUG() << "QGraphicsScenePrivate::getGestureTargets:"
  5924             DEBUG() << "QGraphicsScenePrivate::getGestureTargets:"
  5896                     << gesture << result;
  5925                     << gesture << result;
  5897             if (result.size() == 1) {
  5926             if (result.size() == 1) {
  5898                 normalGestures->insert(gesture, result.first());
  5927                 normalGestures->insert(gesture, result.first());