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()); |