1 /**************************************************************************** |
1 /**************************************************************************** |
2 ** |
2 ** |
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
4 ** All rights reserved. |
4 ** All rights reserved. |
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
6 ** |
6 ** |
7 ** This file is part of the QtGui module of the Qt Toolkit. |
7 ** This file is part of the QtGui module of the Qt Toolkit. |
8 ** |
8 ** |
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(); |
426 /*! |
430 /*! |
427 \internal |
431 \internal |
428 */ |
432 */ |
429 void QGraphicsScenePrivate::_q_polishItems() |
433 void QGraphicsScenePrivate::_q_polishItems() |
430 { |
434 { |
431 QSet<QGraphicsItem *>::Iterator it; |
435 if (unpolishedItems.isEmpty()) |
|
436 return; |
|
437 |
432 const QVariant booleanTrueVariant(true); |
438 const QVariant booleanTrueVariant(true); |
433 while (!unpolishedItems.isEmpty()) { |
439 QGraphicsItem *item = 0; |
434 it = unpolishedItems.begin(); |
440 QGraphicsItemPrivate *itemd = 0; |
435 QGraphicsItem *item = *it; |
441 const int oldUnpolishedCount = unpolishedItems.count(); |
436 unpolishedItems.erase(it); |
442 |
437 if (!item->d_ptr->explicitlyHidden) { |
443 for (int i = 0; i < oldUnpolishedCount; ++i) { |
|
444 item = unpolishedItems.at(i); |
|
445 if (!item) |
|
446 continue; |
|
447 itemd = item->d_ptr.data(); |
|
448 itemd->pendingPolish = false; |
|
449 if (!itemd->explicitlyHidden) { |
438 item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant); |
450 item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant); |
439 item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant); |
451 item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant); |
440 } |
452 } |
441 if (item->isWidget()) { |
453 if (itemd->isWidget) { |
442 QEvent event(QEvent::Polish); |
454 QEvent event(QEvent::Polish); |
443 QApplication::sendEvent((QGraphicsWidget *)item, &event); |
455 QApplication::sendEvent((QGraphicsWidget *)item, &event); |
444 } |
456 } |
|
457 } |
|
458 |
|
459 if (unpolishedItems.count() == oldUnpolishedCount) { |
|
460 // No new items were added to the vector. |
|
461 unpolishedItems.clear(); |
|
462 } else { |
|
463 // New items were appended; keep them and remove the old ones. |
|
464 unpolishedItems.remove(0, oldUnpolishedCount); |
|
465 unpolishedItems.squeeze(); |
|
466 QMetaObject::invokeMethod(q_ptr, "_q_polishItems", Qt::QueuedConnection); |
445 } |
467 } |
446 } |
468 } |
447 |
469 |
448 void QGraphicsScenePrivate::_q_processDirtyItems() |
470 void QGraphicsScenePrivate::_q_processDirtyItems() |
449 { |
471 { |
594 // Remove from parent, or unregister from toplevels. |
616 // Remove from parent, or unregister from toplevels. |
595 if (QGraphicsItem *parentItem = item->parentItem()) { |
617 if (QGraphicsItem *parentItem = item->parentItem()) { |
596 if (parentItem->scene()) { |
618 if (parentItem->scene()) { |
597 Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem", |
619 Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem", |
598 "Parent item's scene is different from this item's scene"); |
620 "Parent item's scene is different from this item's scene"); |
599 item->d_ptr->setParentItemHelper(0); |
621 item->setParentItem(0); |
600 } |
622 } |
601 } else { |
623 } else { |
602 unregisterTopLevelItem(item); |
624 unregisterTopLevelItem(item); |
603 } |
625 } |
604 |
626 |
633 |
655 |
634 // Update selected & hovered item bookkeeping |
656 // Update selected & hovered item bookkeeping |
635 selectedItems.remove(item); |
657 selectedItems.remove(item); |
636 hoverItems.removeAll(item); |
658 hoverItems.removeAll(item); |
637 cachedItemsUnderMouse.removeAll(item); |
659 cachedItemsUnderMouse.removeAll(item); |
638 unpolishedItems.remove(item); |
660 if (item->d_ptr->pendingPolish) { |
|
661 const int unpolishedIndex = unpolishedItems.indexOf(item); |
|
662 if (unpolishedIndex != -1) |
|
663 unpolishedItems[unpolishedIndex] = 0; |
|
664 item->d_ptr->pendingPolish = false; |
|
665 } |
639 resetDirtyItem(item); |
666 resetDirtyItem(item); |
640 |
667 |
641 //We remove all references of item from the sceneEventFilter arrays |
668 //We remove all references of item from the sceneEventFilter arrays |
642 QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin(); |
669 QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin(); |
643 while (iterator != sceneEventFilters.end()) { |
670 while (iterator != sceneEventFilters.end()) { |
772 // automatically by removing WA_InputMethodEnabled on |
799 // automatically by removing WA_InputMethodEnabled on |
773 // the views, but if we are changing focus, we have to |
800 // the views, but if we are changing focus, we have to |
774 // do it ourselves. |
801 // do it ourselves. |
775 if (item) { |
802 if (item) { |
776 for (int i = 0; i < views.size(); ++i) |
803 for (int i = 0; i < views.size(); ++i) |
777 views.at(i)->inputContext()->reset(); |
804 if (views.at(i)->inputContext()) |
|
805 views.at(i)->inputContext()->reset(); |
778 } |
806 } |
779 } |
807 } |
780 #endif //QT_NO_IM |
808 #endif //QT_NO_IM |
781 } |
809 } |
782 |
810 |
1130 enabled, the event is sent; otherwise it is stopped. |
1158 enabled, the event is sent; otherwise it is stopped. |
1131 */ |
1159 */ |
1132 bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event) |
1160 bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event) |
1133 { |
1161 { |
1134 if (QGraphicsObject *object = item->toGraphicsObject()) { |
1162 if (QGraphicsObject *object = item->toGraphicsObject()) { |
1135 if (qt_gestureManager) { |
1163 QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager; |
1136 if (qt_gestureManager->filterEvent(object, event)) |
1164 if (gestureManager) { |
|
1165 if (gestureManager->filterEvent(object, event)) |
1137 return true; |
1166 return true; |
1138 } |
1167 } |
1139 } |
1168 } |
1140 |
1169 |
1141 if (filterEvent(item, event)) |
1170 if (filterEvent(item, event)) |
1559 d_func()->init(); |
1588 d_func()->init(); |
1560 setSceneRect(x, y, width, height); |
1589 setSceneRect(x, y, width, height); |
1561 } |
1590 } |
1562 |
1591 |
1563 /*! |
1592 /*! |
1564 Destroys the QGraphicsScene object. |
1593 Removes and deletes all items from the scene object |
|
1594 before destroying the scene object. The scene object |
|
1595 is removed from the application's global scene list, |
|
1596 and it is removed from all associated views. |
1565 */ |
1597 */ |
1566 QGraphicsScene::~QGraphicsScene() |
1598 QGraphicsScene::~QGraphicsScene() |
1567 { |
1599 { |
1568 Q_D(QGraphicsScene); |
1600 Q_D(QGraphicsScene); |
1569 |
1601 |
1926 \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const |
1958 \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const |
1927 \obsolete |
1959 \obsolete |
1928 \since 4.3 |
1960 \since 4.3 |
1929 |
1961 |
1930 This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode). |
1962 This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode). |
1931 |
1963 |
1932 This function is deprecated and returns incorrect results if the scene |
1964 This function is deprecated and returns incorrect results if the scene |
1933 contains items that ignore transformations. Use the overload that takes |
1965 contains items that ignore transformations. Use the overload that takes |
1934 a QTransform instead. |
1966 a QTransform instead. |
1935 */ |
1967 */ |
1936 |
1968 |
2441 removeItem(group); |
2473 removeItem(group); |
2442 delete group; |
2474 delete group; |
2443 } |
2475 } |
2444 |
2476 |
2445 /*! |
2477 /*! |
2446 Adds or moves the item \a item and all its childen to the scene. |
2478 Adds or moves the \a item and all its childen to this scene. |
|
2479 This scene takes ownership of the \a item. |
2447 |
2480 |
2448 If the item is visible (i.e., QGraphicsItem::isVisible() returns |
2481 If the item is visible (i.e., QGraphicsItem::isVisible() returns |
2449 true), QGraphicsScene will emit changed() once control goes back |
2482 true), QGraphicsScene will emit changed() once control goes back |
2450 to the event loop. |
2483 to the event loop. |
2451 |
2484 |
2452 If the item is already in a different scene, it will first be removed from |
2485 If the item is already in a different scene, it will first be |
2453 its old scene, and then added to this scene as a top-level. |
2486 removed from its old scene, and then added to this scene as a |
2454 |
2487 top-level. |
2455 QGraphicsScene will send ItemSceneChange notifications to \a item while |
2488 |
2456 it is added to the scene. If item does not currently belong to a scene, only one |
2489 QGraphicsScene will send ItemSceneChange notifications to \a item |
2457 notification is sent. If it does belong to scene already (i.e., it is |
2490 while it is added to the scene. If item does not currently belong |
2458 moved to this scene), QGraphicsScene will send an addition notification as |
2491 to a scene, only one notification is sent. If it does belong to |
2459 the item is removed from its previous scene. |
2492 scene already (i.e., it is moved to this scene), QGraphicsScene |
2460 |
2493 will send an addition notification as the item is removed from its |
2461 If the item is a panel, the scene is active, and there is no active panel |
2494 previous scene. |
2462 in the scene, then the item will be activated. |
2495 |
|
2496 If the item is a panel, the scene is active, and there is no |
|
2497 active panel in the scene, then the item will be activated. |
2463 |
2498 |
2464 \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(), |
2499 \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(), |
2465 addRect(), addText(), addWidget(), {QGraphicsItem#Sorting}{Sorting} |
2500 addRect(), addText(), addWidget(), {QGraphicsItem#Sorting}{Sorting} |
2466 */ |
2501 */ |
2467 void QGraphicsScene::addItem(QGraphicsItem *item) |
2502 void QGraphicsScene::addItem(QGraphicsItem *item) |
2469 Q_D(QGraphicsScene); |
2504 Q_D(QGraphicsScene); |
2470 if (!item) { |
2505 if (!item) { |
2471 qWarning("QGraphicsScene::addItem: cannot add null item"); |
2506 qWarning("QGraphicsScene::addItem: cannot add null item"); |
2472 return; |
2507 return; |
2473 } |
2508 } |
2474 if (item->scene() == this) { |
2509 if (item->d_ptr->scene == this) { |
2475 qWarning("QGraphicsScene::addItem: item has already been added to this scene"); |
2510 qWarning("QGraphicsScene::addItem: item has already been added to this scene"); |
2476 return; |
2511 return; |
2477 } |
2512 } |
2478 // Remove this item from its existing scene |
2513 // Remove this item from its existing scene |
2479 if (QGraphicsScene *oldScene = item->scene()) |
2514 if (QGraphicsScene *oldScene = item->d_ptr->scene) |
2480 oldScene->removeItem(item); |
2515 oldScene->removeItem(item); |
2481 |
2516 |
2482 // Notify the item that its scene is changing, and allow the item to |
2517 // Notify the item that its scene is changing, and allow the item to |
2483 // react. |
2518 // react. |
2484 const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange, |
2519 const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange, |
2485 qVariantFromValue<QGraphicsScene *>(this))); |
2520 qVariantFromValue<QGraphicsScene *>(this))); |
2486 QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(newSceneVariant); |
2521 QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(newSceneVariant); |
2487 if (targetScene != this) { |
2522 if (targetScene != this) { |
2488 if (targetScene && item->scene() != targetScene) |
2523 if (targetScene && item->d_ptr->scene != targetScene) |
2489 targetScene->addItem(item); |
2524 targetScene->addItem(item); |
2490 return; |
2525 return; |
2491 } |
2526 } |
2492 |
2527 |
|
2528 if (d->unpolishedItems.isEmpty()) |
|
2529 QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection); |
|
2530 d->unpolishedItems.append(item); |
|
2531 item->d_ptr->pendingPolish = true; |
|
2532 |
2493 // Detach this item from its parent if the parent's scene is different |
2533 // Detach this item from its parent if the parent's scene is different |
2494 // from this scene. |
2534 // from this scene. |
2495 if (QGraphicsItem *itemParent = item->parentItem()) { |
2535 if (QGraphicsItem *itemParent = item->d_ptr->parent) { |
2496 if (itemParent->scene() != this) |
2536 if (itemParent->d_ptr->scene != this) |
2497 item->setParentItem(0); |
2537 item->setParentItem(0); |
2498 } |
2538 } |
2499 |
2539 |
2500 // Add the item to this scene |
2540 // Add the item to this scene |
2501 item->d_func()->scene = targetScene; |
2541 item->d_func()->scene = targetScene; |
2521 if (d->allItemsIgnoreHoverEvents && d->itemAcceptsHoverEvents_helper(item)) { |
2561 if (d->allItemsIgnoreHoverEvents && d->itemAcceptsHoverEvents_helper(item)) { |
2522 d->allItemsIgnoreHoverEvents = false; |
2562 d->allItemsIgnoreHoverEvents = false; |
2523 d->enableMouseTrackingOnViews(); |
2563 d->enableMouseTrackingOnViews(); |
2524 } |
2564 } |
2525 #ifndef QT_NO_CURSOR |
2565 #ifndef QT_NO_CURSOR |
2526 if (d->allItemsUseDefaultCursor && item->hasCursor()) { |
2566 if (d->allItemsUseDefaultCursor && item->d_ptr->hasCursor) { |
2527 d->allItemsUseDefaultCursor = false; |
2567 d->allItemsUseDefaultCursor = false; |
2528 if (d->allItemsIgnoreHoverEvents) // already enabled otherwise |
2568 if (d->allItemsIgnoreHoverEvents) // already enabled otherwise |
2529 d->enableMouseTrackingOnViews(); |
2569 d->enableMouseTrackingOnViews(); |
2530 } |
2570 } |
2531 #endif //QT_NO_CURSOR |
2571 #endif //QT_NO_CURSOR |
2532 |
2572 |
2533 // Enable touch events if the item accepts touch events. |
2573 // Enable touch events if the item accepts touch events. |
2534 if (d->allItemsIgnoreTouchEvents && item->acceptTouchEvents()) { |
2574 if (d->allItemsIgnoreTouchEvents && item->d_ptr->acceptTouchEvents) { |
2535 d->allItemsIgnoreTouchEvents = false; |
2575 d->allItemsIgnoreTouchEvents = false; |
2536 d->enableTouchEventsOnViews(); |
2576 d->enableTouchEventsOnViews(); |
2537 } |
2577 } |
2538 |
2578 |
2539 // Update selection lists |
2579 // Update selection lists |
2562 lastNew->d_func()->focusNext = d->tabFocusFirst; |
2602 lastNew->d_func()->focusNext = d->tabFocusFirst; |
2563 } |
2603 } |
2564 } |
2604 } |
2565 |
2605 |
2566 // Add all children recursively |
2606 // Add all children recursively |
2567 foreach (QGraphicsItem *child, item->children()) |
2607 item->d_ptr->ensureSortedChildren(); |
2568 addItem(child); |
2608 for (int i = 0; i < item->d_ptr->children.size(); ++i) |
|
2609 addItem(item->d_ptr->children.at(i)); |
2569 |
2610 |
2570 // Resolve font and palette. |
2611 // Resolve font and palette. |
2571 item->d_ptr->resolveFont(d->font.resolve()); |
2612 item->d_ptr->resolveFont(d->font.resolve()); |
2572 item->d_ptr->resolvePalette(d->palette.resolve()); |
2613 item->d_ptr->resolvePalette(d->palette.resolve()); |
2573 |
2614 |
2574 if (d->unpolishedItems.isEmpty()) |
|
2575 QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection); |
|
2576 d->unpolishedItems.insert(item); |
|
2577 |
2615 |
2578 // Reenable selectionChanged() for individual items |
2616 // Reenable selectionChanged() for individual items |
2579 --d->selectionChanging; |
2617 --d->selectionChanging; |
2580 if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemSize) |
2618 if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemSize) |
2581 emit selectionChanged(); |
2619 emit selectionChanged(); |
2605 else |
2643 else |
2606 d->lastActivePanel = item; |
2644 d->lastActivePanel = item; |
2607 } |
2645 } |
2608 } |
2646 } |
2609 |
2647 |
2610 if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges) |
2648 if (item->d_ptr->flags & QGraphicsItem::ItemSendsScenePositionChanges) |
2611 d->registerScenePosItem(item); |
2649 d->registerScenePosItem(item); |
2612 |
2650 |
2613 // Ensure that newly added items that have subfocus set, gain |
2651 // Ensure that newly added items that have subfocus set, gain |
2614 // focus automatically if there isn't a focus item already. |
2652 // focus automatically if there isn't a focus item already. |
2615 if (!d->focusItem && item != d->lastFocusItem && item->focusItem() == item) |
2653 if (!d->focusItem && item != d->lastFocusItem && item->focusItem() == item) |
3752 #endif |
3790 #endif |
3753 } |
3791 } |
3754 |
3792 |
3755 bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const |
3793 bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const |
3756 { |
3794 { |
3757 return (!item->isBlockedByModalPanel() && |
3795 return (item->d_ptr->acceptsHover |
3758 (item->acceptHoverEvents() |
3796 || (item->d_ptr->isWidget |
3759 || (item->isWidget() |
3797 && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration())) |
3760 && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration()))); |
3798 && !item->isBlockedByModalPanel(); |
3761 } |
3799 } |
3762 |
3800 |
3763 /*! |
3801 /*! |
3764 This event handler, for event \a hoverEvent, can be reimplemented in a |
3802 This event handler, for event \a hoverEvent, can be reimplemented in a |
3765 subclass to receive hover enter events. The default implementation |
3803 subclass to receive hover enter events. The default implementation |
4245 pixmapPainter.end(); |
4283 pixmapPainter.end(); |
4246 |
4284 |
4247 if (!subPix.isNull()) { |
4285 if (!subPix.isNull()) { |
4248 // Blit the subpixmap into the main pixmap. |
4286 // Blit the subpixmap into the main pixmap. |
4249 pixmapPainter.begin(pix); |
4287 pixmapPainter.begin(pix); |
|
4288 pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source); |
4250 pixmapPainter.setClipRegion(pixmapExposed); |
4289 pixmapPainter.setClipRegion(pixmapExposed); |
4251 pixmapPainter.drawPixmap(br.topLeft(), subPix); |
4290 pixmapPainter.drawPixmap(br.topLeft(), subPix); |
4252 pixmapPainter.end(); |
4291 pixmapPainter.end(); |
4253 } |
4292 } |
4254 } |
4293 } |
4410 oldPainterOpacity != newPainterOpacity, painterStateProtection); |
4449 oldPainterOpacity != newPainterOpacity, painterStateProtection); |
4411 return; |
4450 return; |
4412 } |
4451 } |
4413 |
4452 |
4414 // 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. |
4415 bool pixModified = false; |
4456 bool pixModified = false; |
4416 QGraphicsItemCache::DeviceData *deviceData = &itemCache->deviceData[widget]; |
4457 QGraphicsItemCache::DeviceData *deviceData = &itemCache->deviceData[widget]; |
4417 bool invertable = true; |
4458 bool invertable = true; |
4418 QTransform diff = deviceData->lastTransform.inverted(&invertable); |
4459 QTransform diff = deviceData->lastTransform.inverted(&invertable); |
4419 if (invertable) |
4460 if (invertable) |
4420 diff *= painter->worldTransform(); |
4461 diff *= painter->worldTransform(); |
4421 deviceData->lastTransform = painter->worldTransform(); |
4462 deviceData->lastTransform = painter->worldTransform(); |
4422 if (!invertable || diff.type() > QTransform::TxTranslate) { |
4463 if (!invertable |
|
4464 || diff.type() > QTransform::TxTranslate |
|
4465 || painter->worldTransform().type() > QTransform::TxScale) { |
4423 pixModified = true; |
4466 pixModified = true; |
4424 itemCache->allExposed = true; |
4467 itemCache->allExposed = true; |
4425 itemCache->exposed.clear(); |
4468 itemCache->exposed.clear(); |
4426 pix = QPixmap(); |
4469 pix = QPixmap(); |
4427 } |
4470 } |
4568 { |
4611 { |
4569 // Make sure we don't have unpolished items before we draw. |
4612 // Make sure we don't have unpolished items before we draw. |
4570 if (!unpolishedItems.isEmpty()) |
4613 if (!unpolishedItems.isEmpty()) |
4571 _q_polishItems(); |
4614 _q_polishItems(); |
4572 |
4615 |
|
4616 updateAll = false; |
4573 QRectF exposedSceneRect; |
4617 QRectF exposedSceneRect; |
4574 if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) { |
4618 if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) { |
4575 exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1); |
4619 exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1); |
4576 if (viewTransform) |
4620 if (viewTransform) |
4577 exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect); |
4621 exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect); |
4595 const bool itemHasChildren = !item->d_ptr->children.isEmpty(); |
4639 const bool itemHasChildren = !item->d_ptr->children.isEmpty(); |
4596 if (!itemHasContents && !itemHasChildren) |
4640 if (!itemHasContents && !itemHasChildren) |
4597 return; // Item has neither contents nor children!(?) |
4641 return; // Item has neither contents nor children!(?) |
4598 |
4642 |
4599 const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity); |
4643 const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity); |
4600 const bool itemIsFullyTransparent = (opacity < 0.0001); |
4644 const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity); |
4601 if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) |
4645 if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) |
4602 return; |
4646 return; |
4603 |
4647 |
4604 QTransform transform(Qt::Uninitialized); |
4648 QTransform transform(Qt::Uninitialized); |
4605 QTransform *transformPtr = 0; |
4649 QTransform *transformPtr = 0; |
4638 QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect() |
4682 QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect() |
4639 : transformPtr->mapRect(brect).toRect(); |
4683 : transformPtr->mapRect(brect).toRect(); |
4640 if (widget) |
4684 if (widget) |
4641 item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); |
4685 item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); |
4642 viewBoundingRect.adjust(-1, -1, 1, 1); |
4686 viewBoundingRect.adjust(-1, -1, 1, 1); |
4643 drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.isEmpty(); |
4687 drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) |
|
4688 : !viewBoundingRect.normalized().isEmpty(); |
4644 if (!drawItem) { |
4689 if (!drawItem) { |
4645 if (!itemHasChildren) |
4690 if (!itemHasChildren) |
4646 return; |
4691 return; |
4647 if (itemClipsChildrenToShape) { |
4692 if (itemClipsChildrenToShape) { |
4648 if (wasDirtyParentSceneTransform) |
4693 if (wasDirtyParentSceneTransform) |
4672 painter->setOpacity(opacity); |
4717 painter->setOpacity(opacity); |
4673 |
4718 |
4674 if (sourced->currentCachedSystem() != Qt::LogicalCoordinates |
4719 if (sourced->currentCachedSystem() != Qt::LogicalCoordinates |
4675 && sourced->lastEffectTransform != painter->worldTransform()) |
4720 && sourced->lastEffectTransform != painter->worldTransform()) |
4676 { |
4721 { |
|
4722 if (sourced->lastEffectTransform.type() <= QTransform::TxTranslate |
|
4723 && painter->worldTransform().type() <= QTransform::TxTranslate) |
|
4724 { |
|
4725 QRectF sourceRect = sourced->boundingRect(Qt::DeviceCoordinates); |
|
4726 QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect); |
|
4727 |
|
4728 sourced->setCachedOffset(effectRect.topLeft()); |
|
4729 } else { |
|
4730 sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged); |
|
4731 } |
|
4732 |
4677 sourced->lastEffectTransform = painter->worldTransform(); |
4733 sourced->lastEffectTransform = painter->worldTransform(); |
4678 sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged); |
|
4679 } |
4734 } |
4680 |
4735 |
4681 item->d_ptr->graphicsEffect->draw(painter); |
4736 item->d_ptr->graphicsEffect->draw(painter); |
4682 painter->setWorldTransform(restoreTransform); |
4737 painter->setWorldTransform(restoreTransform); |
4683 sourced->info = 0; |
4738 sourced->info = 0; |
4692 void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform, |
4747 void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform, |
4693 const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget, |
4748 const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget, |
4694 qreal opacity, const QTransform *effectTransform, |
4749 qreal opacity, const QTransform *effectTransform, |
4695 bool wasDirtyParentSceneTransform, bool drawItem) |
4750 bool wasDirtyParentSceneTransform, bool drawItem) |
4696 { |
4751 { |
4697 const bool itemIsFullyTransparent = (opacity < 0.0001); |
4752 const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity); |
4698 const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); |
4753 const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); |
4699 const bool itemHasChildren = !item->d_ptr->children.isEmpty(); |
4754 const bool itemHasChildren = !item->d_ptr->children.isEmpty(); |
4700 |
4755 |
4701 int i = 0; |
4756 int i = 0; |
4702 if (itemHasChildren) { |
4757 if (itemHasChildren) { |
4707 Q_ASSERT(transformPtr); |
4762 Q_ASSERT(transformPtr); |
4708 if (effectTransform) |
4763 if (effectTransform) |
4709 painter->setWorldTransform(*transformPtr * *effectTransform); |
4764 painter->setWorldTransform(*transformPtr * *effectTransform); |
4710 else |
4765 else |
4711 painter->setWorldTransform(*transformPtr); |
4766 painter->setWorldTransform(*transformPtr); |
4712 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); |
4713 } |
4773 } |
4714 |
4774 |
4715 // Draw children behind |
4775 // Draw children behind |
4716 for (i = 0; i < item->d_ptr->children.size(); ++i) { |
4776 for (i = 0; i < item->d_ptr->children.size(); ++i) { |
4717 QGraphicsItem *child = item->d_ptr->children.at(i); |
4777 QGraphicsItem *child = item->d_ptr->children.at(i); |
4743 painter->setWorldTransform(*transformPtr * *effectTransform); |
4803 painter->setWorldTransform(*transformPtr * *effectTransform); |
4744 else |
4804 else |
4745 painter->setWorldTransform(*transformPtr); |
4805 painter->setWorldTransform(*transformPtr); |
4746 } |
4806 } |
4747 |
4807 |
4748 if (itemClipsToShape) |
4808 if (itemClipsToShape) { |
4749 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 } |
4750 painter->setOpacity(opacity); |
4816 painter->setOpacity(opacity); |
4751 |
4817 |
4752 if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget) |
4818 if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget) |
4753 item->paint(painter, &styleOptionTmp, widget); |
4819 item->paint(painter, &styleOptionTmp, widget); |
4754 else |
4820 else |
4774 if (itemHasChildren && itemClipsChildrenToShape) |
4840 if (itemHasChildren && itemClipsChildrenToShape) |
4775 painter->restore(); |
4841 painter->restore(); |
4776 } |
4842 } |
4777 |
4843 |
4778 void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren, |
4844 void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren, |
4779 bool force, bool ignoreOpacity, bool removingItemFromScene) |
4845 bool force, bool ignoreOpacity, bool removingItemFromScene, |
|
4846 bool updateBoundingRect) |
4780 { |
4847 { |
4781 Q_ASSERT(item); |
4848 Q_ASSERT(item); |
4782 if (updateAll) |
4849 if (updateAll) |
4783 return; |
4850 return; |
4784 |
4851 |
4845 if (force) |
4912 if (force) |
4846 item->d_ptr->ignoreVisible = 1; |
4913 item->d_ptr->ignoreVisible = 1; |
4847 if (ignoreOpacity) |
4914 if (ignoreOpacity) |
4848 item->d_ptr->ignoreOpacity = 1; |
4915 item->d_ptr->ignoreOpacity = 1; |
4849 |
4916 |
4850 QGraphicsItem *p = item->d_ptr->parent; |
4917 if (!updateBoundingRect) |
4851 while (p) { |
4918 item->d_ptr->markParentDirty(); |
4852 p->d_ptr->dirtyChildren = 1; |
|
4853 #ifndef QT_NO_GRAPHICSEFFECT |
|
4854 if (p->d_ptr->graphicsEffect && p->d_ptr->graphicsEffect->isEnabled()) { |
|
4855 p->d_ptr->dirty = 1; |
|
4856 p->d_ptr->fullUpdatePending = 1; |
|
4857 } |
|
4858 #endif //QT_NO_GRAPHICSEFFECT |
|
4859 p = p->d_ptr->parent; |
|
4860 } |
|
4861 } |
4919 } |
4862 |
4920 |
4863 static inline bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate *item, |
4921 static inline bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate *item, |
4864 const QRectF &rect, bool itemIsUntransformable) |
4922 const QRectF &rect, bool itemIsUntransformable) |
4865 { |
4923 { |
4930 if (item->d_ptr->graphicsEffect) |
4988 if (item->d_ptr->graphicsEffect) |
4931 itemHasContents = true; |
4989 itemHasContents = true; |
4932 } |
4990 } |
4933 |
4991 |
4934 const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity); |
4992 const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity); |
4935 const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity && opacity < 0.0001; |
4993 const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity |
|
4994 && QGraphicsItemPrivate::isOpacityNull(opacity); |
4936 if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) { |
4995 if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) { |
4937 resetDirtyItem(item, /*recursive=*/itemHasChildren); |
4996 resetDirtyItem(item, /*recursive=*/itemHasChildren); |
4938 return; |
4997 return; |
4939 } |
4998 } |
4940 |
4999 |
5065 |
5124 |
5066 resetDirtyItem(item); |
5125 resetDirtyItem(item); |
5067 } |
5126 } |
5068 |
5127 |
5069 /*! |
5128 /*! |
|
5129 \obsolete |
|
5130 |
5070 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 |
5071 background has been drawn, and before the foreground has been |
5132 background has been drawn, and before the foreground has been |
5072 drawn. All painting is done in \e scene coordinates. Before |
5133 drawn. All painting is done in \e scene coordinates. Before |
5073 drawing each item, the painter must be transformed using |
5134 drawing each item, the painter must be transformed using |
5074 QGraphicsItem::sceneTransform(). |
5135 QGraphicsItem::sceneTransform(). |
5087 |
5148 |
5088 Example: |
5149 Example: |
5089 |
5150 |
5090 \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0 |
5151 \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0 |
5091 |
5152 |
|
5153 Since Qt 4.6, this function is not called anymore unless |
|
5154 the QGraphicsView::IndirectPainting flag is given as an Optimization |
|
5155 flag. |
|
5156 |
5092 \sa drawBackground(), drawForeground() |
5157 \sa drawBackground(), drawForeground() |
5093 */ |
5158 */ |
5094 void QGraphicsScene::drawItems(QPainter *painter, |
5159 void QGraphicsScene::drawItems(QPainter *painter, |
5095 int numItems, |
5160 int numItems, |
5096 QGraphicsItem *items[], |
5161 QGraphicsItem *items[], |
5099 Q_D(QGraphicsScene); |
5164 Q_D(QGraphicsScene); |
5100 // Make sure we don't have unpolished items before we draw. |
5165 // Make sure we don't have unpolished items before we draw. |
5101 if (!d->unpolishedItems.isEmpty()) |
5166 if (!d->unpolishedItems.isEmpty()) |
5102 d->_q_polishItems(); |
5167 d->_q_polishItems(); |
5103 |
5168 |
|
5169 d->updateAll = false; |
5104 QTransform viewTransform = painter->worldTransform(); |
5170 QTransform viewTransform = painter->worldTransform(); |
5105 Q_UNUSED(options); |
5171 Q_UNUSED(options); |
5106 |
5172 |
5107 // Determine view, expose and flags. |
5173 // Determine view, expose and flags. |
5108 QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0; |
5174 QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0; |
5638 // if the TouchBegin handler recurses, we assume that means the event |
5704 // if the TouchBegin handler recurses, we assume that means the event |
5639 // has been implicitly accepted and continue to send touch events |
5705 // has been implicitly accepted and continue to send touch events |
5640 item->d_ptr->acceptedTouchBeginEvent = true; |
5706 item->d_ptr->acceptedTouchBeginEvent = true; |
5641 bool res = sendTouchBeginEvent(item, &touchEvent) |
5707 bool res = sendTouchBeginEvent(item, &touchEvent) |
5642 && touchEvent.isAccepted(); |
5708 && touchEvent.isAccepted(); |
5643 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 } |
5644 ignoreSceneTouchEvent = false; |
5716 ignoreSceneTouchEvent = false; |
|
5717 } |
5645 break; |
5718 break; |
5646 } |
5719 } |
5647 default: |
5720 default: |
5648 if (item->d_ptr->acceptedTouchBeginEvent) { |
5721 if (item->d_ptr->acceptedTouchBeginEvent) { |
5649 updateTouchPointsForItem(item, &touchEvent); |
5722 updateTouchPointsForItem(item, &touchEvent); |
5830 if (gesture->hasHotSpot()) { |
5903 if (gesture->hasHotSpot()) { |
5831 QPoint screenPos = gesture->hotSpot().toPoint(); |
5904 QPoint screenPos = gesture->hotSpot().toPoint(); |
5832 QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport); |
5905 QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport); |
5833 QList<QGraphicsObject *> result; |
5906 QList<QGraphicsObject *> result; |
5834 for (int j = 0; j < items.size(); ++j) { |
5907 for (int j = 0; j < items.size(); ++j) { |
5835 QGraphicsObject *item = items.at(j)->toGraphicsObject(); |
5908 QGraphicsItem *item = items.at(j); |
5836 if (!item) |
5909 |
5837 continue; |
5910 // Check if the item is blocked by a modal panel and use it as |
5838 QGraphicsItemPrivate *d = item->QGraphicsItem::d_func(); |
5911 // a target instead of this item. |
5839 if (d->gestureContext.contains(gestureType)) { |
5912 (void) item->isBlockedByModalPanel(&item); |
5840 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 } |
5841 } |
5919 } |
|
5920 // Don't propagate through panels. |
|
5921 if (item->isPanel()) |
|
5922 break; |
5842 } |
5923 } |
5843 DEBUG() << "QGraphicsScenePrivate::getGestureTargets:" |
5924 DEBUG() << "QGraphicsScenePrivate::getGestureTargets:" |
5844 << gesture << result; |
5925 << gesture << result; |
5845 if (result.size() == 1) { |
5926 if (result.size() == 1) { |
5846 normalGestures->insert(gesture, result.first()); |
5927 normalGestures->insert(gesture, result.first()); |