Changeset 561 for trunk/src/gui/graphicsview/qgraphicsitem.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/gui/graphicsview/qgraphicsitem.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtGui module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 45 45 items in a QGraphicsScene. 46 46 \since 4.2 47 \ingroup multimedia 47 48 48 \ingroup graphicsview-api 49 49 … … 53 53 QGraphicsItem is part of \l{The Graphics View Framework} 54 54 55 \im ggraphicsview-items.png55 \image graphicsview-items.png 56 56 57 57 For convenience, Qt provides a set of standard graphics items for the most … … 92 92 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 0 93 93 94 The boundingRect() function has many different purposes. QGraphicsScene 95 bases its item index on boundingRect(), and QGraphicsView uses it both for 96 culling invisible items, and for determining the area that needs to be 97 recomposed when drawing overlapping items. In addition, QGraphicsItem's 98 collision detection mechanisms use boundingRect() to provide an efficient 99 cut-off. The fine grained collision algorithm in collidesWithItem() is based 100 on calling shape(), which returns an accurate outline of the item's shape 101 as a QPainterPath. 102 103 QGraphicsScene expects all items boundingRect() and shape() to remain 104 unchanged unless it is notified. If you want to change an item's geometry 105 in any way, you must first call prepareGeometryChange() to allow 106 QGraphicsScene to update its bookkeeping. 94 The boundingRect() function has many different purposes. 95 QGraphicsScene bases its item index on boundingRect(), and 96 QGraphicsView uses it both for culling invisible items, and for 97 determining the area that needs to be recomposed when drawing 98 overlapping items. In addition, QGraphicsItem's collision 99 detection mechanisms use boundingRect() to provide an efficient 100 cut-off. The fine grained collision algorithm in 101 collidesWithItem() is based on calling shape(), which returns an 102 accurate outline of the item's shape as a QPainterPath. 103 104 QGraphicsScene expects all items boundingRect() and shape() to 105 remain unchanged unless it is notified. If you want to change an 106 item's geometry in any way, you must first call 107 prepareGeometryChange() to allow QGraphicsScene to update its 108 bookkeeping. 107 109 108 110 Collision detection can be done in two ways: … … 110 112 \list 1 111 113 112 \o Reimplement shape() to return an accurate shape for your item, and rely 113 on the default implementation of collidesWithItem() to do shape-shape 114 intersection. This can be rather expensive if the shapes are complex. 115 116 \o Reimplement collidesWithItem() to provide your own custom item and shape 117 collision algorithm. 114 \o Reimplement shape() to return an accurate shape for your item, 115 and rely on the default implementation of collidesWithItem() to do 116 shape-shape intersection. This can be rather expensive if the 117 shapes are complex. 118 119 \o Reimplement collidesWithItem() to provide your own custom item 120 and shape collision algorithm. 118 121 119 122 \endlist … … 131 134 \img graphicsview-parentchild.png 132 135 133 QGraphicsItem supports affine transformations in addition to its base 134 position, pos(). To change the item's transformation, you can either pass 135 a transformation matrix to setTransform(), or call one of the convenience 136 functions rotate(), scale(), translate(), or shear(). Item transformations 137 accumulate from parent to child, so if both a parent and child item are 138 rotated 90 degrees, the child's total transformation will be 180 degrees. 139 Similarly, if the item's parent is scaled to 2x its original size, its 140 children will also be twice as large. An item's transformation does not 141 affect its own local geometry; all geometry functions (e.g., contains(), 142 update(), and all the mapping functions) still operate in local 143 coordinates. For convenience, QGraphicsItem provides the functions 144 sceneTransform(), which returns the item's total transformation matrix 145 (including its position and all parents' positions and transformations), 146 and scenePos(), which returns its position in scene coordinates. To reset 147 an item's matrix, call resetTransform(). 136 \section1 Transformation 137 138 QGraphicsItem supports projective transformations in addition to its base 139 position, pos(). There are several ways to change an item's transformation. 140 For simple transformations, you can call either of the convenience 141 functions setRotation() or setScale(), or you can pass any transformation 142 matrix to setTransform(). For advanced transformation control you also have 143 the option of setting several combined transformations by calling 144 setTransformations(). 145 146 Item transformations accumulate from parent to child, so if both a parent 147 and child item are rotated 90 degrees, the child's total transformation 148 will be 180 degrees. Similarly, if the item's parent is scaled to 2x its 149 original size, its children will also be twice as large. An item's 150 transformation does not affect its own local geometry; all geometry 151 functions (e.g., contains(), update(), and all the mapping functions) still 152 operate in local coordinates. For convenience, QGraphicsItem provides the 153 functions sceneTransform(), which returns the item's total transformation 154 matrix (including its position and all parents' positions and 155 transformations), and scenePos(), which returns its position in scene 156 coordinates. To reset an item's matrix, call resetTransform(). 157 158 Certain transformation operations produce a different outcome depending on 159 the order in which they are applied. For example, if you scale an 160 transform, and then rotate it, you may get a different result than if the 161 transform was rotated first. However, the order you set the transformation 162 properties on QGraphicsItem does not affect the resulting transformation; 163 QGraphicsItem always applies the properties in a fixed, defined order: 164 165 \list 166 \o The item's base transform is applied (transform()) 167 \o The item's transformations list is applied in order (transformations()) 168 \o The item is rotated relative to its transform origin point (rotation(), transformOriginPoint()) 169 \o The item is scaled relative to its transform origin point (scale(), transformOriginPoint()) 170 \endlist 171 172 \section1 Painting 148 173 149 174 The paint() function is called by QGraphicsView to paint the item's … … 162 187 drawn before their children. 163 188 189 \section1 Sorting 190 191 All items are drawn in a defined, stable order, and this same order decides 192 which items will receive mouse input first when you click on the scene. 193 Normally you don't have to worry about sorting, as the items follow a 194 "natural order", following the logical structure of the scene. 195 196 An item's children are stacked on top of the parent, and sibling items are 197 stacked by insertion order (i.e., in the same order that they were either 198 added to the scene, or added to the same parent). If you add item A, and 199 then B, then B will be on top of A. If you then add C, the items' stacking 200 order will be A, then B, then C. 201 202 \image graphicsview-zorder.png 203 204 This example shows the stacking order of all limbs of the robot from the 205 \l{graphicsview/dragdroprobot}{Drag and Drop Robot} example. The torso is 206 the root item (all other items are children or descendants of the torso), 207 so it is drawn first. Next, the head is drawn, as it is the first item in 208 the torso's list of children. Then the upper left arm is drawn. As the 209 lower arm is a child of the upper arm, the lower arm is then drawn, 210 followed by the upper arm's next sibling, which is the upper right arm, and 211 so on. 212 213 For advanced users, there are ways to alter how your items are sorted: 214 215 \list 216 \o You can call setZValue() on an item to explicitly stack it on top of, or 217 under, other sibling items. The default Z value for an item is 0. Items 218 with the same Z value are stacked by insertion order. 219 220 \o You can call stackBefore() to reorder the list of children. This will 221 directly modify the insertion order. 222 223 \o You can set the ItemStacksBehindParent flag to stack a child item behind 224 its parent. 225 \endlist 226 227 The stacking order of two sibling items also counts for each item's 228 children and descendant items. So if one item is on top of another, then 229 all its children will also be on top of all the other item's children as 230 well. 231 232 \section1 Events 233 164 234 QGraphicsItem receives events from QGraphicsScene through the virtual 165 235 function sceneEvent(). This function distributes the most common events … … 172 242 hover enter, move and leave events 173 243 \o inputMethodEvent() handles input events, for accessibility support 174 \o keyPressEvent() and keyReleaseEvent handle key press and release events244 \o keyPressEvent() and keyReleaseEvent() handle key press and release events 175 245 \o mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(), and 176 246 mouseDoubleClickEvent() handles mouse press, move, release, click and … … 178 248 \endlist 179 249 180 You can filter events for any other item by installing event 181 filters. This functionaly is separate from from Qt's regular 182 event filters (see QObject::installEventFilter()), which only 183 work on subclasses of QObject. After installing your item as an 184 event filter for another item by calling 185 installSceneEventFilter(), the filtered events will be received 186 by the virtual function sceneEventFilter(). You can remove item 187 event filters by calling removeSceneEventFilter(). 250 You can filter events for any other item by installing event filters. This 251 functionality is separate from Qt's regular event filters (see 252 QObject::installEventFilter()), which only work on subclasses of QObject. After 253 installing your item as an event filter for another item by calling 254 installSceneEventFilter(), the filtered events will be received by the virtual 255 function sceneEventFilter(). You can remove item event filters by calling 256 removeSceneEventFilter(). 257 258 \section1 Custom Data 188 259 189 260 Sometimes it's useful to register custom data with an item, be it a custom … … 275 346 drop shadow effects and for decoration objects that follow the parent 276 347 item's geometry without drawing on top of it. 348 349 \value ItemUsesExtendedStyleOption The item makes use of either 350 \l{QStyleOptionGraphicsItem::}{exposedRect} or 351 \l{QStyleOptionGraphicsItem::}{matrix} in QStyleOptionGraphicsItem. By default, 352 the \l{QStyleOptionGraphicsItem::}{exposedRect} is initialized to the item's 353 boundingRect() and the \l{QStyleOptionGraphicsItem::}{matrix} is untransformed. 354 You can enable this flag for the style options to be set up with more 355 fine-grained values. 356 Note that QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag 357 and always initialized to 1. Use 358 QStyleOptionGraphicsItem::levelOfDetailFromTransform() if you need a higher 359 value. 360 361 \value ItemHasNoContents The item does not paint anything (i.e., calling 362 paint() on the item has no effect). You should set this flag on items that 363 do not need to be painted to ensure that Graphics View avoids unnecessary 364 painting preparations. This flag was introduced in Qt 4.6. 365 366 \value ItemSendsGeometryChanges The item enables itemChange() 367 notifications for ItemPositionChange, ItemPositionHasChanged, 368 ItemMatrixChange, ItemTransformChange, and ItemTransformHasChanged. For 369 performance reasons, these notifications are disabled by default. You must 370 enable this flag to receive notifications for position and transform 371 changes. This flag was introduced in Qt 4.6. 372 373 \value ItemAcceptsInputMethod The item supports input methods typically 374 used for Asian languages. 375 This flag was introduced in Qt 4.6. 376 377 \value ItemNegativeZStacksBehindParent The item automatically stacks behind 378 it's parent if it's z-value is negative. This flag enables setZValue() to 379 toggle ItemStacksBehindParent. 380 381 \value ItemIsPanel The item is a panel. A panel provides activation and 382 contained focus handling. Only one panel can be active at a time (see 383 QGraphicsItem::isActive()). When no panel is active, QGraphicsScene 384 activates all non-panel items. Window items (i.e., 385 QGraphicsItem::isWindow() returns true) are panels. This flag was 386 introduced in Qt 4.6. 387 388 \omitvalue ItemIsFocusScope \omit Internal only (for now). \endomit 389 390 \value ItemSendsScenePositionChanges The item enables itemChange() 391 notifications for ItemScenePositionHasChanged. For performance reasons, 392 these notifications are disabled by default. You must enable this flag 393 to receive notifications for scene position changes. This flag was 394 introduced in Qt 4.6. 277 395 */ 278 396 … … 313 431 314 432 \value ItemPositionChange The item's position changes. This notification 315 is only sent when the item's local position changes, relative to its316 parent, has changed (i.e., as a result of calling setPos() or317 moveBy()). The value argument is the new position (i.e., a QPointF). You318 can call pos() to get the original position. Do not call setPos() or319 moveBy() in itemChange() as this notification is delivered; instead, you320 can return the new, adjusted position from itemChange(). After this321 notification, QGraphicsItem immediately sends the ItemPositionHasChanged322 notification if the position changed.433 is sent if the ItemSendsGeometryChanges flag is enabled, and when the 434 item's local position changes, relative to its parent (i.e., as a result 435 of calling setPos() or moveBy()). The value argument is the new position 436 (i.e., a QPointF). You can call pos() to get the original position. Do 437 not call setPos() or moveBy() in itemChange() as this notification is 438 delivered; instead, you can return the new, adjusted position from 439 itemChange(). After this notification, QGraphicsItem immediately sends the 440 ItemPositionHasChanged notification if the position changed. 323 441 324 442 \value ItemPositionHasChanged The item's position has changed. This 325 notification is only sent after the item's local position, relative to its 326 parent, has changed. The value argument is the new position (the same as 327 pos()), and QGraphicsItem ignores the return value for this notification 328 (i.e., a read-only notification). 443 notification is sent if the ItemSendsGeometryChanges flag is enabled, and 444 after the item's local position, relative to its parent, has changed. The 445 value argument is the new position (the same as pos()), and QGraphicsItem 446 ignores the return value for this notification (i.e., a read-only 447 notification). 329 448 330 449 \value ItemTransformChange The item's transformation matrix changes. This 331 notification is only sent when the item's local transformation matrix 332 changes (i.e., as a result of calling setTransform(), or one of the 333 convenience transformation functions, such as rotate()). The value 334 argument is the new matrix (i.e., a QTransform); to get the old matrix, 335 call transform(). Do not call setTransform() or any of the transformation 336 convenience functions in itemChange() as this notification is delivered; 337 instead, you can return the new matrix from itemChange(). 450 notification is send if the ItemSendsGeometryChanges flag is enabled, and 451 when the item's local transformation matrix changes (i.e., as a result of 452 calling setTransform(). The value argument is the new matrix (i.e., a 453 QTransform); to get the old matrix, call transform(). Do not call 454 setTransform() or set any of the transformation properties in itemChange() 455 as this notification is delivered; instead, you can return the new matrix 456 from itemChange(). This notification is not sent if you change the 457 transformation properties. 338 458 339 459 \value ItemTransformHasChanged The item's transformation matrix has 340 changed. This notification is only sent after the item's local 341 trasformation matrix has changed. The value argument is the new matrix 460 changed either because setTransform is called, or one of the 461 transformation properties is changed. This notification is sent if the 462 ItemSendsGeometryChanges flag is enabled, and after the item's local 463 transformation matrix has changed. The value argument is the new matrix 342 464 (same as transform()), and QGraphicsItem ignores the return value for this 343 465 notification (i.e., a read-only notification). 344 466 345 \value ItemSelectedChange The item's selected state changes. If the item 346 is presently selected, it will become unselected, and vice verca. The347 value argument is the new selected state (i.e., true or false). Do not348 call setSelected() in itemChange() as this notification is delivered();349 instead, youcan return the new selected state from itemChange().467 \value ItemSelectedChange The item's selected state changes. If the item is 468 presently selected, it will become unselected, and vice verca. The value 469 argument is the new selected state (i.e., true or false). Do not call 470 setSelected() in itemChange() as this notification is delivered; instead, you 471 can return the new selected state from itemChange(). 350 472 351 473 \value ItemSelectedHasChanged The item's selected state has changed. The … … 447 569 argument is the new opacity (i.e., a double). Do not call setOpacity() as 448 570 this notification is delivered. The return value is ignored. 571 572 \value ItemScenePositionHasChanged The item's scene position has changed. 573 This notification is sent if the ItemSendsScenePositionChanges flag is 574 enabled, and after the item's scene position has changed (i.e., the 575 position or transformation of the item itself or the position or 576 transformation of any ancestor has changed). The value argument is the 577 new scene position (the same as scenePos()), and QGraphicsItem ignores 578 the return value for this notification (i.e., a read-only notification). 449 579 */ 450 580 … … 492 622 */ 493 623 624 /*! 625 \enum QGraphicsItem::PanelModality 626 \since 4.6 627 628 This enum specifies the behavior of a modal panel. A modal panel 629 is one that blocks input to other panels. Note that items that 630 are children of a modal panel are not blocked. 631 632 The values are: 633 \value NonModal The panel is not modal and does not block input to other panels. 634 \value PanelModal The panel is modal to a single item hierarchy and blocks input to its parent pane, all grandparent panels, and all siblings of its parent and grandparent panels. 635 \value SceneModal The window is modal to the entire scene and blocks input to all panels. 636 637 \sa QGraphicsItem::setPanelModality(), QGraphicsItem::panelModality(), QGraphicsItem::ItemIsPanel 638 */ 639 494 640 #include "qgraphicsitem.h" 495 641 … … 502 648 #include "qgraphicswidget.h" 503 649 #include "qgraphicsproxywidget.h" 650 #include "qgraphicsscenebsptreeindex_p.h" 504 651 #include <QtCore/qbitarray.h> 505 652 #include <QtCore/qdebug.h> … … 516 663 #include <QtGui/qstyleoption.h> 517 664 #include <QtGui/qevent.h> 665 #include <QtGui/qinputcontext.h> 666 #include <QtGui/qgraphicseffect.h> 518 667 519 668 #include <private/qgraphicsitem_p.h> … … 522 671 #include <private/qtextdocumentlayout_p.h> 523 672 #include <private/qtextengine_p.h> 673 #include <private/qwidget_p.h> 674 675 #ifdef Q_WS_X11 676 #include <private/qt_x11_p.h> 677 #include <private/qpixmap_x11_p.h> 678 #endif 679 680 #include <private/qgesturemanager_p.h> 524 681 525 682 #include <math.h> 526 683 527 684 QT_BEGIN_NAMESPACE 528 529 // QRectF::intersects() returns false always if either the source or target530 // rectangle's width or height are 0. This works around that problem.531 static inline void _q_adjustRect(QRectF *rect)532 {533 Q_ASSERT(rect);534 if (!rect->width())535 rect->adjust(-0.00001, 0, 0.00001, 0);536 if (!rect->height())537 rect->adjust(0, -0.00001, 0, 0.00001);538 }539 685 540 686 static inline void _q_adjustRect(QRect *rect) … … 556 702 }; 557 703 Q_GLOBAL_STATIC(QGraphicsItemCustomDataStore, qt_dataStore) 558 559 /*!560 \internal561 562 Removes the first instance of \a child from \a children. This is a563 heuristic approach that assumes that it's common to remove items from the564 start or end of the list.565 */566 static void qt_graphicsitem_removeChild(QGraphicsItem *child, QList<QGraphicsItem *> *children)567 {568 const int n = children->size();569 for (int i = 0; i < (n + 1) / 2; ++i) {570 if (children->at(i) == child) {571 children->removeAt(i);572 return;573 }574 int j = n - i - 1;575 if (children->at(j) == child) {576 children->removeAt(j);577 return;578 }579 }580 }581 704 582 705 /*! … … 622 745 // disabled \a childFlag, or has been reparented. 623 746 switch (int(childFlag)) { 747 case -2: 748 flag = AncestorFiltersChildEvents; 749 enabled = q->filtersChildEvents(); 750 break; 624 751 case -1: 625 752 flag = AncestorHandlesChildEvents; … … 629 756 flag = AncestorClipsChildren; 630 757 enabled = flags & QGraphicsItem::ItemClipsChildrenToShape; 631 invalidateCachedClipPathRecursively(/*childrenOnly=*/true);632 758 break; 633 759 case QGraphicsItem::ItemIgnoresTransformations: … … 639 765 } 640 766 641 // Inherit the enabled-state from our parents. 642 if ((parent && ((parent->d_ptr->ancestorFlags & flag) 643 || (int(parent->d_ptr->flags & childFlag) == childFlag) 644 || (childFlag == -1 && parent->d_ptr->handlesChildEvents)))) { 645 enabled = true; 646 ancestorFlags |= flag; 767 if (parent) { 768 // Inherit the enabled-state from our parents. 769 if ((parent->d_ptr->ancestorFlags & flag) 770 || (int(parent->d_ptr->flags & childFlag) == childFlag) 771 || (childFlag == -1 && parent->d_ptr->handlesChildEvents) 772 || (childFlag == -2 && parent->d_ptr->filtersDescendantEvents)) { 773 enabled = true; 774 ancestorFlags |= flag; 775 } else { 776 ancestorFlags &= ~flag; 777 } 778 } else { 779 // Top-level root items don't have any ancestors, so there are no 780 // ancestor flags either. 781 ancestorFlags = 0; 647 782 } 648 649 // Top-level root items don't have any ancestors, so there are no650 // ancestor flags either.651 if (!parent)652 ancestorFlags = 0;653 783 } else { 654 784 // Don't set or propagate the ancestor flag if it's already correct. … … 663 793 664 794 // Don't process children if the item has the main flag set on itself. 665 if ((childFlag != -1 && int(flags & childFlag) == childFlag) || (int(childFlag) == -1 && handlesChildEvents)) 795 if ((childFlag != -1 && int(flags & childFlag) == childFlag) 796 || (int(childFlag) == -1 && handlesChildEvents) 797 || (int(childFlag) == -2 && filtersDescendantEvents)) 666 798 return; 667 799 } … … 755 887 \internal 756 888 757 Returns true if this item or any of its ancestors are untransformable. 758 */ 759 bool QGraphicsItemPrivate::itemIsUntransformable() const 760 { 761 return (flags & QGraphicsItem::ItemIgnoresTransformations) 762 || (ancestorFlags & AncestorIgnoresTransformations); 889 Combines this item's position and transform onto \a transform. 890 891 If you need to change this function (e.g., adding more transformation 892 modes / options), make sure to change all places marked with COMBINE. 893 */ 894 void QGraphicsItemPrivate::combineTransformToParent(QTransform *x, const QTransform *viewTransform) const 895 { 896 // COMBINE 897 if (viewTransform && itemIsUntransformable()) { 898 *x = q_ptr->deviceTransform(*viewTransform); 899 } else { 900 if (transformData) 901 *x *= transformData->computedFullTransform(); 902 if (!pos.isNull()) 903 *x *= QTransform::fromTranslate(pos.x(), pos.y()); 904 } 905 } 906 907 /*! 908 \internal 909 910 Combines this item's position and transform onto \a transform. 911 912 If you need to change this function (e.g., adding more transformation 913 modes / options), make sure to change QGraphicsItem::deviceTransform() as 914 well. 915 */ 916 void QGraphicsItemPrivate::combineTransformFromParent(QTransform *x, const QTransform *viewTransform) const 917 { 918 // COMBINE 919 if (viewTransform && itemIsUntransformable()) { 920 *x = q_ptr->deviceTransform(*viewTransform); 921 } else { 922 x->translate(pos.x(), pos.y()); 923 if (transformData) 924 *x = transformData->computedFullTransform(x); 925 } 926 } 927 928 void QGraphicsItemPrivate::updateSceneTransformFromParent() 929 { 930 if (parent) { 931 Q_ASSERT(!parent->d_ptr->dirtySceneTransform); 932 if (parent->d_ptr->sceneTransformTranslateOnly) { 933 sceneTransform = QTransform::fromTranslate(parent->d_ptr->sceneTransform.dx() + pos.x(), 934 parent->d_ptr->sceneTransform.dy() + pos.y()); 935 } else { 936 sceneTransform = parent->d_ptr->sceneTransform; 937 sceneTransform.translate(pos.x(), pos.y()); 938 } 939 if (transformData) { 940 sceneTransform = transformData->computedFullTransform(&sceneTransform); 941 sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate); 942 } else { 943 sceneTransformTranslateOnly = parent->d_ptr->sceneTransformTranslateOnly; 944 } 945 } else if (!transformData) { 946 sceneTransform = QTransform::fromTranslate(pos.x(), pos.y()); 947 sceneTransformTranslateOnly = 1; 948 } else if (transformData->onlyTransform) { 949 sceneTransform = transformData->transform; 950 if (!pos.isNull()) 951 sceneTransform *= QTransform::fromTranslate(pos.x(), pos.y()); 952 sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate); 953 } else if (pos.isNull()) { 954 sceneTransform = transformData->computedFullTransform(); 955 sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate); 956 } else { 957 sceneTransform = QTransform::fromTranslate(pos.x(), pos.y()); 958 sceneTransform = transformData->computedFullTransform(&sceneTransform); 959 sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate); 960 } 961 dirtySceneTransform = 0; 763 962 } 764 963 … … 782 981 \internal 783 982 983 Make sure not to trigger any pure virtual function calls (e.g., 984 prepareGeometryChange) if the item is in its destructor, i.e. 985 inDestructor is 1. 986 */ 987 void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent) 988 { 989 Q_Q(QGraphicsItem); 990 if (newParent == q) { 991 qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this); 992 return; 993 } 994 if (newParent == parent) 995 return; 996 997 const QVariant newParentVariant(q->itemChange(QGraphicsItem::ItemParentChange, 998 qVariantFromValue<QGraphicsItem *>(newParent))); 999 newParent = qVariantValue<QGraphicsItem *>(newParentVariant); 1000 if (newParent == parent) 1001 return; 1002 1003 if (scene) { 1004 // Deliver the change to the index 1005 scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParentVariant); 1006 1007 // Disable scene pos notifications for old ancestors 1008 if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges)) 1009 scene->d_func()->setScenePosItemEnabled(q, false); 1010 } 1011 1012 if (subFocusItem && parent) { 1013 // Make sure none of the old parents point to this guy. 1014 subFocusItem->d_ptr->clearSubFocus(parent); 1015 } 1016 1017 // We anticipate geometry changes. If the item is deleted, it will be 1018 // removed from the index at a later stage, and the whole scene will be 1019 // updated. 1020 if (!inDestructor) 1021 q_ptr->prepareGeometryChange(); 1022 1023 const QVariant thisPointerVariant(qVariantFromValue<QGraphicsItem *>(q)); 1024 if (parent) { 1025 // Remove from current parent 1026 parent->d_ptr->removeChild(q); 1027 parent->itemChange(QGraphicsItem::ItemChildRemovedChange, thisPointerVariant); 1028 } 1029 1030 // Update toplevelitem list. If this item is being deleted, its parent 1031 // will be 0 but we don't want to register/unregister it in the TLI list. 1032 if (scene && !inDestructor) { 1033 if (parent && !newParent) { 1034 scene->d_func()->registerTopLevelItem(q); 1035 } else if (!parent && newParent) { 1036 scene->d_func()->unregisterTopLevelItem(q); 1037 } 1038 } 1039 1040 // Ensure any last parent focus scope does not point to this item or any of 1041 // its descendents. 1042 QGraphicsItem *p = parent; 1043 QGraphicsItem *parentFocusScopeItem = 0; 1044 while (p) { 1045 if (p->flags() & QGraphicsItem::ItemIsFocusScope) { 1046 // If this item's focus scope's focus scope item points 1047 // to this item or a descendent, then clear it. 1048 QGraphicsItem *fsi = p->d_ptr->focusScopeItem; 1049 if (q_ptr == fsi || q_ptr->isAncestorOf(fsi)) { 1050 parentFocusScopeItem = fsi; 1051 p->d_ptr->focusScopeItem = 0; 1052 } 1053 break; 1054 } 1055 p = p->d_ptr->parent; 1056 } 1057 1058 // Update focus scope item ptr in new scope. 1059 QGraphicsItem *newFocusScopeItem = subFocusItem ? subFocusItem : parentFocusScopeItem; 1060 if (newFocusScopeItem && newParent) { 1061 if (subFocusItem) { 1062 // Find the subFocusItem's topmost focus scope. 1063 QGraphicsItem *ancestorScope = 0; 1064 QGraphicsItem *p = subFocusItem->d_ptr->parent; 1065 while (p) { 1066 if (p->flags() & QGraphicsItem::ItemIsFocusScope) 1067 ancestorScope = p; 1068 if (p->isPanel()) 1069 break; 1070 p = p->parentItem(); 1071 } 1072 if (ancestorScope) 1073 newFocusScopeItem = ancestorScope; 1074 } 1075 1076 QGraphicsItem *p = newParent; 1077 while (p) { 1078 if (p->flags() & QGraphicsItem::ItemIsFocusScope) { 1079 p->d_ptr->focusScopeItem = newFocusScopeItem; 1080 // Ensure the new item is no longer the subFocusItem. The 1081 // only way to set focus on a child of a focus scope is 1082 // by setting focus on the scope itself. 1083 if (subFocusItem && !p->focusItem()) 1084 subFocusItem->d_ptr->clearSubFocus(); 1085 break; 1086 } 1087 p = p->d_ptr->parent; 1088 } 1089 } 1090 1091 if ((parent = newParent)) { 1092 bool implicitUpdate = false; 1093 if (parent->d_func()->scene && parent->d_func()->scene != scene) { 1094 // Move this item to its new parent's scene 1095 parent->d_func()->scene->addItem(q); 1096 implicitUpdate = true; 1097 } else if (!parent->d_func()->scene && scene) { 1098 // Remove this item from its former scene 1099 scene->removeItem(q); 1100 } 1101 1102 parent->d_ptr->addChild(q); 1103 parent->itemChange(QGraphicsItem::ItemChildAddedChange, thisPointerVariant); 1104 if (scene) { 1105 if (!implicitUpdate) 1106 scene->d_func()->markDirty(q_ptr); 1107 1108 // Re-enable scene pos notifications for new ancestors 1109 if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges)) 1110 scene->d_func()->setScenePosItemEnabled(q, true); 1111 } 1112 1113 // Inherit ancestor flags from the new parent. 1114 updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2)); 1115 updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1)); 1116 updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape); 1117 updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations); 1118 1119 // Update item visible / enabled. 1120 if (parent->isVisible() != visible) { 1121 if (!parent->isVisible() || !explicitlyHidden) 1122 setVisibleHelper(parent->isVisible(), /* explicit = */ false, /* update = */ !implicitUpdate); 1123 } 1124 if (parent->isEnabled() != enabled) { 1125 if (!parent->isEnabled() || !explicitlyDisabled) 1126 setEnabledHelper(parent->isEnabled(), /* explicit = */ false, /* update = */ !implicitUpdate); 1127 } 1128 1129 // Auto-activate if visible and the parent is active. 1130 if (q->isVisible() && parent->isActive()) 1131 q->setActive(true); 1132 } else { 1133 // Inherit ancestor flags from the new parent. 1134 updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2)); 1135 updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1)); 1136 updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape); 1137 updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations); 1138 1139 if (!inDestructor) { 1140 // Update item visible / enabled. 1141 if (!visible && !explicitlyHidden) 1142 setVisibleHelper(true, /* explicit = */ false); 1143 if (!enabled && !explicitlyDisabled) 1144 setEnabledHelper(true, /* explicit = */ false); 1145 1146 // If the item is being deleted, the whole scene will be updated. 1147 if (scene) 1148 scene->d_func()->markDirty(q_ptr); 1149 } 1150 } 1151 1152 // Resolve depth. 1153 invalidateDepthRecursively(); 1154 dirtySceneTransform = 1; 1155 1156 // Restore the sub focus chain. 1157 if (subFocusItem) { 1158 subFocusItem->d_ptr->setSubFocus(newParent); 1159 if (parent && parent->isActive()) 1160 subFocusItem->setFocus(); 1161 } 1162 1163 // Deliver post-change notification 1164 q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant); 1165 1166 if (isObject) 1167 emit static_cast<QGraphicsObject *>(q)->parentChanged(); 1168 } 1169 1170 /*! 1171 \internal 1172 1173 Returns the bounding rect of this item's children (excluding itself). 1174 */ 1175 void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rect) 1176 { 1177 for (int i = 0; i < children.size(); ++i) { 1178 QGraphicsItem *child = children.at(i); 1179 QGraphicsItemPrivate *childd = child->d_ptr.data(); 1180 bool hasPos = !childd->pos.isNull(); 1181 if (hasPos || childd->transformData) { 1182 // COMBINE 1183 QTransform matrix = childd->transformToParent(); 1184 if (x) 1185 matrix *= *x; 1186 *rect |= matrix.mapRect(child->boundingRect()); 1187 if (!childd->children.isEmpty()) 1188 childd->childrenBoundingRectHelper(&matrix, rect); 1189 } else { 1190 if (x) 1191 *rect |= x->mapRect(child->boundingRect()); 1192 else 1193 *rect |= child->boundingRect(); 1194 if (!childd->children.isEmpty()) 1195 childd->childrenBoundingRectHelper(x, rect); 1196 } 1197 } 1198 } 1199 1200 void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform, 1201 const QRegion &exposedRegion, bool allItems) const 1202 { 1203 Q_ASSERT(option); 1204 Q_Q(const QGraphicsItem); 1205 1206 // Initialize standard QStyleOption values. 1207 const QRectF brect = q->boundingRect(); 1208 option->state = QStyle::State_None; 1209 option->rect = brect.toRect(); 1210 option->levelOfDetail = 1; 1211 option->exposedRect = brect; 1212 if (selected) 1213 option->state |= QStyle::State_Selected; 1214 if (enabled) 1215 option->state |= QStyle::State_Enabled; 1216 if (q->hasFocus()) 1217 option->state |= QStyle::State_HasFocus; 1218 if (scene) { 1219 if (scene->d_func()->hoverItems.contains(q_ptr)) 1220 option->state |= QStyle::State_MouseOver; 1221 if (q == scene->mouseGrabberItem()) 1222 option->state |= QStyle::State_Sunken; 1223 } 1224 1225 if (!(flags & QGraphicsItem::ItemUsesExtendedStyleOption)) 1226 return; 1227 1228 // Initialize QStyleOptionGraphicsItem specific values (matrix, exposedRect). 1229 option->matrix = worldTransform.toAffine(); //### discards perspective 1230 1231 if (!allItems) { 1232 // Determine the item's exposed area 1233 option->exposedRect = QRectF(); 1234 const QTransform reverseMap = worldTransform.inverted(); 1235 const QVector<QRect> exposedRects(exposedRegion.rects()); 1236 for (int i = 0; i < exposedRects.size(); ++i) { 1237 option->exposedRect |= reverseMap.mapRect(QRectF(exposedRects.at(i))); 1238 if (option->exposedRect.contains(brect)) 1239 break; 1240 } 1241 option->exposedRect &= brect; 1242 } 1243 } 1244 1245 /*! 1246 \internal 1247 784 1248 Empty all cached pixmaps from the pixmap cache. 785 1249 */ … … 787 1251 { 788 1252 QPixmapCache::remove(key); 1253 key = QPixmapCache::Key(); 789 1254 QMutableMapIterator<QPaintDevice *, DeviceData> it(deviceData); 790 1255 while (it.hasNext()) { … … 799 1264 800 1265 /*! 801 Constructs a QGraphicsItem with the given \a parent. 1266 Constructs a QGraphicsItem with the given \a parent item. 1267 It does not modify the parent object returned by QObject::parent(). 802 1268 803 1269 If \a parent is 0, you can add the item to a scene by calling … … 851 1317 associated with a scene, the item will be removed from the scene before it 852 1318 is deleted. 1319 1320 \note It is more efficient to remove the item from the QGraphicsScene before 1321 destroying the item. 853 1322 */ 854 1323 QGraphicsItem::~QGraphicsItem() 855 1324 { 1325 if (d_ptr->isObject) 1326 QObjectPrivate::get(static_cast<QGraphicsObject *>(this))->wasDeleted = true; 1327 d_ptr->inDestructor = 1; 1328 d_ptr->removeExtraItemCache(); 1329 856 1330 clearFocus(); 857 d_ptr->removeExtraItemCache(); 858 859 QVariant variant; 860 foreach (QGraphicsItem *child, d_ptr->children) { 861 if (QGraphicsItem *parent = child->parentItem()) { 862 qVariantSetValue<QGraphicsItem *>(variant, child); 863 parent->itemChange(ItemChildRemovedChange, variant); 1331 1332 // Update focus scope item ptr. 1333 QGraphicsItem *p = d_ptr->parent; 1334 while (p) { 1335 if (p->flags() & ItemIsFocusScope) { 1336 if (p->d_ptr->focusScopeItem == this) 1337 p->d_ptr->focusScopeItem = 0; 1338 break; 864 1339 } 865 delete child; 866 } 867 d_ptr->children.clear(); 868 869 if (QGraphicsItem *parent = parentItem()) { 870 qVariantSetValue<QGraphicsItem *>(variant, this); 871 parent->itemChange(ItemChildRemovedChange, variant); 872 qt_graphicsitem_removeChild(this, &parent->d_func()->children); 873 } 874 if (d_ptr->scene) 875 d_ptr->scene->d_func()->_q_removeItemLater(this); 876 877 delete d_ptr; 1340 p = p->d_ptr->parent; 1341 } 1342 1343 if (!d_ptr->children.isEmpty()) { 1344 while (!d_ptr->children.isEmpty()) 1345 delete d_ptr->children.first(); 1346 Q_ASSERT(d_ptr->children.isEmpty()); 1347 } 1348 1349 if (d_ptr->scene) { 1350 d_ptr->scene->d_func()->removeItemHelper(this); 1351 } else { 1352 d_ptr->resetFocusProxy(); 1353 d_ptr->setParentItemHelper(0); 1354 } 1355 1356 #ifndef QT_NO_GRAPHICSEFFECT 1357 delete d_ptr->graphicsEffect; 1358 #endif //QT_NO_GRAPHICSEFFECT 1359 if (d_ptr->transformData) { 1360 for(int i = 0; i < d_ptr->transformData->graphicsTransforms.size(); ++i) { 1361 QGraphicsTransform *t = d_ptr->transformData->graphicsTransforms.at(i); 1362 static_cast<QGraphicsTransformPrivate *>(t->d_ptr.data())->item = 0; 1363 delete t; 1364 } 1365 } 1366 delete d_ptr->transformData; 878 1367 879 1368 qt_dataStore()->data.remove(this); … … 932 1421 parent, 0 is returned. 933 1422 934 \sa setParentItem(), child ren()1423 \sa setParentItem(), childItems() 935 1424 */ 936 1425 QGraphicsItem *QGraphicsItem::parentItem() const … … 955 1444 956 1445 /*! 1446 \since 4.6 1447 1448 Returns a pointer to the item's parent, cast to a QGraphicsObject. returns 0 if the parent item 1449 is not a QGraphicsObject. 1450 1451 \sa parentItem(), childItems() 1452 */ 1453 QGraphicsObject *QGraphicsItem::parentObject() const 1454 { 1455 QGraphicsItem *p = d_ptr->parent; 1456 return (p && p->d_ptr->isObject) ? static_cast<QGraphicsObject *>(p) : 0; 1457 } 1458 1459 /*! 957 1460 \since 4.4 958 1461 … … 996 1499 QGraphicsWidget *QGraphicsItem::window() const 997 1500 { 998 if (isWidget() && static_cast<const QGraphicsWidget *>(this)->isWindow()) 999 return static_cast<QGraphicsWidget *>(const_cast<QGraphicsItem *>(this)); 1000 if (QGraphicsWidget *parent = parentWidget()) 1001 return parent->window(); 1501 QGraphicsItem *p = panel(); 1502 if (p && p->isWindow()) 1503 return static_cast<QGraphicsWidget *>(p); 1002 1504 return 0; 1505 } 1506 1507 /*! 1508 \since 4.6 1509 1510 Returns the item's panel, or 0 if this item does not have a panel. If the 1511 item is a panel, it will return itself. Otherwise it will return the 1512 closest ancestor that is a panel. 1513 1514 \sa isPanel(), ItemIsPanel 1515 */ 1516 QGraphicsItem *QGraphicsItem::panel() const 1517 { 1518 if (d_ptr->flags & ItemIsPanel) 1519 return const_cast<QGraphicsItem *>(this); 1520 return d_ptr->parent ? d_ptr->parent->panel() : 0; 1521 } 1522 1523 /*! 1524 \since 4.6 1525 1526 Return the graphics item cast to a QGraphicsObject, if the class is actually a 1527 graphics object, 0 otherwise. 1528 */ 1529 QGraphicsObject *QGraphicsItem::toGraphicsObject() 1530 { 1531 return d_ptr->isObject ? static_cast<QGraphicsObject *>(this) : 0; 1532 } 1533 1534 /*! 1535 \since 4.6 1536 1537 Return the graphics item cast to a QGraphicsObject, if the class is actually a 1538 graphics object, 0 otherwise. 1539 */ 1540 const QGraphicsObject *QGraphicsItem::toGraphicsObject() const 1541 { 1542 return d_ptr->isObject ? static_cast<const QGraphicsObject *>(this) : 0; 1003 1543 } 1004 1544 … … 1012 1552 item to the scene yourself. 1013 1553 1014 \sa parentItem(), children() 1554 Calling this function on an item that is an ancestor of \a parent have undefined behaviour. 1555 1556 \sa parentItem(), childItems() 1015 1557 */ 1016 1558 void QGraphicsItem::setParentItem(QGraphicsItem *parent) 1017 1559 { 1018 if (parent == this) { 1019 qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this); 1020 return; 1021 } 1022 if (parent == d_ptr->parent) 1023 return; 1024 const QVariant newParentVariant(itemChange(ItemParentChange, qVariantFromValue<QGraphicsItem *>(parent))); 1025 parent = qVariantValue<QGraphicsItem *>(newParentVariant); 1026 if (parent == d_ptr->parent) 1027 return; 1028 1029 if (QGraphicsWidget *w = d_ptr->isWidget ? static_cast<QGraphicsWidget *>(this) : parentWidget()) { 1030 // Update the child focus chain; when reparenting a widget that has a 1031 // focus child, ensure that that focus child clears its focus child 1032 // chain from our parents before it's reparented. 1033 if (QGraphicsWidget *focusChild = w->focusWidget()) 1034 focusChild->clearFocus(); 1035 } 1036 1037 // We anticipate geometry changes 1038 prepareGeometryChange(); 1039 1040 const QVariant thisPointerVariant(qVariantFromValue<QGraphicsItem *>(this)); 1041 if (d_ptr->parent) { 1042 // Remove from current parent 1043 qt_graphicsitem_removeChild(this, &d_ptr->parent->d_func()->children); 1044 d_ptr->parent->itemChange(ItemChildRemovedChange, thisPointerVariant); 1045 } 1046 1047 if ((d_ptr->parent = parent)) { 1048 bool implicitUpdate = false; 1049 if (parent->d_func()->scene && parent->d_func()->scene != d_ptr->scene) { 1050 // Move this item to its new parent's scene 1051 parent->d_func()->scene->addItem(this); 1052 implicitUpdate = true; 1053 } else if (!parent->d_func()->scene && d_ptr->scene) { 1054 // Remove this item from its former scene 1055 d_ptr->scene->removeItem(this); 1056 } 1057 1058 d_ptr->parent->d_func()->children << this; 1059 d_ptr->parent->itemChange(ItemChildAddedChange, thisPointerVariant); 1060 if (!implicitUpdate) 1061 d_ptr->updateHelper(QRectF(), false, true); 1062 1063 // Inherit ancestor flags from the new parent. 1064 d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1)); 1065 d_ptr->updateAncestorFlag(ItemClipsChildrenToShape); 1066 d_ptr->updateAncestorFlag(ItemIgnoresTransformations); 1067 1068 // Update item visible / enabled. 1069 if (d_ptr->parent->isVisible() != d_ptr->visible) { 1070 if (!d_ptr->parent->isVisible() || !d_ptr->explicitlyHidden) 1071 d_ptr->setVisibleHelper(d_ptr->parent->isVisible(), /* explicit = */ false, /* update = */ !implicitUpdate); 1072 } 1073 if (d_ptr->parent->isEnabled() != d_ptr->enabled) { 1074 if (!d_ptr->parent->isEnabled() || !d_ptr->explicitlyDisabled) 1075 d_ptr->setEnabledHelper(d_ptr->parent->isEnabled(), /* explicit = */ false, /* update = */ !implicitUpdate); 1076 } 1077 1078 } else { 1079 // Inherit ancestor flags from the new parent. 1080 d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1)); 1081 d_ptr->updateAncestorFlag(ItemClipsChildrenToShape); 1082 d_ptr->updateAncestorFlag(ItemIgnoresTransformations); 1083 1084 // Update item visible / enabled. 1085 if (!d_ptr->visible && !d_ptr->explicitlyHidden) 1086 d_ptr->setVisibleHelper(true, /* explicit = */ false); 1087 if (!d_ptr->enabled && !d_ptr->explicitlyDisabled) 1088 d_ptr->setEnabledHelper(true, /* explicit = */ false); 1089 1090 d_ptr->updateHelper(QRectF(), false, true); 1091 } 1092 1093 if (d_ptr->scene) { 1094 // Invalidate any sort caching; arrival of a new item means we need to 1095 // resort. 1096 d_ptr->scene->d_func()->invalidateSortCache(); 1097 } 1098 1099 // Resolve opacity. 1100 d_ptr->updateEffectiveOpacity(); 1101 1102 // Resolve depth. 1103 d_ptr->resolveDepth(parent ? parent->d_ptr->depth : -1); 1104 1105 // Invalidate transform cache. 1106 d_ptr->invalidateSceneTransformCache(); 1107 1108 // Deliver post-change notification 1109 itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant); 1560 d_ptr->setParentItemHelper(parent); 1110 1561 } 1111 1562 … … 1125 1576 \since 4.4 1126 1577 1127 Returns a list of this item's children. The items are returned in no 1128 particular order. 1129 1130 \sa setParentItem() 1578 Returns a list of this item's children. 1579 1580 The items are sorted by stacking order. This takes into account both the 1581 items' insertion order and their Z-values. 1582 1583 \sa setParentItem(), zValue(), {QGraphicsItem#Sorting}{Sorting} 1131 1584 */ 1132 1585 QList<QGraphicsItem *> QGraphicsItem::childItems() const 1133 1586 { 1587 const_cast<QGraphicsItem *>(this)->d_ptr->ensureSortedChildren(); 1134 1588 return d_ptr->children; 1135 1589 } … … 1155 1609 { 1156 1610 return isWidget() && (static_cast<const QGraphicsWidget *>(this)->windowType() & Qt::Window); 1611 } 1612 1613 /*! 1614 \since 4.6 1615 Returns true if the item is a panel; otherwise returns false. 1616 1617 \sa QGraphicsItem::panel(), ItemIsPanel 1618 */ 1619 bool QGraphicsItem::isPanel() const 1620 { 1621 return d_ptr->flags & ItemIsPanel; 1157 1622 } 1158 1623 … … 1212 1677 item is automatically unselected. 1213 1678 1214 By default, no flags are enabled. 1679 By default, no flags are enabled. (QGraphicsWidget enables the 1680 ItemSendsGeometryChanges flag by default in order to track position 1681 changes.) 1215 1682 1216 1683 \sa flags(), setFlag() … … 1218 1685 void QGraphicsItem::setFlags(GraphicsItemFlags flags) 1219 1686 { 1687 if (isWindow()) 1688 flags |= ItemIsPanel; 1689 1220 1690 // Notify change and check for adjustment. 1221 1691 if (quint32(d_ptr->flags) == quint32(flags)) … … 1224 1694 if (quint32(d_ptr->flags) == quint32(flags)) 1225 1695 return; 1696 if (d_ptr->scene) 1697 d_ptr->scene->d_func()->index->itemChange(this, ItemFlagsChange, quint32(flags)); 1226 1698 1227 1699 // Flags that alter the geometry of the item (or its children). 1228 int geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations);1229 bool fullUpdate = ( flags& geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask);1700 const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations | ItemIsSelectable); 1701 bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask); 1230 1702 if (fullUpdate) 1231 d_ptr-> fullUpdateHelper(false, true);1703 d_ptr->paintedViewBoundingRectsNeedRepaint = 1; 1232 1704 1233 1705 // Keep the old flags to compare the diff. … … 1236 1708 // Update flags. 1237 1709 d_ptr->flags = flags; 1238 1239 // Reresolve effective opacity if the opacity flags change.1240 static const quint32 opacityFlagsMask = ItemIgnoresParentOpacity | ItemDoesntPropagateOpacityToChildren;1241 if ((flags & opacityFlagsMask) != (oldFlags & opacityFlagsMask))1242 d_ptr->updateEffectiveOpacity();1243 1710 1244 1711 if (!(d_ptr->flags & ItemIsFocusable) && hasFocus()) { … … 1260 1727 } 1261 1728 1262 if ((flags & ItemClipsToShape) != (oldFlags & ItemClipsToShape))1263 d_ptr->invalidateCachedClipPath();1264 1265 1729 if ((flags & ItemIgnoresTransformations) != (oldFlags & ItemIgnoresTransformations)) { 1266 1730 // Item children clipping changes. Propagate the ancestor flag to … … 1269 1733 } 1270 1734 1271 // ### Why updateHelper? 1272 d_ptr->updateHelper(QRectF(), false, true); 1735 if ((flags & ItemStacksBehindParent) != (oldFlags & ItemStacksBehindParent)) { 1736 // Ensure child item sorting is up to date when toggling this flag. 1737 if (d_ptr->parent) 1738 d_ptr->parent->d_ptr->needSortChildren = 1; 1739 else if (d_ptr->scene) 1740 d_ptr->scene->d_func()->needSortTopLevelItems = 1; 1741 } 1742 1743 if ((flags & ItemAcceptsInputMethod) != (oldFlags & ItemAcceptsInputMethod)) { 1744 // Update input method sensitivity in any views. 1745 if (d_ptr->scene) 1746 d_ptr->scene->d_func()->updateInputMethodSensitivityInViews(); 1747 } 1748 1749 if ((flags & ItemNegativeZStacksBehindParent) != (oldFlags & ItemNegativeZStacksBehindParent)) { 1750 // Update stack-behind. 1751 setFlag(ItemStacksBehindParent, d_ptr->z < qreal(0.0)); 1752 } 1753 1754 if ((d_ptr->panelModality != NonModal) 1755 && d_ptr->scene 1756 && (flags & ItemIsPanel) != (oldFlags & ItemIsPanel)) { 1757 // update the panel's modal state 1758 if (flags & ItemIsPanel) 1759 d_ptr->scene->d_func()->enterModal(this); 1760 else 1761 d_ptr->scene->d_func()->leaveModal(this); 1762 } 1763 1764 if (d_ptr->scene) { 1765 if ((flags & ItemSendsScenePositionChanges) != (oldFlags & ItemSendsScenePositionChanges)) { 1766 if (flags & ItemSendsScenePositionChanges) 1767 d_ptr->scene->d_func()->registerScenePosItem(this); 1768 else 1769 d_ptr->scene->d_func()->unregisterScenePosItem(this); 1770 } 1771 d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true); 1772 } 1273 1773 1274 1774 // Notify change. … … 1333 1833 1334 1834 if (mode == ItemCoordinateCache) { 1335 if (cache->key.isEmpty()) {1336 // Generate new simple pixmap cache key.1337 QString tmp;1338 tmp.sprintf("qgv-%p", this);1339 cache->key = tmp;1340 }1341 1835 if (lastMode == mode && cache->fixedSize == logicalCacheSize) 1342 1836 noVisualChange = true; … … 1348 1842 } 1349 1843 1844 /*! 1845 \since 4.6 1846 1847 Returns the modality for this item. 1848 */ 1849 QGraphicsItem::PanelModality QGraphicsItem::panelModality() const 1850 { 1851 return d_ptr->panelModality; 1852 } 1853 1854 /*! 1855 \since 4.6 1856 1857 Sets the modality for this item to \a panelModality. 1858 1859 Changing the modality of a visible item takes effect immediately. 1860 */ 1861 void QGraphicsItem::setPanelModality(PanelModality panelModality) 1862 { 1863 if (d_ptr->panelModality == panelModality) 1864 return; 1865 1866 PanelModality previousModality = d_ptr->panelModality; 1867 bool enterLeaveModal = (isPanel() && d_ptr->scene && isVisible()); 1868 if (enterLeaveModal && panelModality == NonModal) 1869 d_ptr->scene->d_func()->leaveModal(this); 1870 d_ptr->panelModality = panelModality; 1871 if (enterLeaveModal && d_ptr->panelModality != NonModal) 1872 d_ptr->scene->d_func()->enterModal(this, previousModality); 1873 } 1874 1875 /*! 1876 \since 4.6 1877 1878 Returns true if this item is blocked by a modal panel, false otherwise. If \a blockingPanel is 1879 non-zero, \a blockingPanel will be set to the modal panel that is blocking this item. If this 1880 item is not blocked, \a blockingPanel will not be set by this function. 1881 1882 This function always returns false for items not in a scene. 1883 1884 \sa panelModality() setPanelModality() PanelModality 1885 */ 1886 bool QGraphicsItem::isBlockedByModalPanel(QGraphicsItem **blockingPanel) const 1887 { 1888 if (!d_ptr->scene) 1889 return false; 1890 1891 1892 QGraphicsItem *dummy = 0; 1893 if (!blockingPanel) 1894 blockingPanel = &dummy; 1895 1896 QGraphicsScenePrivate *scene_d = d_ptr->scene->d_func(); 1897 if (scene_d->modalPanels.isEmpty()) 1898 return false; 1899 1900 // ### 1901 if (!scene_d->popupWidgets.isEmpty() && scene_d->popupWidgets.first() == this) 1902 return false; 1903 1904 for (int i = 0; i < scene_d->modalPanels.count(); ++i) { 1905 QGraphicsItem *modalPanel = scene_d->modalPanels.at(i); 1906 if (modalPanel->panelModality() == QGraphicsItem::SceneModal) { 1907 // Scene modal panels block all non-descendents. 1908 if (modalPanel != this && !modalPanel->isAncestorOf(this)) { 1909 *blockingPanel = modalPanel; 1910 return true; 1911 } 1912 } else { 1913 // Window modal panels block ancestors and siblings/cousins. 1914 if (modalPanel != this 1915 && !modalPanel->isAncestorOf(this) 1916 && commonAncestorItem(modalPanel)) { 1917 *blockingPanel = modalPanel; 1918 return true; 1919 } 1920 } 1921 } 1922 return false; 1923 } 1924 1350 1925 #ifndef QT_NO_TOOLTIP 1351 1926 /*! … … 1416 1991 d_ptr->hasCursor = 1; 1417 1992 if (d_ptr->scene) { 1993 d_ptr->scene->d_func()->allItemsUseDefaultCursor = false; 1418 1994 foreach (QGraphicsView *view, d_ptr->scene->views()) { 1995 view->viewport()->setMouseTracking(true); 1419 1996 // Note: Some of this logic is duplicated in QGraphicsView's mouse events. 1420 1997 if (view->underMouse()) { … … 1523 2100 return; 1524 2101 2102 // Don't show child if parent is not visible 2103 if (parent && newVisible && !parent->d_ptr->visible) 2104 return; 2105 1525 2106 // Modify the property. 1526 2107 const QVariant newVisibleVariant(q_ptr->itemChange(QGraphicsItem::ItemVisibleChange, … … 1536 2117 if (c) 1537 2118 c->purge(); 1538 updateHelper(QRectF(), /* force = */ true); 2119 if (scene) 2120 scene->d_func()->markDirty(q_ptr, QRectF(), /*invalidateChildren=*/false, /*force=*/true); 1539 2121 } 1540 2122 … … 1546 2128 if (scene->d_func()->keyboardGrabberItems.contains(q)) 1547 2129 q->ungrabKeyboard(); 2130 if (q->isPanel() && panelModality != QGraphicsItem::NonModal) 2131 scene->d_func()->leaveModal(q_ptr); 1548 2132 } 1549 2133 if (q_ptr->hasFocus() && scene) { 1550 // Hiding the closest non- windowancestor of the focus item2134 // Hiding the closest non-panel ancestor of the focus item 1551 2135 QGraphicsItem *focusItem = scene->focusItem(); 1552 2136 bool clear = true; 1553 if (isWidget && !focusItem->is Window()) {2137 if (isWidget && !focusItem->isPanel()) { 1554 2138 do { 1555 2139 if (focusItem == q_ptr) { … … 1557 2141 break; 1558 2142 } 1559 } while ((focusItem = focusItem->parentWidget()) && !focusItem->is Window());2143 } while ((focusItem = focusItem->parentWidget()) && !focusItem->isPanel()); 1560 2144 } 1561 2145 if (clear) … … 1565 2149 q_ptr->setSelected(false); 1566 2150 } else { 1567 if (isWidget && scene) { 1568 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr); 1569 if (widget->windowType() == Qt::Popup) 1570 scene->d_func()->addPopup(widget); 2151 geometryChanged = 1; 2152 paintedViewBoundingRectsNeedRepaint = 1; 2153 if (scene) { 2154 if (isWidget) { 2155 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr); 2156 if (widget->windowType() == Qt::Popup) 2157 scene->d_func()->addPopup(widget); 2158 } 2159 if (q->isPanel() && panelModality != QGraphicsItem::NonModal) { 2160 scene->d_func()->enterModal(q_ptr); 2161 } 1571 2162 } 1572 2163 } … … 1579 2170 } 1580 2171 2172 // Update activation 2173 if (scene && q->isPanel()) { 2174 if (newVisible) { 2175 if (parent && parent->isActive()) 2176 q->setActive(true); 2177 } else { 2178 if (q->isActive()) 2179 scene->setActivePanel(parent); 2180 } 2181 } 2182 1581 2183 // Enable subfocus 1582 if (newVisible && isWidget) { 1583 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr); 1584 QGraphicsWidget *fw = widget->focusWidget(); 1585 if (fw && fw != scene->focusItem()) 1586 scene->setFocusItem(fw); 2184 if (scene && newVisible) { 2185 QGraphicsItem *p = parent; 2186 bool done = false; 2187 while (p) { 2188 if (p->flags() & QGraphicsItem::ItemIsFocusScope) { 2189 QGraphicsItem *fsi = p->d_ptr->focusScopeItem; 2190 if (q_ptr == fsi || q_ptr->isAncestorOf(fsi)) { 2191 done = true; 2192 while (fsi->d_ptr->focusScopeItem && fsi->d_ptr->focusScopeItem->isVisible()) 2193 fsi = fsi->d_ptr->focusScopeItem; 2194 scene->setFocusItem(fsi); 2195 } 2196 break; 2197 } 2198 p = p->d_ptr->parent; 2199 } 2200 if (!done) { 2201 QGraphicsItem *fi = subFocusItem; 2202 if (fi && fi != scene->focusItem()) { 2203 scene->setFocusItem(fi); 2204 } 2205 } 1587 2206 } 1588 2207 1589 2208 // Deliver post-change notification. 1590 2209 q_ptr->itemChange(QGraphicsItem::ItemVisibleHasChanged, newVisibleVariant); 2210 2211 if (isObject) 2212 emit static_cast<QGraphicsObject *>(q_ptr)->visibleChanged(); 1591 2213 } 1592 2214 … … 1674 2296 q_ptr->ungrabMouse(); 1675 2297 if (q_ptr->hasFocus()) { 1676 // Disabling the closest non- windowancestor of the focus item2298 // Disabling the closest non-panel ancestor of the focus item 1677 2299 // causes focus to pop to the next item, otherwise it's cleared. 1678 2300 QGraphicsItem *focusItem = scene->focusItem(); 1679 2301 bool clear = true; 1680 if (isWidget && !focusItem->is Window() && q_ptr->isAncestorOf(focusItem)) {2302 if (isWidget && !focusItem->isPanel() && q_ptr->isAncestorOf(focusItem)) { 1681 2303 do { 1682 2304 if (focusItem == q_ptr) { … … 1684 2306 break; 1685 2307 } 1686 } while ((focusItem = focusItem->parentWidget()) && !focusItem->is Window());2308 } while ((focusItem = focusItem->parentWidget()) && !focusItem->isPanel()); 1687 2309 } 1688 2310 if (clear) … … 1700 2322 // Schedule redraw. 1701 2323 if (update) 1702 updateHelper();2324 q_ptr->update(); 1703 2325 1704 2326 foreach (QGraphicsItem *child, children) { … … 1709 2331 // Deliver post-change notification. 1710 2332 q_ptr->itemChange(QGraphicsItem::ItemEnabledHasChanged, newEnabledVariant); 2333 2334 if (isObject) 2335 emit static_cast<QGraphicsObject *>(q_ptr)->enabledChanged(); 1711 2336 } 1712 2337 … … 1801 2426 d_ptr->selected = newSelected; 1802 2427 1803 d_ptr->updateHelper(); 1804 2428 update(); 1805 2429 if (d_ptr->scene) { 1806 2430 QGraphicsScenePrivate *sceneD = d_ptr->scene->d_func(); … … 1839 2463 qreal QGraphicsItem::opacity() const 1840 2464 { 1841 if (d_ptr->hasOpacity) { 1842 QVariant o = d_ptr->extra(QGraphicsItemPrivate::ExtraOpacity); 1843 if (!o.isNull()) 1844 return o.toDouble(); 1845 } 1846 return qreal(1.0); 2465 return d_ptr->opacity; 1847 2466 } 1848 2467 … … 1860 2479 qreal QGraphicsItem::effectiveOpacity() const 1861 2480 { 1862 if (!d_ptr->hasEffectiveOpacity) 1863 return qreal(1.0); 1864 1865 QVariant effectiveOpacity = d_ptr->extra(QGraphicsItemPrivate::ExtraEffectiveOpacity); 1866 return effectiveOpacity.isNull() ? qreal(1.0) : qreal(effectiveOpacity.toDouble()); 2481 return d_ptr->effectiveOpacity(); 1867 2482 } 1868 2483 … … 1892 2507 { 1893 2508 // Notify change. 1894 const QVariant newOpacityVariant(itemChange(ItemOpacityChange, double(opacity))); 1895 qreal newOpacity = newOpacityVariant.toDouble(); 1896 1897 // Normalize. 1898 newOpacity = qBound<qreal>(0.0, newOpacity, 1.0); 2509 const QVariant newOpacityVariant(itemChange(ItemOpacityChange, opacity)); 2510 2511 // Normalized opacity 2512 qreal newOpacity = qBound(qreal(0), newOpacityVariant.toReal(), qreal(1)); 1899 2513 1900 2514 // No change? Done. 1901 if ( qFuzzyCompare(newOpacity, this->opacity()))2515 if (newOpacity == d_ptr->opacity) 1902 2516 return; 1903 2517 1904 // Assign local opacity. 1905 if (qFuzzyCompare(newOpacity, qreal(1.0))) { 1906 // Opaque, unset opacity. 1907 d_ptr->hasOpacity = 0; 1908 d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraOpacity); 1909 } else { 1910 d_ptr->hasOpacity = 1; 1911 d_ptr->setExtra(QGraphicsItemPrivate::ExtraOpacity, double(newOpacity)); 1912 } 1913 1914 // Resolve effective opacity. 1915 if (QGraphicsItem *p = d_ptr->parent) 1916 d_ptr->resolveEffectiveOpacity(p->effectiveOpacity()); 1917 else 1918 d_ptr->resolveEffectiveOpacity(1.0); 2518 d_ptr->opacity = newOpacity; 1919 2519 1920 2520 // Notify change. 1921 itemChange(ItemOpacityHasChanged, newOpacity );2521 itemChange(ItemOpacityHasChanged, newOpacityVariant); 1922 2522 1923 2523 // Update. 1924 d_ptr->fullUpdateHelper(); 2524 if (d_ptr->scene) { 2525 #ifndef QT_NO_GRAPHICSEFFECT 2526 d_ptr->invalidateGraphicsEffectsRecursively(); 2527 #endif //QT_NO_GRAPHICSEFFECT 2528 d_ptr->scene->d_func()->markDirty(this, QRectF(), 2529 /*invalidateChildren=*/true, 2530 /*force=*/false, 2531 /*ignoreOpacity=*/true); 2532 } 2533 2534 if (d_ptr->isObject) 2535 emit static_cast<QGraphicsObject *>(this)->opacityChanged(); 2536 } 2537 2538 /*! 2539 Returns a pointer to this item's effect if it has one; otherwise 0. 2540 2541 \since 4.6 2542 */ 2543 #ifndef QT_NO_GRAPHICSEFFECT 2544 QGraphicsEffect *QGraphicsItem::graphicsEffect() const 2545 { 2546 return d_ptr->graphicsEffect; 2547 } 2548 2549 /*! 2550 Sets \a effect as the item's effect. If there already is an effect installed 2551 on this item, QGraphicsItem will delete the existing effect before installing 2552 the new \a effect. 2553 2554 If \a effect is the installed on a different item, setGraphicsEffect() will remove 2555 the effect from the item and install it on this item. 2556 2557 QGraphicsItem takes ownership of \a effect. 2558 2559 \note This function will apply the effect on itself and all its children. 2560 2561 \since 4.6 2562 */ 2563 void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect) 2564 { 2565 if (d_ptr->graphicsEffect == effect) 2566 return; 2567 2568 if (d_ptr->graphicsEffect) { 2569 delete d_ptr->graphicsEffect; 2570 d_ptr->graphicsEffect = 0; 2571 } 2572 2573 if (effect) { 2574 // Set new effect. 2575 QGraphicsEffectSourcePrivate *sourced = new QGraphicsItemEffectSourcePrivate(this); 2576 QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced); 2577 d_ptr->graphicsEffect = effect; 2578 effect->d_func()->setGraphicsEffectSource(source); 2579 prepareGeometryChange(); 2580 } 2581 } 2582 #endif //QT_NO_GRAPHICSEFFECT 2583 2584 /*! 2585 \internal 2586 \since 4.6 2587 Returns the effective bounding rect of the given item space rect. 2588 If the item has no effect, the rect is returned unmodified. 2589 If the item has an effect, the effective rect can be extend beyond the 2590 item's bounding rect, depending on the effect. 2591 2592 \sa boundingRect() 2593 */ 2594 QRectF QGraphicsItemPrivate::effectiveBoundingRect(const QRectF &rect) const 2595 { 2596 #ifndef QT_NO_GRAPHICSEFFECT 2597 Q_Q(const QGraphicsItem); 2598 QGraphicsEffect *effect = graphicsEffect; 2599 if (scene && effect && effect->isEnabled()) { 2600 QRectF sceneRect = q->mapRectToScene(rect); 2601 QRectF sceneEffectRect; 2602 foreach (QGraphicsView *view, scene->views()) { 2603 QRectF deviceRect = view->d_func()->mapRectFromScene(sceneRect); 2604 QRect deviceEffectRect = effect->boundingRectFor(deviceRect).toAlignedRect(); 2605 sceneEffectRect |= view->d_func()->mapRectToScene(deviceEffectRect); 2606 } 2607 return q->mapRectFromScene(sceneEffectRect); 2608 } 2609 #endif //QT_NO_GRAPHICSEFFECT 2610 return rect; 2611 } 2612 2613 /*! 2614 \internal 2615 \since 4.6 2616 Returns the effective bounding rect of the item. 2617 If the item has no effect, this is the same as the item's bounding rect. 2618 If the item has an effect, the effective rect can be larger than the item's 2619 bouding rect, depending on the effect. 2620 2621 \sa boundingRect() 2622 */ 2623 QRectF QGraphicsItemPrivate::effectiveBoundingRect() const 2624 { 2625 #ifndef QT_NO_GRAPHICSEFFECT 2626 Q_Q(const QGraphicsItem); 2627 QRectF brect = effectiveBoundingRect(q_ptr->boundingRect()); 2628 if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) 2629 return brect; 2630 2631 const QGraphicsItem *effectParent = parent; 2632 while (effectParent) { 2633 QGraphicsEffect *effect = effectParent->d_ptr->graphicsEffect; 2634 if (scene && effect && effect->isEnabled()) { 2635 const QRectF brectInParentSpace = q->mapRectToItem(effectParent, brect); 2636 const QRectF effectRectInParentSpace = effectParent->d_ptr->effectiveBoundingRect(brectInParentSpace); 2637 brect = effectParent->mapRectToItem(q, effectRectInParentSpace); 2638 } 2639 if (effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) 2640 return brect; 2641 effectParent = effectParent->d_ptr->parent; 2642 } 2643 2644 return brect; 2645 #else //QT_NO_GRAPHICSEFFECT 2646 return q_ptr->boundingRect(); 2647 #endif //QT_NO_GRAPHICSEFFECT 2648 2649 } 2650 2651 /*! 2652 \internal 2653 \since 4.6 2654 Returns the effective bounding rect of this item in scene coordinates, 2655 by combining sceneTransform() with boundingRect(), taking into account 2656 the effect that the item might have. 2657 2658 If the item has no effect, this is the same as sceneBoundingRect(). 2659 2660 \sa effectiveBoundingRect(), sceneBoundingRect() 2661 */ 2662 QRectF QGraphicsItemPrivate::sceneEffectiveBoundingRect() const 2663 { 2664 // Find translate-only offset 2665 // COMBINE 2666 QPointF offset; 2667 const QGraphicsItem *parentItem = q_ptr; 2668 const QGraphicsItemPrivate *itemd; 2669 do { 2670 itemd = parentItem->d_ptr.data(); 2671 if (itemd->transformData) 2672 break; 2673 offset += itemd->pos; 2674 } while ((parentItem = itemd->parent)); 2675 2676 QRectF br = effectiveBoundingRect(); 2677 br.translate(offset); 2678 return !parentItem ? br : parentItem->sceneTransform().mapRect(br); 1925 2679 } 1926 2680 … … 2035 2789 children's areas. 2036 2790 2037 If a parent item handles child events (setHandlesChildEvents()), it will2038 receive hover move, drag move, and drop events as the cursor passes2039 through its children, but it does not receive hover enter and hover leave,2040 nordrag enter and drag leave events on behalf of its children.2791 If a parent item handles child events, it will receive hover move, 2792 drag move, and drop events as the cursor passes through its 2793 children, but it does not receive hover enter and hover leave, nor 2794 drag enter and drag leave events on behalf of its children. 2041 2795 2042 2796 A QGraphicsWidget with window decorations will accept hover events … … 2048 2802 void QGraphicsItem::setAcceptHoverEvents(bool enabled) 2049 2803 { 2804 if (d_ptr->acceptsHover == quint32(enabled)) 2805 return; 2050 2806 d_ptr->acceptsHover = quint32(enabled); 2807 if (d_ptr->acceptsHover && d_ptr->scene && d_ptr->scene->d_func()->allItemsIgnoreHoverEvents) { 2808 d_ptr->scene->d_func()->allItemsIgnoreHoverEvents = false; 2809 d_ptr->scene->d_func()->enableMouseTrackingOnViews(); 2810 } 2051 2811 } 2052 2812 … … 2058 2818 void QGraphicsItem::setAcceptsHoverEvents(bool enabled) 2059 2819 { 2060 d_ptr->acceptsHover = quint32(enabled); 2061 } 2062 2063 /*! 2820 setAcceptHoverEvents(enabled); 2821 } 2822 2823 /*! \since 4.6 2824 2825 Returns true if an item accepts \l{QTouchEvent}{touch events}; 2826 otherwise, returns false. By default, items do not accept touch events. 2827 2828 \sa setAcceptTouchEvents() 2829 */ 2830 bool QGraphicsItem::acceptTouchEvents() const 2831 { 2832 return d_ptr->acceptTouchEvents; 2833 } 2834 2835 /*! 2836 \since 4.6 2837 2838 If \a enabled is true, this item will accept \l{QTouchEvent}{touch events}; 2839 otherwise, it will ignore them. By default, items do not accept 2840 touch events. 2841 */ 2842 void QGraphicsItem::setAcceptTouchEvents(bool enabled) 2843 { 2844 if (d_ptr->acceptTouchEvents == quint32(enabled)) 2845 return; 2846 d_ptr->acceptTouchEvents = quint32(enabled); 2847 if (d_ptr->acceptTouchEvents && d_ptr->scene && d_ptr->scene->d_func()->allItemsIgnoreTouchEvents) { 2848 d_ptr->scene->d_func()->allItemsIgnoreTouchEvents = false; 2849 d_ptr->scene->d_func()->enableTouchEventsOnViews(); 2850 } 2851 } 2852 2853 /*! 2854 \since 4.6 2855 2856 Returns true if this item filters child events (i.e., all events 2857 intended for any of its children are instead sent to this item); 2858 otherwise, false is returned. 2859 2860 The default value is false; child events are not filtered. 2861 2862 \sa setFiltersChildEvents() 2863 */ 2864 bool QGraphicsItem::filtersChildEvents() const 2865 { 2866 return d_ptr->filtersDescendantEvents; 2867 } 2868 2869 /*! 2870 \since 4.6 2871 2872 If \a enabled is true, this item is set to filter all events for 2873 all its children (i.e., all events intented for any of its 2874 children are instead sent to this item); otherwise, if \a enabled 2875 is false, this item will only handle its own events. The default 2876 value is false. 2877 2878 \sa filtersChildEvents() 2879 */ 2880 void QGraphicsItem::setFiltersChildEvents(bool enabled) 2881 { 2882 if (d_ptr->filtersDescendantEvents == enabled) 2883 return; 2884 2885 d_ptr->filtersDescendantEvents = enabled; 2886 d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2)); 2887 } 2888 2889 /*! 2890 \obsolete 2891 2064 2892 Returns true if this item handles child events (i.e., all events 2065 2893 intended for any of its children are instead sent to this item); … … 2082 2910 2083 2911 /*! 2912 \obsolete 2913 2084 2914 If \a enabled is true, this item is set to handle all events for 2085 2915 all its children (i.e., all events intented for any of its … … 2107 2937 d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1)); 2108 2938 } 2109 2110 /*! 2111 Returns true if this item has keyboard input focus; otherwise, returns 2112 false. 2113 2114 \sa QGraphicsScene::focusItem(), setFocus(), QGraphicsScene::setFocusItem() 2939 /*! 2940 \since 4.6 2941 Returns true if this item is active; otherwise returns false. 2942 2943 An item can only be active if the scene is active. An item is active 2944 if it is, or is a descendent of, an active panel. Items in non-active 2945 panels are not active. 2946 2947 Items that are not part of a panel follow scene activation when the 2948 scene has no active panel. 2949 2950 Only active items can gain input focus. 2951 2952 \sa QGraphicsScene::isActive(), QGraphicsScene::activePanel(), panel(), isPanel() 2953 */ 2954 bool QGraphicsItem::isActive() const 2955 { 2956 if (!d_ptr->scene || !d_ptr->scene->isActive()) 2957 return false; 2958 return panel() == d_ptr->scene->activePanel(); 2959 } 2960 2961 /*! 2962 \since 4.6 2963 2964 If \a active is true, and the scene is active, this item's panel will be 2965 activated. Otherwise, the panel is deactivated. 2966 2967 If the item is not part of an active scene, \a active will decide what 2968 happens to the panel when the scene becomes active or the item is added to 2969 the scene. If true, the item's panel will be activated when the item is 2970 either added to the scene or the scene is activated. Otherwise, the item 2971 will stay inactive independent of the scene's activated state. 2972 2973 \sa isPanel(), QGraphicsScene::setActivePanel(), QGraphicsScene::isActive() 2974 */ 2975 void QGraphicsItem::setActive(bool active) 2976 { 2977 d_ptr->explicitActivate = 1; 2978 d_ptr->wantsActive = active; 2979 if (d_ptr->scene) { 2980 if (active) { 2981 // Activate this item. 2982 d_ptr->scene->setActivePanel(this); 2983 } else { 2984 // Deactivate this item, and reactivate the last active item 2985 // (if any). 2986 QGraphicsItem *lastActive = d_ptr->scene->d_func()->lastActivePanel; 2987 d_ptr->scene->setActivePanel(lastActive != this ? lastActive : 0); 2988 } 2989 } 2990 } 2991 2992 /*! 2993 Returns true if this item is active, and it or its \l{focusProxy()}{focus 2994 proxy} has keyboard input focus; otherwise, returns false. 2995 2996 \sa focusItem(), setFocus(), QGraphicsScene::setFocusItem(), isActive() 2115 2997 */ 2116 2998 bool QGraphicsItem::hasFocus() const 2117 2999 { 2118 return (d_ptr->scene && d_ptr->scene->focusItem() == this); 3000 if (d_ptr->focusProxy) 3001 return d_ptr->focusProxy->hasFocus(); 3002 return isActive() && (d_ptr->scene && d_ptr->scene->focusItem() == this); 2119 3003 } 2120 3004 2121 3005 /*! 2122 3006 Gives keyboard input focus to this item. The \a focusReason argument will 2123 be passed into any focus event generated by this function; it is used to 2124 give an explanation of what caused the item to get focus. 2125 2126 Only items that set the ItemIsFocusable flag can accept keyboard focus. 2127 2128 If this item is not visible (i.e., isVisible() returns false), not 2129 enabled, not associated with a scene, or if it already has input focus, 2130 this function will do nothing. 2131 2132 As a result of calling this function, this item will receive a focus in 2133 event with \a focusReason. If another item already has focus, that item 2134 will first receive a focus out event indicating that it has lost input 3007 be passed into any \l{QFocusEvent}{focus event} generated by this function; 3008 it is used to give an explanation of what caused the item to get focus. 3009 3010 Only enabled items that set the ItemIsFocusable flag can accept keyboard 2135 3011 focus. 2136 3012 2137 \sa clearFocus(), hasFocus() 3013 If this item is not visible, not active, or not associated with a scene, 3014 it will not gain immediate input focus. However, it will be registered as 3015 the preferred focus item for its subtree of items, should it later become 3016 visible. 3017 3018 As a result of calling this function, this item will receive a 3019 \l{focusInEvent()}{focus in event} with \a focusReason. If another item 3020 already has focus, that item will first receive a \l{focusOutEvent()} 3021 {focus out event} indicating that it has lost input focus. 3022 3023 \sa clearFocus(), hasFocus(), focusItem(), focusProxy() 2138 3024 */ 2139 3025 void QGraphicsItem::setFocus(Qt::FocusReason focusReason) 2140 3026 { 2141 if (!d_ptr->scene || !isEnabled() || hasFocus() || !(d_ptr->flags & ItemIsFocusable)) 3027 d_ptr->setFocusHelper(focusReason, /* climb = */ true); 3028 } 3029 3030 /*! 3031 \internal 3032 */ 3033 void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool climb) 3034 { 3035 // Disabled / unfocusable items cannot accept focus. 3036 if (!q_ptr->isEnabled() || !(flags & QGraphicsItem::ItemIsFocusable)) 2142 3037 return; 2143 if (isVisible()) { 2144 // Visible items immediately gain focus from scene. 2145 d_ptr->scene->setFocusItem(this, focusReason); 2146 } else if (d_ptr->isWidget) { 2147 // Just set up subfocus. 2148 static_cast<QGraphicsWidget *>(this)->d_func()->setFocusWidget(); 3038 3039 // Find focus proxy. 3040 QGraphicsItem *f = q_ptr; 3041 while (f->d_ptr->focusProxy) 3042 f = f->d_ptr->focusProxy; 3043 3044 // Return if it already has focus. 3045 if (scene && scene->focusItem() == f) 3046 return; 3047 3048 // Update focus scope item ptr. 3049 QGraphicsItem *p = parent; 3050 while (p) { 3051 if (p->flags() & QGraphicsItem::ItemIsFocusScope) { 3052 p->d_ptr->focusScopeItem = q_ptr; 3053 if (!p->focusItem()) { 3054 // If you call setFocus on a child of a focus scope that 3055 // doesn't currently have a focus item, then stop. 3056 return; 3057 } 3058 break; 3059 } 3060 p = p->d_ptr->parent; 3061 } 3062 3063 if (climb) { 3064 while (f->d_ptr->focusScopeItem && f->d_ptr->focusScopeItem->isVisible()) 3065 f = f->d_ptr->focusScopeItem; 3066 } 3067 3068 // Update the child focus chain. 3069 f->d_ptr->setSubFocus(); 3070 3071 // Update the scene's focus item. 3072 if (scene) { 3073 QGraphicsItem *p = q_ptr->panel(); 3074 if ((!p && scene->isActive()) || (p && p->isActive())) { 3075 // Visible items immediately gain focus from scene. 3076 scene->d_func()->setFocusItemHelper(f, focusReason); 3077 } 2149 3078 } 2150 3079 } … … 2153 3082 Takes keyboard input focus from the item. 2154 3083 2155 If it has focus, a focus out event is sent to this item to tell it that it2156 i s about to lose the focus.3084 If it has focus, a \l{focusOutEvent()}{focus out event} is sent to this 3085 item to tell it that it is about to lose the focus. 2157 3086 2158 3087 Only items that set the ItemIsFocusable flag, or widgets that set an 2159 3088 appropriate focus policy, can accept keyboard focus. 2160 3089 2161 \sa setFocus(), QGraphicsWidget::focusPolicy3090 \sa setFocus(), hasFocus(), QGraphicsWidget::focusPolicy 2162 3091 */ 2163 3092 void QGraphicsItem::clearFocus() 2164 3093 { 2165 if (!d_ptr->scene) 2166 return; 2167 if (d_ptr->isWidget) { 2168 // Invisible widget items with focus must explicitly clear subfocus. 2169 static_cast<QGraphicsWidget *>(this)->d_func()->clearFocusWidget(); 2170 } 2171 if (d_ptr->scene->focusItem() == this) { 3094 // Pass focus to the closest parent focus scope. 3095 if (!d_ptr->inDestructor) { 3096 QGraphicsItem *p = d_ptr->parent; 3097 while (p) { 3098 if (p->flags() & ItemIsFocusScope) { 3099 p->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ false); 3100 return; 3101 } 3102 p = p->d_ptr->parent; 3103 } 3104 } 3105 3106 // Invisible items with focus must explicitly clear subfocus. 3107 d_ptr->clearSubFocus(this); 3108 3109 if (hasFocus()) { 2172 3110 // If this item has the scene's input focus, clear it. 2173 3111 d_ptr->scene->setFocusItem(0); 2174 3112 } 3113 } 3114 3115 /*! 3116 \since 4.6 3117 3118 Returns this item's focus proxy, or 0 if this item has no 3119 focus proxy. 3120 3121 \sa setFocusProxy(), setFocus(), hasFocus() 3122 */ 3123 QGraphicsItem *QGraphicsItem::focusProxy() const 3124 { 3125 return d_ptr->focusProxy; 3126 } 3127 3128 /*! 3129 \since 4.6 3130 3131 Sets the item's focus proxy to \a item. 3132 3133 If an item has a focus proxy, the focus proxy will receive 3134 input focus when the item gains input focus. The item itself 3135 will still have focus (i.e., hasFocus() will return true), 3136 but only the focus proxy will receive the keyboard input. 3137 3138 A focus proxy can itself have a focus proxy, and so on. In 3139 such case, keyboard input will be handled by the outermost 3140 focus proxy. 3141 3142 The focus proxy \a item must belong to the same scene as 3143 this item. 3144 3145 \sa focusProxy(), setFocus(), hasFocus() 3146 */ 3147 void QGraphicsItem::setFocusProxy(QGraphicsItem *item) 3148 { 3149 if (item == d_ptr->focusProxy) 3150 return; 3151 if (item == this) { 3152 qWarning("QGraphicsItem::setFocusProxy: cannot assign self as focus proxy"); 3153 return; 3154 } 3155 if (item) { 3156 if (item->d_ptr->scene != d_ptr->scene) { 3157 qWarning("QGraphicsItem::setFocusProxy: focus proxy must be in same scene"); 3158 return; 3159 } 3160 for (QGraphicsItem *f = item->focusProxy(); f != 0; f = f->focusProxy()) { 3161 if (f == this) { 3162 qWarning("QGraphicsItem::setFocusProxy: %p is already in the focus proxy chain", item); 3163 return; 3164 } 3165 } 3166 } 3167 3168 QGraphicsItem *lastFocusProxy = d_ptr->focusProxy; 3169 if (lastFocusProxy) 3170 lastFocusProxy->d_ptr->focusProxyRefs.removeOne(&d_ptr->focusProxy); 3171 d_ptr->focusProxy = item; 3172 if (item) 3173 item->d_ptr->focusProxyRefs << &d_ptr->focusProxy; 3174 } 3175 3176 /*! 3177 \since 4.6 3178 3179 If this item, a child or descendant of this item currently has input 3180 focus, this function will return a pointer to that item. If 3181 no descendant has input focus, 0 is returned. 3182 3183 \sa hasFocus(), setFocus(), QWidget::focusWidget() 3184 */ 3185 QGraphicsItem *QGraphicsItem::focusItem() const 3186 { 3187 return d_ptr->subFocusItem; 3188 } 3189 3190 /*! 3191 \internal 3192 3193 Returns this item's focus scope item. 3194 */ 3195 QGraphicsItem *QGraphicsItem::focusScopeItem() const 3196 { 3197 return d_ptr->focusScopeItem; 2175 3198 } 2176 3199 … … 2310 3333 item's position in scene coordinates, regardless of its parent. 2311 3334 2312 \sa x(), y(), setPos(), matrix(), {The Graphics View Coordinate System}3335 \sa x(), y(), setPos(), transform(), {The Graphics View Coordinate System} 2313 3336 */ 2314 3337 QPointF QGraphicsItem::pos() const … … 2326 3349 2327 3350 /*! 3351 \since 4.6 3352 3353 Set's the \a x coordinate of the item's position. Equivalent to 3354 calling setPos(x, y()). 3355 3356 \sa x(), setPos() 3357 */ 3358 void QGraphicsItem::setX(qreal x) 3359 { 3360 if (d_ptr->inDestructor) 3361 return; 3362 3363 d_ptr->setPosHelper(QPointF(x, d_ptr->pos.y())); 3364 } 3365 3366 /*! 2328 3367 \fn QGraphicsItem::y() const 2329 3368 … … 2332 3371 \sa x() 2333 3372 */ 3373 3374 /*! 3375 \since 4.6 3376 3377 Set's the \a y coordinate of the item's position. Equivalent to 3378 calling setPos(x(), y). 3379 3380 \sa x(), setPos() 3381 */ 3382 void QGraphicsItem::setY(qreal y) 3383 { 3384 if (d_ptr->inDestructor) 3385 return; 3386 3387 d_ptr->setPosHelper(QPointF(d_ptr->pos.x(), y)); 3388 } 2334 3389 2335 3390 /*! … … 2347 3402 \internal 2348 3403 2349 Sets the position \a pos and notifies the change. If \a update is true, 2350 the item is also updated; otherwise it is not updated before and after the 2351 change. 3404 Sets the position \a pos. 2352 3405 */ 2353 3406 void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) 2354 3407 { 2355 3408 Q_Q(QGraphicsItem); 2356 if (this->pos == pos)2357 return;2358 2359 // Notify the item that the position is changing.2360 const QVariant newPosVariant(q->itemChange(QGraphicsItem::ItemPositionChange, pos));2361 QPointF newPos = newPosVariant.toPointF();2362 if (newPos == this->pos)2363 return;2364 2365 // Update and repositition.2366 3409 inSetPosHelper = 1; 2367 updateCachedClipPathFromSetPosHelper(newPos); 2368 if (scene) { 2369 fullUpdateHelper(true); 3410 if (scene) 2370 3411 q->prepareGeometryChange(); 2371 } 2372 this->pos = newPos; 2373 invalidateSceneTransformCache(); 2374 2375 // Send post-notification. 2376 q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant); 3412 QPointF oldPos = this->pos; 3413 this->pos = pos; 3414 dirtySceneTransform = 1; 2377 3415 inSetPosHelper = 0; 3416 if (isObject) { 3417 if (pos.x() != oldPos.x()) 3418 emit static_cast<QGraphicsObject *>(q_ptr)->xChanged(); 3419 if (pos.y() != oldPos.y()) 3420 emit static_cast<QGraphicsObject *>(q_ptr)->yChanged(); 3421 } 3422 } 3423 3424 /*! 3425 \internal 3426 3427 Sets the transform \a transform. 3428 */ 3429 void QGraphicsItemPrivate::setTransformHelper(const QTransform &transform) 3430 { 3431 q_ptr->prepareGeometryChange(); 3432 transformData->transform = transform; 3433 dirtySceneTransform = 1; 2378 3434 } 2379 3435 … … 2390 3446 void QGraphicsItem::setPos(const QPointF &pos) 2391 3447 { 2392 d_ptr->setPosHelper(pos); 3448 if (d_ptr->pos == pos) 3449 return; 3450 3451 if (d_ptr->inDestructor) 3452 return; 3453 3454 // Update and repositition. 3455 if (!(d_ptr->flags & ItemSendsGeometryChanges)) { 3456 d_ptr->setPosHelper(pos); 3457 return; 3458 } 3459 3460 // Notify the item that the position is changing. 3461 const QVariant newPosVariant(itemChange(ItemPositionChange, qVariantFromValue<QPointF>(pos))); 3462 QPointF newPos = newPosVariant.toPointF(); 3463 if (newPos == d_ptr->pos) 3464 return; 3465 3466 // Update and repositition. 3467 d_ptr->setPosHelper(newPos); 3468 3469 // Send post-notification. 3470 itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant); 3471 d_ptr->sendScenePosChange(); 2393 3472 } 2394 3473 … … 2463 3542 \since 4.3 2464 3543 2465 Returns this item's transformation matrix. If no matrix has been set, the 2466 identity matrix is returned. 3544 Returns this item's transformation matrix. 3545 3546 The transformation matrix is combined with the item's rotation(), scale() 3547 and transformations() into a combined transformations for the item. 3548 3549 The default transformation matrix is an identity matrix. 2467 3550 2468 3551 \sa setTransform(), sceneTransform() … … 2470 3553 QTransform QGraphicsItem::transform() const 2471 3554 { 2472 if (!d_ptr-> hasTransform)3555 if (!d_ptr->transformData) 2473 3556 return QTransform(); 2474 return qVariantValue<QTransform>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)); 2475 } 3557 return d_ptr->transformData->transform; 3558 } 3559 3560 /*! 3561 \since 4.6 3562 3563 Returns the clockwise rotation, in degrees, around the Z axis. The default 3564 value is 0 (i.e., the item is not rotated). 3565 3566 The rotation is combined with the item's scale(), transform() and 3567 transformations() to map the item's coordinate system to the parent item. 3568 3569 \sa setRotation(), transformOriginPoint(), {Transformations} 3570 */ 3571 qreal QGraphicsItem::rotation() const 3572 { 3573 if (!d_ptr->transformData) 3574 return 0; 3575 return d_ptr->transformData->rotation; 3576 } 3577 3578 /*! 3579 \since 4.6 3580 3581 Sets the clockwise rotation \a angle, in degrees, around the Z axis. The 3582 default value is 0 (i.e., the item is not rotated). Assigning a negative 3583 value will rotate the item counter-clockwise. Normally the rotation angle 3584 is in the range (-360, 360), but it's also possible to assign values 3585 outside of this range (e.g., a rotation of 370 degrees is the same as a 3586 rotation of 10 degrees). 3587 3588 The item is rotated around its transform origin point, which by default 3589 is (0, 0). You can select a different transformation origin by calling 3590 setTransformOriginPoint(). 3591 3592 The rotation is combined with the item's scale(), transform() and 3593 transformations() to map the item's coordinate system to the parent item. 3594 3595 \sa rotation(), setTransformOriginPoint(), {Transformations} 3596 */ 3597 void QGraphicsItem::setRotation(qreal angle) 3598 { 3599 prepareGeometryChange(); 3600 if (!d_ptr->transformData) 3601 d_ptr->transformData = new QGraphicsItemPrivate::TransformData; 3602 d_ptr->transformData->rotation = angle; 3603 d_ptr->transformData->onlyTransform = false; 3604 d_ptr->dirtySceneTransform = 1; 3605 3606 if (d_ptr->isObject) 3607 emit static_cast<QGraphicsObject *>(this)->rotationChanged(); 3608 } 3609 3610 /*! 3611 \since 4.6 3612 3613 Returns the scale factor of the item. The default scale factor is 1.0 3614 (i.e., the item is not scaled). 3615 3616 The scale is combined with the item's rotation(), transform() and 3617 transformations() to map the item's coordinate system to the parent item. 3618 3619 \sa setScale(), rotation(), {Transformations} 3620 */ 3621 qreal QGraphicsItem::scale() const 3622 { 3623 if (!d_ptr->transformData) 3624 return 1.; 3625 return d_ptr->transformData->scale; 3626 } 3627 3628 /*! 3629 \since 4.6 3630 3631 Sets the scale \a factor of the item. The default scale factor is 1.0 3632 (i.e., the item is not scaled). A scale factor of 0.0 will collapse the 3633 item to a single point. If you provide a negative scale factor, the 3634 item will be flipped and mirrored (i.e., rotated 180 degrees). 3635 3636 The item is scaled around its transform origin point, which by default 3637 is (0, 0). You can select a different transformation origin by calling 3638 setTransformOriginPoint(). 3639 3640 The scale is combined with the item's rotation(), transform() and 3641 transformations() to map the item's coordinate system to the parent item. 3642 3643 \sa scale(), setTransformOriginPoint(), {Transformations} 3644 */ 3645 void QGraphicsItem::setScale(qreal factor) 3646 { 3647 prepareGeometryChange(); 3648 if (!d_ptr->transformData) 3649 d_ptr->transformData = new QGraphicsItemPrivate::TransformData; 3650 d_ptr->transformData->scale = factor; 3651 d_ptr->transformData->onlyTransform = false; 3652 d_ptr->dirtySceneTransform = 1; 3653 3654 if (d_ptr->isObject) 3655 emit static_cast<QGraphicsObject *>(this)->scaleChanged(); 3656 } 3657 3658 3659 /*! 3660 \since 4.6 3661 3662 Returns a list of graphics transforms that currently apply to this item. 3663 3664 QGraphicsTransform is for applying and controlling a chain of individual 3665 transformation operations on an item. It's particularily useful in 3666 animations, where each transform operation needs to be interpolated 3667 independently, or differently. 3668 3669 The transformations are combined with the item's rotation(), scale() and 3670 transform() to map the item's coordinate system to the parent item. 3671 3672 \sa scale(), rotation(), transformOriginPoint(), {Transformations} 3673 */ 3674 QList<QGraphicsTransform *> QGraphicsItem::transformations() const 3675 { 3676 if (!d_ptr->transformData) 3677 return QList<QGraphicsTransform *>(); 3678 return d_ptr->transformData->graphicsTransforms; 3679 } 3680 3681 /*! 3682 \since 4.6 3683 3684 Sets a list of graphics \a transformations (QGraphicsTransform) that 3685 currently apply to this item. 3686 3687 If all you want is to rotate or scale an item, you should call setRotation() 3688 or setScale() instead. If you want to set an arbitrary transformation on 3689 an item, you can call setTransform(). 3690 3691 QGraphicsTransform is for applying and controlling a chain of individual 3692 transformation operations on an item. It's particularily useful in 3693 animations, where each transform operation needs to be interpolated 3694 independently, or differently. 3695 3696 The transformations are combined with the item's rotation(), scale() and 3697 transform() to map the item's coordinate system to the parent item. 3698 3699 \sa scale(), setTransformOriginPoint(), {Transformations} 3700 */ 3701 void QGraphicsItem::setTransformations(const QList<QGraphicsTransform *> &transformations) 3702 { 3703 prepareGeometryChange(); 3704 if (!d_ptr->transformData) 3705 d_ptr->transformData = new QGraphicsItemPrivate::TransformData; 3706 d_ptr->transformData->graphicsTransforms = transformations; 3707 for (int i = 0; i < transformations.size(); ++i) 3708 transformations.at(i)->d_func()->setItem(this); 3709 d_ptr->transformData->onlyTransform = false; 3710 d_ptr->dirtySceneTransform = 1; 3711 } 3712 3713 /*! 3714 \internal 3715 */ 3716 void QGraphicsItemPrivate::appendGraphicsTransform(QGraphicsTransform *t) 3717 { 3718 if (!transformData) 3719 transformData = new QGraphicsItemPrivate::TransformData; 3720 if (!transformData->graphicsTransforms.contains(t)) 3721 transformData->graphicsTransforms.append(t); 3722 3723 Q_Q(QGraphicsItem); 3724 t->d_func()->setItem(q); 3725 transformData->onlyTransform = false; 3726 dirtySceneTransform = 1; 3727 } 3728 3729 /*! 3730 \since 4.6 3731 3732 Returns the origin point for the transformation in item coordinates. 3733 3734 The default is QPointF(0,0). 3735 3736 \sa setTransformOriginPoint(), {Transformations} 3737 */ 3738 QPointF QGraphicsItem::transformOriginPoint() const 3739 { 3740 if (!d_ptr->transformData) 3741 return QPointF(0,0); 3742 return QPointF(d_ptr->transformData->xOrigin, d_ptr->transformData->yOrigin); 3743 } 3744 3745 /*! 3746 \since 4.6 3747 3748 Sets the \a origin point for the transformation in item coordinates. 3749 3750 \sa transformOriginPoint(), {Transformations} 3751 */ 3752 void QGraphicsItem::setTransformOriginPoint(const QPointF &origin) 3753 { 3754 prepareGeometryChange(); 3755 if (!d_ptr->transformData) 3756 d_ptr->transformData = new QGraphicsItemPrivate::TransformData; 3757 d_ptr->transformData->xOrigin = origin.x(); 3758 d_ptr->transformData->yOrigin = origin.y(); 3759 d_ptr->transformData->onlyTransform = false; 3760 d_ptr->dirtySceneTransform = 1; 3761 } 3762 3763 /*! 3764 \fn void QGraphicsItem::setTransformOriginPoint(qreal x, qreal y) 3765 3766 \since 4.6 3767 \overload 3768 3769 Sets the origin point for the transformation in item coordinates. 3770 This is equivalent to calling setTransformOriginPoint(QPointF(\a x, \a y)). 3771 3772 \sa setTransformOriginPoint(), {Transformations} 3773 */ 3774 2476 3775 2477 3776 /*! … … 2484 3783 QMatrix QGraphicsItem::sceneMatrix() const 2485 3784 { 2486 return sceneTransform().toAffine(); 3785 d_ptr->ensureSceneTransform(); 3786 return d_ptr->sceneTransform.toAffine(); 2487 3787 } 2488 3788 … … 2501 3801 2502 3802 Unlike transform(), which returns only an item's local transformation, this 2503 function includes the item's (and any parents') position .2504 2505 \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System} 3803 function includes the item's (and any parents') position, and all the transfomation properties. 3804 3805 \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}, {Transformations} 2506 3806 */ 2507 3807 QTransform QGraphicsItem::sceneTransform() const 2508 3808 { 2509 // Check if there's any entry in the transform cache. 2510 QGraphicsScenePrivate *sd = d_ptr->scene ? d_ptr->scene->d_func() : 0; 2511 int index = d_ptr->sceneTransformIndex; 2512 if (sd && index != -1 && sd->validTransforms.testBit(index)) 2513 return sd->sceneTransformCache[index]; 2514 2515 // Calculate local transform. 2516 QTransform m; 2517 if (d_ptr->hasTransform) { 2518 m = transform(); 2519 if (!d_ptr->pos.isNull()) 2520 m *= QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y()); 2521 } else if (!d_ptr->pos.isNull()) { 2522 m = QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y()); 2523 } 2524 2525 // Combine with parent and add to cache. 2526 if (d_ptr->parent) { 2527 m *= d_ptr->parent->sceneTransform(); 2528 // Don't cache toplevels 2529 if (sd) { 2530 if (index == -1) { 2531 if (!sd->freeSceneTransformSlots.isEmpty()) { 2532 index = sd->freeSceneTransformSlots.last(); 2533 sd->freeSceneTransformSlots.pop_back(); 2534 } else { 2535 index = sd->sceneTransformCache.size(); 2536 } 2537 d_ptr->sceneTransformIndex = index; 2538 if (index >= sd->validTransforms.size()) { 2539 sd->validTransforms.resize(index + 1); 2540 sd->sceneTransformCache.resize(index + 1); 2541 } 2542 } 2543 sd->validTransforms.setBit(index, 1); 2544 sd->sceneTransformCache[index] = m; 2545 } 2546 } 2547 return m; 3809 d_ptr->ensureSceneTransform(); 3810 return d_ptr->sceneTransform; 2548 3811 } 2549 3812 … … 2573 3836 QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) const 2574 3837 { 3838 // Ensure we return the standard transform if we're not untransformable. 3839 if (!d_ptr->itemIsUntransformable()) { 3840 d_ptr->ensureSceneTransform(); 3841 return d_ptr->sceneTransform * viewportTransform; 3842 } 3843 2575 3844 // Find the topmost item that ignores view transformations. 2576 3845 const QGraphicsItem *untransformedAncestor = this; … … 2590 3859 2591 3860 // First translate the base untransformable item. 2592 QPointF mappedPoint = (untransformedAncestor->sceneTransform() * viewportTransform).map(QPointF(0, 0)); 2593 QTransform matrix; 2594 matrix.translate(mappedPoint.x(), mappedPoint.y()); 2595 matrix = untransformedAncestor->transform() * matrix; 3861 untransformedAncestor->d_ptr->ensureSceneTransform(); 3862 QPointF mappedPoint = (untransformedAncestor->d_ptr->sceneTransform * viewportTransform).map(QPointF(0, 0)); 3863 3864 // COMBINE 3865 QTransform matrix = QTransform::fromTranslate(mappedPoint.x(), mappedPoint.y()); 3866 if (untransformedAncestor->d_ptr->transformData) 3867 matrix = untransformedAncestor->d_ptr->transformData->computedFullTransform(&matrix); 2596 3868 2597 3869 // Then transform and translate all children. 2598 3870 for (int i = 0; i < parents.size(); ++i) { 2599 3871 const QGraphicsItem *parent = parents.at(i); 2600 QPointF pos = parent->pos(); 2601 QTransform moveMatrix; 2602 moveMatrix.translate(pos.x(), pos.y()); 2603 matrix = (parent->transform() * moveMatrix) * matrix; 3872 parent->d_ptr->combineTransformFromParent(&matrix); 2604 3873 } 2605 3874 … … 2644 3913 if (ok) 2645 3914 *ok = true; 2646 const QPointF &itemPos = d_ptr->pos; 2647 if (itemPos.isNull()) 2648 return d_ptr->hasTransform ? transform() : QTransform(); 2649 if (d_ptr->hasTransform) 2650 return transform() * QTransform::fromTranslate(itemPos.x(), itemPos.y()); 2651 return QTransform::fromTranslate(itemPos.x(), itemPos.y()); 3915 QTransform x; 3916 d_ptr->combineTransformFromParent(&x); 3917 return x; 2652 3918 } 2653 3919 … … 2655 3921 if (otherParent == this) { 2656 3922 const QPointF &otherPos = other->d_ptr->pos; 2657 if (other->d_ptr->hasTransform) { 2658 QTransform otherToParent = other->transform(); 2659 if (!otherPos.isNull()) 2660 otherToParent *= QTransform::fromTranslate(otherPos.x(), otherPos.y()); 3923 if (other->d_ptr->transformData) { 3924 QTransform otherToParent; 3925 other->d_ptr->combineTransformFromParent(&otherToParent); 2661 3926 return otherToParent.inverted(ok); 2662 } else {2663 if (ok)2664 *ok = true;2665 return QTransform::fromTranslate(-otherPos.x(), -otherPos.y());2666 3927 } 3928 if (ok) 3929 *ok = true; 3930 return QTransform::fromTranslate(-otherPos.x(), -otherPos.y()); 2667 3931 } 2668 3932 2669 3933 // Siblings 2670 3934 if (parent == otherParent) { 2671 bool hasTr = d_ptr->hasTransform; 2672 bool otherHasTr = other->d_ptr->hasTransform; 3935 // COMBINE 2673 3936 const QPointF &itemPos = d_ptr->pos; 2674 3937 const QPointF &otherPos = other->d_ptr->pos; 2675 2676 if (!hasTr && !otherHasTr) { 3938 if (!d_ptr->transformData && !other->d_ptr->transformData) { 2677 3939 QPointF delta = itemPos - otherPos; 2678 3940 if (ok) … … 2681 3943 } 2682 3944 2683 QTransform itemToParent = QTransform::fromTranslate(itemPos.x(), itemPos.y()); 2684 if (hasTr) 2685 itemToParent = itemPos.isNull() ? transform() : transform() * itemToParent; 2686 2687 QTransform otherToParent = QTransform::fromTranslate(otherPos.x(), otherPos.y()); 2688 if (otherHasTr) 2689 otherToParent = otherPos.isNull() ? other->transform() : other->transform() * otherToParent; 2690 3945 QTransform itemToParent; 3946 d_ptr->combineTransformFromParent(&itemToParent); 3947 QTransform otherToParent; 3948 other->d_ptr->combineTransformFromParent(&otherToParent); 2691 3949 return itemToParent * otherToParent.inverted(ok); 2692 3950 } … … 2695 3953 // ancestor, then the only way is to combine their scene transforms. 2696 3954 const QGraphicsItem *commonAncestor = commonAncestorItem(other); 2697 if (!commonAncestor) 2698 return sceneTransform() * other->sceneTransform().inverted(ok); 3955 if (!commonAncestor) { 3956 d_ptr->ensureSceneTransform(); 3957 other->d_ptr->ensureSceneTransform(); 3958 return d_ptr->sceneTransform * other->d_ptr->sceneTransform.inverted(ok); 3959 } 2699 3960 2700 3961 // If the two items are cousins (in sibling branches), map both to the … … 2703 3964 if (cousins) { 2704 3965 bool good = false; 2705 QTransform thisToScene; 2706 QTransform otherToScene; 2707 thisToScene = itemTransform(commonAncestor, &good); 3966 QTransform thisToScene = itemTransform(commonAncestor, &good); 3967 QTransform otherToScene(Qt::Uninitialized); 2708 3968 if (good) 2709 3969 otherToScene = other->itemTransform(commonAncestor, &good); … … 2724 3984 const QGraphicsItem *p = child; 2725 3985 do { 2726 const QGraphicsItemPrivate *pd = p->d_ptr; 2727 if (pd->hasTransform) 2728 x *= p->transform(); 2729 if (!pd->pos.isNull()) 2730 x *= QTransform::fromTranslate(pd->pos.x(), pd->pos.y()); 3986 p->d_ptr.data()->combineTransformToParent(&x); 2731 3987 } while ((p = p->d_ptr->parent) && p != root); 2732 3988 if (parentOfOther) … … 2746 4002 Use setTransform() instead. 2747 4003 2748 \sa transform(), rotate(), scale(), shear(), translate(),{The Graphics View Coordinate System}4004 \sa transform(), {The Graphics View Coordinate System} 2749 4005 */ 2750 4006 void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) 2751 4007 { 2752 QTransform oldTransform = this->transform(); 2753 QTransform newTransform; 2754 if (!combine) 2755 newTransform = QTransform(matrix); 2756 else 2757 newTransform = QTransform(matrix) * oldTransform; 2758 if (oldTransform == newTransform) 4008 if (!d_ptr->transformData) 4009 d_ptr->transformData = new QGraphicsItemPrivate::TransformData; 4010 4011 QTransform newTransform(combine ? QTransform(matrix) * d_ptr->transformData->transform : QTransform(matrix)); 4012 if (d_ptr->transformData->transform == newTransform) 2759 4013 return; 2760 4014 2761 // Notify the item that the matrix is changing. 2762 QVariant newTransformVariant(itemChange(ItemMatrixChange, 2763 qVariantFromValue<QMatrix>(newTransform.toAffine()))); 2764 newTransform = QTransform(qVariantValue<QMatrix>(newTransformVariant)); 2765 if (oldTransform == newTransform) 4015 // Update and set the new transformation. 4016 if (!(d_ptr->flags & ItemSendsGeometryChanges)) { 4017 d_ptr->setTransformHelper(newTransform); 2766 4018 return; 4019 } 4020 4021 // Notify the item that the transformation matrix is changing. 4022 const QVariant newMatrixVariant = qVariantFromValue<QMatrix>(newTransform.toAffine()); 4023 newTransform = QTransform(qVariantValue<QMatrix>(itemChange(ItemMatrixChange, newMatrixVariant))); 4024 if (d_ptr->transformData->transform == newTransform) 4025 return; 2767 4026 2768 4027 // Update and set the new transformation. 2769 d_ptr->fullUpdateHelper(true, true); 2770 prepareGeometryChange(); 2771 d_ptr->hasTransform = !newTransform.isIdentity(); 2772 d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); 2773 d_ptr->invalidateSceneTransformCache(); 4028 d_ptr->setTransformHelper(newTransform); 2774 4029 2775 4030 // Send post-notification. 2776 // NB! We have to change the value from QMatrix to QTransform. 2777 qVariantSetValue<QTransform>(newTransformVariant, newTransform); 2778 itemChange(ItemTransformHasChanged, newTransformVariant); 4031 itemChange(ItemTransformHasChanged, qVariantFromValue<QTransform>(newTransform)); 2779 4032 } 2780 4033 … … 2794 4047 from scene coordinates to item coordinates. 2795 4048 2796 \sa transform(), rotate(), scale(), shear(), translate(), {The Graphics View Coordinate System} 4049 The transformation matrix is combined with the item's rotation(), scale() 4050 and transformations() into a combined transformation that maps the item's 4051 coordinate system to its parent. 4052 4053 \sa transform(), setRotation(), setScale(), setTransformOriginPoint(), {The Graphics View Coordinate System}, {Transformations} 2797 4054 */ 2798 4055 void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) 2799 4056 { 2800 QTransform oldTransform = this->transform(); 2801 QTransform newTransform; 2802 if (!combine) 2803 newTransform = matrix; 2804 else 2805 newTransform = matrix * oldTransform; 2806 if (oldTransform == newTransform) 4057 if (!d_ptr->transformData) 4058 d_ptr->transformData = new QGraphicsItemPrivate::TransformData; 4059 4060 QTransform newTransform(combine ? matrix * d_ptr->transformData->transform : matrix); 4061 if (d_ptr->transformData->transform == newTransform) 2807 4062 return; 4063 4064 // Update and set the new transformation. 4065 if (!(d_ptr->flags & ItemSendsGeometryChanges)) { 4066 d_ptr->setTransformHelper(newTransform); 4067 return; 4068 } 2808 4069 2809 4070 // Notify the item that the transformation matrix is changing. … … 2811 4072 qVariantFromValue<QTransform>(newTransform))); 2812 4073 newTransform = qVariantValue<QTransform>(newTransformVariant); 2813 if ( oldTransform == newTransform)4074 if (d_ptr->transformData->transform == newTransform) 2814 4075 return; 2815 4076 2816 4077 // Update and set the new transformation. 2817 d_ptr->fullUpdateHelper(true, true); 2818 prepareGeometryChange(); 2819 d_ptr->hasTransform = !newTransform.isIdentity(); 2820 d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); 2821 d_ptr->invalidateSceneTransformCache(); 4078 d_ptr->setTransformHelper(newTransform); 2822 4079 2823 4080 // Send post-notification. 2824 4081 itemChange(ItemTransformHasChanged, newTransformVariant); 4082 d_ptr->sendScenePosChange(); 2825 4083 } 2826 4084 … … 2838 4096 \since 4.3 2839 4097 2840 Resets this item's transformation matrix to the identity matrix. This is 2841 equivalent to calling \c setTransform(QTransform()). 4098 Resets this item's transformation matrix to the identity matrix or 4099 all the transformation properties to their default values. 4100 This is equivalent to calling \c setTransform(QTransform()). 2842 4101 2843 4102 \sa setTransform(), transform() … … 2849 4108 2850 4109 /*! 4110 \obsolete 4111 4112 Use 4113 4114 \code 4115 setRotation(rotation() + angle); 4116 \endcode 4117 4118 instead. 4119 2851 4120 Rotates the current item transformation \a angle degrees clockwise around 2852 4121 its origin. To translate around an arbitrary point (x, y), you need to … … 2865 4134 2866 4135 /*! 4136 \obsolete 4137 4138 Use 4139 4140 \code 4141 setTransform(QTransform::fromScale(sx, sy), true); 4142 \endcode 4143 4144 instead. 4145 2867 4146 Scales the current item transformation by (\a sx, \a sy) around its 2868 4147 origin. To scale from an arbitrary point (x, y), you need to combine … … 2873 4152 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 7 2874 4153 2875 \sa setTransform(), transform() , rotate(), shear(), translate()4154 \sa setTransform(), transform() 2876 4155 */ 2877 4156 void QGraphicsItem::scale(qreal sx, qreal sy) … … 2881 4160 2882 4161 /*! 4162 \obsolete 4163 4164 Use 4165 4166 \code 4167 setTransform(QTransform().shear(sh, sv), true); 4168 \endcode 4169 4170 instead. 4171 2883 4172 Shears the current item transformation by (\a sh, \a sv). 2884 4173 2885 \sa setTransform(), transform() , rotate(), scale(), translate()4174 \sa setTransform(), transform() 2886 4175 */ 2887 4176 void QGraphicsItem::shear(qreal sh, qreal sv) … … 2891 4180 2892 4181 /*! 4182 \obsolete 4183 4184 Use setPos() or setTransformOriginPoint() instead. For identical 4185 behavior, use 4186 4187 \code 4188 setTransform(QTransform::fromTranslate(dx, dy), true); 4189 \endcode 4190 2893 4191 Translates the current item transformation by (\a dx, \a dy). 2894 4192 … … 2897 4195 which is conceptually separate from its position. 2898 4196 2899 \sa setTransform(), transform() , rotate(), scale(), shear()4197 \sa setTransform(), transform() 2900 4198 */ 2901 4199 void QGraphicsItem::translate(qreal dx, qreal dy) … … 2927 4225 2928 4226 /*! 2929 Returns the Z-value , or the elevation, of the item. The Z-value decides2930 the stacking order ofsibling (neighboring) items.4227 Returns the Z-value of the item. The Z-value affects the stacking order of 4228 sibling (neighboring) items. 2931 4229 2932 4230 The default Z-value is 0. 2933 4231 2934 \sa setZValue() 4232 \sa setZValue(), {QGraphicsItem#Sorting}{Sorting}, stackBefore(), ItemStacksBehindParent 2935 4233 */ 2936 4234 qreal QGraphicsItem::zValue() const … … 2940 4238 2941 4239 /*! 2942 Sets the Z-value, or the elevation, of the item, to \a z. The elevation 2943 decides the stacking order of sibling (neighboring) items. An item of high 2944 Z-value will be drawn on top of an item with a lower Z-value if they 2945 share the same parent item. In addition, children of an item will always be drawn 2946 on top of the parent, regardless of the child's Z-value. Sibling items 2947 that share the same Z-value will be drawn in an undefined order, although 2948 the order will stay the same for as long as the items live. 2949 2950 \img graphicsview-zorder.png 2951 2952 Children of different parents are stacked according to the Z-value of 2953 each item's ancestor item which is an immediate child of the two 2954 items' closest common ancestor. For example, a robot item might 2955 define a torso item as the parent of a head item, two arm items, 2956 and two upper-leg items. The upper-leg items would each be parents 2957 of one lower-leg item, and each lower-leg item would be parents of 2958 one foot item. The stacking order of the feet is the same as the 2959 stacking order of each foot's ancestor that is an immediate child 2960 of the two feet's common ancestor (i.e., the torso item); so the 2961 feet are stacked in the same order as the upper-leg items, 2962 regardless of each foot's Z-value. 4240 Sets the Z-value of the item to \a z. The Z value decides the stacking 4241 order of sibling (neighboring) items. A sibling item of high Z value will 4242 always be drawn on top of another sibling item with a lower Z value. 4243 4244 If you restore the Z value, the item's insertion order will decide its 4245 stacking order. 2963 4246 2964 4247 The Z-value does not affect the item's size in any way. … … 2966 4249 The default Z-value is 0. 2967 4250 2968 \sa zValue() 4251 \sa zValue(), {QGraphicsItem#Sorting}{Sorting}, stackBefore(), ItemStacksBehindParent 2969 4252 */ 2970 4253 void QGraphicsItem::setZValue(qreal z) 2971 4254 { 2972 const QVariant newZVariant(itemChange(ItemZValueChange, double(z)));2973 qreal newZ = qreal(newZVariant.toDouble());4255 const QVariant newZVariant(itemChange(ItemZValueChange, z)); 4256 qreal newZ = newZVariant.toReal(); 2974 4257 if (newZ == d_ptr->z) 2975 4258 return; 2976 d_ptr->z = z;2977 d_ptr->fullUpdateHelper();2978 4259 2979 4260 if (d_ptr->scene) { 2980 // Invalidate any sort caching; arrival of a new item means we need to 2981 // resort. 2982 d_ptr->scene->d_func()->invalidateSortCache(); 2983 } 4261 // Z Value has changed, we have to notify the index. 4262 d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, newZVariant); 4263 } 4264 4265 d_ptr->z = newZ; 4266 if (d_ptr->parent) 4267 d_ptr->parent->d_ptr->needSortChildren = 1; 4268 else if (d_ptr->scene) 4269 d_ptr->scene->d_func()->needSortTopLevelItems = 1; 4270 4271 if (d_ptr->scene) 4272 d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true); 2984 4273 2985 4274 itemChange(ItemZValueHasChanged, newZVariant); 4275 4276 if (d_ptr->flags & ItemNegativeZStacksBehindParent) 4277 setFlag(QGraphicsItem::ItemStacksBehindParent, z < qreal(0.0)); 4278 4279 if (d_ptr->isObject) 4280 emit static_cast<QGraphicsObject *>(this)->zChanged(); 4281 } 4282 4283 /*! 4284 \internal 4285 4286 Ensures that the list of children is sorted by insertion order, and that 4287 the siblingIndexes are packed (no gaps), and start at 0. 4288 4289 ### This function is almost identical to 4290 QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes(). 4291 */ 4292 void QGraphicsItemPrivate::ensureSequentialSiblingIndex() 4293 { 4294 if (!sequentialOrdering) { 4295 qSort(children.begin(), children.end(), insertionOrder); 4296 sequentialOrdering = 1; 4297 needSortChildren = 1; 4298 } 4299 if (holesInSiblingIndex) { 4300 holesInSiblingIndex = 0; 4301 for (int i = 0; i < children.size(); ++i) 4302 children[i]->d_ptr->siblingIndex = i; 4303 } 4304 } 4305 4306 /*! 4307 \internal 4308 */ 4309 inline void QGraphicsItemPrivate::sendScenePosChange() 4310 { 4311 Q_Q(QGraphicsItem); 4312 if (scene) { 4313 if (flags & QGraphicsItem::ItemSendsScenePositionChanges) 4314 q->itemChange(QGraphicsItem::ItemScenePositionHasChanged, q->scenePos()); 4315 if (scenePosDescendants) { 4316 foreach (QGraphicsItem *item, scene->d_func()->scenePosItems) { 4317 if (q->isAncestorOf(item)) 4318 item->itemChange(QGraphicsItem::ItemScenePositionHasChanged, item->scenePos()); 4319 } 4320 } 4321 } 4322 } 4323 4324 /*! 4325 \since 4.6 4326 4327 Stacks this item before \a sibling, which must be a sibling item (i.e., the 4328 two items must share the same parent item, or must both be toplevel items). 4329 The \a sibling must have the same Z value as this item, otherwise calling 4330 this function will have no effect. 4331 4332 By default, all sibling items are stacked by insertion order (i.e., the 4333 first item you add is drawn before the next item you add). If two items' Z 4334 values are different, then the item with the highest Z value is drawn on 4335 top. When the Z values are the same, the insertion order will decide the 4336 stacking order. 4337 4338 \sa setZValue(), ItemStacksBehindParent, {QGraphicsItem#Sorting}{Sorting} 4339 */ 4340 void QGraphicsItem::stackBefore(const QGraphicsItem *sibling) 4341 { 4342 if (sibling == this) 4343 return; 4344 if (!sibling || d_ptr->parent != sibling->parentItem()) { 4345 qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling); 4346 return; 4347 } 4348 QList<QGraphicsItem *> *siblings = d_ptr->parent 4349 ? &d_ptr->parent->d_ptr->children 4350 : (d_ptr->scene ? &d_ptr->scene->d_func()->topLevelItems : 0); 4351 if (!siblings) { 4352 qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling); 4353 return; 4354 } 4355 4356 // First, make sure that the sibling indexes have no holes. This also 4357 // marks the children list for sorting. 4358 if (d_ptr->parent) 4359 d_ptr->parent->d_ptr->ensureSequentialSiblingIndex(); 4360 else 4361 d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes(); 4362 4363 // Only move items with the same Z value, and that need moving. 4364 int siblingIndex = sibling->d_ptr->siblingIndex; 4365 int myIndex = d_ptr->siblingIndex; 4366 if (myIndex >= siblingIndex) { 4367 siblings->move(myIndex, siblingIndex); 4368 // Fixup the insertion ordering. 4369 for (int i = 0; i < siblings->size(); ++i) { 4370 int &index = siblings->at(i)->d_ptr->siblingIndex; 4371 if (i != siblingIndex && index >= siblingIndex && index <= myIndex) 4372 ++index; 4373 } 4374 d_ptr->siblingIndex = siblingIndex; 4375 for (int i = 0; i < siblings->size(); ++i) { 4376 int &index = siblings->at(i)->d_ptr->siblingIndex; 4377 if (i != siblingIndex && index >= siblingIndex && index <= myIndex) 4378 siblings->at(i)->d_ptr->siblingOrderChange(); 4379 } 4380 d_ptr->siblingOrderChange(); 4381 } 2986 4382 } 2987 4383 … … 3005 4401 QRectF QGraphicsItem::childrenBoundingRect() const 3006 4402 { 3007 QRectF childRect; 3008 foreach (QGraphicsItem *child, children()) { 3009 QPointF childPos = child->pos(); 3010 QTransform matrix = child->transform(); 3011 if (!childPos.isNull()) 3012 matrix *= QTransform::fromTranslate(childPos.x(), childPos.y()); 3013 childRect |= matrix.mapRect(child->boundingRect() | child->childrenBoundingRect()); 3014 } 3015 return childRect; 4403 if (!d_ptr->dirtyChildrenBoundingRect) 4404 return d_ptr->childrenBoundingRect; 4405 4406 d_ptr->childrenBoundingRect = QRectF(); 4407 d_ptr->childrenBoundingRectHelper(0, &d_ptr->childrenBoundingRect); 4408 d_ptr->dirtyChildrenBoundingRect = 0; 4409 return d_ptr->childrenBoundingRect; 3016 4410 } 3017 4411 … … 3026 4420 Although the item's shape can be arbitrary, the bounding rect is 3027 4421 always rectangular, and it is unaffected by the items' 3028 transformation (scale(), rotate(), etc.).4422 transformation. 3029 4423 3030 4424 If you want to change the item's bounding rectangle, you must first call … … 3058 4452 { 3059 4453 // Find translate-only offset 4454 // COMBINE 3060 4455 QPointF offset; 3061 4456 const QGraphicsItem *parentItem = this; 3062 4457 const QGraphicsItemPrivate *itemd; 3063 4458 do { 3064 itemd = parentItem->d_ptr ;3065 if (itemd-> hasTransform)4459 itemd = parentItem->d_ptr.data(); 4460 if (itemd->transformData) 3066 4461 break; 3067 4462 offset += itemd->pos; … … 3070 4465 QRectF br = boundingRect(); 3071 4466 br.translate(offset); 3072 return !parentItem ? br : parentItem->sceneTransform().mapRect(br); 4467 if (!parentItem) 4468 return br; 4469 if (parentItem->d_ptr->hasTranslateOnlySceneTransform()) { 4470 br.translate(parentItem->d_ptr->sceneTransform.dx(), parentItem->d_ptr->sceneTransform.dy()); 4471 return br; 4472 } 4473 return parentItem->d_ptr->sceneTransform.mapRect(br); 3073 4474 } 3074 4475 … … 3142 4543 { 3143 4544 Q_D(const QGraphicsItem); 3144 if (!d->dirtyClipPath) 3145 return d->emptyClipPath ? QPainterPath() : d->cachedClipPath; 3146 3147 if (!isClipped()) { 3148 d_ptr->setCachedClipPath(QPainterPath()); 3149 return d->cachedClipPath; 3150 } 4545 if (!isClipped()) 4546 return QPainterPath(); 3151 4547 3152 4548 const QRectF thisBoundingRect(boundingRect()); 3153 if (thisBoundingRect.isEmpty()) { 3154 if (d_ptr->flags & ItemClipsChildrenToShape) 3155 d_ptr->setEmptyCachedClipPathRecursively(); 3156 else 3157 d_ptr->setEmptyCachedClipPath(); 4549 if (thisBoundingRect.isEmpty()) 3158 4550 return QPainterPath(); 3159 }3160 4551 3161 4552 QPainterPath clip; … … 3168 4559 3169 4560 // Intersect any in-between clips starting at the top and moving downwards. 3170 bool foundValidClipPath = false;3171 4561 while ((parent = parent->d_ptr->parent)) { 3172 4562 if (parent->d_ptr->flags & ItemClipsChildrenToShape) { 3173 4563 // Map clip to the current parent and intersect with its shape/clipPath 3174 4564 clip = lastParent->itemTransform(parent).map(clip); 3175 if ((foundValidClipPath = !parent->d_ptr->dirtyClipPath && parent->isClipped())) { 3176 if (parent->d_ptr->emptyClipPath) { 3177 if (d_ptr->flags & ItemClipsChildrenToShape) 3178 d_ptr->setEmptyCachedClipPathRecursively(); 3179 else 3180 d_ptr->setEmptyCachedClipPath(); 3181 return QPainterPath(); 3182 } 3183 clip = clip.intersected(parent->d_ptr->cachedClipPath); 3184 if (!(parent->d_ptr->flags & ItemClipsToShape)) 3185 clip = clip.intersected(parent->shape()); 3186 } else { 3187 clip = clip.intersected(parent->shape()); 3188 } 3189 3190 if (clip.isEmpty()) { 3191 if (d_ptr->flags & ItemClipsChildrenToShape) 3192 d_ptr->setEmptyCachedClipPathRecursively(); 3193 else 3194 d_ptr->setEmptyCachedClipPath(); 4565 clip = clip.intersected(parent->shape()); 4566 if (clip.isEmpty()) 3195 4567 return clip; 3196 }3197 4568 lastParent = parent; 3198 4569 } 3199 4570 3200 if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) 3201 || foundValidClipPath) { 4571 if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) 3202 4572 break; 3203 }3204 4573 } 3205 4574 … … 3214 4583 clip = clip.intersected(shape()); 3215 4584 3216 d_ptr->setCachedClipPath(clip);3217 4585 return clip; 3218 4586 } … … 3236 4604 3237 4605 /*! 3238 Returns true if this item collides with \a other; otherwise returns false. 3239 The ways items collide is determined by \a mode. The default value for \a 3240 mode is Qt::IntersectsItemShape; \a other collides with this item if it 3241 either intersects, contains, or is contained by this item's shape. 4606 4607 Returns true if this item collides with \a other; otherwise 4608 returns false. 4609 4610 The \a mode is applied to \a other, and the resulting shape or 4611 bounding rectangle is then compared to this item's shape. The 4612 default value for \a mode is Qt::IntersectsItemShape; \a other 4613 collides with this item if it either intersects, contains, or is 4614 contained by this item's shape (see Qt::ItemSelectionMode for 4615 details). 3242 4616 3243 4617 The default implementation is based on shape intersection, and it calls … … 3294 4668 intersects, contains, or is contained by this item's shape. 3295 4669 4670 Note that this function checks whether the item's shape or 4671 bounding rectangle (depending on \a mode) is contained within \a 4672 path, and not whether \a path is contained within the items shape 4673 or bounding rectangle. 4674 3296 4675 \sa collidesWithItem(), contains(), shape() 3297 4676 */ … … 3334 4713 Returns a list of all items that collide with this item. 3335 4714 3336 The way collisions are detected is determined by \a mode. The default 3337 value for \a mode is Qt::IntersectsItemShape; All items whose shape 3338 intersects or is contained by this item's shape are returned. 3339 3340 \sa QGraphicsScene::collidingItems(), collidesWithItem() 4715 The way collisions are detected is determined by applying \a mode 4716 to items that are compared to this item, i.e., each item's shape 4717 or bounding rectangle is checked against this item's shape. The 4718 default value for \a mode is Qt::IntersectsItemShape. 4719 4720 \sa collidesWithItem() 3341 4721 */ 3342 4722 QList<QGraphicsItem *> QGraphicsItem::collidingItems(Qt::ItemSelectionMode mode) const … … 3433 4813 if (!item) 3434 4814 return false; 3435 return QGraphicsScenePrivate::closestItemFirst_withoutCache(item, this)4815 return qt_closestItemFirst(item, this) 3436 4816 && qt_QGraphicsItem_isObscured(this, item, boundingRect()); 3437 4817 } … … 3518 4898 3519 4899 // Transform QRegion back to device space 3520 QTransform unscale; 3521 unscale.scale(1 / granularity, 1 / granularity); 4900 QTransform unscale = QTransform::fromScale(1 / granularity, 1 / granularity); 3522 4901 QRegion r; 3523 4902 QBitmap colorMask = QBitmap::fromImage(mask.createMaskFromColor(0)); … … 3615 4994 All painting is done in local coordinates. 3616 4995 3617 \sa setCacheMode(), QPen::width(), {Item Coordinates} 4996 \sa setCacheMode(), QPen::width(), {Item Coordinates}, ItemUsesExtendedStyleOption 3618 4997 */ 3619 4998 … … 3622 5001 Returns true if we can discard an update request; otherwise false. 3623 5002 */ 3624 bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, 3625 bool ignoreVisibleBit, 3626 bool ignoreDirtyBit) const 5003 bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreVisibleBit, bool ignoreDirtyBit, 5004 bool ignoreOpacity) const 3627 5005 { 3628 5006 // No scene, or if the scene is updating everything, means we have nothing 3629 5007 // to do. The only exception is if the scene tracks the growing scene rect. 3630 return (!visible && !ignoreVisibleBit) 3631 || (dirty && !ignoreDirtyBit) 3632 || !scene 3633 || (scene->d_func()->updateAll && scene->d_func()->hasSceneRect) 3634 || (!ignoreClipping && (childrenClippedToShape() && isClippedAway())) 3635 || (childrenCombineOpacity() && isFullyTransparent()); 5008 return !scene 5009 || (!visible && !ignoreVisibleBit && !this->ignoreVisible) 5010 || (!ignoreDirtyBit && fullUpdatePending) 5011 || (!ignoreOpacity && !this->ignoreOpacity && childrenCombineOpacity() && isFullyTransparent()); 3636 5012 } 3637 5013 3638 5014 /*! 3639 5015 \internal 3640 3641 Asks the scene to mark this item's scene rect as dirty, requesting a 3642 redraw. This does not invalidate any cache. 3643 3644 The \a force argument is for the update call in setVisible(), which is the 3645 only case where the item's background should be marked as dirty even when 3646 the item isn't visible. 3647 */ 3648 void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force, bool maybeDirtyClipPath) 3649 { 3650 // No scene, or if the scene is updating everything, means we have nothing 3651 // to do. The only exception is if the scene tracks the growing scene rect. 3652 if (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/force)) 5016 */ 5017 int QGraphicsItemPrivate::depth() const 5018 { 5019 if (itemDepth == -1) 5020 const_cast<QGraphicsItemPrivate *>(this)->resolveDepth(); 5021 5022 return itemDepth; 5023 } 5024 5025 /*! 5026 \internal 5027 */ 5028 #ifndef QT_NO_GRAPHICSEFFECT 5029 void QGraphicsItemPrivate::invalidateGraphicsEffectsRecursively() 5030 { 5031 QGraphicsItemPrivate *itemPrivate = this; 5032 do { 5033 if (itemPrivate->graphicsEffect) { 5034 itemPrivate->notifyInvalidated = 1; 5035 5036 if (!itemPrivate->updateDueToGraphicsEffect) 5037 static_cast<QGraphicsItemEffectSourcePrivate *>(itemPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache(); 5038 } 5039 } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : 0)); 5040 } 5041 #endif //QT_NO_GRAPHICSEFFECT 5042 5043 /*! 5044 \internal 5045 */ 5046 void QGraphicsItemPrivate::invalidateDepthRecursively() 5047 { 5048 if (itemDepth == -1) 3653 5049 return; 3654 5050 3655 i f (rect.isNull())3656 dirty = 1;3657 scene->itemUpdated(q_ptr, rect);5051 itemDepth = -1; 5052 for (int i = 0; i < children.size(); ++i) 5053 children.at(i)->d_ptr->invalidateDepthRecursively(); 3658 5054 } 3659 5055 … … 3661 5057 \internal 3662 5058 3663 Propagates updates to \a item and all its children. 3664 */ 3665 void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly, bool maybeDirtyClipPath) 3666 { 3667 if (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, 3668 /*ignoreVisibleBit=*/false, 3669 /*ignoreDirtyBit=*/true)) { 3670 return; 3671 } 3672 3673 if (!childrenOnly && !dirty) { 3674 // Effectively the same as updateHelper(QRectF(), false, maybeDirtyClipPath). 3675 dirty = 1; 3676 scene->itemUpdated(q_ptr, QRectF()); 3677 } 3678 3679 if (dirtyChildren || childrenClippedToShape()) { 3680 // Unnecessary to update children as well. 3681 return; 3682 } 3683 3684 if (ancestorFlags & AncestorClipsChildren) { 3685 Q_Q(QGraphicsItem); 3686 // Check if we can avoid updating all children. 3687 QGraphicsItem *p = parent; 3688 QRectF br = q->boundingRect(); 3689 while (p) { 3690 if (p->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) { 3691 bool ok; 3692 QTransform x = q->itemTransform(p, &ok); 3693 if (!ok) 3694 break; 3695 if (x.mapRect(br).contains(p->boundingRect())) 3696 return; 3697 } 3698 p = p->d_ptr->parent; 3699 if (!p || !(p->d_ptr->ancestorFlags & AncestorClipsChildren)) 3700 break; 3701 // ### check one level only 3702 break; 3703 } 3704 } 3705 foreach (QGraphicsItem *child, children) 3706 child->d_ptr->fullUpdateHelper(false, maybeDirtyClipPath); 3707 dirtyChildren = 1; 3708 } 3709 3710 static inline bool qt_allChildrenCombineOpacity(QGraphicsItem *parent) 3711 { 3712 Q_ASSERT(parent); 3713 if (parent->flags() & QGraphicsItem::ItemDoesntPropagateOpacityToChildren) 3714 return false; 3715 3716 const QList<QGraphicsItem *> children(parent->childItems()); 3717 for (int i = 0; i < children.size(); ++i) { 3718 if (children.at(i)->flags() & QGraphicsItem::ItemIgnoresParentOpacity) 3719 return false; 3720 } 3721 return true; 3722 } 3723 3724 void QGraphicsItemPrivate::updateEffectiveOpacity() 3725 { 3726 Q_Q(QGraphicsItem); 3727 if (parent) { 3728 resolveEffectiveOpacity(parent->effectiveOpacity()); 3729 parent->d_ptr->allChildrenCombineOpacity = qt_allChildrenCombineOpacity(parent); 3730 } else { 3731 resolveEffectiveOpacity(1.0); 3732 } 3733 allChildrenCombineOpacity = qt_allChildrenCombineOpacity(q); 5059 Resolves the stacking depth of this object and all its ancestors. 5060 */ 5061 void QGraphicsItemPrivate::resolveDepth() 5062 { 5063 if (!parent) 5064 itemDepth = 0; 5065 else { 5066 if (parent->d_ptr->itemDepth == -1) 5067 parent->d_ptr->resolveDepth(); 5068 itemDepth = parent->d_ptr->itemDepth + 1; 5069 } 3734 5070 } 3735 5071 … … 3737 5073 \internal 3738 5074 3739 Resolves and propagates this item's effective opacity to its children. 3740 */ 3741 void QGraphicsItemPrivate::resolveEffectiveOpacity(qreal parentEffectiveOpacity) 3742 { 3743 Q_Q(QGraphicsItem); 3744 QGraphicsItem::GraphicsItemFlags myFlags = q->flags(); 3745 QGraphicsItem::GraphicsItemFlags parentFlags = parent ? parent->flags() : QGraphicsItem::GraphicsItemFlags(0); 3746 3747 // My local opacity is always part of my effective opacity. 3748 qreal myEffectiveOpacity = q->opacity(); 3749 3750 // If I have a parent, and I don't ignore my parent's opacity, and my 3751 // parent propagates to me, then combine my local opacity with my parent's 3752 // effective opacity into my effective opacity. 3753 if (parent 3754 && !(myFlags & QGraphicsItem::ItemIgnoresParentOpacity) 3755 && !(parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) { 3756 myEffectiveOpacity *= parentEffectiveOpacity; 3757 } 3758 3759 // Set this item's resolved opacity. 3760 if (qFuzzyCompare(myEffectiveOpacity, qreal(1.0))) { 3761 // Opaque, unset effective opacity. 3762 hasEffectiveOpacity = 0; 3763 unsetExtra(ExtraEffectiveOpacity); 3764 } else { 3765 hasEffectiveOpacity = 1; 3766 setExtra(ExtraEffectiveOpacity, myEffectiveOpacity); 3767 } 3768 3769 // Resolve children always. 3770 for (int i = 0; i < children.size(); ++i) 3771 children.at(i)->d_ptr->resolveEffectiveOpacity(myEffectiveOpacity); 5075 ### This function is almost identical to 5076 QGraphicsScenePrivate::registerTopLevelItem(). 5077 */ 5078 void QGraphicsItemPrivate::addChild(QGraphicsItem *child) 5079 { 5080 // Remove all holes from the sibling index list. Now the max index 5081 // number is equal to the size of the children list. 5082 ensureSequentialSiblingIndex(); 5083 needSortChildren = 1; // ### maybe 0 5084 child->d_ptr->siblingIndex = children.size(); 5085 children.append(child); 3772 5086 } 3773 5087 … … 3775 5089 \internal 3776 5090 3777 Resolves the stacking depth of this object and all its children. 3778 */ 3779 void QGraphicsItemPrivate::resolveDepth(int parentDepth) 3780 { 3781 depth = parentDepth + 1; 3782 for (int i = 0; i < children.size(); ++i) 3783 children.at(i)->d_ptr->resolveDepth(depth); 5091 ### This function is almost identical to 5092 QGraphicsScenePrivate::unregisterTopLevelItem(). 5093 */ 5094 void QGraphicsItemPrivate::removeChild(QGraphicsItem *child) 5095 { 5096 // When removing elements in the middle of the children list, 5097 // there will be a "gap" in the list of sibling indexes (0,1,3,4). 5098 if (!holesInSiblingIndex) 5099 holesInSiblingIndex = child->d_ptr->siblingIndex != children.size() - 1; 5100 if (sequentialOrdering && !holesInSiblingIndex) 5101 children.removeAt(child->d_ptr->siblingIndex); 5102 else 5103 children.removeOne(child); 5104 // NB! Do not use children.removeAt(child->d_ptr->siblingIndex) because 5105 // the child is not guaranteed to be at the index after the list is sorted. 5106 // (see ensureSortedChildren()). 5107 child->d_ptr->siblingIndex = -1; 3784 5108 } 3785 5109 … … 3787 5111 \internal 3788 5112 */ 3789 void QGraphicsItemPrivate::invalidateSceneTransformCache() 3790 { 3791 if (!scene || (parent && sceneTransformIndex == -1)) 3792 return; 3793 if (sceneTransformIndex != -1) 3794 scene->d_func()->validTransforms.setBit(sceneTransformIndex, 0); 3795 for (int i = 0; i < children.size(); ++i) 3796 children.at(i)->d_ptr->invalidateSceneTransformCache(); 3797 } 3798 5113 QGraphicsItemCache *QGraphicsItemPrivate::maybeExtraItemCache() const 5114 { 5115 return (QGraphicsItemCache *)qVariantValue<void *>(extra(ExtraCacheData)); 5116 } 5117 5118 /*! 5119 \internal 5120 */ 3799 5121 QGraphicsItemCache *QGraphicsItemPrivate::extraItemCache() const 3800 5122 { … … 3808 5130 } 3809 5131 5132 /*! 5133 \internal 5134 */ 3810 5135 void QGraphicsItemPrivate::removeExtraItemCache() 3811 5136 { … … 3818 5143 } 3819 5144 3820 void QGraphicsItemPrivate::setEmptyCachedClipPathRecursively(const QRectF &emptyIfOutsideThisRect) 3821 { 3822 setEmptyCachedClipPath(); 3823 3824 const bool checkRect = !emptyIfOutsideThisRect.isNull() 3825 && !(flags & QGraphicsItem::ItemClipsChildrenToShape); 3826 for (int i = 0; i < children.size(); ++i) { 3827 if (!checkRect) { 3828 children.at(i)->d_ptr->setEmptyCachedClipPathRecursively(); 3829 continue; 5145 // Traverses all the ancestors up to the top-level and updates the pointer to 5146 // always point to the top-most item that has a dirty scene transform. 5147 // It then backtracks to the top-most dirty item and start calculating the 5148 // scene transform by combining the item's transform (+pos) with the parent's 5149 // cached scene transform (which we at this point know for sure is valid). 5150 void QGraphicsItemPrivate::ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem) 5151 { 5152 Q_ASSERT(topMostDirtyItem); 5153 5154 if (dirtySceneTransform) 5155 *topMostDirtyItem = q_ptr; 5156 5157 if (parent) 5158 parent->d_ptr->ensureSceneTransformRecursive(topMostDirtyItem); 5159 5160 if (*topMostDirtyItem == q_ptr) { 5161 if (!dirtySceneTransform) 5162 return; // OK, neither my ancestors nor I have dirty scene transforms. 5163 *topMostDirtyItem = 0; 5164 } else if (*topMostDirtyItem) { 5165 return; // Continue backtrack. 5166 } 5167 5168 // This item and all its descendants have dirty scene transforms. 5169 // We're about to validate this item's scene transform, so we have to 5170 // invalidate all the children; otherwise there's no way for the descendants 5171 // to detect that the ancestor has changed. 5172 invalidateChildrenSceneTransform(); 5173 5174 // COMBINE my transform with the parent's scene transform. 5175 updateSceneTransformFromParent(); 5176 Q_ASSERT(!dirtySceneTransform); 5177 } 5178 5179 /*! 5180 \internal 5181 */ 5182 void QGraphicsItemPrivate::setSubFocus(QGraphicsItem *rootItem) 5183 { 5184 // Update focus child chain. Stop at panels, or if this item 5185 // is hidden, stop at the first item with a visible parent. 5186 QGraphicsItem *parent = rootItem ? rootItem : q_ptr; 5187 do { 5188 // Clear any existing ancestor's subFocusItem. 5189 if (parent != q_ptr && parent->d_ptr->subFocusItem) { 5190 if (parent->d_ptr->subFocusItem == q_ptr) 5191 break; 5192 parent->d_ptr->subFocusItem->d_ptr->clearSubFocus(); 3830 5193 } 3831 3832 QGraphicsItem *child = children.at(i); 3833 const QRectF rect = child->mapRectFromParent(emptyIfOutsideThisRect); 3834 if (rect.intersects(child->boundingRect())) 3835 child->d_ptr->invalidateCachedClipPathRecursively(false, rect); 3836 else 3837 child->d_ptr->setEmptyCachedClipPathRecursively(rect); 3838 } 3839 } 3840 3841 void QGraphicsItemPrivate::invalidateCachedClipPathRecursively(bool childrenOnly, const QRectF &emptyIfOutsideThisRect) 3842 { 3843 if (!childrenOnly) 3844 invalidateCachedClipPath(); 3845 3846 const bool checkRect = !emptyIfOutsideThisRect.isNull(); 3847 for (int i = 0; i < children.size(); ++i) { 3848 if (!checkRect) { 3849 children.at(i)->d_ptr->invalidateCachedClipPathRecursively(false); 3850 continue; 3851 } 3852 3853 QGraphicsItem *child = children.at(i); 3854 const QRectF rect = child->mapRectFromParent(emptyIfOutsideThisRect); 3855 if (rect.intersects(child->boundingRect())) 3856 child->d_ptr->invalidateCachedClipPathRecursively(false, rect); 3857 else 3858 child->d_ptr->setEmptyCachedClipPathRecursively(rect); 3859 } 3860 } 3861 3862 void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &newPos) 3863 { 3864 Q_ASSERT(inSetPosHelper); 3865 3866 if (!(ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) 3867 return; // Not clipped by any ancestor. 3868 3869 // Find closest clip ancestor and transform. 3870 Q_Q(QGraphicsItem); 3871 QTransform thisToParentTransform = hasTransform 3872 ? q->transform() * QTransform::fromTranslate(newPos.x(), newPos.y()) 3873 : QTransform::fromTranslate(newPos.x(), newPos.y()); 3874 QGraphicsItem *clipParent = parent; 3875 while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) { 3876 if (clipParent->d_ptr->hasTransform) 3877 thisToParentTransform *= clipParent->transform(); 3878 if (!clipParent->d_ptr->pos.isNull()) { 3879 thisToParentTransform *= QTransform::fromTranslate(clipParent->d_ptr->pos.x(), 3880 clipParent->d_ptr->pos.y()); 3881 } 3882 clipParent = clipParent->d_ptr->parent; 3883 } 3884 3885 // thisToParentTransform is now the same as q->itemTransform(clipParent), except 3886 // that the new position (which is not yet set on the item) is taken into account. 3887 Q_ASSERT(clipParent); 3888 Q_ASSERT(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); 3889 3890 // From here everything is calculated in clip parent's coordinates. 3891 const QRectF parentBoundingRect(clipParent->boundingRect()); 3892 const QRectF thisBoundingRect(thisToParentTransform.mapRect(q->boundingRect())); 3893 3894 if (!parentBoundingRect.intersects(thisBoundingRect)) { 3895 // Item is moved outside the clip parent's bounding rect, 3896 // i.e. it is fully clipped and the clip path is empty. 3897 if (flags & QGraphicsItem::ItemClipsChildrenToShape) 3898 setEmptyCachedClipPathRecursively(); 3899 else 3900 setEmptyCachedClipPathRecursively(thisToParentTransform.inverted().mapRect(parentBoundingRect)); 3901 return; 3902 } 3903 3904 const QPainterPath parentClip(clipParent->isClipped() ? clipParent->clipPath() : clipParent->shape()); 3905 if (parentClip.contains(thisBoundingRect)) 3906 return; // Item is inside the clip parent's shape. No update required. 3907 3908 const QRectF parentClipRect(parentClip.controlPointRect()); 3909 if (!parentClipRect.intersects(thisBoundingRect)) { 3910 // Item is moved outside the clip parent's shape, 3911 // i.e. it is fully clipped and the clip path is empty. 3912 if (flags & QGraphicsItem::ItemClipsChildrenToShape) 3913 setEmptyCachedClipPathRecursively(); 3914 else 3915 setEmptyCachedClipPathRecursively(thisToParentTransform.inverted().mapRect(parentClipRect)); 3916 } else { 3917 // Item is partially inside the clip parent's shape, 3918 // i.e. the cached clip path must be invalidated. 3919 invalidateCachedClipPathRecursively(false, thisToParentTransform.inverted().mapRect(parentClipRect)); 3920 } 5194 parent->d_ptr->subFocusItem = q_ptr; 5195 parent->d_ptr->subFocusItemChange(); 5196 } while (!parent->isPanel() && (parent = parent->d_ptr->parent) && (visible || !parent->d_ptr->visible)); 5197 5198 if (scene && !scene->isActive()) 5199 scene->d_func()->lastFocusItem = subFocusItem; 5200 } 5201 5202 /*! 5203 \internal 5204 */ 5205 void QGraphicsItemPrivate::clearSubFocus(QGraphicsItem *rootItem) 5206 { 5207 // Reset sub focus chain. 5208 QGraphicsItem *parent = rootItem ? rootItem : q_ptr; 5209 do { 5210 if (parent->d_ptr->subFocusItem != q_ptr) 5211 break; 5212 parent->d_ptr->subFocusItem = 0; 5213 parent->d_ptr->subFocusItemChange(); 5214 } while (!parent->isPanel() && (parent = parent->d_ptr->parent)); 5215 } 5216 5217 /*! 5218 \internal 5219 5220 Sets the focusProxy pointer to 0 for all items that have this item as their 5221 focusProxy. ### Qt 5: Use QPointer instead. 5222 */ 5223 void QGraphicsItemPrivate::resetFocusProxy() 5224 { 5225 for (int i = 0; i < focusProxyRefs.size(); ++i) 5226 *focusProxyRefs.at(i) = 0; 5227 focusProxyRefs.clear(); 5228 } 5229 5230 /*! 5231 \internal 5232 5233 Subclasses can reimplement this function to be notified when subFocusItem 5234 changes. 5235 */ 5236 void QGraphicsItemPrivate::subFocusItemChange() 5237 { 5238 } 5239 5240 /*! 5241 \internal 5242 5243 Subclasses can reimplement this function to be notified when its 5244 siblingIndex order is changed. 5245 */ 5246 void QGraphicsItemPrivate::siblingOrderChange() 5247 { 3921 5248 } 3922 5249 … … 3954 5281 return; 3955 5282 5283 // Make sure we notify effects about invalidated source. 5284 #ifndef QT_NO_GRAPHICSEFFECT 5285 d_ptr->invalidateGraphicsEffectsRecursively(); 5286 #endif //QT_NO_GRAPHICSEFFECT 5287 3956 5288 if (CacheMode(d_ptr->cacheMode) != NoCache) { 5289 // Invalidate cache. 3957 5290 QGraphicsItemCache *cache = d_ptr->extraItemCache(); 3958 if (d_ptr->discardUpdateRequest(/* ignoreVisibleBit = */ false, 3959 /* ignoreClipping = */ false, 3960 /* ignoreDirtyBit = */ true)) { 3961 return; 3962 } 3963 3964 // Invalidate cache. 3965 if (rect.isNull()) { 3966 cache->allExposed = true; 3967 cache->exposed.clear(); 3968 } else { 3969 cache->exposed.append(rect); 5291 if (!cache->allExposed) { 5292 if (rect.isNull()) { 5293 cache->allExposed = true; 5294 cache->exposed.clear(); 5295 } else { 5296 cache->exposed.append(rect); 5297 } 3970 5298 } 3971 5299 // Only invalidate cache; item is already dirty. 3972 if (d_ptr-> dirty)5300 if (d_ptr->fullUpdatePending) 3973 5301 return; 3974 } else if (d_ptr->discardUpdateRequest()) { 5302 } 5303 5304 if (d_ptr->discardUpdateRequest()) 3975 5305 return; 3976 } 3977 3978 // Effectively the same as updateHelper(rect); 3979 if (rect.isNull()) 3980 d_ptr->dirty = 1; 3981 d_ptr->scene->itemUpdated(this, rect); 3982 } 3983 5306 5307 if (d_ptr->scene) 5308 d_ptr->scene->d_func()->markDirty(this, rect); 5309 } 3984 5310 3985 5311 /*! … … 4010 5336 return; 4011 5337 if (d->cacheMode != NoCache) { 4012 // ### This is very slow, and can be done much better. If the cache is 4013 // local and matches the below criteria for rotation and scaling, we 4014 // can easily scroll. And if the cache is in device coordinates, we 4015 // can scroll both the viewport and the cache. 4016 update(rect); 5338 QGraphicsItemCache *c; 5339 bool scrollCache = qFuzzyIsNull(dx - int(dx)) && qFuzzyIsNull(dy - int(dy)) 5340 && (c = (QGraphicsItemCache *)qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraCacheData))) 5341 && (d->cacheMode == ItemCoordinateCache && !c->fixedSize.isValid()); 5342 if (scrollCache) { 5343 QPixmap pix; 5344 if (QPixmapCache::find(c->key, &pix)) { 5345 // Adjust with 2 pixel margin. Notice the loss of precision 5346 // when converting to QRect. 5347 int adjust = 2; 5348 QRectF br = boundingRect().adjusted(-adjust, -adjust, adjust, adjust); 5349 QRect irect = rect.toRect().translated(-br.x(), -br.y()); 5350 5351 pix.scroll(dx, dy, irect); 5352 5353 QPixmapCache::replace(c->key, pix); 5354 5355 // Translate the existing expose. 5356 foreach (QRectF exposedRect, c->exposed) 5357 c->exposed += exposedRect.translated(dx, dy) & rect; 5358 5359 // Calculate exposure. 5360 QRegion exposed; 5361 QRect r = rect.toRect(); 5362 exposed += r; 5363 exposed -= r.translated(dx, dy); 5364 foreach (QRect rect, exposed.rects()) 5365 update(rect); 5366 d->scene->d_func()->markDirty(this); 5367 } else { 5368 update(rect); 5369 } 5370 } else { 5371 // ### This is very slow, and can be done much better. If the cache is 5372 // local and matches the below criteria for rotation and scaling, we 5373 // can easily scroll. And if the cache is in device coordinates, we 5374 // can scroll both the viewport and the cache. 5375 update(rect); 5376 } 4017 5377 return; 4018 5378 } … … 4033 5393 static const QLineF right(0, 0, 1, 0); 4034 5394 4035 QTransform deviceTr; 4036 if (d->itemIsUntransformable()) { 4037 deviceTr = deviceTransform(view->viewportTransform()); 4038 } else { 4039 deviceTr = sceneTransform() * view->viewportTransform(); 4040 } 4041 5395 QTransform deviceTr = deviceTransform(view->viewportTransform()); 4042 5396 QRect deviceScrollRect = deviceTr.mapRect(scrollRect).toRect(); 4043 5397 QLineF v1 = deviceTr.map(right); … … 4171 5525 QPointF QGraphicsItem::mapToParent(const QPointF &point) const 4172 5526 { 4173 return d_ptr->pos + (d_ptr->hasTransform ? transform().map(point) : point); 5527 // COMBINE 5528 if (!d_ptr->transformData) 5529 return point + d_ptr->pos; 5530 return d_ptr->transformToParent().map(point); 4174 5531 } 4175 5532 … … 4191 5548 QPointF QGraphicsItem::mapToScene(const QPointF &point) const 4192 5549 { 4193 return sceneTransform().map(point); 5550 if (d_ptr->hasTranslateOnlySceneTransform()) 5551 return QPointF(point.x() + d_ptr->sceneTransform.dx(), point.y() + d_ptr->sceneTransform.dy()); 5552 return d_ptr->sceneTransform.map(point); 4194 5553 } 4195 5554 … … 4236 5595 QPolygonF QGraphicsItem::mapToParent(const QRectF &rect) const 4237 5596 { 4238 QPolygonF p = !d_ptr->hasTransform ? rect : transform().map(rect); 4239 p.translate(d_ptr->pos); 4240 return p; 5597 // COMBINE 5598 if (!d_ptr->transformData) 5599 return rect.translated(d_ptr->pos); 5600 return d_ptr->transformToParent().map(rect); 4241 5601 } 4242 5602 … … 4257 5617 QPolygonF QGraphicsItem::mapToScene(const QRectF &rect) const 4258 5618 { 4259 return sceneTransform().map(rect); 5619 if (d_ptr->hasTranslateOnlySceneTransform()) 5620 return rect.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy()); 5621 return d_ptr->sceneTransform.map(rect); 4260 5622 } 4261 5623 … … 4305 5667 QRectF QGraphicsItem::mapRectToParent(const QRectF &rect) const 4306 5668 { 4307 QRectF r = !d_ptr->hasTransform ? rect : transform().mapRect(rect); 4308 return r.translated(d_ptr->pos); 5669 // COMBINE 5670 if (!d_ptr->transformData) 5671 return rect.translated(d_ptr->pos); 5672 return d_ptr->transformToParent().mapRect(rect); 4309 5673 } 4310 5674 … … 4328 5692 QRectF QGraphicsItem::mapRectToScene(const QRectF &rect) const 4329 5693 { 4330 return sceneTransform().mapRect(rect); 5694 if (d_ptr->hasTranslateOnlySceneTransform()) 5695 return rect.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy()); 5696 return d_ptr->sceneTransform.mapRect(rect); 4331 5697 } 4332 5698 … … 4377 5743 QRectF QGraphicsItem::mapRectFromParent(const QRectF &rect) const 4378 5744 { 4379 QRectF r = rect.translated(-d_ptr->pos); 4380 return d_ptr->hasTransform ? transform().inverted().mapRect(r) : r; 5745 // COMBINE 5746 if (!d_ptr->transformData) 5747 return rect.translated(-d_ptr->pos); 5748 return d_ptr->transformToParent().inverted().mapRect(rect); 4381 5749 } 4382 5750 … … 4400 5768 QRectF QGraphicsItem::mapRectFromScene(const QRectF &rect) const 4401 5769 { 4402 return sceneTransform().inverted().mapRect(rect); 5770 if (d_ptr->hasTranslateOnlySceneTransform()) 5771 return rect.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy()); 5772 return d_ptr->sceneTransform.inverted().mapRect(rect); 4403 5773 } 4404 5774 … … 4437 5807 QPolygonF QGraphicsItem::mapToParent(const QPolygonF &polygon) const 4438 5808 { 4439 QPolygonF p = !d_ptr->hasTransform ? polygon : transform().map(polygon); 4440 p.translate(d_ptr->pos); 4441 return p; 5809 // COMBINE 5810 if (!d_ptr->transformData) 5811 return polygon.translated(d_ptr->pos); 5812 return d_ptr->transformToParent().map(polygon); 4442 5813 } 4443 5814 … … 4451 5822 QPolygonF QGraphicsItem::mapToScene(const QPolygonF &polygon) const 4452 5823 { 4453 return sceneTransform().map(polygon); 5824 if (d_ptr->hasTranslateOnlySceneTransform()) 5825 return polygon.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy()); 5826 return d_ptr->sceneTransform.map(polygon); 4454 5827 } 4455 5828 … … 4481 5854 QPainterPath QGraphicsItem::mapToParent(const QPainterPath &path) const 4482 5855 { 4483 QTransform x = QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y());4484 if ( d_ptr->hasTransform)4485 x = transform() * x;4486 return x.map(path);5856 // COMBINE 5857 if (!d_ptr->transformData) 5858 return path.translated(d_ptr->pos); 5859 return d_ptr->transformToParent().map(path); 4487 5860 } 4488 5861 … … 4496 5869 QPainterPath QGraphicsItem::mapToScene(const QPainterPath &path) const 4497 5870 { 4498 return sceneTransform().map(path); 5871 if (d_ptr->hasTranslateOnlySceneTransform()) 5872 return path.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy()); 5873 return d_ptr->sceneTransform.map(path); 4499 5874 } 4500 5875 … … 4533 5908 QPointF QGraphicsItem::mapFromParent(const QPointF &point) const 4534 5909 { 4535 if (d_ptr->hasTransform) 4536 return transform().inverted().map(point - d_ptr->pos); 5910 // COMBINE 5911 if (d_ptr->transformData) 5912 return d_ptr->transformToParent().inverted().map(point); 4537 5913 return point - d_ptr->pos; 4538 5914 } … … 4556 5932 QPointF QGraphicsItem::mapFromScene(const QPointF &point) const 4557 5933 { 4558 return sceneTransform().inverted().map(point); 5934 if (d_ptr->hasTranslateOnlySceneTransform()) 5935 return QPointF(point.x() - d_ptr->sceneTransform.dx(), point.y() - d_ptr->sceneTransform.dy()); 5936 return d_ptr->sceneTransform.inverted().map(point); 4559 5937 } 4560 5938 … … 4601 5979 QPolygonF QGraphicsItem::mapFromParent(const QRectF &rect) const 4602 5980 { 4603 QRectF r = rect.translated(-d_ptr->pos); 4604 return d_ptr->hasTransform ? transform().inverted().map(r) : r; 5981 // COMBINE 5982 if (!d_ptr->transformData) 5983 return rect.translated(-d_ptr->pos); 5984 return d_ptr->transformToParent().inverted().map(rect); 4605 5985 } 4606 5986 … … 4622 6002 QPolygonF QGraphicsItem::mapFromScene(const QRectF &rect) const 4623 6003 { 4624 return sceneTransform().inverted().map(rect); 6004 if (d_ptr->hasTranslateOnlySceneTransform()) 6005 return rect.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy()); 6006 return d_ptr->sceneTransform.inverted().map(rect); 4625 6007 } 4626 6008 … … 4657 6039 QPolygonF QGraphicsItem::mapFromParent(const QPolygonF &polygon) const 4658 6040 { 4659 QPolygonF p = polygon; 4660 p.translate(-d_ptr->pos); 4661 return d_ptr->hasTransform ? transform().inverted().map(p) : p; 6041 // COMBINE 6042 if (!d_ptr->transformData) 6043 return polygon.translated(-d_ptr->pos); 6044 return d_ptr->transformToParent().inverted().map(polygon); 4662 6045 } 4663 6046 … … 4671 6054 QPolygonF QGraphicsItem::mapFromScene(const QPolygonF &polygon) const 4672 6055 { 4673 return sceneTransform().inverted().map(polygon); 6056 if (d_ptr->hasTranslateOnlySceneTransform()) 6057 return polygon.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy()); 6058 return d_ptr->sceneTransform.inverted().map(polygon); 4674 6059 } 4675 6060 … … 4699 6084 QPainterPath QGraphicsItem::mapFromParent(const QPainterPath &path) const 4700 6085 { 4701 if (d_ptr->parent) 4702 return d_ptr->parent->itemTransform(this).map(path); 4703 return mapFromScene(path); 6086 // COMBINE 6087 if (!d_ptr->transformData) 6088 return path.translated(-d_ptr->pos); 6089 return d_ptr->transformToParent().inverted().map(path); 4704 6090 } 4705 6091 … … 4713 6099 QPainterPath QGraphicsItem::mapFromScene(const QPainterPath &path) const 4714 6100 { 4715 return sceneTransform().inverted().map(path); 6101 if (d_ptr->hasTranslateOnlySceneTransform()) 6102 return path.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy()); 6103 return d_ptr->sceneTransform.inverted().map(path); 4716 6104 } 4717 6105 … … 4725 6113 { 4726 6114 if (!child || child == this) 6115 return false; 6116 if (child->d_ptr->depth() < d_ptr->depth()) 4727 6117 return false; 4728 6118 const QGraphicsItem *ancestor = child; … … 4750 6140 const QGraphicsItem *thisw = this; 4751 6141 const QGraphicsItem *otherw = other; 4752 int thisDepth = d_ptr->depth ;4753 int otherDepth = other->d_ptr->depth ;6142 int thisDepth = d_ptr->depth(); 6143 int otherDepth = other->d_ptr->depth(); 4754 6144 while (thisDepth > otherDepth) { 4755 6145 thisw = thisw->d_ptr->parent; … … 5050 6440 inputMethodEvent(static_cast<QInputMethodEvent *>(event)); 5051 6441 break; 6442 case QEvent::WindowActivate: 6443 case QEvent::WindowDeactivate: 6444 // Propagate panel activation. 6445 if (d_ptr->scene) { 6446 for (int i = 0; i < d_ptr->children.size(); ++i) { 6447 QGraphicsItem *child = d_ptr->children.at(i); 6448 if (child->isVisible() && !child->isPanel()) { 6449 if (!(child->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents)) 6450 d_ptr->scene->sendEvent(child, event); 6451 } 6452 } 6453 } 6454 break; 5052 6455 default: 5053 6456 return false; … … 5189 6592 ensureVisible(). 5190 6593 5191 \sa focusOutEvent(), sceneEvent() 6594 \sa focusOutEvent(), sceneEvent(), setFocus() 5192 6595 */ 5193 6596 void QGraphicsItem::focusInEvent(QFocusEvent *event) 5194 6597 { 5195 6598 Q_UNUSED(event); 6599 update(); 5196 6600 } 5197 6601 … … 5200 6604 focus out events for this item. The default implementation does nothing. 5201 6605 5202 \sa focusInEvent(), sceneEvent() 6606 \sa focusInEvent(), sceneEvent(), setFocus() 5203 6607 */ 5204 6608 void QGraphicsItem::focusOutEvent(QFocusEvent *event) 5205 6609 { 5206 6610 Q_UNUSED(event); 6611 update(); 5207 6612 } 5208 6613 … … 5219 6624 { 5220 6625 Q_UNUSED(event); 5221 d_ptr->updateHelper();6626 update(); 5222 6627 } 5223 6628 … … 5247 6652 { 5248 6653 Q_UNUSED(event); 5249 d_ptr->updateHelper();6654 update(); 5250 6655 } 5251 6656 … … 5337 6742 // Qt::Popup closes when you click outside. 5338 6743 QGraphicsWidget *w = static_cast<QGraphicsWidget *>(this); 5339 if ( w->windowFlags() &Qt::Popup) {6744 if ((w->windowFlags() & Qt::Popup) == Qt::Popup) { 5340 6745 event->accept(); 5341 6746 if (!w->rect().contains(event->pos())) … … 5584 6989 property is queried. 5585 6990 5586 \sa inputMethodEvent() 6991 \sa inputMethodEvent(), QInputMethodEvent, QInputContext 5587 6992 */ 5588 6993 QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const … … 5600 7005 5601 7006 /*! 7007 Returns the current input method hints of this item. 7008 7009 Input method hints are only relevant for input items. 7010 The hints are used by the input method to indicate how it should operate. 7011 For example, if the Qt::ImhNumbersOnly flag is set, the input method may change 7012 its visual components to reflect that only numbers can be entered. 7013 7014 The effect may vary between input method implementations. 7015 7016 \since 4.6 7017 7018 \sa setInputMethodHints(), inputMethodQuery(), QInputContext 7019 */ 7020 Qt::InputMethodHints QGraphicsItem::inputMethodHints() const 7021 { 7022 Q_D(const QGraphicsItem); 7023 return d->imHints; 7024 } 7025 7026 /*! 7027 Sets the current input method hints of this item to \a hints. 7028 7029 \since 4.6 7030 7031 \sa inputMethodHints(), inputMethodQuery(), QInputContext 7032 */ 7033 void QGraphicsItem::setInputMethodHints(Qt::InputMethodHints hints) 7034 { 7035 Q_D(QGraphicsItem); 7036 d->imHints = hints; 7037 } 7038 7039 /*! 5602 7040 This virtual function is called by QGraphicsItem to notify custom items 5603 7041 that some part of the item's state changes. By reimplementing this … … 5676 7114 } 5677 7115 if (d_ptr->scene) 5678 d_ptr->scene->d_func()->addToIndex(this); 5679 d_ptr->updateHelper(); 7116 d_ptr->scene->d_func()->index->addItem(this); 5680 7117 } 5681 7118 … … 5693 7130 return; 5694 7131 } 5695 d_ptr->updateHelper();5696 7132 if (d_ptr->scene) 5697 d_ptr->scene->d_func()-> removeFromIndex(this);7133 d_ptr->scene->d_func()->index->removeItem(this); 5698 7134 } 5699 7135 … … 5713 7149 void QGraphicsItem::prepareGeometryChange() 5714 7150 { 7151 if (d_ptr->inDestructor) 7152 return; 5715 7153 if (d_ptr->scene) { 5716 d_ptr->updateHelper(QRectF(), false, /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper); 7154 d_ptr->scene->d_func()->dirtyGrowingItemsBoundingRect = true; 7155 d_ptr->geometryChanged = 1; 7156 d_ptr->paintedViewBoundingRectsNeedRepaint = 1; 7157 d_ptr->notifyBoundingRectChanged = !d_ptr->inSetPosHelper; 7158 5717 7159 QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); 5718 scenePrivate->removeFromIndex(this); 5719 } 5720 5721 if (d_ptr->inSetPosHelper) 5722 return; 5723 5724 if (d_ptr->flags & ItemClipsChildrenToShape) 5725 d_ptr->invalidateCachedClipPathRecursively(); 5726 else 5727 d_ptr->invalidateCachedClipPath(); 7160 scenePrivate->index->prepareBoundingRectChange(this); 7161 scenePrivate->markDirty(this, QRectF(), /*invalidateChildren=*/true); 7162 7163 // For compatibility reasons, we have to update the item's old geometry 7164 // if someone is connected to the changed signal or the scene has no views. 7165 // Note that this has to be done *after* markDirty to ensure that 7166 // _q_processDirtyItems is called before _q_emitUpdated. 7167 if (scenePrivate->isSignalConnected(scenePrivate->changedSignalIndex) 7168 || scenePrivate->views.isEmpty()) { 7169 if (d_ptr->hasTranslateOnlySceneTransform()) { 7170 d_ptr->scene->update(boundingRect().translated(d_ptr->sceneTransform.dx(), 7171 d_ptr->sceneTransform.dy())); 7172 } else { 7173 d_ptr->scene->update(d_ptr->sceneTransform.mapRect(boundingRect())); 7174 } 7175 } 7176 } 7177 7178 QGraphicsItem *parent = this; 7179 while ((parent = parent->d_ptr->parent)) { 7180 QGraphicsItemPrivate *parentp = parent->d_ptr.data(); 7181 parentp->dirtyChildrenBoundingRect = 1; 7182 // ### Only do this if the parent's effect applies to the entire subtree. 7183 parentp->notifyBoundingRectChanged = 1; 7184 #ifndef QT_NO_GRAPHICSEFFECT 7185 if (parentp->scene && parentp->graphicsEffect) { 7186 parentp->notifyInvalidated = 1; 7187 static_cast<QGraphicsItemEffectSourcePrivate *>(parentp->graphicsEffect->d_func()->source->d_func())->invalidateCache(); 7188 } 7189 #endif 7190 } 5728 7191 } 5729 7192 … … 5740 7203 { 5741 7204 const QRectF murect = painter->transform().mapRect(QRectF(0, 0, 1, 1)); 5742 if (qFuzzy Compare(qMax(murect.width(), murect.height()) + 1, 1))7205 if (qFuzzyIsNull(qMax(murect.width(), murect.height()))) 5743 7206 return; 5744 7207 … … 5790 7253 5791 7254 /*! 7255 \class QGraphicsObject 7256 \brief The QGraphicsObject class provides a base class for all graphics items that 7257 require signals, slots and properties. 7258 \since 4.6 7259 \ingroup graphicsview-api 7260 7261 The class extends a QGraphicsItem with QObject's signal/slot and property mechanisms. 7262 It maps many of QGraphicsItem's basic setters and getters to properties and adds notification 7263 signals for many of them. 7264 7265 \section1 Parents and Children 7266 7267 Each graphics object can be constructed with a parent item. This ensures that the 7268 item will be destroyed when its parent item is destroyed. Although QGraphicsObject 7269 inherits from both QObject and QGraphicsItem, you should use the functions provided 7270 by QGraphicsItem, \e not QObject, to manage the relationships between parent and 7271 child items. 7272 7273 The relationships between items can be explored using the parentItem() and childItems() 7274 functions. In the hierarchy of items in a scene, the parentObject() and parentWidget() 7275 functions are the equivalent of the QWidget::parent() and QWidget::parentWidget() 7276 functions for QWidget subclasses. 7277 7278 \sa QGraphicsWidget 7279 */ 7280 7281 /*! 7282 Constructs a QGraphicsObject with \a parent. 7283 */ 7284 QGraphicsObject::QGraphicsObject(QGraphicsItem *parent) 7285 : QGraphicsItem(parent) 7286 { 7287 QGraphicsItem::d_ptr->isObject = true; 7288 } 7289 7290 /*! 7291 \internal 7292 */ 7293 QGraphicsObject::QGraphicsObject(QGraphicsItemPrivate &dd, QGraphicsItem *parent, QGraphicsScene *scene) 7294 : QGraphicsItem(dd, parent, scene) 7295 { 7296 QGraphicsItem::d_ptr->isObject = true; 7297 } 7298 7299 /*! 7300 Subscribes the graphics object to the given \a gesture with specific \a flags. 7301 7302 \sa ungrabGesture(), QGestureEvent 7303 */ 7304 void QGraphicsObject::grabGesture(Qt::GestureType gesture, Qt::GestureFlags flags) 7305 { 7306 QGraphicsItemPrivate * const d = QGraphicsItem::d_func(); 7307 d->gestureContext.insert(gesture, flags); 7308 (void)QGestureManager::instance(); // create a gesture manager 7309 } 7310 7311 /*! 7312 Unsubscribes the graphics object from the given \a gesture. 7313 7314 \sa grabGesture(), QGestureEvent 7315 */ 7316 void QGraphicsObject::ungrabGesture(Qt::GestureType gesture) 7317 { 7318 QGraphicsItemPrivate * const d = QGraphicsItem::d_func(); 7319 if (d->gestureContext.remove(gesture)) { 7320 QGestureManager *manager = QGestureManager::instance(); 7321 manager->cleanupCachedGestures(this, gesture); 7322 } 7323 } 7324 7325 /*! 7326 \property QGraphicsObject::parent 7327 \brief the parent of the item 7328 7329 \note The item's parent is set independently of the parent object returned 7330 by QObject::parent(). 7331 7332 \sa QGraphicsItem::setParentItem(), QGraphicsItem::parentObject() 7333 */ 7334 7335 /*! 7336 \property QGraphicsObject::opacity 7337 \brief the opacity of the item 7338 7339 \sa QGraphicsItem::setOpacity(), QGraphicsItem::opacity() 7340 */ 7341 7342 /*! 7343 \fn QGraphicsObject::opacityChanged() 7344 7345 This signal gets emitted whenever the opacity of the item changes 7346 7347 \sa QGraphicsItem::opacity() 7348 */ 7349 7350 /*! 7351 \fn QGraphicsObject::parentChanged() 7352 7353 This signal gets emitted whenever the parent of the item changes 7354 */ 7355 7356 /*! 7357 \property QGraphicsObject::pos 7358 \brief the position of the item 7359 7360 Describes the items position. 7361 7362 \sa QGraphicsItem::setPos(), QGraphicsItem::pos() 7363 */ 7364 7365 /*! 7366 \property QGraphicsObject::x 7367 \brief the x position of the item 7368 7369 Describes the items x position. 7370 7371 \sa QGraphicsItem::setX(), setPos(), xChanged() 7372 */ 7373 7374 /*! 7375 \fn QGraphicsObject::xChanged() 7376 7377 This signal gets emitted whenever the x position of the item changes 7378 7379 \sa pos() 7380 */ 7381 7382 /*! 7383 \property QGraphicsObject::y 7384 \brief the y position of the item 7385 7386 Describes the items y position. 7387 7388 \sa QGraphicsItem::setY(), setPos(), yChanged() 7389 */ 7390 7391 /*! 7392 \fn QGraphicsObject::yChanged() 7393 7394 This signal gets emitted whenever the y position of the item changes. 7395 7396 \sa pos() 7397 */ 7398 7399 /*! 7400 \property QGraphicsObject::z 7401 \brief the z value of the item 7402 7403 Describes the items z value. 7404 7405 \sa QGraphicsItem::setZValue(), zValue(), zChanged() 7406 */ 7407 7408 /*! 7409 \fn QGraphicsObject::zChanged() 7410 7411 This signal gets emitted whenever the z value of the item changes. 7412 7413 \sa pos() 7414 */ 7415 7416 /*! 7417 \property QGraphicsObject::rotation 7418 This property holds the rotation of the item in degrees. 7419 7420 This specifies how many degrees to rotate the item around its transformOrigin. 7421 The default rotation is 0 degrees (i.e. not rotated at all). 7422 */ 7423 7424 /*! 7425 \fn QGraphicsObject::rotationChanged() 7426 7427 This signal gets emitted whenever the roation of the item changes. 7428 */ 7429 7430 /*! 7431 \property QGraphicsObject::scale 7432 This property holds the scale of the item. 7433 7434 A scale of less than 1 means the item will be displayed smaller than 7435 normal, and a scale of greater than 1 means the item will be 7436 displayed larger than normal. A negative scale means the item will 7437 be mirrored. 7438 7439 By default, items are displayed at a scale of 1 (i.e. at their 7440 normal size). 7441 7442 Scaling is from the item's transformOrigin. 7443 */ 7444 7445 /*! 7446 \fn void QGraphicsObject::scaleChanged() 7447 7448 This signal is emitted when the scale of the item changes. 7449 */ 7450 7451 7452 /*! 7453 \property QGraphicsObject::enabled 7454 \brief whether the item is enabled or not 7455 7456 This property is declared in QGraphicsItem. 7457 7458 By default, this property is true. 7459 7460 \sa QGraphicsItem::isEnabled(), QGraphicsItem::setEnabled() 7461 \sa QGraphicsObject::enabledChanged() 7462 */ 7463 7464 /*! 7465 \fn void QGraphicsObject::enabledChanged() 7466 7467 This signal gets emitted whenever the item get's enabled or disabled. 7468 7469 \sa isEnabled() 7470 */ 7471 7472 /*! 7473 \property QGraphicsObject::visible 7474 \brief whether the item is visible or not 7475 7476 This property is declared in QGraphicsItem. 7477 7478 By default, this property is true. 7479 7480 \sa QGraphicsItem::isVisible(), QGraphicsItem::setVisible(), visibleChanged() 7481 */ 7482 7483 /*! 7484 \fn QGraphicsObject::visibleChanged() 7485 7486 This signal gets emitted whenever the visibility of the item changes 7487 7488 \sa visible 7489 */ 7490 7491 /*! 7492 \fn const QObjectList &QGraphicsObject::children() const 7493 \internal 7494 7495 This function returns the same value as QObject::children(). It's 7496 provided to differentiate between the obsolete member 7497 QGraphicsItem::children() and QObject::children(). QGraphicsItem now 7498 provides childItems() instead. 7499 */ 7500 7501 /*! 7502 \property QGraphicsObject::transformOriginPoint 7503 \brief the transformation origin 7504 7505 This property sets a specific point in the items coordiante system as the 7506 origin for scale and rotation. 7507 7508 \sa scale, rotation, QGraphicsItem::transformOriginPoint() 7509 */ 7510 7511 7512 /*! 5792 7513 \class QAbstractGraphicsShapeItem 5793 7514 \brief The QAbstractGraphicsShapeItem class provides a common base for 5794 7515 all path items. 5795 7516 \since 4.2 5796 \ingroup multimedia7517 \ingroup graphicsview-api 5797 7518 5798 7519 This class does not fully implement an item by itself; in particular, it … … 5929 7650 can add to a QGraphicsScene. 5930 7651 \since 4.2 5931 \ingroup multimedia5932 7652 \ingroup graphicsview-api 5933 7653 … … 6132 7852 can add to a QGraphicsScene. 6133 7853 \since 4.2 6134 \ingroup multimedia6135 7854 \ingroup graphicsview-api 6136 7855 … … 6377 8096 can add to a QGraphicsScene. 6378 8097 \since 4.2 6379 \ingroup multimedia6380 8098 \ingroup graphicsview-api 6381 8099 … … 6694 8412 can add to a QGraphicsScene. 6695 8413 \since 4.2 6696 \ingroup multimedia6697 8414 \ingroup graphicsview-api 6698 8415 … … 6928 8645 QGraphicsScene. 6929 8646 \since 4.2 6930 \ingroup multimedia6931 8647 \ingroup graphicsview-api 6932 8648 … … 7190 8906 a QGraphicsScene. 7191 8907 \since 4.2 7192 \ingroup multimedia7193 8908 \ingroup graphicsview-api 7194 8909 … … 7379 9094 Q_D(QGraphicsPixmapItem); 7380 9095 if (mode != d->transformationMode) { 7381 d_ptr->updateHelper();7382 9096 d->transformationMode = mode; 7383 9097 update(); … … 7427 9141 { 7428 9142 Q_D(const QGraphicsPixmapItem); 7429 qreal pw = 1.0;7430 9143 if (d->pixmap.isNull()) 7431 9144 return QRectF(); 7432 return QRectF(d->offset, d->pixmap.size()).adjusted(-pw/2, -pw/2, pw/2, pw/2); 9145 if (d->flags & ItemIsSelectable) { 9146 qreal pw = 1.0; 9147 return QRectF(d->offset, d->pixmap.size()).adjusted(-pw/2, -pw/2, pw/2, pw/2); 9148 } else { 9149 return QRectF(d->offset, d->pixmap.size()); 9150 } 7433 9151 } 7434 9152 … … 7467 9185 (d->transformationMode == Qt::SmoothTransformation)); 7468 9186 7469 QRectF exposed = option->exposedRect.adjusted(-1, -1, 1, 1); 7470 exposed &= QRectF(d->offset.x(), d->offset.y(), d->pixmap.width(), d->pixmap.height()); 7471 painter->drawPixmap(exposed, d->pixmap, exposed.translated(-d->offset)); 9187 painter->drawPixmap(d->offset, d->pixmap); 7472 9188 7473 9189 if (option->state & QStyle::State_Selected) … … 7557 9273 a QGraphicsScene to display formatted text. 7558 9274 \since 4.2 7559 \ingroup multimedia7560 9275 \ingroup graphicsview-api 7561 9276 … … 7592 9307 public: 7593 9308 QGraphicsTextItemPrivate() 7594 : control(0), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false) 9309 : control(0), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false), clickCausedFocus(0) 7595 9310 { } 7596 9311 … … 7613 9328 bool tabChangesFocus; 7614 9329 9330 uint clickCausedFocus : 1; 9331 7615 9332 QGraphicsTextItem *qq; 7616 9333 }; 9334 7617 9335 7618 9336 /*! … … 7628 9346 #endif 7629 9347 ) 7630 : QGraphics Item(parent, scene), dd(new QGraphicsTextItemPrivate)9348 : QGraphicsObject(*new QGraphicsItemPrivate, parent, scene), dd(new QGraphicsTextItemPrivate) 7631 9349 { 7632 9350 dd->qq = this; … … 7635 9353 setAcceptDrops(true); 7636 9354 setAcceptHoverEvents(true); 9355 setFlags(ItemUsesExtendedStyleOption); 7637 9356 } 7638 9357 … … 7649 9368 #endif 7650 9369 ) 7651 : QGraphics Item(parent, scene), dd(new QGraphicsTextItemPrivate)9370 : QGraphicsObject(*new QGraphicsItemPrivate, parent, scene), dd(new QGraphicsTextItemPrivate) 7652 9371 { 7653 9372 dd->qq = this; 7654 9373 setAcceptDrops(true); 7655 9374 setAcceptHoverEvents(true); 9375 setFlag(ItemUsesExtendedStyleOption); 7656 9376 } 7657 9377 … … 7743 9463 QTextControl *c = dd->textControl(); 7744 9464 QPalette pal = c->palette(); 9465 QColor old = pal.color(QPalette::Text); 7745 9466 pal.setColor(QPalette::Text, col); 7746 9467 c->setPalette(pal); 9468 if (old != col) 9469 update(); 7747 9470 } 7748 9471 … … 7915 9638 } 7916 9639 } 7917 return QGraphicsItem::sceneEvent(event); 9640 bool result = QGraphicsItem::sceneEvent(event); 9641 9642 // Ensure input context is updated. 9643 switch (event->type()) { 9644 case QEvent::ContextMenu: 9645 case QEvent::FocusIn: 9646 case QEvent::FocusOut: 9647 case QEvent::GraphicsSceneDragEnter: 9648 case QEvent::GraphicsSceneDragLeave: 9649 case QEvent::GraphicsSceneDragMove: 9650 case QEvent::GraphicsSceneDrop: 9651 case QEvent::GraphicsSceneHoverEnter: 9652 case QEvent::GraphicsSceneHoverLeave: 9653 case QEvent::GraphicsSceneHoverMove: 9654 case QEvent::GraphicsSceneMouseDoubleClick: 9655 case QEvent::GraphicsSceneMousePress: 9656 case QEvent::GraphicsSceneMouseMove: 9657 case QEvent::GraphicsSceneMouseRelease: 9658 case QEvent::KeyPress: 9659 case QEvent::KeyRelease: 9660 // Reset the focus widget's input context, regardless 9661 // of how this item gained or lost focus. 9662 if (QWidget *fw = qApp->focusWidget()) { 9663 #ifndef QT_NO_IM 9664 if (QInputContext *qic = fw->inputContext()) { 9665 if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut) 9666 qic->reset(); 9667 else 9668 qic->update(); 9669 } 9670 #endif //QT_NO_IM 9671 } 9672 break; 9673 default: 9674 break; 9675 } 9676 9677 return result; 7918 9678 } 7919 9679 … … 7924 9684 { 7925 9685 if ((QGraphicsItem::d_ptr->flags & (ItemIsSelectable | ItemIsMovable)) 7926 7927 7928 7929 9686 && (event->buttons() & Qt::LeftButton) && dd->_q_mouseOnEdge(event)) { 9687 // User left-pressed on edge of selectable/movable item, use 9688 // base impl. 9689 dd->useDefaultImpl = true; 7930 9690 } else if (event->buttons() == event->button() 7931 7932 7933 9691 && dd->control->textInteractionFlags() == Qt::NoTextInteraction) { 9692 // User pressed first button on non-interactive item. 9693 dd->useDefaultImpl = true; 7934 9694 } 7935 9695 if (dd->useDefaultImpl) { 7936 9696 QGraphicsItem::mousePressEvent(event); 7937 7938 9697 if (!event->isAccepted()) 9698 dd->useDefaultImpl = false; 7939 9699 return; 7940 9700 } 9701 7941 9702 dd->sendControlEvent(event); 7942 9703 } … … 7951 9712 return; 7952 9713 } 9714 7953 9715 dd->sendControlEvent(event); 7954 9716 } … … 7961 9723 if (dd->useDefaultImpl) { 7962 9724 QGraphicsItem::mouseReleaseEvent(event); 7963 7964 7965 9725 if (dd->control->textInteractionFlags() == Qt::NoTextInteraction 9726 && !event->buttons()) { 9727 // User released last button on non-interactive item. 7966 9728 dd->useDefaultImpl = false; 7967 7968 9729 } else if ((event->buttons() & Qt::LeftButton) == 0) { 9730 // User released the left button on an interactive item. 7969 9731 dd->useDefaultImpl = false; 7970 9732 } 7971 9733 return; 7972 9734 } 9735 9736 QWidget *widget = event->widget(); 9737 if (widget && (dd->control->textInteractionFlags() & Qt::TextEditable) && boundingRect().contains(event->pos())) { 9738 qt_widget_private(widget)->handleSoftwareInputPanel(event->button(), dd->clickCausedFocus); 9739 } 9740 dd->clickCausedFocus = 0; 7973 9741 dd->sendControlEvent(event); 7974 9742 } … … 8022 9790 { 8023 9791 dd->sendControlEvent(event); 9792 if (event->reason() == Qt::MouseFocusReason) { 9793 dd->clickCausedFocus = 1; 9794 } 8024 9795 update(); 8025 9796 } … … 8258 10029 input. 8259 10030 8260 The default for a QGraphicsTextItem is Qt::NoTextInteraction. Setting a8261 value different to Qt::NoTextInteraction will also set the ItemIsFocusable8262 QGraphicsItem flag.10031 The default for a QGraphicsTextItem is Qt::NoTextInteraction. This function 10032 also affects the ItemIsFocusable QGraphicsItem flag by setting it if \a flags 10033 is different from Qt::NoTextInteraction and clearing it otherwise. 8263 10034 8264 10035 By default, the text is read-only. To transform the item into an editor, … … 8268 10039 { 8269 10040 if (flags == Qt::NoTextInteraction) 8270 setFlags(this->flags() & ~ QGraphicsItem::ItemIsFocusable);10041 setFlags(this->flags() & ~(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod)); 8271 10042 else 8272 setFlags(this->flags() | QGraphicsItem::ItemIsFocusable); 10043 setFlags(this->flags() | QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod); 10044 8273 10045 dd->textControl()->setTextInteractionFlags(flags); 8274 10046 } … … 8419 10191 that you can add to a QGraphicsScene. 8420 10192 \since 4.2 8421 \ingroup multimedia8422 10193 \ingroup graphicsview-api 8423 10194 … … 8655 10426 one. 8656 10427 \since 4.2 8657 \ingroup multimedia8658 10428 \ingroup graphicsview-api 8659 10429 … … 8670 10440 8671 10441 The boundingRect() function of QGraphicsItemGroup returns the 8672 bounding rectangle of all items in the item group. In addition, 8673 item groups have handlesChildEvents() enabled by default, so all 8674 events sent to a member of the group go to the item group (i.e., 8675 selecting one item in a group will select them all). 8676 QGraphicsItemGroup ignores the ItemIgnoresTransformations flag on its 8677 children (i.e., with respect to the geometry of the group item, the 8678 children are treated as if they were transformable). 10442 bounding rectangle of all items in the item group. 10443 QGraphicsItemGroup ignores the ItemIgnoresTransformations flag on 10444 its children (i.e., with respect to the geometry of the group 10445 item, the children are treated as if they were transformable). 8679 10446 8680 10447 There are two ways to construct an item group. The easiest and … … 8761 10528 } 8762 10529 8763 QTransform oldSceneMatrix = item->sceneTransform(); 10530 // COMBINE 10531 bool ok; 10532 QTransform itemTransform = item->itemTransform(this, &ok); 10533 10534 if (!ok) { 10535 qWarning("QGraphicsItemGroup::addToGroup: could not find a valid transformation from item to group coordinates"); 10536 return; 10537 } 10538 10539 QTransform newItemTransform(itemTransform); 8764 10540 item->setPos(mapFromItem(item, 0, 0)); 8765 10541 item->setParentItem(this); 8766 QTransform newItemTransform(oldSceneMatrix); 8767 newItemTransform *= sceneTransform().inverted();10542 10543 // removing position from translation component of the new transform 8768 10544 if (!item->pos().isNull()) 8769 10545 newItemTransform *= QTransform::fromTranslate(-item->x(), -item->y()); 10546 10547 // removing additional transformations properties applied with itemTransform() 10548 QPointF origin = item->transformOriginPoint(); 10549 QMatrix4x4 m; 10550 QList<QGraphicsTransform*> transformList = item->transformations(); 10551 for (int i = 0; i < transformList.size(); ++i) 10552 transformList.at(i)->applyTo(&m); 10553 newItemTransform *= m.toTransform().inverted(); 10554 newItemTransform.translate(origin.x(), origin.y()); 10555 newItemTransform.rotate(-item->rotation()); 10556 newItemTransform.scale(1/item->scale(), 1/item->scale()); 10557 newItemTransform.translate(-origin.x(), -origin.y()); 10558 10559 // ### Expensive, we could maybe use dirtySceneTransform bit for optimization 10560 8770 10561 item->setTransform(newItemTransform); 8771 10562 item->d_func()->setIsMemberOfGroup(true); 8772 10563 prepareGeometryChange(); 8773 QTransform itemTransform(item->transform());8774 if (!item->pos().isNull())8775 itemTransform *= QTransform::fromTranslate(item->x(), item->y());8776 10564 d->itemsBoundingRect |= itemTransform.mapRect(item->boundingRect() | item->childrenBoundingRect()); 8777 10565 update(); … … 8795 10583 8796 10584 QGraphicsItem *newParent = d_ptr->parent; 10585 10586 // COMBINE 10587 bool ok; 10588 QTransform itemTransform; 10589 if (newParent) 10590 itemTransform = item->itemTransform(newParent, &ok); 10591 else 10592 itemTransform = item->sceneTransform(); 10593 8797 10594 QPointF oldPos = item->mapToItem(newParent, 0, 0); 8798 10595 item->setParentItem(newParent); 8799 // ### This function should remap the item's matrix to keep the item's8800 // transformation unchanged relative to the scene.8801 10596 item->setPos(oldPos); 10597 10598 // removing position from translation component of the new transform 10599 if (!item->pos().isNull()) 10600 itemTransform *= QTransform::fromTranslate(-item->x(), -item->y()); 10601 10602 // removing additional transformations properties applied 10603 // with itemTransform() or sceneTransform() 10604 QPointF origin = item->transformOriginPoint(); 10605 QMatrix4x4 m; 10606 QList<QGraphicsTransform*> transformList = item->transformations(); 10607 for (int i = 0; i < transformList.size(); ++i) 10608 transformList.at(i)->applyTo(&m); 10609 itemTransform *= m.toTransform().inverted(); 10610 itemTransform.translate(origin.x(), origin.y()); 10611 itemTransform.rotate(-item->rotation()); 10612 itemTransform.scale(1 / item->scale(), 1 / item->scale()); 10613 itemTransform.translate(-origin.x(), -origin.y()); 10614 10615 // ### Expensive, we could maybe use dirtySceneTransform bit for optimization 10616 10617 item->setTransform(itemTransform); 8802 10618 item->d_func()->setIsMemberOfGroup(item->group() != 0); 8803 10619 … … 8856 10672 } 8857 10673 10674 #ifndef QT_NO_GRAPHICSEFFECT 10675 QRectF QGraphicsItemEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const 10676 { 10677 const bool deviceCoordinates = (system == Qt::DeviceCoordinates); 10678 if (!info && deviceCoordinates) { 10679 // Device coordinates without info not yet supported. 10680 qWarning("QGraphicsEffectSource::boundingRect: Not yet implemented, lacking device context"); 10681 return QRectF(); 10682 } 10683 10684 QRectF rect = item->boundingRect(); 10685 if (!item->d_ptr->children.isEmpty()) 10686 rect |= item->childrenBoundingRect(); 10687 10688 if (deviceCoordinates) { 10689 Q_ASSERT(info->painter); 10690 rect = info->painter->worldTransform().mapRect(rect); 10691 } 10692 10693 return rect; 10694 } 10695 10696 void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter) 10697 { 10698 if (!info) { 10699 qWarning("QGraphicsEffectSource::draw: Can only begin as a result of QGraphicsEffect::draw"); 10700 return; 10701 } 10702 10703 Q_ASSERT(item->d_ptr->scene); 10704 QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func(); 10705 if (painter == info->painter) { 10706 scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion, 10707 info->widget, info->opacity, info->effectTransform, info->wasDirtySceneTransform, 10708 info->drawItem); 10709 } else { 10710 QTransform effectTransform = info->painter->worldTransform().inverted(); 10711 effectTransform *= painter->worldTransform(); 10712 scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion, 10713 info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform, 10714 info->drawItem); 10715 } 10716 } 10717 10718 QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset, 10719 QGraphicsEffect::PixmapPadMode mode) const 10720 { 10721 const bool deviceCoordinates = (system == Qt::DeviceCoordinates); 10722 if (!info && deviceCoordinates) { 10723 // Device coordinates without info not yet supported. 10724 qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context"); 10725 return QPixmap(); 10726 } 10727 if (!item->d_ptr->scene) 10728 return QPixmap(); 10729 QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func(); 10730 10731 const QRectF sourceRect = boundingRect(system); 10732 QRectF effectRectF; 10733 10734 bool unpadded = false; 10735 if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) { 10736 if (info) { 10737 effectRectF = item->graphicsEffect()->boundingRectFor(boundingRect(Qt::DeviceCoordinates)); 10738 unpadded = (effectRectF.size() == sourceRect.size()); 10739 if (info && system == Qt::LogicalCoordinates) 10740 effectRectF = info->painter->worldTransform().inverted().mapRect(effectRectF); 10741 } else { 10742 // no choice but to send a logical coordinate bounding rect to boundingRectFor 10743 effectRectF = item->graphicsEffect()->boundingRectFor(sourceRect); 10744 } 10745 } else if (mode == QGraphicsEffect::PadToTransparentBorder) { 10746 // adjust by 1.5 to account for cosmetic pens 10747 effectRectF = sourceRect.adjusted(-1.5, -1.5, 1.5, 1.5); 10748 } else { 10749 effectRectF = sourceRect; 10750 unpadded = true; 10751 } 10752 10753 QRect effectRect = effectRectF.toAlignedRect(); 10754 10755 if (offset) 10756 *offset = effectRect.topLeft(); 10757 10758 bool untransformed = !deviceCoordinates 10759 || info->painter->worldTransform().type() <= QTransform::TxTranslate; 10760 if (untransformed && unpadded && isPixmap()) { 10761 if (offset) 10762 *offset = boundingRect(system).topLeft().toPoint(); 10763 return static_cast<QGraphicsPixmapItem *>(item)->pixmap(); 10764 } 10765 10766 if (deviceCoordinates) { 10767 // Clip to viewport rect. 10768 int left, top, right, bottom; 10769 effectRect.getCoords(&left, &top, &right, &bottom); 10770 if (left < 0) { 10771 if (offset) 10772 offset->rx() += -left; 10773 effectRect.setX(0); 10774 } 10775 if (top < 0) { 10776 if (offset) 10777 offset->ry() += -top; 10778 effectRect.setY(0); 10779 } 10780 // NB! We use +-1 for historical reasons (see QRect documentation). 10781 QPaintDevice *device = info->painter->device(); 10782 const int deviceWidth = device->width(); 10783 const int deviceHeight = device->height(); 10784 if (right + 1 > deviceWidth) 10785 effectRect.setRight(deviceWidth - 1); 10786 if (bottom + 1 > deviceHeight) 10787 effectRect.setBottom(deviceHeight -1); 10788 10789 } 10790 if (effectRect.isEmpty()) 10791 return QPixmap(); 10792 10793 QPixmap pixmap(effectRect.size()); 10794 pixmap.fill(Qt::transparent); 10795 QPainter pixmapPainter(&pixmap); 10796 pixmapPainter.setRenderHints(info ? info->painter->renderHints() : QPainter::TextAntialiasing); 10797 10798 QTransform effectTransform = QTransform::fromTranslate(-effectRect.x(), -effectRect.y()); 10799 if (deviceCoordinates && info->effectTransform) 10800 effectTransform *= *info->effectTransform; 10801 10802 if (!info) { 10803 // Logical coordinates without info. 10804 QTransform sceneTransform = item->sceneTransform(); 10805 QTransform newEffectTransform = sceneTransform.inverted(); 10806 newEffectTransform *= effectTransform; 10807 scened->draw(item, &pixmapPainter, 0, &sceneTransform, 0, 0, qreal(1.0), 10808 &newEffectTransform, false, true); 10809 } else if (deviceCoordinates) { 10810 // Device coordinates with info. 10811 scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, info->exposedRegion, 10812 info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform, 10813 info->drawItem); 10814 } else { 10815 // Item coordinates with info. 10816 QTransform newEffectTransform = info->transformPtr->inverted(); 10817 newEffectTransform *= effectTransform; 10818 scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, info->exposedRegion, 10819 info->widget, info->opacity, &newEffectTransform, info->wasDirtySceneTransform, 10820 info->drawItem); 10821 } 10822 10823 pixmapPainter.end(); 10824 10825 return pixmap; 10826 } 10827 #endif //QT_NO_GRAPHICSEFFECT 10828 8858 10829 #ifndef QT_NO_DEBUG_STREAM 8859 10830 QDebug operator<<(QDebug debug, QGraphicsItem *item) … … 8864 10835 } 8865 10836 8866 QStringList flags; 8867 if (item->isVisible()) flags << QLatin1String("isVisible"); 8868 if (item->isEnabled()) flags << QLatin1String("isEnabled"); 8869 if (item->isSelected()) flags << QLatin1String("isSelected"); 8870 if (item->hasFocus()) flags << QLatin1String("HasFocus"); 8871 8872 debug << "QGraphicsItem(this =" << ((void*)item) 8873 << ", parent =" << ((void*)item->parentItem()) 10837 if (QGraphicsObject *o = item->toGraphicsObject()) 10838 debug << o->metaObject()->className(); 10839 else 10840 debug << "QGraphicsItem"; 10841 debug << "(this =" << (void*)item 10842 << ", parent =" << (void*)item->parentItem() 8874 10843 << ", pos =" << item->pos() 8875 << ", z =" << item->zValue() << ", flags = {"8876 << flags.join(QLatin1String("|")) << " })";10844 << ", z =" << item->zValue() << ", flags = " 10845 << item->flags() << ")"; 8877 10846 return debug; 10847 } 10848 10849 QDebug operator<<(QDebug debug, QGraphicsObject *item) 10850 { 10851 if (!item) { 10852 debug << "QGraphicsObject(0)"; 10853 return debug; 10854 } 10855 10856 debug.nospace() << item->metaObject()->className() << '(' << (void*)item; 10857 if (!item->objectName().isEmpty()) 10858 debug << ", name = " << item->objectName(); 10859 debug.nospace() << ", parent = " << ((void*)item->parentItem()) 10860 << ", pos = " << item->pos() 10861 << ", z = " << item->zValue() << ", flags = " 10862 << item->flags() << ')'; 10863 return debug.space(); 8878 10864 } 8879 10865 … … 8963 10949 str = "ItemOpacityHasChanged"; 8964 10950 break; 10951 case QGraphicsItem::ItemScenePositionHasChanged: 10952 str = "ItemScenePositionHasChanged"; 10953 break; 8965 10954 } 8966 10955 debug << str; … … 8999 10988 str = "ItemStacksBehindParent"; 9000 10989 break; 10990 case QGraphicsItem::ItemUsesExtendedStyleOption: 10991 str = "ItemUsesExtendedStyleOption"; 10992 break; 10993 case QGraphicsItem::ItemHasNoContents: 10994 str = "ItemHasNoContents"; 10995 break; 10996 case QGraphicsItem::ItemSendsGeometryChanges: 10997 str = "ItemSendsGeometryChanges"; 10998 break; 10999 case QGraphicsItem::ItemAcceptsInputMethod: 11000 str = "ItemAcceptsInputMethod"; 11001 break; 11002 case QGraphicsItem::ItemNegativeZStacksBehindParent: 11003 str = "ItemNegativeZStacksBehindParent"; 11004 break; 11005 case QGraphicsItem::ItemIsPanel: 11006 str = "ItemIsPanel"; 11007 break; 11008 case QGraphicsItem::ItemIsFocusScope: 11009 str = "ItemIsFocusScope"; 11010 break; 11011 case QGraphicsItem::ItemSendsScenePositionChanges: 11012 str = "ItemSendsScenePositionChanges"; 11013 break; 9001 11014 } 9002 11015 debug << str; … … 9006 11019 QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlags flags) 9007 11020 { 9008 debug << "(";11021 debug << '('; 9009 11022 bool f = false; 9010 for (int i = 0; i < 9; ++i) {11023 for (int i = 0; i < 16; ++i) { 9011 11024 if (flags & (1 << i)) { 9012 11025 if (f) 9013 debug << "|";11026 debug << '|'; 9014 11027 f = true; 9015 11028 debug << QGraphicsItem::GraphicsItemFlag(int(flags & (1 << i))); 9016 11029 } 9017 11030 } 9018 debug << ")";11031 debug << ')'; 9019 11032 return debug; 9020 11033 }
Note:
See TracChangeset
for help on using the changeset viewer.